MATLAB博客

给处于领先地位的人的实用建议

如何通过改变两行来制作这个MATLAB程序的GPU版本

在他的文章中, 人生小游戏 , Steve Eddins向我们展示了以下几行实现的代码 康威的人生游戏 .史蒂夫的版本使用了750 x 750的游戏板,而我使用的是2000 x 2000,因为我想要一些有肉的东西来计算
清晰的清除所有变量
抽搐
Im = rand(2000,2000)>0.8;
k = 1:50 0
T = conv2(im(:,:,k),[2,2,2;2,1,2;2,2,2],,“相同”);
Im (:,:,1,k+1) = (t > 4) & (t < 8);
结束
OriginalTime = toc
OriginalTime = 39.4715
正如史蒂夫向我们展示的,这非常容易变成一个动画动图。因为我的游戏板太大了,所以我只放大它的一小部分
imwrite (~ im(1∶1∶1,:)“Life.gif”“延迟时间”, 0.02,“LoopCount”正)
life.gif
快速编写代码的第一步:预分配
我痴迷于MATLAB编程语言的速度,想知道是否有什么可以用这几行来加快它们的速度,而不太破坏它们的优雅。
让我们从简单的东西开始:预分配输出数组, 即时通讯
清晰的清除所有变量
抽搐
Im = 0 (2000,2000,1,501,“逻辑”);
Im (:,:,1,1) = rand(2000,2000) > 0.8;
k = 1:50 0
T = conv2(im(:,:,k),[2,2,2;2,1,2;2,2,2],,“相同”);
Im (:,:,1,k+1) = (t > 4) & (t < 8);
结束
PreallocatedTime = toc
PreallocatedTime = 14.2942
超过2倍的速度为一个额外的线和一个修改线。不错,但我还能继续吗?
将许多MATLAB代码从CPU实现转移到GPU实现非常容易!
我的电脑有一个很好的NVIDIA图形处理器,我可以使用 并行计算工具箱
gpuDevice ()
ans =
CUDADevice与属性:名称:'NVIDIA GeForce RTX 3070'索引:1 ComputeCapability: '8.6' SupportsDouble: 1 Driv金宝apperVersion: 11.6000 ToolkitVersion: 11.2000 MaxThreadsPerBlock: 1024 MaxShmemPerBlock: 49152 MaxThreadBlockSize: [1024 1024 64] MaxGridSize: [2.1475e+09 65535 65535] SIMDWidth: 32 TotalMemory: 8.5894e+09 AvailableMemory: 7.2939e+09 MultiprocessorCount: 46 ClockRateKHz: 1725000 ComputeMode: 'Default' GPUOverlapsTransfers: 1 KernelExecutionTimeout: 1 CanMapHostMemory:1 Device金宝appSupported: 1 DeviceAvailable: 1 DeviceSelected: 1
GPU非常适合做这种事情,但是编写一个GPU版本会很困难,对吧?硬核CUDA编码的深夜等待着你。
但还有另一种方法!
超过 1000个MATLAB函数 (包括官方工具箱中的工具)都“重载”了 gpuArray 数据类型。这在实践中意味着,虽然这段代码在CPU上运行:
A = rand(3);
B = rand(4);
Cfull = conv2(A,B)
Cfull = 6×6
0.2357 0.1997 0.7748 0.4111 0.5196 0.0080 0.2237 0.4145 1.3158 1.2236 0.0201 0.6943 0.7811 2.3386 1.8777 1.5679 0.0412 0.3726 0.9340 2.2665 2.3125 1.7186 0.5522 0.5210 0.8183 1.7277 1.9970 1.4909 0.8490 0.2133 0.8088 1.2790 1.8410 1.2599 0.5397
这段代码运行在GPU上:
gpuA = gpuArray(A);%将A传输到图形处理器,命名为gpuA
gpuB = gpuArray(B);%将B传输到图形处理器,命名为gpuB
Cfull_gpu = conv2(gpuA,gpuB)现在运行在GPU上
Cfull_gpu = 0.2357 0.1997 0.7748 0.4111 0.5196 0.0080 0.2237 0.4145 1.3158 1.0064 1.2236 0.0201 0.6943 0.7811 2.3386 1.8777 1.5679 0.0412 0.3726 0.9340 2.2665 2.3125 1.7186 0.5522 0.5210 0.8183 1.7277 1.9970 1.4909 0.8490 0.2133 0.8088 1.2790 1.8410 1.2599 0.5397
所有你需要做的是为了使超过1000个MATLAB函数在NVIDIA GPU上工作是并行计算工具箱,它允许你给出它们 gpuArray S而不是普通数组。
你是否真的会得到加速取决于许多因素,但要开始,简单地让事情在GPU而不是CPU上运行,这就是它!
回到Steve的代码。我需要做的是改变的初始化 即时通讯 到一个 gpuArray 一切都会自动在GPU上运行。这就是我的改变
Im = 0 (2000,2000,1,501,“逻辑”);
Im (:,:,1,1) = rand(2000,2000) > 0.8;
Im = 0 (2000,2000,1,501,“逻辑”“gpuArray”);
Im (:,:,1,1) = rand(2000,2000,“gpuArray”) > 0.8;
让我们试一试
清晰的清除所有变量
dev = gpuDevice();
抽搐
Im = 0 (2000,2000,1,501,“逻辑”“gpuArray”);
Im (:,:,1,1) = rand(2000,2000,“gpuArray”) > 0.8;
k = 1:50 0
T = conv2(im(:,:,k),[2,2,2;2,1,2;2,2,2],,“相同”);
Im (:,:,1,k+1) = (t > 4) & (t < 8);
结束
等待(dev);
GpuTime = toc
GpuTime = 5.3013
几乎比使用预分配数组的CPU版本快3倍,比原始版本快约7倍!考虑到我只修改了2行代码,这还不错。此外,这是我所写过的最简单的GPU模拟“移植”
现在,我相信有CUDA专家可以做得比这更好——从糟糕的过度工作的GPU中挤出每一滴性能可能——但是用这么少的工作将速度提高3倍已经很不错了,MATLAB生态系统中有几个选项可以让你更深入地探索其他方法。

wait(dev)发生了什么?

眼尖的人可能已经注意到我的GPU版本中有几行我还没有提到的额外代码。就在我们说话的时候,我能感觉到你伸手去拿评论按钮,告诉我我骗了你....我改了四行,不是两行!这里有两句话,我很方便地选择了不告诉你
这些线条的原因都与时间有关。你看,当你要求在GPU上完成一个计算时,MATLAB就会开始工作,然后移动到下一行 无需等待GPU完成计算。 这可以用于一些非常漂亮的代码交织,在这里你可以让CPU和GPU同时运行,但如果你使用它也会打乱时间 抽搐/ toc .GPU代码的计时可能会很棘手,这就是为什么MathWorks还会给你 gputimeit 命令。
如果我想做的只是运行代码,而不是计时,那么我就不需要为这两行额外的代码而烦恼。所以我说的都是真的…从某种角度来看。

系统细节

  • MATLAB R2022a
  • CPU:第11代英特尔(R)酷睿(TM) i7-11700 @ 2.50GHz
  • GPU: NVIDIA GeForce RTX 3070
  • 操作系统:Windows 11

轮到你了

你有没有一些代码可以很容易地运行在这样的GPU上,并显示出性能的提升?
|

コメント

コメントを残すには,ここをクリックしてMathWorksアカウントにサインインするか新しいMathWorksアカウントを作成します。