任务与先修:让一个数字可被重新算出
训练收据说明优化工作了,但还没有回答留出文本难度和生成行为。本章要从冻结 checkpoint 产生一份可审计评估,而不是挑选最好看的样本。读者需会前三章的条件概率、对数、字节分母与规范BPE路径,以及第四章的非重叠窗口。我们明确报告三类不同对象:冻结参数下的条件预测损失、给定解码规则的生成串、分布与任务边界。它们各有用途,任何一个都不能替代另外两个。测试前已经固定宽度二十四、三十二次请求合并与八十更新,不用测试分数回头选择配置。
评估调用 model.eval 和无梯度上下文,避免训练行为与计算图;结束后恢复原先 train/eval 状态,使训练中的定期验证不悄悄改变下一步模式。此实验dropout为零,模式切换对当前数值影响小,仍要保持接口契约。每篇逐窗计算loss乘该窗有效目标数,得到NLL总和,随后累计文档目标数和原始UTF-8字节数。所有正文token和EOS各计一次;BOS不计,目标−100不计。输出逐文档记录,因此可以独立复算整体结果。
指标一:似然与困惑度
令第j篇文档在固定窗口协议下的NLL为 、有效目标数为 、正文原始字节数为 。总和分别记 S、N、B。对相同tokenizer与上下文协议,平均NLL为 S/N;困惑度是它的指数,等于真实目标概率几何平均数的倒数。所谓“等效候选数”只是对这个数值的直觉,不能推断模型实际均匀地在若干词中选择。不同编码或边界改变N,即使同样文本也不能直接横比PPL。
由对数换底,nats除以 就变成bits,再除正文bytes。BPE可能有多条token序列解码成同一文本,本项目只给规范encode路径计分,因此R不是对所有路径求和得到的文本边缘负对数。其分子还包含每篇EOS开销,分母不包含BOS/EOS或文件JSON字段。若要比较两个tokenizer,至少须冻结同一原始文本、相同边界计分政策、同样窗口与模型预算,并在名字中保留这个限定。统一分母并不能消除所有设计差异。
算例一:三个数互相校验
假设测试两篇,总NLL分别是六和九,总目标数分别二与四,原始正文分别三和七字节。S=15、N=6、B=10,均值为2.5 nats/target,PPL约12.182494,R约2.164043 bits/raw-byte。先平均两篇均值会得到 (3+2.25)/2=2.625,错误地把短文目标权重加大。独立检查一是用PPL取自然对数回到2.5;独立检查二是用R乘10再乘log2回到15。这种循环核算能发现分母、换底和字段单位错接。
项目真实固定测试有四篇,每篇六十三个原始字节,共252bytes;BPE加EOS后总119目标,NLL总和401.284752。由同一分子得到3.372141 nats/target、PPL约29.140844、R约2.297347。测试与验证各只留出一个动作模板组,而且仍共享人名与尾句,所以这个结果只能描述人工体系内的留出难度。小数位来自计算,不表示估计误差小;四篇高度相关文本不能支撑自然语料总体的精密结论。
基线把复杂系统放回可解释尺度
第一个基线是全部V个输出类别均匀,任何目标损失logV,可直接检查代码的数量级。第二个基线用训练目标计数拟合带平滑unigram:每个编号概率是 (count+alpha)/(训练目标总数+alpha×V),alpha取一。它不读上下文,只体现训练类别频率。验证与测试只查这个冻结概率表,不能重新估计计数。即使BOS从不成为训练目标,也仍在模型V类输出支持中,所以本基线同样给BOS平滑概率,使比较支持一致;它不会生成BOS作为正确目标。
算例二:不平滑的无限损失与错误的测试拟合
玩具训练目标是 [a,a,b,EOS],四类支持 [a,b,c,EOS]。加一后概率为3/8、2/8、1/8、2/8。测试目标 [c,EOS] 的NLL为 ,按目标均值约1.732868。若不平滑,c概率为零,NLL无限;这并不代表数学坏了,而是基线给观测事件零概率。若偷偷把测试c也计入训练频次,损失会变小,却不再是对未见数据的有效评估。
基线比神经模型更好并非必须隐藏的失败:它可能意味着模型预算太小、优化未稳定、窗口协议不利或数据只是频率主导。反过来胜过unigram也只说明利用了某些上下文统计,不证明复杂推理。我们不在这里设置“必须优于某阈值才展示”的筛选规则,因为那会鼓励挑选seed和测试集。基线应与模型结果一起固定保留,失败点也属于实验结果。
import math
S,N,B=15.,6,10
ppl=math.exp(S/N); rate=S/(B*math.log(2))
assert abs(math.log(ppl)-2.5)<1e-12
assert abs(rate*B*math.log(2)-S)<1e-12
train=['a','a','b','EOS']; vocab=['a','b','c','EOS']
q={v:(train.count(v)+1)/(len(train)+len(vocab)) for v in vocab}
nll=-sum(math.log(q[v]) for v in ['c','EOS'])
assert abs(nll-math.log(32))<1e-12
assert abs(sum(q.values())-1)<1e-12
print('PPL',round(ppl,6),'bits/byte',round(rate,6),'smoothed test NLL',round(nll,6))
生成是一项带策略的观察
项目生成从BOS加prompt正文编码开始,取最后位置logits,遮掉BOS候选,greedy选择最大项,遇EOS停止或达到max_new。这不是从原始模型分布随机采样:BOS候选被禁止,argmax也改变了行为,因此生成样本不能直接当作未改分布的统计估计。若上下文超过C,截取最后C个编号并从位置零重新计算,不假装learned绝对位置能无限增长;生成位置因此与完整长上下文条件不同。
同一模型给“某续接有低损失”与“greedy最终输出可读”是不同问题。teacher forcing评估每一步条件在真实过去上,生成却把自己刚输出的错误继续作为上下文。一次错误可能让后续进入训练中罕见区域,形成重复、混合词或非法UTF-8。应该保存prompt、生成编号、是否EOS停止、是否严格UTF-8成功与解码策略;只贴修饰后的自然语言句子会丢掉可定位的故障证据。随机采样若加入温度或top-k,也须作为新的明确协议记录。
实际固定实验prompt“小禾”的greedy续接为“整禾桥阿写下时间。”,UTF-8合法并以EOS停止。尾句来自训练共享模板,前半句组合混乱。这支持的结论很有限:模型能在该设置输出合法字节与已见片段,且结束控制可观察;它不支持“学会了写中文”。即使另一个prompt偶然生成通顺句子,也不能消除已保存失败。对这个语料,通顺与否还没有独立人工评分协议,因此不把一次主观观感写成准确率。
不确定性、留出组与诊断层级
文档平均的波动不能直接当成独立样本置信区间。我们的四篇测试来自同一个动作模板,存在强相关;以四篇独立抽样进行普通bootstrap会低估模板层面的不确定性。若要估计跨模板泛化,应有多个独立留出组,在组层面重采样或分组交叉验证,并为模型选择另留测试。当前项目没有足够独立组来给稳定总体区间,所以报告逐文档明细与限制,比给装饰性的“正负误差条”更诚实。
诊断顺序应从契约到统计:先核验语料和tokenizer摘要、有效目标数与EOS数,再检查损失是否有限、均匀基线是否对齐、权重是否冻结,最后才解释train/validation差距。训练NLL低而验证高,可以符合有限数据过拟合,也可能是留出组包含训练少见字节;需看逐文档和类别统计,不能单凭一条曲线断言架构优劣。若评估实现漏尾窗,即使曲线平滑也无效,应该先修复计数并重跑所有受影响结果。
本章项目增量是独立evaluate命令、逐文档收据、基线和可观察生成失败。第八章会冻结同一表示与评估协议,只改变宽度和更新预算,讨论什么是受控规模证据。进入下一章前应能从evaluation-test.json独立恢复三个指标,并说明为何它们既不是自然语言能力分数,也不是训练token数越多就必然降低的数学定理。
基线实测同样保存到了baselines.json。固定测试的均匀NLL每目标为5.669881,加一训练unigram为4.399566,完整微型decoder为3.372141。三个模型使用同一词表、同一目标集合和同一EOS政策,因此在本协议下可比较:decoder在这个留出组利用了比训练类别频数更多的信息。这个比较不隔离具体架构收益,因为unigram的参数化与训练方法不同;它只是一个能揭示流水线是否有明显问题的参照。
还应区分概率支持和生成约束。评估时softmax包含BOS这一列,真实目标从不为BOS,但其分到的概率会挤占其他类别;生成时将它遮掉意味着条件分布被重新限制。故若要严格估计生成策略的期望质量,应按该策略采样并评分;不能把原始teacher-forcing NLL直接称为约束解码后的性能。本项目仅用greedy样本作故障观察,并清楚记录其策略,不对样本做总体统计推断。
如果某篇测试文本原始字节数很短,EOS在R中的占比会大;同样的正文预测能力在大量短文上可能比少量长文有更高结束开销。因此跨数据集比较时还要报告文档数与长度分布,不能只统一总B。本项目每篇正文六十三字节,边界比率固定,适合核对公式,却没有覆盖长短混合语料的估计问题。保持逐文档NLL和长度,才能日后检查这种分布差异。
概率质量还可以从校准角度提问,但当前项目没有单独实现可靠的校准评测。低NLL会奖励给真实目标较高概率,也惩罚过度自信的错误,却不能单独告诉我们某个置信度分箱中的正确率是否匹配;生成句子的“可信度”更不是一个token最大概率。若要研究校准,需要独立定义目标事件、分箱和留出样本,并避免在同一小测试上选择温度。这里保留原始概率似然口径,不把它改名为答案可靠性或事实准确率。
python run.py evaluate --split test
python baseline.py
TRY IT YOURSELF
练习一:恢复测试指标
给S=401.28475189208984、N=119、B=252,写出三项指标公式及数量级,指出EOS在哪个量中。
提示 1
提示 2
对照参考解答
TRY IT YOURSELF
练习二:寻找评估污染
有人在每篇测试文档上先更新unigram计数再评分,说这没有训练神经网络。为什么结果仍与本章任务不同?
提示 1
提示 2
对照参考解答
TRY IT YOURSELF
练习三:生成与似然
提出两个能同时出现“验证NLL下降、生成仍差”的原因,并给出不改变测试选择的诊断。