Token 与词嵌入
本章是「第一章 · 它是什么」的开篇。我们先建立一张概念地图——AI、机器学习、深度学习、大模型谁包含谁,监督、自监督、强化三大学习范式如何塑造了 LLM 的训练方式;再回答一个最根本的问题:模型根本"看不见"文字,它眼…
本章是「第一章 · 它是什么」的开篇。我们先建立一张概念地图——AI、机器学习、深度学习、大模型谁包含谁,监督、自监督、强化三大学习范式如何塑造了 LLM 的训练方式;再回答一个最根本的问题:模型根本"看不见"文字,它眼里只有数字。文字先经分词器切成 token,再经嵌入层变成向量——这条"从文字到向量"的数字化链路,是理解注意力机制、上下文窗口、API 计费、RAG 检索的共同地基。下一章将打开模型内部,看神经网络如何学习。
1. 开篇导引:AI、机器学习与大模型
在动手写任何 Agent 之前,先花 20 分钟把几个高频词汇的关系理清楚。你不需要会推导公式,但需要一张准确的概念地图——否则后面读任何资料、做任何技术选型,都容易张冠李戴。
1.1 概念嵌套:谁包含谁
这四个词经常被混用,但它们是严格的嵌套关系:
人工智能 (AI)
└── 机器学习 (ML)
└── 深度学习 (DL)
└── 大语言模型 (LLM)
用一句话区分:
| 概念 | 核心思想 | 典型例子 |
|---|---|---|
| 人工智能 AI | 让机器表现出智能行为的总目标 | 围棋程序、导航、聊天机器人 |
| 机器学习 ML | 不手写规则,让机器从数据中总结规律 | 垃圾邮件分类、房价预测 |
| 深度学习 DL | 用多层神经网络从数据中提取规律 | 图像识别、语音识别、LLM |
| 大语言模型 LLM | 超大规模的深度学习模型,专门处理语言 | GPT、Claude、Qwen、DeepSeek |
一个常见的误解是把"AI"等同于"LLM"。实际上你在地图 App 里看到的路径规划、游戏里的 NPC 行为树,都是 AI,但和神经网络无关。Agent 开发者每天打交道的,主要是最内层的 LLM,以及围绕它构建的系统。
另外要知道:实现 AI 有多条历史路线。早期主流是"符号主义"——把知识写成显式规则(if-else 的极端形态),专家系统是它的巅峰,但规则永远写不完,最终败给了"数据主义"——也就是机器学习:与其教机器规则,不如给它数据让它自己学。
1.2 机器学习的本质:从"写规则"到"找参数"
用你熟悉的方式对比一下。
传统编程:
规则 + 数据 --程序--> 结果
(你写 if-else,数据进来,确定性输出)
机器学习:
数据 + 结果 --训练--> 规则(模型)
(给它样本和标准答案,它总结出规律)
举个开发中的类比:假设你要判断用户输入的是不是手机号。传统做法是你写正则。机器学习做法是你准备十万条"输入+是否手机号"的样本,扔给算法,它输出一个模型——你拿到的是一堆数字(参数),而不是一段能读懂的逻辑。
这个"模型 = 一堆参数"的认知非常重要,后面会反复出现:
所谓模型,就是一个函数,函数里全是待定的数字。训练,就是把这堆数字调到合适的值。
用代码感受一次"学习"
下面是最小化的机器学习示例:从带噪声的数据中学出 y ≈ 2x + 1 这个规律。先看"封装好的写法":
import numpy as np
from sklearn.linear_model import LinearRegression
# 造数据:y = 2x + 1,加了随机噪声模拟真实世界的脏数据
rng = np.random.default_rng(42)
X = rng.uniform(0, 10, 200).reshape(-1, 1)
y = 2 * X.squeeze() + 1 + rng.normal(0, 0.5, 200)
model = LinearRegression()
model.fit(X, y) # 这一步就是"学习"
print(model.coef_, model.intercept_) # 输出约 [2.0] 和 1.0 —— 它自己学出来的
运行后你会发现模型学到的系数约等于 2 和 1——没有人告诉它公式,它从 200 个样本里自己找到了。这个"哇"的时刻,就是机器学习的全部魔法所在(第 02 章会拆开 fit 里面发生了什么,其实就是循环执行梯度下降)。
1.3 三大学习范式
同样是"从数据学",按"数据有没有标签、反馈从哪来"可以分出三种范式。这个分类直接影响你理解 LLM 的训练流程,也决定了你该对模型的输出抱多大信任。
监督学习(Supervised Learning)
数据形态:(输入, 标准答案) 成对出现。
例子:垃圾邮件分类。你有十万封邮件,每封都标注了"是/否垃圾邮件",算法学习从内容到标签的映射。
在 LLM 世界里的对应:后训练阶段的指令微调(SFT)——人类写好"问题 + 理想回答"的示范对,模型照着学。详见第 04 章。
自监督学习(Self-supervised Learning)
数据形态:没有人工标注,但可以从数据自身"造出"标签。
这是理解 LLM 的关键。语言模型的任务是"预测下一个词":
输入:今天天气真
标签:好 ← 这个标签不是人标的,就是原文本身
整本维基百科都是训练数据:把每个位置的下一个词遮住,让模型猜,猜错了就调整参数。不需要任何人工标注,人类几千年积累的文字全部变成了现成的训练数据——这是大模型能"大力出奇迹"的根基。
类比:完形填空。你做一万道完形填空题后,语感会大幅提升,虽然没人给你讲过语法。
强化学习(Reinforcement Learning)
数据形态:没有标准答案,只有行为的"奖励/惩罚"反馈。
Agent 在环境里试错:做出动作 → 环境给回报 → 学会追求长期回报最大的策略。
在 LLM 世界里的对应:RLHF(人类反馈强化学习)——让人类对模型的多个回答排序,训练一个奖励模型,再用强化学习让模型往人类偏好的方向调整。详见第 04 章。
三者对比
| 监督学习 | 自监督学习 | 强化学习 | |
|---|---|---|---|
| 数据形态 | (输入, 标签) | (输入, 自造标签) | (状态, 动作, 奖励) |
| 反馈来源 | 人工标注 | 数据本身 | 环境/评价者 |
| 数据规模 | 受标注成本限制 | 只受数据量限制 | 受交互成本限制 |
| 在 LLM 中的角色 | 指令微调 | 预训练 | 对齐人类偏好 |
还有一个不入流但常被提到的:无监督学习(比如聚类),自监督可以看作它的一种特例(自动构造监督信号),这里不展开。
1.4 生成式与判别式
按模型的输出目标,还可以分一刀,这一刀解释了为什么 ChatGPT 是"聊天"而不是"分类器":
| 判别式模型 | 生成式模型 | |
|---|---|---|
| 学的是什么 | 输入 → 类别的边界 | 数据本身的分布 |
| 输出 | 类别/概率值 | 完整的内容(一段文字、一张图) |
| 例子 | 垃圾邮件分类器 | GPT、Stable Diffusion |
| 一句话 | 判断"是什么" | 创造"是什么样" |
一个有助于建立直觉的理解角度:生成式建模比判别式更难,因为它要理解数据的"全貌"而不是只找决策边界。语言模型为了预测下一个词,被迫学会语法、事实知识、推理模式——预测下一个词这个看似简单的任务,逼出了通用智能。这也是为什么 LLM 的能力常常超出设计者预期。
1.5 Agent 开发者为什么需要这些
你可能会想:我调 API 就够了,为什么先学范式?三个直接理由:
- 看懂模型卡和文档。任何模型的说明里都有"预训练/微调/对齐"这些词,不了解范式,就只能死记硬背参数怎么调。
- 预判模型的能力边界。知道自监督的语料里有什么、没有什么,你就能判断哪些任务模型"天生会"、哪些需要 few-shot 示例、哪些必须外挂工具。比如问模型今天几号——训练数据里没有"现在",它必然答不准,这就是需要工具的原因之一。
- 理解 Agent 的定位。Agent 的本质(第 08 章)是"让模型在循环中决定调用什么工具"。而"决定"这个能力,来自后训练阶段学会的指令遵循。不懂训练流程,就理解不了模型为什么"会听话",也理解不了为什么它有时不听话。
2. 模型眼中的文字:Token 与分词
模型的输入不是文字,是数字。中间的翻译官叫分词器(Tokenizer)。理解 token 是 Agent 开发的实用刚需:API 按它计费、上下文窗口按它计算、模型数不清 "strawberry" 里有几个 "r" 的著名缺陷也源于它。这一节我们手写一个能用的 BPE 分词器,把这个"翻译官"彻底看透。
2.1 为什么需要分词
神经网络只能处理数字(准确说是向量)。把文字变成数字,最朴素的三种方案各有致命缺陷:
| 方案 | 词表大小 | 问题 |
|---|---|---|
| 按字符切 | 极小(英文 26 个) | 序列太长,"hello" 占 5 个位置;单个字符没有语义 |
| 按单词切 | 百万级 | 词表爆炸;遇到没见过的词(拼写错误、新术语)直接失效 |
| 不切,整个句子 | 天文数字 | 不可行 |
现实需要的方案:常见的内容切长一点(省空间、有语义),罕见的内容切短一点(保证不失效)。这就是 BPE(Byte Pair Encoding,字节对编码)的核心思想。
2.2 BPE 的原理:从数据里学切法
BPE 原本是 1994 年的压缩算法,2016 年被引入 NLP。它的思路一句话说清:
从"每个字符单独成块"开始,统计语料里相邻两块最常一起出现的组合,把它们合并成一个新块。重复几千次,常见词自然粘连成整块,罕见词保持碎块。
用一个小语料走一遍(先看英文,中文同理后面讲):
语料: low, lower, newest, widest
初始: l o w / l o w e r / n e w e s t / w i d e s t
第一轮统计,e 和 s 相邻出现 2 次(newest、widest),其他对都只有 1 次。合并 es:
l o w / l o w e r / n e w es t / w i d es t
第二轮统计,es 和 t 相邻出现 2 次。合并 est:
l o w / l o w e r / n e w est / w i d est
第三轮,l 和 o 相邻 2 次(low、lower)。合并 lo:
lo w / lo w e r / n e w est / w i d est
继续几百轮后,"low" 会变成一个不可分的 token,而 "wideness" 这种没见过的词会退化为 "wide" + "ss" 之类的碎片——老词成块,新词拆碎,永远不会有词表外的词。
最后每个"块"(token)分配一个编号,得到词表(vocabulary)。编码文本 = 查表把 token 变编号,输入模型。
2.3 手写一个 Mini BPE
下面是完整可运行的简化版 BPE(约 40 行)。虽然生产级实现(如 tiktoken、sentencepiece)有很多工程优化,但核心逻辑就是这些:
from collections import Counter
class MiniBPE:
def __init__(self, num_merges: int):
self.num_merges = num_merges # 计划合并的次数 = 词表扩张量
self.merges: list[tuple[str, str]] = []
@staticmethod
def _to_pieces(word: str) -> list[str]:
# 初始切分:每个字符一个块,末尾加特殊结束符标记词边界
return list(word) + ["</w>"]
def _count_pairs(self, corpus: list[list[str]]) -> Counter:
pairs = Counter()
for word in corpus:
for i in range(len(word) - 1):
pairs[(word[i], word[i + 1])] += 1
return pairs
def _merge_in_corpus(self, corpus, pair):
merged = []
for word in corpus:
new_word, i = [], 0
while i < len(word):
if i < len(word) - 1 and (word[i], word[i + 1]) == pair:
new_word.append(word[i] + word[i + 1]) # 粘成一块
i += 2
else:
new_word.append(word[i])
i += 1
merged.append(new_word)
return merged
def train(self, text: str):
corpus = [self._to_pieces(w) for w in text.split()]
for _ in range(self.num_merges):
pairs = self._count_pairs(corpus)
if not pairs:
break
best = max(pairs, key=pairs.get) # 找最高频相邻对
self.merges.append(best)
corpus = self._merge_in_corpus(corpus, best)
def encode(self, word: str) -> list[str]:
pieces = self._to_pieces(word)
# 按训练学到的合并顺序重放
for a, b in self.merges:
i, new_pieces = 0, []
while i < len(pieces):
if i < len(pieces) - 1 and (pieces[i], pieces[i + 1]) == (a, b):
new_pieces.append(a + b); i += 2
else:
new_pieces.append(pieces[i]); i += 1
pieces = new_pieces
return pieces
# ---------- 训练 ----------
bpe = MiniBPE(num_merges=12)
bpe.train("low low low lower newest newest newest widest widen")
for w in ["low", "lower", "newest", "widen", "lowering"]:
print(f"{w:>10} → {bpe.encode(w)}")
输出:
low → ['low', '</w>']
lower → ['low', 'er', '</w>']
newest → ['newest', '</w>']
widen → ['wid', 'en', '</w>']
lowering → ['low', 'er', 'ing', '</w>'] ← 训练时没见过的词,自动拆碎
观察结果:
low、newest出现频繁,被完整粘成单 tokenwiden、lowering是训练语料外的词,自动退化为子词组合,永不失效
这正是我们要的性质:高频词省空间、低频词保兼容。
2.4 中文在 BPE 里会发生什么
生产级分词器(如 Qwen、DeepSeek 的)通常在字节层面做 BPE(Byte-level BPE),好处是任何 UTF-8 文本——中文、emoji、生僻字——都能编码,绝无"未知字符"。
但在中文语料不足的词表里,汉字经常被切成多个字节碎片。一个直观的对比(数量级示意,不同词表有差异):
| 文本 | 大致 token 数 |
|---|---|
| "hello world" | 2 |
| "你好世界" | 4 左右(好词表)~ 8+(差词表) |
推论很实用:同样一件事,用中文提问比用英文多消耗 token——直接影响 API 费用和上下文占用。做 Agent 的时候,长 system prompt 用中文写会比英文更快吃满窗口。
用 tiktoken(OpenAI 的分词器,Python 直接可用)实测:
# uv add tiktoken
import tiktoken
enc = tiktoken.get_encoding("o200k_base") # GPT-4o 系列的词表
for text in ["hello world", "你好世界", "strawberry"]:
print(f"{text!r:>16} → {len(enc.encode(text))} tokens")
print(enc.encode("strawberry")) # 看看它被切成了什么
输出:
'hello world' → 2 tokens
'你好世界' → 4 tokens
'strawberry' → 2 tokens ← 'str' + 'awberry' 或类似切法
2.5 Token 解释了模型的经典缺陷
为什么大模型数不清 "strawberry" 有几个 "r"?
因为模型看到的不是 s-t-r-a-w-b-e-r-r-y 十个字符,而是 ['str', 'aw', 'berry'] 这样的 token 碎片。字符信息在分词阶段就被压缩掉了——你让模型数 r,相当于让一个只能看到 "str / aw / berry" 三个积木的人数积木里的字母,只能靠背(训练时见过相关文本)或拼凑。
这个例子对 Agent 开发者的启示:给模型布置任务时,要意识到它的感知粒度是 token,不是字符、不是像素。数数、对齐、精确复制这类任务天生吃亏,属于"能用工具就别为难模型"的范畴。同类缺陷还有:
- 反转单词的字母顺序(同样依赖字符级感知)
- 生成指定字数的长文(token 到字符的映射不是定长)
- 精确的数学计算(token 之间没有数位对齐)——需要工具调用
2.6 和 Agent 开发直接相关的三件事
① 计费。几乎所有 LLM API 按 token 计价,输入输出分开算。系统提示词很长时,每一轮对话都在为它付费。
② 上下文窗口。"128K 上下文"指的是 128K 个 token,不是字数。粗略换算:英文 1 token ≈ 0.75 个单词;中文一个汉字 ≈ 0.6~1 个 token(取决于词表质量)。
③ 首字延迟。API 的"输出速度"通常标注为 xx tokens/s。生成 1000 token 的回答,在 50 tokens/s 的速度下要 20 秒——这就是为什么流式输出(streaming)是长回答的标配体验。
一个实用的 token 用量监控示例(为第 05 章的 API 实战预热):
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
model="qwen3:4b",
messages=[{"role": "user", "content": "用一句话解释什么是 token"}],
)
usage = resp.usage
print(f"输入 {usage.prompt_tokens} + 输出 {usage.completion_tokens} = "
f"{usage.total_tokens} tokens")
3. 语义的几何空间:词嵌入
Token 编号只是给每个词发了个身份证号,编号本身不携带语义——"猫"是 8721、"微波炉"是 4306,这两个数字之间的关系毫无意义。词嵌入(Embedding)解决的问题是:把每个 token 变成一个几百到几千维的向量,让语义关系变成几何关系。这是"模型理解语言"的物理基础。
3.1 从 one-hot 到稠密向量
最直接的编码方式是 one-hot:词表大小 $V$,每个词是一个 $V$ 维向量,只有自己对应的位置是 1。
import numpy as np
vocab = ["猫", "狗", "微波炉"]
for i, w in enumerate(vocab):
v = np.zeros(len(vocab)); v[i] = 1
print(f"{w}: {v}")
猫: [1. 0. 0.]
狗: [0. 1. 0.]
微波炉: [0. 0. 1.]
两个致命缺陷:
- 维度灾难:词表 100K,每个词就是 100K 维的向量,其中 99999 个数字是 0
- 语义盲:任何两个 one-hot 向量的余弦相似度都是 0,"猫"和"狗"的距离等于"猫"和"微波炉"的距离
词嵌入的思路:改用低维稠密向量(如 1024 维,每一维都有值),并且让向量的位置关系反映语义关系。这就是"分布式表示"(distributed representation)——语义不存储在某一个数字里,而是散布在整个向量的模式中。
3.2 核心假设:几何即语义
词嵌入建立在一个语言学假设上(分布假说,1957 年 Firth:"看一个词的伙伴,就知道它的意思"):出现在相似上下文里的词,语义相近。"猫"和"狗"都常出现在"喂、撸、养、可爱"附近,所以它们的向量应该靠近。
理想状况下,嵌入空间有这样的性质:
| 几何关系 | 语义解释 |
|---|---|
| 两个向量夹角小 | 两个词语义相近 |
| 两个向量方向相反 | 语义对立(好 ↔ 坏) |
| 向量差 $\vec{国王} - \vec{女王}$ | 约等于"性别"这个抽象方向 |
| 一段文本向量的中心 | 这段文本的主题 |
著名的例子(词向量时代最经典的发现,在 Word2Vec 里首次观察到):
$$ \vec{国王} - \vec{男人} + \vec{女人} \approx \vec{女王} $$
$$ \vec{巴黎} - \vec{法国} + \vec{中国} \approx \vec{北京} $$
词与词之间可以做"语义算术"——这不是设计出来的,是模型从海量语料中自己学出来的。
3.3 Embedding 的工程本质:一张可查的表
实现上,词嵌入朴素得让人意外:一张 V × d 的大表(词表大小 × 嵌入维度)。第 $i$ 行就是 token $i$ 的向量。
import numpy as np
rng = np.random.default_rng(0)
V, d = 50000, 1024 # 假设词表 5 万,维度 1024
E = rng.normal(0, 0.02, (V, d)) # 这张表就是 embedding 层
token_id = 8721
x = np.zeros(V); x[token_id] = 1 # one-hot
# 方式一:矩阵乘 one-hot
v1 = E.T @ x
# 方式二:直接查表
v2 = E[token_id]
print(np.allclose(v1, v2)) # True —— 乘 one-hot ≡ 查行
print(v2.shape) # (1024,)
关键认知:
- Embedding 层就是一个可训练的参数矩阵,形状
(V, d),是第 02 章"参数"概念的直接应用 - "查表"和"乘 one-hot"数学上等价,工程上当然用查表(不用真的存 one-hot)
- 训练开始时这张表是随机的(毫无语义),随着预训练推进,梯度不断更新它,语义结构自己浮现(emerge)——没有人为设计"性别维度",但组织语义的压力自然催生了它
对尺寸有感觉:Qwen 这类 8B 模型,词表约 150K、维度 4096,光嵌入表就有约 6 亿参数。
3.4 相似度:怎么算"近"
两个向量怎么比较?主流是余弦相似度——不看长度,只看方向夹角:
$$ \cos(\mathbf{a}, \mathbf{b}) = \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{a}| \, |\mathbf{b}|} $$
值域 [-1, 1]:1 表示方向相同,0 表示正交(无关),-1 表示相反。
import numpy as np
def cosine(a, b):
return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
# 手工构造一个玩具语义空间(3 维足够演示)
# 性别维度 体型维度 人造物维度
king = np.array([ 0.9, 0.8, 0.0])
queen = np.array([-0.8, 0.7, 0.1])
man = np.array([ 0.95, 0.0, 0.0])
woman = np.array([-0.95, 0.0, 0.0])
microwave = np.array([0.0, -0.2, 0.99])
print(f"king vs queen : {cosine(king, queen):+.3f}")
print(f"king vs microwave : {cosine(king, microwave):+.3f}")
print(f"king-man+woman ≈ queen? {cosine(king - man + woman, queen):+.3f}")
输出:
king vs queen : +0.266
king vs microwave : -0.093
king-man+woman ≈ queen? +0.996
上面是我手工摆的玩具向量(真实空间是几千维、由训练学出来的),但它演示了三件事:语义近的向量方向接近(king/queen > king/微波炉);语义算术在方向上成立;比较的是方向而非长度(每个词向量的长度还和词频有关,不适合做语义比较)。
3.5 拿真实的模型验证一次
用 Ollama 起一个本地 embedding 模型(如 nomic-embed-text),实测语义相似度:
# 前置: ollama pull nomic-embed-text
import ollama
def embed(text: str) -> list[float]:
r = ollama.embed(model="nomic-embed-text", input=text)
return r.embeddings[0] # ollama-python 0.4+ 返回 Pydantic 对象
import numpy as np
def cosine(a, b):
a, b = np.array(a), np.array(b)
return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
pairs = [
("一只猫在睡觉", "小猫正在打盹"),
("一只猫在睡觉", "今天股市大涨"),
("如何学好编程", "学习编程的方法"),
]
for a, b in pairs:
print(f"cos = {cosine(embed(a), embed(b)):+.3f} {a!r} vs {b!r}")
典型输出(数值随模型版本浮动,量级关系稳定):
cos = +0.74 '一只猫在睡觉' vs '小猫正在打盹' ← 语义相近
cos = +0.11 '一只猫在睡觉' vs '今天股市大涨' ← 语义无关
cos = +0.62 '如何学好编程' vs '学习编程的方法' ← 主题相近
真实模型里,语义关系确实被编码进了几何空间——这就是"模型懂语言"的物理载体。这套能力也是 RAG(检索增强生成)的基石:把文档和问题都变成向量,用余弦相似度找出"最相关的段落"。第 15 章讲 Agent 记忆检索时会直接用到它。
3.6 在 Transformer 里的位置
把前文的 token 和本节的嵌入连起来,模型处理输入的第一步就完整了:
"你好世界"
│ 分词器(本章第 2 节)
▼
[1234, 5678, 9012] token 编号
│ 查嵌入表(本节)
▼
[[...], [...], [...]] 形状 (3, d) 的向量序列
│
▼
送入注意力机制(第 03 章)
注意一个重要转变:进入注意力层之后,模型处理的不再是"一个个词",而是"一排互相影响的向量"。后续每一层都在持续地修改这些向量,让每个位置的信息融合上下文——这是第 03 章的主角注意力机制要解决的问题。
顺带回答一个常见疑问:上下文窗口(context window)——它规定了一次最多送入多少 token。所有历史对话、系统提示词、工具定义都共享这个额度。窗口满会发生什么、怎么管理,第 06 章会专门处理。
4. 本章小结
- AI ⊃ ML ⊃ DL ⊃ LLM,Agent 开发主要和最内层打交道;机器学习的本质是从数据中确定一个函数的参数,而不是手写规则——模型 = 参数确定的函数
- 三大范式:监督(人标答案)、自监督(数据自造答案,LLM 预训练的核心)、强化(环境给奖励,对齐的核心)
- 生成式模型学习数据分布,因此获得了"创造"能力;预测下一个词逼出了通用能力
- 模型只认识数字,分词器负责文字 → token 编号的翻译
- BPE:高频组合粘成大块,罕见内容退化为小块,词表外永不失效;手写 MiniBPE 40 行跑通"训练 + 编码"全流程
- Byte-level BPE 保证任意 UTF-8 可编码;中文相对费 token
- token 粒度解释了模型数不清字母、算不准字数等经典缺陷;token 是计费单位、上下文计量单位、输出速度单位
- one-hot 维度高且语义盲;词嵌入用低维稠密向量编码语义;分布假说:上下文相似的词语义相近,语义结构从训练中自然涌现
- Embedding 层 = 一张
(V, d)的可训练大表,查表等价于乘 one-hot;余弦相似度衡量"语义距离",是 RAG 和记忆检索的基石 - king − man + woman ≈ queen:语义算术证明了"几何即语义";模型内部流动的从来不是文字,是向量序列
下一篇:02 · 前向传播与反向传播