从Bigram模型入门语言模型:Tokenization、Embedding与概率预测

📅 2026/7/17 3:18:13
从Bigram模型入门语言模型:Tokenization、Embedding与概率预测
你肯定听说过语言模型也大概知道它能生成文本。但有没有想过一个最简单的语言模型到底是怎么工作的它内部到底在做什么为什么从最简单的模型开始理解反而能帮你真正搞懂那些复杂大模型的本质今天我们就用十分钟彻底拆解 Andrej Karpathy 在他的经典教程中提到的 Bigram 语言模型。这个模型简单到只有几行代码但它却包含了现代大语言模型最核心的几个概念Tokenization、Embedding、概率预测。更重要的是通过理解这个最简单的模型你能建立一个清晰的认知框架以后面对任何复杂模型时都知道该从哪里入手理解。1. 先搞清楚 Bigram 模型到底在解决什么问题很多人一听到“语言模型”就觉得是高大上的东西其实它的核心任务非常简单给定一段文本预测下一个最可能出现的词是什么。Bigram 模型用最直接的方式解决这个问题它只关注当前词和下一个词的关系。比如在句子“我今天去”后面模型会统计“去”后面最常出现的词是“超市”、“学校”还是“吃饭”然后根据历史频率给出概率。1.1 为什么从 Bigram 开始学最有价值现在的大语言模型动辄千亿参数为什么还要回过头来学习这个看似过时的简单模型因为 Bigram 模型像是一个“解剖标本”它把语言模型最核心的机制赤裸裸地展示给你看没有那些复杂的注意力机制、层归一化等现代组件的干扰。你能清晰地看到三个关键环节Tokenization如何把文本切成可处理的单元Embedding如何把离散的符号变成连续的数值表示概率预测如何根据上下文计算下一个词的概率分布理解了这个最小闭环你再去看 Transformer 架构时就会意识到它本质上是在用更聪明的方式解决同样的问题——只是规模更大、方法更精巧。1.2 Bigram 模型的局限性正是它的教学价值Bigram 模型有个明显的缺陷它只能看到前一个词。这意味着在预测“我今天去”后面的词时它完全忽略“我今天”这个更长的上下文只盯着“去”这个孤立的词。这个局限性反而很有教学意义。当你明白为什么只考虑前一个词不够时你就能真正理解为什么现代模型需要更长的上下文窗口为什么注意力机制如此重要。这种“从问题出发”的理解方式比直接背诵复杂概念要深刻得多。2. 亲手实现一个 Bigram 模型代码背后的思考让我们用 Python 实现一个最简单的 Bigram 模型。代码很短但每一行都值得仔细品味。2.1 第一步准备数据与 Tokenizationimport torch import torch.nn as nn # 示例文本数据 text hello world hello python hello coding # 构建词汇表 chars sorted(list(set(text))) vocab_size len(chars) print(f词汇表: {chars}) print(f词汇表大小: {vocab_size}) # 创建字符到索引的映射 stoi {ch: i for i, ch in enumerate(chars)} itos {i: ch for i, ch in enumerate(chars)}这里我们做了最简单的 Tokenization——按字符切分。在实际的大语言模型中Tokenization 要复杂得多可能是按子词subword或词片token切分。但核心思想是一样的把连续的文本变成离散的符号序列。2.2 第二步构建训练数据# 将文本转换为索引序列 encoded [stoi[ch] for ch in text] print(f编码后的文本: {encoded}) # 构建 Bigram 训练对 xs, ys [], [] for i in range(len(encoded) - 1): xs.append(encoded[i]) # 当前字符 ys.append(encoded[i1]) # 下一个字符 xs torch.tensor(xs) ys torch.tensor(ys) print(f输入序列: {xs}) print(f目标序列: {ys})注意这里的关键设计每个训练样本都是当前字符下一个字符的对。这就是 Bigram 的核心——只考虑相邻两个字符的关系。2.3 第三步实现 Embedding 层# 定义模型 class BigramModel(nn.Module): def __init__(self, vocab_size): super().__init__() self.embedding nn.Embedding(vocab_size, vocab_size) def forward(self, x): return self.embedding(x) # 形状: (序列长度, vocab_size) model BigramModel(vocab_size)nn.Embedding是这个模型中最值得深入理解的部分。它实际上是一个查找表把每个字符索引映射到一个长度为vocab_size的向量。这个向量的每个维度可以理解为该字符在不同上下文特征上的得分。2.4 第四步训练与推理# 训练配置 optimizer torch.optim.Adam(model.parameters(), lr0.1) loss_fn nn.CrossEntropyLoss() # 训练循环 for epoch in range(100): logits model(xs) # 获取预测分数 loss loss_fn(logits, ys) optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 20 0: print(fEpoch {epoch}, Loss: {loss.item():.4f}) # 生成文本 def generate_text(model, start_char, length10): model.eval() current torch.tensor([stoi[start_char]]) result [start_char] for _ in range(length): logits model(current) probs torch.softmax(logits, dim-1) next_char torch.multinomial(probs, 1).item() result.append(itos[next_char]) current torch.tensor([next_char]) return .join(result) print(f生成的文本: {generate_text(model, h, 20)})训练完成后这个模型就能根据起始字符生成新的文本了。虽然生成的文本可能没有太多语义意义但这个过程完整展示了语言模型的工作机制。3. 从 Bigram 到现代大语言模型的关键跃迁理解了 Bigram 模型后你就能清晰地看到语言模型发展的几个关键突破点3.1 从 Bigram 到 N-gram扩展上下文窗口Bigram 只考虑前一个词Trigram 考虑前两个词N-gram 考虑前 N-1 个词。这看起来是自然的演进但有个致命问题随着 N 增大需要统计的参数数量呈指数级增长。这就是所谓的维度灾难。现代大语言模型通过神经网络解决了这个问题。神经网络不需要显式存储所有可能的 N-gram 组合而是学习一种通用的计算模式能够处理任意长度的上下文。3.2 从统计计数到神经网络学习Bigram 模型本质上是基于频率统计的给定当前词下一个词的概率直接由训练数据中的共现频率决定。神经网络语言模型的突破在于它不再直接统计频率而是学习一种从输入到输出的映射函数。这种映射能够捕捉更复杂的语言模式包括语法结构、语义关系等。3.3 Embedding 的进化从简单映射到语义空间在我们实现的 Bigram 模型中Embedding 只是一个简单的查找表。但在现代模型中Embedding 已经演变成高维的语义空间其中相似的词在空间中的位置也相近。这种语义 Embedding 使得模型能够进行zero-shot推理、类比推理等复杂任务。比如著名的国王 - 男人 女人 女王的例子就展示了 Embedding 空间中的线性关系。4. 把 Bigram 理解应用到实际工作中学习 Bigram 模型不是为了真的用它来做项目而是为了建立一个坚实的概念基础。这个基础能帮助你在实际工作中更好地理解和使用现代大语言模型。4.1 调试复杂模型的思维框架当你遇到大语言模型生成效果不好时可以回归到最基本的 Bigram 思维检查 Tokenization输入文本是否被正确切分特殊字符处理是否正确检查 Embedding模型是否理解了关键术语的语义检查概率分布模型的输出概率是否合理是否存在过度自信或过度保守这种回归基础的调试方法往往比盲目调整超参数更有效。4.2 理解模型限制的起点Bigram 模型的最大限制是上下文长度太短。现代模型虽然有很大的上下文窗口但仍然有其限制。理解这个根本性的限制能帮助你更好地设计提示词prompt把关键信息放在模型最容易注意到的地方。4.3 从原理出发的优化思路知道了语言模型的基本原理你就能更好地理解各种优化技术的意义注意力机制解决长距离依赖问题位置编码让模型知道词序信息层归一化稳定训练过程残差连接缓解梯度消失这些技术都不是凭空发明的而是为了解决语言建模中的具体问题而发展出来的。5. 常见误区与实操建议5.1 不要过度追求模型复杂度很多人在学习语言模型时一上来就研究最先进的架构。这就像还没学会走路就想跑步一样。建议的学习路径是先理解 Bigram/N-gram 等统计语言模型再学习简单的神经网络语言模型如 RNN/LSTM最后深入 Transformer 架构每一步都要亲手实现代码确保真正理解。5.2 重视数据预处理环节在实际项目中Tokenization 和数据清洗往往比模型架构更重要。一个常见的误区是花大量时间调模型却忽略了数据质量问题。建议的数据处理流程分析数据分布和异常值设计合适的 Tokenization 策略处理大小写、标点、特殊字符的一致性建立完整的数据验证管道5.3 理解概率的本质语言模型输出的是概率分布而不是确定的答案。这个认知很重要因为它意味着模型会有不确定性这是正常的多次生成可能得到不同结果需要设计合适的采样策略如温度调节、top-p采样5.4 从实验到生产的考量在实验环境中跑通模型只是第一步。要应用到生产环境还需要考虑推理速度优化内存使用效率批量处理能力错误处理和降级方案监控和日志记录Bigram 模型虽然简单但它提醒我们任何模型最终都要解决实际问题而不仅仅是追求技术指标。通过这十分钟的深入理解你现在应该对语言模型有了更本质的认识。下次当你使用 ChatGPT 或其他大模型时你会知道它背后其实是在做类似 Bigram 的事情——只是规模更大、方法更精巧。这种从简单到复杂的理解路径才是真正掌握深度学习技术的正确方式。