中文序列标注任务(一)

简介:

记录使用中文语料,测试实践,序列标注任务,主要使用 huggingface 提供的一系列 数据加载库:datasets, 预训练模型等

1. 数据准备:

text1:中国#1实施 从明年起 将 实施|v 第九个 五年计划#2实施
text2:从明年起将实施第九个五年计划
label:B-S,B-I,O,O,O,O,O,B-V,I-V,O,O,O,B-O,I-O,I-O,I-O

这个任务跟只是跟命名实体识别类似,我的目标是要识别出句子中的标识出来的,主语,谓语和宾语,像 text1 标识出来的那样,将数据处理成 CSV 文件:
data

2. huggingface datasets库:

使用datasets读取数据集,huggingface 开源 了上百种公开的数据集,使用 datasets 库可以很方便的下载并且使用这些数据,下面记录官方教程以下载 conll2003 数据集为例:

  • 首先是加载包,然后下载数据集
from datasets import load_dataset, load_metric
datasets = load_dataset("conll2003")
print(datasets )
>>
DatasetDict({
    train: Dataset({
        features: ['id', 'tokens', 'pos_tags', 'chunk_tags', 'ner_tags'],
        num_rows: 14041
    })
    validation: Dataset({
        features: ['id', 'tokens', 'pos_tags', 'chunk_tags', 'ner_tags'],
        num_rows: 3250
    })
    test: Dataset({
        features: ['id', 'tokens', 'pos_tags', 'chunk_tags', 'ner_tags'],
        num_rows: 3453
    })
})

这里还可以指定读取多少:

datasets = load_dataset("conll2003",split="train[:100])
>>
Dataset({
    features: ['id', 'tokens', 'pos_tags', 'chunk_tags', 'ner_tags'],
    num_rows: 100
})
train_dataset = load_dataset('csv', encoding='utf-8',data_files=r'train.csv')
valid_dataset = load_dataset('csv', encoding='utf-8',data_files=r'valid.csv')
#通过以下的方式访问数据:
train_dataset 
train_dataset ['train']
train_dataset ['train'][0]
train_dataset['train']['text']
>>
DatasetDict({
    train: Dataset({
        features: ['id', 'text', 'ner_tags'],
        num_rows: 10000
    })
})
>>
Dataset({
    features: ['id', 'text', 'ner_tags'],
    num_rows: 10000
})
>>
{'id': 1, 'text': '本报讯记者周晓燕赴京参加中共十四届五中全会刚刚回到厦门的中共中央候补委员中共福建省委常委厦门市委书记石兆彬昨天在厦门市委召开的全市领导干部大会上传达了这次会议的主要精神', 'ner_tags': 'O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,B-V,I-V,O,O,O,O,O,O,O,O,B-O,I-O'}
>>

2. 准备模型

  • 导入 tokenizer,model,trainer 等
from transformers import AutoTokenizer   
import transformers
from transformers import AutoModelForTokenClassification, TrainingArguments, Trainer

tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
assert isinstance(tokenizer, transformers.PreTrainedTokenizerFast)#The assertion ensures that our tokenizer is a fast tokenizers

model_checkpoint="bert-base-chinese"
model = AutoModelForTokenClassification.from_pretrained(model_checkpoint, num_labels=len(label_list))#model_checkpoint = "distilbert-base-uncased"

-下面需要将 label 转换为 索引 Id 并且对应 经过 bert tokenizer 之后的词,因为有的词会切分成子词,这样的话需要把原本的 label 也对应到各个子词上:
其中有几个函数注意:

  • word_ids():
    经过了tokenizer()之后有的单词会被拆分成子单词,跟原来的lable等idx无法对应,通过函数word_ids()可以对应到每个单词(包括子单词)属于第几个单词,然后通过这个索引获得对应的label索引
  • label_all_tokens=ture/false:
    这是一个开关,有两种处理子词 对应label 的策略:
    true:表示特殊标记记作-100,其他则为其来自的单词id,无论子单词还是别的
    false:则处理成单词开头词为其单词id,子单词也为-100,这里特殊标记是指 bert 打上的 'CLS' 和 'SEP' 标记等
label_list=['O', 'B-V', 'I-V', 'B-O', 'I-O', 'B-S', 'I-S']
label_all_tokens = True
def tokenize_and_align_labels(examples):
    tokenized_inputs = tokenizer(examples["text"], truncation=True)
    labels = []
    for i, label in enumerate(examples[f"ner_tags"]):
        label=[label_list.index(item) for item in label.strip().split(',')]
        word_ids = tokenized_inputs.word_ids(batch_index=i)
        previous_word_idx = None
        label_ids = []
        for word_idx in word_ids:
            if word_idx is None:
                label_ids.append(-100)
            elif word_idx != previous_word_idx:
                label_ids.append(label[word_idx])
            else:
                label_ids.append(label[word_idx] if label_all_tokens else -100)
            previous_word_idx = word_idx
        labels.append(label_ids)
    tokenized_inputs["labels"] = labels
    return tokenized_inputs
  • 使用 datasets 的map 方法,这会把函数应用到数据集中所有需要处理的数据中,训练集,验证集,测试集等会在这一条命令中被处理:
  • 可以看到处理之后的数据集,features 字段增加了 "input_ids" ,"attention_mask","labels" 等新的数据结构
train_tokenized_datasets = train_dataset.map(tokenize_and_align_labels, batched=True)
valid_tokenized_datasets = valid_dataset.map(tokenize_and_align_labels, batched=True)
print(train_tokenized_datasets)
print(valid_tokenized_datasets)
>>
DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'id', 'input_ids', 'labels', 'ner_tags', 'text', 'token_type_ids'],
        num_rows: 10000
    })
})
DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'id', 'input_ids', 'labels', 'ner_tags', 'text', 'token_type_ids'],
        num_rows: 3000
    })
})

3. 开始训练,定义 TrainingArguments,trainer 等:

args = TrainingArguments(
    f"test-{task}",
    evaluation_strategy = "epoch",
    learning_rate=2e-5,
    per_device_train_batch_size=batch_size,# # batch size per device during training
    per_device_eval_batch_size=batch_size,## batch size for evaluation
    num_train_epochs=3,
    weight_decay=0.01,
)
from transformers import DataCollatorForTokenClassification
data_collator = DataCollatorForTokenClassification(tokenizer)
  • 关于 data_collator 的使用说明:

Then we will need a data collator that will batch our processed examples together while applying padding to make them all the same size (each pad will be padded to the length of its longest example). There is a data collator for this task in the Transformers library, that not only pads the inputs, but also the labels:

  • 定义度量 函数:
    测试使用:
metric = load_metric("seqeval")
labels = [ 'O', 'O', 'O', 'O', 'B-ORG', 'I-ORG', 'O', 'O', 'O', 'B-PER', 'I-PER']
metric.compute(predictions=[labels], references=[labels])
>>
{'LOC': {'precision': 1.0, 'recall': 1.0, 'f1': 1.0, 'number': 2},
 'ORG': {'precision': 1.0, 'recall': 1.0, 'f1': 1.0, 'number': 1},
 'PER': {'precision': 1.0, 'recall': 1.0, 'f1': 1.0, 'number': 1},
 'overall_precision': 1.0,
 'overall_recall': 1.0,
 'overall_f1': 1.0,
 'overall_accuracy': 1.0}
import numpy as np
def compute_metrics(p):
    predictions, labels = p
    predictions = np.argmax(predictions, axis=2)
    # Remove ignored index (special tokens)
    true_predictions = [
        [label_list[p] for (p, l) in zip(prediction, label) if l != -100]
        for prediction, label in zip(predictions, labels)
    ]
    true_labels = [
        [label_list[l] for (p, l) in zip(prediction, label) if l != -100]
        for prediction, label in zip(predictions, labels)
    ]
    results = metric.compute(predictions=true_predictions, references=true_labels)
    return {
        "precision": results["overall_precision"],
        "recall": results["overall_recall"],
        "f1": results["overall_f1"],
        "accuracy": results["overall_accuracy"],
    }
  • 定义 trainer:
print(train_tokenized_datasets)
print(valid_tokenized_datasets['train'])
trainer = Trainer(
    model,## the instantiated 🤗 Transformers model to be trained
    args,# # training arguments, defined above
    train_dataset=train_tokenized_datasets['train'],
    eval_dataset=valid_tokenized_datasets['train'],
    data_collator=data_collator,
    tokenizer=tokenizer,
    compute_metrics=compute_metrics
)
>>

  • 开始训练:
trainer.train()
  • 验证集测试:
trainer.evaluate()  

下面是一些实验记录,修改一些参数:
将全部长度padding 成 512(我的数据最长的是503左右):稍微

tokenized_inputs = tokenizer(examples["text"], padding='max_length')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容