Skip to content

Commit bc2df22

Browse files
committed
更新代码,与PaddleNLP(commit:b8e12c5a3)同步
1 parent 02989e3 commit bc2df22

8 files changed

+878
-257
lines changed

README.md

+161-63
Large diffs are not rendered by default.

convert.py

+51-1
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@
3333
from utils import logger
3434

3535
MODEL_MAP = {
36+
# vocab.txt/special_tokens_map.json/tokenizer_config.json are common to the default model.
3637
"uie-base": {
3738
"resource_file_urls": {
3839
"model_state.pdparams":
39-
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base_v0.1/model_state.pdparams",
40+
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base_v1.0/model_state.pdparams",
4041
"model_config.json":
4142
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base/model_config.json",
4243
"vocab_file":
@@ -117,6 +118,55 @@
117118
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base/tokenizer_config.json",
118119
}
119120
},
121+
"uie-base-en": {
122+
"resource_file_urls": {
123+
"model_state.pdparams":
124+
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base_en_v1.1/model_state.pdparams",
125+
"model_config.json":
126+
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base_en/model_config.json",
127+
"vocab_file":
128+
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base_en/vocab.txt",
129+
"special_tokens_map":
130+
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base_en/special_tokens_map.json",
131+
"tokenizer_config":
132+
"https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base_en/tokenizer_config.json",
133+
}
134+
},
135+
# uie-m模型需要Ernie-M模型
136+
# "uie-m-base": {
137+
# "resource_file_urls": {
138+
# "model_state.pdparams":
139+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_base_v1.0/model_state.pdparams",
140+
# "model_config.json":
141+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_base/model_config.json",
142+
# "vocab_file":
143+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_base/vocab.txt",
144+
# "special_tokens_map":
145+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_base/special_tokens_map.json",
146+
# "tokenizer_config":
147+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_base/tokenizer_config.json",
148+
# "sentencepiece_model_file":
149+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_base/sentencepiece.bpe.model"
150+
151+
# }
152+
# },
153+
# "uie-m-large": {
154+
# "resource_file_urls": {
155+
# "model_state.pdparams":
156+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_large_v1.0/model_state.pdparams",
157+
# "model_config.json":
158+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_large/model_config.json",
159+
# "vocab_file":
160+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_large/vocab.txt",
161+
# "special_tokens_map":
162+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_large/special_tokens_map.json",
163+
# "tokenizer_config":
164+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_large/tokenizer_config.json",
165+
# "sentencepiece_model_file":
166+
# "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_m_base/sentencepiece.bpe.model"
167+
# }
168+
# },
169+
# Rename to `uie-medium` and the name of `uie-tiny` will be deprecated in future.
120170
"uie-tiny": {
121171
"resource_file_urls": {
122172
"model_state.pdparams":

doccano.md

+92-7
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,15 @@ Relation类型标签构建示例:
105105

106106
示例中定义了`时间``选手``赛事名称``得分`四种Span类型标签。
107107

108+
```text
109+
schema = [
110+
'时间',
111+
'选手',
112+
'赛事名称',
113+
'得分'
114+
]
115+
```
116+
108117
#### 5.2 关系抽取
109118

110119
关系抽取(Relation Extraction,简称RE),是指从文本中识别实体并抽取实体之间的语义关系,即抽取三元组(实体一,关系类型,实体二)。
@@ -117,6 +126,18 @@ Relation类型标签构建示例:
117126

118127
示例中定义了`作品名``人物名``时间`三种Span类型标签,以及`歌手``发行时间``所属专辑`三种Relation标签。Relation标签**由Subject对应实体指向Object对应实体**
119128

129+
该标注示例对应的schema为:
130+
131+
```text
132+
schema = {
133+
'作品名': [
134+
'歌手',
135+
'发行时间',
136+
'所属专辑'
137+
]
138+
}
139+
```
140+
120141
#### 5.3 事件抽取
121142

122143
事件抽取 (Event Extraction, 简称EE),是指从自然语言文本中抽取事件并识别事件类型和事件论元的技术。UIE所包含的事件抽取任务,是指根据已知事件类型,抽取该事件所包含的事件论元。
@@ -129,6 +150,17 @@ Relation类型标签构建示例:
129150

130151
示例中定义了`地震触发词`(触发词)、`等级`(事件论元)和`时间`(事件论元)三种Span标签,以及`时间``震级`两种Relation标签。触发词标签**统一格式为`XX触发词`**`XX`表示具体事件类型,上例中的事件类型是`地震`,则对应触发词为`地震触发词`。Relation标签**由触发词指向对应的事件论元**
131152

153+
该标注示例对应的schema为:
154+
155+
```text
156+
schema = {
157+
'地震触发词': [
158+
'时间',
159+
'震级'
160+
]
161+
}
162+
```
163+
132164
#### 5.4 评价观点抽取
133165

134166
评论观点抽取,是指抽取文本中包含的评价维度、观点词。
@@ -141,7 +173,15 @@ Relation类型标签构建示例:
141173

142174
示例中定义了`评价维度``观点词`两种Span标签,以及`观点词`一种Relation标签。Relation标签**由评价维度指向观点词**
143175

144-
#### 5.5 分类任务
176+
该标注示例对应的schema为:
177+
178+
```text
179+
schema = {
180+
'评价维度': '观点词'
181+
}
182+
```
183+
184+
#### 5.5 句子级分类任务
145185

146186
标注示例:
147187

@@ -151,11 +191,38 @@ Relation类型标签构建示例:
151191

152192
示例中定义了`正向``负向`两种类别标签对文本的情感倾向进行分类。
153193

194+
该标注示例对应的schema为:
195+
196+
```text
197+
schema = '情感倾向[正向,负向]'
198+
```
199+
200+
#### 5.6 实体/评价维度级分类任务
201+
202+
<div align="center">
203+
<img src=https://user-images.githubusercontent.com/40840292/172628328-878923d7-8c5d-4667-a0e2-b92bce89b47c.png height=200 hspace='20'/>
204+
</div>
205+
206+
标注示例:
207+
208+
示例中定义了`评价维度##正向``评价维度##负向``观点词`三种Span标签以及`观点词`一种Relation标签。其中,`##`是实体类别/评价维度与分类标签的分隔符(可通过doccano.py中的separator参数自定义)。
209+
210+
该标注示例对应的schema为:
211+
212+
```text
213+
schema = {
214+
'评价维度': [
215+
'观点词',
216+
'情感倾向[正向,负向]'
217+
]
218+
}
219+
```
220+
154221
<a name="数据导出"></a>
155222

156223
## 6. 数据导出
157224

158-
#### 6.1 导出抽取式任务数据
225+
#### 6.1 导出抽取式和实体/评价维度级分类任务数据
159226

160227
选择导出的文件类型为``JSONL(relation)``,导出数据示例:
161228

@@ -226,7 +293,7 @@ Relation类型标签构建示例:
226293
- ``to_id``: Span2对应的标识ID。
227294
- ``type``: Relation类型。
228295

229-
#### 6.2 导出分类式任务数据
296+
#### 6.2 导出句子级分类任务数据
230297

231298
选择导出的文件类型为``JSONL``,导出数据示例:
232299

@@ -264,10 +331,10 @@ python doccano.py \
264331
--negative_ratio 5
265332
```
266333

267-
#### 7.2 分类式任务数据转换
334+
#### 7.2 句子级分类任务数据转换
268335

269336
- 当标注完成后,在 doccano 平台上导出 `JSON` 形式的文件,并将其重命名为 `doccano_cls.json` 后,放入 `./data` 目录下。
270-
- 在数据转换阶段,我们会自动构造用于模型训练需要的prompt信息。例如句子级情感分类中,prompt为``情感倾向[正向,负向]``,可以通过`prompt_prefix``options`参数进行声明。
337+
- 在数据转换阶段,我们会自动构造用于模型训练的prompt信息。例如句子级情感分类中,prompt为``情感倾向[正向,负向]``,可以通过`prompt_prefix``options`参数进行声明。
271338
- 通过 [doccano.py](./doccano.py) 脚本进行数据形式转换,然后便可以开始进行相应模型训练。
272339

273340
```shell
@@ -280,17 +347,35 @@ python doccano.py \
280347
--options "正向" "负向"
281348
```
282349

350+
#### 7.3 实体/评价维度级分类任务数据转换
351+
352+
- 当标注完成后,在 doccano 平台上导出 `JSONL(relation)` 形式的文件,并将其重命名为 `doccano_ext.json` 后,放入 `./data` 目录下。
353+
- 在数据转换阶段,我们会自动构造用于模型训练的prompt信息。例如评价维度级情感分类中,prompt为``XXX的情感倾向[正向,负向]``,可以通过`prompt_prefix``options`参数进行声明。
354+
- 通过 [doccano.py](./doccano.py) 脚本进行数据形式转换,然后便可以开始进行相应模型训练。
355+
356+
```shell
357+
python doccano.py \
358+
--doccano_file ./data/doccano_ext.json \
359+
--task_type "ext" \
360+
--save_dir ./data \
361+
--splits 0.8 0.1 0.1 \
362+
--prompt_prefix "情感倾向" \
363+
--options "正向" "负向" \
364+
--separator "##"
365+
```
366+
283367
可配置参数说明:
284368

285369
- ``doccano_file``: 从doccano导出的数据标注文件。
286370
- ``save_dir``: 训练数据的保存目录,默认存储在``data``目录下。
287371
- ``negative_ratio``: 最大负例比例,该参数只对抽取类型任务有效,适当构造负例可提升模型效果。负例数量和实际的标签数量有关,最大负例数量 = negative_ratio * 正例数量。该参数只对训练集有效,默认为5。为了保证评估指标的准确性,验证集和测试集默认构造全负例。
288372
- ``splits``: 划分数据集时训练集、验证集所占的比例。默认为[0.8, 0.1, 0.1]表示按照``8:1:1``的比例将数据划分为训练集、验证集和测试集。
289373
- ``task_type``: 选择任务类型,可选有抽取和分类两种类型的任务。
290-
- ``options``: 指定分类任务的类别标签,该参数只对分类类型任务有效。
291-
- ``prompt_prefix``: 声明分类任务的prompt前缀信息,该参数只对分类类型任务有效。
374+
- ``options``: 指定分类任务的类别标签,该参数只对分类类型任务有效。默认为["正向", "负向"]
375+
- ``prompt_prefix``: 声明分类任务的prompt前缀信息,该参数只对分类类型任务有效。默认为"情感倾向"。
292376
- ``is_shuffle``: 是否对数据集进行随机打散,默认为True。
293377
- ``seed``: 随机种子,默认为1000.
378+
- ``separator``: 实体类别/评价维度与分类标签的分隔符,该参数只对实体/评价维度级分类任务有效。默认为"##"。
294379

295380
备注:
296381
- 默认情况下 [doccano.py](./doccano.py) 脚本会按照比例将数据划分为 train/dev/test 数据集

doccano.py

+54-19
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# Copyright (c) 2022 Heiheiyoyo. All Rights Reserved.
1+
# coding=utf-8
2+
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
23
#
34
# Licensed under the Apache License, Version 2.0 (the "License");
45
# you may not use this file except in compliance with the License.
@@ -48,12 +49,16 @@ def _check_sum(splits):
4849
raw_examples = f.readlines()
4950

5051
def _create_ext_examples(examples,
51-
negative_ratio=0,
52+
negative_ratio,
53+
prompt_prefix="情感倾向",
54+
options=["正向", "负向"],
55+
separator="##",
5256
shuffle=False,
5357
is_train=True):
54-
entities, relations = convert_ext_examples(
55-
examples, negative_ratio, is_train=is_train)
56-
examples = entities + relations
58+
entities, relations, aspects = convert_ext_examples(
59+
examples, negative_ratio, prompt_prefix, options, separator,
60+
is_train)
61+
examples = entities + relations + aspects
5762
if shuffle:
5863
indexes = np.random.permutation(len(examples))
5964
examples = [examples[i] for i in indexes]
@@ -81,34 +86,62 @@ def _save_examples(save_dir, file_name, examples):
8186
if len(args.splits) == 0:
8287
if args.task_type == "ext":
8388
examples = _create_ext_examples(raw_examples, args.negative_ratio,
84-
args.is_shuffle)
89+
args.prompt_prefix, args.options,
90+
args.separator, args.is_shuffle)
8591
else:
8692
examples = _create_cls_examples(raw_examples, args.prompt_prefix,
8793
args.options, args.is_shuffle)
8894
_save_examples(args.save_dir, "train.txt", examples)
8995
else:
9096
if args.is_shuffle:
9197
indexes = np.random.permutation(len(raw_examples))
98+
index_list = indexes.tolist()
9299
raw_examples = [raw_examples[i] for i in indexes]
93100

94101
i1, i2, _ = args.splits
95102
p1 = int(len(raw_examples) * i1)
96103
p2 = int(len(raw_examples) * (i1 + i2))
97104

105+
train_ids = index_list[:p1]
106+
dev_ids = index_list[p1:p2]
107+
test_ids = index_list[p2:]
108+
109+
with open(os.path.join(args.save_dir, "sample_index.json"), "w") as fp:
110+
maps = {
111+
"train_ids": train_ids,
112+
"dev_ids": dev_ids,
113+
"test_ids": test_ids
114+
}
115+
fp.write(json.dumps(maps))
116+
98117
if args.task_type == "ext":
99-
train_examples = _create_ext_examples(
100-
raw_examples[:p1], args.negative_ratio, args.is_shuffle)
101-
dev_examples = _create_ext_examples(
102-
raw_examples[p1:p2], -1, is_train=False)
103-
test_examples = _create_ext_examples(
104-
raw_examples[p2:], -1, is_train=False)
118+
train_examples = _create_ext_examples(raw_examples[:p1],
119+
args.negative_ratio,
120+
args.prompt_prefix,
121+
args.options, args.separator,
122+
args.is_shuffle)
123+
dev_examples = _create_ext_examples(raw_examples[p1:p2],
124+
-1,
125+
args.prompt_prefix,
126+
args.options,
127+
args.separator,
128+
is_train=False)
129+
test_examples = _create_ext_examples(raw_examples[p2:],
130+
-1,
131+
args.prompt_prefix,
132+
args.options,
133+
args.separator,
134+
is_train=False)
105135
else:
106-
train_examples = _create_cls_examples(
107-
raw_examples[:p1], args.prompt_prefix, args.options)
108-
dev_examples = _create_cls_examples(
109-
raw_examples[p1:p2], args.prompt_prefix, args.options)
110-
test_examples = _create_cls_examples(
111-
raw_examples[p2:], args.prompt_prefix, args.options)
136+
train_examples = _create_cls_examples(raw_examples[:p1],
137+
args.prompt_prefix,
138+
args.options)
139+
dev_examples = _create_cls_examples(raw_examples[p1:p2],
140+
args.prompt_prefix,
141+
args.options)
142+
test_examples = _create_cls_examples(raw_examples[p2:],
143+
args.prompt_prefix,
144+
args.options)
112145

113146
_save_examples(args.save_dir, "train.txt", train_examples)
114147
_save_examples(args.save_dir, "dev.txt", dev_examples)
@@ -138,7 +171,9 @@ def _save_examples(save_dir, file_name, examples):
138171
parser.add_argument("--is_shuffle", default=True, type=bool,
139172
help="Whether to shuffle the labeled dataset, defaults to True.")
140173
parser.add_argument("--seed", type=int, default=1000,
141-
help="random seed for initialization")
174+
help="Random seed for initialization")
175+
parser.add_argument("--separator", type=str, default='##',
176+
help="Used only for entity/aspect-level classification task, separator for entity label and classification label")
142177

143178
args = parser.parse_args()
144179
# yapf: enable

0 commit comments

Comments
 (0)