матричное умножение cublas дает ВНУТРЕННЮЮ ОШИБКУ при применении к матрице с одним очень длинным измерением с несколькими графическими процессорами - PullRequest
0 голосов
/ 18 октября 2019

Я пытался просто применить cublasDgemm (умножение матрицы на матрицу) на несколько матриц с элементом типа «double» (8 байтов), каждый из которых имеет одно измерение, которое очень велико. В моем случае размеры матриц 12755046 на 46. Проще говоря, A [46,12755046] * B_i [12755046,46] = C_i [46,46], где i = 1,2,3, ... .

Машина имеет 128 ГБ памяти и два GTX2080Ti (11 ГБ памяти GPU), поэтому моей первоначальной стратегией было распределение B_i для каждого GPU. Однако я всегда получаю ВНУТРЕННЮЮ ОШИБКУ, когда выполняю свой код на двух графических процессорах.

Поэтому я решил эту проблему, попробовав три вещи: 1. использовать только один графический процессор. Нет ошибки. 2. уменьшите размер матрицы, но продолжайте использовать два графических процессора. Нет ошибки. 3. использовать cublasXt, который неявно использует два графических процессора. Без ошибок.

Хотя это решено, я все еще заинтересован в поиске ответа на вопрос, почему мой первоначальный план не работал для матрицы большого размера? Я предполагаю, что это может быть связано с некоторыми внутренними ограничениями от cublas, или я пропустил некоторые конфигурации?

Я приложил свой упрощенный код здесь, чтобы проиллюстрировать мой первоначальный план:

double *A, *B[2], *C[2];
cudaMallocManaged(&A, 46*12755046*sizeof(double));
cudaMallocManaged(&B[0], 46*12755046*sizeof(double));
cudaMallocManaged(&B[1], 46*12755046*sizeof(double));
cudaMallocManaged(&C[0], 46*12755046*sizeof(double));
cudaMallocManaged(&C[1], 46*12755046*sizeof(double));
givevalueto(A);
givevalueto(B[0]);
givevalueto(B[1]);
double alpha = 1.0;
double beta = 0.0;
cublasHandle_t  handle[nGPUs];
int iGPU;
for(iGPU=0;iGPU<nGPUs;iGPU++)
{
   cublasCreate (& handle[iGPU]);
}
for(iGPU=0;iGPU<nGPUs;i++)
{
   cudaSetDevice(iGPU);
   cublasDgemm(handle[iGPU],CUBLAS_OP_N,CUBLAS_OP_N,46,46,12755046,&alpha,A,46,B[iGPU],12755046,&beta,C[iGPU],46);
}
for(iGPU=0;iGPU<nGPUs;i++)
{
   cudaSetDevice(iGPU);
   cudaDeviceSynchronize();
}
for(iGPU=0;iGPU<nGPUs;iGPU++)
{
   cudaFree(B[iGPU]);
}

1 Ответ

2 голосов
/ 18 октября 2019

Дескриптор cublas применим к устройству, которое было активным при его создании.

Из документации для cublasCreate:

Контекст библиотеки CUBLAS привязан к текущему устройству CUDA.

См. Также описание контекста cublas:

Предполагается, что устройство, связанное с конкретным контекстом cuBLAS, остается неизменным между соответствующим cublasCreate() и cublasDestroy () вызывает. Чтобы библиотека cuBLAS использовала другое устройство в том же хост-потоке, приложение должно установить новое устройство для использования, вызвав cudaSetDevice (), а затем создать другой контекст cuBLAS, который будет связан с новым устройством, вызвавcublasCreate ().

Вы можете исправить свой код с помощью:

for(iGPU=0;iGPU<nGPUs;iGPU++)
{
   cudaSetDevice(iGPU);              // add this line
   cublasCreate (& handle[iGPU]);
}
...