pythonlstm模型训练好后如何使⽤_【⾃然语⾔处理】的迁移学习:微调BERT来对垃圾。。。
随着深度学习的发展,递归神经⽹络(RNN和LSTM)和卷积神经⽹络(CNN)等神经⽹络结构已经完成了⾃然语⾔处理(NLP)的⼤部分任务,它在⽂本分类、语⾔建模、机器翻译等性能上都有了很⼤的提⾼。
然⽽,与计算机视觉(Computer Vision)中的深度学习性能相⽐,⾃然语⾔处理的深度学习模型的性能就差强⼈意了。
缺少⼤型带标记的⽂本数据集。⽬前,⼤多数带标记的⽂本数据集对于⾃然语⾔处理的深度学习模型来说都不够“⼤”,不原因之⼀在于缺少⼤型带标记的⽂本数据集
如果在⼩数据集上训练这样的⽹络会导致过拟合。
⾜以训练深度神经⽹络,因为深度神经⽹络的参数量很⼤,如果在⼩数据集上训练这样的⽹络会导致过拟合
(对于过拟合的概念解释有很多,⼩编这⾥摘来《数据挖掘-概念与技术》中的解释便于⼤家理解,“即在机器学习期间,它可能并⼊了训练数据中的某些特殊的异常点,这些异常不在⼀般数据集中出现。”)
(overfittingt是这样⼀种现象:⼀个假设在训练数据上能够获得⽐其他假设更好的拟合,但是在训练数
据外的数据集上却不能很好的拟合数据。此时我们就叫这个假设出现了overfitting的现象。出现这种现象的主要原因是训练数据中存在噪⾳或者训练数据太少。)除此之外,⾃然语⾔处理落后于计算机视觉发展的另⼀个重要原因是它缺乏迁移学习(transfer learning)
缺乏迁移学习(transfer learning)。要知道,迁移学习在计算机视觉深度学习中发挥了重要作⽤。借助Imagenet等⼤型标记数据集的强可⽤性,基于CNN的深度模型训练成为可能——⽬前,这些⼤型标记数据集已经被⼴泛⽤作于计算机视觉任务的预训练模型了。
Transformer模型,NLP深度学习才算有了新的飞跃。
⽽在⾃然语⾔处理的深度学习上,直到2018年⾕歌提出Transformer模型
⽂本分类(Text Classification),包括以下⼏个部分:
本⽂将通过实际演⽰来解释如何调整BERT来进⾏⽂本分类(Text Classification),
1. ⾃然语⾔处理中的迁移学习
2. 模型微调(Model Fine-Tuning)是什么意思?
3. BERT简介
4. 【实际演⽰】微调BERT来对垃圾邮件进⾏分类
1.⾃然语⾔处理中的迁移学习
迁移学习是⼀种将深度学习模型在⼤数据集⾥训练,然后在另⼀个数据集上执⾏类似任务的技术
预训练迁移学习是⼀种将深度学习模型在⼤数据集⾥训练,然后在另⼀个数据集上执⾏类似任务的技术。我们称这种深度学习模型为预训练模型(Pre-trained Models)。
模型(Pre-trained Models)
预训练模型最著名的例⼦是在ImageNet数据集⾥训练的计算机视觉(Computer Vision)深度学习模型。解决问题的最好⽅式是使⽤⼀个预先训练好的模型,⽽不是从头开始构建⼀个模型。拿⽇常⼯作和⽣活举例,想必⼤家为了顺利甚⾄完美地提案,⼀定会提前不断地进⾏准备和模拟吧?迁移学习是⼀个道理。
随着近年来⾃然语⾔处理的发展,迁移学习成为了⼀种可⾏的选择。
NLP中的⼤部分任务,如⽂本分类、语⾔建模、机器翻译等,都是序列建模任务(Sequence Modeling tasks)。这种传统的机器学习模型和神经⽹络⽆法捕捉⽂本中出现的顺序信息(sequential
information)。因此,⼈们开始使⽤递归神经⽹络(RNN和LSTM),这些结构可以建模⽂本中出现的顺序信息。
⼀个典型的RNN
RNNs不能并⾏化(parallelized),它们⼀次只能接受⼀个输⼊。对于⽂本序
然⽽,递归神经⽹络也有局限,其中的主要问题是RNNs不能并⾏化(parallelized)
列,RNN或LSTM每次输⼊只能接受⼀次切分(Token),即逐个地传递序列。如果在⼀个⼤数据集⾥训练这样⼀个模型会花费很多时间。
⽔涨船⾼的时间成本使在NLP⾥使⽤迁移学习的呼声不断,终于,在2018年,⾕歌在《Attention is All You Need》
《Attention is All You Need》⼀⽂中介绍Transformer模型,这个模型成为了NLP深度学习的⾥程碑。
了Transformer模型
Transformer模型结构
很快,基于Transformer的NLP任务模型⼜多⼜快地发展起来。
使⽤Transformer的模型有很多优点,其中最重要的以下两点——
整个序列作为⼀次输⼊——这对于基于RNN的模型来说是⼀次速度的飞跃,因为1. 这些模型不是单个切分地处理输⼊的序列,⽽是将整个序列作为⼀次输⼊
这意味着现在模型可以靠GPUs加速了!
我们不需要标记数据来预训练这些模型了——我们只需要提供⼤量未标记的⽂本数据来训练基于Transformer的模型。然后我们可2. 我们不需要标记数据来预训练这些模型了——
以将这个训练模型套⽤在其他NLP任务中,如⽂本分类(Text Classification)、命名实体识别(Named Entity Recognition)、⽂本⽣成(Text Generation)等。这就是在⾃然语⾔处理中迁移学习的⼯作⽅式。
BERT和GPT-2是当下最流⾏的基于Transformer的模型,
⽽在本⽂中,我们将重点关注BERT
如何使⽤预先训练好的BERT模型来执⾏⽂本分类。
python怎么读的将重点关注BERT并学习如何使⽤预先训练好的BERT模型来执⾏⽂本分类
2. 模型微调(Model Fine-Tuning)是什么意思?
BERT(Bidirectional Encoder Representations from Transformers)是⼀个具有⼤量参数的⼤型神经⽹络架构,其参数量可以从1亿到3亿多个。所以,在⼀个⼩数据集上从零开始训练BERT模型会导致过拟合。
所以训练BERT模型需要从⼤型数据集开始,然后使⽤相对⼩的数据集上进⾏再训练模型,这个过程被称为模型微调(Model Fine-
模型微调(Model Fine-Tuning)。
Tuning)
模型微调的⼏种⽅法:
训练整个架构:我们可以在(相对较⼩的)训练数据集上的进⼀步训练整个预训练模型,并输出到softmax层。这种⽅法会让误差在训练整个架构:
整个架构中反向传播,并且模型的预训练权重会根据新的数据集进⾏更新。
训练部分层,同时冻结其他层:另⼀种使⽤预训练模型的⽅法是部分训练。我们保持保持模型初始层的权重不变,⽽只对更⾼层进⾏训练部分层,同时冻结其他层:
再训练。这种⽅法需要我们⾃⼰尝试需要冻结多少层,训练多少层。
冻结整个架构:这种⽅法是冻结整个预训练模型,加上⼀些我们⾃⼰的神经⽹络层,然后训练这个新模型。注意,这⾥只有附加层的冻结整个架构:
权重会在训练期间更新。
本教程使⽤的是第三种⽅法,我们将在微调期间冻结整个BERT层,在其加上⼀个密集层和softmax层。
(softmax经常⽤在神经⽹络的最后⼀层,作为输出层,进⾏多分类。此外,softmax在增强学习领域内,softmax经常被⽤作将某个值转化为激活概率,这类情况下,softmax的公式如下:)
带温度参数的softmax函数
3. BERT简介
让我们来看看BERT研究团队如何描述其NLP框架的吧:
BERT全称为 Bidirectional Encoder Representations from Transformers(来⾃Transformer的双向编码器表⽰)。它通过对左右上下⽂的共同条件作⽤,来预先训练未标记⽂本的深层双向表⽰。因此,预先训练好的BERT模型可以通过⼀个额外的输出层进⾏微调,从⽽为NLP任务创建最先进的模型。
感觉是不是很深奥,我们⼀起梳理梳理吧!
⾸先,BERT全称是B idirectional E E ncoder R R epresentations from T T ransformers。这⾥的每个单词都有其意义,我们接下来会逐⼀介绍。⽬前,这⼀⾏需要记住的关键内容是——BERT是基于Transformer架构的。
其次,BERT预先训练了⼤量未标记的⽂本语料库,包括整个Wikipedia(25亿个单词!)和图书语料库(8亿个单词)。
当我们在⼀个⼤⽂本语料库⾥训练模型时,模型就能对语⾔如何⽣成有更深⼊透彻的理解 预训练是BERT的出⾊之处。因为 当我们在⼀个⼤⽂本语料库⾥训练模型时,模型就能对语⾔如何⽣成有更深⼊透彻的理解——这对⼏乎所有⾃然语⾔处理任务⽽⾔都是重中之重。
第三,BERT是⼀个“深度双向”模型。双向意味着BERT在训练阶段可以同时从切词的左边和右边学习信息。
想要了解更多关于BERT体系结构及其预训练的信息,⼤家可以阅读下⾯这篇⽂章:
Demystifying BERT: A Comprehensive Guide to the Groundbreaking NLP Framework w ww.analyticsvidhya
.【实际演⽰】微调BERT来对垃圾邮件进⾏分类
4.【实际演⽰】微调BERT来对垃圾邮件进⾏分类
现在我们将在ransformer库的帮助下对BERT模型进⾏微调,以执⾏⽂本分类——
问题陈述
在⽇常⽣活中接收的各类信息中,不免会有垃圾邮件。⽽我们的任务就是建⽴⼀个系统,可以⾃动检测消息是否是垃圾邮件。⽤例的数据集可以点击这⾥下载
安装Transformer库
我们将安装Huggingface的Transformer库。这个库允许导⼊⼤量基于Transformer的预训练模型。只需执⾏下⾯的代码来安装:
!
pip install transformers
导⼊库
import numpy as np
import pandas as pd
import torch
as nn
del_selection import train_test_split
ics import classification_report
import transformers
from transformers import AutoModel, BertTokenizerFast
# specify GPU
device = torch.device("cuda")
加载数据集
将数据集读⼊pandas数据框
df = ("")
()
该数据集由两列——“标签”和“⽂本”组成。“⽂本”列包含消息正⽂,“标签”列是⼀个⼆进制定类变量,1表⽰垃圾邮件,0表⽰该消息不是垃圾邮件。
现在我们将把这个数据集分成三个集——⽤于训练、验证和测试。
# split train dataset into train, validation and test sets
训练集和验证集⽤来对模型进⾏微调,并对测试集进⾏预测。
导⼊BERT模型和BERT切分
我们将导⼊有着亿个参数的BERT模型。其实还有⼀个更⼤的BERT模型叫做BERT-large,它有亿个参数。
# import BERT-base pretrained model
bert = ('bert-base-uncased')
# Load the BERT tokenizer
tokenizer = ('bert-base-uncased')
让我们来看看这个BERT切分是怎么⼯作的吧。先试着使⽤它对⼏个句⼦进⾏编码:
# sample data
text = ["this is a bert model tutorial", "we will fine-tune a bert model"]
# encode text
sent_id = (text, padding=True)
# output
print(sent_id)
这是输出结果:
{‘input_ids’: [[101, 2023, 2003, 1037, 14324, 2944, 14924, 4818, 102, 0],
[101, 2057, 2097, 2986, 1011, 8694, 1037, 14324, 2944, 102]],
‘attention_mask’: [[1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}
可以看见,输出是⼀个包含两个条⽬的dictionary。
' input_ids '包含输⼊句⼦的整数序列。整数101和102是特殊切分。我们将它们添加到两个序列中,0表⽰填充切分。' attention_mask '包含1和0,它告诉模型要注意与掩码值1对应的标记并忽略其余的。
切分句⼦
# get length of all the messages in the train set
seq_len = [len(()) for i in train_text]
(seq_len).hist(bins = 30)
我们可以清楚地看到,⼤多数句⼦的长度为25个字符或更少。⽽最⼤长度是175。如果我们选择175作为填充长度那么所有输⼊序列长度为175,⼤部分的标记在这些序列将填充标记不会帮助模型学习任何有⽤的东西,最重要的是,它会使训练速度较慢。
因此,我们将设25为填充长度。
# tokenize and encode sequences in the training set
tokens_train = (
(),
max_length = 25,
pad_to_max_length=True,
truncation=True
)
# tokenize and encode sequences in the validation set
tokens_val = (
(),
max_length = 25,
pad_to_max_length=True,
truncation=True
)
# tokenize and encode sequences in the test set
tokens_test = (
(),
max_length = 25,
pad_to_max_length=True,
truncation=True
我们现在已经将训练,验证和测试集中的句⼦转换为每个长度为25个的切分整数序列。 接下来,我们需要将整数序列转换为张量。
## convert lists to tensors
train_seq = (tokens_train['input_ids'])
train_mask = (tokens_train['attention_mask'])
train_y = (())
val_seq = (tokens_val['input_ids'])
val_mask = (tokens_val['attention_mask'])
val_y = (())
test_seq = (tokens_test['input_ids'])
test_mask = (tokens_test['attention_mask'])
test_y = (())
现在我们将为训练集和验证集创建dataloaders,这些dataloaders将在训练阶段将成批的训练数据和验证数据作为输⼊传递给模型。
from torch.utils.data import TensorDataset, DataLoader, RandomSampler, SequentialSampler
#define a batch size
batch_size = 32
# wrap tensors
train_data = TensorDataset(train_seq, train_mask, train_y)
# sampler for sampling the data during training
train_sampler = RandomSampler(train_data)
# dataLoader for train set
train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=batch_size)
# wrap tensors
val_data = TensorDataset(val_seq, val_mask, val_y)
# sampler for sampling the data during training
val_sampler = SequentialSampler(val_data)
# dataLoader for validation set
val_dataloader = DataLoader(val_data, sampler = val_sampler, batch_size=batch_size)
定义模型架构
⼩编在前⽂说到了,本次使⽤的微调⽅法是第三种,即在对模型进⾏微调之前,会冻结模型的所有层。如果有⼩伙伴希望微调BERT模型的预训练权重,那么就不需要执⾏下⾯这段代码。
# freeze all the parameters
for param in bert.parameters():
接下来,就到定义我们的模型架构的时候了

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。