x86准备好迎接ACE了吗?

Hacker News Top 新闻

摘要

本文分析了x86生态系统咨询小组提出的新ACE规范,该规范扩展了英特尔的AMX,用于AI矩阵乘法,具有固定块大小和外积指令,并与Arm的SME进行了比较。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/07/14 04:18

# x86 准备好迎接 ACE 了吗? 来源:https://chipsandcheese.com/p/is-x86-ready-to-ace-it CPU 设计必须不断发展,以跟上不断变化的工作负载。有时,这种发展涉及扩展指令集,以高效地表示某些类型的计算。英特尔 AMX 扩展就是这样一个例子。AMX 通过提供一组 2D tile 寄存器和配置寄存器,加速了机器学习工作负载中的矩阵乘法。程序员随后可以配置专用执行单元(“加速器”),以处理这些 tile 寄存器中的矩阵数据。AMX 首次在英特尔的 Sapphire Rapids 服务器 CPU 上实现,配备了 tile 矩阵乘法单元(TMUL)加速器。现在,x86 生态系统咨询小组已经撰写了一份**白皮书**(https://x86ecosystem.org/wp-content/uploads/2026/03/ACE-Whitepaper-v1.pdf)和**规范**(https://x86ecosystem.org/resource/ai-compute-extensions-ace-specification/)来介绍 ACE,它引入了第二种加速器类型。虽然 ACE 是 AMX 中的一个加速器,与 TMUL 并列,但我将把它们称为“AMX”和“ACE”,因为 TMUL 是 AMX 发布时唯一存在的加速器实现,并且至今仍是硬件中唯一可用的 AMX 加速器。文档也倾向于称它们为“AMX”和“ACE”。 AMX TMUL 提供了高度可配置的设置,代码可以为每个 tile 寄存器指定矩阵 tile 参数。例如,tile 寄存器 tmm0 可以设置为一个 16x64 的 INT8 值矩阵,通过指定 16 行和每行 64 字节(“colsb”)。TMUL 矩阵乘法指令(如 TDPBSSD)会考虑 tile 配置,并在指定 tile 之间执行整个矩阵乘法运算。在数据类型方面,AMX TMUL 可以处理 INT8、FP16 和 BF16 值。最新的 TMUL 迭代,实现在 Granite Rapids-D CPU 上,还支持包含 FP16 实部和 FP16 虚部的复数。 [](https://substackcdn.com/image/fetch/$s_!Bo09!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd3cd9f-8e0f-4b70-ab76-eaa93ec32c72_751x361.png) ACE 取消了 tile 寄存器的配置选项,始终将它们视为 64 字节 x 16 行。复数不再支持,但 FP8 加入了进来。在计算方面,ACE 提供外积指令,而不是 AMX 提供的内积指令。 [](https://substackcdn.com/image/fetch/$s_!xAVD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F003e8aa7-55c2-443c-81b1-555057c678a3_1330x920.png) Arm 的可扩展矩阵扩展(SME)及其 SME2 扩展是一个明显的比较对象。这两个 ISA 扩展都旨在 CPU ISA 框架内加速矩阵乘法,提供比集成度较低的加速器(如 GPU)更低的延迟替代方案。然而,这两个 ISA 扩展在多个方面有所不同。ACE 建立在 AMX 之上,并继续使用 AMX 的 8 KB tile 寄存器来存储矩阵值。 相比之下,Arm 的 SME 具有可变的“流式”向量长度(SVL),就像 SVE 的向量长度(VL)一样。SVE 和 SME 的向量长度不必相同,而且通常不同。与 SVE 一样,SME 允许向量长度从 128 位到 2048 位,以 2 的幂增长。 流式向量长度定义了“ZA”存储数组的大小,这是 SME 相当于 AMX tile 寄存器的部分。ZA 存储是一个二维数组,每一边都与 SME 的流式向量长度匹配。因此,ZA 存储容量范围从 128 位流式向量长度时的 256 字节,到最大 2048 位向量长度时的 64 KB。 虽然 AVX512-VNNI 和 AMX 加速**内积**(https://en.wikipedia.org/wiki/Inner_product_space),但 ACE 和 SME 加速**外积**(https://en.wikipedia.org/wiki/Outer_product)。 两个向量 **a** 和 **b** 的内积(或在此特例中的**点积**(https://en.wikipedia.org/wiki/Dot_product))是: \\\(\\mathbf a \\cdot \\mathbf b = \\mathbf a^\\mathsf\{T\} \\mathbf b = \\sum\_\{i=1\}^n a\_i b\_i\\\) 如果你是一位物理学家,你可能通过几何解释学到: \\\(\\mathbf a \\cdot \\mathbf b = \|\\mathbf a\| \\, \|\\mathbf b\| \\cos \\theta\\\) 其中 θ 是向量之间的夹角。另一方面,向量 **a** 和 **b** 的外积(或一般情况下的**张量积**(https://en.wikipedia.org/wiki/Tensor_product))产生一个**秩为 1**(https://en.wikipedia.org/wiki/Rank_(linear_algebra))的矩阵 **C** 如下: \\\(\\mathbf\{a\} \\otimes \\mathbf\{b\} = \\mathbf a \\mathbf b^\\mathsf\{T\} = \\mathbf C = \\begin\{bmatrix\} a\_1b\_1 & a\_1b\_2 & \\dots & a\_1b\_n \\\\ a\_2b\_1 & a\_2b\_2 & \\dots & a\_2b\_n \\\\ \\vdots & \\vdots & \\ddots & \\vdots \\\\ a\_mb\_1 & a\_mb\_2 & \\dots & a\_mb\_n \\end\{bmatrix\} \\\) **C** 的所有列都与 **a** 成比例,这告诉我们它是一个秩为 1 的矩阵,同时也表明矩阵乘法只是外积的和,例如: \\\(\\mathbf C = \\mathbf AB = \\sum\_\{i=1\}^n \\mathbf a\_i^\{row\} \\mathbf b\_i^\{col\}\\\) 事实上,线性代数中的许多运算都可以看作是外积的线性组合,这使得外积成为在处理器中实现的一个自然原语,最明显的例子是矩阵的**奇异值分解**(https://en.wikipedia.org/wiki/Singular_value_decomposition): \\\(\\mathbf M = \\mathbf\{U \\Sigma V\}^\\mathsf\{T\}\\\) 用内积形式理解起来并不简单,但它只是 **U** 和 **V** 的列的外积乘以每个对应奇异值的和,即: \\\(\\sum\_\{i=1\}^\{rank\(A\)\} \(\\mathbf u\_i \\otimes \\mathbf v\_i\) \\sigma\_i\\\) 即使像 FFT 这样不太容易转换为外积形式的算法,也被重新表述为利用 SME 作为加速器。Arm 给出了以下示例,但如果你搜索论文,可以找到各种更有效的方法。 [](https://substackcdn.com/image/fetch/$s_!h6d4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F298f8731-72e2-446c-972a-5c25d18385d8_2048x546.png) 历史上我们主要使用内积,因为这减少了我们需要在寄存器中保存的状态量,而由于寄存器是宝贵资源,这一点一直很重要。 然而,正如我们上面所见,几乎所有线性代数都可以通过两种视角来看待,代码可以轻松地在内积和外积之间转换。SME 利用这一点(https://developer.arm.com/documentation/109246/0101/matmul-fp32--Single-precision-matrix-by-matrix-multiplication/Overview-of-the-matmul-fp32-algorithm)通过外积进行矩阵乘法,ACE 也试图做同样的事情。 模型权重通常被量化到非常小的位宽,以减少内存带宽和容量压力。与 NVIDIA 的 **Tensor Cores**(https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#tcgen05-matrix-shape)不同,ACE 和 SME 在软件中预处理输入向量,因此可以支持几乎任何你能想到的格式,而不仅仅是一组有限的“原生”格式。 量化后的权重被转换为原生支持的数据类型,以利用加速器。ACE 依赖 AVX-512/AVX10 的固定 512 位向量宽度来加速这一转换过程。一个 512 位向量足够大,可以容纳一个查找表,使用 VPERMB 将最多 6 位的数据类型映射到 8 位输出;对于 7 位输入,VPERMI2B 可以将两个 512 位向量寄存器一起用作查找表。 ACE/AVX10.3 中新增的 VUNPACKB 指令可以将 2 到 7 位的元素提取到字节对齐的位置,然后前面提到的向量置换指令可以执行数据类型转换。因此,ACE 通过仅用这三条指令处理 2 到 7 位之间的任何数据类型,提供了一定程度的未来适应性,并且你可以通过软件实现几乎任何你选择的方法。 x86-64 EAG 还希望这种灵活性能让 ACE 硬件应用于超出反量化模型权重的场景,例如数据压缩的码本。 [](https://substackcdn.com/image/fetch/$s_!T_vu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee1558e3-6c48-4940-9b81-87af74817296_1430x278.png)使用 VUNPACKB 和 VPERM\(2I\)B 进行数据转换是一个两步过程,但灵活且可以处理 2 到 7 位的任何输入数据类型 Arm 不能依赖足够宽的向量寄存器来作为数据转换的查找表,因为 SVE 允许实现定义从 128 到 2048 位的流式向量长度。因此,SME2 增加了一个 512 位的 ZT0 寄存器,专门设计用作 16 x 4B 的查找表。LUTI2 和 LUTI4 指令通过解压缩向量寄存器中的 2 位或 4 位索引值,在 ZT0 中查找它们的值,并将输出值放入目标向量寄存器,从而实现数据转换。 添加固定宽度的 ZT0 寄存器让 Arm 能够在可变向量长度的 SVE/SME 框架内加速数据转换,但不如 ACE 的 VUNPACKB + 置换组合灵活。量化到 2 位或 4 位以外的模型权重将无法受益于 SME2 的查找表加速,并且需要多个不同查找表的更复杂码本方法也无法得到支持。 [](https://substackcdn.com/image/fetch/$s_!q3Ge!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24aa0834-e5d7-453f-bbbc-ca5c8a6ba0cd_960x262.png)使用 SME2 的 ZT0 查找表寄存器进行数据转换。灵活性较低,但 Arm 的 LUT 指令不需要中间寄存器来解包,也不依赖于固定的向量长度。 另一方面,SME2 的机制让 Arm 能够用一条指令而不是两条指令来表示数据类型转换。它还减少了对向量寄存器的压力,因为查找表存储在单独的寄存器中,并且 LUT 指令不需要单独的向量寄存器来保存解包后的中间值。在灵活性方面,Arm 可以继续扩展 ISA,添加 LUT 指令变体来支持更多数据类型宽度。 像 FP8 这样的低精度数据类型动态范围较低。开放计算项目的微缩放格式规范通过缩放因子解决了这个问题。一个缩放值应用于一组值,从而增加乘法结果的动态范围,而无需增加每个数据元素的位宽。ACE 通过一个新的 1024 位块缩放寄存器 BSR0 支持这一点。BSR0 分为两个 512 位半部分,每个半部分对应外积操作的两个输入之一。每个半部分进一步分为四组 16 个 8 位缩放值,由外积指令中的立即数操作数选择。 [](https://substackcdn.com/image/fetch/$s_!SdOq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482628ff-c73e-4913-8160-960e85005fa5_331x323.png)来自 ACE v1 公开规范,展示了一个带缩放的外积 Arm 的 SME 通过浮点模式寄存器(FPMR)中的 8 位 LSCALE 和 LSCALE2 字段支持缩放。BF1CVT 使用 LSCALE,BF2CVT 使用 LSCALE2。虽然 Arm 文档描述了两条指令,但实际上该方案与 ACE 使用立即数选择 BSR 组的方式类似。BF1CVT 和 BF2CVT 之间存在 1 位操作码差异,创造性的解码器可以将其视为立即数。使用缩放因子在 SME 中是一个两步过程:BF1CVT/BF2CVT 应用缩放,然后一个单独的外积指令执行计算。ACE 的 BSR0 和 SME 的 FPMR 的更新指令都会覆盖整个寄存器,这表明两边的 ISA 设计者都认为缩放值不会频繁变化。 存在一种可能性,即在硬件实现中这两个寄存器都不会重命名,因此任何缩放值更新都会为 FP8 指令创建一个序列化屏障。如果缩放值确实频繁变化到需要重命名的程度,那么两个 ISA 都处于困境。ACE 的所有 FP8 外积指令都引用 BSR0,因此依赖于最后一次 BSR0 写入。SME 有单独的缩放和外积数学指令,但 FPMR 还包含控制 FP8 格式和溢出行为的字段。因此,它最终陷入同样的境地:所有 FP8 数学都依赖于最后一次 FPMR 写入。 量化是减少内存带宽需求的一种方法。分块是另一种方法。简单的矩阵乘法会产生局部性较差的内存访问模式。将矩阵分割成子矩阵(tile)有助于通过适应高速缓存来改善数据重用,而不是频繁地从 DRAM 中流式输入数据。但即使采用分块,带宽挑战仍然存在。如果计算能力足够强,能够比从内存子系统的更低层级(L2、L3 甚至 DRAM)流式输入 tile 更快地处理它们,缓存带宽也可能成为瓶颈。 更大的 tile 有助于缓解这个问题。计算结果矩阵的每个 tile 涉及将第一个输入矩阵对应行中的每个 tile 与第二个输入矩阵对应列中的每个 tile 相乘。更大的 tile 意味着可以用更少的 tile 覆盖整个矩阵。因为每个输入 tile 在输出 tile 的匹配行或列中出现的频率更低,所以在整个矩阵乘法过程中,它被加载的次数更少。 [](https://substackcdn.com/image/fetch/$s_!6Axr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F553edf58-9ff9-4580-a50e-9e3e9af34354_1099x170.png)可视化一个小例子。第一个矩阵中的一个输入 tile 在矩阵被覆盖为 2x2 个 tile 时,只需为三个输出 tile 加载。如果是 3x3 的 tile 划分,它需要被加载五次 寄存器容量影响 tile 大小,因为我们希望将累加器保留在寄存器中。每次累加都是一次读-修改-写操作,即两次内存访问。此外,大多数内存子系统的存储带宽小于加载带宽,这反映了典型应用程序行为:内存读取远多于写入。ACE 保留了 AMX 引入的 8 KB tile 寄存器,但将数学指令改为从 AVX-512 向量寄存器中获取两个输入。TMUL 数学指令的所有操作数都来自 tile 寄存器,迫使代码使用部分 tile 寄存器容量来保存临时输入数据。 例如,考虑一个 **C = AB** 矩阵乘法操作,矩阵大小为 32K x 32K,数据类型为 8 位整数值(INT8)。**A** 和 **B** 是输入矩阵,**C** 是结果矩阵。该矩阵乘法需要 32768^3 即 35.2 万亿次乘加(MAC)操作。**C** 将始终保留在寄存器中,而 **A** 和 **B** 只在必要时分配寄存器。 AVX-512 提供了 32 个 512 位向量寄存器。我们可以使用大约 24 个寄存器来存储 **C** 的累加器,其余八个用于存储输入值。AVX-512 FMA 指令只能从内存获取一个输入,这意味着另一个输入必须在操作之前加载到寄存器中。 [](https://substackcdn.com/image/fetch/$s_!Ohbd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c67ad7b-10c2-4f9e-8181-a9b5464cba69_216x211.png) 我们需要从 **A** 加载 16 x 32k 个元素,从 **B** 加载 24 x 32k 个元素来计算我们的输出 tile,因此我们需要加载 40 x 32k ≈ 1.

相似文章

[x86] AI计算扩展(ACE)规范

Hacker News Top

x86生态系统咨询小组发布了AI计算扩展(ACE)规范,该规范定义了新的x86指令和寄存器状态,用于加速机器学习工作负载中的矩阵乘法和低精度数据格式。

AI芯片的强劲动力(6分钟阅读)

TLDR AI

本文解释了脉动阵列如何处理AI芯片中超过95%的计算,详细介绍了它们的设计、工作模式以及为什么它们在矩阵乘法中高效。

在Ryzen AI 7 350 NPU上达到峰值TOPS性能

Lobsters Hottest

关于在AMD Ryzen AI 7 350 NPU上实现峰值TOPS性能的技术深度剖析,与Xilinx AIE-ML v2 AI引擎进行比较,并解释用于矩阵乘法工作负载的硬件架构。