A*B
假设我在 GPU 上有一个维度为的矩阵,其中B
(列数)是假设 C 样式的前导维度。CUDA(或 cublas)中是否有任何方法可以将此矩阵转置为 FORTRAN 样式,其中A
(行数)成为前导维度?
如果可以在传输过程中进行转置,host->device
同时保持原始数据不变,那就更好了。
A*B
假设我在 GPU 上有一个维度为的矩阵,其中B
(列数)是假设 C 样式的前导维度。CUDA(或 cublas)中是否有任何方法可以将此矩阵转置为 FORTRAN 样式,其中A
(行数)成为前导维度?
如果可以在传输过程中进行转置,host->device
同时保持原始数据不变,那就更好了。
如标题中所要求的,要转置设备行主矩阵 A[m][n],可以这样做:
float* clone = ...;//copy content of A to clone
float const alpha(1.0);
float const beta(0.0);
cublasHandle_t handle;
cublasCreate(&handle);
cublasSgeam( handle, CUBLAS_OP_T, CUBLAS_OP_N, m, n, &alpha, clone, n, &beta, clone, m, A, m );
cublasDestroy(handle);
并且,将两个行优先矩阵 A[m][k] B[k][n] 相乘,C=A*B
cublasSgemm( handle, CUBLAS_OP_N, CUBLAS_OP_N, n, m, k, &alpha, B, n, A, k, &beta, C, n );
其中 C 也是一个行优先矩阵。
CUDA SDK 包含一个矩阵转置,您可以在此处查看有关如何实现的代码示例,从简单的实现到优化的版本。
例如:
天真的转置
__global__ void transposeNaive(float *odata, float* idata,
int width, int height, int nreps)
{
int xIndex = blockIdx.x*TILE_DIM + threadIdx.x;
int yIndex = blockIdx.y*TILE_DIM + threadIdx.y;
int index_in = xIndex + width * yIndex;
int index_out = yIndex + height * xIndex;
for (int r=0; r < nreps; r++)
{
for (int i=0; i<TILE_DIM; i+=BLOCK_ROWS)
{
odata[index_out+i] = idata[index_in+i*width];
}
}
}
就像 talonmies 指出的那样,您可以在 cublas 矩阵运算中指定是否要转置矩阵,例如:对于 cublasDgemm() where C = a * op(A) * op(B) + b * C,假设您想将 A 操作为转置 (A^T),在参数上您可以指定它是 ('N' normal or 'T' transposed)
与 CUDA 5 工具包捆绑的 CUBLAS 版本包含可用于转置矩阵的类似 BLAS 的方法 (cublasgeam)。它记录在这里。
这是一个工作示例:
#include "cublas_v2.h"
#include <vector>
#include <iostream>
using std::cout;
void print_matrix(float *data, int rows, int cols) {
cout << "[";
for( int row=0; row < rows; row++) {
cout << "[";
for( int col=0; col < cols; col++) {
cout << data[row*cols+col] << ",";
}
cout << "]";
}
cout << "]";
}
int main() {
// allocate host vector
std::vector<float> h_a = {1,2,3,4,5,6,7,8,9,10};
int nbytes=h_a.size()*sizeof(*h_a.data());
std::vector<float> h_b(h_a.size());
// define the number or rows and the number of columns
int m=2,n=5;
// allocate device vectors
float *d_a, *d_b;
cudaMalloc(&d_a, nbytes);
cudaMalloc(&d_b, nbytes);
// copy host vector to device
cudaMemcpy(d_a,h_a.data(), nbytes, cudaMemcpyHostToDevice);
// perform a transpose
{
float alpha=1;
float *A=d_a;
int lda=n;
float beta=0;
float *B=NULL;
int ldb=n;
float *C=d_b;
int ldc=m;
cublasHandle_t handle;
cublasCreate(&handle);
cublasStatus_t success=cublasSgeam( handle, CUBLAS_OP_T, CUBLAS_OP_N, m, n, &alpha, A, lda, &beta, B, ldb, C, ldc);
if ( success != CUBLAS_STATUS_SUCCESS)
cout << "\33[31mError: " << success << "\33[0m\n";
cublasDestroy(handle);
}
// copy back to host
cudaMemcpy(h_b.data(),d_b,nbytes,cudaMemcpyDeviceToHost);
cout << "origional: ";
print_matrix(h_a.data(),m,n);
cout << "\n";
cout << "transposed: ";
print_matrix(h_b.data(),n,m);
cout << "\n";
cudaFree(d_a);
cudaFree(d_b);
return 0;
}