Menu Close

为什么人工智能需要的不只是一颗高速 CPU?

现代 CPU 每秒可以运行数十亿个时钟周期。它能够执行程序、管理操作系统,同时处理各种不同的任务。那么,为什么人工智能系统还经常需要 GPU 和专用加速器?

为什么人工智能需要的不只是一颗高速 CPU?

答案并不是简单的“CPU 不够快”。

人工智能工作负载对计算机提出了一组特殊要求:大量重复的算术运算、规模庞大的数值数据,以及这些数据在内存与计算单元之间的频繁移动。提高时钟频率,只能解决其中一部分问题。

要理解人工智能硬件,我们需要同时关注三个方面:计算是怎样完成的、有多少计算可以并行执行,以及数据能否高效地送到计算硬件。

我们可以从一个远比大语言模型简单的地方开始:逻辑门。

第一章:从逻辑门到算术运算

逻辑门处理二进制信号。与门、或门和非门分别执行简单的逻辑操作,但把这些逻辑门组合起来,就可以构成执行算术运算的电路。

半加器可以将两个二进制位相加,全加器则进一步处理来自低位的进位。把这些电路连接起来,处理器就能够对位数更多的二进制数进行加法运算。

乘法需要更复杂的电路。一种基本方法是先生成部分积,再将它们相加。实际处理器会采用经过优化的设计,但基本原理没有改变:算术运算由经过精心组织的数字电路完成。

现在,设想一种不断重复的计算:将两个数相乘,再把乘积加入一个累计结果。

新的累计结果 = 原来的累计结果 + A × B

这就是乘加运算,通常称为 Multiply-Accumulate,简称 MAC。它广泛出现在神经网络的计算过程中。

如果处理器用于某种运算的算术单元有限,大量计算就必须分成许多步骤完成。增加算术单元,可以让更多计算并行执行,前提是这些计算之间具有足够的独立性,而且数据能够及时送达。

人工智能加速器与其他处理器建立在相同的数字电路基础上。它们的优势,来自围绕特定工作负载,对算术电路、存储和数据移动方式进行专门组织。

第二章:为什么时钟频率不能说明全部问题

一颗运行在 4 GHz 的 CPU,每秒具有 40 亿个时钟周期。但这并不意味着它每秒恰好完成 40 亿条指令、40 亿次乘法,或者 40 亿次人工智能运算。

有些指令需要多个周期才能完成。现代处理器也可以在一个周期内发射多条指令,让不同指令重叠执行,还可以通过一条指令处理多个数据元素。

因此,性能不仅取决于每秒有多少个时钟周期,还取决于每个周期能够完成多少有用的工作。

假设有两颗处理器。第一颗的时钟频率更高,但用于某种运算的算术单元较少;第二颗的时钟频率较低,却能够同时执行更多同类运算。对于具有足够并行性的工作负载,第二颗处理器反而可能更早完成任务。

通用 CPU 将相当一部分硬件资源用于处理多样化、难以预测的程序。分支预测、缓存、指令调度和低延迟执行能力,使它能够灵活应对不同任务。

人工智能加速器则更加重视重复的数值计算。它们通过牺牲一部分通用性,换取对所支持运算更高的吞吐量或更好的能效。

CPU 完全可以运行人工智能模型,对于较小的工作负载,它可能已经足够。只有当应用对吞吐量、响应时间或功耗效率的要求超过某套 CPU 系统的能力时,专用硬件的价值才会更加明显。

第三章:神经网络内部不断重复的计算

许多神经网络层会将输入值与训练得到的权重结合起来。

看一个简单例子,输入包含三个数:

输入:[1, 2, 3]

对应的三个权重是:

权重:[4, 5, 6]

将对应位置的数相乘,再把乘积相加:

1 × 4 + 2 × 5 + 3 × 6 = 32

这种计算叫作点积,也称为内积。

计算一个输出值并不复杂,但一个神经网络层可能需要生成成千上万个输出,每个输出又使用不同的一组权重。如果同时处理多组输入,计算量还会进一步增加。

这些计算可以组织成矩阵乘法。矩阵就是按行和列排列的数字集合。在矩阵乘法中,每个输出元素都由第一个矩阵的一行与第二个矩阵的一列进行点积计算得到。

举一个小例子:矩阵 A 的两行分别是 [1, 2] 和 [3, 4],矩阵 B 的两行分别是 [5, 6] 和 [7, 8]。结果矩阵左上角的元素为:

1 × 5 + 2 × 7 = 19

按照相同方法计算,其余三个输出元素分别是 22、43 和 50。因此,结果矩阵的两行分别为 [19, 22] 和 [43, 50]。

更大的矩阵只是把同一种计算模式重复到更大的规模。如果矩阵 A 有 M 行、K 列,矩阵 B 有 K 行、N 列,那么结果矩阵就包含 M × N 个输出元素。常规的稠密矩阵乘法实现需要执行 M × N × K 次乘加步骤。

这种高度重复的计算结构,为专用硬件提供了发挥优势的机会。

第四章:从单个数值到向量和矩阵

标量运算处理单个数值,向量运算可以对多个元素执行相应操作,而矩阵运算则通过行与列的组合,生成一组累加结果。

现代 CPU 已经支持向量处理,并不是所有数字都必须逐个计算。向量指令能够同时处理多个数据元素,因此在科学计算、多媒体处理和人工智能中都很重要。

矩阵硬件在此基础上,更进一步地围绕操作数的重复组合来组织计算。

假设同一个输入值需要参与多个输出元素的计算。如果每次使用它都重新从较远的存储位置读取,就会产生重复的数据传输。硬件可以把这个值保留在本地,并将它提供给多个算术单元。

同样,中间累加结果也可以保留在更新它们的电路附近。硬件完成多次乘加操作之后,再把最终结果写回其他存储位置。

一个大型矩阵中的小块通常称为 tile,也就是矩阵分块。软件和硬件经常把大型矩阵乘法拆分成多个小块,使它们能够适应现有的存储容量和执行资源。

这种组织方式同时利用了并行计算和数据复用。当矩阵硬件的结构与工作负载的形状、数值格式相匹配时,加速效果才更明显。

如果运算规模很小、矩阵很狭窄,或者形状不适合硬件,一个大型矩阵引擎也可能无法充分发挥能力。拥有更多算术单元,只有在足够多的有效工作能够送达这些单元时才有意义。

第五章:算术运算再快,也要等待数据

在算术单元将两个数相乘之前,这两个数必须先到达计算单元。

处理器通过分层存储结构访问数据,包括寄存器、缓存和主内存。加速器也有自己的本地存储和内存系统。这些存储层级在容量、带宽、延迟和能耗方面各不相同。

内存容量表示能够存放多少数据,内存带宽表示每秒能够传输多少数据。一套系统可能拥有足够的容量来装下模型,却没有足够的带宽来快速处理它。

假设一个模型包含 80 亿个参数,每个参数使用 2 字节存储:

80 亿 × 2 字节 = 160 亿字节,也就是约 16 GB 的权重数据。

这里按照十进制计算 GB,而且尚未包括工作缓冲区、注意力缓存和其他运行开销。

如果某个执行步骤需要把这 16 GB 数据全部经过一个持续带宽为每秒 100 GB 的内存接口传输,那么仅传输过程就需要:

16 GB ÷ 100 GB/s = 0.16 秒

这是一个用于解释带宽限制的简化例子,不是对某个具体模型或计算机的性能预测。缓存、压缩、批处理、模型架构和软件实现,都会改变实际的数据传输量。

但基本原理很明确:让乘法运算变得更快,并不能消除等待操作数所花费的时间。

分析性能时,我们经常区分计算受限和内存访问受限的运算。哪一种限制占主导,部分取决于算术强度,也就是在所分析的存储层级上,每传输一个字节的数据,能够完成多少计算。

第六章:为什么数据复用如此重要

假设一个权重从内存中被读取出来,却只使用一次,那么这次传输只支撑了很少的计算。

如果同一个权重只读取一次,随后保留在本地,并用于处理多个输入值,那么相同的数据传输就能够支撑更多有用的工作。

这就是矩阵形状和批处理方式如此重要的原因。

矩阵与向量相乘,是将一个矩阵应用于一个向量;矩阵与矩阵相乘,则可以把同一个矩阵同时应用于多个向量,从而创造复用矩阵元素的机会。

例如,每次只处理一个输入,可能需要反复读取同一组权重。把多个输入组成一批处理,则可能让硬件在计算多个结果时重复利用已经读取的权重。

这并不意味着批次越大越好。更大的批次需要额外存储,而且等待多个请求凑成一个批次,也可能增加用户等待响应的时间。

矩阵分块提供了另一种数据复用方式:先把一小组输入值和权重装入快速存储,利用它们完成多次计算,再替换成下一组数据。

矩阵运算的维度和算术强度,会影响它究竟更容易受到计算能力限制,还是数据传输限制。这个原则并不局限于某一种 GPU:硬件利用率取决于工作如何组织,而不仅仅取决于总共需要多少次运算。

第七章:为什么聊天机器人读取和生成文本的方式不同

典型的自回归语言模型在处理请求时,可以分成两个主要阶段:预填充,也就是 prefill,以及解码生成,也就是 decode。

在预填充阶段,模型处理用户输入的提示词。在同一层内部,多个输入 token 的位置可以并行处理,因此能够形成较大的矩阵运算。模型也会建立后续注意力计算需要使用的信息。

在解码生成阶段,模型逐步生成新的 token。一个 token 可能对应一个词、词的一部分、标点符号,或者其他文本片段。

在常规的自回归生成过程中,下一步计算依赖上一步选出的 token。因此,对于单条输出序列,模型不能把所有后续内容都当作相互独立的任务一次性生成。

看一个简化例子:某个线性层处理 256 个提示词位置时,可以将一个 256 × K 的输入矩阵与一个 K × N 的权重矩阵相乘。进入解码阶段后,如果只处理一个新位置,同一层的输入就可能变成 1 × K。

后一种计算的输入行数更少,权重在不同输入行之间被重复利用的机会也更少。

因此,预填充阶段通常能够明显受益于较强的矩阵计算吞吐能力,而单条序列的解码生成则经常遇到内存带宽限制。实际瓶颈仍然取决于模型、上下文长度、批次大小和具体实现。

语言模型通常会维护一个键值缓存,也就是 KV cache,用来保存此前注意力计算中的键和值,避免重复计算。它能够节省计算量,但也需要占用内存,并在后续生成过程中被访问。

把多条序列放在一起处理,可以改善硬件利用率,但系统同时也必须容纳这些序列的缓存,并满足各自的响应延迟要求。

这有助于解释一个常见现象:同一台计算机可能很快完成提示词处理,却仍然只能以相对较慢的速度逐步生成答案。

第八章:更小的数值表示,可以减少工作量

人工智能硬件还可以通过使用适合模型的数值格式来提高效率。

一个 32 位浮点数占用 4 字节,一个 16 位数值占用 2 字节,一个 8 位数值占用 1 字节。

对于 100 万个数值,仅原始数值数据的存储量就分别约为 4 MB、2 MB 和 1 MB。更紧凑的表示方式,可以同时减少存储需求和数据传输量。

在硬件支持的情况下,低精度算术运算还可能需要更小的电路面积或更少的能量,从而让硬件在相同资源预算下提供更多运算能力。

不过,位数减少也意味着可表示的数值数量减少。选择数值格式,需要在效率与数值特性之间进行权衡。

FP16 和 BF16 都使用 16 位,但它们对这些位的分配方式不同。BF16 提供较宽的指数范围,而用于表示尾数的位数更少,因此精度特性也不同。FP8 进一步减少位数,不同的 FP8 格式同样会在数值范围和精度之间作出不同取舍。

一种常见做法是使用较低精度的输入完成乘法,再使用较高精度的格式累加结果。例如,某些支持相应运算的硬件可以使用 FP8 输入进行乘法,并用 FP32 格式累加。

量化则将数值映射到更紧凑的表示方式。它的实际效果取决于模型、缩放方法、软件和硬件支持。

较小的数值格式可以提高效率,但模型输出是否仍然达到可接受的质量,必须通过测试确认,不能仅凭位数减少就作出判断。

第九章:RISC-V 在人工智能加速中的位置

RISC-V 是一种指令集架构,也就是对软件能够请求哪些操作,以及这些操作应当表现出什么行为的定义。

它不是某一款固定的处理器设计。不同 RISC-V 处理器在性能、内存系统和执行硬件方面,可能存在很大差异。

RISC-V 的标准向量扩展 RVV,为数据并行计算提供了基础。除了矩阵乘法,向量处理也适用于许多其他人工智能操作,包括归一化、激活函数、归约和数值格式转换。

围绕矩阵扩展的设计,探索了在这一基础上继续发展或与之配合的不同方式。

**批量点积(Batched Dot Products)**通过复用向量操作数,计算多个累加结果。

**集成式矩阵扩展(Integrated Matrix Extensions,IME)**将矩阵操作数和结果保留在向量寄存器模型之中。

**向量矩阵扩展(Vector Matrix Extensions,VME)**使用向量寄存器提供输入,并引入专门的矩阵累加器状态。

**附接式矩阵扩展(Attached Matrix Extensions,AME)**则为矩阵操作数和结果提供相对独立的组织方式。

这些方向的主要区别,在于数据保存在哪里,以及计算单元如何访问这些数据。它们体现的仍然是本文一直讨论的架构选择:并行算术运算、本地累加,以及高效的操作数传输。

理解这些设计时,需要区分标准向量扩展、矩阵扩展提案,以及厂商的具体实现。某种扩展出现在技术演示或架构介绍中,并不代表每一颗 RISC-V 处理器都已经具备相应能力。

评估实际产品时,应查看具体芯片及其软件工具链所支持的扩展,而不能仅凭“采用 RISC-V”就判断它的人工智能性能。

第十章:人工智能性能由整个系统决定

即使矩阵硬件非常强大,也无法加速程序中的所有部分。

神经网络还需要执行归一化、激活、索引和数据格式转换等操作。外围应用则需要准备输入、调度任务、管理内存,并把输出交给用户。

假设矩阵乘法占程序总执行时间的 80%。如果把这一部分加速到原来的 10 倍,而剩余部分保持不变,那么新的总执行时间就是:

20% + 80% ÷ 10 = 原执行时间的 28%

整个程序的速度大约提高到原来的 3.6 倍,而不是 10 倍。没有被加速的部分,限制了整体性能的提升。

软件也决定着硬件能否被充分利用。经过优化的计算库会选择合适的计算内核、安排数据布局,并调度运算。有些优化会把多个操作融合起来,避免中间结果反复写入较慢的存储,再从中读取。

CPU 仍然承担着通用程序执行和系统协调的重要工作。根据系统设计,它也可能完成模型中的一部分,甚至全部数值计算。

因此,有意义的性能评估不能只看时钟频率或峰值每秒运算次数。对于交互式语言模型,更实用的指标包括首个 token 的等待时间、后续输出 token 之间的延迟、内存占用,以及在所需输出质量下能够达到的性能。

最合适的设计,是作为一个完整系统,能够满足应用实际要求的设计。

结论

人工智能硬件与其他数字计算系统具有相同的基础:逻辑门、算术电路、寄存器和内存。

真正发生变化的,是这些组件的组织方式。

高速 CPU 能够执行各种不同的程序,但高要求的人工智能工作负载,还会受益于大规模并行算术运算、高效的矩阵处理、合适的数值格式,以及在计算单元附近反复利用数据的能力。

GPU、专用加速器,以及围绕 RISC-V 的矩阵扩展设计,正在通过不同的组织方式提供这些能力。

关键问题并不只是处理器的时钟运行得有多快,而是整个系统能够完成多少有用的工作、能以多快的速度提供所需数据,以及完成这些工作需要消耗多少能量。

这就是为什么人工智能需要的不只是一颗高速 CPU。

Posted in 家庭生活