第 8 节 / 共 10 节

第8章 预训练模型微调实战(day11-12)

🎯 使用 transformers 完成 BERT 下游任务微调完整流程。
📖 笔记

NLP 基础(day11-12)

NLP基础

【了解】今日内容介绍

  • fasttext工具介绍
  • fasttext文本分类
  • fasttext词向量迁移
  • 迁移学习
  • Transformers库的使用

【掌握】fasttext工具介绍

简介

fasttext是自然语言处理(NLP)任务的开源工具包,由Facebook AI Research(FAIR)开发。

它被广泛用于各种任务,包括情感分析、文本分类、命名实体识别、机器翻译等

主要作用

  • 文本分类
  • 训练词向量

优势

正如其名,在保持较高精度的情况下,快速的进行训练和预测是fasttext的最大优势。

原因:

  • fasttext工具包中内含的fasttext模型,模型结构简单

  • 使用fasttext模型训练词向量时,使用层次softmax结构, 来提升超多类别下的模型性能

  • 采用负采样(negative sampling),每次训练仅仅更新一小部分的权重, 降低梯度下降过程中的计算量

  • fasttext模型过于简单无法捕捉词序特征, 可采用n-gram特征提取文本特征以弥补模型缺陷提升精度

安装

# pip安装
pip install fasttext-wheel -i https://mirrors.aliyun.com/pypi/simple/

# 如果安装失败,则执行如下命令,文件见day01资料文件夹
pip install fasttext_wheel-0.9.2-cp38-cp38-win_amd64.whl

注意事项:

一定要明确Python环境,避免导致安装后失效的情况。

模型架构

FastText 模型架构和 Word2Vec 中的 CBOW 模型很类似。不同之处在于FastText是预测标签,而 CBOW 模型预测中间词。

fasttext是由3层组成:

  • 输入层:是对文档embedding之后的向量, 包含N-gram特征

  • 隐藏层:是对输入数据的求和平均

  • 输出层:是文档对应的label

如下图所示:

1752767199452

层次softmax

计算超多类别分类时,为了提高效率,不再使用传统的softmax来进行多分类的计算,可使用哈夫曼树,使用层次化的softmax来进行概率的计算。

普通softmax:求每个单词的概率分布。如下图:

1752767335592

层次softmax:求每个单词的概率分布转化为求单词路径的概率乘积。如下图:

1752767352624

霍夫曼树作用:用来构建带权最小二叉树。霍夫曼树,也称哈夫曼树、最优二叉树,因为:huffman

霍夫曼树目的:完成哈夫曼编码,哈夫曼编码是一种变长、极少多余编码方案。

说明如下:

带权路径长度WPL(weighted path length):
左图的叶子节点为: 3,5,7,9
左图的wpl计算:3*3 + 5*3 + 7*2 + 9*1 = 47  
WPL最小的二叉树就是赫夫曼树

如下图:

1752767765091

哈夫曼树如何构建?

  • 第一步:假设有四个Label分别为:A~D。统计其在语料库出现的频数。

1752767680922

  • 第二步:第一次合并建树

1752767686392

  • 第三步:第二次合并建树

1752767691895

  • 第四步:第三次合并建树

1752767697111

负采样

为什么需要负采样?

  • 神经网络经过一个训练样本的训练,它的权重就会进行一次调整。

  • 比如利用Skip-Gram进行词向量训练:如果词汇量的数量为上万个,利用softmax计算概率时,需要计算上万个概率值,且每个值都需要进行反向传播更新模型参数,这是非常消耗计算资源的,并且实际中训练起来会非常慢。

  • 负采样每次让一个训练样本仅仅更新一小部分的权重,这样就会降低梯度下降的计算量。

负采样的优势?

  • 提高训练速度,选择了部分数据计算损失,损失计算更加简单。

  • 改进效果,增加部分负样本,能够模拟真实场景下的噪声情况,能够让模型的稳健性更强。

扩展阅读:

# 概念名词解释
下采样/降采样:一堆样本100个,采10个。
上采样/升采样:一堆样本100个,采200个。
负采样:通过随机选择负样本,来减少softmax的计算量。

# 作用
下/降采样:数据预处理技术,用于减少数据量。
上/升采样:数据预处理技术,用于增加数据量。
负采样:模型优化技术。用于提升训练效率。

【掌握】fasttext文本分类

概述

文本分类的是将文档(例如电子邮件,帖子,文本消息,产品评论等)分配给一个或多个类别。

训练文本分类模型需要是有监督学习,需要标签。

分类

  • 二分类:文本被分类两个类别,往往这两个类别是对立面。比如: 判断一句评论是好评还是差评。

  • 单标签多分类:文本可被分成多个类别中的一个类别(即被打上某一个标签)。比如:输入一个人名, 判断它是来自哪个国家的人名。

  • 多标签多分类:文本可被分成多个类别中的一多类别(即被打上多个个标签)。比如: 输入一段讨论,话题可以美食、体育新闻、游戏。

步骤

第一步: 获取数据
第二步: 训练集与验证集的划分
第三步: 训练模型
第四步: 使用模型进行预测并评估
第五步: 模型调优
第六步: 模型保存与重加载

获取数据

案例:本案例烹饪相关的数据集, 它是由facebook AI实验室提供的演示数据集。

数据:

__label__sauce __label__cheese How much does potato starch affect a cheese sauce recipe?
__label__food-safety __label__acidity Dangerous pathogens capable of growing in acidic environments
__label__cast-iron __label__stove How do I cover up the white spots on my cast iron stove?
__label__restaurant Michelin Three Star Restaurant; but if the chef is not there
__label__knife-skills __label__dicing Without knife skills, how can I quickly and accurately dice vegetables?
__label__storage-method __label__equipment __label__bread What's the purpose of a bread box?
__label__baking __label__food-safety __label__substitutions __label__peanuts how to seperate peanut oil from roasted peanuts at home?
__label__chocolate American equivalent for British chocolate terms
__label__baking __label__oven __label__convection Fan bake vs bake
__label__sauce __label__storage-lifetime __label__acidity __label__mayonnaise Regulation and balancing of readymade packed mayonnaise and other sauces

数据说明:

fasttext工具数据格式:__label__AAA__label__BBB text1text1text1

多标签多分类问题

训练集与验证集划分

# 12404条数据作为训练数据
head -n 12404 cooking.stackexchange.txt > cooking_train.txt

# 3000条数据作为验证数据
tail -n 3000 cooking.stackexchange.txt > cooking_valid.txt

训练模型

# 导入fasttext
import fasttext

# 使用fasttext的train_supervised方法进行文本分类模型的训练
model = fasttext.train_supervised("../data/cooking_train.txt")

预测和评估

# 使用模型预测一段输入文本, 通过我们常识, 可知预测是正确的, 但是对应预测概率并不大
model.predict("Which baking dish is best to bake a banana bread ?")

# 元组中的第一项代表标签, 第二项代表对应的概率
(('__label__baking',), array([0.06550845]))


# 为了评估模型到底表现如何, 我们在3000条的验证集上进行测试
model.test("data/cooking/cooking_valid.txt")

# 元组中的每项分别代表, 验证集样本数量, 精度以及召回率 
(3000, 0.124, 0.0541)

模型调优

  • 数据方面:重新处理数据
# 使标点符号与单词分离并统一使用小写字母
cat cooking.stackexchange.txt | sed -e "s/\([.\!?,'/()]\)/ \1 /g" | tr "[:upper:]" "[:lower:]" > cooking.preprocessed.txt

# 划分数据集
head -n 12404 cooking.preprocessed.txt > cooking.pre.train
tail -n 3000 cooking.preprocessed.txt > cooking.pre.valid

重新进行模型训练:

model = fasttext.train_supervised(input="data/cooking/cooking.pre.train")

model.test("data/cooking/cooking.pre.valid")
# 我们看到精度和召回率都有所提升
(3000, 0.161, 0.06962663975782038)
  • 增加训练轮数
model = fasttext.train_supervised(input="data/cooking/cooking.pre.train", epoch=25)

model.test("data/cooking/cooking.pre.valid")
  • 调整学习率
model = fasttext.train_supervised(input="data/cooking/cooking.pre.train", epoch=25, lr=1.0)

model.test("data/cooking/cooking.pre.valid")
  • 增加n-gram特征
model = fasttext.train_supervised(input="data/cooking/cooking.pre.train", epoch=25, lr=1.0, wordNgrams=2)

model.test("data/cooking/cooking.pre.valid")
  • 修改损失计算方式
model = fasttext.train_supervised(input="data/cooking/cooking.pre.train", epoch=25, lr=1.0, wordNgrams=2, loss='hs')

model.test("data/cooking/cooking.pre.valid")
  • 自动超参数调优
model = fasttext.train_supervised(input="data/cooking/cooking.pre.train", autotuneValidationFile='data/cooking/cooking.pre.valid', autotuneDuration=600)

model.test("data/cooking/cooking.pre.valid")
  • 实际生产中多标签多分类问题的损失计算方式
model = fasttext.train_supervised(input="data/cooking/cooking.pre.train", epoch=25, lr=1.0, wordNgrams=2, loss='ova')

# 参数k代表指定模型输出多少个标签, 默认为1, 这里设置为-1, 意味着尽可能多的输出.
# 参数threshold代表显示的标签概率阈值, 设置为0.5, 意味着显示概率大于0.5的标签
model.predict("Which baking dish is best to bake a banana bread ?", k=-1, threshold=0.5)

模型保存和加载

# 使用model的save_model方法保存模型到指定目录
model.save_model("data/model/model_cooking.bin")

# 使用fasttext的load_model进行模型的重加载
model = fasttext.load_model("data/model/model_cooking.bin")

# 重加载后的模型使用方法和之前完全相同
model.predict("Which baking dish is best to bake a banana bread ?", k=-1, threshold=0.5)
((u'__label__baking', u'__label__bananas', u'__label__bread'), array([1.00000, 0.939923, 0.592677]))

【掌握】fasttext词向量迁移

概述

使用在大型语料库上已经进行训练完成的词向量模型。

也就是说,已经存在的、已经训练好的词向量,拿过来直接用。

fasttext提供的可迁移的词向量

#1.
fasttext提供了157种语言的在CommonCrawl和Wikipedia语料上进行训练的可迁移词向量模型, 它们采用CBOW模式进行训练, 词向量维度为300维. 可通过该地址查看具体语言词向量模型: https://fasttext.cc/docs/en/crawl-vectors.html

#2.
fasttext提供了294种语言的在Wikipedia语料上进行训练的可迁移词向量模型, 它们采用skipgram模式进行训练, 词向量维度同样是300维. 可通过该地址查看具体语言词向量模型: https://fasttext.cc/docs/en/pretrained-vectors.html

案例

#1.下载词向量模型文件

#2.解压文件

#3.加载bin文件获取词向量

#4.利用邻近词进行效果检验

实现

#1.下载词向量模型压缩的bin.gz文件
wget https://dl.fbaipublicfiles.com/fasttext/vectors-crawl/cc.zh.300.bin.gz

#2.解压bin.gz文件到bin文件
gunzip cc.zh.300.bin.gz

# 3.加载模型
model = fasttext.load_model("cc.zh.300.bin")

# 4.获取词向量
model.get_word_vector("音乐")
# 获取邻近词
model.get_nearest_neighbors("音乐")

【了解】迁移学习

概念

把预训练模型中已经学习知识迁移到另外一个地方,形象比喻成迁移学习。

迁移方式

方式一:直接使用预训练模型,也就是开箱即用。比如fasttext工具包。

方式二:微调预训练模型。

名词介绍

预训练模型

  • 一般情况下预训练模型都是大型模型。

特点:网络复杂,参数多,需要大量的数据进行训练

  • 在NLP领域,预训练模型往往是语言模型。

因语言模型的训练是无监督的,可以获得大规模语料。比如:输入一句话,生成下一个单词、或者句子,这就是语言模型。比如:打字软件是一个AI程序,是一个语言模型。

  • 语言模型又是许多典型NLP任务的基础,如机器翻译,文本生成,阅读理解等。

常见预训练模型BERT, GPT, roBERTa, transformer-XL

微调

  • 微调的对象
  • 预训练模型

  • 微调的方式:

  • 1.微调预训练模型的参数
  • 2.增加1层或2层输出结构再用小批量标准数据进行重新训练

  • 微调的目标

  • 让模型更加适应特性任务

说白了,就是下载一个预训练模型比如bert,再用自己的小数据重新训练一下,这个动作就是微调。

【掌握】NLP常见预训练模型

常见预训练模型可以分为三类:

  • 自编码语言模型(Auto Encoder Language Model,简称AE)

主要用来进行文本理解;比如: 阅读理解,完型填空,提取句子特征做分类。

代表模型:BERT。

  • 自回归语言模型(Auto Regressive Language Model ,简称AR)

主要用来进行文本生成,比如:文本摘要、翻译、文本写作。

代表模型:GPT。

  • Seq2Seq混合模型(Sequence-to-Sequence,就是AR+AR)

主要用来做综合任务,比如:摘要、翻译、看图说话。

代表模型:T5。

【实现】Transformers库的使用

了解Transformers库

Transformers是HuggingFace公司开源的、基于 transformer 模型结构的,提供预训练语言库。

HuggingFace的开源社区,尤其是在github上开源的预训练模型库Transformers已成为工业风向标。

HuggingFace网址:https://huggingface.co/

魔搭网址:https://www.modelscope.cn/

如果环境中没有transformers库,则需要安装:

# transformers库的安装命令
pip install transformers -i https://pypi.tuna.tsinghua.edu.cn/simple
或者
pip install transformers-4.46.3-py3-none-any.whl

# 额外安装一个datasets库
pip install datasets -i https://pypi.tuna.tsinghua.edu.cn/simple

说明:

transformers-4.46.3-py3-none-any.whl文件在今日资料目录下。

Transformers库三层应用结构

  • 管道(Pipline)方式:高度集成的极简使用方式,只需要几行代码即可实现一个NLP任务。
  • 自动模型(AutoMode)方式:可载入并使用BERTology系列模型。
  • 具体模型(SpecificModel)方式:在使用时,需要明确指定具体的模型,并按照每个BERTology系列模型中的特定参数进行调用,该方式相对复杂,但具有较高的灵活度。

管道方式

文本分类任务

文本分类是指模型可以根据文本中的内容来进行分类。

import numpy as np
from transformers import pipeline

# 1.文本分类任务
def text_classification():
    # 定义模型
    model = pipeline(task="text-classification", model="../model/chinese_sentiment")
    # 直接预测
    output = model(inputs="我爱北京天安门,天安门上太阳升。")
    # 数出结果
    print('output-->', output)


if __name__ == '__main__':
    text_classification()

特征提取任务

特征抽取任务只返回文本处理后的特征,属于预训练模型的范畴。特征抽取任务的输出结果需要和其他模型一起工作。

# 2.特征提取任务
def feature_extraction():
    # 定义模型
    model = pipeline(task="feature-extraction", model="../model/bert-base-chinese")
    # 直接预测
    output = model(inputs="人生该如何起头")
    # 数出结果
    print('output-->', np.array(output).shape)


if __name__ == '__main__':
    # text_classification()
    feature_extraction()

完形填空任务

完型填空任务又被叫做“遮蔽语言建模任务”,它属于BERT模型训练过程中的子任务。

# 3.完形填空任务
def fill_mask():
    # 定义模型
    model = pipeline(task="fill-mask", model="../model/chinese-bert-wwm")
    # 直接预测
    output = model("我想明天去[MASK]家吃饭.")
    print('output-->', output)


if __name__ == '__main__':
    # text_classification()
    # feature_extraction()
    fill_mask()

阅读理解任务

阅读理解任务又称为“抽取式问答任务”,即输入一段文本和一个问题,让模型输出结果。

# 4.阅读理解任务
def question_answer():
    context = '我叫张三,我是一个程序员,我的喜好是打篮球。'
    questions = ['我是谁?', '我是做什么的?', '我的爱好是什么?']
    model = pipeline(task="question-answering", model="../model/chinese_pretrain_mrc_roberta_wwm_ext_large")
    output = model(context=context, question=questions)
    print('output-->', output)


if __name__ == '__main__':
    # text_classification()
    # feature_extraction()
    # fill_mask()
    question_answer()

文本摘要任务

文本摘要,就是输入一段文本,输出是一段概况、简单的文字。说白了,就是对一段话进行总结。

# 5.文本摘要任务
def summarization():
    text = "BERT is a transformers model pretrained on a large corpus of English data " \
           "in a self-supervised fashion. This means it was pretrained on the raw texts " \
           "only, with no humans labelling them in any way (which is why it can use lots " \
           "of publicly available data) with an automatic process to generate inputs and " \
           "labels from those texts. More precisely, it was pretrained with two objectives:Masked " \
           "language modeling (MLM): taking a sentence, the model randomly masks 15% of the " \
           "words in the input then run the entire masked sentence through the model and has " \
           "to predict the masked words. This is different from traditional recurrent neural " \
           "networks (RNNs) that usually see the words one after the other, or from autoregressive " \
           "models like GPT which internally mask the future tokens. It allows the model to learn " \
           "a bidirectional representation of the sentence.Next sentence prediction (NSP): the models" \
           " concatenates two masked sentences as inputs during pretraining. Sometimes they correspond to " \
           "sentences that were next to each other in the original text, sometimes not. The model then " \
           "has to predict if the two sentences were following each other or not."
    model = pipeline(task="summarization", model="../model/distilbart-cnn-12-6")
    output = model(text)
    print("output-->", output)


if __name__ == '__main__':
    # text_classification()
    # feature_extraction()
    # fill_mask()
    # question_answer()
    summarization()

NER任务

命名实体识别(NER)任务是NLP中的基础任务。它用于识别文本中的人名(PER)、地名(LOC)、组织(ORG)以及其他实体(MISC)等。例如:(王 B-PER) (小 I-PER) (明 I-PER) (在 O) (办 B-LOC) (公 I-LOC) (室 I-LOC)。其中O表示一个非实体,B表示一个实体的开始,I表示一个实体块的内部。

命名实体识别本质上是一个分类任务(又叫序列标注任务),命名实体识别是句法分析的基础,而句法分析又是NLP任务的核心。

# 6.NER任务
def ner():
    model = pipeline(task="token-classification", model="../model/roberta-base-finetuned-cluener2020-chinese")
    output = model("我爱北京天安门,天安门上太阳升")
    print("output-->", output)


if __name__ == '__main__':
    # text_classification()
    # feature_extraction()
    # fill_mask()
    # question_answer()
    # summarization()
    ner()

自动模型方式

文本分类任务

文本分类是指模型可以根据文本中的内容来进行分类。

# 1.文本分类任务
def text_classification():
    # 1.加载tokenizer
    my_tokenizer = AutoTokenizer.from_pretrained("../model/chinese_sentiment")
    print('my_tokenizer-->', my_tokenizer)

    # 2.加载模型
    model = AutoModelForSequenceClassification.from_pretrained("../model/chinese_sentiment")
    print("model-->", model)

    # 3.准备句子
    message = "人生该如何起头"

    # 4.对句子进行编码
    # padding:True/longest,则表示以最长的句子打padding,max_length,表示以max_length的长度打padding
    msg_encode = my_tokenizer.encode(text=message, padding='longest', truncation=True, max_length=20, return_tensors='pt')
    print("msg_encode-->", msg_encode, msg_encode.shape)

    # 5.传入模型进行预测
    model.eval()
    output = model(msg_encode)
    print("output-->", output)


if __name__ == '__main__':
    text_classification()

特征提取任务

特征抽取任务只返回文本处理后的特征,属于预训练模型的范畴。特征抽取任务的输出结果需要和其他模型一起工作。

# 2.特征提取任务
def feature_extraction():
    # 1.加载tokenizer
    my_tokenizer = AutoTokenizer.from_pretrained("../model/bert-base-chinese")
    print("my_tokenizer-->", my_tokenizer)

    # 2.加载模型
    model = AutoModel.from_pretrained("../model/bert-base-chinese")
    print("model-->", model)

    # 3.准备句子
    message = ["人生该如何起头","你是谁"]

    # 4.对句子进行编码
    # encode_plus:更加强大的编码方式
    output1 = my_tokenizer.encode_plus(text=message, padding="max_length", truncation=True, return_tensors='pt', max_length=30)
    # input_ids:根据词表,用于将词表转为id,起始为101,分隔符为102
    # token_type_ids:标识不同的句子,用0标识第一个句子,用1表示第二个句子
    # attention_mask:把padding的位置标识为0,非padding的位置标识为1
    print('output1-->', output1)


    # 5.传入模型进行预测
    model.eval()
    output = model(**output1)
    # token级别的词向量
    print("output-->", output.last_hidden_state.shape) # [1, 30, 768]
    # 从[1,30,768]中拿出 CLS[1,768],经过linear层(768,768),不改变维度,得到[1,768],这个数据就代表整个句子,也称为句向量。
    print("output-->", output.pooler_output.shape) # [1, 768]


if __name__ == '__main__':
    # text_classification()
    feature_extraction()

完形填空任务

完型填空任务又被叫做“遮蔽语言建模任务”,它属于BERT模型训练过程中的子任务。

# 3.完形填空任务
def fill_mask():
    #1.加载分词器
    tokenizer = AutoTokenizer.from_pretrained("../model/chinese-bert-wwm")
    print("tokenizer-->", tokenizer)

    #2.加载模型
    model = AutoModelForMaskedLM.from_pretrained("../model/chinese-bert-wwm")
    print("model-->", model)

    #3.准备语句
    message = "我今天中午准备去[MASK]家吃饭"

    #4.对句子进行编码
    input = tokenizer.encode_plus(message, return_tensors='pt')
    print('output1-->', input)

    #5.送入模型
    model.eval()
    output = model(**input)
    print('output-->', output.logits.shape) # [1, 14, 21128]

    # 一定要item(),把数据取出来,logits就是预测结果。
    index = torch.argmax(output.logits[0][9]).item()
    print("mask_pred_idx-->", index)

    res = tokenizer.convert_ids_to_tokens(index)
    print("res-->", res)


if __name__ == '__main__':
    # text_classification()
    # feature_extraction()
    fill_mask()

阅读理解任务

阅读理解任务又称为“抽取式问答任务”,即输入一段文本和一个问题,让模型输出结果。

# 4.阅读理解任务
def reading():
    #1.加载分词器
    tokenizer = AutoTokenizer.from_pretrained("../model/chinese_pretrain_mrc_roberta_wwm_ext_large")
    #2.加载模型
    model = AutoModelForQuestionAnswering.from_pretrained("../model/chinese_pretrain_mrc_roberta_wwm_ext_large")
    #3.准备语句,并且编码
    context = '我叫张三,我是一个程序员,我的喜好是打篮球'
    questions = ['我是谁', '我是做什么的', '我的爱好是什么']
    #4.模型预测
    model.eval()
    for question in questions:
        input = tokenizer.encode_plus(question, context,  return_tensors='pt')
        print("input-->", input)
        output = model(**input)
        print("output-->", output)
        # 获取开始和结束的logits
        start = torch.argmax(output.start_logits, dim=-1)
        end = torch.argmax(output.end_logits, dim=-1)
        print("start-->", start)
        print("end-->", end)
        # 把logits转换为汉字
        answer = tokenizer.convert_ids_to_tokens(input["input_ids"][0][start: end + 1])
        print("question-->", question)
        print("answer-->", answer)


if __name__ == '__main__':
    # text_classification()
    # feature_extraction()
    # fill_mask()
    reading()

文本摘要任务

文本摘要,就是输入一段文本,输出是一段概况、简单的文字。说白了,就是对一段话进行总结。

# 5.文本摘要任务
def summarization():
    #1.加载分词器
    tokenizer = AutoTokenizer.from_pretrained("../model/distilbart-cnn-12-6")
    #2.加载模型
    model = AutoModelForSeq2SeqLM.from_pretrained("../model/distilbart-cnn-12-6")
    #3.准备语句,编码
    text = "BERT is a transformers model pretrained on a large corpus of English data " \
           "in a self-supervised fashion. This means it was pretrained on the raw texts " \
           "only, with no humans labelling them in any way (which is why it can use lots " \
           "of publicly available data) with an automatic process to generate inputs and " \
           "labels from those texts. More precisely, it was pretrained with two objectives:Masked " \
           "language modeling (MLM): taking a sentence, the model randomly masks 15% of the " \
           "words in the input then run the entire masked sentence through the model and has " \
           "to predict the masked words. This is different from traditional recurrent neural " \
           "networks (RNNs) that usually see the words one after the other, or from autoregressive " \
           "models like GPT which internally mask the future tokens. It allows the model to learn " \
           "a bidirectional representation of the sentence.Next sentence prediction (NSP): the models" \
           " concatenates two masked sentences as inputs during pretraining. Sometimes they correspond to " \
           "sentences that were next to each other in the original text, sometimes not. The model then " \
           "has to predict if the two sentences were following each other or not."

    inputs = tokenizer.encode_plus(text, return_tensors="pt")
    #4.送入模型,进行摘要生成
    model.eval()
    output = model.generate(inputs["input_ids"])
    # [1, 84]:表示生成了一段话,这段话有84个token
    print('output-->', output, output.shape)
    #5.解码
    res = tokenizer.decode(output[0], skip_special_tokens=True, clean_up_tokenization_spaces=False)
    print("res-->", res)


if __name__ == '__main__':
    # text_classification()
    # feature_extraction()
    # fill_mask()
    # reading()
    summarization()

NER任务

命名实体识别(NER)任务是NLP中的基础任务。它用于识别文本中的人名(PER)、地名(LOC)、组织(ORG)以及其他实体(MISC)等。例如:(王 B-PER) (小 I-PER) (明 I-PER) (在 O) (办 B-LOC) (公 I-LOC) (室 I-LOC)。其中O表示一个非实体,B表示一个实体的开始,I表示一个实体块的内部。

命名实体识别本质上是一个分类任务(又叫序列标注任务),命名实体识别是句法分析的基础,而句法分析又是NLP任务的核心。

# 6.NER任务
def ner():
    #1.加载分词器
    tokenizer = AutoTokenizer.from_pretrained("../model/roberta-base-finetuned-cluener2020-chinese")
    #2.加载模型
    model = AutoModelForTokenClassification.from_pretrained("../model/roberta-base-finetuned-cluener2020-chinese")
    configs = AutoConfig.from_pretrained("../model/roberta-base-finetuned-cluener2020-chinese")
    #3.准备语料,编码
    message = '我爱北京天安门,天安门上太阳升'
    inputs = tokenizer.encode_plus(message, return_tensors='pt')
    print("inputs-->", inputs)
    #4.送入模型,进行预测
    model.eval()
    output = model(**inputs)
    # [1, 17, 32],默认对每一个token做了一个32的分类
    print("output-->", output.logits, output.logits.shape) # [1, 17, 32]
    #5.获得添加特殊字符的句子
    tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])
    print("tokens-->", tokens)
    #6.判断token是否是特殊符号,特殊符号一定不是实体。
    output_list = []
    for token, logit in zip(tokens, output.logits[0]):
        if token in tokenizer.all_special_tokens:
            continue
        # 得到预测结果的index
        index = torch.argmax(logit, dim=-1).item()
        # 把index转换为label
        label = configs.id2label[index]
        output_list.append((token, label))
    print("output_list-->", output_list)


if __name__ == '__main__':
    # text_classification()
    # feature_extraction()
    # fill_mask()
    # reading()
    # summarization()
    ner()

具体模型方式

完型填空任务又被叫做“遮蔽语言建模任务”,它属于BERT模型训练过程中的子任务。

下面使用具体模型来实现。

import torch
from transformers import BertForMaskedLM, BertTokenizer
def fill_mask():
    #1.加载分词器
    tokenizer = BertTokenizer.from_pretrained("../model/chinese-bert-wwm")
    #2.加载模型
    model = BertForMaskedLM.from_pretrained("../model/chinese-bert-wwm")
    #3.准备语料,编码
    message = "我明天准备去[MASK]家吃饭"
    inputs = tokenizer.encode_plus(message, return_tensors='pt')
    print("inputs-->", inputs)
    #4.送入模型,进行预测
    output = model(**inputs).logits
    print("output-->", output, output.shape)
    #5.获取结果
    index = torch.argmax(output[0][7]).item()
    print("index-->", index)
    res = tokenizer.convert_ids_to_tokens(index)
    print("res-->", res)


if __name__ == '__main__':
    fill_mask()
💻 代码

微调实战代码

3 个文件