矩阵运算是现代科学计算和机器学习的基础操作。从图像处理到神经网络训练,矩阵乘法、转置、求逆等操作无处不在。传统上这些计算都由CPU完成,但随着数据规模膨胀,CPU的串行计算模式逐渐暴露出性能瓶颈。
我曾在处理一个2000×2000的矩阵乘法时,发现即使使用多线程优化,CPU完成计算仍需近10秒。而当我将同样的计算迁移到一块中端游戏显卡上时,计算时间骤降至0.2秒。这个50倍的性能差距促使我深入研究GPU并行计算的奥秘。
现代CPU是典型的"大而全"设计:
这种设计擅长处理:
GPU则采用截然不同的架构:
这种架构专为以下场景优化:
关键洞察:CPU像是一个博学教授,能快速解决各种复杂问题;GPU则像一支军队,擅长用数量碾压简单但大规模的任务。
线程层次结构:
内存模型:
c复制__global__ void matMul(float *A, float *B, float *C, int N) {
// 每个线程计算C的一个元素
int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if(row < N && col < N) {
float sum = 0;
for(int k=0; k<N; k++) {
sum += A[row*N + k] * B[k*N + col];
}
C[row*N + col] = sum;
}
}
执行配置:
c复制// 启动配置示例:16x16的block,共(N/16)x(N/16)个block
dim3 blocks(N/16, N/16);
dim3 threads(16, 16);
matMul<<<blocks, threads>>>(d_A, d_B, d_C, N);
基础实现到优化版本的性能对比:
| 优化策略 | 2048x2048矩阵耗时(ms) | 加速比 |
|---|---|---|
| 原生CPU实现 | 10240 | 1x |
| 基础CUDA实现 | 210 | 48x |
| 共享内存优化 | 85 | 120x |
| 寄存器优化 | 62 | 165x |
| Tensor Core使用 | 18 | 568x |
CPU平台:
GPU平台:
使用以下矩阵规模进行测试:
测试操作包括:
矩阵乘法耗时对比(单位:ms):
| 矩阵规模 | CPU | GPU | 加速比 |
|---|---|---|---|
| 256x256 | 12.5 | 0.8 | 15.6x |
| 1024x1024 | 620 | 6.4 | 96.8x |
| 4096x4096 | 45200 | 210 | 215.2x |
内存带宽利用率对比:
经典矩阵乘法优化技巧:
c复制__global__ void matMulShared(float *A, float *B, float *C, int N) {
__shared__ float sA[16][16];
__shared__ float sB[16][16];
int bx = blockIdx.x, by = blockIdx.y;
int tx = threadIdx.x, ty = threadIdx.y;
int row = by * 16 + ty;
int col = bx * 16 + tx;
float sum = 0;
for(int m=0; m<N/16; ++m) {
sA[ty][tx] = A[row*N + (m*16+tx)];
sB[ty][tx] = B[(m*16+ty)*N + col];
__syncthreads();
for(int k=0; k<16; ++k) {
sum += sA[ty][k] * sB[k][tx];
}
__syncthreads();
}
C[row*N + col] = sum;
}
低效的实现:
c复制if(row % 2 == 0) {
// 偶数行处理
} else {
// 奇数行处理
}
高效的做法是让相邻线程处理连续内存地址,确保所有线程执行相同指令。
访问模式对比:
A[row*N + col](跨行访问导致非合并)A[col*N + row](连续访问)适用场景:
不适用场景:
PCIe传输瓶颈:
线程块配置不当:
同步开销过大:
__syncthreads()耗时约50时钟周期混合计算框架示例:
python复制# 使用CuPy进行异构计算
import cupy as cp
import numpy as np
# 大数据留在GPU
x_gpu = cp.random.rand(10000, 10000)
# 小数据在CPU处理
def cpu_process(data):
return np.sum(data, axis=0)
# 自动内存传输
result = cpu_process(x_gpu.get()) if x_gpu.shape[0] < 1000 else cp.sum(x_gpu, axis=0)
性能平衡策略: