抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

预训练模型最开始是在图像领域提出的,获得了良好的效果,近几年才被广泛应用到自然语言处理各项任务中。

  • (1) 2003 年 Bengio 提出神经网络语言模型 NNLM,从此统一了 NLP 的特征形式 ——Embedding;

  • (2) 2013 年 Mikolov 提出词向量 Word2vec,延续 NNLM 又引入了大规模预训练(Pretrain)的思路;

  • (3) 2017 年 Vaswani 提出 Transformer 模型,实现用一个模型处理多种 NLP 任务。

  • (4) 基于 Transformer 架构,2018 年底开始出现一大批预训练语言模型 (3 个预训练代表性模型 BERT [2018]、XLNet [2019] 和 MPNet [2020]),刷新众多 NLP 任务,形成新的里程碑事件。

预训练模型的应用通常分为两步:

  • 第一步:在计算性能满足的情况下用某个较大的数据集训练出一个较好的模型。

  • 第二步:根据不同的任务,改造预训练模型,用新任务的数据集在预训练模型上进行微调。

预训练模型的好处是训练代价较小,配合下游任务可以实现更快的收敛速度,并且能够有效地提高模型性能,尤其是对一些训练数据比较稀缺的任务。换句话说,预训练方法可以认为是让模型基于一个更好的初始状态进行学习,从而能够达到更好的性能。

要讲自然语言的预训练,得先从图像领域的预训练说起。

图像领域的预训练

图像领域的预训练

设计好网络结构以后,对于图像来说一般是 CNN 的多层叠加网络结构,可以先用某个训练集合比如训练集合 A 或者训练集合 B 对这个网络进行预先训练,在 A 任务上或者 B 任务上学会网络参数,然后存起来以备后用。假设我们面临第三个任务 C,网络结构采取相同的网络结构,在比较浅的几层 CNN 结构,网络参数初始化的时候可以加载 A 任务或者 B 任务学习好的参数,其它 CNN 高层参数仍然随机初始化。

之后我们用 C 任务的训练数据来训练网络,此时有两种做法,一种是浅层加载的参数在训练 C 任务过程中不动,这种方法被称为 “Frozen”;

另外一种是底层网络参数尽管被初始化了,在 C 任务训练过程中仍然随着训练的进程不断改变,这种一般叫 “Fine-Tuning”,顾名思义,就是更好地把参数进行调整使得更适应当前的 C 任务。

对于层级的 CNN 结构来说,不同层级的神经元学习到了不同类型的图像特征,由底向上特征形成层级结构。

对于层级的CNN结构来说,不同层级的神经元学习到了不同类型的图像特征,由底向上特征形成层级结构

如果我们手头是个人脸识别任务,训练好网络后,把每层神经元学习到的特征可视化肉眼看一看每层学到了啥特征,你会看到最底层的神经元学到的是线段等特征,图示的第二个隐层学到的是人脸五官的轮廓,第三层学到的是人脸的轮廓,通过三步形成了特征的层级结构,越是底层的特征越是所有不论什么领域的图像都会具备的比如边角线弧线等底层基础特征,越往上抽取出的特征越与手头任务相关。

正因为此,所以预训练好的网络参数,尤其是底层的网络参数抽取出特征跟具体任务越无关,越具备任务的通用性,所以这是为何一般用底层预训练好的参数初始化新任务网络参数的原因。

而高层特征跟任务关联较大,实际可以不用使用,或者采用 Fine-tuning 用新数据集合清洗掉高层无关的特征抽取器。

用ImageNet来做网络的预训练

一般我们用 ImageNet 来做网络的预训练,主要有两点,一方面 ImageNet 是图像领域里有超多事先标注好训练数据的数据集合,分量足是个很大的优势,量越大训练出的参数越靠谱;另外一方面因为 ImageNet 有 1000 类,类别多,算是通用的图像数据,跟领域没太大关系,所以通用性好。

Word Embedding

现有的机器学习方法往往无法直接处理文本数据,因此需要找到合适的方法,将文本数据转换为数值型数据,由此引出了 Word Embedding 的概念,Word Embedding 算法携带了语义信息且维度经过压缩便于运算。

语言模型

语言模型

为了能够量化地衡量哪个句子更像一句人话,可以设计如上图所示函数,核心函数 P 的思想是根据句子里面前面的一系列前导单词预测后面单词的概率大小。

神经网络语言模型

神经网络语言模型

NNLM 是从语言模型出发 (即计算概率角度),构建神经网络针对目标函数对模型进行最优化,训练的起点是使用神经网络去搭建语言模型实现词的预测任务,并且在优化过程后模型的副产品就是词向量。

Word2Vec

2013 年最火的用语言模型做 Word Embedding 的工具是 Word2Vec,后来又出了 Glove。

Word2Vec

Word2Vec 有两种训练方法,一种叫 CBOW,核心思想是从一个句子里面把一个词抠掉,用这个词的上文和下文去预测被抠掉的这个词;

第二种叫做 Skip-gram,和 CBOW 正好反过来,输入某个单词,要求网络预测它的上下文单词。

使用 Word2Vec 或者 Glove,通过做语言模型任务,就可以获得每个单词的 Word Embedding。

Word Embedding 的使用

Word Embedding的使用

我们有个 NLP 的下游任务,比如 QA,就是问答问题,所谓问答问题,指的是给定一个问题 X,给定另外一个句子 Y, 要判断句子 Y 是否是问题 X 的正确答案。

句子中每个单词以 Onehot 形式作为输入,然后乘以 Word Embedding 矩阵 Q,就直接取出单词对应的 Word Embedding。

使用 Word Embedding 等价于把 Onehot 层到 embedding 层的网络用预训练好的参数矩阵 Q 初始化。

这跟前面讲的图像领域的低层预训练过程其实是一样的,区别无非 Word Embedding 只能初始化第一层网络参数,再高层的参数就无能为力了。

下游 NLP 任务在使用 Word Embedding 的时候也类似图像有两种做法,一种是 Frozen,就是 Word Embedding 那层网络参数固定不动;另外一种是 Fine-Tuning,就是使用新的训练集合训练,在训练过程中,更新 Word Embedding 这层参数。

Word Embedding 的问题

Word Embedding的问题

是多义词问题。多义词是自然语言中经常出现的现象,也是语言灵活性和高效性的一种体现。

多义词对 Word Embedding 来说有什么负面影响?如上图所示,比如多义词 Bank,有两个常用含义,但是 Word Embedding 在对 bank 这个单词进行编码的时候,是区分不开这两个含义的,因为它们尽管上下文环境中出现的单词不同,但是在用语言模型训练的时候,不论什么上下文的句子经过 word2vec,都是预测相同的单词 bank,而同一个单词占的是同一行的参数空间,这导致两种不同的上下文信息都会编码到相同的 word embedding 空间里去。所以 word embedding 无法区分多义词的不同语义,这就是它的一个比较严重的问题。

从 Word Embedding 到 ELMO

ELMO 是 “Embedding from Language Models” 的简称。在此之前的 Word Embedding 本质上是个静态的方式,所谓静态指的是训练好之后每个单词的表达就固定住了,以后使用的时候,不论新句子上下文单词是什么,这个单词的 Word Embedding 不会跟着上下文场景的变化而改变。

ELMO 的本质思想是:事先用语言模型学好一个单词的 Word Embedding,此时多义词无法区分,实际使用 Word Embedding 的时候,单词已经具备了特定的上下文了,这个时候可以根据上下文单词的语义去调整单词的 Word Embedding 表示,这样经过调整后的 Word Embedding 更能表达在这个上下文中的具体含义,自然也就解决了多义词的问题了。所以 ELMO 本身的思路是根据当前上下文对 Word Embedding 动态调整。

从Word Embedding到ELMO

ELMO 采用了典型的两阶段过程,第一个阶段是利用语言模型进行预训练;第二个阶段是在做下游任务时,从预训练网络中提取对应单词的网络各层的 Word Embedding 作为新特征补充到下游任务中。

使用这个网络结构利用大量语料做语言模型任务就能预先训练好这个网络,如果训练好这个网络后,输入一个新句子 ,句子中每个单词都能得到对应的三个 Embedding: 最底层是单词的 Word Embedding,往上走是第一层双向 LSTM 中对应单词位置的 Embedding,这层编码单词的句法信息更多一些;再往上走是第二层 LSTM 中对应单词位置的 Embedding,这层编码单词的语义信息更多一些。也就是说,ELMO 的预训练过程不仅仅学会单词的 Word Embedding,还学会了一个双层双向的 LSTM 网络结构,而这两者后面都有用。

从Word Embedding到ELMO

上图展示了下游任务的使用过程,比如我们的下游任务仍然是 QA 问题,此时对于问句 X,我们可以先将句子 X 作为预训练好的 ELMO 网络的输入,这样句子 X 中每个单词在 ELMO 网络中都能获得对应的三个 Embedding,之后给予这三个 Embedding 中的每一个 Embedding 一个权重 a,这个权重可以学习得来,根据各自权重累加求和,将三个 Embedding 整合成一个。然后将整合后的这个 Embedding 作为 X 句在自己任务的那个网络结构中对应单词的输入,以此作为补充的新特征给下游任务使用。对于上图所示下游任务 QA 中的回答句子 Y 来说也是如此处理。因为 ELMO 给下游提供的是每个单词的特征形式,所以这一类预训练的方法被称为 “Feature-based Pre-Training”。

从 Word Embedding 到 GPT

从Word Embedding到GPT

GPT 是 “Generative Pre-Training” 的简称,从名字看其含义是指的生成式的预训练。GPT 也采用两阶段过程,第一个阶段是利用语言模型进行预训练,第二阶段通过 Fine-tuning 的模式解决下游任务。

Transformer

Transformer 是个叠加的 “自注意力机制(Self Attention)” 构成的深度网络,是目前 NLP 里最强的特征提取器。

Transformer 是一种基于 encoder-decoder 结构的模型。在机器翻译任务上的表现超过了 RNN,CNN,只用 encoder-decoder 和 attention 机制就能达到很好的效果,最大的优点是可以高效地并行化。

Transformer

自注意力机制模型

人类视觉通过快速扫描全局图像,获得需要重点关注的目标区域,也就是一般所说的注意力焦点,而后对这一区域投入更多注意力资源,以获取更多所需要关注目标的细节信息,而抑制其他无用信息。

这是人类利用有限的注意力资源从大量信息中快速筛选出高价值信息的手段.

深度学习中的注意力机制从本质上讲和人类的选择性视觉注意力机制类似,核心目标也是从众多信息中选择出对当前任务目标更关键的信息。

Attention 在同一个英语句子内单词间产生的联系。

自注意力机制模型

自注意力机制模型

Self Attention 可以捕获同一个句子中单词之间的一些句法特征(比如图展示的有一定距离的短语结构)或者语义特征(比如图展示的 its 的指代对象 Law)。

很明显,引入 Self Attention 后会更容易捕获句子中长距离的相互依赖的特征,因为如果是 RNN 或者 LSTM,需要依次序序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。

SelfAttention 在计算过程中会直接将句子中任意两个单词的联系通过一个计算步骤直接联系起来,所以远距离依赖特征之间的距离被极大缩短,有利于有效地利用这些特征。除此外,SelfAttention 对于增加计算的并行性也有直接帮助作用。这是为何 Self Attention 逐渐被广泛使用的主要原因。

GPT 如何使用

GPT如何使用

把任务的网络结构改造成和 GPT 的网络结构是一样的。然后,在做下游任务的时候,利用第一步预训练好的参数初始化 GPT 的网络结构,对网络参数进行 Fine-tuning,使得这个网络更适合解决手头的问题。

从 GPT 和 ELMO 及 word2Vec 到 Bert

从GPT和ELMO及word2Vec到Bert

Bert 采用和 GPT 完全相同的两阶段模型,首先是语言模型预训练;其次是使用 Fine-Tuning 模式解决下游任务。和 GPT 的最主要不同在于在预训练阶段采用了类似 ELMO 的双向语言模型,当然另外一点是语言模型的数据规模要比 GPT 大。

BERT 本质上是一个自编码(Auto Encoder)语言模型,为了能见多识广,BERT 使用 3 亿多词语训练,采用 12 层双向 Transformer 架构。注意,BERT 只使用了 Transformer 的编码器部分,可以理解为 BERT 旨在学习庞大文本的内部语义信息。

具体训练目标之一,是被称为掩码语言模型的 MLM。即输入一句话,给其中 15% 的字打上 “mask” 标记,经过 Embedding 输入和 12 层 Transformer 深度理解,来预测 “mask” 标记的地方原本是哪个字。

input:   欲把西[mask]比西子,淡[mask]浓抹总相宜
output: 欲把西[湖]比西子,淡[妆]浓抹总相宜

例如我们输入 “欲把西 [mask] 比西子,淡 [mask] 浓抹总相宜” 给 BERT,它需要根据没有被 “mask” 的上下文,预测出掩盖的地方是 “湖” 和 “妆”。

MLM 任务的灵感来自于人类做完形填空。挖去文章中的某些片段,需要通过上下文理解来猜测这些被掩盖位置原先的内容。

训练目标之二,是预测输入的两句话之间是否为上下文(NSP)的二分类问题。继续输入 “欲把西 [湖] 比西子,淡 [妆] 浓抹总相宜”,BERT 将预测这两句话的组合是否合理(这个例子是 “yes”)。(随后的研究者对预训练模型探索中证明,NSP 任务过于简单,对语言模型的训练作用并不是很大)

通过这两个任务和大规模语料训练,BERT 语言模型可以很好学习到文本之间的蕴含的关系。

从GPT和ELMO及word2Vec到Bert

NLP 的四大任务

NLP的四大任务

绝大部分 NLP 问题可以归入上图所示的四类任务中:

一类是序列标注,这是最典型的 NLP 任务,比如中文分词,词性标注,命名实体识别,语义角色标注等都可以归入这一类问题,它的特点是句子中每个单词要求模型根据上下文都要给出一个分类类别。

第二类是分类任务,比如我们常见的文本分类,情感计算等都可以归入这一类。它的特点是不管文章有多长,总体给出一个分类类别即可。

第三类任务是句子关系判断,比如 Entailment,QA,语义改写,自然语言推理等任务都是这个模式,它的特点是给定两个句子,模型判断出两个句子是否具备某种语义关系;

第四类是生成式任务,比如机器翻译,文本摘要,写诗造句,看图说话等都属于这一类。它的特点是输入文本内容后,需要自主生成另外一段文字。

NLP的四大任务

根据任务选择不同的预训练数据初始化 encoder 和 decoder 即可。这是相当直观的一种改造方法。当然,也可以更简单一点,比如直接在单个 Transformer 结构上加装隐层产生输出也是可以的。不论如何,从这里可以看出,NLP 四大类任务都可以比较方便地改造成 Bert 能够接受的方式。这其实是 Bert 的非常大的优点,这意味着它几乎可以做任何 NLP 的下游任务,具备普适性,这是很强的。

BERT 的应用案例

下载 bert 预训练模型

Google - BERT 源码 https://github.com/google-research/bert 下载预训练模型。

下载bert预训练模型

我这里选择中文的 BERT,下载解压后的目录如下:

下载bert预训练模型

安装 bert-as-service

顾名思义,将 BERT 模型直接封装成一个服务,堪称上手最快的 BERT 工具。作者是肖涵博士。

使用 pip 安装:

pip install bert-serving-server # server
pip install bert-serving-client # client, independent of `bert-serving-server

开启 BERT service

bert-serving-start -model_dir E:\nlp\chinese_L-12_H-768_A-12

安装bert-as-service

安装bert-as-service

使用客户端获取句子编码

安装bert-as-service

安装bert-as-service

案例一 查找最相近的句子

根据 bert 获取句子向量,并计算出句子之间的余弦相似度,找出最相似的句子。

# 导入bert客户端
from bert_serving.client import BertClient
import numpy as np

class SimilarModel:
def __init__(self):
self.bert_client = BertClient()

def close_bert(self):
self.bert_client .close()

def get_sentence_vec(self,sentence):
'''
根据bert获取句子向量
:param sentence:
:return:
'''
return self.bert_client .encode([sentence])[0]

def cos_similar(self,sen_a_vec, sen_b_vec):
'''
计算两个句子的余弦相似度
:param sen_a_vec:
:param sen_b_vec:
:return:
'''
vector_a = np.mat(sen_a_vec)
vector_b = np.mat(sen_b_vec)
num = float(vector_a * vector_b.T)
denom = np.linalg.norm(vector_a) * np.linalg.norm(vector_b)
cos = num / denom
return cos

if __name__=='__main__':
# 从候选集condinates 中选出与sentence_a 最相近的句子
condinates = ['为什么天空是蔚蓝色的','太空为什么是黑的?','天空怎么是蓝色的','明天去爬山如何']
sentence_a = '天空为什么是蓝色的'
bert_client = SimilarModel()
max_cos_similar = 0
most_similar_sentence = ''
for sentence_b in condinates:
sentence_a_vec = bert_client.get_sentence_vec(sentence_a)
sentence_b_vec = bert_client.get_sentence_vec(sentence_b)
cos_similar = bert_client.cos_similar(sentence_a_vec,sentence_b_vec)
if cos_similar > max_cos_similar:
max_cos_similar = cos_similar
most_similar_sentence = sentence_b

print('最相似的句子:',most_similar_sentence)
bert_client .close_bert()
# 为什么天空是蔚蓝色的

案例二 简单模糊搜索

将问题编码为向量:

from bert_serving.client import BertClient
doc_vecs = bc.encode(questions)

最后,我们准备接收新查询并针对现有问题执行简单的 “模糊” 搜索。为此,每次出现新查询时,我们都将其编码为向量,并使用来计算其点积 doc_vecs。将结果递减排序;并返回前 k 个类似的问题,如下所示:

while True:
query = input('your question: ')
query_vec = bc.encode([query])[0]
# compute normalized dot product as score
score = np.sum(query_vec * doc_vecs, axis=1) / np.linalg.norm(doc_vecs, axis=1)
topk_idx = np.argsort(score)[::-1][:topk]
print('top %d questions similar to "%s"' % (topk, query))
for idx in topk_idx:
print('> %s\t%s' % ('%.1f' % score[idx], questions[idx]))

现在运行代码并键入查询,查看此搜索引擎如何处理模糊匹配:

简单模糊搜索

案例三 法条推荐

介绍

根据刑事法律文书中的案情描述和事实部分,预测本案涉及的相关法条;

数据说明

所使用的数据集是来自 “中国裁判文书网” 公开的刑事法律文书,其中每份数据由法律文书中的案情描述和事实部分组成,同时也包括每个案件所涉及的法条、被告人被判的罪名和刑期长短等要素。

数据集共包括 268 万刑法法律文书,共涉及 202 条罪名,183 条法条,刑期长短包括 0-25 年、无期、死刑。

数据利用 json 格式储存,每一行为一条数据,每条数据均为一个字典。

fact: 事实描述

meta: 标注信息,标注信息中包括:

criminals: 被告 (数据中均只含一个被告)

punish_of_money: 罚款 (单位:元)

accusation: 罪名

relevant_articles: 相关法条

term_of_imprisonment: 刑期

刑期格式 (单位:月)

death_penalty: 是否死刑

life_imprisonment: 是否无期

imprisonment: 有期徒刑刑期

这里是简单的一条数据展示:

{
"fact": "2015年11月5日上午,被告人胡某在平湖市乍浦镇的嘉兴市多凌金牛制衣有限公司车间内,与被害人孙某因工作琐事发生口角,后被告人胡某用木制坐垫打伤被害人孙某左腹部。经平湖公安司法鉴定中心鉴定:孙某的左腹部损伤已达重伤二级。",
"meta":
{
"relevant_articles": [234],
"accusation": ["故意伤害"],
"criminals": ["胡某"],
"term_of_imprisonment":
{
"death_penalty": false,
"imprisonment": 12,
"life_imprisonment": false
}
}
}

实现流程

进入 OpenCLaP 下载刑事文书 BERT,并运行 bert-as-service 服务。

创建一个连接到 BertServer 的 BertClient
from bert_serving.client import ConcurrentBertClient
bc = ConcurrentBertClient()
获取编码向量和标签
def get_encodes(x):
# x 是 batch_size 大小的行 ,每行都是一个json对象
samples = [json.loads(l) for l in x] # 一个 batch_size 大小的连续样本
text = [s['fact'][:50] + s['fact'][-50:] for s in samples] # 获取案情描述和事实部分文字
features = bc.encode(text) # 使用bert将字符串列表编码为向量列表
# 随机选择一个标签
labels = [[str(random.choice(s['meta']['relevant_articles']))] for s in samples]
return features, labels
构建 TensorFlow DNN 模型的分类器
estimator = DNNClassifier(
hidden_units=[512], # 每层隐藏单元的 Iterable 数.所有层都完全连接.
feature_columns=[tf.feature_column.numeric_column('feature', shape=(768,))], # 包含模型使用的所有特征列的iterable.集合中的所有项目都应该是从 _FeatureColumn 派生的类的实例.
n_classes=len(laws), # 标签类的数量.默认为 2,即二进制分类,必须大于1.
config=run_config, # RunConfig 对象配置运行时设置
label_vocabulary=laws_str, # 字符串列表,表示可能的标签值.如果给定,标签必须是字符串类型,并且 label_vocabulary 具有任何值.如果没有给出,这意味着标签已经被编码为整数或者在[0,1]内浮动, n_classes=2 ;并且被编码为{0,1,...,n_classes-1}中的整数值,n_classes> 2.如果没有提供词汇表并且标签是字符串,也会出现错误.
optimizer=tf.train.AdamOptimizer(),# 优化函数
dropout=0.1 # 当不是 None 时,我们将放弃给定坐标的概率.
)
训练和评估
# 输入函数
input_fn = lambda fp: (tf.data.TextLineDataset(fp) # TextLineDataset接口提供了一种方法从数据文件中读取。只需要提供文件名(1个或者多个)。这个接口会自动构造一个dataset,类中保存的元素:文中一行,就是一个元素,是string类型的tenser。
# map将分别对Dataset的每个元素执行一个函数,而apply将立即对整个Dataset执行一个函数
.apply(tf.contrib.data.shuffle_and_repeat(buffer_size=10000)) # repeat重复和shuffle重排 tf.data.Dataset.repeat 转换会将输入数据重复有限(或无限)次;每次数据重复通常称为一个周期。tf.data.Dataset.shuffle 转换会随机化数据集样本的顺序。
# 将此数据集的连续元素合并为批。
.batch(batch_size)
# tf.py_func()接收的是tensor,然后将其转化为numpy array送入我们自定义的get_encodes函数,最后再将get_encodes函数输出的numpy array转化为tensor返回
.map(lambda x: tf.py_func(get_encodes, [x], [tf.float32, tf.string], name='bert_client'),
num_parallel_calls=num_parallel_calls)
.map(lambda x, y: ({'feature': x}, y))
.prefetch(20)) # 创建一个从该数据集中预提取元素的Dataset 大多数数据集输入管道应以调用结束prefetch。这允许在处理当前元素时准备以后的元素。这通常会提高延迟和吞吐量,但以使用额外的内存存储预取元素为代价。
# TrainSpec确定训练的输入数据以及持续时间
train_spec = TrainSpec(input_fn=lambda: input_fn(train_fp))
# EvalSpec结合了训练模型的计算和输出的详细信息.计算由计算指标组成,用以判断训练模型的性能.输出将训练好的模型写入外部存储.
eval_spec = EvalSpec(input_fn=lambda: input_fn(eval_fp), throttle_secs=0) # 第一次评估发生在throttle_secs秒后
# 训练和评估
train_and_evaluate(estimator, train_spec, eval_spec)
运行 tensorboard 可视化训练过程
tensorboard --logdir=law-model

运行tensorboard可视化训练过程

运行tensorboard可视化训练过程

案例四 互联网新闻情感分析

介绍

对新闻情绪进行分类,0 代表正面情绪、1 代表中性情绪、2 代表负面情绪。

数据说明

FieldTypeDescription
idString 新闻 ID News ID
textString 新闻正文内容 Content of news text
labelString 新闻情感标签 Emotional label in news

实现流程

加载数据集
def load_dataset(filepath):
dataset_list = []
f = open(filepath, 'r', encoding='utf-8')
r = csv.reader(f)
for item in r:
if r.line_num == 1:
continue
dataset_list.append(item)

# 空元素补0
for item in dataset_list:
if item[1].strip() == '':
item[1] = '0'

return dataset_list
网络类,全连接层
class Net(nn.Module):
# in_dim=768, out_dim=3
def __init__(self, in_dim, out_dim):
super(Net, self).__init__()

self.linear1 = nn.Linear(in_dim, 500)
self.linear2 = nn.Linear(500, 400)
self.linear3 = nn.Linear(400, 300)
self.linear4 = nn.Linear(300, 200)
self.linear5 = nn.Linear(200, out_dim)

def forward(self, x):
x = self.linear1(x)
x = self.linear2(x)
x = self.linear3(x)
x = self.linear4(x)
x = self.linear5(x)
return x
计算每个 batch 的准确率
def  batch_accuracy(pre, label):
pre = pre.argmax(dim=1)
correct = torch.eq(pre, label).sum().float().item()
accuracy = correct / float(len(label))

return accuracy
训练
for epoch in range(EPOCHS):
step = -1
for text, label in train_loader:
# tuple转list
text = list(text)
label = list(label)
label = list(map(int, label))
# 使用中文bert,生成句向量
sen_vec = bertclient.encode(text)
sen_vec = torch.tensor(sen_vec)
label = torch.LongTensor(label)
label = label.cuda()
# 输入到网络中,反向传播
pre = net(sen_vec).cuda()
loss = criterion(pre, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 更新loss曲线,并计算准确率
step = step + 1
flag = flag + 1
if step % 100 == 0:
acc = batch_accuracy(pre, label)
print('epoch:{} | batch:{} | acc:{} | loss:{}'.format(epoch, step, acc, loss.item()))
测试
net.load_state_dict(torch.load('net.pt'))

test_result = []
for item in test_dataset:

sen_vec = bertclient.encode([item[1]])
sen_vec = torch.tensor(sen_vec)

with torch.no_grad():
pre = net(sen_vec).cuda()
pre = pre.argmax(dim=1)
pre = pre.item()
test_result.append([item[0], pre])

# 写入csv文件
df = pd.DataFrame(test_result)
df.to_csv('test_result.csv',index=False, header=['id', 'label'])
训练可视化

训练可视化

训练可视化

训练可视化

控制台输出

控制台输出

参考文献

从 Word Embedding 到 Bert 模型 — 自然语言处理中的预训练技术发展史

Transformer

深度学习中的注意力模型

谷歌的 bert

肖涵博士的 bert-as-service

Serving-Google-BERT-in-Production-using-Tensorflow-and-ZeroMQ

CAIL2018 数据集

刑事文书 BERT:

tensorboard 使用详解

Visdom 可视化工具

互联网新闻情感分析

推荐阅读
尝试在博客中添加简易文章推荐功能 尝试在博客中添加简易文章推荐功能 特征和分类器 特征和分类器 大数据处理技术-Hadoop-MapReduce 大数据处理技术-Hadoop-MapReduce 大数据处理技术-hadoop的架构模型(1.x,2.x的各种架构模型介绍) 大数据处理技术-hadoop的架构模型(1.x,2.x的各种架构模型介绍) 基于Audioscrobbler数据集的音乐推荐(pyspark) 基于Audioscrobbler数据集的音乐推荐(pyspark) 手把手教你用 Python 开始第一个机器学习项目 手把手教你用 Python 开始第一个机器学习项目

留言区

Are You A Robot?