单 GPU 计算
随着每代新产品的发展,GPU 卡的内核数量、内存大小和速度效率都在快速增长。视频游戏长期受益于改进的 GPU 性能。现在,这些卡足够灵活,可以执行一般的数值计算任务,例如训练神经网络。
有关最新 GPU 要求的信息,请参阅 Parallel Computing Toolbox 的网页;或者查询 MATLAB 以确定您的 PC 是否有支持的 GPU。此函数返回系统中 GPU 的数量:
count = gpuDeviceCount
count =
1
如果结果是一个或多个,您可以通过索引查询每个 GPU 的特征。这包括它的名称、多处理器的数量、每个多处理器的 SIMDWidth 以及总内存。
gpu1 = gpuDevice(1)
gpu1 =
CUDADevice with properties:
Name: 'GeForce GTX 470'
Index: 1
ComputeCapability: '2.0'
SupportsDouble: 1
DriverVersion: 4.1000
MaxThreadsPerBlock: 1024
MaxShmemPerBlock: 49152
MaxThreadBlockSize: [1024 1024 64]
MaxGridSize: [65535 65535 1]
SIMDWidth: 32
TotalMemory: 1.3422e+09
AvailableMemory: 1.1056e+09
MultiprocessorCount: 14
ClockRateKHz: 1215000
ComputeMode: 'Default'
GPUOverlapsTransfers: 1
KernelExecutionTimeout: 1
CanMapHostMemory: 1
DeviceSupported: 1
DeviceSelected: 1
利用 GPU 的最简单方法是指定在参数 'useGPU' 设置为 'yes'('no' 为默认值)的情况下调用 train 和 sim。
net2 = train(net1,x,t,'useGPU','yes')
y = net2(x,'useGPU','yes')
如果 net1 具有默认的训练函数 trainlm,您会看到一条警告,指出 GPU 计算不支持 Jacobian 矩阵训练,仅支持梯度训练。因此,训练函数自动更改为梯度训练函数 trainscg。为避免出现该通知,您可以在训练前指定该函数:
net1.trainFcn = 'trainscg';
要验证训练和仿真是否在 GPU 设备上进行,请要求显示计算机资源:
net2 = train(net1,x,t,'useGPU','yes','showResources','yes')
y = net2(x,'useGPU','yes','showResources','yes')
以上每行代码都输出以下资源摘要:
Computing Resources:
GPU device #1, GeForce GTX 470
当任一输入参数是 gpuArray 时,许多 MATLAB 函数会自动在 GPU 上执行。通常情况下,您可以使用 gpuArray 和 gather 函数在 GPU 之间来回移动数组。然而,为了在 GPU 上高效进行神经网络计算,需要转置矩阵和填充列以使每列中的第一个元素在 GPU 内存中正确对齐。Deep Learning Toolbox 提供一个名为 nndata2gpu 的特殊函数,它可将数组移至 GPU 上并对其进行适当的组织:
xg = nndata2gpu(x);
tg = nndata2gpu(t);
现在,您可以使用已在 GPU 上转换的数据来训练和仿真网络,而不必指定 'useGPU' 参数。然后使用补充函数 gpu2nndata 转换生成的 GPU 数组并将其返回给 MATLAB。
在使用 gpuArray 数据进行训练之前,必须使用 configure 函数,用常规的 MATLAB 矩阵手动配置网络的输入和输出:
net2 = configure(net1,x,t); % Configure with MATLAB arrays
net2 = train(net2,xg,tg); % Execute on GPU with NNET formatted gpuArrays
yg = net2(xg); % Execute on GPU
y = gpu2nndata(yg); % Transfer array to local workspace
在 GPU 和其他可能需要部署神经网络的硬件上,通常情况下指数函数 exp 不是用硬件实现的,而是用软件库实现的。这可能减慢使用 tansig sigmoid 传递函数的神经网络的运行速度。另外还有 Elliot sigmoid 函数,其表达式不包括对任何更高阶函数的调用:
(equation)a = n / (1 + abs(n))
在训练前,网络的 tansig 层可转换为 elliotsig 层,如下所示:
for i=1:net.numLayers
if strcmp(net.layers{i}.transferFcn,'tansig')
net.layers{i}.transferFcn = 'elliotsig';
end
end
现在,训练和仿真可能在 GPU 上更快,部署硬件更简单。