параллельные вычисления на python | тест pycuda, сравнение и анализ

алгоритм

Алгоритм инкрементного обучения может изучать узлы и параметры сети одновременно, но с ростом структуры модели вычислительные затраты становятся все выше и выше, есть два способа уменьшить временные затраты на расчет: ( 1) Исследуйте метод разделения модели, разделите относительно большую модель на несколько более мелких подмоделей; (2) за счет повышения вычислительной мощности компьютера (GPU или CPU). TX2 может использовать CUDA для параллельных вычислений на графическом процессоре, а pycuda как библиотека параллельных вычислений для python может легко обеспечить параллельное ускорение на графическом процессоре. Эта статья использует pycuda для достижения параллельного ускорения и сравнивает его с numpy.

pycuda реализует параллельные вычисления

Учебники по установке и простому использованию см.официальный сайт пикуда.

простой пример

import pycuda.autoinit
import pycuda.driver as drv
import numpy as np
import time
from pycuda.compiler import SourceModule
mod = SourceModule('''
__global__ void Text_GPU(float *A , float *B, float *K, size_t N){

    int bid = blockIdx.x;  
    int tid = threadIdx.x;

    __shared__ float s_data[2];

    s_data[tid] = (A[bid*2 + tid] - B[bid*2 + tid]);
    __syncthreads();
    if(tid == 0)
    {
        float sum_d = 0.0;
        for(int i=0;i<N;i++)
        {
            sum_d += (s_data[i]*s_data[i]);
        }
        K[bid] = exp(-sum_d);
    }
}
''')

multiply_them = mod.get_function("Text_GPU")
tic = time.time() 
A = np.random.random((1000,20)).astype(np.float32)
B = np.random.random((1000,20)).astype(np.float32)
K = np.zeros((1000,), dtype=np.float32)
N = 20
N = np.int32(N)   
multiply_them(
        drv.In(A), drv.In(B), drv.InOut(K), N,
        block=(20,1,1), grid=(1000,1))
toc = time.time()
print("time cost is:"+str(toc-tic)) 

time cost:0.00536298751831

Примечания

сетка и блок

Связь между блоками осуществляется через глобальную память (Global Memory), а потоки в одном блоке могут взаимодействовать друг с другом через общую память (Shared Memory). Каждому блоку потока соответствует своя собственная локальная память (Local Memory).在这里插入图片描述

SourceModule

mod = SourceModule('''
__global__ void Text_GPU(.....){
......
}
''')

Этот код представляет собой функцию ядра C++, которая определяет основной код параллельных вычислений на графическом процессоре. Например: определите функцию ядра, которая добавляет два вектора

mod = SourceModule("""
__global__ void multiply_them(float *dest, float *a, float *b)
{
  const int i = threadIdx.x;
  dest[i] = a[i] + b[i];
}
""")

_shared_Переменная;

Определите общую память в том же блоке.

__syncthreads()

Функция синхронизации, когда приведенный выше код был выполнен в том же блоке, выполните код ниже функции синхронизации.

blockIdx.x и threadIdx.x

blockIdx.x принимает идентификатор блока, а threadIdx.x принимает идентификатор потока.

Сравнение с вычислениями numpy без ускорения GPU

Первый метод Numpy (не для цикла)

import numpy as np
import time
A = np.random.random((1000,20)).astype(np.float32)
B = np.random.random((1000,20)).astype(np.float32)
tic = time.time()
dk = A-B
dd = [np.sum(a**2) for a in dk]
K1 = np.exp(-np.array(dd))
toc = time.time()
print("time cost is:"+str(toc-tic))

time cost is:0.0174951553345

Второй метод Numpy (для цикла)

import numpy as np
import time
A = np.random.random((1000,20)).astype(np.float32)
B = np.random.random((1000,20)).astype(np.float32)
def Guassion_kernel(x, u):
    d = x-u
    dd = [np.sum(a**2) for a in d]
    return np.exp(-sum(dd))

tic = time.time()

Phi_x = []
for j in range(1000):
    Phi_x.append(Guassion_kernel(A[j], B[j]))
toc = time.time()
print("time cost is:"+str(toc-tic)) 
print(Phi_x)

time cost is:0.0264999866486

В сравнении

В таблице приведены расчетные затраты трех вышеуказанных методов. Видно, что затраты времени вычисления ускорения графического процессора самые низкие, а затраты времени вычисления цикла FOR самые высокие. Это только предварительное сравнение, в практических приложениях ускорение GPU иногда не быстрее, чем CPU. Когда объем данных невелик, а предварительная конфигурация с ускорением на GPU требует дополнительных вычислений, иногда время вычислений с ускорением на GPU больше, чем на CPU.

types GPU CPU without for loop CPU with for loop
time cost 0.00536298751831 0.0174951553345 0.0264999866486
Наконец, он применяется в инкрементном алгоритме, потому что количество узлов медленно увеличивается. Три способа расчета стоимости каждого шага итерации показаны на рисунке ниже. Мы обнаружили, что в начале операции количество узлов невелико, а стоимость вычислительного времени GPU выше, чем у CPU, но позже GPU и CPU (... Похоже, что GPU не имеет больших преимуществ , главным образом потому, что количество узлов все еще невелико, сотни узлов), я считаю, что с дальнейшим увеличением узлов эффективность GPU будет более заметной.
在这里插入图片描述
## в заключении
В этой статье рассказывается о pycuda и реализуются параллельные вычисления на GPU в python.