HED:High-Entropy Diagnostics
本仓库用于分析 RL 训练后的 LLM checkpoint 在生成过程中的高熵 token
动态,并生成 QAE Figure 2/3 复现实验所需的表格和图片。
当前流程分成三部分:
- 在 GPU 机器上获取高熵 token 原始数据。
- 准备每个 checkpoint step 对应的 pass@1 指标。
- 用 manifest 合并表格并绘制 Figure 2/3。
复现口径
QAE 复现默认使用严格模式。
- Figure 2 的论文复现需要同时提供
without_clip 和 with_clip 两组 run。
- 只有单组 run 时也可以绘图,但输出会被标记为
single_run_diagnostic。
- Figure 3 必须在 manifest 里显式设置
fig3.steps。
- Figure 3 论文口径使用 sampled high-entropy token 的归一化概率。
top-k probability mass 仍会作为诊断表生成,但不是主 Figure 3 口径。
Anthropomorphic 和 reasoning token 的分类规则在
qae_repro/markers.py。Figure 2 只统计 anthropomorphic token;Figure 3
把 anthropomorphic、reasoning 和 other 分开着色。
获取高熵原始数据
推荐入口是 scripts/run_hed.sh。它用于远程 GPU 机器,默认假设有 8 张
40GB A100。
运行前需要确认:
- checkpoint 已经转换成 HuggingFace
actor_hf 目录。
- checkpoint 路径形如
${CKPT_ROOT}/global_step_<STEP>/actor_hf。
- 每个
actor_hf 目录下至少有 config.json 和 tokenizer/model 文件。
- prompt 数据是 parquet 文件,至少包含
prompt、question 或 problem
其中一列。
启动方式:
实际使用时通常只需要编辑 scripts/run_hed.sh 顶部配置块。
scripts/run_hed.sh 配置参数
这些参数可以直接改脚本顶部,也可以通过环境变量覆盖。
| 参数 | 默认值 | 说明 |
|---|
CKPT_ROOT | /workspace/train_rl/qwen_3_8b/dapo/checkpoints | checkpoint 根目录。脚本会读取 ${CKPT_ROOT}/global_step_<STEP>/actor_hf。 |
DATA | /workspace/rl/data/dapo_math_17k_train.parquet | prompt parquet 数据路径。 |
OUT_ROOT | /workspace/train_rl/qwen_3_8b/hed/results/high_entropy_tokens/dapo_with_clip | 高熵 token 原始/合并分析输出根目录。 |
LOG_DIR | ${OUT_ROOT}/logs | shard 日志目录。 |
STEPS | (20 80 200) | 要分析的 checkpoint step。当前脚本按 step 串行处理;论文 Figure 3/8 使用 20/80/200。 |
GPUS | (0 1 2 3 4 5 6 7) | 每个 step 内用于 prompt shard 并行的 GPU 列表。 |
NUM_PROMPTS | 512 | 从 parquet 中采样的 base prompt 数。 |
SAMPLES_PER_PROMPT | 1 | 每个 base prompt 重复生成的样本数。 |
MAX_PROMPT_LEN | 1024 | tokenizer 输入截断长度。 |
MAX_NEW_TOKENS | 2048 | 每条 generation 最多生成 token 数。 |
TEMPERATURE | 1.0 | 生成采样温度;<=0 时使用 greedy。 |
BATCH_SIZE | 8 | 单个 shard 进程内部的推理 batch size。 |
TOP_ENTROPY_FRAC | 0.2 | 每个 step 内取 entropy 最高的比例。 |
TOP_PROB_K | 50 | 每个高熵位置记录 top-k token 概率质量,用于 probability-mass 诊断。 |
DEVICE_MAP | auto | 传给 transformers.AutoModelForCausalLM.from_pretrained 的 device_map。 |
SEED | 0 | prompt 采样随机种子。所有 shard 使用同一个 seed,保证切分前的 prompt 集一致。 |
原始数据生成策略
当前策略是 step 串行、batch 数据并行:
- 外层按
STEPS 顺序处理 checkpoint。
- 每个 step 内按
GPUS 启动多个 shard 进程。
- 每个 shard 只看到一张 GPU:
CUDA_VISIBLE_DEVICES=<GPU>。
- 所有 shard 使用相同
DATA、NUM_PROMPTS 和 SEED 先采样完整 prompt 集。
- 再按全局 generation index 切分:
prompt_index % num_prompt_shards == prompt_shard_id。
- 每个 shard 只写 raw token parquet,不单独计算高熵阈值。
- 一个 step 的所有 shard 完成后,脚本合并 raw parquet。
- 合并后在完整 step token records 上统一计算
TOP_ENTROPY_FRAC 阈值。
- 生成该 step 的
high_entropy_positions.csv、summary 和 probability-mass 诊断表。
- 当前 step 完成后才进入下一个 step,避免同时加载多个 checkpoint。
这意味着当前脚本不再支持 checkpoint step 并行;并行粒度是同一个 step 内的
prompt shard。
输出目录
以 OUT_ROOT=/workspace/train_rl/qwen_3_8b/hed/results/high_entropy_tokens/dapo_with_clip
为例:
1${OUT_ROOT}/logs/
2${OUT_ROOT}/step_20/shard_0/raw_token_records_step_20.parquet
3${OUT_ROOT}/step_20/shard_1/raw_token_records_step_20.parquet
4...
5${OUT_ROOT}/step_20/high_entropy_positions.csv
6${OUT_ROOT}/step_20/summary_by_step.csv
7${OUT_ROOT}/step_20/token_probability_mass_high_entropy.csv
8${OUT_ROOT}/step_20/category_probability_mass_high_entropy.csv
9${OUT_ROOT}/merged/high_entropy_positions.csv
10${OUT_ROOT}/merged/summary_by_step.csv
11${OUT_ROOT}/merged/token_probability_mass_high_entropy.csv
12${OUT_ROOT}/merged/category_probability_mass_high_entropy.csv
manifest 里的 high_entropy_csv 应指向 merged 结果,例如:
/workspace/train_rl/qwen_3_8b/hed/results/high_entropy_tokens/dapo_with_clip/merged/high_entropy_positions.csv
直接调用分析脚本
通常不需要直接调用 scripts/analyze_high_entropy_anthro_tokens.py,因为
scripts/run_hed.sh 已经处理了 shard、等待和合并。下面是该脚本的启动参数,
用于调试或自定义流水线。
| 参数 | 默认值 | 说明 |
|---|
--ckpt_root | /workspace/train_rl/qwen_3_8b/dapo/checkpoints | checkpoint 根目录。 |
--steps | all | 要分析的 step,支持 all 或多个显式 step。 |
--data | /workspace/rl/data/dapo_math_17k_train.parquet | prompt parquet 路径。 |
--tokenizer_path | None | tokenizer 路径;不填时使用第一个 checkpoint 的 actor_hf。 |
--out_dir | /workspace/train_rl/qwen_3_8b/dapo/high_entropy_anthro_tokens | 输出目录。 |
--num_prompts | 128 | 采样 base prompt 数。 |
--samples_per_prompt | 1 | 每个 base prompt 的 generation 数。 |
--seed | 0 | prompt 采样随机种子。 |
--prompt_shard_id | 0 | 当前 prompt shard id。 |
--num_prompt_shards | 1 | prompt shard 总数。 |
--max_prompt_len | 1024 | prompt 最大 token 长度。 |
--max_new_tokens | 512 | 最大生成 token 数。 |
--temperature | 1.0 | 采样温度。 |
--top_prob_k | 50 | 每个位置记录 top-k token 概率。 |
--batch_size | 2 | 推理 batch size。 |
--top_entropy_frac | 0.2 | 高熵位置比例。 |
--top_k_plot | 20 | 每张诊断图显示的 token 数。 |
--raw_records | None | 读取一个或多个 raw parquet,并只做合并后的 summary/table 输出。 |
--raw_only | False | 只写 raw parquet,不生成高熵 CSV、summary 或图。 |
--skip_plots | False | 只写表格,不画诊断图。 |
--device_map | auto | 模型加载的 device map。 |
准备 pass@1 指标
Figure 2 需要每个 step 的 pass@1 指标。可以从 W&B 导出,也可以手动提供
本地 CSV。
从 W&B 导出
先复制并编辑 manifest:
cp configs/qae_repro.example.json configs/qae_repro.local.json
在 manifest 的每个 run 中填写:
name:run 名称。
role:without_clip 或 with_clip。
high_entropy_csv:上一步得到的 merged high_entropy_positions.csv。
metrics_csv:导出的 pass@1 CSV 保存路径。
wandb_run_id:W&B run id。
top_prob_k:高熵分析时使用的 TOP_PROB_K。
设置 W&B API key 后运行:
1export WANDB_API_KEY=...
2python3 scripts/qae_repro.py fetch-metrics \
3 --manifest configs/qae_repro.local.json \
4 --entity cartman \
5 --project a100_verl_collapse_study
fetch-metrics 参数:
| 参数 | 必填 | 说明 |
|---|
--manifest | 是 | manifest JSON 路径。 |
--entity | 是 | W&B entity。 |
--project | 是 | W&B project。 |
metric key 默认是 val-core/aime2025/acc/mean@1,step key 默认是
training/global_step。可以在 manifest 的 metrics.metric_key 和
metrics.step_key 中修改。
手动提供本地指标
如果不使用 W&B,直接准备一个 CSV,并在 manifest 的 metrics_csv 指向它。
默认列名为:
1step,pass1
250,0.12
3100,0.18
4200,0.21
合并表格与绘制 Figure 2/3
manifest 示例在 configs/qae_repro.example.json。核心字段:
| 字段 | 说明 |
|---|
name | 实验名称。 |
strict | 是否启用严格复现检查。 |
output_root | 表格、图片、metadata 输出根目录。 |
metrics.metric_key | 从 W&B 读取的 pass@1 metric key。 |
metrics.step_key | 从 W&B 读取的 step key。 |
runs[].name | 单个 run 名称。 |
runs[].role | without_clip、with_clip 或诊断用角色。 |
runs[].high_entropy_csv | 高熵 merged CSV。 |
runs[].metrics_csv | pass@1 CSV。 |
runs[].wandb_run_id | 可选,W&B run id。 |
runs[].top_prob_k | 原始数据里记录的 top-k 概率数量。 |
fig3.steps | Figure 3 使用的 step,必须显式设置。 |
fig3.top_k | Figure 3 展示的 token 数。 |
当前仓库里的 configs/qae_repro.local.json 对齐实验机默认产物:
results/high_entropy_tokens/dapo_with_clip/merged/high_entropy_positions.csv
它只包含 dapo_with_clip 单组 run,strict=false,输出到:
results/qae_repro_workdir/qwen3_8b_dapo_with_clip_qae/
如果要做 Figure 2 论文口径复现,需要从 configs/qae_repro.example.json
准备一个同时包含 dapo_without_clip 和 dapo_with_clip 的 manifest,并确保
两组 run 都已有各自的 merged/high_entropy_positions.csv 和 pass@1 CSV。
先构建标准化表格:
python3 scripts/qae_repro.py merge --manifest configs/qae_repro.local.json
merge 参数:
| 参数 | 必填 | 说明 |
|---|
--manifest | 是 | manifest JSON 路径。 |
再绘图:
1python3 scripts/qae_repro.py plot \
2 --manifest configs/qae_repro.local.json \
3 --figures fig2 fig3
plot 参数:
| 参数 | 必填 | 默认值 | 说明 |
|---|
--manifest | 是 | 无 | manifest JSON 路径。 |
--figures | 否 | fig2 fig3 | 要绘制的图,取值为 fig2、fig3。 |
输出目录:
1results/qae_repro_workdir/<manifest_name>/raw/
2results/qae_repro_workdir/<manifest_name>/tables/
3results/qae_repro_workdir/<manifest_name>/figures/
4results/qae_repro_workdir/<manifest_name>/metadata/
其中:
tables/figure2_paper_reproduction.csv 或
tables/figure2_single_run_diagnostic.csv 是 Figure 2 表格。
tables/figure3_high_entropy_token_probability.csv 是 Figure 3 表格。
figures/*.png 是最终图片。
metadata/manifest_resolved.json 是路径解析后的 manifest。
results/ 是实验产物统一目录。其中中间结果默认不进入 git;最终图表发布到
results/final_artifacts/,这是 results/ 下唯一用于 git 同步的子目录。
需要把最终图表提交到代码仓库时,先把 tables/、figures/ 和 metadata/
发布到 git 跟踪目录:
目录命名约定:
1results/high_entropy_tokens/<run_name>/ # HED token 级原始 records、step 汇总和 merged CSV
2results/qae_repro_workdir/<manifest_name>/ # QAE merge/plot 工作区、W&B 指标、临时表格和图片
3results/final_artifacts/qae_repro/<name>/ # 最终图表和表格,随代码 git 同步
bash scripts/publish_final_artifacts.sh configs/qae_repro.local.json
发布后的最终图表位于:
results/final_artifacts/qae_repro/<manifest_name>/
旧版 Figure 2 绘图脚本
scripts/plot_qae_fig2_anthro_pass1.py 是直接绘制 Figure 2 风格图的旧入口。
主流程推荐使用 scripts/qae_repro.py merge 和 scripts/qae_repro.py plot。
旧脚本参数:
| 参数 | 必填 | 默认值 | 说明 |
|---|
--without_clip_high_entropy_csv | 是 | 无 | without clip 的高熵 CSV。 |
--without_clip_metrics_csv | 是 | 无 | without clip 的 pass@1 CSV。 |
--with_clip_high_entropy_csv | 是 | 无 | with clip 的高熵 CSV。 |
--with_clip_metrics_csv | 是 | 无 | with clip 的 pass@1 CSV。 |
--out_png | 是 | 无 | 输出 PNG 路径。 |
--out_summary_csv | 否 | None | 可选 summary CSV 输出路径。 |
--step_col | 否 | step | step 列名。 |
--metric_col | 否 | pass1 | 指标列名。 |
--phase_boundary_step | 否 | 150 | 阶段分界 step。 |
--no_phase_labels | 否 | False | 不显示阶段标签。 |
实验环境搭建
本仓库通过 HuggingFace Hub 托管代码和实验结果。实验机器通常无法直接访问
GitHub 或 huggingface.co,因此所有操作统一走 hf-mirror.com 镜像。
初次搭建
实验机(容器):
1# 1. 用镜像 clone 代码(<token> 替换为你的 HF token)
2git clone https://Ottoman6324:<token>@hf-mirror.com/Ottoman6324/hed
3cd hed
4
5# 2. 安装依赖
6pip install huggingface_hub
7apt-get update && apt-get install -y git-lfs
8git lfs install
9
10# 3. 配置 HF 环境变量(写入 ~/.bashrc 避免每次重复)
11echo 'export HF_ENDPOINT=https://hf-mirror.com' >> ~/.bashrc
12echo 'export HF_TOKEN=<token>' >> ~/.bashrc
13source ~/.bashrc
Mac:
1git clone https://huggingface.co/Ottoman6324/hed
2cd hed
3pip install huggingface_hub
4brew install git-lfs
5git lfs install
6hf auth login # 输入 HF token
日常使用
1# 拉取最新代码(实验机用镜像,Mac 不需要)
2git pull
3# 实验机的 git remote 已经是 hf-mirror.com,直接 git pull 即可
4
5# 运行实验(输出到 results/ 目录)
6bash scripts/run_hed.sh
7
8# 运行 QAE 复现分析
9python3 scripts/qae_repro.py merge --manifest configs/qae_repro.local.json
10python3 scripts/qae_repro.py plot --manifest configs/qae_repro.local.json
如果机器上已有旧路径产物,可以直接迁移到清晰命名目录:
1mkdir -p results/high_entropy_tokens results/qae_repro_workdir
2if [ -d results/dapo_with_clip ] && [ ! -e results/high_entropy_tokens/dapo_with_clip ]; then
3 mv results/dapo_with_clip results/high_entropy_tokens/dapo_with_clip
4fi
5if [ -d results/dapo_without_clip ] && [ ! -e results/high_entropy_tokens/dapo_without_clip ]; then
6 mv results/dapo_without_clip results/high_entropy_tokens/dapo_without_clip
7fi
8if [ -d results/qae_repro ]; then
9 for path in results/qae_repro/*; do
10 [ -e "$path" ] && mv "$path" results/qae_repro_workdir/
11 done
12fi
同步实验结果与最终图表
实验产出统一放在 results/ 下,但同步方式分两类:
results/final_artifacts/ 之外的中间结果(raw、合并表格、临时图片等)
同步到 HuggingFace Ottoman6324/hed-results Dataset 仓库。
- 最终用于论文/汇报的图表复制到
results/final_artifacts/,随代码仓库 git
同步。
results/final_artifacts/**/*.png 已在 .gitattributes 中配置为 Git LFS/Xet
对象。推送最终图表前需要确认当前机器已安装并初始化 Git LFS:
实验机上传(走镜像,上传完成后在 Mac 上就能下载):
HF_ENDPOINT=https://hf-mirror.com bash scripts/sync_results_upload.sh
发布最终图表到 git 跟踪目录:
1bash scripts/publish_final_artifacts.sh configs/qae_repro.local.json
2git add .gitattributes results/final_artifacts/
3git commit -m "Add QAE final artifacts"
4git lfs ls-files | grep results/final_artifacts
5git lfs push origin main
6git push
如果 git push 时 HuggingFace 提示包含 binary files,说明 PNG 没有作为
LFS/Xet pointer 提交。此时需要安装 git-lfs,重新 git add PNG 并
git commit --amend --no-edit 后再推送。
Mac 下载:
bash scripts/sync_results_download.sh
Mac 上传、实验机下载(反向场景,比如在 Mac 上整理好 manifest 后同步到实验机):
1# Mac 上
2bash scripts/sync_results_upload.sh
3
4# 实验机上
5HF_ENDPOINT=https://hf-mirror.com bash scripts/sync_results_download.sh
架构总览
HF Hub
├── Ottoman6324/hed (Model repo — 代码)
│ └── git clone/pull/push
│ 实验机走 hf-mirror.com,Mac 直连 huggingface.co
│ results/final_artifacts/ 下保存最终图表
│
└── Ottoman6324/hed-results (Dataset repo — 实验结果)
└── scripts/sync_results_upload.sh / sync_results_download.sh
实验机走镜像,Mac 直连,保存 results/ 下除 final_artifacts 外的中间结果
注意:results/ 大部分内容已加入 .gitignore,不会随代码 git push。
只有 results/final_artifacts/ 会进入 git。中间结果通过 HF Dataset repo 管理;
最终图表通过 results/final_artifacts/ 进入 git。
测试
python3 -m unittest discover -s tests