Files
CompanionGuard-RL/record.md
zhangsiyuan 52ba43f08d feat: Module C v5/v6 training complete, ablations, SOTA baselines, paper updates
- Module C: BC+PPO training v5/v6 done; eval results in experiments/eval_intervention_v{5,6}.json
- Reward: v5 label-aligned constrained reward (code/src/rl/reward.py)
- Ablations: Module B (history_r, response_only, full) + Module C (wo_category_reward)
- SOTA baselines: WildGuard and ShieldGemma2b eval scripts and results
- Paper: update sections 05–08 (Module B/C description, experiments table, discussion)
- Docs: add record.md (change log), update state.md and exp.md; retire change.md
- Tools: add html-to-ppt utilities and run_shieldgemma2b.sh
- Configs: add ablation YAML configs for Module B and C
- Cleanup: remove stale reference/ PNG screenshots

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 14:24:09 +08:00

22 KiB
Raw Permalink Blame History

CompanionGuard-RL — 历史变更记录

当前状态与下一步计划 → state.md | 踩坑经验库 → exp.md


2026-05-20 — P1a+P1b 消融实验完成

Module B 消融结果experiments/eval_abl_b_*.json

变体 Binary F1 FNR Level-W F1 Fine-Macro F1
Response-only 0.9990 0.000 0.5828 0.5025
History+Response 0.9995 0.000 0.5837 0.4667
Full (P+H+R) 0.9995 0.000 0.5585 0.4633

关键发现FNR=0 对所有变体成立Response-only 的 binary_f1=0.9990 仅低 0.0005。 Level/Fine 指标差异≤0.025,在训练方差范围内,不构成系统性趋势。

Module C 消融结果experiments/eval_abl_c_wo_category_reward.json

变体 Safety Recall Over-Refusal Action Acc Crisis Prec UX F-score
BC-only 0.940 0.000 0.697 0.509 0.969
w/o Category Reward 0.951 0.000 0.712 0.486 0.975
Full RL 0.953 0.000 0.706 0.571 0.976

关键发现:类别奖励提升 CrisisPrecision +8.5pp,代价是 ActionAcc -0.6pp(安全优先取舍)。

代码变更

  • src/data/dataset.pyformat_conversation()CompanionGuardDatasetablation_mode 参数
  • scripts/train_detector.py:从 config 读取 ablation_mode
  • scripts/evaluate.py:加 --ablation-mode CLI 参数
  • src/rl/reward.py:加 enable_category_reward 参数
  • src/rl/companion_env.py:透传 enable_category_reward
  • scripts/train_intervention.py:从 config 读取 enable_category_reward
  • 新建 3 个消融配置:detector_config_abl_response_only.yamldetector_config_abl_history_r.yamlintervention_config_abl_wo_category.yaml

踩坑:服务器 accelerate launch 需 PYTHONPATH

直接 nohup accelerate launch ... &ModuleNotFoundError: No module named 'src'。 原因accelerate 用 torch.distributed.run 启动子进程,子进程不继承父进程的工作目录 PATH。 修复:必须在同一 SSH 命令中先设 PYTHONPATH=$PROJ:$PYTHONPATHcd $PROJ 同时加 NCCL 环境变量(NCCL_P2P_DISABLE=1 NCCL_IB_DISABLE=1 NCCL_SHM_DISABLE=1)。 参考模板见 run_train_3gpu.sh

论文更新

  • 05_moduleB.tex:188:填入 3 行消融表 + 分析文字
  • 06_moduleC.tex:196:填入 3 行消融表 + 分析文字

2026-05-20 — WildGuard 分语言分层评估

背景

审稿人潜在质疑WildGuard/ShieldGemma 失败是否主要因为测试数据是中文?

数据分布test set

语言 样本数 其中高风险 覆盖类别
zh 1384 954 R1R10 全部
en 102 85 R1/R2/R6/R7/R8/R9无 R3/R4/R5/R10

英文数据来源:suicide_risk48条R1为主+ cosafe54条R6/R7/R9为主。 R3/R4/R5/R10 四个伴侣特有类别完全不存在于英文子集。

WildGuard 分语言结果experiments/eval_wildguard_stratified.json

子集 FNR Recall F1 n_risky
EN102条 0.882 0.118 0.211 85
ZH1384条 0.990 0.011 0.021 954

结论

  • 语言壁垒存在但不是主因EN→ZH FNR 差距约 0.108
  • 即使在英文上WildGuard 仍漏检 88.2%——说明是伴侣场景领域偏差+分类体系缺口造成的,而非纯语言问题
  • 英文子集缺少 R3/R4/R5/R10无法直接对比伴侣特有类别的跨语言表现

论文处置

  • 未放入主表(样本量小,逐类别无意义)
  • 加入 08_discussion.tex 局限四段落,用于回应潜在质疑

2026-05-19 — WildGuard 评估结果(已填入论文)

最终结果experiments/eval_sota_wildguard.json

指标 WildGuard ShieldGemma-2B Module B
binary_f1 0.038 0.027 0.9995
Recall 0.019 0.014 1.000
Precision 1.000
FNR 0.981 0.987 0.000

Per-categoryWildGuard recall R1=0.015, R2=0.021, R3=0.000, R4=0.000, R5=0.016, R6=0.031, R7=0.022, R8=0.069, R9=0.026, R10=0.000

解读WildGuard 极少输出 "yes"1039 个高风险样本仅检出 20 个), precision=1.0 说明偶发检出均为真阳性,但 recall 仅 1.9%。 R3/R4/R10伴侣特有类别完全漏检与 ShieldGemma-2B 结论一致。

脚本 bug 记录

首次运行结果全 0FNR=1.0)是解析 bug 脚本检查 "response: unsafe" 但 WildGuard 实际输出 "harmful response: yes/no"。 已修复 scripts/eval_sota_baselines.py(服务器)和 code/scripts/eval_sota_baselines.py(本地)。

论文更新

  • 05_moduleB.texWildGuard 行填入数字;分析段落扩展为同时讨论两款模型
  • 07_experiments.texL2b 描述填数字RQ1 分析段落加入 WildGuard

2026-05-19 — WildGuard 模型下载与评估准备

问题过程

  1. hf download allenai/wildguard 初次报 Access denied(需申请授权)
  2. 获得授权后,hf download --local-dir 多次尝试均卡死大文件shard 1.incomplete 停在 8KB 不增长
  3. 多个失败进程的 stale lock 文件(.cache/huggingface/download/*.lock)导致新进程永久 spin 等待
  4. wget -e use_proxy=yes 同样挂在 HTTPS 连接阶段
  5. 根因hf download / wget 通过 HTTPS 代理下载大文件(>1GB时不稳定小文件可通

修复方案

# 杀残留进程
ps aux | grep 'hf download' | grep -v grep | awk '{print $2}' | xargs kill
# 清 stale 锁(注意:会丢失 .incomplete 中的未完成进度)
rm -rf /path/to/wildguard/.cache
# 用 curl 下大文件
nohup curl -L --proxy http://127.0.0.1:7890 \
  -H "Authorization: Bearer <TOKEN>" -C - \
  "https://huggingface.co/allenai/wildguard/resolve/main/model-00001-of-00002.safetensors" \
  -o /path/wildguard/model-00001-of-00002.safetensors > /tmp/curl_dl.log 2>&1 &

额外教训

  • 第一次下载的 30 分钟 10 MB/s 流量:实为 ShieldGemma-2B~5G19:40-19:53+ WildGuard shard 24.3G21:12 落盘)
  • WildGuard shard 1 从未真正写出:hf download 并行下载时 shard 1 被卡在锁里shard 2 运气好完成了
  • rm -rf .cache 会删掉已在 .incomplete 中积累的部分进度,删前应先 ls -lh 确认大小

最终结果

  • shard 19.3Gmodel-00001-of-00002.safetensorscurl 下载22:56 完成
  • shard 24.3Gmodel-00002-of-00002.safetensors早已存在
  • 依赖补充:pip install sentencepieceWildGuard 用 Mistral tokenizer 需要)
  • 详细经验 → exp.md § 13

2026-05-19 — Module C v5 训练完成 + 根因分析 + v6 修复

v5 评估结果eval_intervention_v5.json

方法 safety_recall over_refusal action_accuracy crisis_precision safety_ux_fscore
Rule-based 0.908 0.000 0.952
Threshold 0.908 0.000 0.624 0.952
BC-only v5 0.914 0.000 0.695 0.509 0.955
RL v5 (BC+PPO) 0.833 0.000 0.717 0.531 0.909

Per-levelRL v5

Level           n   PASS   WARN   RWRT   REJT  CRISIS
L0_Safe       237  1.000  0.000  0.000  0.000   0.000
L1_Mild       280  0.836  0.075  0.071  0.000   0.018
L2_Moderate   317  0.032  0.448  0.413  0.054   0.054
L3_High       456  0.011  0.204  0.533  0.169   0.083  ← 20.4% WARN 是关键问题
L4_Critical   196  0.000  0.056  0.117  0.480   0.347

异常safety_recall 从 1.000v3退回 0.833(低于 rule baseline 0.908

根因safety_recall 只计 REWRITE/REJECT/CRISIS 为真实干预WARN 不算。

两重原因叠加:

  1. 标注噪声:训练集中有约 53 条 L3/L4 样本的 a_recommend=WARNBC-only 即有 L3 9.9% WARN + L4 4.1% WARN。这给 WARN 带来了 +3.0 exact match 正向信号。

  2. reward 缺陷v5 reward 对 L3/L4 只惩罚 PASS-5.0),未惩罚 WARN。PPO 熵从 0.489→0.074 极度收敛,把"L3选WARN"模式泛化BC 45条 → PPO 93条

精确计算:

  • L3: 93条 WARN × 未干预 + L4: 11条 WARN × 未干预
  • safety_recall = (456-5-93 + 196-11)/652 = 543/652 = 0.833

v6 修复与最终结果

修复 1code/src/rl/reward.py 新增 WARN_HIGH_PENALTY = -3.0

if action == ACTION_WARN and l_risk >= 3:
    reward += WARN_HIGH_PENALTY

v6 训练后 L3 WARN 从 93→79略降penalty=-3.0 不足以完全克服 BC 初始化的偏置。

修复 2最终方案code/scripts/evaluate.py 增加推理时 safety floor

det_l = int(s.get("det_l_risk", s["l_risk"]))
if action_val == _ACTION_WARN and det_l >= 3:
    action_val = _ACTION_REWRITE

v6 最终评估结果eval_intervention_v6.json含 action masking

方法 safety_recall over_refusal action_accuracy crisis_precision safety_ux_fscore
Rule-based 0.908 0.000 0.952
Threshold 0.908 0.000 0.624 0.952
BC-only v5 0.940 0.000 0.697 0.509
RL v6 (Ours) 0.953 0.000 0.706 0.571 0.976

论文使用此结果。 论文中明确说明policy 加 safety floorWARN on L3/L4 → REWRITE属于 constrained intervention policy不是掩盖。


2026-05-19 — 服务器修复后基础设施变更

SSH 认证方式更换

服务器修复后密码认证失效,改为 ED25519 公钥认证。

  • 本地私钥:C:\Users\张思远\.ssh\ai_tunnel_key2026-05-19 创建)
  • ~/.ssh/configserver5090 条目从旧密钥 id_server_5090 更新为 ai_tunnel_key
  • CLAUDE.md 服务器节同步更新

存储 UUID 变更

服务器修复后存储卷重新挂载UUID 从 siton-data-740d234e02d749f08fe5347b0c74c49f 变为 siton-data-2849d4ce327c4ccfb233ce33868fe7fe

  • 影响文件:configs/intervention_config.yamldetector.model_name)、configs/detector_config_server.yamlmodel.name
  • 已用 sed 替换服务器文件,本地文件同步更新
  • 教训:服务器修复/重置后,含绝对路径的 config 文件必须第一时间检查 UUID 是否变更

代理隧道

服务器无外网访问,但本地开有隧道转发至服务器 127.0.0.1:7890HTTP proxy

  • 服务器上 pip/curl 使用网络时需设置 http_proxy=http://127.0.0.1:7890 https_proxy=http://127.0.0.1:7890
  • 验证命令:netstat -tlnp | grep 7890,监听 127.0.0.1:7890 表示隧道正常

2026-05-19 — CLAUDE.md 增加行为准则

新增"行为准则"节,五类策略:结果异常立即暂停、不可逆操作需确认、范围纪律、研究诚信、歧义时询问。


2026-05-19 — P0 完成:论文结果节主体就绪

修改的文件

文件 改动内容
paper/sections/06_moduleC.tex 主表填入 v6 数字 + 新增 BC-only 行per-level 表替换为 v6 数据;删除 v3 参考行;分析文字更新
paper/sections/07_experiments.tex RQ2 文字更新为 v6 结论;基线列表改为 ShieldGemma-2B / WildGuardRQ1 SOTA 漏检率填入具体数字
paper/sections/05_moduleB.tex ShieldGemma-2B 行填入实测数字;正文新增 ShieldGemma-2B 漏检分析段
paper/sections/08_discussion.tex 局限一/二 的"v5更新"占位符替换为 v6 实际结果

Module C v6 最终数字(eval_intervention_v6.json

方法 SafetyRecall OverRefusal ActionAcc CrisisPrecision UX Fscore
BC-only 0.940 0.000 0.696 0.509 0.969
Ours (RL) 0.953 0.000 0.706 0.571 0.976

ShieldGemma-2B 评估结果(eval_sota_shieldgemma2b.json2026-05-19 19:55

  • binary_f1=0.027Recall=0.014FNR=0.987Level F1(W)=N/A
  • 所有伴侣特有类别 recall=0.000R3/R4/R8/R9/R10 均未检出)
  • 表现比简单关键词匹配L1c FNR=0.816)还差——核心原因:中文数据 + 无伴侣特有分类体系
  • 论文价值ShieldGemma-2B vs Module BFNR 0.987 vs 0.000)是最有说服力的对比

SOTA 评估工具链

  • code/scripts/eval_sota_baselines.py:支持 shieldgemma2b / wildguard 两种模式
  • 服务器模型路径:$PROJ/../shieldgemma-2b(已下载,google/shieldgemma-2b
  • 服务器 HF CLI/opt/conda/envs/dlapo-py310-cu128/bin/hfv1.14.0hf auth login / hf download
  • WildGuardallenai/wildguard,开放无需审核,随时可跑

剩余 \todo{}(全部 P1

WildGuard 数字、LLM-as-judge、Module B/C 消融表、IRB 声明。详见 state.md 剩余 todo 一览表。


2026-05-19 — CLAUDE.md 重写

将 CLAUDE.md 精简为"跨会话永远成立"的内容:系统架构、不变量、论文论点、文档导航、代码结构、服务器入口。 移出的内容:模块状态表(→ state.md、scp 命令(→ state.md、PyYAML/NCCL 调试经验(→ exp.md、带版本注释的文件清单→ state.md


2026-05-19 — 文档整理与服务器统一

  • change.md 内容整合入 state.md(执行计划)和 record.md(历史记录),原文件删除
  • state.md 重写为"当前状态 + 下一步计划"单一视图
  • record.md 新建,承接所有历史变更记录
  • CLAUDE.md 更新文件地图,新增四文件更新规则
  • 服务器统一为服务器 1ssh -p 20083 root@10.82.3.180,密码 m2dGcwyrhI),移除服务器 2 相关信息

2026-05-19 — Git Port Regression 修复

问题: 8c74d91port wangyu data pipeline引入了 pin_memory regression。

train_intervention.py 在 BC 阶段:

  • build_bc_tensors(..., device="cpu") 返回 CPU tensor ✓
  • 随后 obs_tensor.to(accelerator.device) 移到 GPU ← 新增的错误行
  • DataLoader(pin_memory=True) 收到 CUDA tensor → RuntimeError: cannot pin cuda tensor

修复:.to(accelerator.device) 改为 .cpu(),保持 tensor 在 CPU 直到 accelerator.prepare() 在训练时自动搬运 batch。


2026-05-12 — Module C 训练完成v3 最终结果)

训练完成记录

  • 单 GPU 模式(--num_processes=1BC 5 epochs + PPO 200k steps
  • 权重:checkpoints/intervention/final_v2.pt5.1MB
  • 评估:experiments/eval_intervention_v3.json(论文基准)

Bug 修复时序(调试过程)

# 错误 根因 修复
1 ModuleNotFoundError: gymnasium 服务器环境缺包 cp -r .../gymnasium .../site-packages/
2 ModuleNotFoundError: wandb 环境缺 wandb 及依赖链 train_intervention.py + ppo_trainer.py 改为 try/exceptuse_wandb: false
3 OSError: Can't load hfl/chinese-macbert-large 服务器无公网 intervention_config.yaml 改为本地绝对路径
4 RuntimeError: No backend type associated with device type cpu torch.distributed.broadcast 不支持 CPU tensor broadcast 段加 .to(accelerator.device) 再广播
5 TypeError: '<=' not supported between float and str PyYAML 6.x 将 1e-3 解析为字符串 配置改为 0.001 / 0.0003
6 AttributeError: SequentialSampler has no set_epoch DataLoader 用 SequentialSampler 而非 DistributedSampler if hasattr(loader.sampler, "set_epoch"): guard
7 RuntimeError: cannot pin torch.cuda.FloatTensor pin_memory=True 要求 CPU tensor但 tensor 已在 GPU BC 阶段 tensor 保持 CPUaccelerator.prepare() 处理设备搬运
8 CUDA error: an illegal memory accessBC 后 PPO 开始) accelerator.wait_for_everyone()torch.distributed.barrier() 在 RTX 5090 NCCL 下崩溃 改用 --num_processes=1 单 GPU 运行

评估 Bug 修复v1→v2→v3

Bug Apreprocessing.py build_obs_vector 用了 ground truth l_risk(部署不可得)。修复:改用 sample.get("det_l_risk", sample["l_risk"])

Bug Bmetrics.py intervention_recall_high 阈值过粗l_risk≥3 → action≥2三种策略无差别。修复新增 per_level_action_distaction_accuracyvs a_recommend

版本 代码 模型 结论
eval v1 GT l_risk state GT l_risk 训练) 两个 bug指标虚高废弃
eval v2 det_l_risk GT l_risk 训练) train/eval 不一致,废弃
eval v3 det_l_risk 重训) 论文使用

Module C v3 完整评估结果

汇总指标:

方法 safety_recall(L3/L4) over_refusal action_accuracy crisis_precision safety_ux_fscore
Rule-based (l≥3→REJECT) 0.908 0.000 0.952
Threshold Baseline 0.908 0.000 0.624 0.952
Ours (RL v2) 1.000 0.004 0.575 0.421 0.998

Per-level Action DistributionRule / Threshold / RL

Rule-based (l_risk≥3→REJECT)
Level         n    PASS  WARN  RWRT  REJT CRISIS
L0_Safe     237   1.000 0.000 0.000 0.000  0.000
L1_Mild     280   0.918 0.000 0.000 0.082  0.000
L2_Moderate 317   0.420 0.000 0.000 0.580  0.000
L3_High     456   0.114 0.000 0.000 0.886  0.000
L4_Critical 196   0.041 0.000 0.000 0.959  0.000

Threshold Baseline
Level         n    PASS  WARN  RWRT  REJT CRISIS
L0_Safe     237   1.000 0.000 0.000 0.000  0.000
L1_Mild     280   0.843 0.075 0.082 0.000  0.000
L2_Moderate 317   0.044 0.375 0.552 0.000  0.028
L3_High     456   0.009 0.105 0.739 0.000  0.147
L4_Critical 196   0.000 0.041 0.316 0.000  0.643

Ours (RL v2, det_l_risk 重训)
Level         n    PASS  WARN  RWRT  REJT CRISIS
L0_Safe     237   0.987 0.008 0.004 0.000  0.000
L1_Mild     280   0.729 0.011 0.229 0.000  0.032
L2_Moderate 317   0.000 0.000 0.902 0.000  0.098
L3_High     456   0.000 0.000 0.871 0.000  0.129
L4_Critical 196   0.000 0.000 0.633 0.000  0.367

2026-05-15 — 论文 LaTeX 框架搭建

  • paper/main.tex 创建ctexart + xelatex22 页可编译
  • 方法节§3-§6完整结果节骨架
  • refs.bib 15 条参考文献

2026-05-12 — Module C v5 技术方案定稿

根因分析

为什么 v3 action_accuracy=0.575crisis_precision=0.421

  1. reward 与 a_recommend 语义冲突:矩阵式 reward 理想动作L1→WARN, L2→REWRITE…与数据集标注分布不一致L1 99.3% PASSL3 74.3% REWRITE
  2. c_primary_idx 用了检测器预测值(训练 reward 应用 GT
  3. 评估指标 safety_ux_fscore 过宽松,掩盖动作校准问题

a_recommend 分布test set

Level 主要标注动作
L0 100% PASS
L1 99.3% PASS
L2 93.4% WARN
L3 74.3% REWRITE17.5% REJECT8.1% CRISIS
L4 55.6% REJECT44.4% CRISIS

论文隐患与对策(已在设计中处理)

  1. action_accuracy 循环论证a_recommend 来自规则映射,非独立人工标注。对策:额外报告 safety/category 指标;抽样 50-100 条做人工复核。
  2. 单步 MDP 用 PPO 合理性:每样本一步,更像 contextual bandit。对策论文表述为 reward-optimized adaptive intervention policy加 BC-only 对照。
  3. detector 在 train set 上训练过Module C 训练 obs 来自 frozen detector 对 train set 的预测,可能偏乐观。对策:明确说明 Module C 评估在 held-out test 上。
  4. crisis_precision 定义与动作语义冲突:旧定义只把 L4 算正确 CRISIS若 R1 L3 也触发 CRISIS 则会被算错误。对策:新增 crisis_appropriatenessCRISIS on L4 or R1 with L3/L4

2026-05-0912 — Module B 最终版 v4

v2 → v3 → v4 演进

指标 v24022条 v38813条 v49896条
binary_f1 0.9848 0.9989 0.9995
high_risk_recall 0.9989 1.0000
FNR 1.52% 0.11% 0.00%
level_macro_f1 ~0.43 0.497 0.550
L1 Mild F1 ~0 0.174 0.635
fine_macro_f1 0.000 (bug) 0.476 0.463

v4 细粒度标签 F1

标签 v3 F1 v4 F1
FalseReassurance 0.279 0.383
PseudoTherapy 0.239 0.338
IsolationReinforcement 0.288 0.356
RiskNormalization 0.627 0.698
CoRumination 0.350 0.269 ↓targeted 副作用)
CrisisNonResponse 0.588 0.394 ↓targeted 副作用)

2026-05-09 — 4-GPU DDP 架构wangyu已 port 入 master

origin/main 提交 b4be398 设计了混合并行策略:

  • 预处理阶段4 GPU 分布式推理(distributed_preprocess()all_gather_object
  • BC 阶段4 GPU DDPDistributedSampler + accelerator.prepare
  • PPO 阶段:仅 GPU-0顺序决策无法并行

已知限制RTX 5090 accelerator.wait_for_everyone()torch.distributed.barrier() 在 BC 结束时崩溃CUDA illegal memory access。当前方案--num_processes=1 单卡运行。


数据集构建历史

版本 样本数 关键变化
v1 ~2,000 初始 LLM 生成
v2 4,022 扩充,加入 human 子集
v3 8,813 扩充核心集到 8,000 + 弱标签专项
v4最终 9,896 补充 targeted 1,083 条FalseReassurance/PseudoTherapy/IsolationReinforcement

v4 数据来源:

来源 样本数
Qwen2.5-72B 生成(核心) 8,000
弱标签专项generate_targeted.py 1,083
Human-AI Suicide Risk Dataset 393
CoSafe Dataset 420