2026/1/10 11:44:37
网站建设
项目流程
18款禁用网站app入口,网页设计参考网站,南充建网站,哈尔滨铁路局建设网站当你和AI聊天时#xff0c;它回答的每句话#xff0c;其实都是一个字一个字“猜”出来的。它只做一件事#xff1a;根据已经说出的所有字#xff0c;猜出下一个最可能的字。
你问#xff1a;“今天天气#xff1f;”
AI心里在猜#xff1a;看到“今天天气” → 猜下一个…当你和AI聊天时它回答的每句话其实都是一个字一个字“猜”出来的。它只做一件事根据已经说出的所有字猜出下一个最可能的字。你问“今天天气”AI心里在猜看到“今天天气” → 猜下一个是“很”。看到“今天天气很” → 猜下一个是“好”。看到“今天天气很好” → 猜下一个是“。”于是回答诞生了“今天天气很好。”这个“每次只猜下一个字”的简单规则就是自回归模型。它支撑着所有智能对话AI的回答。一、自回归模型1.1 核心公式概率的链条自回归模型的核心思想可以用一个优雅的公式表达P(x1,x2,...,xT)∏t1TP(xt∣x1,x2,...,xt−1) P(x_1, x_2, ..., x_T) \prod_{t1}^{T} P(x_t | x_1, x_2, ..., x_{t-1})P(x1,x2,...,xT)t1∏TP(xt∣x1,x2,...,xt−1)分解理解x1,x2,...,xTx_1, x_2, ..., x_Tx1,x2,...,xT表示一个由T个词组成的序列P(x1,x2,...,xT)P(x_1, x_2, ..., x_T)P(x1,x2,...,xT)是这个序列出现的概率P(xt∣x1,x2,...,xt−1)P(x_t | x_1, x_2, ..., x_{t-1})P(xt∣x1,x2,...,xt−1)是在给定前t-1个词的条件下第t个词出现的概率∏\prod∏表示连乘将所有条件概率相乘得到整个序列的概率直观例子对于句子“我爱学习”P(我, 爱, 学习)P(我)×P(爱∣我)×P(学习∣我, 爱) P(\text{我, 爱, 学习}) P(\text{我}) \times P(\text{爱} | \text{我}) \times P(\text{学习} | \text{我, 爱})P(我,爱,学习)P(我)×P(爱∣我)×P(学习∣我,爱)1.2 自回归的条件概率分解在深度学习中我们通过神经网络参数化这个条件概率P(xt∣x1,...,xt−1)Softmax(fθ(x1,...,xt−1))P(x_t | x_1, ..., x_{t-1}) \text{Softmax}(f_\theta(x_1, ..., x_{t-1}))P(xt∣x1,...,xt−1)Softmax(fθ(x1,...,xt−1))其中fθf_\thetafθ是参数为θ的神经网络如TransformerSoftmax函数将网络输出转换为概率分布模型在每一步输出一个在词汇表上的概率分布二、训练数据构建2.1 准备训练材料海量文本想象我们要训练AI理解中文就需要准备一个庞大的“语料库”——这就像给AI准备的“语文课本”包含了各种类型的文本 新闻文章、小说、百科知识、社交媒体对话、论坛讨论、学术论文、技术文档、诗歌、歌词、剧本…处理过程如下收集文本从各种渠道获取海量文字清洗整理去掉错别字、乱码、无关内容分词处理将连续的文字切成有意义的单元2.2 核心技巧向右位移训练自回归模型的关键在于如何教AI玩“猜词游戏”。我们通过“向右位移”的方法将一句话拆解成多个“猜词”练习。工作原理很简单给定一个完整的句子序列我们构建输入从第一个词到倒数第二个词目标从第二个词到最后一个词用公式表示给定序列: [x1,x2,x3,x4,x5]\text{给定序列: }[x_1, x_2, x_3, x_4, x_5]给定序列:[x1,x2,x3,x4,x5]输入: [x1,x2,x3,x4]\text{输入: }[x_1, x_2, x_3, x_4]输入:[x1,x2,x3,x4]目标: [x2,x3,x4,x5]\text{目标: }[x_2, x_3, x_4, x_5]目标:[x2,x3,x4,x5]假设我们的句子是“机器学习是人工智能的重要分支”第一步分词处理首先将这句话切割成有意义的单元token[机器,学习,是,人工,智能,的,重要,分支]第二步添加特殊标记为了让AI知道一句话从哪里开始、到哪里结束我们添加两个特殊标记BOS序列开始Beginning of SequenceEOS序列结束End of Sequence添加后的完整序列[BOS,机器,学习,是,人工,智能,的,重要,分支,EOS]第三步向右位移构建训练对输入AI看到的目标AI要猜的训练目标[][机器]根据开始标记猜第一个词是机器[, 机器][学习]根据机器猜下一个是学习[, 机器, 学习][是]根据机器学习猜下一个是是………[, 机器, 学习, 是, 人工, 智能, 的, 重要, 分支][]根据完整句子猜下一个是结束标记第四步实际训练处理在实际训练中我们不是创建多个独立训练对而是用一次性构建的方式输入[BOS, 机器, 学习, 是, 人工, 智能, 的, 重要, 分支]目标[机器, 学习, 是, 人工, 智能, 的, 重要, 分支, EOS]第五步滑动窗口处理长文本的关键在实际应用中我们通常面对的是很长的文本比如一篇文章、一本书。这时候就不能用向右位移的方法处理整个文本了为此我们引入了滑动窗口技术。滑动窗口包含两个关键参数窗口长度每次能看到多少个词窗口位移每次滑动多少个词参数设置窗口长度 4 窗口位移 2窗口位置输入窗口内容目标窗口内容窗口1[BOS, 机器, 学习, 是, 人工][机器, 学习, 是, 人工, EOS]窗口2[BOS, 是, 人工, 智能, 的][是, 人工, 智能, 的, EOS]窗口3[BOS, 智能, 的, 重要, 分支][智能, 的, 重要, 分支, EOS]………2.3 损失函数衡量“猜对”的程度在训练过程中我们需要一个标准来衡量AI“猜词”的水平。这就是损失函数的作用。计算原理在每个位置AI会给出对下一个词的“猜测”一个概率分布我们将这个猜测与真实的词比较计算它们之间的差异使用交叉熵损失用数学公式表示L−∑t1T−1logP(xt1∣x1,...,xt) \mathcal{L} -\sum_{t1}^{T-1} \log P(x_{t1} | x_1, ..., x_t)L−t1∑T−1logP(xt1∣x1,...,xt)当AI看到“机器学习是”时它可能认为下一个是“人工智能”的概率是0.7是“深度学习”的概率是0.2是“一个”的概率是0.1如果真实的下一个词是“人工智能”那么损失就是理想情况AI应该100%确定是“人工智能”实际情况AI只有70%确定损失值 -log(0.7) ≈ 0.36三、训练技巧教师强制策略3.1 教师强制Teacher Forcing的定义教师强制是一种训练策略在训练时总是使用真实的前一个词作为当前步的输入而不是使用模型自己可能错误的预测结果。训练步骤教师强制模式自由运行模式第一步输入: [BOS] → 预测: 机器输入: [BOS] → 预测: 机器第二步输入: [BOS, 机器] → 预测: 学习输入: [BOS, 预测1] → 预测: ?第三步输入: [BOS, 机器, 学习] → 预测: 是输入: [BOS, 预测1, 预测2] → 预测: ?第四步输入: [BOS, 机器, 学习, 是] → 预测: 人工输入: [BOS, 预测1, 预测2, 预测3] → 预测: ?假设在自由运行模式下模型在某个位置预测错误了教师强制模式理想情况步骤1:输入[BOS]→ 预测机器✓ 步骤2:输入[BOS,机器]→ 预测学习✓ 步骤3:输入[BOS,机器,学习]→ 预测是✓ 步骤4:输入[BOS,机器,学习,是]→ 预测人工✓ 步骤5:输入[BOS,机器,学习,是,人工]→ 预测智能✓...每一步都有正确的输入能学到正确的关系自由运行模式假设步骤4预测错误步骤1:输入[BOS]→ 预测机器✓ 步骤2:输入[BOS,机器]→ 预测学习✓ 步骤3:输入[BOS,机器,学习]→ 预测是✓ 步骤4:输入[BOS,机器,学习,是]→ 预测技术✗应该是人工 步骤5:输入[BOS,机器,学习,是,技术]→ 预测的✗输入已经错了 步骤6:输入[BOS,机器,学习,是,技术,的]→ 预测重要?完全偏离了...一个错误导致后续所有步骤都学不到正确关系教师强制的优势训练稳定避免错误累积传播收敛快速每一步都有正确的老师指导并行计算可以同时计算所有位置的损失梯度稳定反向传播时梯度不会因错误预测而发散3.2 暴露偏差问题与解决方法暴露偏差是教师强制策略的一个根本问题训练时使用真实数据但推理时使用模型自己的预测导致输入分布不一致。阶段输入来源输入质量结果训练时使用训练集中的真实词100%正确模型在理想条件下学习推理时使用模型自己生成的词可能包含错误模型在现实条件下工作例子说明训练时模型学习的是看到[BOS, 机器, 学习, 是]→ 应该输出人工但推理时模型面对的是看到[BOS, 机器, 学习, 是]→ 输出人工假设正确下一步看到[BOS, 机器, 学习, 是, 人工]→ 输出智能再下一步看到[BOS, 机器, 学习, 是, 人工, 智能]→ 输出的问题在于如果模型在推理时某一步出错了比如把人工输出成了技术它从来没有在训练时见过输入包含错误的情况不知道该如何处理。解决方法1. 计划采样Scheduled Sampling这是一种折中方案训练时不完全使用真实数据也不完全使用模型预测而是按一定概率混合。在每个训练步骤以概率ε使用真实的前一个词以概率(1-ε)使用模型自己预测的词。输入t{真实词t−1以概率 ϵ预测词t−1以概率 1−ϵ \text{输入}_t \begin{cases} \text{真实词}_{t-1} \text{以概率 } \epsilon \\ \text{预测词}_{t-1} \text{以概率 } 1-\epsilon \end{cases}输入t{真实词t−1预测词t−1以概率ϵ以概率1−ϵ训练过程训练初期ε接近1.0几乎全用真实数据训练后期ε逐渐减小增加使用模型预测的比例2. 课程学习第一阶段完全使用教师强制让模型先学会基本规律第二阶段逐渐引入模型自己的预测第三阶段完全或大部分使用模型预测3. 波束搜索推理时使用这不是训练技巧而是推理时的补救措施普通贪婪解码看到机器 → 选概率最高的学习 看到机器学习 → 选概率最高的是 看到机器学习是 → 选概率最高的人工 ...波束搜索波束宽度2通过保留多个候选序列降低了单步错误导致全局失败的风险。第一步保留2个最可能的词 [学习(0.6), 技术(0.3)] 第二步对每个候选扩展下一个词 - 学习 是(0.5) → 得分0.6×0.50.3 - 学习 的(0.2) → 得分0.6×0.20.12 - 技术 是(0.4) → 得分0.3×0.40.12 - 技术 领域(0.3) → 得分0.3×0.30.09 保留得分最高的2个序列 [学习 是, 技术 是] 第三步继续扩展...四、Transformer架构自回归的引擎4.1 后续掩码因果关系的守护者在自回归模型中最核心的要求是生成第t个词时只能看到前面t-1个词不能看到未来的词。这就是后续掩码Causal Mask也叫因果掩码要确保的事情。假设我们要生成机器学习是人工智能的重要分支这句话。在生成过程中当AI生成第3个词是时它只能看到[机器, 学习]当AI生成第5个词智能时它只能看到[机器, 学习, 是, 人工]绝对不能让它看到的、“重要”、分支这些未来的词但Transformer的注意力机制天生可以让每个位置看到所有位置。后续掩码就是在计算注意力时用一个眼罩遮住未来的位置。后续掩码是一个下三角矩阵形状为[序列长度, 序列长度]。矩阵的每个位置M[i][j]表示如果j ≤ i当前位置i可以看位置j则M[i][j] 0如果j i当前位置i不能看未来的位置j则M[i][j] -∞对于长度为4的序列掩码矩阵为M[[0,-∞,-∞,-∞],[0,0,-∞,-∞],[0,0,0,-∞],[0,0,0,0]]注意力计算公式原本是Attention(Q,K,V)softmax(QKTdk)V\text{Attention}(Q, K, V) \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)VAttention(Q,K,V)softmax(dkQKT)V加入后续掩码后变成Attention(Q,K,V)softmax(QKTdkM)V\text{Attention}(Q, K, V) \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}} M\right)VAttention(Q,K,V)softmax(dkQKTM)V在PyTorch中后续掩码的实现涉及特殊的梯度处理。我们来看一下具体细节importtorchimporttorch.nn.functionalasFdefcausal_attention(q,k,v):带后续掩码的注意力计算# q, k, v的形状: [batch_size, seq_len, d_model]batch_size,seq_len,d_modelq.shape# 1. 计算注意力分数# scores形状: [batch_size, seq_len, seq_len]scorestorch.matmul(q,k.transpose(-2,-1))/(d_model**0.5)# 2. 创建后续掩码下三角矩阵# 方法1使用torch.trilmasktorch.tril(torch.ones(seq_len,seq_len))# 下三角全1矩阵# 将1变成True保留0变成False掩码maskmask.bool()# 3. 应用掩码# 将mask为False的位置上三角填充为非常大的负数# 这样在softmax中这些位置的权重会变成0scoresscores.masked_fill(~mask,-1e9)# 4. 计算注意力权重attn_weightsF.softmax(scores,dim-1)# 5. 加权求和outputtorch.matmul(attn_weights,v)returnoutput,attn_weights梯度更新的特殊处理在PyTorch中masked_fill操作和后续的梯度计算有一个关键特性掩码位置不参与梯度计算当我们在scores上执行masked_fill(~mask, -1e9)时被填充为-1e9的位置在正向传播中这些值被设为常数-1e9在反向传播中这些常数位置的梯度为0softmax的数值稳定性将未来位置设为-1e9经过softmax后这些位置的权重为e−1e9es0es1...e−1e9...≈0 \frac{e^{-1e9}}{e^{s_0} e^{s_1} ... e^{-1e9} ...} \approx 0es0es1...e−1e9...e−1e9≈0由于数值下溢实际上这些位置对输出没有任何贡献因此这些位置在反向传播中也不会产生有效的梯度梯度流向示意图正向传播 位置0:只计算基于位置0的梯度 位置1:计算基于位置0、1的梯度 位置2:计算基于位置0、1、2的梯度...反向传播 位置2的梯度 ← 只能流向位置0、1、2的参数 位置1的梯度 ← 只能流向位置0、1的参数 位置0的梯度 ← 只能流向位置0的参数nn.MultiheadAttention是 PyTorch 提供的官方多头注意力实现其内部已经优化了注意力计算。在自回归模型中我们可以通过简单的方式实现因果掩码。importtorchimporttorch.nnasnn# 创建 MultiheadAttentiond_model512n_heads8mhann.MultiheadAttention(embed_dimd_model,num_headsn_heads,batch_firstTrue,# 输入形状为 (batch, seq, feature)dropout0.1)# 创建输入batch_size2seq_len10xtorch.randn(batch_size,seq_len,d_model)# 创建因果掩码defcreate_causal_mask(seq_len,device):创建因果掩码上三角矩阵# 上三角矩阵对角线上方为True需要屏蔽masktorch.triu(torch.ones(seq_len,seq_len,devicedevice),diagonal1).bool()returnmask# 计算自注意力causal_maskcreate_causal_mask(seq_len,x.device)output,attn_weightsmha(x,x,x,attn_maskcausal_mask)4.2 位置编码顺序的记忆Transformer还有一个重要组件位置编码。这是为了让模型知道词在序列中的位置。在传统的RNN中词是一个接一个处理的天然知道顺序。但Transformer是并行处理所有词的它本身不知道机器在第1位“学习在第2位。位置编码就是给每个位置一个独特的位置指纹”。Transformer使用正弦和余弦函数来生成位置编码对于位置pos维度i从0到d/2-1PE(pos,2i)sin(pos100002i/d)PE_{(pos, 2i)} \sin\left(\frac{pos}{10000^{2i/d}}\right)PE(pos,2i)sin(100002i/dpos)PE(pos,2i1)cos(pos100002i/d)PE_{(pos, 2i1)} \cos\left(\frac{pos}{10000^{2i/d}}\right)PE(pos,2i1)cos(100002i/dpos)其中pos词在序列中的位置0, 1, 2, …i维度索引d模型的维度如768每个词有两个部分的信息词嵌入表示这个词本身的含义位置编码表示这个词在序列中的位置词嵌入(机器) 位置编码(位置0) 输入的机器 词嵌入(学习) 位置编码(位置1) 输入的学习 词嵌入(是) 位置编码(位置2) 输入的是 ...五、推理过程从概率到文本当AI模型训练完成后我们需要让它生成文本这就是推理过程。推理的本质是模型基于已有的文本预测下一个最可能的词然后重复这个过程。5.1 基础解码策略贪婪解码选择最确定的路贪婪解码是最简单的策略每一步都选择概率最高的词。数学表达xtargmaxP(x∣x1,...,xt−1) x_t \arg\max P(x | x_1, ..., x_{t-1})xtargmaxP(x∣x1,...,xt−1)假设模型已经生成了机器学习是现在要生成下一个词。模型给出的概率分布是“人工”概率0.6“深度”概率0.3“神经”概率0.1贪婪解码会选择概率最高的人工。完整生成过程步骤1:输入机器→ 概率分布:学习(0.7),技术(0.2),科学(0.1)→ 选择学习步骤2:输入机器学习→ 概率分布:是(0.6),的(0.3),方法(0.1)→ 选择是步骤3:输入机器学习是→ 概率分布:人工(0.6),深度(0.3),神经(0.1)→ 选择人工步骤4:输入机器学习是人工→ 概率分布:智能(0.8),智能的(0.1),智能是(0.05)→ 选择智能...最终:机器学习是人工智能的重要分支优点简单快速缺点可能错过更好的整体序列因为每一步只考虑当前最优束搜索保留多条候选路径束搜索维护k个最可能的序列每一步扩展这些序列然后保留概率最高的k个。维护Top-k序列{(s1,p1),(s2,p2),...,(sk,pk)}\{(s_1, p_1), (s_2, p_2), ..., (s_k, p_k)\}{(s1,p1),(s2,p2),...,(sk,pk)}。假设我们要生成机器学习是人工智能束搜索过程束宽k2如下初始:只有开始标记BOS步骤1:基于BOS生成第一个词 候选1:机器(概率0.7)候选2:计算(概率0.2)候选3:数据(概率0.1)保留前2个:[机器,计算]步骤2:扩展两个候选 扩展机器:机器学习(概率0.7×0.60.42)机器技术(概率0.7×0.30.21)扩展计算:计算科学(概率0.2×0.50.10)计算机(概率0.2×0.40.08)合并后保留前2:机器学习(0.42)机器技术(0.21)步骤3:继续扩展 扩展机器学习:机器学习是(0.42×0.60.252)机器学习在(0.42×0.30.126)扩展机器技术:机器技术是(0.21×0.40.084)机器技术的(0.21×0.50.105)保留前2:机器学习是(0.252)机器学习在(0.126)继续这个过程最终选择概率最高的完整序列。优点比贪婪解码找到更好序列的概率更高缺点计算量随束宽k线性增长5.2 随机采样策略增加多样性随机采样不是每次都选概率最高的词而是根据概率分布随机选择。这让生成更有创造性。温度采样温度采样通过温度参数τ调整概率分布的平滑度P′(x)exp(logP(x)/τ)∑x′exp(logP(x′)/τ)P(x) \frac{\exp(\log P(x) / \tau)}{\sum_{x}\exp(\log P(x) / \tau)}P′(x)∑x′exp(logP(x′)/τ)exp(logP(x)/τ)其中τ是温度参数τ 1分布更尖锐更确定更少随机性τ 1原始分布τ 1分布更平滑更多随机性假设模型在某个位置给出的原始概率分布是“人工”概率0.6“深度”概率0.3“神经”概率0.1低温τ0.5更确定原始logits:log(0.6)-0.51,log(0.3)-1.20,log(0.1)-2.30除以τ:-0.51/0.5-1.02,-1.20/0.5-2.40,-2.30/0.5-4.60取exp:exp(-1.02)0.36,exp(-2.40)0.09,exp(-4.60)0.01归一化:人工:0.36/(0.360.090.01)0.78深度:0.09/0.460.20神经:0.01/0.460.02结果高概率词更高低概率词更低中温τ1.0原始分布保持原始概率人工:0.6,深度:0.3,神经:0.1高温τ2.0更随机除以τ:-0.51/2-0.255,-1.20/2-0.60,-2.30/2-1.15取exp:exp(-0.255)0.77,exp(-0.60)0.55,exp(-1.15)0.32归一化:人工:0.77/(0.770.550.32)0.47深度:0.55/1.640.34神经:0.32/1.640.19结果分布更均匀低概率词概率提升Top-k采样限定候选池Top-k采样只从概率最高的k个词中随机选择。例子k3原始概率分布前10个词人工:0.6,深度:0.3,神经:0.05,机器:0.02,计算:0.01,算法:0.005,...Top-3候选人工(0.6),深度(0.3),神经(0.05)重新归一化总和0.60.30.050.95新分布人工:0.6/0.950.63,深度:0.3/0.950.32,神经:0.05/0.950.05从新分布中随机采样Top-p采样核采样按概率累积筛选Top-p采样从累积概率达到p的最小词集中采样。按概率从高到低排序人工:0.6,深度:0.3,神经:0.05,机器:0.02,计算:0.01,算法:0.005,...计算累积概率人工:0.6人工深度:0.9达到p0.9人工深度神经:0.95超过p0.9 取最小词集使累积概率≥0.9{人工,深度}重新归一化总和0.60.30.9新分布人工:0.6/0.90.67,深度:0.3/0.90.33从新分布中随机采样六、代码示例手搓一个简单的 GPTimportrandomimportreimportwarningsfromcollectionsimportCounterimportmatplotlib.pyplotaspltimportnumpyasnpimporttorchimporttorch.nnasnnimporttorch.nn.functionalasFimporttorch.optimasoptimfromtorch.utils.dataimportDataset,DataLoader warnings.filterwarnings(ignore)# 设置中文字体plt.rcParams[font.sans-serif][SimHei,Arial Unicode MS,DejaVu Sans]plt.rcParams[axes.unicode_minus]False# 1. 设置和工具函数 SEED42torch.manual_seed(SEED)torch.cuda.manual_seed(SEED)np.random.seed(SEED)random.seed(SEED)torch.backends.cudnn.deterministicTruedevicetorch.device(cudaiftorch.cuda.is_available()elsecpu)print(f使用设备:{device})# 示例语料corpus[机器学习是人工智能的重要分支它使计算机能够从数据中学习。,深度学习是机器学习的一个子集使用神经网络来模拟人脑的工作方式。,自然语言处理是人工智能的另一个重要领域专注于计算机和人类语言之间的交互。,Transformer模型在自然语言处理任务中表现出色特别是在机器翻译和文本生成方面。,自回归模型如GPT通过预测下一个词来生成连贯的文本。,注意力机制是Transformer的核心它允许模型在处理序列时关注不同部分的信息。,预训练语言模型通过大规模无监督学习获得通用语言理解能力然后可以通过微调适应特定任务。,迁移学习使得我们可以在一个任务上学到的知识应用到另一个相关任务上大大提高了模型效率。,计算机视觉是人工智能的另一个重要分支专注于让计算机理解和解释视觉信息。,强化学习通过试错的方式让智能体学习如何在一系列动作中获得最大化的累积奖励。]defclean_text(text):textre.sub(r[^\w\u4e00-\u9fa5。,.!?;:\s],,text)textre.sub(r\s, ,text)returntext.strip()deftokenize(text):tokens[]forcharintext:ifchar.strip():tokens.append(char)returntokens# 2. 数据预处理 cleaned_corpus[clean_text(text)fortextincorpus]tokenized_corpus[tokenize(text)fortextincleaned_corpus]vocab_counterCounter()fortokensintokenized_corpus:vocab_counter.update(tokens)VOCAB_SIZE5000special_tokens[PAD,UNK,BOS,EOS]vocab_itemsspecial_tokens[wordforword,_invocab_counter.most_common(VOCAB_SIZE-len(special_tokens))]word2idx{word:idxforidx,wordinenumerate(vocab_items)}idx2word{idx:wordforidx,wordinenumerate(vocab_items)}# 3. Word2Vec词向量训练 classWord2VecEmbeddings:def__init__(self,tokenized_corpus,vector_size128,window5,min_count1):self.tokenized_corpustokenized_corpus self.vector_sizevector_size self.windowwindow self.min_countmin_count self.modelNonedeftrain(self):# 在实际应用中应该使用更大的语料训练Word2Vec# 这里为了简化我们使用随机初始化self.modeltype(obj,(object,),{wv:{}})returnself.modeldefget_embedding_matrix(self,word2idx):vocab_sizelen(word2idx)embedding_matrixnp.random.randn(vocab_size,self.vector_size)*0.1forword,idxinword2idx.items():ifwordinspecial_tokens:ifwordPAD:embedding_matrix[idx]np.zeros(self.vector_size)else:embedding_matrix[idx]np.random.randn(self.vector_size)*0.01else:# 随机初始化非特殊标记embedding_matrix[idx]np.random.randn(self.vector_size)*0.1returntorch.FloatTensor(embedding_matrix)w2vWord2VecEmbeddings(tokenized_corpus,vector_size128)embedding_matrixw2v.get_embedding_matrix(word2idx)# 4. 数据集和数据加载器 classTextDataset(Dataset):def__init__(self,tokenized_corpus,word2idx,max_len100):self.tokenized_corpustokenized_corpus self.word2idxword2idx self.max_lenmax_len self.unk_idxword2idx.get(UNK,1)def__len__(self):returnlen(self.tokenized_corpus)def__getitem__(self,idx):tokensself.tokenized_corpus[idx]tokens_with_special[BOS]tokens[EOS]iflen(tokens_with_special)self.max_len:tokens_with_specialtokens_with_special[:self.max_len]indices[self.word2idx.get(token,self.unk_idx)fortokenintokens_with_special]returntorch.tensor(indices,dtypetorch.long)defcollate_fn(self,batch):lengths[len(seq)forseqinbatch]max_lenmax(lengths)padded_seqstorch.full((len(batch),max_len),self.word2idx[PAD],dtypetorch.long)fori,seqinenumerate(batch):seq_lenlen(seq)padded_seqs[i,:seq_len]seq# 创建padding掩码key_padding_maskpadded_seqsself.word2idx[PAD]labelspadded_seqs.clone()foriinrange(len(batch)):seq_lenlengths[i]ifseq_len1:labels[i,:seq_len-1]padded_seqs[i,1:seq_len]labels[i,seq_len-1]self.word2idx[EOS]else:labels[i,0]self.word2idx[EOS]labels[i,seq_len:]-100returnpadded_seqs,key_padding_mask,labels,torch.tensor(lengths)datasetTextDataset(tokenized_corpus,word2idx,max_len50)dataloaderDataLoader(dataset,batch_size2,shuffleTrue,collate_fndataset.collate_fn)# 5. Transformer模型 classPositionalEncoding(nn.Module):def__init__(self,d_model,max_len5000):super().__init__()petorch.zeros(max_len,d_model)positiontorch.arange(0,max_len,dtypetorch.float).unsqueeze(1)div_termtorch.exp(torch.arange(0,d_model,2).float()*(-np.log(10000.0)/d_model))pe[:,0::2]torch.sin(position*div_term)pe[:,1::2]torch.cos(position*div_term)pepe.unsqueeze(0)self.register_buffer(pe,pe)defforward(self,x):returnxself.pe[:,:x.size(1)]classTransformerBlock(nn.Module):def__init__(self,d_model,n_heads,d_ff,dropout0.1):super().__init__()self.self_attnnn.MultiheadAttention(d_model,n_heads,dropoutdropout,batch_firstTrue)self.feed_forwardnn.Sequential(nn.Linear(d_model,d_ff),nn.ReLU(),nn.Dropout(dropout),nn.Linear(d_ff,d_model))self.norm1nn.LayerNorm(d_model)self.norm2nn.LayerNorm(d_model)self.dropoutnn.Dropout(dropout)defforward(self,x,attn_maskNone,key_padding_maskNone):attn_output,_self.self_attn(x,x,x,attn_maskattn_mask,key_padding_maskkey_padding_mask)xself.norm1(xself.dropout(attn_output))ff_outputself.feed_forward(x)xself.norm2(xself.dropout(ff_output))returnxclassAutoRegressiveTransformer(nn.Module):def__init__(self,vocab_size,d_model128,n_heads4,n_layers4,d_ff512,max_len100,dropout0.1,embedding_matrixNone):super().__init__()self.vocab_sizevocab_size self.d_modeld_model self.n_headsn_headsifembedding_matrixisnotNone:self.embeddingnn.Embedding.from_pretrained(embedding_matrix,freezeFalse,padding_idx0)else:self.embeddingnn.Embedding(vocab_size,d_model,padding_idx0)self.positional_encodingPositionalEncoding(d_model,max_len)self.transformer_layersnn.ModuleList([TransformerBlock(d_model,n_heads,d_ff,dropout)for_inrange(n_layers)])self.dropoutnn.Dropout(dropout)self.output_layernn.Linear(d_model,vocab_size)self._init_weights()def_init_weights(self):forpinself.parameters():ifp.dim()1:nn.init.xavier_uniform_(p)defcreate_causal_mask(self,seq_len,device):masktorch.triu(torch.ones(seq_len,seq_len,devicedevice),diagonal1).bool()returnmaskdefforward(self,input_ids,key_padding_maskNone,lengthsNone):batch_size,seq_leninput_ids.shape deviceinput_ids.device xself.embedding(input_ids)xx*np.sqrt(self.d_model)xself.positional_encoding(x)xself.dropout(x)# 创建因果掩码causal_maskself.create_causal_mask(seq_len,device)forlayerinself.transformer_layers:xlayer(x,attn_maskcausal_mask,key_padding_maskkey_padding_mask)logitsself.output_layer(x)returnlogitsdefgenerate_with_visualization(self,prompt,max_len50,temperature1.0,top_kNone,top_pNone): 生成文本并记录推理过程的详细信息 返回生成的文本和推理步骤的详细信息 self.eval()devicenext(self.parameters()).device tokenstokenize(clean_text(prompt))indices[word2idx.get(BOS,2)][word2idx.get(token,1)fortokenintokens]# 记录每一步的推理信息inference_steps[]withtorch.no_grad():forstepinrange(max_len):input_tensortorch.tensor([indices],devicedevice)logitsself.forward(input_tensor)last_logitslogits[0,-1,:]iftemperature!1.0:last_logitslast_logits/temperature probsF.softmax(last_logits,dim-1)# 记录原始概率分布original_probsprobs.clone()# 采样策略iftop_kisnotNone:top_k_probs,top_k_indicestorch.topk(probs,min(top_k,len(probs)))probstorch.zeros_like(probs)probs[top_k_indices]top_k_probs probsprobs/probs.sum()iftop_pisnotNoneandtop_p1.0:sorted_probs,sorted_indicestorch.sort(probs,descendingTrue)cumulative_probstorch.cumsum(sorted_probs,dim-1)sorted_indices_to_removecumulative_probstop_pifsorted_indices_to_remove[0]:sorted_indices_to_remove[0]Falseindices_to_removesorted_indices[sorted_indices_to_remove]probs[indices_to_remove]0probsprobs/probs.sum()# 从分布中采样next_idxtorch.multinomial(probs,1).item()# 记录这一步的详细信息current_input.join([idx2word.get(idx,UNK)foridxinindices[1:]])# 跳过BOSselected_tokenidx2word.get(next_idx,UNK)selected_probprobs[next_idx].item()# 获取前3个最可能的候选词使用原始概率topk_values,topk_indicestorch.topk(original_probs,min(3,len(original_probs)))# 修改为3candidates[idx2word.get(idx.item(),UNK)foridxintopk_indices]candidate_probstopk_values.cpu().numpy()# 转换为numpy用于记录inference_steps.append({step:step1,current_input:current_input,candidates:candidates,candidate_probs:candidate_probs,selected_token:selected_token,selected_prob:selected_prob})# 添加到序列indices.append(next_idx)# 如果生成了结束标记停止ifidx2word.get(next_idx,UNK)EOS:breakgenerated_tokens[]foridxinindices[1:]:# 跳过BOStokenidx2word.get(idx,UNK)iftokenEOS:breakgenerated_tokens.append(token)generated_text.join(generated_tokens)returngenerated_text,inference_stepsdefgenerate(self,prompt,max_len50,temperature1.0,top_kNone,top_pNone):普通生成函数不记录详细信息generated_text,_self.generate_with_visualization(prompt,max_len,temperature,top_k,top_p)returngenerated_text# 6. 训练函数 deftrain_epoch(model,dataloader,criterion,optimizer,device,clip1.0):model.train()total_loss0total_tokens0forbatch_idx,(inputs,key_padding_mask,labels,lengths)inenumerate(dataloader):inputsinputs.to(device)key_padding_maskkey_padding_mask.to(device)labelslabels.to(device)logitsmodel(inputs,key_padding_mask,lengths)losscriterion(logits.view(-1,model.vocab_size),labels.view(-1))optimizer.zero_grad()loss.backward()torch.nn.utils.clip_grad_norm_(model.parameters(),clip)optimizer.step()num_tokens(labels!-100).sum().item()total_lossloss.item()*num_tokens total_tokensnum_tokens avg_losstotal_loss/total_tokensiftotal_tokens0else0returnavg_lossdefevaluate(model,dataloader,criterion,device):model.eval()total_loss0total_tokens0withtorch.no_grad():forinputs,key_padding_mask,labels,lengthsindataloader:inputsinputs.to(device)key_padding_maskkey_padding_mask.to(device)labelslabels.to(device)logitsmodel(inputs,key_padding_mask,lengths)losscriterion(logits.view(-1,model.vocab_size),labels.view(-1))num_tokens(labels!-100).sum().item()total_lossloss.item()*num_tokens total_tokensnum_tokens avg_losstotal_loss/total_tokensiftotal_tokens0else0perplexitynp.exp(avg_loss)returnavg_loss,perplexity# 7. 可视化函数 defvisualize_inference_steps(inference_steps,prompt,save_pathinference_visualization.png): 可视化推理过程的每一步 ifnotinference_steps:print(没有推理步骤可可视化)return# 限制最多显示10步display_stepsinference_steps[:8]# 只取前10步# 计算需要多少个子图n_stepslen(display_steps)n_cols4n_rows(n_steps1)//n_cols fig,axesplt.subplots(n_rows,n_cols,figsize(15,5*n_rows))ifn_steps1:axesnp.array([[axes]])elifn_rows1:axesaxes.reshape(1,-1)elifn_cols1:axesaxes.reshape(-1,1)fig.suptitle(f推理过程可视化 - 提示: {prompt} (显示前{min(9,len(inference_steps))}步),fontsize16,y1.02)fori,step_infoinenumerate(display_steps):rowi//n_cols coli%n_cols axaxes[row,col]candidatesstep_info[candidates][:3]# 只取前3个候选词probsstep_info[candidate_probs][:3]# 只取前3个概率selected_tokenstep_info[selected_token]selected_probstep_info[selected_prob]current_inputstep_info[current_input]# 如果当前输入太长截断显示iflen(current_input)20:current_inputcurrent_input[:20]...# 为被选中的token设置不同的颜色colors[lightblue]*len(candidates)forj,candinenumerate(candidates):ifcandselected_token:colors[j]redbreak# 绘制柱状图barsax.bar(range(len(candidates)),probs,colorcolors,edgecolorblack)ax.set_xticks(range(len(candidates)))ax.set_xticklabels(candidates,rotation45,haright,fontsize8)ax.set_ylabel(概率)ax.set_ylim([0,max(probs)*1.2iflen(probs)0else1.0])# 添加概率值标签forj,(bar,prob)inenumerate(zip(bars,probs)):heightbar.get_height()ax.text(bar.get_x()bar.get_width()/2.,height0.001,f{prob:.3f},hacenter,vabottom,fontsize7,rotation90)# 设置标题titlef步骤{step_info[step]}: 已生成 {current_input}titlef\n选中: {selected_token} (概率:{selected_prob:.3f})ax.set_title(title,fontsize10)# 添加网格ax.yaxis.grid(True,linestyle--,alpha0.7)# 隐藏多余的子图foriinrange(n_steps,n_rows*n_cols):rowi//n_cols coli%n_cols axes[row,col].axis(off)plt.tight_layout()plt.savefig(save_path,dpi150,bbox_inchestight)plt.show()print(f可视化已保存到:{save_path})deftrain_model():VOCAB_SIZElen(word2idx)D_MODEL128N_HEADS4N_LAYERS4D_FF512MAX_LEN50DROPOUT0.1modelAutoRegressiveTransformer(vocab_sizeVOCAB_SIZE,d_modelD_MODEL,n_headsN_HEADS,n_layersN_LAYERS,d_ffD_FF,max_lenMAX_LEN,dropoutDROPOUT,embedding_matrixembedding_matrix).to(device)criterionnn.CrossEntropyLoss(ignore_index-100)optimizeroptim.Adam(model.parameters(),lr0.001,betas(0.9,0.98),eps1e-9)scheduleroptim.lr_scheduler.StepLR(optimizer,step_size5,gamma0.5)num_epochs20forepochinrange(num_epochs):train_losstrain_epoch(model,dataloader,criterion,optimizer,device)val_loss,perplexityevaluate(model,dataloader,criterion,device)scheduler.step()returnmodel# 9. 推理示例 definference_examples(model):test_prompts[机器学习,人工智能,深度学习模型,人工智能技术]strategies[(贪婪解码,{temperature:0.1,top_k:None,top_p:None}),(温度采样(τ0.8),{temperature:0.8,top_k:None,top_p:None}),(温度采样(τ1.2),{temperature:1.2,top_k:None,top_p:None}),(Top-k采样(k10),{temperature:1.0,top_k:10,top_p:None}),(Top-p采样(p0.9),{temperature:1.0,top_k:None,top_p:0.9}),]print(\n*60)print(推理示例:)print(*60)forpromptintest_prompts:print(f\n提示: {prompt})forstrategy_name,paramsinstrategies:generatedmodel.generate(prompt,max_len30,**params)print(f{strategy_name}:{generated})print(-*40)# 10. 详细推理过程 defdetailed_inference_visualization(model,prompt机器学习,strategy_name贪婪解码,temperature0.1,top_kNone,top_pNone,max_steps10):# 修改为10步 执行详细的推理过程并可视化 print(f\n{*60})print(f详细推理过程: 提示{prompt}, 策略{strategy_name})print(f{*60})# 使用可视化生成函数generated_text,inference_stepsmodel.generate_with_visualization(prompt,max_lenmax_steps,temperaturetemperature,top_ktop_k,top_ptop_p)print(f生成结果:{generated_text})print(f\n推理步骤详情 (显示前{min(10,len(inference_steps))}步):)forstepininference_steps[:10]:# 只显示前10步print(f\n步骤{step[step]}:)print(f 当前输入: {step[current_input]})print(f 候选词 (前3个):)forcand,probinzip(step[candidates][:3],step[candidate_probs][:3]):# 只显示前3个marker ✓ifcandstep[selected_token]elseprint(f {cand}:{prob:.4f}{marker})print(f 选中: {step[selected_token]} (概率:{step[selected_prob]:.4f}))# 可视化ifinference_steps:save_pathfinference_{prompt}_{strategy_name}.pngvisualize_inference_steps(inference_steps,prompt,save_path)if__name____main__:modeltrain_model()inference_examples(model)detailed_inference_visualization(model,prompt人工智能,strategy_name温度采样,temperature0.8,max_steps10)print(\n模型训练和推理完成)提示:机器学习贪婪解码:机器学习是人工智能的重要分支它使计算机能够从数据中学习。 温度采样(τ0.8):机器学习是人工智能的另一个重要分支它使计算机中学习获得最大通过测任 温度采样(τ1.2):机器学习是人工BOS能使获得们可和以个奖它错动别是在核心解人工。 Top-k采样(k10):机器学习是人工智能的重要分支它使计算机能型理解中学习。 Top-p采样(p0.9):机器学习是人工智能的另一个重要领域专注于让计算机能体学习。----------------------------------------提示:人工智能贪婪解码:人工智能的重要分支它使计算机能体学习获得最大化的文本。 温度采样(τ0.8):人工智能专注意力模型使贯的信算机能的相关任务中表现出色它拟通过相关 温度采样(τ1.2):人工智能移子过大言另一 Top-k采样(k10):人工智能的知效率智能体学习通过大规f到的核心特定学习是人类语言模型 Top-p采样(p0.9):人工智能的方式让智能的移s序列成连注于让何在一个关任务特互。----------------------------------------提示:深度学习模型贪婪解码:深度学习模型在一个任务上学习的另一个任务中表现出色专注于计算机器翻译和 温度采样(τ0.8):深度学习模型在处们可以在一个子集释络来注于关注于计算机何在一个重要间的 温度采样(τ1.2):深度学习模型Po注于forme域a语言拟人中nm任务子络网人脑的G支UNK。 Top-k采样(k10):深度学习模型效分的一个言分支它使计算机器学习获得我们可以作er的交下个 Top-p采样(p0.9):深度学习模型理络提的分练个子一个学习PAD能的文本到的方式。----------------------------------------提示:人工智能技术贪婪解码:人工智能UNKUNKransformermer模型在机器学习。 温度采样(τ0.8):人工智能UNKUNK习获得通过大强个重要领域应在一系列动作中学习获得过微调适应知 温度采样(τ1.2):人工智能UNKUNK关我们重特器之成类别言之间的可获得最预允经专不同 Top-k采样(k10):人工智能UNKUNKTransformer模型在处理解和文本。 Top-p采样(p0.9):人工智能UNKUNK得我T练语言度了模型在处理解和文本大规视觉部是人脑部信息。----------------------------------------详细推理过程:提示人工智能,策略温度采样生成结果:人工智能的重要分支专注于让 推理步骤详情(显示前10步):步骤1:当前输入:人工智能候选词(前3个):的:0.3264✓力:0.1290够:0.0600选中:的(概率:0.3264)步骤2:当前输入:人工智能的候选词(前3个):重:0.2218✓另:0.1457工:0.0736选中:重(概率:0.2218)步骤3:当前输入:人工智能的重候选词(前3个):要:0.8711✓过:0.0248训:0.0077选中:要(概率:0.8711)步骤4:当前输入:人工智能的重要候选词(前3个):分:0.6177✓过:0.1368领:0.0459选中:分(概率:0.6177)步骤5:当前输入:人工智能的重要分候选词(前3个):支:0.8837✓的:0.0361通:0.0123选中:支(概率:0.8837)步骤6:当前输入:人工智能的重要分支候选词(前3个)::0.9817✓模:0.0023然:0.0014选中:(概率:0.9817)步骤7:当前输入:人工智能的重要分支候选词(前3个):它:0.5508专:0.1657✓特:0.0605选中:专(概率:0.1657)步骤8:当前输入:人工智能的重要分支专候选词(前3个):注:0.9476✓言:0.0038子:0.0036选中:注(概率:0.9476)步骤9:当前输入:人工智能的重要分支专注候选词(前3个):于:0.8476✓意:0.0239不:0.0134选中:于(概率:0.8476)步骤10:当前输入:人工智能的重要分支专注于候选词(前3个):计:0.3456让:0.2211✓模:0.0449选中:让(概率:0.2211)本代码实现了一个完整的自回归Transformer语言模型核心功能包括数据预处理中文文本清洗、分词、词汇表构建词向量训练Word2Vec预训练词向量初始化模型架构完整的Transformer解码器训练过程自回归语言模型训练推理生成多种采样策略生成文本可视化推理过程的详细可视化这个代码展示了自回归Transformer语言模型的完整实现从数据预处理到模型训练再到多种推理策略和可视化。虽然模型规模较小但包含了GPT等大语言模型的核心原理自回归逐词生成每个词基于前面所有词Transformer架构多头注意力、前馈网络、残差连接多种采样策略平衡生成质量与多样性训练-推理一致性训练时的右移策略与推理时的生成过程一致