基于GPU的模板处理

此示例演示如何通过实现John H.Conway的“生命游戏”,为模具类型操作生成CUDA®内核。

“生命游戏”是一个零玩家细胞自动机由一组细胞组成的游戏(人口)在矩形网格(宇宙).细胞以离散的时间步进化,称为一代又一代.一套应用于细胞及其邻近细胞的数学规则控制它们的生、死和繁殖。这个“生活游戏”的实现是基于电子书中提供的示例MATLAB中的实验由Cleve Moler提供。实施遵循以下规则:

  • 单元排列在二维网格中。

  • 在每一步中,每个细胞的八个近邻的生命力决定了它的命运。

  • 任何有三个邻居的细胞在下一步就会有生命。

  • 一个有两个邻居的活细胞在下一步仍然是活的。

  • 所有其他单元格(包括有三个以上邻居的单元格)都会在下一步死亡或保持空状态。

下面是一些单元格如何更新的示例。

许多数组操作可以表示为钢网操作,其中输出数组的每个元素依赖于输入数组的一个小区域。本例中的模具是每个单元周围的3×3区域。有限差分、卷积、中值滤波和有限元方法是模板处理可以执行的其他操作的示例。

先决条件

  • CUDA®支持NVIDIA®GPU,具有3.2或更高的计算能力。

  • NVIDIA CUDA工具包和驱动程序。

  • 编译器和库的环境变量。有关编译器和库支持的版本的信息,请参见万博1manbetx第三方产品s manbetx 845. 有关设置环境变量的信息,请参见设置前提产品s manbetx 845

验证GPU环境

要验证运行此示例所需的编译器和库是否正确设置,请使用coder.checkGpuInstall函数。

envCfg=coder.gpuEnvConfig(“主持人”);envCfg。BasicCodegen = 1;envCfg。安静= 1;coder.checkGpuInstall (envCfg);

生成一个随机初始总体

由于游戏是零玩家,游戏的演化由其初始状态决定。例如,在二维网格上创建初始细胞群,约25%的位置处于活动状态。

gridSize = 500;numGenerations = 100;initialGrid = (rand(gridSize,gridSize) > .75);%绘制初始网格显示亮度图像(initialGrid);Colormap ([1 1 1;0 0.5 0]);标题(“初始网格”);

玩人生游戏

原始生命的游戏函数是“Game of Life”的完全矢量化实现。该函数每次生成一个单元格就更新网格上的所有单元格。

类型生命起源游戏
%%MATLAB矢量化实现函数网格=gameoflife_orig(initialGrid)%2016-2019版权所有MathWorks,Inc.numGenerations=100;网格=初始网格;[gridSize,~]=大小(初始网格);%循环通过每一代更新网格并显示它。对于generation=1:numGenerations grid=updateGrid(grid,gridSize);imagesc(网格);彩色地图([11;0.50]);标题([“迭代时的网格”,num2str(生成)];现在抽;end function X=updateGrid(X,N)%Index向量将中心索引增加或减少1%,从而访问左、右、上和下的邻居。p=[11:N-1];q=[2:N];%数一数八个邻居中有多少人还活着。邻居=X(:,p)+X(:,q)+X(p,:)+X(q,:)+。。。X(p,p)+X(q,q)+X(p,q)+X(q,p);%具有两个活动邻居的活动单元或具有%3个活动邻居的任何单元在下一步处于活动状态。X=(X&(邻居==2))|(邻居==3);结束

通过调用。来玩游戏生命起源游戏具有初始总体的函数。游戏会在100代中迭代,并在每一代中显示人口。

gameoflife_orig (initialGrid);

转换游戏的生命为GPU代码生成

看一下updateGrid函数时,显然相同的操作分别应用于每个网格位置。然而,每个细胞必须知道它的八个邻居。修改后的gameoflife_模具函数使用gpucoder.stencilKernelPragma计算每个单元格周围的3 × 3区域。模板内核的GPU编码器™实现在每个线程中计算网格的一个元素,并使用共享内存来改善内存带宽和数据局域性。

类型gameoflife_stencil
function grid = gameoflife_stencil(initialGrid) %#codegen % Copyright 2016-2019 The MathWorks, Inc. numGenerations = 100;网格= initialGrid;%循环每代更新网格。for generation = 1:numGenerations grid = gpucoder. for generation = 1:numGenerationsstencilKernel(@updateElem, grid, [3,3], 'same');X = updateElem(window) [winH, winW] = size(window);邻居= 0;for wh = 1:winH neighbors = window(1,1) + window(1,2) + window(1,3)…+ window(2,1) + window(2,3)…+ window(3,1) + window(3,2) + window(3,3);end end X = (window(2,2) & (neighbors == 2))) | (neighbors == 3); end

为函数生成CUDA MEX

要生成CUDA MEX,请执行以下操作:gameoflife_stencil函数,创建GPU代码配置对象,然后使用codegen命令。

cfg = coder.gpuConfig (墨西哥人的);评估('codegen -config cfg -args {initialGrid} gameoflife_stencil');

运行MEX命令

运行生成的gameoflife_stencil_mex随机初始总体。

gridGPU = gameoflife_stencil_mex (initialGrid);%100代后绘制网格显示亮度图像(gridGPU);Colormap ([1 1 1;0 0.5 0]);标题(“最终网格-CUDA MEX”);

结论

CUDA代码是为一个简单的模具操作生成的,康威的“生命游戏”gpucoder.stencilKernel您可以使用本例中显示的技术来实现一系列模板操作,包括有限元算法、卷积和过滤器。