尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从一条直线到大模型输出一个token(三):隐藏层与嵌入

从一条直线到大模型输出一个token(三):隐藏层与嵌入 从一条直线到大模型输出一个token三隐藏层与嵌入建议先看从一条直线到大模型输出一个token二分词与token表上一篇末尾我们把今天西安的天气怎么样变成了一串干巴巴的整数[ 5237 , 23872 , 301 , 16652 , 19602 , 1148 ] [5237,\ 23872,\ 301,\ 16652,\ 19602,\ 1148][5237,23872,301,16652,19602,1148]。这一篇解决一个问题这些编号没有任何语义模型怎么读懂它们从一条直线到大模型输出一个token三隐藏层与嵌入从一条直线到大模型输出一个token三隐藏层与嵌入1. 先看全局大模型是一条流水线2. 模型的宽度一个 token 用多少个数字表示2.1 直觉字用笔画描述token 用什么描述2.2 为什么不能直接用 token id2.3 蠢办法one-hot 编码2.4 聪明办法稠密向量隐藏层登场的时刻3. 语义空间的魔法国王 − 男人 女人 ≈ 女王4. 嵌入层一张 5.3 亿参数的查询表4.1 嵌入层的真面目就是个查表4.2 贯穿案例6 个 token 的查表全过程4.3 这些数字哪来的训练5. 嵌入矩阵的两个不知道小结下一篇预告1. 先看全局大模型是一条流水线在钻进细节之前先把大模型的整体轮廓画出来。剥掉所有花哨的概念一个大模型就是一条四段流水线如图 3-1 所示。图3-1 大模型整体流水线本篇位置第一站嵌入层第一段token 数组上一篇的产出6 个整数第二段嵌入层把 6 个整数变成 6×4096 的数字矩阵本篇主角第三段几十层 Transformer逐层加工语义第 4~9 篇逐层拆第四段输出层把最后一层的结果变成 12.8 万个词的概率第 10 篇不同 Transformer 层之间的处理方式一句话概括上一层的输出矩阵就是下一层的输入矩阵。数据从头流到尾形状基本不变6×4096 进6×4096 出但每一层都在悄悄改写矩阵里的数字——离输出越近数字里编码的语义越深。这一篇只讲第一站嵌入层。2. 模型的宽度一个 token 用多少个数字表示2.1 直觉字用笔画描述token 用什么描述一个汉字可以用笔画描述鑫有 24 画全是金一个 token 呢模型的世界里一个 token 的全部信息就是一串数字。问题是用多少个数字用 1 个数只能表达重要/不重要这种一维信息太穷了用 10 个数能表达 10 个独立的特征勉强用 4096 个数每个数字都是一个独立维度的特征够用这个数字就是模型宽度d_model当前主流大模型清一色 4096LLaMA-3-8B、GLM-4、DeepSeek-V3系列基线都是。宽度越大的模型单个 token 能携带的语义信息越丰富——这也是大模型大的含义之一。2.2 为什么不能直接用 token id有个绕不开的问题为什么不直接把 token id比如 5237当输入非要变成 4096 个数字因为 id 只是个编号编号本身没有语义。5236 和 5237 相差 15237 和 5238 也相差 1但它们对应的词可能一个是“一个是天气”——编号的距离和语义的距离毫无关系。更麻烦的是id 的数值大小还会干扰矩阵运算下一篇会看到模型会误以为 5238 比 5237更重要。2.3 蠢办法one-hot 编码真要硬用编号标准的做法是 one-hot把每个 token 表示成一个 129,280 维的向量词表多大就多少维只有自己那个位置是 1其他全是 0。“今天”id5237就是第 5237 位是 1 的超长向量。这办法有两个致命伤如图 3-2 所示。图3-2 为何需要嵌入层one-hot 的两个致命伤 vs 稠密向量任何两个词的距离都一样远。one-hot 向量之间两两垂直「今天」和「天气」的距离等于「今天」和「」的距离。语义信息为零。维度爆炸。一个 token 要占 129,280 个数字的存储6 个 token 就是 6×129,280——而其中 99.997% 都是 0。2.4 聪明办法稠密向量隐藏层登场的时刻解决方案给每个 token 配 4096 个训练出来的实数让每个数字都承载一点语义信息。这就是稠密向量dense vector也叫词向量word embedding。回头看第一篇的升维思想一条直线1 维不够用就升到平面2 维、升到高维。这里一模一样——1 个编号不够表达语义就升到 4096 维让每一维都贡献一点语义。4096 维的空间里「今天」和「天气」可以靠得很近「今天」和「」可以离得远——距离有了含义。这个 4096 维向量所在的地方术语叫隐藏层hidden layer / hidden state。隐藏的意思很朴素它是模型的内部状态用户看不见只存在于模型肚子里的层层计算之间。3. 语义空间的魔法国王 − 男人 女人 ≈ 女王隐藏层最迷人的性质是语义可以做几何运算。把每个词的向量画在语义空间里演示用 2 维真实 4096 维会发现一个惊人的规律语义类比关系 空间中的平行向量如图 3-3 所示。图3-3 语义空间的几何运算国王−男人女人≈女王具体过程国王 − 男人 女人 ≈ 女王 \text{国王} - \text{男人} \text{女人} \approx \text{女王}国王−男人女人≈女王「男人 → 女人」这个箭头方向代表性别这个语义维度「男人 → 国王」这个箭头方向代表王室这个语义维度从「国王」出发加上性别方向的箭头落点附近最近的词就是「女王」这个著名例子word2vec 时代就发现说明了一件事隐藏层学到的不是编号而是把语义编码成了几何关系。男人/女人共享人类维度、国王/女王共享王室维度——这些规律没有人教纯粹从海量文本的统计共现中学出来。顺便回答大纲里的问题——隐藏层解决了什么问题它把离散的、无语义的 token id翻译成了连续的、有几何结构的语义向量。没有这一步后面的注意力机制第 7 篇根本无从谈起——注意力要计算词和词的相关性而相关性就是向量距离id 之间没有距离可言。4. 嵌入层一张 5.3 亿参数的查询表4.1 嵌入层的真面目就是个查表说明本系列的词表规模取自 DeepSeek-V3——其 token 词表大小为129,280128K数据来源是 HuggingFace 官方模型仓库的config.json中vocab_size字段deepseek-ai/DeepSeek-V3。后续篇章涉及词表规模的计算都以这个数字为准。把 129,280 个 token 各配一个 4096 维向量需要的存储就是一张大表DeepSeek-V3 词表 129,280 行宽度 4096E ∈ R 129280 × 4096 \mathbf{E} \in \mathbb{R}^{129280 \times 4096}E∈R129280×4096参数量的算法129,280 × 4096 529,530,880 ≈ 5.3 129{,}280 \times 4096 529{,}530{,}880 \approx 5.3129,280×4096529,530,880≈5.3亿个实数参数每个数用 2 字节半精度浮点存储约 1GB。这就是嵌入层Embedding Layer。术语听起来玄乎实现却朴素得让人失望**嵌入层就是一张查询表token id 是行号输入 id返回那一行的 4096 个数字。**没有乘法没有激活函数就是查表。注意区分两件事整张嵌入表 E 是 129,280×40965.3 亿参数常驻显存对一句 6 token 的话查表输出只是 6×409624,576 个数——它只是从大表里捞出 6 行。用代码描述大模型实现细节跳过不影响理解# 嵌入层的伪代码一张大表 一次查表classEmbedding:def__init__(self,vocab_size129280,d_model4096):self.tablerandom_init(vocab_size,d_model)# 训练前随机初始化129,280×4096defforward(self,token_ids):# 输入: [5237, 23872, 301, 16652, 19602, 1148] 长度 6returnself.table[token_ids]# 查表: 按 6 个行号取出 6 行 → 6×4096 矩阵table[token_ids]就是全部——token id 当行号用六行拼成一个矩阵。4.2 贯穿案例6 个 token 的查表全过程把我们贯穿案例的 6 个 token 代入完整过程如图 3-4 所示。图3-4 嵌入层查表6个token id → 6×4096矩阵演示6×4id5237 查第 5237 行拿到「今天」的向量[ 0.32 , − 1.07 , 0.88 , 0.05 ] [0.32, -1.07, 0.88, 0.05][0.32,−1.07,0.88,0.05]演示值真实是 4096 个数id23872 查第 23872 行拿到「西安」的向量……6 次查表拼出矩阵X [ 0.32 − 1.07 0.88 0.05 − 0.58 0.91 0.27 − 0.72 0.41 − 0.22 0.95 0.18 − 0.41 1.22 − 0.19 0.66 0.77 0.15 − 0.93 0.44 − 0.12 0.87 0.33 − 1.05 ] \mathbf{X} \begin{bmatrix} 0.32 -1.07 0.88 0.05 \\ -0.58 0.91 0.27 -0.72 \\ 0.41 -0.22 0.95 0.18 \\ -0.41 1.22 -0.19 0.66 \\ 0.77 0.15 -0.93 0.44 \\ -0.12 0.87 0.33 -1.05 \end{bmatrix}X​0.32−0.580.41−0.410.77−0.12​−1.070.91−0.221.220.150.87​0.880.270.95−0.19−0.930.33​0.05−0.720.180.660.44−1.05​​shape 从( 6 , ) (6,)(6,)变成( 6 , 4 ) (6, 4)(6,4)真实规模( 6 , 4096 ) (6, 4096)(6,4096)。从此刻起模型操作的对象从整数升级成了矩阵——第一篇学的矩阵乘法从下一篇开始就要真刀真枪地上了。4.3 这些数字哪来的训练表里的 5.3 亿个数字不是人填的是训练出来的。训练开始前随机初始化训练过程中模型每次预测错了比如该输出晴却输出了雨误差会一路反传回嵌入表微调每个 token 的向量——「西安」的向量会被推向地名语义区「天气」的向量被推向气象语义区。几万亿 token 训练下来这张表就成了一部语义地图。这也解释了为什么嵌入层是模型参数量的重要组成部分5.3 亿参数约占一个 8B 模型总参数的 6.6%。5. 嵌入矩阵的两个不知道嵌入层解决了语义问题但留下了两个大坑——这正是下一篇文章存在的理由。坑一矩阵不知道顺序。做个实验把 X 的第 1 行今天和第 4 行天气交换得到 X′如图 3-5 所示。图3-5 嵌入矩阵的两个「不知道」不知道顺序也不知道语义对矩阵乘法来说X 和 X′ 只是被当作两张行排列不同的表每行内容不变后续计算对每一行的处理方式完全一样。“今天在天气前面这个信息矩阵本身完全没记录。比如我吃苹果和苹果吃我”同样的三个词顺序不同意思就不同一个是陈述一个荒唐但矩阵 X 完全分不出这两种情况。坑二矩阵里还没有上下文。第 3 行的「今天」向量在整句话的语境里应该是提问时间背景的意思但如果单看这一行它和「今天吃了什么」里的「今天」是同一个向量。一个词的具体含义要结合上下文才能确定——这个结合上下文的活儿嵌入层干不了得靠后面的 Transformer。小结这一篇token 从整数进化成了矩阵模型宽度 d_model4096一个 token 的语义用 4096 个数字表示宽度是大模型之大的来源之一one-hot 的致命伤距离无意义维度爆炸逼出了稠密向量方案——隐藏层隐藏层把语义编码成几何关系国王−男人女人≈女王嵌入层一张 129,280×4096 的查询表约 5.3 亿参数id 当行号查表即得向量贯穿案例[ 5237 , 23872 , 301 , 16652 , 19602 , 1148 ] [5237, 23872, 301, 16652, 19602, 1148][5237,23872,301,16652,19602,1148]查表成 6×4096 矩阵演示 6×4留下两个坑矩阵不知道顺序、不知道上下文下一篇预告矩阵不知道顺序那就手动把顺序信息加进去。下一篇讲位置编码RoPE——给每个 token 的向量打上我在第几位的标记。会看到三代方案的演进正弦余弦绝对位置编码原始 Transformer2017→ 可学习位置编码GPT-2 时代→ 旋转位置编码 RoPE当前所有主流大模型的事实标准。并且第一次用第一篇学的矩阵乘法给我们的 6×4 矩阵亲手算一遍位置编码。系列目录从一条直线到高维空间分词与 token 表隐藏层与嵌入当前篇位置编码 RoPETransformer Block 全景与层归一化QKV 三剑客注意力权重与多头机制残差连接与前馈网络输出矩阵与多层堆叠首 token 诞生与 KV-Cache版权声明本文为博主原创文章遵循 CC 4.0 BY-SA 版权协议转载请附上原文出处链接和本声明。
返回列表