A*B
GPU 上の次元の行列があるとします。ここで、 B
(列数) は C スタイルを想定した主要な次元です。この行列を FORTRAN スタイルに転置する CUDA (または cublas) の方法はありますA
か?
host->device
元のデータを変更せずに、転送時に転置できるとさらに良いです。
A*B
GPU 上の次元の行列があるとします。ここで、 B
(列数) は C スタイルを想定した主要な次元です。この行列を FORTRAN スタイルに転置する CUDA (または cublas) の方法はあります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);
そして、2 つの行優先行列 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が指摘したように、行列を転置として操作するかどうかを指定できます。たとえば、cublasDgemm()の場合、C = a * op(A)* op(B)+ b * Cと仮定すると、 Aを転置(A ^ T)として操作したい場合は、それが('N'通常または'T'転置)であるかどうかを指定できるパラメーターで
CUDA 5 ツールキットにバンドルされている CUBLAS のバージョンには、行列の転置に使用できる BLAS に似たメソッド (cublasgeam) が含まれています。ここに文書化されています。