如果想让构建的模型更加惊鹊,就需要引用到transformer神经网络模型,首先我们需要认识一下这个模型。Transformer神经网络模型是一种基于自注意力机制(Self-Attention Mechanism)的深度学习模型,最初由Google的研究团队在2017年的论文《Attention is All You Need》中提出。该模型主要用于处理序列数据,尤其是在自然语言处理(NLP)领域取得了显著成效,但它也适用于其他类型的序列数据,如时间序列分析或图像序列分析等。
Transformer的核心组件
自注意力机制(Self-Attention):
允许模型在处理一个词时,考虑到句子中的其他词,从而更好地理解上下文。
相较于传统的序列模型(如RNN、LSTM),自注意力机制能够并行处理输入序列,从而提高训练效率。
多头注意力(Multi-Head Attention):
通过多个自注意力机制并行运行,然后合并它们的输出,模型可以从不同的角度学习输入数据的表示。
位置编码(Positional Encoding):
由于自注意力机制本身不考虑序列中元素的位置信息,Transformer通过添加位置编码来提供这一信息。
编码器-解码器结构(Encoder-Decoder Architecture):
Transformer模型通常由两部分组成:编码器(Encoder)和解码器(Decoder)。
编码器负责将输入序列转换成一种中间表示,解码器则根据这种表示生成输出序列。
自注意力机制的工作原理可以分为以下几个关键步骤:
查询(Query)、键(Key)和值(Value)的计算:
对于输入序列中的每个元素,通过线性变换(通常是权重矩阵乘法)分别生成查询向量(Q)、键向量(K)和值向量(V)。这些向量代表了元素在自注意力机制中的不同角色:查询向量用于与其他元素的键向量进行匹配,键向量用于被查询向量匹配,值向量则包含了元素的实际内容信息。
注意力分数计算:
对于序列中的每个元素(作为查询),计算其与序列中所有其他元素(作为键)之间的注意力分数。这通常通过查询向量和键向量的点积来实现,有时为了稳定softmax函数的梯度,还会对点积结果进行缩放。
注意力权重分配:
将计算出的注意力分数通过softmax函数转换为归一化的概率分布,即注意力权重。这些权重表示了当前元素在处理时应该给予序列中其他元素多少关注。
加权求和得到输出:
根据注意力权重,对当前元素的值向量以及序列中所有其他元素的值向量进行加权求和,得到当前元素的最终输出表示。这个输出表示不仅包含了当前元素的信息,还融合了序列中其他相关信息。以下是代码简介。
中心节点: 自注意力机制 ├── 输入序列 │ ├── 元素1 │ ├── 元素2 │ ├── ... │ └── 元素n ├── 查询(Query)、键(Key)、值(Value)计算 │ ├── 线性变换 │ │ ├── Q1, K1, V1 │ │ ├── Q2, K2, V2 │ │ ├── ... │ │ └── Qn, Kn, Vn │ └── 输出: Q, K, V 矩阵 ├── 注意力分数计算 │ ├── 点积运算 │ ├── 缩放因子 (可选) │ └── 输出: 注意力分数矩阵 ├── 注意力权重分配 │ ├── softmax 函数 │ └── 输出: 注意力权重矩阵 └── 加权求和得到输出 ├── 加权求和 └── 输出: 每个元素的最终表示
接下来重要的是编码器-译码器结构, 两者都是6层结构,由编码器的第一层结构开始,一层层经过解码器的解读,将中间转化得到的词向量得到为转化为最终输出结果
编码器(Encoder)
作用:将输入序列(如文本、图像等)编码成一个固定长度的向量表示,这个向量通常被称为“上下文向量”(context vector)或“隐藏状态”(hidden state)。
过程:
接收输入序列。
逐步处理序列中的每个元素(如词语、像素等),更新其内部状态。
在处理完整个序列后,其最终状态作为对整个序列的压缩表示。
常用模型:循环神经网络(RNN)、长短期记忆网络(LSTM)、门控循环单元(GRU)等。
解码器(Decoder)
作用:根据编码器生成的上下文向量,逐步生成输出序列。
过程:
接收编码器的上下文向量作为初始状态。
在每个时间步,基于当前状态和前一时间步的输出(或训练时的目标输出),预测下一个输出元素。
重复此过程,直到生成序列结束标记。
常用模型:与编码器相同类型的模型,以保持一致性。
以下是一个简化的编码器-解码器原理的思维导图文字描述:
中心主题:编码器-解码器模型
分支一:编码器
接收输入序列
逐步处理序列元素
生成上下文向量
常用模型:RNN, LSTM, GRU
分支二:解码器
接收上下文向量作为初始状态
逐步生成输出序列
基于当前状态和前一时间步输出预测下一个元素
常用模型:与编码器相同
分支三:注意力机制
引入注意力机制提升性能
允许解码器关注输入序列的不同部分
提高输出的准确性和相关性
以下是调整代码
# 位置编码
class PositionalEncoding(nn.Module):
def __init__(self, d_model, dropout=0.1, max_len=5000):
super(PositionalEncoding, self).__init__()
self.dropout = nn.Dropout(p=dropout)
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0).transpose(0, 1)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:x.size(0), :]
return self.dropout(x)
# Transformer
class TransformerModel(nn.Module):
def __init__(self, src_vocab, tgt_vocab, d_model, nhead, num_encoder_layers, num_decoder_layers, dim_feedforward, dropout):
super(TransformerModel, self).__init__()
self.transformer = nn.Transformer(d_model, nhead, num_encoder_layers, num_decoder_layers, dim_feedforward, dropout)
self.src_embedding = nn.Embedding(len(src_vocab), d_model)
self.tgt_embedding = nn.Embedding(len(tgt_vocab), d_model)
self.positional_encoding = PositionalEncoding(d_model, dropout)
self.fc_out = nn.Linear(d_model, len(tgt_vocab))
self.src_vocab = src_vocab
self.tgt_vocab = tgt_vocab
self.d_model = d_model
def forward(self, src, tgt):
# 调整src和tgt的维度
src = src.transpose(0, 1) # (seq_len, batch_size)
tgt = tgt.transpose(0, 1) # (seq_len, batch_size)
src_mask = self.transformer.generate_square_subsequent_mask(src.size(0)).to(src.device)
tgt_mask = self.transformer.generate_square_subsequent_mask(tgt.size(0)).to(tgt.device)
src_padding_mask = (src == self.src_vocab['<pad>']).transpose(0, 1)
tgt_padding_mask = (tgt == self.tgt_vocab['<pad>']).transpose(0, 1)
src_embedded = self.positional_encoding(self.src_embedding(src) * math.sqrt(self.d_model))
tgt_embedded = self.positional_encoding(self.tgt_embedding(tgt) * math.sqrt(self.d_model))
output = self.transformer(src_embedded, tgt_embedded,
src_mask, tgt_mask, None, src_padding_mask, tgt_padding_mask, src_padding_mask)
return self.fc_out(output).transpose(0, 1)
需要注意的问题:为使模型更加精准,我们可以通过调参来实现,增大训练集的数目,增加其宽度或者深度,增强其翻译文本的能力。还可以通过加入术语词典来增强其功能,比如将某些同义词做整体代换,替换为某一指定内容,还可以增加预处理流程,提前进行筛选,将不符合意思的词语或乱码提前进行删除,提高效率等。