2013-07-01 7 views
6

का उपयोग कर एकाधिक एसवीडी के लिए समांतर कार्यान्वयन मैं जीपीयू का उपयोग कर समानांतर प्रोग्रामिंग के लिए नया हूं इसलिए यदि प्रश्न व्यापक या अस्पष्ट है तो मैं क्षमा चाहता हूं। मुझे पता है कि सीयूएलए लाइब्रेरी में कुछ समानांतर एसवीडी फ़ंक्शन है, लेकिन यदि मेरे पास कारक बनाने के लिए अपेक्षाकृत छोटी मैट्रिक्स की बड़ी संख्या है तो रणनीति क्या होनी चाहिए? उदाहरण के लिए मेरे पास n आयाम d, n के साथ matrices बड़े हैं और d छोटा है। इस प्रक्रिया को समानांतर कैसे करें? क्या कोई मुझे संकेत दे सकता है?सीयूडीए

उत्तर

4

आप अपनी समस्या की चर्चा के लिए CULA ब्लॉग के Batched Operations पोस्ट पर एक नज़र डाल सकते हैं।

संपादित

मैं क्या नीचे अपनी टिप्पणी से समझ में से, आप प्रत्येक थ्रेड एक अलग SVD गणना करने के लिए करना चाहते हैं। इसलिए, मूल रूप से प्रत्येक थ्रेड को मानक, अनुक्रमिक एसवीडी योजना निष्पादित करनी चाहिए। उसके लिए कुछ संभवतः उपयोगी संदर्भ:

Numerical Recipes

Golub, Van Loan, Matrix Computations

आप यह तरीका अपनाते हैं, हालांकि, मुझे डर है कि तुम अब और सक्षम cuBLAS उपयोग करने के लिए नहीं होगा हूँ, के रूप में उन host कार्यों प्रतिदेय नहीं हैं device से (जब तक आपके पास गणना क्षमता >3.5 नहीं है, तो simpleDevLibCUBLAS उदाहरण देखें।)। लेकिन मूल रूप से मुझे लगता है कि आप किसी भी तरह से बैच अवधारणा को अपने आप लागू कर रहे हैं। बाहर का तारीख

Singular Value Decomposition on GPU using CUDA

+0

बैच solver/मैट्रिक्स उलटा कोड CUDA पर पोस्ट के अनुरूप डेवलपर वेबसाइट पंजीकृत आप एक मैट्रिक्स-प्रति-धागा या एक मैट्रिक्स-प्रति-धागा ब्लॉक दृष्टिकोण पर विचार कर सकते। यह अच्छा काम करता है यदि बैच आकार बड़ा है और matrices बहुत छोटे हैं। आपके मामले में एन और डी के लिए सामान्य मूल्य क्या हैं? – njuffa

+0

बीएलएएस बैच मोड में केवल मैट्रिक्स गुणा है, है ना? मैं एसवीडी के लिए इसका उपयोग कैसे कर सकता हूं? और क्या आप मुझे जीपीयू में धागे या ब्लॉक को विभाजित करने के तरीके का एक उदाहरण उदाहरण दे सकते हैं और प्रत्येक इकाई समानांतर में एक एसवीडी करता है? उदाहरण के लिए यदि एन = 500 डी = 20। धन्यवाद! –

+0

मैंने अपनी पोस्ट संपादित की है। मुझे आशा है कि यह सहायक होगा। – JackOLantern

7

मेरे पिछले जवाब है:

आप एक अधिक मानक समानांतर GPU कार्यान्वयन के लिए जाने का निर्णय तो नीचे दिए गए संदर्भ ब्याज की हो सकता है। फरवरी 2015 तक, सीयूडीए 7 (वर्तमान में रिलीज उम्मीदवार संस्करण में) अपनी एसयूएसओएलवीआर लाइब्रेरी में पूर्ण एसवीडी क्षमताओं की पेशकश करता है। नीचे, मैं CUDA CuSOLVER का उपयोग करके एकवचन मूल्य अपघटन उत्पन्न करने का एक उदाहरण प्रदान कर रहा हूं।

आपके द्वारा उठाए जा रहे विशिष्ट मुद्दे के बारे में (छोटे आकार के कई मैट्रिक्स के एसवीडी की गणना करना), आपको धाराओं का उपयोग करके नीचे प्रदान कर रहे उदाहरण को अनुकूलित करना चाहिए। प्रत्येक कार्य के लिए एक धारा संबद्ध करने के

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 
012 का उपयोग कर सकते करने के लिए

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__); } 
+0

मैग्मा का उपयोग करके इस दृष्टिकोण बनाम आप क्या सोचते हैं? –

+1

@AndreasYankopolus मैंने दो पुस्तकालयों की तुलना नहीं की है, क्षमा करें। – JackOLantern

संबंधित मुद्दे