首页›行业资讯›在35美元FPGA上运行语言模型
← 返回行业资讯
技术教程

在35美元FPGA上运行语言模型

Hacker News ·
作者介绍如何在低成本35美元FPGA开发板上运行语言模型,展示边缘推理可行性。
本文为原文全文的中文翻译(约 3271 字),原文配图已同步至站内;机器翻译仅供快速阅读,细节请以原文为准。

在35美元FPGA上运行语言模型

我最近开展了一个在FPGA上实现语言模型的项目。简单来说,现场可编程门阵列(FPGA)是一种可重新配置的集成电路,能够实现用硬件描述语言(HDL,如SystemVerilog)编写的硬件电路设计。它们特别有意思的地方在于,你不需要像使用微控制器那样在其上运行软件,而是将芯片重新配置为硬件设计。这能带来软件无法实现的能力,比如组合逻辑电路中的真正并行性。MiSTer等项目正是借此实现了与原始硬件极为接近的主机模拟。

我的目标是:

我最终得到了一个使用TinyChat数据集训练的107万参数模型。它能够以约每秒10个token的速度生成基本连贯的输出。

这里有一个可在浏览器中运行的交互式模型移植版本,你可以试用一下来感受模型的行为表现。

下一token候选 按Run或Step。专家:路由器在18个专家中选择了哪些,每循环一次 上下文:注意力机制看到最后32个token,delta状态记住其余部分 你的消息在注意力窗口之外生成 你可以在GitHub上找到项目文件,在Hugging Face上找到模型检查点。

硬件约束

我使用的FPGA平台是iCESugar上的iCE40UP5K。这是一个资源严重受限的平台。

从规格来看,最重要的特性是:

我实际上只有144KB的存储空间,且没有原生浮点运算支持。这意味着我从一开始就需要将模型设计为定点数量化。

V1 - 238K参数

我从非常简单的结构开始,使用带有自注意力的单层Transformer,针对Int4进行量化感知训练。分词器使用在TinyChat上训练的BPE,词表大小为2048。

我从tinyworldformer中获得了一些灵感,尝试了循环Transformer。

其思路是将输出反馈通过部分或全部层。这样在不增加模型层数的情况下,每个token可以获得更高的有效深度。

测试表明,我的模型在6次循环时性能最佳,不过这仅基于我所使用的数据集。

最终架构如下所示

Ice40GPT( (tok): Embedding(2048, 64) (pos): Embedding(32, 96) (up): QLinear(in_features=64, out_features=96, bias=False) (blocks): ModuleList( (0): Block( (norm1): ModuleList( (0-5): 6 x RMSNorm() ) (norm2): ModuleList( (0-5): 6 x RMSNorm() ) (qkv): QLinear(in_features=96, out_features=144, bias=False) (proj): QLinear(in_features=96, out_features=96, bias=False) (up): QLinear(in_features=96, out_features=384, bias=False) (down): QLinear(in_features=384, out_features=96, bias=False) ) ) (norm): RMSNorm() ) 该设计是一个逐token处理的状态机。它遵循预期的流程:嵌入 →(归一化 → 注意力 → 前馈)× 6次循环 → logits。板卡启动时,模型权重被复制到SPRAM中,而Block RAM则存放激活值和KV缓存。与设备的通信通过UART以115200波特率完成。

为了节省资源:

扩展至100万参数

既然已经有了一个可工作的设计,我想将模型扩展到超过100万参数,约为当前模型规模的5倍。这意味着需要寻找机会,在遵守硬件约束并保持性能的前提下扩大模型。

因此,以下是我实施的改进(排名不分先后):

混合专家(MoE)架构

从稠密模型转向稀疏模型,使我能够增大前馈网络的规模,而无需显著增加矩阵乘法的规模。我还将模型权重移至闪存,并动态复制每个 token 所需的专家。这使我能够将模型规模扩大到 1M 参数,但每个 token 仅保持约 200k 活跃参数(1M-A200k)。

使用 RoPE 替代位置嵌入

为 token 位置保留第二张嵌入表的开销较大,约 1.5 KB。将其替换为旋转位置嵌入(RoPE)后,我可以用少量额外的动态计算来替代该表。

混合门控 delta 网络实现更长上下文

我希望模型在更长上下文的响应上表现更好,但由于 RAM 有限,无法扩展上下文窗口,因此我选择了门控 delta 网络,它能维持固定的内存预算。在我的设计中,我发现它更像是一种长期记忆,因此自注意力关注的是上下文窗口中存在的 token,而 delta 网络的输出残差则维护已被挤出窗口的 token 的摘要。

经过这些修改后,我的模型架构如下所示。

Ice40GPT((tok): Embedding(2048, 64) (up): QLinear(in_features=64, out_features=96, bias=False) (blocks): ModuleList( (0): Block( (norm1): ModuleList( (0-5): 6 x RMSNorm() ) (norm2): ModuleList( (0-5): 6 x RMSNorm() ) (qkv): QLinear(in_features=96, out_features=144, bias=False) (proj): QLinear(in_features=96, out_features=96, bias=False) (delta): DeltaMixer( (qkv): QLinear(in_features=96, out_features=96, bias=False) (gate): QLinear(in_features=96, out_features=4, bias=False) (proj): QLinear(in_features=32, out_features=96, bias=False) ) (moe): Experts( (router): ModuleList( (0-5): 6 x QLinear(in_features=96, out_features=18, bias=False) ) ) ) ) (norm): RMSNorm() ) 而这是当前的资源利用率报告。

信息:器件利用率:信息:ICESTORM_LC:5215/5280 98% 信息:ICESTORM_RAM:29/30 96% 信息:SB_IO:12/39 30% 信息:SB_GB:6/8 75% 信息:ICESTORM_PLL:0/1 0% 信息:SB_WARMBOOT:0/1 0% 信息:ICESTORM_DSP:8/8 100% 信息:ICESTORM_HFOSC:0/1 0% 信息:ICESTORM_LFOSC:0/1 0% 信息:SB_I2C:0/2 0% 信息:SB_SPI:0/2 0% 信息:IO_I3C:0/2 0% 信息:SB_LEDDA_IP:0/1 0% 信息:SB_RGBA_DRV:0/1 0% 信息:ICESTORM_SPRAM:4/4 100% 信息:SB_FILTER_50NS:0/2 0% 信息:根据约束条件放置了12个单元。信息:时钟'clk$SB_IO_IN_$glb_clk'的最大频率:22.50 MHz(在12.00 MHz下通过)信息:时钟'clk$SB_IO_IN_$glb_clk'的最大频率:21.81 MHz(在12.00 MHz下通过)结论:总的来说,这非常有趣。参与这个项目让我对底层运作有了更深入的理解。学习在约束条件下进行构建总是很有启发性的。

展望未来,我认为系统的每个部分都还有很大的优化空间。我正在考虑的事项包括:

阅读原文 →
来源:Hacker News

本页摘要由 AI 辅助整理,经编辑审核后发布;AI 仅用于提炼与分类,原文均附来源链接。