这学期选了一门 Large Scale Computing Systems 的课,名字很高大上,其实讲的就是GPU原理/编程和并行计算。本来是想好好学一波的,无奈老师讲的实在太烂,课件也不清楚,只能在网上各种查阅资料学习,先分享一波个人觉得讲的很好的课件,也是本篇文章内容的主要来源(论Tokyo Tech和CalTech的差距):
CS 179: GPU Programmingcourses.cms.caltech.edu一、GPU与并行计算
从GPU的全称Graphic Processing Unit(图形处理单元)就可以看出来,GPU诞生之初是为了处理图像。我们知道,在游戏中,往往有着比较复杂的光影变幻,而计算机中显示的图像是由一个个像素点组成的。因此,这些光影变幻的实质就是对图像中的每个像素点做一个函数变幻。而如果使用并行能力不足的CPU计算,我们往往就需要时间来顺序计算每个像素点,这样就会造成游戏图像的延迟,导致游戏变得不好玩(x)。因此,索尼公司于1994年在PlayStation上首次引入了GPU的概念。有趣的是,起初为了游戏而开发的GPU后来却在科学研究领域发扬光大。
GPU大幅加速了大规模的矩阵计算。以我目前的水平看来,目前GPU并行计算应用最多的领域有:
1. 图像领域,包括传统的图像处理、计算机视觉,以及GPU的起源游戏领域。这些都是最适合GPU进行并行计算的地方。我们现在能够流畅地玩到各种3A游戏大作,都是得益于GPU的并行计算能力;
2. 深度学习,也是我目前的研究领域(说来惭愧,之前对CUDA的了解仅限于调用API上)。神经网络的逐层计算和数据、参数可以被向量化的特性使其特别适合并行化运算。
二、基于CUDA的GPU编程:概念
GPU的本质是超级多核的计算单元,但是它并不像CPU有很大的内存单元,因此计算时往往需要先从CPU上读取数据,在GPU进行并行计算后再将结果返回给GPU。下面我结合CUDA函数简要描述一下操作流程。
- 分配内存 CudaMalloc():在GPU上开辟临时内存。
- 转移数据 CudaMemcpy():将主内存的数据转移到GPU的临时内存中。
- 调用CUDA内核进行并行计算 CUDA Kernal Invocation。
- 转移数据 CudaMemcpy():将GPU临时内存中的数据(计算结果)转移回主内存中。
- 释放内存 CudaFree():释放GPU上的临时内存。
三、实例:计算矩阵乘积
任务:给定两个N×N的矩阵A[][]和B[][],计算它们的乘积C[][]。
首先我们看一下非并行的C程序:
void MatrixMult(float *A, float *B, float *C, int N)
{
for(int i=0; i<N; ++i) {
for(int j=0; j<N; ++j) {
sum = 0.0;
for(int k=