qinghuan
← 理解模型与输入 / 全部笔记

单元 08 / 理解模型与输入

P1 · 重点提升L1 · 基础

控制生成随机性与 Token 预算

分清温度、采样和输出长度各控制什么,再用实际任务比较效果和用量。

本篇目录 · 按需要跳转

这篇重点学什么

本篇重点:先累计每项概率,再用二分查找选中一次采样结果;检查边界输入和调用预算,观察生成结果的随机性。

开始读正文 ↓
学过相近内容?查看哪些可以跳过

两条路线有些基础相同。已经学会的部分可以跳过,另一条路线只用来补你当前需要的内容。

概率与 softmax

共同基础概率归一化与数值稳定性是共同基础;采样和求梯度是不同任务。

另一条路线补充什么?

先推导交叉熵与 p − one-hot 梯度,再比较把多条损失求和或取平均(loss reduction)会怎样改变训练。

读完这篇,你能做什么

能只改变一种生成选项进行重复比较,报告字段合格率、差异和实际用量。

学习理由、准备要求与知识点

为什么学它

调整采样可以改变回答的变化程度,却不能代替事实检查。要靠重复比较判断参数效果,而不是把某个设置当作可靠保证。

先读这些内容

知识点清单

  • 候选 Token 分数
  • 概率归一化与 softmax
  • 贪心与采样
  • Temperature
  • top-k 与 top-p
  • 输出长度限制
  • 全任务 Token 预算
  • 种子及可重复性边界

运行前先确认完整算法使用 Java 17 标准库;JDK 源码基线为 OpenJDK 17 GA。示例是内存中的机制模型,外部服务接入需要另外配置和验证。

01先弄懂它是什么

模型生成回答时,通常先给下一个 token 的候选打分,再按规则选一个。贪心解码每次选最高分,采样则按概率分布随机选。选出的 token 会加入上下文,下一步的候选分布也随之改变。所以整段回答是一步步生成的,不是从固定句子库里抽出一条。

几种常见设置控制的是选候选的方式:Temperature 通常通过缩放分数,让分布更集中或更分散;top-k 限制候选数量;top-p 保留累计概率达到阈值的高概率候选。应用顺序和支持哪些参数要看具体实现。温度低不会自动核实事实,温度高也不保证更有创意,还是要在同一任务和评估标准下比较效果。

输出长度上限、单次上下文和全任务调用预算分别控制不同资源。随机生成可能出现更长回答、额外工具轮次或不稳定格式,因此预算约束必须由程序维护。种子有助于重现实验,但远端模型版本、批处理、硬件和实现变化仍可能影响结果,不能对所有服务承诺逐字相同。

文中这几个词,先认一认

候选分布
各个候选被选择的概率安排:每项非负,归一化后全部相加为一。
累积分布
按固定候选顺序把概率逐项加起来,形成一段段区间;区间越长,抽中机会越大。
解码策略
根据当前候选分数决定下一 token 的规则,例如贪心或采样;它本身不会检查事实。

还有陌生词?到术语小抄里看一个具体例子 ↗

02看看它怎么工作

假设三个候选权重为二、一、一,归一概率为二分之一、四分之一、四分之一。把[0,1)切成[0,0.5)、[0.5,0.75)、[0.75,1),随机数落在哪段就选哪个候选。零权重区间长度为零,不应被选到,这决定了二分查找必须找第一个严格大于u的累计值。

构建累计表只需一遍;以后每次选择通过二分把候选范围缩半。将随机数作为函数参数,可以直接测试边界0、0.5和接近1,而不依赖“多抽几次似乎正确”的不稳定测试。随机源和确定性映射分离,也是排查采样偏差的好方法。

权重先除以最大值再求和,避免两个巨大有限数相加溢出。全部为零、负数或非有限值明确拒绝。浮点累加会有舍入误差,将最终累计值固定为一用于封闭范围;这不使浮点概率完全精确,极小权重可能因表示精度被压成零宽区间。

正在加载流程图…

图中状态只描述本篇可执行机制;业务调用仍需由外层应用负责。
查看流程图源码(Mermaid)
flowchart LR
  L["候选分数"] --> F["温度及候选过滤"]
  F --> W["非负权重"]
  W --> C["累计概率表"]
  U["随机数 u"] --> B["二分定位区间"]
  C --> B
  B --> T["选择 Token 并更新预算"]

按顺序看,每一步做了什么

  1. 记录分数处理顺序、采样参数和模型版本。
  2. 得到经过过滤的非负权重,检查是否仍有候选。
  3. 构建归一累计表,固定候选顺序。
  4. 从[0,1)取随机数,查找第一个严格更大的累计值。
  5. 生成后更新调用与Token账本,达到任务上限即终止。

03对照实现代码

OpenJDK 17 Random 源码 (新标签页)↗

OpenJDK 17 GA,jdk-17+35 · Random.nextDouble

下方为原创 Java 教学片段,调用已核验的 JDK API 说明局部机制;不是该类原样源码,也不实现神经网络。完整程序见算法模块。

核心机制代码 · java
Random random = new Random(42L); // 固定种子便于本地实验复现。
double u = random.nextDouble(); // 取值范围包含 0,不包含 1。
int selected = draw(cdf, u); // 随机源与区间查找分开测试。
// Random 不是用于凭证或安全令牌的密码学随机源。

Random.nextDouble从伪随机位构造[0,1)范围内的double,源码给出了确定的生成机制。上界不包含一,使最后一个正宽区间能够用统一规则处理。

同一种随机生成器、相同种子和相同调用顺序可复现实验序列;如果额外调用一次随机数,后续选择都会移动。因此记录种子还不够,要固定整个实验路径。

真实模型服务不一定使用java.util.Random,也不一定暴露同等种子语义。Java程序只验证累积分布的选择机制,不能据此承诺某个远端服务重复输出。

普通伪随机源满足教学采样需求,却不应生成安全令牌;安全性质与统计分布是不同契约。这里没有把采样行为赋予身份或授权含义。

代码先调用谁,再调用谁

  1. 配置固定权重和候选顺序
  2. 归一后建立累计表
  3. Random.nextDouble提供u
  4. 二分查找累计区间
  5. 返回候选索引并更新任务计量

04动手写一个例子

累积分布二分采样

输入非负有限权重建立累计表,再输入u∈[0,1)返回候选索引。空分布和全零权重拒绝。Java17 Main.java通过固定u运行自测,不依赖随机碰巧命中。

输入 1
权重[2,1,1],u=0.5
输出 1
索引1
输入 2
权重[0,1,0],u=0
输出 2
索引1

最大值缩放不改变相对权重。先算缩放后总量,再逐项累加归一比例得到非递减累计表,最后项设为一。

二分保持答案在[lo,hi]中:若cdf[mid]严格大于u,答案可能在左边或mid;否则mid及更左位置都不能满足严格比较,将lo移到mid+1。

零权重产生相等累计值,严格大于规则自动跨过这些平台。只找大于等于会在u为零或精确边界时选到零概率项,边界测试因此比大量随机样本更直接。

为什么这样写是对的累计表非递减且末项为一;二分过程中所有小于lo的位置累计值不大于u,答案始终是第一个累计值大于u的位置。

时间 构建O(n),每次抽样O(log n)额外空间 O(n)

n为候选数量。构建表需要几次线性扫描;m次抽样共O(n+m log n)。这不包括神经网络计算分数和top-p排序成本。

保存为 Main.java,运行 javac --release 17 -encoding UTF-8 Main.java,再运行 java Main。程序包含固定输入自测,断言失败时会抛出错误。

Main.java · 完整可运行程序 · Java
public class Main {
    static double[] build(double[] weights){
        if(weights.length==0)throw new IllegalArgumentException("empty");
        double max=0;for(double w:weights){
            if(!Double.isFinite(w)||w<0)throw new IllegalArgumentException("weight");
            max=Math.max(max,w);
        }
        if(max==0)throw new IllegalArgumentException("all zero");
        double sum=0;for(double w:weights)sum+=w/max; // 先缩放再求和。
        double[] cdf=new double[weights.length];double prefix=0;
        for(int i=0;i<weights.length;i++){prefix+=(weights[i]/max)/sum;cdf[i]=Math.min(1,prefix);}
        cdf[cdf.length-1]=1;return cdf; // 收束浮点累计的尾部误差。
    }
    static int draw(double[] cdf,double u){
        if(!Double.isFinite(u)||u<0||u>=1)throw new IllegalArgumentException("u");
        int lo=0,hi=cdf.length-1;
        while(lo<hi){int mid=lo+(hi-lo)/2;
            if(cdf[mid]>u)hi=mid;else lo=mid+1; // 必须严格大于,跳过零宽区间。
        }
        return lo;
    }
    static void eq(int e,int a){if(e!=a)throw new AssertionError(a);}
    public static void main(String[] args){
        double[] c=build(new double[]{2,1,1});
        eq(0,draw(c,0));eq(1,draw(c,0.5));eq(2,draw(c,Math.nextDown(1.0)));
        eq(1,draw(build(new double[]{0,1,0}),0));
        eq(1,draw(build(new double[]{Double.MAX_VALUE,Double.MAX_VALUE}),0.5));
        try{build(new double[]{0,0});throw new AssertionError();}catch(IllegalArgumentException expected){}
        try{draw(c,1);throw new AssertionError();}catch(IllegalArgumentException expected){}
        System.out.println("PASS 7 tests");
    }
}

这些特殊情况也要试一试

  • u等于一不属于输入契约,必须拒绝。
  • 零权重不能因为累计值相等而被选中。
  • draw只接收build产生的合法累计表,外部表应另加验证。
进阶选读 · 后续再读:动态分布与大量抽样

场景分布固定但抽样次数很大,或者每次都有少量权重变化。

做法固定分布可研究别名表,O(n)预处理后常数时间选择;动态权重可用树状数组维护前缀和并按累计质量定位。

复杂度别名表O(n)空间、单次O(1);树状数组更新与选择O(log n),但浮点误差和非负总量仍需处理。

好处与代价复杂结构增加实现和校验成本;候选每步全部变化时,预处理仍需重做,不能只报告抽样内核速度。

05项目里怎么用

调参实验一次只改一个因素,保留提示、数据与模型配置。先用格式合规和禁止行为作为硬门槛,再比较任务质量、输出长度与失败率。更随机的输出可能增加风格多样性,也可能增加无关内容,不能只挑最好的一次展示。

一次任务用了多少预算,要把修复、重试和子任务的调用一起算进去;没有返回用量的部分标为未知。输出上限太小,JSON 可能还没写完就被截断;上限过大,也可能带来更多等待和费用。可以先观察实际输出长度,再为超限情况设计明确的错误状态和可恢复展示,避免把半份结果当成完成。

复现报告说明可控条件:本地权重、种子、代码版本和调用顺序可固定;远端服务的内部实现可能不可见。出现差异时先确认输入和配置,再分析随机变化;不要把所有差异都解释成模型升级,也不要把一次相同结果当作完全确定性的证明。

容易踩的坑

  • 把低温度当作事实正确的保证。
  • 忽略top-k与top-p的实现顺序及支持边界。
  • 二分使用大于等于,选中零权重项。
  • 只记录种子,不记录代码路径与模型配置。

几种做法,怎么选

表格有四列,窄屏可左右滑动查看代价和适用条件。

方案优势代价与限制适用条件
贪心输出选择简单,便于建立基线可能缺少多样性,仍会出错格式或确定任务的对照组
概率采样可探索多种候选表达波动更大,需要重复评价开放生成与多候选方案
固定候选表采样易测边界与概率机制不代表真实模型随上下文变化解码算法教学

06检验是否读懂了

先自己想、自己写,再展开答案核对。场景题是假设的练习情境;遇到还没学过的内容,可以做完基础后再回来。

先用自己的话解释

01Temperature调整的是事实来源吗?

展开参考答案与推导

不是,它改变候选分数或分布形状;资料缺失仍需检索和核验,采样参数无法补出可靠来源。

02累计表为什么允许相等值?

展开参考答案与推导

零权重对应零宽区间,相邻累计值可相等;二分必须寻找严格超过随机数的第一项。

03种子为什么不是完整复现条件?

展开参考答案与推导

生成器类型、调用顺序和输入分布也会影响序列,远端模型与计算实现还可能变化。

换个情况,还会处理吗

01重复运行格式偶尔失败,怎么办?

展开参考答案与推导

保留失败样本,固定提示和参数检查契约;比较多次运行通过率,并由应用校验输出,而非仅降低温度。

02抽样很快但整体生成仍慢,查哪里?

展开参考答案与推导

分离模型分数计算、候选过滤、抽样和网络时间;本题二分只是其中一小步,不能据此推断端到端性能。

03预算用完但还在自动修复,哪里缺约束?

展开参考答案与推导

修复流程没有共享任务级账本或停止条件;将每次调用预留和实际用量纳入统一预算。

写代码试一试

01精确边界应选哪项?

输入 / 条件
权重[1,1],u=0.5
输出 / 预期
索引1

提示 区间左闭右开。

展开参考答案与推导

首区间[0,0.5),第二个区间从0.5开始,因此找第一个cdf>u,不能返回首项。

02怎样验证全零权重?

输入 / 条件
[0,0,0]
输出 / 预期
拒绝

提示 先找最大值。

展开参考答案与推导

最大值为零说明不存在正质量候选,无法归一化;不要把它自动改成均匀分布而改变业务语义。

03增加平移分数不变性应在哪一层测?

输入 / 条件
logits全部加常数
输出 / 预期
Softmax概率不变

提示 不是在原始权重上相加。

展开参考答案与推导

对logits做共同平移再Softmax会抵消;直接给权重加常数会改变概率比例,两个操作不能混淆。

读完之后,独立完成

课后作业:自己做一遍

本篇共 9 道作业,先完成 7 道基础与综合任务,再按前置知识挑战进阶题。其中包含 1 道思维拓展,试着换个条件,看看原来的办法是否还管用。不附参考答案。

这次练什么

能只改变一种生成选项进行重复比较,报告字段合格率、差异和实际用量。

本篇重点加练

候选截断与全任务预算共同影响生成策略,需要把局部设置放回完整任务衡量。

  • top-k 与 top-p
  • 全任务 Token 预算

重点内容会多练几次。先说清楚怎么做,再试试空数据、出错或条件改变时会发生什么。

先自己做,卡住时记下问题,再回来查。问答题写清“为什么、什么时候适用”;动手题留下输入、输出和运行步骤,方便下次重做。

基础必做

  1. 作业 01原理问答

    给四个候选Token分数[3,1,0,-2],解释分数、归一化概率和选中结果的关系,并列出数值计算需要处理的异常输入。

    提交内容
    一份独立书面回答或标注图,包含自造例子、概念边界及判断依据。
    怎样算完成
    • 逐项回应题目要求,区分事实、假设与个人判断。
    • 能用自己的例子解释适用条件,记录尚未弄懂的点。

    练到的知识点候选 Token 分数 · 概率归一化与 softmax

  2. 作业 02代码推演

    对同一分数向量设置不同Temperature,分别推演贪心与采样的执行步骤;记录随机数参与的位置,不预先假定实验结论。

    提交内容
    手工推演记录,写明输入约定、中间状态、最终判断;可运行时附程序对照记录。
    怎样算完成
    • 推演包含中间过程,数据形状、单位、顺序或状态前后一致。
    • 主动检查至少一个边界或异常条件,能解释手算与运行差异。

    练到的知识点贪心与采样 · Temperature

综合应用

  1. 作业 03面试场景

    为简短分类答案与开放式总结选择候选截断和长度限制,列出top-k、top-p与输出上限的验收指标及失败样本。

    提交内容
    场景分析与决策记录,包含信息缺口、约束、备选方案和验证计划。
    怎样算完成
    • 方案回应给定约束,列出至少一种替代方案及代价。
    • 每项关键结论说明所需证据,不能核实的部分明确标注。

    练到的知识点top-k 与 top-p · 输出长度限制

  2. 作业 04编程实践

    实现带任务总预算的假采样器,固定输入与随机种子,连续运行多轮并核算消耗;测试中途预算不足和相同种子重复运行。

    提交内容
    可复现的最小程序或实验材料、自写测试、环境说明与运行记录;题目允许纸面实验时提交完整案例表。
    怎样算完成
    • 提交物按说明可以重现;测试覆盖正常、边界与失败场景。
    • 运行证据与断言能核验声明的行为,注明模拟与真实执行范围。

    练到的知识点全任务 Token 预算 · 种子及可重复性边界

  3. 作业 05排错实验

    构造概率边界恰好落在累计区间端点的输入,记录采样器选择规则;再改变候选顺序检查实现是否遵守你声明的契约。

    提交内容
    最小故障输入、复现步骤、观测记录、定位依据及回归用例。
    怎样算完成
    • 其他人可按记录复现故障,并区分现象与已验证原因。
    • 定位过程有观测依据,回归用例可以再次暴露原问题。

    练到的知识点概率归一化与 softmax · top-k 与 top-p

  4. 作业 06编程实践

    自行构造三至五步合法概率表,每一步候选分布不同,声明 EOS、每步预算计量、总预算和随机源;模拟多步任务,对比两组自选 top-k/top-p 策略的实际选择、停止位置和剩余预算。

    提交内容
    可复现的小程序或题目允许的离线实验、自写测试、输入和运行记录。
    怎样算完成
    • 输入、环境和运行过程可重现,测试覆盖声明的重点条件。
    • 验证目标由合同确定,模拟结果不冒充真实服务证据。

    练到的知识点top-k 与 top-p · 全任务 Token 预算

  5. 作业 07面试场景

    一个回答阶段希望扩大候选多样性,但任务还必须留下验证步骤的预算。制定预算与候选策略的联合合同,说明质量不达标时如何记录而非无限重试。

    提交内容
    场景评审记录,包含约束、备选方案、未决信息和验证计划。
    怎样算完成
    • 方案回应题目约束,取舍能对应到可核验的事实。
    • 给出失败或条件变化时的检查方式。

    练到的知识点top-k 与 top-p · 全任务 Token 预算

进阶挑战 · 掌握前置后选做

  1. 作业 08设计评审

    在固定小评测集上比较三种采样设置,联合报告成功率、输出长度和波动,并说明种子不能控制的外部因素。

    提交内容
    设计评审文档或对照实验报告,包含前置条件、方案取舍、验收证据与尚未验证的范围。
    怎样算完成
    • 比较使用一致条件与事先声明的标准,记录失败与未知结果。
    • 说明方案的适用前提、未覆盖风险及后续验证方法。

    练到的知识点贪心与采样 · Temperature · 全任务 Token 预算

思维拓展

先写出你的猜想,再用例子或实验验证。答案可以不同,但要说清依据、适用情况,以及还有什么没弄懂。

  1. 作业 09思维拓展 · 条件变化

    如果任务从单次生成改为“生成多个候选再验证”,重新定义截断、停止与质量比较标准,评审相同单次参数是否仍有相同含义。

    提交内容
    变更前后条件表、重新评审的方案、检验用例与新增代价。
    怎样算完成
    • 只改变明确列出的条件,比较口径保持一致。
    • 修改方案说明收益、代价与仍未验证的范围。

    练到的知识点top-k 与 top-p · 全任务 Token 预算

完成后,再检验一次

给每题标记“独立完成 / 查阅后完成 / 尚未完成”。查过资料或没做出的题,记下卡在哪里。隔一天换一组输入再试,能解释结果和出错原因,再把这个知识点标为掌握。

继续阅读

先看能帮你完成当前练习的部分。例子跑通后,再读更深入的解释。

打开资料库,找下一份学习材料 ↗