4.6自注意力机制和bert_第1页
4.6自注意力机制和bert_第2页
4.6自注意力机制和bert_第3页
4.6自注意力机制和bert_第4页
4.6自注意力机制和bert_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

大数据技术在会计与财务中的应用作者:张敏等2026/9/8《大数据技术在会计与财务中的应用》配套课件第4章·4.6自注意力机制、Transformer和BERT目录4.6.1自注意力机制与Transformer模型4.6.2BERT模型4.6自注意力机制、Transformer和BERT4.6自注意力机制、Transformer和BERT|02/19前文所述的RNN和LSTM模型的一个重大缺陷是无法并行处理输入序列中的元素。为了解决这个问题,Vaswani等在2017年提出了以自注意力机制为核心的Transformer模型。自注意力机制是一种能够计算序列中各个元素之间的依赖关系的机制,可以并行计算序列中各个元素的表示。自注意力机制允许模型在处理序列的每个元素时考虑到序列中的所有其他元素,以便更好地理解整个序列的上下文。这种机制的关键是能够捕捉序列内部的长距离依赖关系,而不像传统的RNN和LSTM那样受到序列长度的限制。Transformer模型在机器翻译等任务上取得了很好的效果,成为了自然语言处理领域的一个重要模型。而在此基础上开发的BERT模型,随后风靡学术界和业界,在文本分析领域得到了极为广泛的应用。自注意力机制的工作流程(1)输入表示:序列中的每个元素(如单词或字符)首先被转换为固定长度的向量表示。(2)打分:通过计算序列中各元素之间的相互作用(通常是通过点积或其他相似性度量)来赋予不同的权重。(3)权重归一化:使用Softmax函数将这些权重归一化,使它们的总和为1,这样每个元素与其他元素的关联程度就被量化了。(4)加权求和:根据归一化的权重对所有输入向量进行加权求和,得到每个位置的输出表示。4.6.1自注意力机制与Transformer模型4.6自注意力机制、Transformer和BERT|03/19自注意力机制是Transformer模型的核心,它使得每个序列元素可以直接与其他所有元素关联,而不是通过多个步骤间接关联。这种机制帮助Transformer模型有效捕捉长序列中的依赖关系,并提高处理效率。Transformer模型包含两个主要部分:编码器(Encoder)和解码器(Decoder)。(1)编码器(Encoder):编码器由多个相同的层组成,每一层都包含一个自注意力机制和一个简单的前馈神经网络。编码器处理输入序列,并将信息传递给解码器。(2)解码器(Decoder):解码器也由多层构成,每层除了包含自注意力机制和前馈神经网络外,还增加了一个编码器-解码器注意力机制,允许解码器关注输入序列的不同部分。Transformer模型的示意图如图4-3所示,左侧为编码器,右侧为解码器。多头注意力机制(Multi-HeadAttention)是指在自注意力机制中使用多组查询、键和值向量,以便模型可以并行地学习不同特征的表示。4.6.1自注意力机制与Transformer模型4.6自注意力机制、Transformer和BERT|04/19大名鼎鼎的BERT(BidirectionalEncoderRepresentationsfromTransformers)模型就是基于Transformer模型构建的,在自然语言处理领域取得了很好的效果,成为了预训练模型的代表之一。BERT基于Transformer模型的编码器(Encoder)部分,使用多层自注意力机制来处理输入文本,每层包含多头注意力和前馈神经网络。BERT的关键在于其双向训练策略,这能够捕获双向上下文的信息,从而使得每个单词都能在其上下文中被全面地理解。BERT通过以下两种预训练任务来学习语言表示:(1)遮蔽语言模型(MaskedLanguageModel,MLM):随机遮蔽输入句子中的某些单词,然后模型需要预测这些被遮蔽的单词。这种任务帮助BERT学习单词的双向上下文表示。(2)下一句预测(NextSentencePrediction,NSP):给定两个句子A和B,模型需要预测B是否为A的下文。这种任务帮助BERT捕捉句子间的关系。尽管BERT是预训练的,其也可以通过微调以适应各种特定的NLP任务,如文本分类、问答、命名实体识别等。微调时,我们通常在BERT的基础上添加一层输出层以适应具体的任务,然后在特定任务的数据集上进行训练。BERT模型应用的场景和前文所述的RNN等传统神经网络模型类似,但由于其预训练的特性和先进的结构,BERT比RNN等传统模型拥有更高的准确率。接下来我们将通过代码示例来演示如何使用HuggingFace的transformers库加载预训练的BERT模型,进行文本的分类任务。(1)文本预处理。如前所述,第一步始终是对文本的预处理。importpandasaspd

#本次我们使用的数据集是新闻文本数据集,该数据集将新闻文本分成了5个类别,分别是politics,technology,entertainment,business,sport

data=pd.read_csv(r"news-text.csv")fromnltk.corpusimportstopwords

fromnltk.tokenizeimportword_tokenize

importstring

importnltk

#对数据集进行预处理#加载英文停用词表

stop_words=set(stopwords.words('english'))

#初始化词干提取器

stemmer=nltk.SnowballStemmer("english")

4.6.2BERT模型4.6自注意力机制、Transformer和BERT|05/19

#这个函数是用来去除标点符号,停用词,词干化的

defpreprocess(text):

#文本转化成小写text=text.lower()

#去掉标点符号

text=''.join([wordforwordintextifwordnotinstring.punctuation])

#分词

tokens=word_tokenize(text)

#去掉停用词tokens=[wordforwordintokensifwordnotinstop_words]

#词干提取

tokens=[stemmer.stem(word)forwordintokens]

#对每个词处理以后,再合成处理后的字符串

return''.join(tokens)#对数据集中的每个文本应用上面的函数,得到处理后的文本

data['text_standard']=data['text'].apply(preprocess)4.6.2BERT模型4.6自注意力机制、Transformer和BERT|06/19(2)转换文本格式以适应BERT模型。预处理后,我们还需要把文本转换为BERT模型可以接受的输入格式,即对文本分词并将其转换为BERT模型输入所需的张量(Tensor)格式。#加载bert的tokenizerfromtransformersimportBertTokenizer

#引入预定义的BERTtokenizer,注意模型(Mode)l要使用其对应的tokenizer。

tokenizer=BertTokenizer.from_pretrained('bert-base-uncased')

#我们利用这句话来看看经过tokenizer处理后,会得到什么输出

example_text='IwillwatchMementotonight'

#padding='max_length'是指把所有的句子都填充到最大长度;return_tensors="pt"是指返回pytorchtensor,这是一个pytorch的数据格式

bert_input=tokenizer(example_text,padding='max_length',max_length=20,

truncation=True,return_tensors="pt")

#bert的tokenizer会输出三组数据,分别是input_ids,token_type_ids,attention_mask,我们来看看这三组数据的内容

#input_ids是指把每个词转换成对应的id

print(bert_input['input_ids'])

#token_type_ids是指把每个词转换成对应的id

print(bert_input['token_type_ids'])

#attention_mask是指把每个词转换成对应的idprint(bert_input['attention_mask'])4.6.2BERT模型4.6自注意力机制、Transformer和BERT|07/19(3)构建转换数据的函数。完成了文本预处理后,我们将开始构建BERT模型所需要的输入格式,即构建DataLoader,将数据转换为Tensor格式。#引入pytorch,注意这里是torch而不是pytorchimporttorch

importnumpyasnp

#引入BERT的tokenizer,用于把文本转换成BERT的输入格式

fromtransformersimportBertTokenizer

#加载bert的tokenizer

tokenizer=BertTokenizer.from_pretrained('bert-base-uncased')

#用于把标签转换成数字,编码

labels={'business':0,'entertainment':1,

'sport':2,

'tech':3,

'politics':4

}

4.6.2BERT模型4.6自注意力机制、Transformer和BERT|08/19

#定义一个数据集的类(Class),用于加载数据,该类继承自torch.utils.data.Dataset,继承指的是一个类可以继承另一个类的属性和方法

classDataset(torch.utils.data.Dataset):

#初始化函数

def__init__(self,df):

#把标签转换成数字,作为该类的属性之一

self.labels=[labels[label]forlabelindf['category']]

#把文本转换成bert的输入格式,作为该类的属性之一

self.texts=[tokenizer(text,padding='max_length',max_length=512,truncation=True,return_tensors="pt")fortextindf['text_standard']]

#定义一个方法,用于返回数据集的长度

def__len__(self):

returnlen(self.labels)

#定义一个方法,用于返回数据集中的标签

defget_batch_labels(self,idx):

returntorch.tensor(self.labels[idx])

#定义一个方法,用于返回数据集中的文本

defget_batch_texts(self,idx):

returnself.texts[idx]

#这是一个魔术方法,用于返回数据集中的一个样本。魔术方法指的是以__开头和结尾的方法,当我们调用类的实例时,这些方法会自动被调用,因此被称为魔术方法

def__getitem__(self,idx):

batch_texts=self.get_batch_texts(idx)

batch_y=self.get_batch_labels(idx)

#返回值是一个元组,元组的第一个元素是文本,第二个元素是标签

returnbatch_texts,batch_y4.6.2BERT模型4.6自注意力机制、Transformer和BERT|09/19(4)划分训练集和验证集。对数据集进行分割,分为训练集和验证集。#引入sklearn的train_test_split函数,用于将数据集分成训练集和测试集fromsklearn.model_selectionimporttrain_test_split

#把数据集分成训练集和测试集,测试集训练集各占10%

df_train,df_test=train_test_split(data,test_size=0.1,random_state=42)

df_train,df_val=train_test_split(df_train,test_size=0.1,random_state=42)(5)构建BERT模型具体结构。下面我们来构建BERT模型的具体结构,包括一个初始化函数和一个前向传播函数。初始化函数用于加载预训练的BERT模型,前向传播函数用于定义模型的计算流程,指导模型如何处理输入的数据。#引入torch.nn,用于构建神经网络fromtorchimportnn#引入BERT模型

fromtransformersimportBertModel

#定义一个类,用于构建BERT分类器的具体结构,该类继承自nn.Module

classBertClassifier(nn.Module):

#初始化函数,dropout是神经网络中的一个技术,原理是在训练过程中,随机让一部分神

经元失活,以减少过拟合

def__init__(self,dropout=0.5):

#调用父类的初始化函数,super()是一个内置函数,用于调用父类的方法

super(BertClassifier,self).__init__()

#定义本项目使用的bert模型,这是一个预训练好的bert模型,我们也可以使用其他的bert模型

self.bert=BertModel.from_pretrained('bert-base-uncased')

#定义dropout层

self.dropout=nn.Dropout(dropout)

#定义一个线性层,输入是768维,输出是5维,5是指5个类别。当我们需要分类的类别不是5个时,我们需要修改这个数字

self.linear=nn.Linear(768,5)

#定义一个激活函数,激活函数的目的是为神经网络引入非线性因素,以提高神经网络的表达能力,否则神经网络可以简化为一个线性模型

self.relu=nn.ReLU()

4.6.2BERT模型4.6自注意力机制、Transformer和BERT|10/19#定义一个前向传播函数,前向传播是指数据从输入层到输出层的传播过程

defforward(self,input_id,mask):

#调用bert模型,输入是input_id和mask,input_id是指文本对应的id,由于我们在处理文本时,有填充的部分,所以需要mask来告诉模型哪些是填充的部分,哪些是真实的文本

_,pooled_output=self.bert(input_ids=input_id,attention_mask=mask,return_dict=False)

#把bert模型的输出传入dropout层

dropout_output=self.dropout(pooled_output)

#把dropout层的输出传入线性层

linear_output=self.linear(dropout_output)

#把线性层的输出传入激活函数

final_layer=self.relu(linear_output)

returnfinal_layer#得到最终的输出4.6.2BERT模型4.6自注意力机制、Transformer和BERT|11/19定义模型后,我们还需要定义一个训练函数,利用我们的数据微调BERT模型(预训练后的)从而适用于下游文本分类任务。#引入Adam优化器fromtorch.optimimportAdam

#引入tqdm,这是一个用于显示训练的进度条的包fromtqdmimporttqdm

#定义训练函数,输入是模型,训练集,验证集,学习率和迭代次数

deftrain(model,train_data,val_data,learning_rate,epochs):

#将数据转换成Dataset的格式,我们在前面定义了Dataset类,这里我们调用这个类

train,val=Dataset(train_data),Dataset(val_data)

#利用DataLoader把数据转换成一个个的小batch,而后送入模型。Batchsize是32,意味着每次送入模型的数据有32个

train_dataloader=torch.utils.data.DataLoader(train,batch_size=32,shuffle=True)

val_dataloader=torch.utils.data.DataLoader(val,batch_size=32)

use_cuda=torch.cuda.is_available()

#利用GPU训练

device=torch.device("cuda"ifuse_cudaelse"cpu")4.6.2BERT模型4.6自注意力机制、Transformer和BERT|12/19#定义损失函数,由于是一个多分类的问题,所以用CrossEntropyLoss。如果是二分类问题,可以用BCELoss。应当根据具体问题选择合适的损失函数

criterion=nn.CrossEntropyLoss()

#定义优化器

optimizer=Adam(model.parameters(),lr=learning_rate)

ifuse_cuda:#把模型送入GPU

model=model.cuda()

#把损失函数送入GPU

criterion=criterion.cuda()

#epochs指迭代次数

forepoch_numinrange(epochs):

#初始化训练集的准确率

total_acc_train=0

#初始化训练集的损失

total_loss_train=0

fortrain_input,train_labelintqdm(train_dataloader):

#以下分别将train_input和train_label送入GPU

mask=train_input['attention_mask'].to(device)

#因为BERT的输入是[batch_size,seq_length],所以需要把维度为1的维度去掉,这里我们用squeeze(1)来去掉维度值为1的维度

input_id=train_input['input_ids'].squeeze(1).to(device)

4.6.2BERT模型4.6自注意力机制、Transformer和BERT|13/19train_label=train_label.to(device)

#将input_id和mask送入模型,得到输出

output=model(input_id,mask)

#利用损失函数计算损失

batch_loss=criterion(output,train_label.long())#利用损失函数计算损失

#把每个batch的损失加起来,得到这一轮的总损失

total_loss_train+=batch_loss.item()

#计算准确率,这里的逻辑是,output.argmax(dim=1)是指找到每个batch中概率最大的那个类别,然后和train_label比较,如果相等就是1,不相等就是0,然后把所有的1加起来

acc=(output.argmax(dim=1)==train_label).sum().item()

#batch内所有的1加总,循环完所有的batch以后,就是整个训练集的判断正确的样本的数量

total_acc_train+=acc

#如果不在每次迭代开始时清零梯度,PyTorch会累积(或叠加)上一次迭代计算的梯度到现有梯度上。这意味着我们的梯度将会与之前所有迭代的梯度混合,而不是只反映当前迭代中的数据。这会导致模型参数的更新不正确,从而影响训练过程的效率和准确性。简单来说,model.zero_grad()确保我们的模型在每次迭代时只学习当前批次数据的特征,而不是被之前批次的梯度信息干扰。这是实现有效、准确的模型训练的关键步骤之一。

model.zero_grad()

4.6.2BERT模型4.6自注意力机制、Transformer和BERT|14/19#反向传播过程,反向传播指的是神经网络的误差从输出层向输入层传播,以更新神经网络的参数

batch_loss.backward()

#利用优化器更新参数

optimizer.step()

#初始化验证集的准确率

total_acc_val=0#初始化验证集的损失

total_loss_val=0

#由于这里是验证集,不需要反向传播来更新参数,所以用torch.no_grad()来关闭梯度计算

withtorch.no_grad():#以下的逻辑和训练集处理几乎是一样的,不再赘述

forval_input,val_labelinval_dataloader:

val_label=val_label.to(device)

mask=val_input['attention_mask'].to(device)

input_id=val_input['input_ids'].squeeze(1).to(device)

4.6.2BERT模型4.6自注意力机制、Transformer和BERT|15/19output=model(input_id,mask)

batch_loss=criterion(output,val_label.long())

total_loss_val+=batch_loss.item()

acc=(output.argmax(dim=1)==val_label).sum().item()

total_acc_val+=acc

print(

f'Epochs:{epoch_num+1}|TrainLoss:{total_loss_train/len(train_data):.3f}\

|TrainAccuracy:{total_acc_train/len(train_data):.3f}\

|ValLoss:{total_loss_val/len(val_data):.3f}\

|ValAccuracy:{total_acc_val/len(val_data):.3f}')#打印每一轮的训练集和验证集的损失和准确率

EPOCHS=5

model=BertClassifier()

LR=1e-54.6.2BERT模型4.6自注意力机制、Transformer和BERT|16/19(6)训练环节。至此,我们已准备好数据,同时构建了BERT模型的结构。我们此时可以调用函数开始训练。train(model,df_train,df_val,LR,EPOCHS)

#保存模型到本地

torch.save(model.state_dict(),'bert_model.pt')

#从本地加载模型

model=BertClassifier()

model.load_state_dict(torch.load('bert_model.pt'))(7)训练(FineTune)后的验证和预测。在微调BERT模型后,我们可以利用微调后的模型预测新的样本,并将结果输出到excel,结果包含testdata中的文本、预测值以及真实值。defpredict(model,test_data):

print(len(test_data))

test=Dataset(test_data)

test_dataloader=torch.utils.data.DataLoader(test,batch_size=2)

use_cuda=torch.cuda.is_available()

device=torch.device("cuda"ifuse_cudaelse"cpu")

ifuse_cuda:

model=model.cuda()

total_acc_test=0

#用来预测,不需要反向传播,同样要关闭梯度计算

withtorch.no_grad():

4.6.2BERT模型4.

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论