我想使用PlaidML加快Mac Pro计算机上的深度学习培训。安装PlaidML之后,我运行“ plaidml-setup”,并收到以下消息:
virtual ToString()
为什么说这是“实验装置”?在Mac Pro上配置PlaidML是否正常?
我应该单击“是”继续设置吗?
编辑: 单击“是”后,系统将显示另一组选项:
检测到多个设备(您可以通过设置PLAIDML_DEVICE_IDS进行覆盖)。 请选择默认设备:
PlaidML Setup (0.3.5)
Thanks for using PlaidML!
Some Notes:
* Bugs and other issues: https://github.com/plaidml/plaidml
* Questions: https://stackoverflow.com/questions/tagged/plaidml
* Say hello: https://groups.google.com/forum/#!forum/plaidml-dev
* PlaidML is licensed under the GNU AGPLv3
Default Config Devices:
No devices.
Experimental Config Devices:
llvm_cpu.0 : CPU (LLVM)
opencl_amd_amd_radeon_pro_555_compute_engine.0 : AMD AMD Radeon Pro 555 Compute Engine (OpenCL)
metal_amd_radeon_pro_460.0 : AMD Radeon Pro 460 (Metal)
opencl_intel_intel(r)_hd_graphics_630.0 : Intel Inc. Intel(R) HD Graphics 630 (OpenCL)
opencl_cpu.0 : Intel CPU (OpenCL)
metal_intel(r)_hd_graphics_unknown.0 : Intel(R) HD Graphics Unknown (Metal)
Using experimental devices can cause poor performance, crashes, and other nastiness.
Enable experimental device support? (y,n)[n]:
我应该选择哪个?还是没关系?
答案 0 :(得分:0)
您正在运行什么版本的macOS?机器是哪一年?我怀疑对于较旧的计算机或macOS <10.14,您没有看到默认值,因为PlaidML遵循了Apple的deprecation of OpenGL/CL in 10.14 in favor of Metal。
FWIW,在我的机器上,我看到了类似的选项,除了金属设备列在“默认配置设备”下。
对于每个选项简明(好吧,也许我被带走了)解释:
您可以在CPU或GPU上训练/运行ML模型。 CPU不太适合ML应用程序中常见的矩阵数学流水线。现代CPU具有Streaming SIMD Extensions(SIMD表示 S 单 I n指令 M 多张 D ata)或SSE 。这些允许您执行一组更有限的类似矩阵的操作。例如,当添加两个向量而不是考虑每对元素并一一添加时,SIMD允许您一次添加许多数字。例如,compiling the following code with clang -O3 -march=native
:
#include <array>
auto add(std::array<float, 64> a, std::array<float, 64> b) {
std::array<float, 64> output;
for (size_t i = 0; i < 64; i++) {
output[i] = a[i] + b[i];
}
return output;
}
根据我们是否通过-mno-sse
(您可能会猜到,它会生成可在不带SSE的CPU上运行的二进制文件),可以看到两种不同的编译。使用SSE:
add(std::array<float, 64ul>, std::array<float, 64ul>):
mov rax, rdi
vmovups zmm0, zmmword ptr [rsp + 8]
vaddps zmm0, zmm0, zmmword ptr [rsp + 264]
vmovups zmmword ptr [rdi], zmm0
vmovups zmm0, zmmword ptr [rsp + 72]
vaddps zmm0, zmm0, zmmword ptr [rsp + 328]
vmovups zmmword ptr [rdi + 64], zmm0
vmovups zmm0, zmmword ptr [rsp + 136]
vaddps zmm0, zmm0, zmmword ptr [rsp + 392]
vmovups zmmword ptr [rdi + 128], zmm0
vmovups zmm0, zmmword ptr [rsp + 200]
vaddps zmm0, zmm0, zmmword ptr [rsp + 456]
vmovups zmmword ptr [rdi + 192], zmm0
vzeroupper
ret
没有SSE:
add(std::array<float, 64ul>, std::array<float, 64ul>):
mov rax, rdi
lea rcx, [rsp + 264]
lea rdx, [rsp + 8]
xor esi, esi
.LBB0_1:
fld dword ptr [rdx + 4*rsi]
fadd dword ptr [rcx + 4*rsi]
fstp dword ptr [rax + 4*rsi]
fld dword ptr [rdx + 4*rsi + 4]
fadd dword ptr [rcx + 4*rsi + 4]
fstp dword ptr [rax + 4*rsi + 4]
fld dword ptr [rdx + 4*rsi + 8]
fadd dword ptr [rcx + 4*rsi + 8]
fstp dword ptr [rax + 4*rsi + 8]
fld dword ptr [rdx + 4*rsi + 12]
fadd dword ptr [rcx + 4*rsi + 12]
fstp dword ptr [rax + 4*rsi + 12]
fld dword ptr [rdx + 4*rsi + 16]
fadd dword ptr [rcx + 4*rsi + 16]
fstp dword ptr [rax + 4*rsi + 16]
fld dword ptr [rdx + 4*rsi + 20]
fadd dword ptr [rcx + 4*rsi + 20]
fstp dword ptr [rax + 4*rsi + 20]
fld dword ptr [rdx + 4*rsi + 24]
fadd dword ptr [rcx + 4*rsi + 24]
fstp dword ptr [rax + 4*rsi + 24]
fld dword ptr [rdx + 4*rsi + 28]
fadd dword ptr [rcx + 4*rsi + 28]
fstp dword ptr [rax + 4*rsi + 28]
add rsi, 8
cmp rsi, 64
jne .LBB0_1
ret
您不需要深入了解这里发生的事情,但是请注意,SSE二进制文件中以v
开头的指令。这些是AVX指令。 zmm0
是一个AVX寄存器,可以容纳16个float
(AVX-512提供512位寄存器,float
是32位)。 LLVM利用了这一优势,而不是逐个元素地添加数字(就像我们在原始代码中所写的那样),而是一次执行16个。您会看到以下程序集的4个变体,一个接一个(注意括号内的数学):
vmovups zmm0, zmmword ptr [rsp + (8 + 64*N)]
vaddps zmm0, zmm0, zmmword ptr [rsp + (8 + 4*64 + 64*N)]
vmovups zmmword ptr [rdi + (64*N)], zmm0
这里的数学需要对System V call ABI有所了解。简而言之,请忽略8 +
。 [rsp + 64*N]
使您a[16*N]
成为a[16*(N+1)]
的专属用户。 [rsp + (4*64 + 64*N)]
跳过所有a
(a
是64个floats
,每个大小为4个字节),并使您从b[16*N]
到b[16*(N+1)]
,排他。并且[rdi + (64*N)]
是output[16*N]
至output[16*(N+1)]
的唯一对象。因此,这有效地转换为以下伪代码:
std::array<float, 16> temp = {a[16*N], a[16*N+1], ..., a[16*N+16]};
temp += {b[16*N], b[16*N+1], ..., b[16*N+16]};
{output[16*n], output[16*N+1], ..., output[16*N+16]} = temp;
因此,确实,我们看到AVX-512(SIMD的扩展)使我们能够一次以16个数字的块进行加法。快速将其与-mno-sse
版本进行比较。应该清楚的是,它正在做更多的工作。同样,我们有一种指令模式(尽管这次是循环的):
fld dword ptr [rdx + 4*rsi + 4*N]
fadd dword ptr [rcx + 4*rsi + 4*N]
fstp dword ptr [rax + 4*rsi + 4*N]
其中有八个(N
的范围从0到8,不包括在内)。它被包裹在一个循环中,该循环重复8次(8 * 8 = 64,数组长度)。您应该能够猜测这里发生了什么。它与上面的非常相似,除了我们一次处理一个数字而不是16。fld
与vmovups
类似,fadd
与vaddps
类似。伪代码看起来更像我们实际编写的代码:
float temp = a[loop_num*8 + N];
temp += b[loop_num*8 + N];
output[loop_num*8] = temp;
希望直觉上,一次执行16项比每次执行1项效率更高。
还有blas之类的花哨的线性代数框架,它们可以压缩您在数学方面从CPU可以获得的几乎所有性能。
GPU的工作方式略有不同。总体简化是将GPU视为具有巨大SIMD指令(特别适合于浮点运算)的设备。因此,想象一下一次只处理一张完整的图像,而不是一次处理16张,并且一次操作就可以对其应用像素滤镜(例如更改亮度或饱和度)。
那么该切线与什么有关系?
AVX指令使在CPU上运行某些代码有些合理。您在其中带有_cpu
时看到的所有选项将仅在CPU上运行。 llvm_cpu
将使用与上面使用的clang
类似的技术(clang
在后台使用llvm)来编译运行/训练ML模型所需的所有数学运算。鉴于现代CPU是多核的,因此可以达到16 * number_of_cores
加速。
OpenCL is an open standard用于编写数学计算并轻松地在各种硬件(包括GPU)上运行它们。 CPU还可以模拟OpenCL(诚然,速度要慢得多-记住CPU只能做16倍,GPU可以做很多)。
Metal是Apple的OpenGL / CL的替代品。它完成了类似的工作,但特定于macOS(且为封闭源)。
要评论的唯一区别是“Intel®HD Graphics 630”和“ AMD Radeon 460”。您的计算机有两个GPU。第一个是集成显卡。这里的集成意味着您的Intel CPU内嵌了一个小GPU。它的性能不如独立的GPU(一个独立于CPU often found in card form factors for desktops的GPU),但是它可以完成某些强度较低的图形任务(通常更省电)。您的AMD Radeon 460是独立的GPU。这可能是您完成此任务最强大的硬件。
因此,我谨记这些设备将是最快到最慢的设备:
metal_amd_radeon_pro_460.0
-离散GPU速度很快,Apple优化了Metal,使其在新Mac上可以很好地运行opencl_amd_amd_radeon_pro_555_compute_engine.0
-它仍然使用离散GPU,但是OpenCL稍有被忽略,现在已在macOS上弃用,因此它可能不会很快。 metal_intel(r)_hd_graphics_unknown.0
-集成GPU比CPU更好,Apple对Metal进行了优化opencl_intel_intel(r)_hd_graphics_630.0
-与其他OpenCL相同(除了这是集成的非离散GPU)llvm_cpu.0
-使用CPU,但是LLVM非常擅长编写高效的SIMD代码。opencl_cpu.0
-这模拟(2)和(4),但使用CPU的速度要慢得多。另外,它可能没有LLVM用于输出有效SIMD代码的所有花哨算法。但是所有这些都是推测,您可以通过pip install plaidbench plaidml-keras keras
对其进行测试。对于每个设备,运行plainml-setup
(选择该设备),然后运行plainbench keras mobilenet
(或其他任何基准测试)。这是我在计算机上看到的结果:
| device | exeuction (s) | fps | correctness |
|------------------------------|---------------|--------|-------------|
| Metal AMD Radeon Pro 560 | 9.009 | 112.53 | PASS |
| OpenCL AMD Radeon Pro 560 | 18.339 | 93.29 | PASS |
| OpenCL Intel HD Graphics 630 | 23.204 | 60.18 | FAIL |
| Metal Intel HD Graphics 630 | 24.809 | 41.27 | PASS |
| LLVM CPU | 66.072 | 16.82 | PASS |
| OpenCL CPU Emulation | 155.639 | 6.71 | FAIL |
我已经将设备重命名为更漂亮的名称,但是它们到标识符的映射应该很明显。
执行时间是模型运行所花费的时间(越低越好),而FPS是执行所获得的FPS(越好越好)。
我们注意到订单通常是我们所期望的。离散GPU比集成GPU更快,而集成GPU则比CPU更快。需要指出的重要一点是,集成GPU和CPU仿真上的OpenCL无法通过正确性检查。 CPU仿真仅下降了约7%,而集成GPU下降了约77%。您可能只想选择通过计算机上正确性检查的设备(如果但不能保证,如果后端或设备本身未通过检查,则可能是错误的)。
tl; dr使用金属+离散GPU(AMD Radeon)。这是您拥有的最快的设备。使用任何基于CPU的设备只会使您的风扇旋转,并消耗大量的功率(并花费大量时间来完成/训练)。
答案 1 :(得分:0)
是的,您绝对需要实验支持才能使用PlaidML。之后,您要选择
3: metal_amd_radeon_pro_460.0
或任何带有“ metal”和“ radeon”的字样(或NVIVIA,如果您愿意的话)。使用Intel UHD图形(即使您可以选择6 : metal_intel(r)_hd_graphics_unknown.0
也没什么意义,因为它不如独立的GPU。
Apple已不赞成使用OpenCL,而推荐使用Apple的Metal框架,最近,OpenCL的格子设置在plaidbench
上出现Fail错误。例如,如果您使用opencl
驱动程序,则在运行
Fail
错误
plaidbench keras mobilenet
您很有可能会使用Success
驱动程序来获得metal
。