☰
使用 HANS 数据集对 NLI 模型进行对抗性评估:基于 Transformers run_hans.py 实战指南
2026/9/25 5:39:15 网站建设 项目流程
  • 推理引擎
  • 大模型

【免费下载链接】FlexGen

Running large language models on a single GPU for throughput-oriented scenarios.

项目地址:https://gitcode.com/gh_mirrors/fl/FlexGen
点击查看免费下载

导读

本文介绍如何基于 Hugging Face Transformers 生态,使用 HANS(Heuristic Analysis for NLI Systems)数据集对自然语言推理(NLI)模型进行对抗性评估。HANS 专门用于检测模型是否在依赖词汇重叠、子序列、句法成分等表层启发式线索,而非真正理解蕴含关系。读完本文,你将掌握完整的评估流水线:从获取 HANS 数据集、用 GLUE 脚本训练 NLI 模型,到运行run_hans.py生成预测文件、再通过 HANS 官方评分脚本按三类启发式分别统计 entailed / non-entailed 准确率,并能读懂示例结果揭示的模型脆弱性。本指南以仓库中的 README.md 为骨架,结合 run_hans.py 与 utils_hans.py 源码展开。

HANS:为什么需要对抗性评估

常规 GLUE 评测(如 MNLI 的 dev 集准确率)衡量的是模型在标准分布上的表现。然而,已有研究(McCoy et al., 2019,见 arXiv:1902.01007)指出,很多 NLI 模型"作弊":它们并非真正理解句子的蕴含关系,而是利用训练数据中的统计捷径。HANS 数据集正是为暴露这一缺陷而设计,它构造了三种启发式陷阱:

  • 词汇重叠(lexical overlap):前提与假设共享大量词汇,模型易误判为蕴含;
  • 子序列(subsequence):假设恰好是前提的连续子串,模型易直接判蕴含;
  • 句法成分(constituent):假设与前提的某个句法成分相同,模型易被误导。

HANS 对每种启发式同时提供entailed(真蕴含)与non-entailed(假蕴含)两类样例。若模型依赖启发式而非语义,其 non-entailed 准确率会远低于 entailed 准确率——这正是对抗性评估的核心诊断信号。本指南对应的示例由 Nafise Sadat Moosavi 提供,被收录于仓库的 research_projects 目录。

环境准备与依赖

运行评估脚本前需要安装 Transformers 及相关依赖。仓库中 requirements.txt 明确锁定transformers == 3.5.1。由于run_hans.py基于较老的 Trainer API(使用HfArgumentParser、TrainingArguments),建议在兼容该版本的 Python 3.6+ 环境中执行:

pip install transformers==3.5.1

此外脚本运行依赖torch、numpy、tqdm、filelock(用于缓存文件的跨进程锁),请一并安装:

pip install torch numpy tqdm filelock

获取 HANS 数据集

HANS 数据集由 Tom McCoy 提供,可从其官方仓库下载。下载解压后,目录中应包含以下两个核心文件:

  • heuristics_train_set.txt:训练集,带标签(run_hans.py支持do_train时使用);
  • heuristics_evaluation_set.txt:评估集,即对抗性评测所用数据。

从源码 utils_hans.py 可以看到,HansProcessor正是读取这两个文件构造样例:

def get_train_examples(self, data_dir): return self._create_examples(self._read_tsv(os.path.join(data_dir, "heuristics_train_set.txt")), "train") def get_dev_examples(self, data_dir): return self._create_examples(self._read_tsv(os.path.join(data_dir, "heuristics_evaluation_set.txt")), "dev")

因此,命令行中的--data_dir $HANS_DIR必须指向包含上述两个.txt文件的目录。

获取经过 NLI 训练的模型

HANS 评估针对的是已经过 NLI 任务训练的模型。README 建议使用run_glue.py在 MNLI 上训练模型(例如 BERT-base),训练产物即模型目录路径$MODEL_PATH。仓库中的 legacy/pytorch-lightning/run_glue.py 即为此类训练脚本的示例(使用glue_processors、glue_tasks_num_labels等 API 完成 GLUE 任务处理)。

模型目录需包含pytorch_model.bin(或 TF 权重)、config.json与词表文件,run_hans.py通过AutoConfig/AutoTokenizer/AutoModelForSequenceClassification加载。需要注意run_hans.py的版本差异:--model_name_or_path若指向含.ckpt的路径,源码会以from_tf=True加载 TF 权重(见 run_hans.py)。

运行对抗性评估:run_hans.py 完整指南

命令行参数

README 给出的核心命令如下:

export HANS_DIR=path-to-hans export MODEL_TYPE=type-of-the-model-e.g.-bert-roberta-xlnet-etc export MODEL_PATH=path-to-the-model-directory-that-is-trained-on-NLI-e.g.-by-using-run_glue.py python run_hans.py \ --task_name hans \ --model_type $MODEL_TYPE \ --do_eval \ --data_dir $HANS_DIR \ --model_name_or_path $MODEL_PATH \ --max_seq_length 128 \ --output_dir $MODEL_PATH

参数说明如下:

参数取值示例含义
--task_namehans任务名,必须为hans(源码hans_tasks_num_labels = {"hans": 3}仅注册了该任务)
--model_typebert/roberta/xlnet等模型类型,决定 tokenizer 行为
--do_eval无值触发评估模式,生成预测文件
--data_dirHANS 数据集目录需包含heuristics_evaluation_set.txt等文件
--model_name_or_path模型目录或 HF 模型 ID被评估的 NLI 模型
--max_seq_length128序列最大长度,超长截断、不足补齐
--output_dir模型目录预测结果输出位置

三类参数对象与可选参数

run_hans.py通过HfArgumentParser同时解析三组参数(见 run_hans.py):

  • ModelArguments:--config_name、--tokenizer_name、--cache_dir,用于指定与模型不同的配置/分词器或下载缓存位置;
  • DataTrainingArguments:--task_name、--data_dir、--max_seq_length(默认 128)、--overwrite_cache;
  • TrainingArguments(Transformers 内置):--do_train、--do_eval、--per_device_eval_batch_size、--seed、--local_rank(分布式)、--fp16、--overwrite_output_dir等。README 示例仅用默认 batch size 与 seed;若要复现示例结果,注意保持 seed 一致。

由于--output_dir同时是模型目录,且评估模式不触发"目录非空"校验(该校验仅在do_train时生效,见 run_hans.py),直接复用模型目录输出是安全的。

数据加载与特征化细节

评估数据由HansDataset加载(utils_hans.py),关键逻辑:

  • 缓存:特征会被缓存为cached_dev_<Tokenizer类名>_<max_seq_length>_hans文件,使用FileLock保证分布式下仅单进程构建、其余进程复用缓存;可用--overwrite_cache强制重建;
  • RoBERTa 标签修正:对 RoBERTa / XLM-R / BART 系列,源码会交换 label 1 与 label 2(# HACK(label indices are swapped in RoBERTa pretrained model),见 utils_hans.py);
  • 标签体系:HansProcessor.get_labels()返回["contradiction", "entailment", "neutral"],其中 HANS 评估将contradiction与neutral归并为 non-entailment(label 0),entailment为 label 1(见 utils_hans.py);
  • pairID 保留:TSV 中第 8 列是样例编号,前缀ex会被剥离并转为整数,作为预测结果与黄金标签对齐的键(见 utils_hans.py)。

预测输出与结果文件

评估完成后,trainer.predict(eval_dataset)得到 logits,经np.argmax(..., axis=1)取预测类别,随后写入$MODEL_PATH/hans_predictions.txt(见 run_hans.py),格式为:

pairID,gold_label ex1,entailment ex2,contradiction ...

随后使用 HANS 数据集官方提供的评分脚本hans/evaluate_heur_output.py(需从 HANS 仓库获取)对该文件进行评估,即:

python hans/evaluate_heur_output.py --output_dir $MODEL_PATH

或按该脚本的接口传入hans_predictions.txt路径与评估集路径。

示例结果解读:BERT-base 的脆弱性

README 给出了一个参考结果:使用 batch size 8、随机种子 42 在 MNLI 上训练的 BERT-base 模型,在 HANS 上的表现如下:

Heuristic entailed results: lexical_overlap: 0.9702 subsequence: 0.9942 constituent: 0.9962 Heuristic non-entailed results: lexical_overlap: 0.199 subsequence: 0.0396 constituent: 0.118

这是对抗性评估最有说服力的证据:

  • entailed 准确率极高(0.97~0.99):模型面对真蕴含样例时几乎全对,说明它非常擅长"找证据";
  • non-entailed 准确率极低(0.04~0.20):当样例满足启发式特征但语义上并不蕴含时,模型几乎全部误判为蕴含。

两者之间巨大的落差说明:该模型在 MNLI 上虽表现良好,却严重依赖表层启发式线索而非真正的语义推理,是典型的"表面线索投机者"。若你的模型在 HANS 上 non-entailed 准确率明显更高,说明其推理能力更稳健。需要强调的是,该结果是特定配置(batch size 8、seed 42)下的参考值,并非所有 BERT-base 模型的普适结论,不同训练配置会得到不同数字。

进阶扩展:结合评估脚本进行分布外诊断

run_hans.py还支持训练模式(--do_train),可在 HANS 训练集上继续微调并保存模型与 tokenizer(run_hans.py)。常见进阶用法包括:

  • 多模型对比:对 BERT、RoBERTa、XLNet 等不同架构分别运行run_hans.py --do_eval,对比各类启发式的 non-entailed 准确率,定位最稳健的架构;
  • 训练干预实验:在 NLI 训练中引入对抗样本、数据增强或去偏正则,再回到 HANS 验证改进效果;
  • 参数敏感性:调整--max_seq_length(默认 128,HANS 样例普遍较短,128 足够)、--per_device_eval_batch_size、--seed,观察结果稳定性;
  • 与 GLUE 指标对照:将 MNLI dev 准确率与 HANS 得分对照,展示"标准评测高分 ≠ 鲁棒推理"的差异。

小结

本文完整梳理了基于 HANS 的 NLI 对抗性评估流程:获取数据集 → 用run_glue.py训练 NLI 模型 → 运行run_hans.py --do_eval生成hans_predictions.txt→ 用 HANS 官方evaluate_heur_output.py按三类启发式统计 entailed / non-entailed 准确率。源码层面的关键实现(标签修正、pairID 对齐、缓存与多进程锁、RoBERTa 标签交换)均在 run_hans.py 与 utils_hans.py 中得到印证。对抗性评估是检验 NLI 模型真实推理能力、避免"高分低能"的重要工具,建议将其纳入模型发布的常规评测流程。

  • 推理引擎
  • 大模型

【免费下载链接】FlexGen

Running large language models on a single GPU for throughput-oriented scenarios.

项目地址:https://gitcode.com/gh_mirrors/fl/FlexGen
点击查看免费下载

相关推荐

上一篇:skrollr实现视差滚动的无障碍支持:ARIA属性应用
下一篇:Android视频缓存终极指南:深入解析缓存文件格式与数据结构

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询