我在CUDA中用于矩阵乘法的代码允许我将正方形矩阵和非正方形矩阵相乘,但是,宽度和高度都必须是块大小的倍数。
所以,例如,我可以乘以[3] [6] * [6] [3](使用blocksize = 3),但我不能乘以[3] [2] * [2] [3]
有谁知道这样做的方法?这是我的核心:
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#define blocksize 3
#define HM (1*blocksize)
#define WM (2*blocksize)
#define WN (1*blocksize)
#define HN WM
#define WP WN
#define HP HM
#define PTH WM
#define PTW HM
__global__ void nonsquare(float*M, float*N, float*P, int uWM,int uWN)
{
__shared__ float MS[blocksize][blocksize];
__shared__ float NS[blocksize][blocksize];
int tx=threadIdx.x, ty=threadIdx.y, bx=blockIdx.x, by=blockIdx.y;
int rowM=ty+by*blocksize;
int colN=tx+bx*blocksize;
float Pvalue=0;
for(int m=0; m< uWM/blocksize;++m){
MS[ty][tx]=M[rowM*uWM+(m*blocksize+tx)];
NS[ty][tx]=M[colN + uWN*(m*blocksize+ty)];
__syncthreads();
for(int k=0;k<blocksize;k++)
Pvalue+=MS[ty][k]*NS[k][tx];
__syncthreads();
P[rowM*WP+colN]=Pvalue;
}
}
提前致谢!
答案 0 :(得分:5)
我认为最简单的方法就是用零填充最后的块:
for(int m=0; m< uWM/blocksize;++m){
colM = m*blocksize+tx;
rowN = m*blocksize+ty;
if (rowM > uWN || rowN > uWM || colM > uWM || colN > uWN) {
MS[ty][tx]=0.;
NS[ty][tx]=0.;
} else {
MS[ty][tx]=M[rowM*uWM+colM];
NS[ty][tx]=N[colN + uWN*rowN];
}
加或减。 (NS线应该引用N,而不是M,对吗?)
但是,因为我似乎是唯一一个在可能的情况下主张使用现有调优库的人 - 为什么不使用CUBLAS或MAGMA而不是自己动手?它们很快,并经过数百名用户的测试。
答案 1 :(得分:2)
这里的基本性能要求是共享内存“tile”的第一维或第二维是16的舍入倍数 - 历史上这是实现最佳全局内存带宽所必需的(即半翘曲合并事务) 。它是否应该是图块的第一维或第二维是由矩阵是按行还是按主要顺序存储来决定的。没有什么可说共享内存块需要是正方形的,只是存储的前导维度(BLAS表示法中的LDA)是16的圆倍数。
您可以使用tile维度作为模板参数轻松地模拟内核,并根据矩阵维度实例化多个版本。对于给定的体系结构,可能存在最佳的平铺维度,其平衡占用率和指令级并行度。解决这个问题的“聪明”方法可能是将矩阵乘法分解为两个操作 - 第一个以最佳图块大小进行大部分工作,第二个以不同大小进行剩余列。如果结果在产品完成后直接返回到主机内存,则第二个操作可能最好使用优化的BLAS在主机上完成,与GPU内核重叠。这是UTK Magma库中许多例程使用的方法。