Я пытаюсь изучить CUDA
и использовать PyCUDA
для написания простого кода умножения матрицы. В течение двух 4x4 матриц генерируются случайным образом я получаю следующее решение:PyCUDA точность кода умножения матрицы
Cuda:
[[ -5170.86181641 -21146.49609375 20690.02929688 -35413.9296875 ]
[-18998.5 -3199.53271484 13364.62890625 7141.36816406]
[ 31197.43164062 21095.02734375 1750.64453125 11304.63574219]
[ -896.64978027 18424.33007812 -17135.00390625 7418.28417969]]
Python:
[[ -5170.86035156 -21146.49609375 20690.02929688 -35413.9296875 ]
[-18998.5 -3199.53271484 13364.62695312 7141.36816406]
[ 31197.43164062 21095.02929688 1750.64404297 11304.63574219]
[ -896.64941406 18424.33007812 -17135.00390625 7418.28417969]]
Cuda-Python:
[[-0.00146484 0. 0. 0. ]
[ 0. 0. 0.00195312 0. ]
[ 0. -0.00195312 0.00048828 0. ]
[-0.00036621 0. 0. 0. ]]
погрешность составляет порядка 1e-3
и возрастает по мере увеличить размер матриц. Я не уверен, что это ошибка или нет. Мой вопрос заключается в том, является ли такая «большая» ошибка нормальной вещью с int32
или я делаю что-то неправильно?
Вот исходный код:
matmul.py
import numpy as np
import time
# import pycuda stuff
import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import SourceModule
BLOCK_SIZE = 16
n = 4
ni = np.int32(n)
# matrix A
a = np.random.randn(n, n)*100
a = a.astype(np.float32)
# matrix B
b = np.random.randn(n, n)*100
b = b.astype(np.float32)
# matrix B
c = np.empty([n, n])
c = c.astype(np.float32)
# allocate memory on device
a_gpu = cuda.mem_alloc(a.nbytes)
b_gpu = cuda.mem_alloc(b.nbytes)
c_gpu = cuda.mem_alloc(c.nbytes)
# copy matrix to memory
cuda.memcpy_htod(a_gpu, a)
cuda.memcpy_htod(b_gpu, b)
# compile kernel
mod = SourceModule(open("kernels.cu", "r").read())
# get function
matmul = mod.get_function("matmul");
# set grid size
if n%BLOCK_SIZE != 0:
grid=(n/BLOCK_SIZE+1,n/BLOCK_SIZE+1,1)
else:
grid=(n/BLOCK_SIZE,n/BLOCK_SIZE,1)
# call gpu function
start = time.time()
matmul(ni, a_gpu, b_gpu, c_gpu, block=(BLOCK_SIZE,BLOCK_SIZE,1), grid=grid);
end = time.time()
print "Time: %.5f s"%(end-start)
# copy back the result
cuda.memcpy_dtoh(c, c_gpu)
print np.linalg.norm(c - np.dot(a,b))
print c
print np.dot(a,b)
print c - np.dot(a,b)
kernels.cu
__global__ void matmul(int n, const float *A, const float *B, float *C){
int tx = threadIdx.x;
int ty = threadIdx.y;
int bx = blockIdx.x;
int by = blockIdx.y;
int row = by*blockDim.y + ty;
int col = bx*blockDim.x + tx;
if(row < n && col < n){
float val = 0.0;
for(int i=0; i<n; ++i){
val += A[row*n + i]*B[n*i + col];
}
C[row*n + col] = val;
}
}
Ошибка * relative * имеет порядок 1e-7, что разумно для расчетов с плавающей запятой с одиночной точностью (32 бит). –
Спасибо! Я был смущен между относительным и абсолютным порядком точности. – maverick