/experiments/5_1_logprobs/

5.1 节实验:在本机加载小模型,逐步读出每个 token 的候选与概率,看温度和 top-p 怎样改变采样

目录文件列表

文件 / 目录说明大小
📁 ../返回上级目录-
📁 sample_output/子目录-
📄 README.md6.1 KB
📄 logprobs.py6.8 KB
📄 requirements.txt24 B
📄 temperature_step1.py2.9 KB

README.md

5.1 看模型每一步在想什么:候选 token、概率与采样

这份代码回答三个问题。模型每一步在哪些 token 之间选、各有多大把握;温度和 top-p 改的是什么;同一个问题问几次、答案不一样时,从概率上能不能事先看出它哪里没把握。

它对你给的提示做三件事:

  1. 温度 0 生成一遍(每步都选概率最高的 token),逐步列出选中的 token、它的概率、排在后面的几个候选,以及要凑满 90% 的概率需要多少个候选。
  2. 在几个温度下各采样 5 次,把回复里概率低于 0.3 的 token 用【token|概率】标出来。
  3. 温度 1 再加上 top-p 0.9 采样 5 次,和不加 top-p 的那一组对比。

这里的概率一律指模型原始分布(温度 1)下的概率,所以同一个 token 在不同温度的回复里标出的数字相同,便于比较。

需要什么设备

本地小模型,下面两档都能跑:

没有这两样也能用 CPU 跑,只是慢。AI Builder Space 上的模型目前都不返回 logprobs(2026 年 10 月核实),所以这份代码没有 API 版。

安装与运行

cd 5_1_logprobs
uv venv && source .venv/bin/activate      # 没有 uv 就用 python3 -m venv .venv
uv pip install -r requirements.txt        # torch 和 transformers,约 1 GB
python logprobs.py                        # 第一次会下载模型;之后在 M3 Ultra 上约 20 秒跑完
python logprobs.py --prompt "你自己的问题" --prompt "另一个问题"
python logprobs.py --model Qwen/Qwen3.5-0.8B --temps 0.5 1.0 --samples 10

运行时可能看到几行 falling back to its reference PyTorch implementation 的提示,意思是 Qwen3.5 的线性注意力层没有用加速版实现,结果是对的,只是慢一些,可以忽略。在 NVIDIA 显卡上可以再 uv pip install flash-linear-attention 换成加速实现(我们在 RTX 5090 上就是这样跑的);Mac 上目前没有对应的加速实现。

该看到什么

默认两个提示,一个有确定答案(法国的首都),一个要模型编具体信息(推荐一家上海的独立咖啡馆,给店名和地址)。我们的样例输出在 sample_output/(2026-10-23,Qwen3.5-2B;mps_m3ultra_* 是 Mac Studio,cuda_rtx5090_* 是一张 RTX 5090)。下面的数字来自 Mac:

同一个模型、温度 0,换一台机器结果也可能不同。 我们在一张 RTX 5090(CUDA)上跑了同一份代码(sample_output/cuda_rtx5090_*)。法国首都那题和 Mac 上几乎一样(“法” 0.70、“法国” 0.20)。咖啡馆那题第 3 步,Mac 上“独立” 0.24、左引号 0.21,显卡上左引号 0.24、“独立” 0.22,前两名只差零点零几,bf16 在两种硬件上的舍入差异就足以让排名对调。于是显卡上的温度 0 回复变成了“推荐上海‘老上海’咖啡馆,地址位于黄浦区南京东路步行街附近”,店名第一个字“老”的概率只有 0.01。温度 0 只保证每步选当时概率最高的那个,前几名挨得很近时,结果对硬件、精度、批大小都很敏感。

采样有随机性,你的回复和我们的不会逐字相同;--seed 可以换随机种子。我们换过两个种子重跑,上面的现象都在:咖啡馆问题在每个温度下都是 5 次 5 个不同的答案,法国首都在温度 0.7 以下每次都是同一个答案,温度 1.5 有时出乱码有时不出。

换成你自己的数据

用 --prompt 换成你工作里真会问的问题,最好一个有标准答案、一个要模型给具体名字、数字或引用的。看两件事:温度 0 的逐步表里,哪些位置的概率掉到 0.3 以下、凑满 90% 要几百上千个候选;采样几次,答案是不是在这些位置上变来变去。这些位置往往就是需要你核实、或者需要你在上下文里直接给出事实的地方。

结果的 JSON 存在 results/ 下,包括逐步的候选表和每次采样的原文。

温度那张图的数据

temperature_step1.py 取一个提示第 1 步的整张词表 logits(加载方式同 logprobs.py),分别除以 0.5、1.0、1.5 再做 softmax,记下前五名候选和“其余全部”的概率,存到 sample_output/temperature_step1_<设备>.json。教材 5.1 的温度图读的就是 sample_output/temperature_step1_mps.json(2026 年 10 月,Mac Studio M3 Ultra)。温度 1.0 那一列和 logprobs.py 第 1 步的概率一致。