基础篇

F05|Embedding查表:把一个编号换成一排数

基础篇约 3.7 千字1 组分步图解

从具体对象与小例子开始,理解计算过程与适用条件。

本章目录
动态图解 · F05

Embedding是查一行,不是把编号转二进制

一组浮点数怎样替代一个Token编号?

词表编号像目录的页码;Embedding像打开那一页看到的数值卡。页码2并不会通过“转成0010”得到语义。模型取到的是参数表里事先存好的小数和负数,后续层再根据上下文加工它。

EEmbedding参数表:每行对应一个词表项。
查表以整数编号选择一整行。
上下文化同一初始向量经过不同上下文后得到不同表示。

输入与适用条件:完全沿用F05正文6×4小数参数表。图示的维度是特征宽度,不是二进制位数。

1 / 5 · 为“我”取第1行

第1步,共5步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

Embedding是查一行,不是把编号转二进制:为“我”取第1行6行4列参数表 EPAD0000我0.2-0.10.70.4爱-0.30.80.10.5学习0.60.2-0.40.9你0.1-0.50.90.3!-0.20.40.5-0.6我 → 编号1用编号选一行,不对编号做二进制展开。取出的四个特征0.2-0.10.70.4

编号1定位Embedding表的第1行,得到[0.2, -0.1, 0.7, 0.4]。这一行用来表示本例Token“我”,不会因为同批还有其他句子而改为另一行。

E[1] = [0.2, -0.1, 0.7, 0.4]

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

编号方便定位项目,但直接比较编号大小不能表达任务所需关系。

怎样实现

为每项取出可训练的向量,再交给后续运算。

可能的代价与误解

误把0/1教学矩阵当成所有Embedding的格式;误以为同一个词在所有层都不变。

如何判断是否做对

逐项检查原文、编号、取表行号、输出行顺序四者一一对应。

为什么不能直接拿“编号大小”理解文字

模型需要一种可以进行加权、组合、比较和更新的数字表示。编号1只是一个地址;它与编号4相差3没有语言意义。最常见的输入方式是准备一张可学习的数字表,让每个词表编号对应一排数。这张表叫Embedding矩阵(嵌入矩阵),记作E。

可学习的意思是训练时这些数会被调整;普通推理时通常从训练好的参数中读取,不是看到一句新话才临时生成一张表。Embedding查表本身就是模型的一个层,不是某个额外联网检索服务。

先搞清三种表示:二进制、One-hot、Embedding

这三者都可能写成数字,却不是相同的计算步骤。假设本教材把“爱”编成Token编号2,词表共有6项。

写法具体结果表达的内容
整数在内存中的二进制形式00000010(用8位保存整数2)电脑怎么存储数字;不是模型的语义向量
One-hot(独热)向量[0,0,1,0,0,0](6个位置中只有第2号为1)用一个0/1指示数组标明“选中编号2”
Embedding向量[-0.3,0.8,0.1,0.5](模型参数表的第2行)供后续神经网络计算的4个实数;通常由训练形成

One-hot也不是一般意义的二进制数:它的长度取决于词表有多少项;当词表变大,One-hot会更长。而整数2的二进制表示取决于整数存储格式。

One-hot与Embedding确实有数学联系:如果把One-hot当作一行数字,并与6行4列的Embedding矩阵相乘,结果恰好选出第2行。这称为一种等价的数学表达;实际实现通常直接按编号查表,不需要真的先生成那6个0/1再做矩阵乘法。

本教材接下来的Embedding数值特意包含小数与负数。这才便于理解:新增的轴表示每个Token对应多少个数值特征,绝不是“把编号展开成多少个二进制位”。

用6行4列的表,表示“我爱学习”和“你爱”

沿用6项教学词表,指定每个片段用4个数表示,写作d=4。下面的数字是人为构造的浮点数,有正数、负数和小数,只用来解释运算,并不代表“我”“你”的真实含义:

ID 片段 特征0 特征1 特征2 特征3
0 PAD 0.0 0.0 0.0 0.0
1 我 0.2 -0.1 0.7 0.4
2 爱 -0.3 0.8 0.1 0.5
3 学习 0.6 0.2 -0.4 0.9
4 你 0.1 -0.5 0.9 0.3
5 ! -0.2 0.4 0.5 -0.6

这张Embedding表记作E,形状为[6,4]:6行是词表中可以查找的6个编号;4列表示每个编号对应4个数。查表时,不是随机取三行,而是按两句话里各个文本片段的编号,依次取出对应的行。

先认清两条编号序列分别代表哪句话:

第一句话是“我爱学习”。本教材把它分成三个Token:“我/爱/学习”,编码成编号序列[1,2,3]。

第二句话是“你爱”。它分成两个Token:“你/爱”,原始编号是[4,2];为了与第一句话组批,末尾补一个PAD(编号0),所以计算时写成[4,2,0]。PAD是占位,不是“你爱”的第三个词。

接下来做的Embedding查表,就是把这些Token编号逐个换成可供神经网络计算的数字向量。也可以把它理解为为两句话的每个Token生成初始数值表示;但不是把整句话压缩成一个向量。

第一句话:“我爱学习”怎样查表

先前的编号[1,2,3]不是无意义的三个孤立数字,而是依次对应“我”“爱”“学习”。查表过程逐项如下:

原文Token对应编号从E中查找取出的4个数字
我1E[1][0.2,-0.1,0.7,0.4]
爱2E[2][-0.3,0.8,0.1,0.5]
学习3E[3][0.6,0.2,-0.4,0.9]

按照“我 → 爱 → 学习”的原有顺序,把三排数放在一起,就得到“我爱学习”的初始Embedding表示:

原文:“我”   “爱”   “学习”
编号:  1      2       3

“我”   → [0.2,-0.1,0.7,0.4]
“爱”   → [-0.3,0.8,0.1,0.5]
“学习” → [0.6,0.2,-0.4,0.9]

第一句话的结果:
[[0.2,-0.1,0.7,0.4],
 [-0.3,0.8,0.1,0.5],
 [0.6,0.2,-0.4,0.9]]       shape=[3,4]  (3个Token,每个4个数)

第二句话:“你爱”怎样查表

第二句话的真实文本只有“你/爱”两个Token,对应编号[4,2]。组批时加入的0代表PAD,因此要依次查E[4]、E[2]、E[0]:

原文Token / 占位对应编号从E中查找取出的4个数字
你4E[4][0.1,-0.5,0.9,0.3]
爱2E[2][-0.3,0.8,0.1,0.5]
PAD(非原文)0E[0][0,0,0,0]

同样按位置排列,得到的是“你爱”的两个Token表示,加上一个供组批使用的PAD占位表示:

原文:“你”   “爱”              (只有2个Token)
编号:  4      2       0(PAD)  (补齐后安排3个位置)

“你”   → [0.1,-0.5,0.9,0.3]
“爱”   → [-0.3,0.8,0.1,0.5]
PAD    → [0,0,0,0]  (只是占位,不属于“你爱”)

第二句话的结果:
[[0.1,-0.5,0.9,0.3],
 [-0.3,0.8,0.1,0.5],
 [0,0,0,0]]       shape=[3,4]  (2个Token + 1个PAD,每位置4个数)

把两句话的结果放在一起:第一张三行四列代表“我爱学习”的三个Token;第二张三行四列代表“你爱”的两个Token和一个PAD。现在有2张表,每张3行,每行4个数,所以结果H的形状是[2,3,4]。

这里要区分两步:文字 → Token编号是分词器的编码;Token编号 → Embedding向量是模型内的查表表示。到这一步,每个位置有一排数,但还没有把整句话算成一个能直接代表完整句意的向量,也没有生成回答。两个句子都包含“爱”(编号2),所以它们在同一张表里最初查到的都是[-0.3,0.8,0.1,0.5];后续网络会根据位置和上下文更新各自的表示。

用一句可执行的定义表示:H中某条输入、某个位置的一排数,等于E中该位置Token编号所指向的那一行。PAD行虽然在这张教学表里恰好全为零,也仍然需要按照后续掩码规则处理。

为什么从两个轴变成三个轴

注意,原来的输入是两条句子,每条安排3个Token位置,所以它有两个轴:[2,3]。此时每个位置只存一个编号,例如第一句话的第2个位置是编号2(“爱”)。

查表后,这个位置不再只存编号2,而是存放E[2]=[-0.3,0.8,0.1,0.5],即4个可用于计算的数。第一句话仍有3个位置,两句话仍有2条;改变的是每个位置存什么,所以增加“位置内部的第几个数”这个索引方向:

[B,T] --逐编号查E--> [B,T,d]

请按真实对象读这三个下标:H[第几句话, 第几个Token位置, 第几个特征]。例如H[0,1,0]=-0.3,是第一句话“我爱学习”中“爱”这个Token的初始向量的第1个数;H[1,1,0]=-0.3则是第二句话“你爱”里的“爱”。两者初始查同一行,后续结合上下文才可能不同。

“多一个轴”不是增加了一种新文本,也不是把一个整数复制4次。二进制位只描述数字的存储;One-hot的6个位置用来指定词表项;Embedding新增的4个特征来自所选表的4列。这三种“长度”不能混同。补齐改变位置数T;Embedding改变每个位置的表示宽度d。

再看一个更大规模的例子:B=2,T=128,d=4096:有2条输入,每条安排128个位置;每个位置的一个编号被换成4096个数,因此得到2张128行4096列的表。形状是[2,128,4096],不是再生成了4096个Token。

隐藏维度到底“隐藏”了什么

隐藏表示指网络内部产生、不是直接提供给用户的中间数字表示;隐藏维度d是这种表示每个位置的宽度。隐藏不意味着神秘、加密或私人思考记录。

这一排数的各列通常没有人工指定的名称,不能擅自说第一维表示“动物”、第二维表示“快乐”。它们共同参与预测,可能以分布式方式表示多种信息。为了教学我们把列叫特征0到特征3,而不是捏造语义标签。

同一Token在标准固定查表中通常取同一行;经过位置处理和读取上下文的后续层,表示才会因句子不同而改变。输入Embedding、上下文化隐藏状态、整篇文档检索向量都可能是“一排数”,但来源、训练目标和用途不同。

PAD行是零,就能不用mask吗

不能由此保证。即使Value是零,若它参与概率归一化,仍可能分走注意力权重;位置处理、偏置等也可能让后续值不再为零。PAD是否参与,必须按掩码和损失约定处理。这里的零行是教学选择,不是完整隔离机制。

计算边界:不能说查完Embedding“才进入神经网络”。查表层已是模型运算的一部分;更准确的边界是:此前主要做请求组织和编号转换,从Embedding开始进入模型的数值表示与后续网络计算。

运行示例 · F05

一整句话怎样逐位置取出Embedding

输入与条件。沿用本书六行四列浮点Embedding表。[1,2,3]代表“我/爱/学习”,[4,2,0]代表“你/爱/PAD”。下面每一行都保留文字标签。

步骤与对象内部动作中间结果 / 新状态
1表示“我爱学习”第1片段我 → ID 1 → E[1]得到 [0.2,-0.1,0.7,0.4]。
2表示“我爱学习”第2片段爱 → ID 2 → E[2]得到 [-0.3,0.8,0.1,0.5]。
3表示“我爱学习”第3片段学习 → ID 3 → E[3]得到 [0.6,0.2,-0.4,0.9];三排数合起来表示整句的三个初始Token。
4表示“你爱”你 → E[4],爱 → E[2]得到 [0.1,-0.5,0.9,0.3] 和 [-0.3,0.8,0.1,0.5]。
5处理占位PAD → E[0]本例取 [0,0,0,0],仍需有效位置限制。
6检查形状每个编号被替换为一排4个数[2,3] → [2,3,4];最后一个轴选某个Token的第几个特征。

把过程连起来。Embedding不是把整数编译成二进制。这里的“爱”在两句中的初始向量相同;经过上下文计算后,它们的隐藏状态可以不同。

边界与反例。这些小数是教学参数,没有给每一列指定“情感”“词性”等人类意义,也不是训练后模型的真实权重。

依据与适用范围:[EMBED]。示例输入和场景由本书明确设定。

课后自检

自检 1

E形状[100,8],输入ID形状[3,7],查表结果是什么?

查看参考答案收起参考答案
结果[3,7,8],共168个数。E有100行是词表容量,不等于本次输入有100个位置。
自检 2

同一个“爱”出现在两句话里,为什么以后表示可能不同?

查看参考答案收起参考答案
初始固定查表可相同;随后加入位置信息并通过注意力使用不同上下文,所以后续隐藏状态可能不同。
自检 3

“爱”的编号为2、词表6项、Embedding宽度4:它的二进制存储、One-hot和Embedding分别是什么?为什么查表后会多一个轴?

查看参考答案收起参考答案
整数2若按8位保存,可写成00000010;One-hot是[0,0,1,0,0,0];本例Embedding为[-0.3,0.8,0.1,0.5]。前两个是编号的存储或标识方式,第三个是参数表里选中的一排4个可训练数。输入每个位置原本只放1个编号,查表后每位置放4个数,才使[2,3]变成[2,3,4]。新增轴不是二进制位数或Token数。

机制依据:[F-EMBED][TR]。本节数值与情景除另注外均为原创教学示例;来源不代替中文讲解。

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。