让大神 Andrej Karpathy 一键三连❤️(点赞 + 转发 + 评论),一个教你从头开始实现 Llama3 的代码库爆火。
X 上转赞收藏量超 6.8k,GitHub 揽星 2k+。
火就火在,它教你从头用 Meta 开源的权重进行推理,详细解释和展开了注意力机制中多个头的矩阵乘法、位置编码以及所有中间层。
换句话说,他解释了每行代码都在干啥。
Karpathy 看后直呼打造者 Nishant Aklecha(后文暂称 “纳哥”)是个有品的人:
完全展开后,比起模块相互嵌套和调用时,更容易理解每一步具体在做什么。
网友们对其也是赞不绝口,纷纷致敬:
话不多说,一起来看纳哥是如何手把手教的。
(量子位在不改变原意的基础上,进行了编译整理)
在运行纳哥提供的文件前,大伙儿需要预先下载 Meta 官方提供的 Llama3 模型权重。
纳哥表示自己没搞分词器,推荐用 Karpathy 的现成简洁版 BPE 代码。
PS:
“字节级(byte-level)”BPE 算法,在 UTF-8 编码的字符串上运行,广泛应用于大模型分词。Karpathy 提供的这个代码库包含两个分词器,都能在给定文本上训练分词器的词汇表和合并规则、将文本编码为 token、将 token 解码为文本。
读取模型文件的方式通常取决于 model classes 的编写方式以及 class 中变量的命名。但由于纳哥是从头开始实现 Llama3,所以将逐个张量地读取文件内容。
通过此配置可以推断出模型的结构和参数信息,例如模型包含的 Transformer 层数、多头注意力块中的头数,以及词汇表的大小等细节。
将文本转换为 token 时,纳哥使用 tiktoken 作为分词器。
接下来,纳哥展示了在代码中将 token 转换为高维的嵌入表示。这是代码库中唯一使用内置神经网络模块的部分。
[17×1]的 token 矩阵变成了 [17×4096] 的嵌入矩阵。也就是说,每个 token 被转换为一个长度为 4096 的嵌入向量,总共有 17 个这样的嵌入向量。
然后,纳哥对嵌入进行 RMS 归一化。经过这一步后,嵌入的形状不会改变,只有数值被归一化了。纳哥强调需要一个 norm_eps,避免意外将 RMS 值设为 0 导致除以 0 的错误。
以下是公式:
构建 Transformer 的第一层,进行归一化处理,从模型字典中访问 layer.0(即第一层)。归一化之后,张量的形状仍然是 [17×4096],与嵌入时相同,但数值已被归一化。
跟着纳哥从头实现注意力机制,加载 Transformer 第一层的注意力头。
从模型中加载 query、key、value 和 output 向量时,它们的形状分别是 [4096×4096]、[1024×4096]、[1024×4096] 和 [4096×4096]。
纳哥表示乍一看有点奇怪,因为理想情况是每个注意力头的 q、k、v 和 o 向量是独立的。而代码作者将它们捆绑在一起,是为了方便并行计算注意力头的矩阵乘法。
把所有这些向量解包开来:
下一步,纳哥将从多个注意力头中解包 query,解包后的形状是 [32x128x4096],32 是 Llama3 中的注意力头数量,128 是 query 向量的大小,4096 是 token 嵌入的大小。
在这里,纳哥访问了第一层第一个注意力头的 query 权重矩阵,query 权重矩阵的大小是 [128×4096]。
将 query 权重矩阵与 token 嵌入相乘,获得每个 token 的 query 向量。结果的形状为 [17×128],有 17 个 token,每个 token 对应一个长度为 128 的 query 向量。
接下来需要位置编码。
现在已经为 prompt 中的每个 token 生成了 query 向量,但每个单独的 query 向量并不知道它在 prompt 中的具体位置。
例如,query:“the answer to the ultimate question of life, the universe, and everything is”(生命、宇宙和一切的终极问题的答案是)。
在这个 prompt 中,使用了三次”the”,需要根据它们在 prompt 中的位置,使这三个”the”token 的 query 向量有所不同(每个向量的大小为 [1×128])。
通过使用 RoPE(旋转位置嵌入)来进行这些旋转操作。
上一步中,纳哥将 query 向量分成对,并对每一对应用一个旋转角度偏移。
由此,得到的向量大小为 [17x64x2],这是将长度为 128 的 query 向量对每个 prompt 中的 token 分成 64 对。这 64 对中的每一对都会根据 m*(theta) 进行旋转,其中 m 是要旋转 query 的 token 的位置。
使用复数的点积来旋转一个向量:
现在每个 token 的 query 元素都有一个复数(角度变化向量),可以将 query 向量(之前分成的对)转换为复数,然后通过点积根据位置旋转 query 向量。
获得旋转后的向量后,可以通过将复数重新视为实数来得到成对的 query 向量。
旋转后的对现在已经合并,有一个新的 query 向量(旋转后的 query 向量),其形状为 [17×128],其中 17 是 token 的数量,128 是 query 向量的维度。
key 与 query 几乎相同。
纳哥表示自己不会详细讲解 key 的数学原理,只需要记住以下几点:
key 生成的 key 向量维度也是 128;key 的权重只有 query 的四分之一,这是因为 key 的权重在同一时间内被 4 个头共享,来减少计算量;key 也会旋转添加位置信息,原因与 query 相同。
此时,纳哥已经为每个 token 获得了旋转后的 query 和 key。每个 query 和 key 现在的形状都是 [17×128]。
下一步,纳哥将对 query 矩阵和 key 矩阵进行相乘操作。这样做会生成一个评分矩阵,将每个 token 关联起来。这些评分描述了每个 token 的 query 与每个 token 的 key 之间的相关性,这就是自注意力机制。
注意力评分矩阵(qk_per_token)的形状为 [17×17],其中 17 是 prompt 中的 token 数量。
接下来需要对 query key 评分进行掩码处理。在 Llama3 的训练过程中,未来 token 的 qk 评分是被掩码的,只通过过去的 token 来预测 token。
因此,在推理时,要将未来的 token 评分设置为 0。
接下来是 value,接近注意力机制的最后一步。
这些评分(0-1)用于确定每个 token 使用多少 value 矩阵。
和 key 一样,value 的权重也在每 4 个注意力头之间共享,所以下面 value 权重矩阵的形状是 [8x128x4096]。
第一层,第一个注意力头的 value 权重矩阵如下所示:
然后是 value 向量。
使用 value 权重来获取每个 token 的注意力值,矩阵的大小是 [17×128],其中 17 是 prompt 中的 token 数量,128 是每个 token 的 value 向量的维度。
注意力:与每个 token 的 value 相乘后得到的注意力向量的形状为 [17×128]。
现在有了第一层第一个头的注意力 value。然后纳哥运行一个循环,对第一层的每个头执行与上面的计算完全相同的数学运算。
然后得到了第一层所有 32 个头的 qkv_attention 矩阵,接下来将所有注意力得分合并成一个大小为 [17×4096] 的大矩阵。
对于第 0 层注意力机制的最后步骤,其一是将注意力得分矩阵与权重矩阵相乘。
这是一个简单的线性层,所以只需进行矩阵乘法。
现在得到了注意力机制后的嵌入 value 变化,应该被添加到原始的 token 嵌入中。
对嵌入增量进行归一化处理,然后通过嵌入增量运行一个前馈神经网络。
在 Llama3 中,加载前馈权重并实现前馈网络。使用了一种名为 SwiGLU 的前馈网络,这种网络结构在模型需要的时候,能够有效地增加非线性。
现在完成了第一层之后每个 token 的新嵌入。现在只剩下 31 层了,只需通过一个循环来完成。
纳哥表示可以将这个编辑后的嵌入想象成包含了第一层中所有查询信息的嵌入。随着层数的增加,每一层都会对输入的信息进行越来越复杂的处理,直到最终得到一个能够全面了解下一个需要预测的 token 的嵌入。
之前做的所有事情,对每一层都重复一次。
然后得到了最终的嵌入,这是模型对下一个 token 的最优预测。这个嵌入的形状与常规的 token 嵌入相同,为 [17×4096],其中 17 是 token 的数量,4096 是嵌入的维度。
最后,将嵌入解码成 token 值。
使用输出解码器将最终的嵌入转换成一个 token。
接下来看纳哥使用最后一个 token 的嵌入来预测下一个 value,希望预测的结果是 42。
因为根据《银河系漫游指南》一书中的说法,42 是 “生命、宇宙及一切的终极问题的答案”。大多数 LLM 在这里都会回答 42,这将验证整个代码的正确性。
模型预测下一个 token 的编号为 2983。这个编号对应数字 42 吗?
OK,结束。
简单介绍一下 Nishant Aklecha。
Nishant Aklecha 是构建和改进定制语言模型平台 Glaive AI 的研究员,曾任职于摩根士丹利,负责训练和微调大语言模型。
此外,他还和朋友一同创立了一个研究实验室,名为 A10(AAAAAAAAAA)。
他们的目标可以总结成一句话:让研究变得更加触手可及。
除了放出这个代码库,Nishant Aklecha 可谓好人做到底。
网友想更好地理解这个代码库的内容,Nishant 直接一个 YouTube 视频甩了过来:
之前 Nishant Aklecha 还曾写过一篇 Blog,详解了潜在一致性模型(LCM),同样收获了不少好评。
啥也不说了,感兴趣的家人们赶紧码住吧。
GitHub 链接:github.com/naklecha/ll…
参考链接:
[1]x.com/naklecha/st…
[2]naklecha.notion.site/explained-l…
[3]www.youtube.com/watch?v=o29…
[4]www.youtube.com/watch?v=eMl…
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。