10分钟掌握Bigram语言模型:从数学原理到PyTorch实战
在深度学习和大语言模型快速发展的今天很多开发者希望从基础原理入手真正理解模型的核心工作机制。Andrej Karpathy 提出的 Bigram 语言模型以其极简的设计和清晰的逻辑成为了学习语言模型入门的最佳起点。本文将以“Caleb Writes Code”视频中精讲的实现思路为蓝本带你用10分钟掌握 Bigram 模型的完整构建过程从理论到代码实现再到训练与推理让你不仅知其然更知其所以然。1. Bigram 语言模型核心概念解析1.1 什么是 Bigram 模型Bigram二元语法模型是自然语言处理中最简单的语言模型之一。它的核心思想非常直观基于前一个词来预测下一个词的概率分布。比如在句子 I love programming 中love 的出现只依赖于前一个词 Iprogramming 的出现只依赖于 love。从概率论的角度来看Bigram 模型将一个句子的概率分解为一系列条件概率的乘积 P(w1, w2, ..., wn) P(w1) × P(w2|w1) × P(w3|w2) × ... × P(wn|wn-1)这种简化虽然丢失了长距离的依赖关系但使得模型非常容易理解和实现特别适合作为理解更复杂语言模型如 RNN、Transformer的入门阶梯。1.2 Bigram 模型的应用场景与局限性在实际应用中Bigram 模型虽然简单但仍然有其价值。它常用于文本生成的基础实验拼写检查和自动更正简单的语音识别系统作为更复杂模型的组成部分然而Bigram 模型的局限性也很明显无法捕捉长距离依赖关系数据稀疏问题严重很多词对在训练数据中从未出现生成文本的连贯性有限理解这些局限性有助于我们明白为什么需要更复杂的模型以及如何通过平滑技术等方法来改进基础模型。2. 环境准备与工具选择2.1 开发环境配置为了跟随本文实现 Bigram 模型你需要准备以下环境操作系统Windows、macOS 或 Linux 均可Python 版本3.8 或以上版本主要依赖库PyTorch用于张量运算和自动梯度计算NumPy数值计算基础库你可以使用以下命令快速安装所需依赖pip install torch numpy2.2 代码编辑器选择推荐使用 Jupyter Notebook 或 VS Code 进行实验Jupyter Notebook适合交互式开发和逐步调试VS Code配合 Python 插件提供完整的开发体验如果你选择 Jupyter Notebook可以使用以下命令安装pip install jupyter jupyter notebook3. Bigram 模型数学原理深入理解3.1 概率估计与计数统计Bigram 模型的核心是计算条件概率 P(wj|wi)。在训练过程中我们通过简单的计数统计来估计这些概率P(wj|wi) count(wi, wj) / count(wi)其中 count(wi, wj) 表示词对 (wi, wj) 在训练语料中出现的次数count(wi) 表示词 wi 出现的总次数。这种最大似然估计方法虽然直观但会遇到零概率问题——当训练语料中未出现某个词对时模型会赋予其零概率。为了解决这个问题实践中会使用各种平滑技术。3.2 模型的数据表示在实现 Bigram 模型时我们需要将文本转换为模型可以处理的数值形式。这通常涉及两个步骤构建词汇表将每个唯一的词映射到一个整数索引创建映射关系词到索引的映射word_to_index和索引到词的映射index_to_word这种表示方法使得我们可以用张量运算来高效处理文本数据。4. 完整实现从数据预处理到模型训练4.1 数据准备与预处理让我们从一个简单的文本开始实现完整的数据处理流程import torch import torch.nn as nn import torch.nn.functional as F # 示例训练数据 text hello world hello python hello deep learning words text.split() # 构建词汇表 vocab sorted(set(words)) vocab_size len(vocab) # 创建词到索引的映射 word_to_index {word: idx for idx, word in enumerate(vocab)} index_to_word {idx: word for idx, word in enumerate(vocab)} print(词汇表:, vocab) print(词汇表大小:, vocab_size) print(词到索引映射:, word_to_index)4.2 Bigram 模型类实现下面是完整的 Bigram 模型实现包含嵌入层和概率计算class BigramLanguageModel(nn.Module): def __init__(self, vocab_size): super().__init__() # 每个词都对应一个嵌入向量直接预测下一个词的概率 self.token_embedding_table nn.Embedding(vocab_size, vocab_size) def forward(self, idx, targetsNone): # idx 和 targets 都是形状为 (B, T) 的整数张量 logits self.token_embedding_table(idx) # (B, T, vocab_size) if targets is None: loss None else: # 计算交叉熵损失 B, T, C logits.shape logits logits.view(B*T, C) targets targets.view(B*T) loss F.cross_entropy(logits, targets) return logits, loss def generate(self, idx, max_new_tokens): # idx 是当前上下文形状为 (B, T) for _ in range(max_new_tokens): # 获取预测 logits, loss self.forward(idx) # 只关注最后一个时间步 logits logits[:, -1, :] # 变为 (B, C) # 应用softmax获取概率 probs F.softmax(logits, dim-1) # 从概率分布中采样 idx_next torch.multinomial(probs, num_samples1) # 将采样结果拼接到序列中 idx torch.cat((idx, idx_next), dim1) return idx4.3 训练数据准备与批处理为了高效训练我们需要将文本数据转换为模型可处理的格式# 将文本转换为索引序列 data torch.tensor([word_to_index[word] for word in words], dtypetorch.long) # 准备输入-目标对 inputs data[:-1] # 除最后一个词外的所有词 targets data[1:] # 除第一个词外的所有词 print(输入序列:, inputs) print(目标序列:, targets) print(输入序列对应的词:, [index_to_word[idx.item()] for idx in inputs]) print(目标序列对应的词:, [index_to_word[idx.item()] for idx in targets])4.4 模型训练循环现在让我们实现完整的训练过程# 初始化模型 model BigramLanguageModel(vocab_size) # 创建优化器 optimizer torch.optim.Adam(model.parameters(), lr0.01) # 训练循环 for epoch in range(100): # 前向传播 logits, loss model(inputs.unsqueeze(0), targets.unsqueeze(0)) # 反向传播 optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 20 0: print(fEpoch {epoch}, Loss: {loss.item():.4f}) print(f最终损失: {loss.item():.4f})5. 文本生成与模型推理5.1 使用训练好的模型生成文本训练完成后我们可以使用模型来生成新的文本# 从hello开始生成 start_word hello start_idx torch.tensor([[word_to_index[start_word]]], dtypetorch.long) # 生成5个新词 generated_indices model.generate(start_idx, max_new_tokens5) generated_words [index_to_word[idx.item()] for idx in generated_indices[0]] print(生成的文本:, .join(generated_words))5.2 概率分析与采样策略理解模型的预测概率分布对于调试和改进模型至关重要# 查看模型对特定词的预测概率 test_word hello test_idx torch.tensor([[word_to_index[test_word]]], dtypetorch.long) with torch.no_grad(): logits, _ model(test_idx) probs F.softmax(logits, dim-1) print(当前词:, test_word) print(下一个词的预测概率分布:) for i, prob in enumerate(probs[0, -1]): print(f {index_to_word[i]}: {prob.item():.3f})6. 模型优化与改进方案6.1 平滑技术解决零概率问题基础的 Bigram 模型面临严重的零概率问题。以下是几种常见的平滑技术加一平滑Laplace Smoothing P(wj|wi) (count(wi, wj) 1) / (count(wi) V) 其中 V 是词汇表大小回退平滑Backoff 当 Bigram 计数为零时回退到 Unigram 概率在 PyTorch 实现中我们可以在损失函数中加入标签平滑def forward_with_smoothing(self, idx, targetsNone, smoothing0.1): logits self.token_embedding_table(idx) if targets is None: loss None else: logits logits.view(-1, logits.size(-1)) targets targets.view(-1) # 标签平滑 confidence 1.0 - smoothing log_probs F.log_softmax(logits, dim-1) nll_loss -log_probs.gather(dim-1, indextargets.unsqueeze(1)) nll_loss nll_loss.squeeze(1) smooth_loss -log_probs.mean(dim-1) loss confidence * nll_loss smoothing * smooth_loss loss loss.mean() return logits, loss6.2 对数概率的数值稳定性在实际实现中我们通常使用对数概率来避免数值下溢问题def log_probability(self, sequence): 计算序列的对数概率 total_log_prob 0.0 for i in range(1, len(sequence)): current_word sequence[i] previous_word sequence[i-1] # 获取条件概率实际实现中会使用平滑版本 prob self.get_bigram_prob(previous_word, current_word) total_log_prob torch.log(prob 1e-8) # 避免log(0) return total_log_prob7. 扩展到更大数据集7.1 使用真实文本数据当我们将 Bigram 模型应用于更大规模的真实数据时需要改进数据处理流程def load_and_preprocess_text(file_path): 加载和预处理文本文件 with open(file_path, r, encodingutf-8) as f: text f.read() # 基础文本清理 text text.lower() # 更复杂的分词处理可以在这里添加 words text.split() return words def create_batches(data, batch_size, seq_length): 创建训练批次 num_batches len(data) // (batch_size * seq_length) data data[:num_batches * batch_size * seq_length] data data.reshape(batch_size, -1) batches [] for i in range(0, data.shape[1] - seq_length, seq_length): x data[:, i:iseq_length] y data[:, i1:iseq_length1] batches.append((x, y)) return batches7.2 内存优化的实现对于大规模数据我们需要考虑内存使用效率class MemoryEfficientBigramModel(nn.Module): def __init__(self, vocab_size): super().__init__() # 使用更紧凑的表示 self.bigram_counts nn.Parameter(torch.zeros(vocab_size, vocab_size)) self.unigram_counts nn.Parameter(torch.zeros(vocab_size)) def forward(self, idx, targets): # 使用稀疏矩阵运算提高效率 batch_size, seq_len idx.shape # 计算条件概率使用对数空间 log_probs self.compute_log_probs(idx) # 只计算目标位置的损失 loss -log_probs.gather(2, targets.unsqueeze(2)).squeeze(2).mean() return log_probs, loss8. 常见问题与调试技巧8.1 训练过程中的典型问题损失不下降检查学习率是否合适验证数据预处理是否正确确认模型参数初始化是否合理梯度爆炸/消失使用梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0)检查激活函数和初始化方法过拟合增加训练数据量使用早停法early stopping添加正则化项8.2 模型评估指标除了损失函数我们还应该关注其他评估指标def evaluate_model(model, test_data): 评估模型性能 model.eval() total_loss 0 total_tokens 0 with torch.no_grad(): for batch in test_data: inputs, targets batch logits, loss model(inputs, targets) total_loss loss.item() * inputs.numel() total_tokens inputs.numel() perplexity torch.exp(torch.tensor(total_loss / total_tokens)) return total_loss / total_tokens, perplexity.item() # 计算困惑度Perplexity loss, perplexity evaluate_model(model, test_batches) print(f测试集困惑度: {perplexity:.2f})9. 从 Bigram 到现代语言模型9.1 Bigram 与 N-gram 模型的关系Bigram 是 N-gram 模型家族中最简单的成员。理解 Bigram 为学习更复杂的模型奠定了基础Trigram基于前两个词预测下一个词4-gram、5-gram捕捉更长的上下文但数据稀疏性问题更严重神经网络语言模型使用神经网络来估计概率克服了 N-gram 模型的局限性9.2 通向 Transformer 的路径Bigram 模型的学习为理解现代大语言模型提供了重要基础词嵌入概念Bigram 中的查找表是现代词嵌入的雏形条件概率建模自回归生成的核心思想概率链式法则语言模型的基本数学框架理解这些基础概念后学习 Transformer 架构和注意力机制会更加自然。10. 实际项目应用建议10.1 教学与实验场景Bigram 模型在以下场景中特别有用教学演示直观展示语言模型的基本原理算法原型快速验证文本处理流程基准测试作为更复杂模型的性能基准10.2 生产环境注意事项虽然 Bigram 模型简单但在实际应用中仍需注意数据质量训练数据的质量直接影响模型性能内存使用词汇表大小会显著影响内存占用推理速度对于实时应用需要优化推理性能# 生产环境中的优化版本 class OptimizedBigramModel: def __init__(self, model_path): self.model torch.jit.load(model_path) self.model.eval() def predict_next_word(self, current_word): with torch.no_grad(): # 优化后的推理逻辑 pass通过本文的完整实现和深入解析你应该已经掌握了 Bigram 语言模型的核心概念和实现技巧。这个简单的模型是理解现代大语言模型的重要基石为你进一步学习 Transformer、BERT、GPT 等先进模型奠定了坚实的基础。

相关新闻

AI Agent开发与大模型应用实战:从WAIC前沿趋势到工程落地

AI Agent开发与大模型应用实战:从WAIC前沿趋势到工程落地

最近在关注人工智能领域的朋友们可能注意到了,世界人工智能大会(WAIC)学术平台首届论文录用结果已经公布,57篇优秀论文从全球众多投稿中脱颖而出,覆盖了12个国家和地区。这不仅是学术界的盛事,更为我们开发…

2026/8/22 8:54:37 阅读更多 →
终极指南:如何免费让老手柄在新游戏中重获新生

终极指南:如何免费让老手柄在新游戏中重获新生

终极指南:如何免费让老手柄在新游戏中重获新生 【免费下载链接】XOutput A small DirectInput to Xinput wrapper 项目地址: https://gitcode.com/gh_mirrors/xou/XOutput 在游戏世界中,你是否曾遇到过这样的尴尬:手头的老式DirectInp…

2026/8/22 9:55:12 阅读更多 →
量化交易入门:从零搭建Python策略回测系统与工程化实践

量化交易入门:从零搭建Python策略回测系统与工程化实践

你有没有过这样的经历:看着股票、期货或者加密货币的K线图上下翻飞,心里盘算着“如果我在那个低点买入,这个高点卖出,现在该赚多少了”?这种事后诸葛亮的懊悔,几乎是每个市场参与者的日常。但更让人沮丧的是…

2026/8/20 5:49:14 阅读更多 →

最新新闻

本地部署开源大模型:从硬件选型到实战配置全攻略

本地部署开源大模型:从硬件选型到实战配置全攻略

1. 项目概述:为什么本地部署大模型需要一份硬件配置攻略?最近和几个做量化交易的朋友聊天,他们都在琢磨一件事:能不能把那些动辄几百亿参数的“开源 股票 期货 量化大模型”搬到自己的机器上跑?一方面是为了数据隐私和…

2026/8/23 10:05:03 阅读更多 →
从零搭建QQ云崽机器人:Linux服务器部署与插件开发指南

从零搭建QQ云崽机器人:Linux服务器部署与插件开发指南

在实际项目开发或运维过程中,我们经常需要将一些自动化、信息查询或娱乐功能集成到即时通讯工具中,QQ机器人就是其中一种常见的实现方式。云崽机器人(Yunzai-Bot)是一个基于 Node.js 开发的、可扩展的 QQ 机器人框架,它…

2026/8/23 10:05:03 阅读更多 →
空中加油问题:从数学建模到组合优化算法的实战解析

空中加油问题:从数学建模到组合优化算法的实战解析

1. 项目概述:从一道赛题到一类经典优化问题的实战拆解 “空中加油”这个题目,乍一看像是军事或航空领域的专业问题,但对于参加过“华为杯”研究生数学建模竞赛的老兵来说,这绝对是一道让人印象深刻的经典赛题。它远不止是计算几架…

2026/8/23 10:05:03 阅读更多 →
RAG技术解析:从原理到面试全攻略

RAG技术解析:从原理到面试全攻略

1. 项目概述 RAG(Retrieval-Augmented Generation)技术是当前大模型应用领域最热门的方向之一。作为一名长期跟踪AI技术发展的从业者,我发现无论是刚入行的新人还是资深开发者,掌握RAG技术都已成为职业发展的关键技能。特别是在求…

2026/8/23 10:05:03 阅读更多 →
Spine动画AVATAR换装系统性能优化:单骨架动态附件架构实践

Spine动画AVATAR换装系统性能优化:单骨架动态附件架构实践

1. 项目概述:当AVATAR换装遇见Spine动画在游戏和互动应用开发里,AVATAR(虚拟形象)换装系统一直是个既让人兴奋又让人头疼的活儿。兴奋在于,它能极大地提升用户个性化体验和留存;头疼在于,当换装…

2026/8/23 10:05:03 阅读更多 →
dTree 入门指南:3 步画出支持多个父节点的数据树(家谱 / 组织关系)

dTree 入门指南:3 步画出支持多个父节点的数据树(家谱 / 组织关系)

dTree 入门指南:3 步画出支持多个父节点的数据树(家谱 / 组织关系) 【免费下载链接】dTree A library for visualizing data trees with multiple parents, such as family trees. Built on top of D3. 项目地址: https://gitcode.com/gh_m…

2026/8/23 10:04:03 阅读更多 →

日新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/23 0:00:50 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/23 0:00:50 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/23 0:00:50 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/23 0:00:50 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/23 0:00:50 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/23 0:00:50 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/22 18:08:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/22 7:31:03 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/22 3:22:48 阅读更多 →