# AQuA Verifier — DeBERTa-v3-large Token Classification 基于 [DIVERSE](https://github.com/lz1oceani/diverse)(ICLR 2024)的 verifier 实现,在 AQuA 数学推理数据集上训练,用于对解题路径逐条打分。 ## 模型信息 | 项目 | 说明 | |------|------| | 基座模型 | microsoft/deberta-v3-large | | 任务类型 | Token 分类(5 类) | | 标签 | SOLUTION-CORRECT(0), SOLUTION-INCORRECT(1), STEP-CORRECT(2), STEP-INCORRECT(3), O(4) | | 训练数据 | AQuA — 250 题 × (20 条候选解/题 + 1 条正确答案/题) = 5250 条 | | 训练轮数 | 1 epoch(建议续训到 3-5 epoch 以获得更好泛化) | | 输入格式 | `[CLS] {步骤用%%分隔} && {题目}`,末尾带 `####{答案字母}` | | 打分方式 | 取 `[CLS]` 位置的 SOLUTION-CORRECT 概率 × 10,范围 0~10 | | 分数含义 | 越高表示模型越认可这条推理路径的正确性 | ## 文件说明 ``` aqua-verifier/ ├── run_ner.py # 训练入口 ├── verifier_data_prepare.py # 数据准备(LLM 输出 → CoNLL 格式 train.txt) ├── deberta_model.py # DeBERTa-v2 自定义模型(必须用此类加载,不能用 AutoModel) ├── utils_ner.py # CoNLL 数据加载与特征转换 ├── tasks.py # NER 任务定义 ├── utils.py # 数据结构 / 步骤标注 / 加权投票评估 ├── utils_io.py # 文件读取工具 ├── verifier_metrics.py # 评估指标(weighted voting accuracy) ├── labels.txt # 5 个标签 ├── config.json # 模型配置(含 task_specific_params 权重) ├── model.safetensors # 训练权重 ├── spm.model # SentencePiece tokenizer 模型 └── tokenizer_config.json # Tokenizer 配置 ``` ## 加载模型并打分 ```python import torch from transformers import AutoTokenizer from deberta_model import DebertaV2ForTokenClassification # 加载(换成你的 HuggingFace 用户名) tokenizer = AutoTokenizer.from_pretrained("你的用户名/aqua-verifier") model = DebertaV2ForTokenClassification.from_pretrained("你的用户名/aqua-verifier") model.eval() def score(question: str, solution: str) -> float: """ question: "Q: ... Options: A)... B)..." solution: 解题步骤(换行会自动转为 %%),末尾带 Therefore the answer is X. 或 ####X 返回 0~10 的分数 """ sol = solution.strip().replace("\r\n", "\n").replace("\n", "%%") # 如果没有 ####X 但文中有 "answer is X",自动补全 if "####" not in sol: import re m = re.search(r"answer is ([A-E])", sol, re.IGNORECASE) if m: sol += f" ####{m.group(1)}" text = f"[CLS] {sol} && {question}" inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=512) with torch.no_grad(): logits = model(**inputs).logits # [CLS] 位置 → SOLUTION-CORRECT 概率 → 映射到 0~10 return torch.softmax(logits[0, 0], dim=-1)[0].item() * 10 # 示例 q = "Q: 2+2=? Options: A)1 B)2 C)3 D)4 E)5" sol = "2+2=4%%Therefore the answer is D. ####D" print(score(q, sol)) # ~9.9 ``` > **注意**:不能用 `AutoModel.from_pretrained()`,必须从本仓库的 `deberta_model.py` 导入 `DebertaV2ForTokenClassification`。 ## 完整训练流程 ### 第一步:准备 LLM 生成结果 使用 deepseek-v4-flash 对 AQuA 每道题生成多条候选解(建议每题 10~20 条),按以下 JSONL 格式保存: ```json { "context": "Q: 示例题1...\\nOptions: ...\\nA: 示例解...\\n...(可放 few-shot prompt)", "samples": ["LLM生成的候选解1", "LLM生成的候选解2", ...], "metadata": { "question": "Q: 目标题目的文本", "ground_truth": "Q: 目标题\\nA: 标准答案推理过程", "correct": "A", "options": ["A)...", "B)...", "C)...", "D)...", "E)..."] } } ``` ### 第二步:生成 CoNLL 训练数据 ```bash python verifier_data_prepare.py \ --generator_result_file ./dataset/llm_outputs.jsonl \ --output_dir ./dataset/ \ --dataset_name AQuA \ --split train \ --text_entailment_model_name microsoft/deberta-large-mnli \ --text_entailment_batch_size 512 ``` > 步骤标注方式:对每条候选解的每个步骤,用 NLI 模型(`deberta-large-mnli`)与正确答案的对应步骤做文本蕴含判断。蕴含则为 STEP-CORRECT,不蕴含则为 STEP-INCORRECT。整体正确性用答案是否匹配判断。 输出:`train.txt`(CoNLL 格式,每行 `TOKEN LABEL`,序列之间空行分隔)。 ### 第三步:训练 Verifier ```bash python run_ner.py \ --model_name_or_path microsoft/deberta-v3-large \ --dataset_name AQuA \ --train_data ../data/train.txt \ --test_data ../data/test.txt \ --data_labels labels.txt \ --output_dir ../output/ \ --do_train --do_eval \ --per_device_train_batch_size 8 \ --num_train_epochs 5 \ --learning_rate 1e-5 \ --alpha 0.1 \ --overwrite_output_dir \ --save_strategy epoch \ --evaluation_strategy epoch \ --logging_steps 50 \ --save_total_limit 2 ``` 参数说明: | 参数 | 说明 | | ---- | ---- | | `--alpha 0.1` | STEP-CORRECT/INCORRECT 的 loss 权重。SOLUTION 类别固定为 1.0 | | `--num_train_epochs 5` | 建议 3-5 epoch。当前权重仅训了 1 epoch | | `--per_device_train_batch_size 8` | V100/A100 可用 8,小显存降到 4 | | `--save_total_limit 2` | 只保留最近 2 个 checkpoint,防磁盘满 | | `--learning_rate 1e-5` | DeBERTa-large 推荐学习率 | ### 续训 ```bash python run_ner.py \ ...(同上参数)... \ --resume_from_checkpoint ../output/checkpoint-NNN ``` ## 环境依赖 ```bash # 核心依赖 pip install torch transformers datasets numpy scipy tqdm seqeval rouge_score nltk absl-py six multiset conllu # 版本锁定(重要) pip install "transformers==4.38.2" "accelerate==0.27.2" ``` 如果在华为云 Ascend NPU 上训练,额外安装: ```bash pip install torch_npu export HF_ENDPOINT=https://hf-mirror.com ``` ## 评分原理与使用方式 训练时对序列中两个位置做标注: - **`[CLS]` token** → SOLUTION-CORRECT / SOLUTION-INCORRECT(整体解对不对,loss weight = 1.0) - **`%%` 分隔符 token** → STEP-CORRECT / STEP-INCORRECT(NLI 模型逐步骤判断正误,loss weight = 0.1) 推理打分有两种方式: 1. **整体打分(推荐)**:取 `[CLS]` 的 SOLUTION-CORRECT 概率,训练最充分(weight 1.0),实测区分度最好。 2. **逐步骤打分**:取每个 `%%` token 的 STEP-CORRECT 概率,可以看模型认为哪些步骤对。但当前仅训了 1 epoch,单个步骤的打分区分度有限。 ## 常见问题 ### 不能用 AutoModel 加载 本模型修改了 DeBERTa-v2 的内部代码(兼容新版 PyTorch/numpy),必须用仓库中的 `deberta_model.py`: ```python from deberta_model import DebertaV2ForTokenClassification model = DebertaV2ForTokenClassification.from_pretrained("用户名/aqua-verifier") ``` ### 分数偏低/偏高 因为预算不够,本模型仅训练了 1 epoch,在训练数据风格的推理文本上区分度良好(CORRECT ~9.9, INCORRECT ~0.01),但在不同 LLM 生成的推理风格上分数整体偏低。建议: - 同题内做相对比较(选最高分路径),不依赖绝对阈值 - 或续训 3-5 epoch 提升泛化 ## 参考 - [DIVERSE: Towards Diverse and Effective Verifier-guided Reasoning](https://arxiv.org/abs/2410.09328) - [原始代码仓库](https://github.com/lz1oceani/diverse)