昇思25天学习打卡营第15天|基于 MindSpore 实现 BERT 对话情绪识别

文章目录

昇思MindSpore应用实践

本系列文章主要用于记录昇思25天学习打卡营的学习心得。

1、基于 MindSpore 实现 BERT 对话情绪识别
BERT 模型简介

自2017年Google发表"Attention is ALL You Need"之后,基于自注意力机制结构的网络模型开始在各领域发展,特别是Transformer网络,针对序列的强大长距离关联处理能力在NLP领域取得了成效,BERT 的创新点在于它将双向 Transformer 用于语言模型,曾一度刷新各项NLP任务的SOTA记录,包括问答 Question Answering (SQuAD v1.1),推理 Natural Language Inference (MNLI) 等,也由此拉开了LLM的序幕。

在此之前,以往的NLP模型,如RNN网络,通常是从左向右输入一个文本序列,或者将 left-to-right 和 right-to-left 的训练结合起来(如Bi-LSTM)。实验结果表明,双向训练的语言模型对语境的理解会比单向的语言模型更深刻,

BERT 利用了 Transformer 的 Encoder 部分。Transformer 基于自注意力机制可以学习文本中单词之间的上下文关系。Transformer 的原型包括两个独立的机制,一个 Encoder 负责接收文本作为输入,一个 Decoder 负责预测任务的结果。BERT 的目标是生成语言模型,所以只需要 Encoder 机制。

Transformer 的 encoder 是一次性读取整个文本序列 ,而不是从左到右或从右到左地按顺序读取,这个特征使得模型能够基于单词的两侧学习,相当于是一个双向的功能

下图是 Transformer 的 encoder 部分,输入是一个 token 序列,先对其进行 embedding 称为向量,然后输入给神经网络,输出是大小为 H 的向量序列,每个向量对应着具有相同索引的 token。

BERT模型的主要创新点都在pre-train方法上,即用了Masked Language ModelNext Sentence Prediction两种方法分别捕捉词语和句子级别的representation。

在用Masked Language Model方法训练BERT的时候,随机把语料库中15%的单词做Mask操作。对于这15%的单词做Mask操作分为三种情况:80%的单词直接用Mask替换、10%的单词直接替换成另一个新的单词、10%的单词保持不变。

因为涉及到Question Answering (QA) 和 Natural Language Inference (NLI)之类的任务,增加了Next Sentence Prediction预训练任务,目的是让模型理解两个句子之间的联系。与Masked Language Model任务相比,Next Sentence Prediction更简单些,训练的输入是句子A和B,B有一半的几率是A的下一句,输入这两个句子,BERT模型预测B是不是A的下一句

BERT预训练之后,会保存它的Embedding table和12层Transformer权重(BERT-BASE)或24层Transformer权重(BERT-LARGE)。使用预训练好的BERT模型可以对下游任务进行Fine-tuning,比如:文本分类、相似度判断、阅读理解等。

对话情绪识别(Emotion Detection,简称EmoTect),专注于识别智能对话场景中用户的情绪,针对智能对话场景中的用户文本,自动判断该文本的情绪类别并给出相应的置信度,情绪类型分为积极、消极、中性。 对话情绪识别适用于聊天、客服等多个场景,能够帮助企业更好地把握对话质量、改善产品的用户交互体验,也能分析客服服务质量、降低人工质检成本。

下面以MindSpore给出的一个文本情感分类任务为例子来说明BERT模型的整个应用过程:

python 复制代码
import os

import mindspore
from mindspore.dataset import text, GeneratorDataset, transforms
from mindspore import nn, context

from mindnlp._legacy.engine import Trainer, Evaluator
from mindnlp._legacy.engine.callbacks import CheckpointCallback, BestModelCallback
from mindnlp._legacy.metrics import Accuracy

# 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)
数据集

这里提供一份已标注的、经过分词预处理的机器人聊天数据集,来自于百度飞桨团队。数据由两列组成,以制表符('\t')分隔,第一列是情绪分类的类别(0表示消极;1表示中性;2表示积极),第二列是以空格分词的中文文本,如下示例,文件为 utf8 编码。

label--text_a

0--谁骂人了?我从来不骂人,我骂的都不是人,你是人吗 ?

1--我有事等会儿就回来和你聊

2--我见到你很高兴谢谢你帮我

这部分主要包括数据集读取,数据格式转换,数据 Tokenize 处理和 pad 操作。

数据加载和数据预处理

新建 process_dataset 函数用于数据加载和数据预处理:

python 复制代码
import numpy as np

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处理:

python 复制代码
from mindnlp.transformers import BertTokenizer
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()

'input_ids', 'attention_mask', 'labels'

python 复制代码
print(next(dataset_train.create_tuple_iterator()))

Tensor(shape=\[32, 64, dtype=Int64, value=

\[ 101, 6443, 3221 ... 0, 0, 0,

101, 872, 1963 ... 0, 0, 0,

101, 6929, 872 ... 0, 0, 0,

...

101, 872, 4268 ... 0, 0, 0,

101, 671, 4991 ... 0, 0, 0,

101, 1376, 1480 ... 0, 0, 0]), Tensor(shape=32, 64, dtype=Int64, value=

\[1, 1, 1 ... 0, 0, 0,

1, 1, 1 ... 0, 0, 0,

1, 1, 1 ... 0, 0, 0,

...

1, 1, 1 ... 0, 0, 0,

1, 1, 1 ... 0, 0, 0,

1, 1, 1 ... 0, 0, 0]), Tensor(shape=32, dtype=Int32, value= [1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 2, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1,

1, 1, 2, 1, 1, 1, 1, 1])]

2、模型训练

通过 BertForSequenceClassification 构建用于情感分类的 BERT 模型,加载预训练权重,设置情感三分类的超参数自动构建模型。后面对模型采用自动混合精度操作,提高训练的速度,然后实例化优化器,紧接着实例化评价指标,设置模型训练的权重保存策略,最后就是构建训练器,模型开始训练。

python 复制代码
from mindnlp.transformers import BertForSequenceClassification, BertModel
from mindnlp._legacy.amp import auto_mixed_precision

# set bert config and define parameters for training
model = BertForSequenceClassification.from_pretrained('bert-base-chinese', num_labels=3)
model = auto_mixed_precision(model, 'O1')

optimizer = nn.Adam(model.trainable_params(), learning_rate=2e-5)

metric = Accuracy()
# define callbacks to save checkpoints
ckpoint_cb = CheckpointCallback(save_path='checkpoint', ckpt_name='bert_emotect', epochs=1, keep_checkpoint_max=2)
best_model_cb = BestModelCallback(save_path='checkpoint', ckpt_name='bert_emotect_best', auto_load=True)

trainer = Trainer(network=model, train_dataset=dataset_train,
                  eval_dataset=dataset_val, metrics=metric,
                  epochs=5, optimizer=optimizer, callbacks=[ckpoint_cb, best_model_cb])
# start training
trainer.run(tgt_columns="labels")
模型验证

将验证数据集加再进训练好的模型,对数据集进行验证,查看模型在验证数据上面的效果,此处的评价指标为准确率。

python 复制代码
evaluator = Evaluator(network=model, eval_dataset=dataset_test, metrics=metric)
evaluator.run(tgt_columns="labels")

% print_log:
Evaluate Score: {'Accuracy': 0.9083011583011583}
3、模型推理

遍历推理数据集,将结果与标签进行统一展示。

python 复制代码
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)
from mindspore import Tensor

for label, text in dataset_infer:
    predict(text, label)

# print_log:
inputs: '我 要 客观', predict: '中性' , label: '中性'
inputs: '靠 你 真是 说 废话 吗', predict: '消极' , label: '消极'
inputs: '口嗅 会', predict: '中性' , label: '中性'
inputs: '每次 是 表妹 带 窝 飞 因为 窝路痴', predict: '中性' , label: '中性'
inputs: '别说 废话 我 问 你 个 问题', predict: '消极' , label: '消极'
inputs: '4967 是 新加坡 那 家 银行', predict: '中性' , label: '中性'
inputs: '是 我 喜欢 兔子', predict: '积极' , label: '积极'
inputs: '你 写 过 黄山 奇石 吗', predict: '中性' , label: '中性'
inputs: '一个一个 慢慢来', predict: '中性' , label: '中性'
inputs: '我 玩 过 这个 一点 都 不 好玩', predict: '消极' , label: '消极'
inputs: '网上 开发 女孩 的 QQ', predict: '中性' , label: '中性'
inputs: '背 你 猜 对 了', predict: '中性' , label: '中性'
inputs: '我 讨厌 你 , 哼哼 哼 。 。', predict: '消极' , label: '消极'

Reference

昇思大模型平台
不会停的蜗牛-5 分钟入门 Google 最强NLP模型:BERT

相关推荐
钓了猫的鱼儿13 小时前
基于深度学习+AI的电梯内电动车目标检测与预警系统(Python源码+数据集+UI可视化界面+YOLOv11训练结果)
人工智能·深度学习·目标检测
zhangfeng113314 小时前
transformer 挑战者 mamba 架构,线性attention RNN给改进iclr 2024拒稿
rnn·深度学习·transformer
YOLO数据集集合14 小时前
输电线缺陷目标检测|无人机电力巡检深度学习数据集|电网线缆散股智能识别数据
人工智能·深度学习·yolo·目标检测·无人机
王天天(Bennet)14 小时前
【从第一性原理来深入理解Transformer-更适合入门的理解(llama-3B模型为例)】
深度学习·transformer·llama
Kobebryant-Manba15 小时前
安装cuda
pytorch·python·深度学习·conda·numpy
动物园猫15 小时前
无人机角度的道路损害检测数据集分享(适用于YOLO系列深度学习分类检测任务)
深度学习·yolo·无人机
手写码匠15 小时前
手写 Prefix Caching:从零构建 LLM 提示词缓存引擎
人工智能·深度学习·算法·aigc
AI人工智能+16 小时前
基于深度学习与计算机视觉的表格识别技术:不仅能精准提取表格中的文字内容,更能深度解析复杂的表格结构,实现版面信息的完美还原
深度学习·计算机视觉·自然语言处理·ocr·表格识别
盼小辉丶16 小时前
PyTorch强化学习实战(11)——N步DQN(N-step DQN)
pytorch·python·深度学习·强化学习