Я новичок в параллельном программировании с использованием графического процессора, поэтому извиняюсь, если вопрос является широким или неопределенным. Я знаю, что в библиотеке CULA есть параллельная функция SVD, но какая должна быть стратегия, если у меня есть большое количество относительно небольших матриц для факторизации? Например, у меня есть n
матрицы с размером d
, n
большой и d
маленький. Как распараллелить этот процесс? Может ли кто-нибудь дать мне подсказку?Параллельная реализация для нескольких SVD с использованием CUDA
ответ
Вы можете посмотреть сообщение Batched Operations блога CULA для обсуждения вашей проблемы.
EDIT
Из того, что я понял из вашего комментария ниже, вы хотите, чтобы каждый поток, чтобы вычислить отдельный СВД. Таким образом, в основном каждый поток должен выполнять стандартную последовательную схему SVD. Для что некоторые, возможно, полезные ссылки:
Golub, Van Loan, Matrix Computations
Если вы используете этот подход, хотя, боюсь, вы не сможете больше использовать cuBLAS, поскольку те host
функции не отозваны от device
(если у вас нет вычислительной возможности >3.5
, см. пример simpleDevLibCUBLAS
.). Но в основном таким образом я думаю, что вы каким-то образом реализуете концепцию партии.
Если вы решили перейти к более стандартной реализации параллельно GPU, ниже ссылка может заинтересовать:
Мой предыдущий ответ теперь устарелый. По состоянию на февраль 2015 года CUDA 7 (в настоящее время в версии для кандидатов на выпуск) предлагает полные возможности SVD в своей библиотеке cuSOLVER. Ниже приведен пример создания разложения сингулярных значений с использованием CUDA cuSOLVER.
Касательно конкретной проблемы, которую вы поднимаете (, вычисляя SVD нескольких матриц малого размера), вы должны адаптировать пример, который я предоставляю ниже, используя потоки. Для того, чтобы связать поток для каждой задачи вы можете использовать
cudaStreamCreate()
и
cusolverDnSetStream()
kernel.cu
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include<iostream>
#include<iomanip>
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<math.h>
#include <cusolverDn.h>
#include <cuda_runtime_api.h>
#include "Utilities.cuh"
/********/
/* MAIN */
/********/
int main(){
// --- gesvd only supports Nrows >= Ncols
// --- column major memory ordering
const int Nrows = 7;
const int Ncols = 5;
// --- cuSOLVE input/output parameters/arrays
int work_size = 0;
int *devInfo; gpuErrchk(cudaMalloc(&devInfo, sizeof(int)));
// --- CUDA solver initialization
cusolverDnHandle_t solver_handle;
cusolverDnCreate(&solver_handle);
// --- Setting the host, Nrows x Ncols matrix
double *h_A = (double *)malloc(Nrows * Ncols * sizeof(double));
for(int j = 0; j < Nrows; j++)
for(int i = 0; i < Ncols; i++)
h_A[j + i*Nrows] = (i + j*j) * sqrt((double)(i + j));
// --- Setting the device matrix and moving the host matrix to the device
double *d_A; gpuErrchk(cudaMalloc(&d_A, Nrows * Ncols * sizeof(double)));
gpuErrchk(cudaMemcpy(d_A, h_A, Nrows * Ncols * sizeof(double), cudaMemcpyHostToDevice));
// --- host side SVD results space
double *h_U = (double *)malloc(Nrows * Nrows * sizeof(double));
double *h_V = (double *)malloc(Ncols * Ncols * sizeof(double));
double *h_S = (double *)malloc(min(Nrows, Ncols) * sizeof(double));
// --- device side SVD workspace and matrices
double *d_U; gpuErrchk(cudaMalloc(&d_U, Nrows * Nrows * sizeof(double)));
double *d_V; gpuErrchk(cudaMalloc(&d_V, Ncols * Ncols * sizeof(double)));
double *d_S; gpuErrchk(cudaMalloc(&d_S, min(Nrows, Ncols) * sizeof(double)));
// --- CUDA SVD initialization
cusolveSafeCall(cusolverDnDgesvd_bufferSize(solver_handle, Nrows, Ncols, &work_size));
double *work; gpuErrchk(cudaMalloc(&work, work_size * sizeof(double)));
// --- CUDA SVD execution
cusolveSafeCall(cusolverDnDgesvd(solver_handle, 'A', 'A', Nrows, Ncols, d_A, Nrows, d_S, d_U, Nrows, d_V, Ncols, work, work_size, NULL, devInfo));
int devInfo_h = 0; gpuErrchk(cudaMemcpy(&devInfo_h, devInfo, sizeof(int), cudaMemcpyDeviceToHost));
if (devInfo_h != 0) std::cout << "Unsuccessful SVD execution\n\n";
// --- Moving the results from device to host
gpuErrchk(cudaMemcpy(h_S, d_S, min(Nrows, Ncols) * sizeof(double), cudaMemcpyDeviceToHost));
gpuErrchk(cudaMemcpy(h_U, d_U, Nrows * Nrows * sizeof(double), cudaMemcpyDeviceToHost));
gpuErrchk(cudaMemcpy(h_V, d_V, Ncols * Ncols * sizeof(double), cudaMemcpyDeviceToHost));
std::cout << "Singular values\n";
for(int i = 0; i < min(Nrows, Ncols); i++)
std::cout << "d_S["<<i<<"] = " << std::setprecision(15) << h_S[i] << std::endl;
std::cout << "\nLeft singular vectors - For y = A * x, the columns of U span the space of y\n";
for(int j = 0; j < Nrows; j++) {
printf("\n");
for(int i = 0; i < Nrows; i++)
printf("U[%i,%i]=%f\n",i,j,h_U[j*Nrows + i]);
}
std::cout << "\nRight singular vectors - For y = A * x, the columns of V span the space of x\n";
for(int i = 0; i < Ncols; i++) {
printf("\n");
for(int j = 0; j < Ncols; j++)
printf("V[%i,%i]=%f\n",i,j,h_V[j*Ncols + i]);
}
cusolverDnDestroy(solver_handle);
return 0;
}
Utilities.cuh
#ifndef UTILITIES_CUH
#define UTILITIES_CUH
extern "C" int iDivUp(int, int);
extern "C" void gpuErrchk(cudaError_t);
extern "C" void cusolveSafeCall(cusolverStatus_t);
#endif
Utilities.cu
#include <stdio.h>
#include <assert.h>
#include "cuda_runtime.h"
#include <cuda.h>
#include <cusolverDn.h>
/*******************/
/* iDivUp FUNCTION */
/*******************/
extern "C" int iDivUp(int a, int b){ return ((a % b) != 0) ? (a/b + 1) : (a/b); }
/********************/
/* CUDA ERROR CHECK */
/********************/
// --- Credit to http://stackoverflow.com/questions/14038589/what-is-the-canonical-way-to-check-for-errors-using-the-cuda-runtime-api
void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) { exit(code); }
}
}
extern "C" void gpuErrchk(cudaError_t ans) { gpuAssert((ans), __FILE__, __LINE__); }
/**************************/
/* CUSOLVE ERROR CHECKING */
/**************************/
static const char *_cudaGetErrorEnum(cusolverStatus_t error)
{
switch (error)
{
case CUSOLVER_STATUS_SUCCESS:
return "CUSOLVER_SUCCESS";
case CUSOLVER_STATUS_NOT_INITIALIZED:
return "CUSOLVER_STATUS_NOT_INITIALIZED";
case CUSOLVER_STATUS_ALLOC_FAILED:
return "CUSOLVER_STATUS_ALLOC_FAILED";
case CUSOLVER_STATUS_INVALID_VALUE:
return "CUSOLVER_STATUS_INVALID_VALUE";
case CUSOLVER_STATUS_ARCH_MISMATCH:
return "CUSOLVER_STATUS_ARCH_MISMATCH";
case CUSOLVER_STATUS_EXECUTION_FAILED:
return "CUSOLVER_STATUS_EXECUTION_FAILED";
case CUSOLVER_STATUS_INTERNAL_ERROR:
return "CUSOLVER_STATUS_INTERNAL_ERROR";
case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
return "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED";
}
return "<unknown>";
}
inline void __cusolveSafeCall(cusolverStatus_t err, const char *file, const int line)
{
if(CUSOLVER_STATUS_SUCCESS != err) {
fprintf(stderr, "CUSOLVE error in file '%s', line %d\n %s\nerror %d: %s\nterminating!\n",__FILE__, __LINE__,err, \
_cudaGetErrorEnum(err)); \
cudaDeviceReset(); assert(0); \
}
}
extern "C" void cusolveSafeCall(cusolverStatus_t err) { __cusolveSafeCall(err, __FILE__, __LINE__); }
Что вы думаете об этом подходе против использования MAGMA? –
@AndreasYankopolus Я не сравнивал две библиотеки, извините. – JackOLantern
- 1. Идеальная реализация SVD?
- 2. Реализация алгоритма SVD
- 3. SVD реализация map уменьшить
- 4. Реализация SVD Matlab
- 5. Реализация рекомендации SVD в Mahout
- 6. clojure: параллельная обработка с использованием нескольких компьютеров
- 7. Параллельная реализация вычисления суммы больших смежных подпоследовательностей в большом массиве с использованием Cuda
- 8. Параллельная реализация вычисления суммы смежных подпоследовательностей в массиве с использованием Cuda
- 9. Усеченная реализация SVD в Java
- 10. Параллельная реализация Bellman-Ford
- 11. Параллельная реализация кэша LRU
- 12. Реализация MySQL с CUDA
- 13. opencv for-loop с CUDA - параллельная обработка
- 14. параллельная декомпозиция SVD с openMP-деос не выполняется, как ожидалось
- 15. Сжатие изображения с использованием SVD
- 16. Параллельная реализация исключения Гаусса с помощью pthreads
- 17. Сортировка, параллельная реализация очереди (скрученная) с sqlite?
- 18. Расчет SVD с использованием нескольких ядер в R
- 19. Параллельная реализация шаблона издателя/подписчика
- 20. Обработка нескольких изображений с использованием CUDA
- 21. Параллельная реализация DFS для неориентированного графика
- 22. Классификация документов с использованием LSA/SVD
- 23. Размер SVD и решатель в CUDA (в устройстве)
- 24. Параллельная реализация LINQ в моно?
- 25. Одновременный запуск нескольких ядер с использованием CUDA для графического процессора
- 26. Реализация критической секции в CUDA
- 27. Реализация контрольного журнала с использованием нескольких таблиц
- 28. Реализация больших моделей линейной регрессии с использованием CUDA
- 29. Реализация общей памяти CUDA
- 30. Soft Thresholding Реализация CUDA
Аналогичны дозируемой решатель/матрицы обратного кода, размещенный на CUDA зарегистрирован на сайт для разработчиков вы могли бы рассмотреть матрицу-за-нить или подход матрицы Межпоточного-блок. Это хорошо работает, если размер партии большой, а матрицы очень малы. Каковы типичные значения для n и d в вашем случае? – njuffa
BLAS пакетный режим имеет только матричное умножение, правильно? Как я могу использовать его для SVD? И не могли бы вы дать мне пример кода, как разделить потоки или блоки в графическом процессоре и позволить каждой единице параллельно использовать SVD? Например, если n = 500 d = 20. Благодаря! –
Я отредактировал мое сообщение. Надеюсь, это будет полезно. – JackOLantern