2

我想使用 PlaidML 在我的 Mac Pro 计算机上加速深度学习训练。安装 PlaidML 后,我运行“plaidml-setup”,并收到以下消息:

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]:

为什么说这是“实验设备”?在 Mac Pro 上配置 PlaidML 是否正常?

我应该单击“是”继续设置吗?

编辑:单击“是”后,我看到了另一组选项:

检测到多个设备(您可以通过设置 PLAIDML_DEVICE_IDS 覆盖)。请选择默认设备:

1 : llvm_cpu.0
   2 : opencl_amd_amd_radeon_pro_555_compute_engine.0
   3 : metal_amd_radeon_pro_460.0
   4 : opencl_intel_intel(r)_hd_graphics_630.0
   5 : opencl_cpu.0
   6 : metal_intel(r)_hd_graphics_unknown.0

Default device? (1,2,3,4,5,6)[1]:

我应该选择哪一个?还是没关系?

4

2 回答 2

2

您运行的是哪个版本的 macOS?机器是哪年的?我怀疑对于较旧的机器或 macOS < 10.14,您看不到默认设置,因为 PlaidML 已经注意到 Apple在 10.14 中弃用 OpenGL/CL 以支持 Metal

FWIW,在我的机器上,我看到了类似的选项,除了金属设备列在“默认配置设备”下。

至于这些选项中的每一个(好吧,也许我被带走了)解释说:

您可以在 CPU 或 GPU 上训练/运行 ML 模型。CPU 不太适合 ML 应用程序中常见的矩阵数学流水线。现代 CPU 具有流式SIMD扩展(SIMD 表示单指令数据或 SSE 。这些允许您执行一组更有限的类似矩阵的操作。例如,当添加两个向量而不是考虑每对元素并一个接一个地添加它们时,SIMD 允许您一次添加多个数字。例如,使用以下代码编译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 上工作的二进制文件)。与上交所:

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

您不需要深入了解这里发生了什么,但请注意以vSSE 二进制文件开头的指令。这些是AVX指令。并且zmm0是一个可以容纳16s的AVX寄存器float(AVX-512提供512位寄存器,floats是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 调用 ABI的知识。简单地说,忽略8 +. [rsp + 64*N]让你a[16*N]a[16*(N+1)]独家。[rsp + (4*64 + 64*N)]跳过所有a(每个大小为 4 个字节a的 64个)并让您排他。并且是,排他的。所以这有效地转换为以下伪代码:floatsb[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]

其中有 8 个(N范围从 0 到 8,不包含)。这被包裹在一个循环中,该循环重复 8 次(8 * 8 = 64,数组长度)。你应该能够猜到这里发生了什么。它与上面非常相似,只是我们一次处理一个数字而不是 16。fld类似于vmovupsfadd类似于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可能会使用与上述类似的技术clangclang在幕后使用 llvm)来编译运行/训练 ML 模型所需的所有数学。鉴于现代 CPU 是多核的,这可能与16 * number_of_cores加速一样多。

OpenCL 是用于编写数学计算并在各种硬件(包括 GPU)上轻松运行它们的开放标准。OpenCL 也可以由 CPU 模拟(诚然,速度要慢得多——记住 CPU 只能做 16 倍,GPU 可以做更多)。

Metal是 Apple 对 OpenGL/CL 的替代品。它完成了类似的事情,但是是 macOS 特定的(并且是封闭源代码)。

唯一需要评论的区别是“Intel(R) HD Graphics 630”与“AMD Radeon 460”。您的计算机有两个 GPU。第一个是集成显卡。这里的集成意味着您的英特尔 CPU 内部嵌入了一个小 GPU。它的性能不如独立 GPU(与 CPU 分离,通常在台式机的卡外形尺寸中找到),但它可以完成某些不太密集的图形任务(并且通常更节能)。您的 AMD Radeon 460 是独立 GPU。它可能是您为这项任务所拥有的最强大的硬件。

因此,考虑到这一点,我预测这些设备将从最快到最慢:

  1. metal_amd_radeon_pro_460.0- 独立 GPU 速度很快,Apple 优化了 Metal,使其在新 Mac 上运行良好
  2. opencl_amd_amd_radeon_pro_555_compute_engine.0- 这仍然使用独立的 GPU,但 OpenCL 被忽略了一点,现在在 macOS 上已弃用,所以它可能不会那么
  3. metal_intel(r)_hd_graphics_unknown.0- 集成 GPU 优于 CPU,Apple 优化了 Metal
  4. opencl_intel_intel(r)_hd_graphics_630.0- 关于其他 OpenCL 的情况同上(除了这是一个集成的非独立 GPU)
  5. llvm_cpu.0- 这使用 CPU,但 LLVM 非常擅长编写高效的 SIMD 代码。
  6. 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 的东西只会让你的粉丝加速并消耗大量电力(并且需要永远完成/训练)。

于 2019-04-15T14:51:11.457 回答
1

是的,您绝对需要实验性支持才能使用 PlaidML,期间。之后,您要选择

3: metal_amd_radeon_pro_460.0

或任何说“金属”和“radeon”的东西(或 NVIVIA,如果你有它并且更喜欢它)。使用 Intel UHD 显卡(即使您可以选择6 : metal_intel(r)_hd_graphics_unknown.0)没有什么意义,因为它不如独立 GPU。

Apple 已弃用 OpenCL 以支持 Apple 的 Metal 框架,最近 OpenCL 格子设置在plaidbench. 比如你使用了opencl驱动,运行的时候保证会Fail报错

plaidbench keras mobilenet

你很可能会得到Success一个metal司机。

于 2019-09-09T16:00:09.827 回答