DocRED 基线模型的 3 大特征工程:共指嵌入、NER 类型嵌入与距离嵌入详解
【免费下载链接】DocREDDataset and codes for ACL 2019 DocRED: A Large-Scale Document-Level Relation Extraction Dataset.项目地址: https://gitcode.com/gh_mirrors/do/DocRED
DocRED是 ACL 2019 发布的最大规模文档级关系抽取(Document-Level Relation Extraction)数据集与官方基线代码库。本文带你快速看懂 DocRED 基线模型中最核心的3 大特征工程:共指嵌入(Coreference Embedding)、NER 类型嵌入(Entity Type Embedding)与距离嵌入(Distance Embedding),理解它们如何帮助模型"读懂"实体之间的关系。
📚 一分钟认识 DocRED:它解决什么问题?
传统的关系抽取只关注"一句话里两个实体的关系",但现实文档中,实体关系往往跨越多个句子、多个同义表达。例如:
- 同一实体(如"鲁迅"与"周树人")在文中多次出现,模型需要知道它们是同一个东西;
- 两个实体可能相距甚远,模型需要感知它们的距离与方向;
- 实体本身有类别(人物、地点、组织等),类别信息对判断关系至关重要。
DocRED 正是针对这些难点构建的文档级关系抽取基准:标注了命名实体与关系,要求模型综合整个文档的多句话来推理实体间的关系。
官方基线模型位于
code/models/目录下,包括LSTM.py、BiLSTM.py、CNN3.py、ContextAware.py等,本文以最常用的LSTM / BiLSTM 基线为例讲解。
🚀 快速上手:获取 DocRED 基线代码
想动手体验?只需两步:
1️⃣ 克隆仓库并安装依赖:
git clone https://gitcode.com/gh_mirrors/do/DocRED pip3 install -r code/requirements.txt2️⃣ 准备数据:按code/README.md的说明将预处理数据放入code/prepro_data/目录,然后即可启动训练:
python3 train.py --model_name BiLSTM --save_name checkpoint_BiLSTM --train_prefix dev_train --test_prefix dev_dev安装与数据准备的完整步骤可参考 code/README.md,全局超参数则集中在code/config/Config.py中。
🧩 3 大特征工程一览表
DocRED 基线模型在词嵌入之外,额外拼接了 3 种手工设计的特征嵌入。它们都在code/config/Config.py中通过超参数控制:
| 特征 | 超参数 | 维度 | 作用 |
|---|---|---|---|
| 🎯 共指嵌入 | coref_size = 20 | 20 | 让模型区分"哪个 token 属于哪个实体" |
| 🏷️ NER 类型嵌入 | entity_type_size = 20 | 20 | 告诉模型实体的类别(人名、地名等) |
| 📏 距离嵌入 | dis_size = 20 | 20 | 编码头尾实体的距离与方向 |
三者最终与词嵌入一起拼接,送入 LSTM / BiLSTM 进行上下文建模(见code/models/BiLSTM.py)。
词嵌入 + 共指嵌入 + NER类型嵌入 → LSTM 编码 → 实体表示 → + 距离嵌入 → 双线性层 → 97 类关系下面逐一拆解。
🎯 特征一:共指嵌入(Coreference Embedding)——让模型"认出同一个实体"
为什么需要它?
文档中一个实体(Entity)往往由**多个提及(Mention)**组成。比如"苹果公司"、"苹果"、"该公司"可能都指代同一实体。如果只看词本身,模型根本不知道哪些词"打包"成了同一个实体。
实现思路
- 数据预处理阶段:
code/gen_data.py遍历文档中每个实体的所有提及,把该提及覆盖的每个 token 位置标记为所属实体的编号(从 1 开始),存为*_pos.npy矩阵; - 模型阶段:用一个 Embedding 层
nn.Embedding(max_length, coref_size, padding_idx=0)为每个"实体编号"生成20 维向量,与词向量拼接后一起输入 RNN。
也就是说:同一个实体下的所有 token,无论词面多不同,都会共享同一个共指向量——这就是"共指"信息的注入方式。
💡 相关实现在 code/models/LSTM.py 中的
coref_embed,预处理逻辑在 code/gen_data.py。
效果类比
这就像给文档中的每个实体发了一张工牌:词向量描述"这个词说什么",共指向量描述"这个词归哪个实体管"。
🏷️ 特征二:NER 类型嵌入(Entity Type Embedding)——告诉模型"它是谁"
为什么需要它?
关系抽取中,实体类型是强信号。例如:
- (人物,地点)→ 很可能触发"出生地"关系;
- (作品,人物)→ 很可能触发"作者"关系。
实现思路
- 数据预处理阶段:
code/gen_data.py将每个实体提及的 NER 类型(如 PERSON、LOCATION、ORGANIZATION 等)通过ner2id.json词表映射为编号,写入*_ner.npy; - 模型阶段:使用
nn.Embedding(7, entity_type_size, padding_idx=0),即7 类(1 个 padding + 6 种实体类型)各映射为 20 维向量,同样与词向量拼接输入 RNN。
💡 对应代码见 code/models/BiLSTM.py 中的
ner_emb;NER 类型与编号的映射来自数据目录中的ner2id.json。
为什么只有 7 类?
DocRED 的实体类型体系比较精简(6 类 + 1 个 padding),因此嵌入表只有 7 行。这体现了特征工程的一个原则:类别空间小、语义明确的信号,用小而精的嵌入表就够了。
📏 特征三:距离嵌入(Distance Embedding)——把距离"量化"成 9 档
为什么需要它?
两个实体的距离直接影响关系概率:
- 相距 1 个词(如"作者-作品"紧密搭配)与相距 200 个词(跨段落推理)是完全不同的推理难度;
- 而且方向也有意义:头实体在尾实体之前还是之后,往往暗示不同的语义模式。
实现思路:两级量化
距离嵌入是整个基线中最巧妙的部分,分两步走:
第一步:距离分桶(在code/config/Config.py中定义)
原始距离(可能高达数百)太大,直接嵌入会浪费参数。基线用dis2idx映射表把距离对数式地量化为 9 档:
| 原始距离 | 量化档位 | 原始距离 | 量化档位 |
|---|---|---|---|
| 1 | 1 | 32 ~ 63 | 6 |
| 2 | 2 | 64 ~ 127 | 7 |
| 3 ~ 4 | 3 | 128 ~ 255 | 8 |
| 5 ~ 7 | 4 | ≥ 256 | 9 |
| 8 ~ 15 | 5 |
第二步:方向编码 + 嵌入查表
在code/config/Config.py的 batch 构建中,先计算带符号距离(头实体在前为正、在后为负),再统一+10 偏移,得到 1~19 的桶编号(10 表示"零距离"并作为 padding)。最后用nn.Embedding(20, dis_size, padding_idx=10)查出 20 维向量。
也就是说,1 个 20 维向量同时编码了"距离有多远 + 方向是谁先出现"两个维度的信息。
距离嵌入怎么用?
注意一个细节:距离嵌入不进入 RNN,而是在实体表示(头实体、尾实体各自做加权平均池化)得到之后,才拼接进双线性层(Bilinear):
- 头实体表示 ⊕ 头→尾距离向量
- 尾实体表示 ⊕ 尾→头距离向量
两路拼接后再送入nn.Bilinear输出97 类关系(96 种关系 + 1 种无关系)。这个"实体交互 + 距离感知"的打分结构,是文档级关系抽取基线的经典范式。
🔗 三大特征如何协同:一条完整的特征流水线
把三个特征串起来,DocRED 基线模型的完整数据流如下:
| 阶段 | 做什么 | 关键位置 |
|---|---|---|
| ① 预处理 | 生成 word / pos(共指)/ ner / char 四个矩阵 | code/gen_data.py |
| ② 输入拼接 | 词向量 + 共指向量 + NER 向量(每个 token 三路拼接) | code/models/LSTM.py |
| ③ 上下文编码 | 单向/双向 LSTM(hidden = 128,词嵌入冻结不训练) | code/models/BiLSTM.py |
| ④ 实体表示 | 用实体内 token 的加权平均池化出头/尾实体向量 | h_mapping/t_mapping |
| ⑤ 距离打分 | 实体向量拼接距离嵌入 → 双线性层 → 97 类关系概率 | code/config/Config.py |
几个值得新手记住的设计点:
- ✂️词嵌入是冻结的(
requires_grad = False),模型完全依赖上下文网络和特征嵌入来适应任务,这大大降低了过拟合风险; - 🧮实体表示是平均池化而非取单个 token,天然兼容"同一实体多个提及"的文档级场景;
- ⚖️所有特征维度都很小(各 20 维),手工特征轻、信息密度高,正是 2019 年深度模型之外特征工程价值的典型体现。
✅ 总结:从 DocRED 学到 3 个通用经验
- 实体边界特征(共指嵌入):凡是文档级任务,"哪些词属于同一实体"都是必备信号;
- 类型先验特征(NER 嵌入):类别信号小而强,用紧凑嵌入表注入即可;
- 距离量化特征(距离嵌入):连续大数值先分桶再嵌入,是处理"位置/距离"类特征的通用技巧。
掌握这 3 大特征工程,你就理解了 DocRED 官方基线的"骨架"。想要深入实验,可以从code/train.py与code/test.py入手,对照code/models/下的多个模型实现(LSTM、BiLSTM、CNN3、ContextAware),观察每种结构在特征使用上的差异——例如ContextAware在距离打分之上还叠加了自注意力,思路一脉相承。
祝你在 DocRED 上玩得开心!🎉
【免费下载链接】DocREDDataset and codes for ACL 2019 DocRED: A Large-Scale Document-Level Relation Extraction Dataset.项目地址: https://gitcode.com/gh_mirrors/do/DocRED
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考