把GPT拆成数据结构,一文看懂Transformer底层原理
文章目录1. 先宏观理解Transformer 是个翻译中介2. 拆开黑盒编码器 解码器2.1 编码器两个子层一条龙2.2 解码器多了一张“偷看”的嘴3. 张量数字排队进模型3.1 输入是一张矩阵3.2 超参数程序员的专属旋钮4. 开始 encode每个词各走各路5. self-attention让每个词学会查户口5.1 为什么要上下文5.2 RNN一边写一边记小抄5.3 Q/K/V相亲三角色5.4 注意力六步走6. 矩阵版注意力六步合一7. 多头注意力8 个脑袋同时干活8. 位置编码给词排座次9. 终极拷问Qwen 7B 的 7B 是什么P.S. 无意间发现了一个巨牛的人工智能教程非常通俗易懂对AI感兴趣的朋友强烈推荐去看看 传送门https://blog.csdn.net/HHX_01在 AI 圈混最怕的不是学不会而是名词太多。多头注意力、位置编码、QKV、Embedding……我的脑容量大概只有 64GB还全是缓存根本存不住这些词。所以今天我不背名词换个思路把 GPT 当数据结构拆。1. 先宏观理解Transformer 是个翻译中介看 Transformer 的结构图我总有一种看相亲节目流程图的错觉。左侧输入法语“je suis étudiant”右侧输出英语“I am a student”中间那个蓝盒子就是 Transformer 本体帮你把一句人话变成另一句人话。把包装纸撕开里面其实就三样东西一堆编码器Encoder、一堆解码器Decoder、以及连接它们的管道。就这么简单跟食堂打菜窗口一个逻辑窗口是固定的吃什么取决于你递过去的盘子。常规配置是 6 层编码器 6 层解码器。为什么是 6没有为什么跟油条配豆浆一样属于出厂默认套餐你想 12 层也没人拦你只要显卡扛得住。2. 拆开黑盒编码器 解码器2.1 编码器两个子层一条龙每个编码器就两个子层Self-Attention自注意力编码某个词的时候顺便瞄一眼其他词在干嘛Feed Forward前馈网络每个词独立处理谁也不碍着谁流程很简单输入先进自注意力再进前馈网络最后把结果递给下一个编码器。6 个编码器结构长得一模一样但权重完全不一样——就像双胞胎长得像性格一个社牛一个社恐。2.2 解码器多了一张“偷看”的嘴解码器在编码器那两层的基础上中间多了一层 Encoder-Decoder Attention专门盯着编码器的输出看。你可以这样理解编码器是出题老师解码器是答题学生中间那层注意力就是学生偷偷瞄参考答案的目光。老师写答案的时候不看学生学生写答案的时候必须看老师的板书。3. 张量数字排队进模型3.1 输入是一张矩阵所有 NLP 模型的第一步都是 embedding把每个词变成一坨数字。拿“我喜欢苹果”来说我 喜欢 苹果 ↓ ↓ ↓ 向量1 向量2 向量3为了方便演示我用 4 维向量数值都是我现场瞎编的sentence_vectors [ [0.1, 0.3, -0.2, 0.5], # “我”的向量 [0.6, -0.1, 0.4, 0.2], # “喜欢”的向量 [0.2, -0.5, 0.8, 0.1], # “苹果”的向量 ]真实场景里每个词是 512 维所以这个例子的输入就是一张 3×512 的矩阵3 个词每个词 512 个数字。一个句子 3 个词就 1536 个数字你平时打的那几百字换算成数字大概能撑爆我的想象。3.2 超参数程序员的专属旋钮超参数就是模型和训练过程的外部配置是你说什么它听什么的少数场景之一。比如max_seq_length 5 # 每条输入序列最多保留 5 个 token这个值设多少完全看心情模型只有照做的份连反驳都不敢。4. 开始 encode每个词各走各路嵌入只发生在最底层的编码器。再往上每个编码器接收的都是正下方编码器吐出来的向量列表。这里有个关键特性每个位置的词在编码器里都有自己的专属通道。自注意力层里这些通道之间有依赖关系不能并行但到了前馈层大家彻底独立可以同时跑。翻译成人话自注意力层像早高峰排队进地铁前馈层像各吃各的外卖互不干扰。5. self-attention让每个词学会查户口5.1 为什么要上下文翻译 “The animal didn’t cross the street because it was too tired” 时模型必须搞清楚 “it” 到底指谁是 street 还是 animal这个对人是送分题对算法就是送命题。就像女朋友说“随便”你永远不知道她指的是火锅还是日料猜错就是一场冷战。self-attention 干的事就是处理每个词的时候回头把整句话扫一遍寻找线索把“it”和“animal”强行绑在一起。5.2 RNN一边写一边记小抄如果你懂 RNN可以把它的 hidden state 理解为小抄处理新词的时候手里攥着前面所有词压缩出来的信息。第 1 步处理“我” 当前输入 x1 初始状态 h0 → RNN 计算 → 得到 h1 第 2 步处理“喜欢” 当前输入 x2 上一步状态 h1 → RNN 计算 → 得到 h2 第 3 步处理“苹果” 当前输入 x3 上一步状态 h2 → RNN 计算 → 得到 h3注意这里的“”不是简单相加而是“一起参与计算”。关键点在于处理“苹果”的时候传进来的不只是“苹果”的向量还有记录了“我”“喜欢”的 h2。小抄有个致命缺点写太长就会忘记前面写了什么——RNN 处理长句会丢失早期信息这跟我的记忆力同款毛病。Transformer 不记小抄它直接把整句话摊在桌上查想翻哪页翻哪页。5.3 Q/K/V相亲三角色self-attention 第一步为每个输入向量生成三个新向量——Query、Key、Value。它们来自训练好的三个权重矩阵 WQ、WK、WV。Query你在相亲现场手里拿的“我的条件清单”Key对面每个人的“自我介绍”Value如果看对眼了对方身上值得打包带走的优点5.4 注意力六步走拿第一个词 “Thinking” 举例**第一步算分。**用 q1 和每个词的 key 做点积。分数越高说明越“来电”。**第二步除以 8。**8 是 64 维 key 向量维度的平方根业界默认值目的是让梯度更稳定。相当于打分之前先深呼吸三秒防止情绪上头。**第三步softmax。**把分数变成正数且加起来等于 1像极了把一学期成绩换算成 GPA反正怎么算都不好看。**第四步加权。**把每个 value 乘以对应的 softmax 分数。想关注的词保留原值无关紧要的词乘个 0.001直接淹没。**第五步求和。**把加权后的 value 全部加起来得到当前位置的输出 z1。到此单词版 self-attention 结束。但实际跑起来没人用单词版太慢了我们看矩阵版。6. 矩阵版注意力六步合一矩阵版就三行Q X × WQ K X × WK V X × WV整个注意力输出一步算完Attention softmax(Q × Kᵀ / √d_k) × VX 的每一行对应一个词。注意维度embedding 是 512 维Q/K/V 只有 64 维。进模型的时候是个 200 斤的大胖子到注意力层直接瘦身成 64 维——所以说注意力机制是 AI 界的健身房进去的都掉维度。7. 多头注意力8 个脑袋同时干活单个注意力头有个毛病z1 里绝大部分还是词自己的信息旁边词只蹭到一点点。就像一个人 review 代码眼里全是自己写的部分bug 看半天看不见。论文的解决办法简单粗暴搞 8 组 Q/K/V 权重矩阵8 个头同时算得到 8 个不同的 Z。相当于 8 个程序员一起 code review有人盯格式有人盯逻辑有人盯性能各有各的关注点。最后一步把 8 个 Z 拼成一个长条矩阵再乘一个联合训练的权重矩阵 WO压回一个矩阵喂给前馈网络。8. 位置编码给词排座次Transformer 本身对“顺序”一无所知。在它眼里“我打你”和“你打我”可能完全一样——这比脸盲还严重它连主语宾语都分不清。解决办法给每个词的 embedding 加上一个位置向量。这个向量遵循特定规律——左半边用 sin 函数生成右半边用 cos 函数生成再拼起来保证每个位置都有独一无二的“身份证号”。好处是这套编码能无限扩展到超长序列句子再长位置号都能发得出来绝不重号。9. 终极拷问Qwen 7B 的 7B 是什么答案大约 70 亿个可训练数字分布在一堆矩阵和向量里Qwen 7B ↓ 大约 70 亿个可训练数字 ↓ 这些数字分布在很多矩阵/向量里 ↓ 其中就包括 WQ / WK / WV / WO Embedding 矩阵 FFN 的权重矩阵 LayerNorm 参数 输出层权重 ……你平时聊天的每一个字都是这 70 亿个数字在背后加班算出来的。你的消息是免费的它们的工资是电费。P.S. 无意间发现了一个巨牛的人工智能教程非常通俗易懂对AI感兴趣的朋友强烈推荐去看看传送门https://blog.csdn.net/HHX_01