一位全加器是数字电路的第一课:输入两个比特 a、b 和低位进来的进位 c,输出这一位的和 s 和往高位送的进位。把它烧进 FPGA,最后落到芯片上的是两张小小的真值表,写成十六进制只有两个数:
s = 0x96 # 1001 0110:a、b、c 里有奇数个 1 时为 1cout = 0xE8 # 1110 1000:a、b、c 里至少两个 1 时为 1同一个全加器也可以用两个“神经元”来做:每个神经元把输入加权求和,超过阈值就输出 1。这时候写下的不是比特,而是 9 个实数,比如 [1, 1, 1], −1.5 和 [1, 1, 1, −2], −0.5。Transformer 说到底也是这样一个东西:一张固定的计算图,加上几十亿、几千亿个这样的实数。
这样一比,问题就来了。FPGA 是一片可以随意配置的电路,Transformer 跑一步也是一个电路,两者看起来是一回事,那它们到底哪里相同、哪里不同? FPGA 从 1985 年就有了,比 Transformer 早了三十多年,单片上的逻辑单元也从几十个涨到了上千万个,为什么智能没有在 FPGA 上“涌现”出来? 我们先把两种电路各自怎么配置讲清楚,再一层层往下找它们真正的差别。
一、两种电路各自怎么配置
FPGA:查找表和导线
FPGA(现场可编程门阵列)里没有固定的与门、或门,只有成片的查找表(LUT,look-up table)和它们之间的可编程导线。一个 k 输入的查找表就是一块 位的小存储器:k 个输入拼成一个地址,读出那一位就是输出。所以 4 输入 LUT 有 16 个配置位,可以实现任意一个 4 输入的布尔函数;现在的主流芯片用 6 输入 LUT,64 个配置位。导线也一样,每个交叉点上的开关接通还是断开,都由一个配置位决定。
把一个设计放进 FPGA 的过程是:工程师用 Verilog 之类的硬件描述语言写出电路,综合工具把它翻译成查找表,布局布线工具决定每张表放在芯片哪个位置、走哪几根线,最后生成比特流(bitstream),也就是所有配置位的总和。上电时比特流写进芯片,电路就成形了。
第一块 FPGA 是 1985 年 Xilinx 的 XC2064,只有 64 个可配置逻辑块,每块是一个 4 输入的逻辑函数1。2023 年 AMD 发布的 VP1902 有 846 万个 LUT2。
Transformer:固定的计算图和权重
Transformer 每预测一个词元(token),都要把同一张计算图走一遍:词嵌入把符号变成向量,注意力从前面的位置取信息,MLP 在每个位置上做非线性变换,输出头给每个候选打分3。这张图里有哪些乘法、加法、softmax,连接方式是什么,在训练之前就定死了;会变的只有图里的权重,也就是那几千亿个实数。
从这个角度看,Transformer 的一次前向计算就是一个电路,权重就是它的配置。跑在 GPU 上时,这个电路是用矩阵乘法“模拟”出来的;也可以真把它做进硬件,后面会看到,确实有人把它放进了 FPGA。
同一个全加器,两种配置
把开头那个全加器画出来,两种配置的样子就很清楚了。
左边的查找表就是把真值表原样存下来:地址 3(c=0、b=1、a=1)那一行,s 是 0,进位是 1。右边的阈值神经元是另一种存法:进位神经元把三个输入加起来,超过 1.5 就输出 1;和神经元再减去两倍进位,剩下的超过 0.5 就输出 1。
两种写法得到的是同一个函数,所以电路本身只是骨架,功能全在那串配置里。这是两者最根本的共同点。那么,除了这一点,它们在“能表示什么”上还有多像?
二、相同之处:骨架固定,功能在配置里
都能表示任意函数
查找表网络能表示任意布尔函数,这几乎是定义:最笨的办法是把整张真值表存进一大片 LUT 里。阈值神经元也一样,图 1 用两个神经元做出了全加器,而全加器串起来就是任意位数的加法器;与、或、非都能用一个阈值神经元实现,所以任意布尔电路都能一个门一个门地换成神经元。
反过来,神经网络里的乘加和比较,本身也是数字电路,FPGA 当然能实现。两边谁也不比谁“多”一种能力,差别只在需要多大的电路。
一步之内能算多深
再细一点,可以问“一步”能算多少。FPGA 的一次计算是一片组合逻辑,深度由设计者决定,只受时钟频率约束;如果加上寄存器和时钟,让电路每一拍更新一次状态,它就是一台完整的有限状态机,CPU 本身就能用 FPGA 实现。
Transformer 的一次前向只有固定的几十层。理论计算机科学里有一个干净的结论:如果数值精度是输入长度的对数级,一次前向可以用常数深度的阈值电路来模拟,属于复杂度类 TC⁰4。也就是说,单看一步,Transformer 是一种层数固定、但每层可以很宽的阈值电路,和图 1 右边那种神经元电路是同一类东西。
Transformer 的“循环”来自自回归:每一步写出一个词元,接到输入末尾,再算下一步。允许它先写一串中间步骤(也就是思维链)以后,表示能力会随步数增长:线性步数可以识别所有正则语言,多项式步数恰好对应 P5。
| FPGA | Transformer | |
|---|---|---|
| 基本单元 | 4–6 输入查找表,任意布尔函数 | 加权求和 + 非线性(注意力、MLP) |
| 一步之内 | 任意深度的组合逻辑,受时钟频率约束 | 固定层数;对数精度下属于常数深度阈值电路 TC⁰ |
| 加上循环 | 寄存器 + 时钟:任意有限状态机,可以做成 CPU | 自回归把输出写回输入:线性步数覆盖正则语言,多项式步数对应 P |
| 实现对方 | 可以跑神经网络推理:Brainwave 在 Stratix 10 上批大小 1 时 39.5 TFLOPS | 训练好的网络可以整个编译成查找表(LogicNets、LUTNet) |
只要电路够大,谁都能模拟谁;单看“能表示什么”,FPGA 不比 Transformer 弱,一步之内甚至更强。
它们可以互相实现
表 1 最后一行不是理论上的可能,而是已经做成的工程。微软的 Project Brainwave 把神经网络推理放在数据中心的 FPGA 上,权重全部放进片上存储,在 Stratix 10 上批大小为 1 时达到 39.5 TFLOPS 的有效算力,用在必应搜索里6。反方向,LUTNet 直接训练 FPGA 查找表里的内容7,LogicNets 先训练一个每个神经元只有很少输入的网络,再把每个神经元整个换成一张真值表,编译成 FPGA 电路8。
到这里,一个直觉上的答案就被排除了:FPGA 时代没有出现智能,不是因为 FPGA“表示不了”智能需要的计算。既然能表示,那差别在哪里? 回到图 1 最后那句话:两边的数,一边只能是 0 和 1,一边可以连续地调。这串数是谁写的、怎么写出来的,才是下一节的问题。
三、配置由谁来写
现象:FPGA 上的每一位都是人决定的
一个 FPGA 设计里的每一个配置位,归根到底都来自工程师写下的 Verilog。综合和布局布线工具会替人做大量优化,但它们只是把人已经想清楚的功能翻译成比特,不会自己发明功能。工程师得先知道全加器是什么,才写得出 assign s = a ^ b ^ c;。
而且这条路很慢。一个大设计跑一遍布局布线要几个小时:在 Virtex-7 2000T 上,一个大设计用 Vivado 跑了 5 小时、占了 9 GB 内存,旧工具 ISE 要 13 小时9。改一行代码,等半天才能在板子上看到结果。
所以 FPGA 能做的事,被设计者的理解力框住了:电路不会比写它的人更聪明。要出现“没人设计过、自己长出来”的能力,配置就不能由人来写。
第一次尝试:让进化来写
上世纪九十年代,真有人这样试过。1996 年,萨塞克斯大学的 Adrian Thompson 用遗传算法直接“进化”FPGA 的配置10。他用的是 Xilinx XC6216,只取芯片一角 10×10 共 100 个格子,每格 18 个配置位,整个“基因”是 1800 个比特。任务是分辨两种方波:输入 1 kHz 时输出一个电平,输入 10 kHz 时输出另一个电平,而且不给时钟、不给任何外部元件。
做法很朴素:随机生成 50 个配置,逐个写进真实的芯片,用示波器和积分器给它们的表现打分;分高的留下来交叉、变异,生成下一代。
结果是成功的,而且很奇特。最后的电路只用了 32 个格子,没有时钟,却能分辨周期差了五个数量级的信号(每个格子的延迟只有几纳秒,信号周期是 0.1 和 1 毫秒)。其中几个格子跟输出之间没有任何导线相连,可一旦把它们固定住,电路就失灵;Thompson 推测它们是通过电源线或电磁耦合在起作用。这个电路还很怕温度:用一盏 60 瓦的灯泡烤芯片,或者在凉风习习的晚上打开实验室所有窗户,频率响应就会平移,分辨就不再完美。
这次实验正好说明了让机器写配置的两面。好的一面是,它真的写出了人写不出来的东西,这正是“涌现”的味道。坏的一面是代价:1800 个比特的配置,就要 25 万次评估、两三周时间;而且进化利用的是这一块芯片的物理细节,换一块芯片、换一个温度就不一定成立。
为什么这么慢? 照这个速度,GPT-3 那样几万亿比特的配置是不可能靠进化写出来的。
梯度下降:参数怎样一步步收敛
要说清楚这一点,得先说清楚“训练”和“收敛”是怎么回事。
训练一个网络,先要把“它现在错得有多厉害”变成一个数,叫损失(loss)。做加法时,可以数一数输出的比特错了几个;实际训练更常用交叉熵,它不只看对错,还看模型对正确答案有几分把握,所以“差一点就对了”和“错得离谱”会得到不同的分数。
接下来可以打一个比方:把所有参数当成坐标,损失当成高度,整张网络的所有可能配置就是一片起伏的地形,训练就是在这片地形上往低处走。梯度是脚下这一点在每个方向上的坡度,它告诉你:这个参数调大一点,损失是升还是降、变化多快。梯度下降每一步做两件事:先算出坡度,再朝下坡的方向挪一小步,步子的大小叫学习率。一步一步走下去,损失降到一个很低的位置,参数也不再怎么变,这就叫收敛。
坡度怎么算?网络是一层套一层的函数,按微积分里的链式法则,最后的损失对某个参数的导数,等于从输出往回、沿途每一层“输入变一点、输出变多少”的连乘。反向传播就是把这件事从输出层往回一次做完,代价大约只是一次前向计算的两倍,就能得到所有参数各自的导数11。参数从 1800 个变成 1800 亿个,每一步的代价跟着线性增长,但每一步仍然同时告诉每个参数该往哪边走。
Transformer 能收敛,靠的是三样东西凑在一起。
每个零件都可导。矩阵乘法、softmax、归一化、GELU 之类的激活函数,都是光滑的函数,输入变一点,输出就跟着变一点;ReLU 只在 0 这一个点上有折角,不影响大局。注意力也不例外:softmax 给出的权重是 0.96、0.01 这样的连续值,而不是“选中 / 不选中”,所以“该看哪里”本身也能被梯度慢慢调准。
坡度能传到底。几十层的网络,连乘一长串导数,很容易乘到接近 0(梯度消失)或者大得离谱(梯度爆炸)。Transformer 每个部件外面都有一条残差连接,输出等于输入加上部件算出来的增量,梯度可以沿着这条直通的路一路传回最前面;归一化把每层的数值拉回固定范围,避免越乘越大。
参数多,路就多。直觉上,几千亿维的地形应该坑坑洼洼,走到哪个小坑里就出不来;但实践中,参数远多于“恰好够用”时,能把训练数据拟合好的配置非常多,彼此连成大片的低地,从随机起点出发大多都能走到其中一处。这是大量训练经验的观察,理论上还没有完全说清楚。还要注意,“收敛”指的是走到一处足够低的地方,而不是找到唯一的最优解:同一个模型换个随机种子训练两次,参数完全不同,表现却差不多。
原因:比特上没有坡度
FPGA 的配置位只能是 0 或 1。把上面的地形换到比特上,就不再是连绵的山坡,而是一个个孤立的点:每个比特只有两个位置,中间没有“往右挪一点”可言。
这件事可以直接量出来。我们搭了一张由 4 输入查找表组成的小网络学 3 位加法(下一小节的实验用的也是它),再给它做一个“软”版本:每张查找表的 16 个比特各换成一个实数 θ,经过 sigmoid 变成 0 到 1 之间的“软比特”,θ 大于 0 就对应比特 1,小于 0 对应比特 0。软版本用梯度训练到第 20 步、还没收敛的时候,挑出其中一个配置项,把它从 −6 扫到 6,分别看软网络的损失和取回比特后的硬电路错了多少(图 3)。软查找表上,损失随它平滑变化,当前位置的坡度清楚地指向右边;硬查找表上,这个配置项小于 0 时电路错 86 个输出位,大于 0 时错 70 个,两边都是平的。
硬的那张图上,坡度在每一处都是 0,只在 0 处有一个跳变,那里导数根本不存在。梯度下降站在任何一点上,看到的都是“往哪边走都一样”,一步也迈不出去。剩下的办法只有试:把这一位整个翻过去,重新评估一次,看看变好没有。
而试的代价随规模增长得极快。变异搜索每做一次评估,得到的只是一个分数:这一组随机翻转合起来让整体变好了还是变差了,至于是哪一位起了作用、哪一位帮了倒忙,分数里看不出来。1800 个比特有 种组合;配置越长,随机翻转碰巧改对、又没碰坏别处的机会越小,越到后期越难。
这里要分清两件事。FPGA 芯片本身完全可以执行梯度下降,Brainwave 就是在 FPGA 上跑神经网络;收敛不了的,是 FPGA 自己的比特流。而且普通 FPGA 的比特流还不能随便乱改,有的配置会让两个驱动源接到同一根线上;Thompson 特意选了 XC6216,正是因为它的任何配置都不会损坏芯片10。这不是 FPGA 的硬件缺陷,而是“配置是比特”这件事本身决定的。
实验:同一张查找表网络,两种写法
为了看看这个差别放大以后有多大,我们用同一类“FPGA 式”网络做了个小实验12。网络由 4 输入查找表组成,每张表 16 个配置位;导线随机连好以后就不再改,每张表从原始输入和上一层的输出里随机挑 4 根线,就像布局布线已经做完。任务是 n 位无符号加法:输入 2n 个比特,输出 n+1 个比特,把所有 种输入都算对才算成功。网络宽 16n 张表、深 n+2 层,2 位加法有 1584 个配置位,4 位加法有 5200 个。
同一张网络,我们用两种办法去写它的配置。
- 变异搜索,相当于简化版的 Thompson:每一轮把当前配置复制 64 份,每份随机翻转大约 2 个比特,挑出得分最高的一份;只要不比当前差,就替换掉当前配置。
- 梯度下降:用图 3 里那种软查找表,输入也允许是 0 到 1 之间的小数,查找表的输出就是 16 个软比特按输入加权的平均。这样整张网络对配置可以求导,用 Adam 优化;每 10 步把实数按正负取回成比特,放回真正的硬电路上检查是不是全对。
| 任务 | 配置位 | 梯度下降:多少步全对 | 变异搜索:20 万次评估后 |
|---|---|---|---|
| 2 位加法 | 1584 | 50、30、30 步 | 全对,分别用了 4673、10945、2945 次 |
| 3 位加法 | 3136 | 80、80、90 步 | 95.3%、96.9%、96.9% 的题全对 |
| 4 位加法 | 5200 | 1270、1530 步;第三个 3000 步时 97.7% | 54.7%、65.6%、52.0% |
| 5 位加法 | 7776 | 4000 步时 94.2%、97.6%,没有全对(2 个种子) | 没有跑(4 位已经差得很远) |
梯度一步要算一次前向和一次反向,大约相当于 3 次评估。3 位加法上,我们又给变异搜索加到 200 万次评估,它在第 153 万次时全对。
结果(表 2)和 Thompson 的经验一致,而且差距随规模拉得很快。2 位加法的配置只有 1584 位,两种办法都能写对,变异搜索用几千到一万次评估,梯度用三五十步。到 3 位加法,梯度仍然只要 80 来步,变异搜索 20 万次评估后停在 95% 到 97%,我们把预算加到 200 万次,它在第 153 万次评估时才全对,差不多是梯度的六千倍。4 位加法上,梯度要一千多步,变异搜索 20 万次以后只有一半多的题全对。
图 4 把 4 位加法的过程画了出来。变异搜索前几千次评估涨得很快,因为随机配置里错的地方很多,随便翻几位都可能改好;越往后,对的位越多,随机翻转碰到“该翻的那一位”而不碰坏别处的机会越小,曲线就趴下了。梯度下降每一步都知道 5200 个数各自该往哪边调,不靠运气。
这个实验也有它的边界。梯度这一边并不是无敌的:5 位加法时,两个种子跑完 4000 步分别有 94.2% 和 97.6% 的题全对,没有完全写对;规模再大就要换更好的网络结构和训练方法,这正是深度学习这些年一直在做的事。我们的网络是随机布线、只有几千个配置位的玩具,不能拿来推算真实 FPGA 上的情况;它要说明的只是方向:同样是写一串配置,离散的比特只能靠试,连续的实数可以靠算。
解决:把比特放松成实数
这个实验里的“软查找表”并不是我们的发明,它正是近几年把 FPGA 和神经网络接起来的那条路。可微逻辑门网络把每个逻辑门放松成 16 种二输入门的概率混合,用梯度训练,训练完再给每个门挑最可能的那一种13;它的后续工作在 CIFAR-10 图像分类上做到了 86.29% 的准确率,用了大约 6100 万个逻辑门14。前面提到的 LUTNet、LogicNets 也都是先在连续空间里训练,再落成查找表。权重只有 ±1 的二值神经网络也是同样的套路:训练时在背后保留一份实数权重,前向用它的符号,反向时假装“取符号”这一步的导数是 1,让梯度穿过去,更新的是那份实数15。
也就是说,今天要让 FPGA 上的配置“自己学出来”,办法是先借用神经网络的连续参数和梯度,学完再离散化。真正写配置的,是梯度下降,FPGA 只是最后承载结果的地方。
配置能被梯度写出来,这只是第一步。下一个问题是:就算配置能学,FPGA 那种烧写后就焊死的导线,是不是学习的合适形状?
四、导线是焊死的还是现算的
现象:按内容取数,固定电路要为每个位置备一套
看一个最简单的“理解”任务:给一张表,北京对应京,上海对应沪,广东对应粤,四川对应川;问“上海”,答“沪”。语言里这种事无处不在:读到“她”时,要回头找前文里哪个名字是她;读到“这个函数”,要找前面定义的是哪个函数。该从哪里取信息,取决于内容本身。
FPGA 当然能做这件事,图 5 左边就是标准做法:每个槽位后面接一个比较器,比较结果送进选择器。选择本身是运行时按数据决定的,这一点和注意力一样。差别在于有哪些候选、怎么比较,全都要在烧写时铺成实实在在的电路:槽位数定死了,多一个槽位就多一套比较器和一路选择;“相等”这个比较标准也是写死的,要换成“意思相近”,就得重新设计电路。
注意力:导线由数据当场算出来
注意力做的是同一件事,但换了一种存法。当前位置算一个查询向量 q,每个位置算一个键 k 和一个值 v,q 和每个 k 做点积得到分数,softmax 变成权重,再按权重把 v 加起来3。可以把这组权重看成这一步临时接上的导线:权重 0.96 就是一根粗线,0.01 就是几乎断开。
关键在于 、、 三个矩阵对所有位置共用。配置里不需要列出“第 3 个位置和第 7 个位置之间要不要接线”,只需要写下“什么样的查询和什么样的键算相近”。这个“相近”本身也是学出来的:训练会把“她”和前文的人名放到点积大的方向上去。至于序列有多长,那是运行时的事,参数一个不用多,代价是要做的乘法跟着变多。
这对“学习”很重要。如果连接方式要写进配置,学习者就得对所有可能的连接一一试错,配置的长度随位置数增长;把连接变成数据的函数以后,要学的只是一个比较规则,而且它是连续的、可以求导的。
边写边读:把中间结果写回输入
导线现算还有一个后果。Transformer 每写出一个词元,都会把它接到输入末尾,下一步可以像读输入一样读它。比如用 Transformer 做十进制加法时,它不需要一根专门传进位的导线,而是把上一位的两个数字再看一遍,跟自己刚写下的那一位比一比,就能推出有没有进位。思维链让表示能力随步数增长,靠的也是这个:中间结果写在序列里,后面的步骤用注意力按需取回5。
FPGA 也有存储,寄存器和片上存储器一样能保存中间结果;但读哪一格、写哪一格,同样是电路里写死的地址逻辑。Transformer 的“草稿纸”和它读输入用的是同一套注意力,读哪里也是现算的。
到这里,我们看到了两个结构上的差别:配置能不能求导,导线是不是现算。可就算有了这两样,1990 年代也不可能一下子做出 GPT。还差的是什么? 是规模。
五、规模:差了多少个数量级
| 对象 | 年份 | 配置有多大 | 配置怎么写出来 |
|---|---|---|---|
| XC2064 | 1985 | 64 个 4 输入逻辑块 | 工程师手写 |
| Thompson 的进化电路 | 1996 | 1800 bit | 遗传算法,约 25 万次评估、2–3 周 |
| 本文的查找表网络 | 2026 | 1584–7776 bit | 梯度几十到几千步;变异搜索写对 3 位加法要 153 万次评估 |
| VP1902 | 2023 | 846 万个 6 输入 LUT,查找表内容约 5.4 亿 bit(不含布线) | 工程师写 Verilog,工具综合、布局布线 |
| GPT-3 | 2020 | 1750 亿个参数,按 16 bit 存约 2.8 万亿 bit | 梯度下降,约 3000 亿个 token,3.14×10²³ 次浮点运算 |
VP1902 的 5.4 亿 bit 是按 846 万 × 64 估算的,只算查找表本身;GPT-3 的配置比它多约 5000 倍。
把几样东西的配置摆在一起(表 3),差距是按数量级算的。最大的 FPGA,查找表内容大约 5.4 亿比特,已经全靠工程师和工具一层层写出来;GPT-3 的 1750 亿个参数按 16 比特存是 2.8 万亿比特16,多出约 5000 倍,没有任何人知道其中某一个数为什么是现在这个值。
写出这么大的配置,需要的不只是算法,还有两样东西。一是数据:GPT-3 读了大约 3000 亿个 token16,这么多可用的文本要到互联网普及很久以后才有。二是算力:训练 GPT-3 用了大约 3.14×10²³ 次浮点运算17。拿 Brainwave 那块 Stratix 10 的 39.5 TFLOPS 来算,一块 FPGA 不停地跑也要 250 年左右;1990 年代的芯片还要再慢好几个数量级。
而“涌现”恰好是规模的产物。Wei 等人把它定义为“小模型上没有、大模型上出现”的能力,许多能力在训练计算量达到 10²² 到 10²⁴ 次浮点运算这个区间时才明显高于随机水平17。也有人认为,所谓的“突然出现”很大程度上是评价指标造成的:用只看答案对错的指标,曲线就像突然跳起来;换成连续的指标,能力其实是平滑增长的18。这两种看法争的是“涌现”是不是突变,但都同意一点:这些能力出现在规模很大的时候,小模型上看不到。
所以就算 1996 年有人用梯度和注意力去训练 FPGA,配置规模、数据和算力也都差了好几个数量级,看不到涌现是意料之中的。那么回到开头的问题,把这几条放在一起,答案是什么?
六、为什么 FPGA 时代没有出现涌现
先把时间线摆出来。FPGA 和神经网络其实是同时代的东西,并不存在“先有 FPGA 时代、后有 Transformer 时代”。
把前面几节合起来,答案可以分成三层。
第一层:智能不在电路里,在配置里。 FPGA 是一种承载配置的硬件,和 GPU 是同一类东西。问“FPGA 上为什么没有涌现”,就像问“GPU 上为什么在 2012 年之前没有涌现”:硬件一直在那里,缺的是一份够好的配置。FPGA 的四十年里,几乎所有配置都是工程师写的,而人写出来的电路不会超出写它的人对问题的理解。
第二层:唯一能自动写配置的办法,在 FPGA 的比特上走不远。 进化是那个年代最自然的尝试,Thompson 的实验也确实长出了没人设计过的电路;但离散的比特没有梯度,搜索的代价随配置长度急剧上升,我们的小实验在几千比特的规模上就看到了这一点。能把配置写到几万亿比特的只有梯度下降,而梯度下降要求配置是连续的。反向传播 1986 年就有了11,它天然属于神经网络那条线,不属于 FPGA。
第三层:就算有了连续参数,还要有合适的结构和足够的规模。 注意力让“连哪里”变成数据的函数,一组参数能用在任意长度的输入上;而涌现出现在配置、数据和算力都很大的时候。等到这几样凑齐,跑训练的硬件已经是 GPU 了:它天生适合大块的矩阵乘法,改一行代码几秒钟就能重新跑,而 FPGA 改一次设计要等几个小时的布局布线。Hooker 把这种“一条研究路线能不能赢,取决于它是否碰巧适合当时的硬件”的现象叫作硬件彩票19,神经网络抽中的是 GPU。
所以更准确的说法是:FPGA 时代并不缺可配置的电路,缺的是一个能从数据里自动写出几万亿个配置数的方法,以及让这个方法有效的连续参数、可学习的连接方式、海量数据和算力。这些条件凑齐的地方是 GPU 上的神经网络。FPGA 后来也接上了这条线:Brainwave 把训练好的网络放到 FPGA 上跑,可微逻辑门让梯度来写查找表,但写配置的始终是梯度,不是 FPGA 自己。
七、回到开头
回到开头那两个十六进制数。0x96 和 0xE8 是人写的:工程师先知道全加器是什么,再把它的真值表交给工具。神经元那 9 个实数 [1, 1, 1], −1.5 和 [1, 1, 1, −2], −0.5,其实也是我们手写的,它们和 0x96 一样“不聪明”。
这一点可以在 Transformer 自己身上看得很清楚。AdderBoard 排行榜上有一个只有 6 个参数的 Transformer,能把十位数加法做对,它的 6 个参数全是人推出来的,本质上是一个用 Transformer 零件搭出来的加法电路,和 FPGA 上手写的加法器没有什么两样;同一个榜上训练出来的模型最少要 36 个参数,那是梯度下降自己找到的解(详见《做加法最少要几个参数》)。
所以 Transformer 和 FPGA 的差别,不在“它是不是电路”,而在这串配置数能不能由梯度从数据里写出来,以及写到多大。手写的配置,不管放在 FPGA 上还是 Transformer 上,都不会涌现;梯度写的配置,放到 FPGA 上照样能跑。
小结
- 两者相同在哪? 都是“固定骨架 + 一串配置数”:FPGA 的配置是查找表和导线开关的比特,Transformer 的配置是权重。都能表示任意函数,也能互相实现:FPGA 能跑神经网络,训练好的网络能编译成查找表。
- 表示能力是不是差别? 不是。Transformer 一次前向是常数深度的阈值电路,FPGA 加上寄存器和时钟是任意状态机,一步之内 FPGA 甚至更强。
- 配置由谁来写?为什么 Transformer 的参数能收敛? FPGA 上是人,Transformer 上是梯度。收敛就是沿着损失的坡度一步步往下走:Transformer 的每个零件都可导,残差和归一化让坡度传得下去,参数多让低处连成一片。FPGA 的比特只有 0 和 1,损失对它的坡度处处是 0,只能整位翻过去试;Thompson 的进化电路 1800 个比特就要 25 万次评估,我们的实验里变异搜索在几千比特的网络上就追不上梯度下降。把比特放松成实数以后,梯度一样能写查找表。
- 导线有什么不同? FPGA 的连接在烧写时铺好,每条可能的路都写在配置里;注意力的连接每一步由数据算出,参数和序列长度无关,比较规则本身也能学。
- 规模差多少? 最大 FPGA 的查找表内容约 5.4 亿比特,GPT-3 约 2.8 万亿比特,还要 3000 亿 token 和 3×10²³ 次浮点运算;涌现只在这样的规模上出现。
- 为什么 FPGA 时代没有涌现? 因为智能在配置里而不在电路里;那个年代能自动写配置的方法走不远,能走远的梯度下降属于神经网络,等数据和算力凑齐时它已经跑在 GPU 上了。
如果想自己试一试,实验代码只有一百来行,依赖 PyTorch,train_grad 和 train_evo 分别是梯度和变异两种写法,在笔记本上几分钟就能跑完 2 到 4 位加法12。
参考资料
Footnotes
-
Chip Hall of Fame: Xilinx XC2064 FPGAspectrum.ieee.org ↗1985 年的第一块 FPGA,64 个可配置逻辑块,每块是一个 4 输入的逻辑函数。https://spectrum.ieee.org/chip-hall-of-fame-xilinx-xc2064-fpga ↩
-
AMD Introduces World's Largest FPGA-Based Adaptive SoC for Emulation and Prototypingir.amd.com ↗Versal Premium VP1902:1850 万个系统逻辑单元、846 万个 LUT。“最大”是厂商自己的说法。https://ir.amd.com/news-events/press-releases/detail/1141/amd-introduces-worlds-largest-fpga-based-adaptive-soc ↩
-
Attention Is All You Needarxiv.org ↗https://arxiv.org/abs/1706.03762 ↩ ↩2
-
The Parallelism Tradeoff: Limitations of Log-Precision Transformersarxiv.org ↗对数精度的 Transformer 一次前向可以用常数深度的阈值电路模拟,属于 uniform TC⁰。https://arxiv.org/abs/2207.00729 ↩
-
The Expressive Power of Transformers with Chain of Thoughtarxiv.org ↗允许生成中间步骤后,线性步数可以识别全部正则语言,多项式步数恰好对应 P(各自带有归一化方式的前提条件)。https://arxiv.org/abs/2310.07923 ↩ ↩2
-
Serving DNNs in Real Time at Datacenter Scale with Project Brainwavemicrosoft.com ↗微软在 Intel Stratix 10 FPGA 上跑神经网络推理,批大小为 1 时有效算力 39.5 TFLOPS,权重全部放在片上存储里。https://www.microsoft.com/en-us/research/uploads/prod/2018/03/mi0218_Chung-2018Mar25.pdf ↩
-
LUTNet: Learning FPGA Configurations for Highly Efficient Neural Network Inferencearxiv.org ↗直接训练 FPGA 查找表里的内容,把查找表当作神经网络的算子。https://arxiv.org/abs/1910.12625 ↩
-
LogicNets: Co-Designed Neural Networks and Circuits for Extreme-Throughput Applicationsarxiv.org ↗先训练稀疏、低比特的网络,再把每个神经元整个换成一张真值表,编译成 FPGA 网表。https://arxiv.org/abs/2004.03021 ↩
-
FPGA Design Suite Generates Global Minimum Layoutelectronicdesign.com ↗Virtex-7 2000T 上的一个大设计,Vivado 布局布线用了 5 小时、9 GB 内存,旧工具 ISE 要 13 小时。https://www.electronicdesign.com/technologies/embedded/digital-ics/fpga/article/21789745/fpga-design-suite-generates-global-minimum-layout ↩
-
An Evolved Circuit, Intrinsic in Silicon, Entwined with Physicscse-robotics.engr.tamu.edu ↗在 XC6216 的 10×10 格上用遗传算法进化出音调分辨电路。文中的代数、评估时间、32 个有效格、温度实验都取自这篇论文的第 3–5 节。https://cse-robotics.engr.tamu.edu/dshell/cs625/Thompson96Evolved.pdf ↩ ↩2
-
Learning representations by back-propagating errorsdoi.org ↗https://doi.org/10.1038/323533a0 ↩ ↩2
-
本文的实验代码与调研笔记
/mnt/project-files/transformer-fpga-research/:experiment/lutnet.py是查找表网络和两种训练方法,run_scale.py、run_more.py是实验入口,输出在logs/。PyTorch 2.14.1 CPU 版,4 核。 ↩ ↩2 -
Deep Differentiable Logic Gate Networksarxiv.org ↗把每个逻辑门放松成 16 种二输入门的概率混合,用梯度训练,训练完再取最可能的那个门。https://arxiv.org/abs/2210.08277 ↩
-
Convolutional Differentiable Logic Gate Networksarxiv.org ↗同一思路做到 CIFAR-10 上 86.29%,用了约 6100 万个逻辑门。https://arxiv.org/abs/2411.04732 ↩
-
Binarized Neural Networksarxiv.org ↗权重和激活都是 ±1 的网络;训练时保留实数权重,用直通估计(straight-through estimator)让梯度穿过取符号。凭领域知识整理,发文前可再核对。https://arxiv.org/abs/1602.02830 ↩
-
Language Models are Few-Shot Learnersarxiv.org ↗GPT-3:1750 亿参数,训练用了约 3000 亿个 token。https://arxiv.org/abs/2005.14165 ↩ ↩2
-
Emergent Abilities of Large Language Modelsarxiv.org ↗附录里 GPT-3 175B 的训练计算量记为 3.14×10²³ FLOPs;涌现能力定义为“小模型上没有、大模型上出现”。https://arxiv.org/abs/2206.07682 ↩ ↩2
-
Are Emergent Abilities of Large Language Models a Mirage?arxiv.org ↗认为很多“突然出现”是评价指标不连续造成的,换成连续指标后曲线是平滑的。https://arxiv.org/abs/2304.15004 ↩
-
The Hardware Lotteryarxiv.org ↗一个研究方向能不能赢,很大程度上取决于它是否碰巧适合当时的硬件和软件。https://arxiv.org/abs/2009.06489 ↩