MindSpore学习实践——BERT 对话情绪识别
昇思MindSpore打卡营第四期——|基于MindSpore的BERT模型的情感分析
MindSpore学习实践——基于 MindSpore 实现 BERT 对话情绪识别
前言
BERT是Google于2018年末开发并发布的一种新型语言模型。与BERT模型相似的预训练语言模型例如问答、命名实体识别、自然语言推理、文本分类等在许多自然语言处理任务中发挥着重要作用。模型是基于Transformer中的Encoder并加上双向的结构,因此一定要熟练掌握Transformer的Encoder的结构。
BERT主要创新点都在pre-train方法上,即用了Masked Language Model和Next Sentence Prediction两种方法分别捕捉词语和句子级别的representation,这可以使得他的通用性得到增强;同时BERT的多层Transformer结构允许在不同任务之间共享参数。因此BERT只需通过在预训练模型的基础上微调部分参数,就可以较好的适应部分下游任务。
语言模型的演变:

BERT模型本质上是结合了ELMo模型与GPT模型的优势。 相比于ELMo,BERT仅需改动最后的输出层,而非模型架构,便可以在下游任务中达到很好的效果; 而相比于GPT,BERT在处理词元表示时考虑到了双向上下文的信息;
BERT的介绍
- Tokenization
使用分词器将输入的句子分词,然后首尾添加[CLS]与[SEP]特殊字符,后转换为数字id,(token序列转换成id序列,笔者正在学习transformer相关)

- Embedding(嵌入)
输入到BERT模型的信息由三部分内容组成:
- 表示内容的token ids
- 表示位置的position ids
- 用于区分不同句子的token type ids

-
BERT是由Transformer的Encoder层堆叠而成,BERT的模型大小有BERT BASE以及BERT LARGE两种。其中,前者与transformer参数量齐平(110兆参数);后者在此基础上扩大了参数量(340兆参数)。
-
BERT会针对每一个位置输出大小为hidden size的向量,在下游任务中,会根据任务内容的不同,选取不同的向量放入输出层:

- BERT的输出层:
- pooler output为[CLS]经过线性层+激活函数tanh的输出,其可以用于句子级别的分类/回归任务
- sequence output为BERT输出的每个位置对应的vector
BERT的预训练
BERT预训练任务有两种:Masked Language Modelling(MLM) 和Next Sentence Prediction(NSP)。
- MLM:随机遮盖输入句子中的一些词语,并预测被遮盖的词语是什么(完形填空)
- NSP:预测两个句子是不是上下文的关系
-
Masked Language Modelling(MLM)
- 在在输入中随机遮盖15%的token (即将token替换为[MASK])
- 将[MASK]位置对应的BERT输出 放入输出层中,预测被遮盖的 token,但这之后本质是在进行一个分类任务
- 为了使得预训练任务和推理任务尽可能接近,BERT在随机遮盖的15%的tokens中又进行了进一步的处理: •
- 80%的概率替换为[MASK]
- 10%的概率替换为文本中的随机词
- 10%的概率不进行替换,保持原有的词
- MLM (完形填空)局限性是它们倾向于生成无意义或不恰当的文本。由于模型并不真正理解它生成的文本,它有时会生成语法正确但语义上无意义的输出。例如,它可能会生成类似“猫对狗吠叫”这样的句子,这在语法上是正确的,但在意义上是无效的。
-
Next Sentence Prediction(NSP)
Next Sentence Prediction (NSP) 捕捉句子级别信息,简单来说是一个针对句子对的分类问题,判断一组句子中,句子B是否为句子A的下一句(Is Next or NotNext)
BERT的微调
在下游任务中,我们使用少量的标注数据(labelled data)对预训练Transformer编码器的所有参数进行微调,额外的输出层将从头开始训练。
比如在预训练模型的基础上添加少量特定任务的层,并进行少量训练可以使得BERT适应各种下游任务,如文本分类、命名实体识别、问答系统等。
代码实训
- 环境配置
#安装mindnlp 0.4.0套件
!pip install mindnlp==0.4.0
!pip uninstall soundfile -y
!pip install https://ms-release.obs.cn-north-4.myhuaweicloud.com/2.3.1/MindSpore/unified/aarch64/mindspore-2.3.1-cp39-cp39-linux_aarch64.whl --trusted-host ms-release.obs.cn-north-4.myhuaweicloud.com -i https://pypi.tuna.tsinghua.edu.cn/simple
- 下载数据集
# download dataset
!wget https://baidu-nlp.bj.bcebos.com/emotion_detection-dataset-1.0.0.tar.gz -O emotion_detection.tar.gz
!tar xvf emotion_detection.tar.gz
- 准备数据集
import os
import mindspore
from mindspore.dataset import text, GeneratorDataset, transforms
from mindspore import nn, context
from mindnlp.engine import Trainer
# prepare dataset
class SentimentDataset:
"""Sentiment Dataset"""
def __init__(self, path):
self.path = path
self._labels, self._text_a = [], []
self._load()
def _load(self):
with open(self.path, "r", encoding="utf-8") as f:
dataset = f.read()
lines = dataset.split("\n")
for line in lines[1:-1]:
label, text_a = line.split("\t")
self._labels.append(int(label))
self._text_a.append(text_a)
def __getitem__(self, index):
return self._labels[index], self._text_a[index]
def __len__(self):
return len(self._labels)
- 数据预处理
import numpy as np
# 昇腾NPU环境下暂不支持动态Shape,数据预处理部分采用静态Shape处理:
from mindnlp.transformers import BertTokenizer
def process_dataset(source, tokenizer, max_seq_len=64, batch_size=32, shuffle=True):
is_ascend = mindspore.get_context('device_target') == 'Ascend'
column_names = ["label", "text_a"]
dataset = GeneratorDataset(source, column_names=column_names, shuffle=shuffle)
# transforms
type_cast_op = transforms.TypeCast(mindspore.int32)
def tokenize_and_pad(text):
if is_ascend:
tokenized = tokenizer(text, padding='max_length', truncation=True, max_length=max_seq_len)
else:
tokenized = tokenizer(text)
return tokenized['input_ids'], tokenized['attention_mask']
# map dataset
dataset = dataset.map(operations=tokenize_and_pad, input_columns="text_a", output_columns=['input_ids', 'attention_mask'])
dataset = dataset.map(operations=[type_cast_op], input_columns="label", output_columns='labels')
# batch dataset
if is_ascend:
dataset = dataset.batch(batch_size)
else:
dataset = dataset.padded_batch(batch_size, pad_info={'input_ids': (None, tokenizer.pad_token_id),
'attention_mask': (None, 0)})
return dataset
# 昇腾NPU环境下暂不支持动态Shape,数据预处理部分采用静态Shape处理:
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
tokenizer.pad_token_id
dataset_train = process_dataset(SentimentDataset("data/train.tsv"), tokenizer)
dataset_val = process_dataset(SentimentDataset("data/dev.tsv"), tokenizer)
dataset_test = process_dataset(SentimentDataset("data/test.tsv"), tokenizer, shuffle=False)
dataset_train.get_col_names()
print(next(dataset_train.create_tuple_iterator()))
- 模型构建
from mindnlp.transformers import BertForSequenceClassification
from mindnlp.engine import TrainingArguments
from mindnlp import evaluate
import numpy as np
# set bert config and define parameters for training
model = BertForSequenceClassification.from_pretrained('bert-base-chinese', num_labels=3)
training_args = TrainingArguments(
output_dir="bert_imdb_finetune",
evaluation_strategy="epoch",
save_strategy="epoch",
logging_strategy="epoch",
load_best_model_at_end=True,
num_train_epochs=3.0,
learning_rate=2e-5
)
metric = evaluate.load("accuracy")
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = np.argmax(logits, axis=-1)
return metric.compute(predictions=predictions, references=labels)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset_train,
eval_dataset=dataset_val,
compute_metrics=compute_metrics
)
- 开始训练
# start training
trainer.train()
- 模型验证
trainer.evaluate(dataset_test)
- 模型推理
from mindspore import Tensor
dataset_infer = SentimentDataset("data/infer.tsv")
def predict(text, label=None):
label_map = {0: "消极", 1: "中性", 2: "积极"}
text_tokenized = Tensor([tokenizer(text).input_ids])
logits = model(text_tokenized)
predict_label = logits[0].asnumpy().argmax()
info = f"inputs: '{text}', predict: '{label_map[predict_label]}'"
if label is not None:
info += f" , label: '{label_map[label]}'"
print(info)
for label, text in dataset_infer:
predict(text, label)
# 自定义一个推理数据集
predict("家人们咱就是说一整个无语住了 绝绝子叠buff")
推理结果:

总结心得
本次课学习了BERT模型,主要在于NLP中的预训练模型、BERT的结构、BERT的预训练以及BERT的微调上,笔者还有机会通过启智平台实践完成了一次BERT的微调与推理,收获很大,也对模型的推理有了进一步的认知。笔者还是对BERT模型在微调后可以适应多种任务的能力所惊叹,其快速易用性可以用于多种领域,虽然本次课程结束了,但笔者未来仍将继续学习BERT模型并尝试自己完成BERT模型的微调并实现既定的想法。
昇腾计算产业是基于昇腾系列(HUAWEI Ascend)处理器和基础软件构建的全栈 AI计算基础设施、行业应用及服务,https://devpress.csdn.net/organization/setting/general/146749包括昇腾系列处理器、系列硬件、CANN、AI计算框架、应用使能、开发工具链、管理运维工具、行业应用及服务等全产业链
更多推荐

所有评论(0)