找回密码
 立即注册
首页 业界区 安全 Transformer模型开发从0到1——原理深入与项目实践 ...

Transformer模型开发从0到1——原理深入与项目实践

段干叶农 前天 11:01
第1~5章详细介绍了Transformer模型的框架及各个功能模块的代码实现,而Transformer模型最初也是为机器翻译打造的。那么如何使用Transformer模型训练一个机器翻译的模型,又是如何使用Transformer模型进行机器翻译的?
15.1.1        基于Transformer模型的机器翻译模型训练
在实现机器翻译(中英翻译为例)前,首先需要搜集大量的中英文对照数据,并进行机器翻译模型的训练,其模型训练代码如下:
第15章/15.1.1/基于Transformer模型的机器翻译模型训练-第一部分

导入相关的库

import math
import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as Data
import torch.nn.functional as F
device = 'cpu' #使用cpu还是 GPU进行加速推理训练 #device = 'cuda'
epochs = 100 #transformer模型训练的步数
训练集

这里为了演示随机输入了3个句子,当然真正的模型训练是需要大量的数据

sentences = [
#中文和英语的句子,单词个数不一定相同
#编码器输入     解码器输入        解码器输出
['我 爱 你 P', 'S i love you .', 'i love you . E'],
['你 好 吗 P', 'S how are you .', 'how are you . E'],
['人 工 智 能 P', 'S artificial intelligence .', 'artificial intelligence . E']
]
Padding 字符一般定义为0,其他的单词可以自行定义

中文词库

src_vocab = {'P': 0, '我': 1, '爱': 2, '你': 3, '好': 4, '吗': 5,  '人':6, '工':7, '智':8, '能':9}
src_idx2word = {i: w for i, w in enumerate(src_vocab)} #把单词的字典变成
{0: 'P', 1: '我', 2: '爱', 3: '你', 4: '好', 5: '吗', 6: '人', 7: '工',

8: '智', 9: '能'}

src_vocab_size = len(src_vocab) #输入编码器的词库数据长度
英文词库

tgt_vocab = {'P': 0, 'i': 1, 'love': 2, 'you': 3, 'how': 4, 'are': 5, 'artificial':6,'intelligence':7, 'S': 8, 'E': 9, '.': 10}
idx2word = {i: w for i, w in enumerate(tgt_vocab)} #把单词的字典变成


tgt_vocab_size = len(tgt_vocab)  #输入解码器的词库数据长度
src_len = 8  #编码器输入最大句子长度,长度不够的使用pad 代替
tgt_len = 7  #解码器输入最大句子长度,长度不够的使用pad 代替
Transformer 超参数

d_model = 512  #词嵌入维度
d_ff = 2048  #前馈神经网络的维度
d_k = d_v = 64  #多头注意力机制维度
n_layers = 6  #模型搭建的层数
n_heads = 8  #多头注意力机制的头数
在初始化部分,主要是定义Transformer模型的一些超参数及输入给模型的数据集。当然要想真正训练一个机器翻译的大模型,需要搜集大量的训练数据集,而这里为了演示代码的运行过程,定义了几个中英翻译的句子。每个句子的中英文的数据按照列表类型保存起来,其每列表有三部分组成,例如['我 爱 你 P', 'S i love you .', 'i love you . E']
(1)第一部分是中文数据“我 爱 你 P”,此数据会传递给Transformer模型的编码器,作为中文输入数据,其中字母“P”代表掩码字符。
(2)第二部分是对应的英文数据“S i love you .”,此数据会传递给Transformer模型的解码器,作为英文输入数据,其字母“S”代表单词start,Transformer模型碰到此单词“S”则说明模型需要开始预测下一个单词了。
(3)第三部分是英文数据“i love you . E”,此数据作为Transformer模型解码器的输出,其字母“E”,代表单词end,Transformer模型一旦碰到字母“E”,则说明模型需要结束预测。
得到训练集数据后,需要把每个汉字及每个英文单词都使用阿拉伯数字来代替以便后期进行词嵌入操作,例如“0”代表“P”,中文数据集中“1”代表“我”,英文数据集中“1”代表“i”等。需要把数据集按照数字依次排列,当然每个数字代表的数据集单词并不是固定的,只要确保不重复使用即可,其代码如下:
第15章/15.1.1/基于Transformer模型的机器翻译模型训练-第二部分

def make_data(sentences):
#把单词序列转换为数字序列
enc_inputs, dec_inputs, dec_outputs = [], [], []
for i in range(len(sentences)):
enc_input = [src_vocab[n] for n in sentences[0].split()]
#每次生成这一行sentence中encoder_input对应的id编码
for _ in range(src_len-len(enc_input)):
enc_input.append(0)
dec_input = [tgt_vocab[n] for n in sentences[1].split()]
#每次生成这一行sentence中decoder_input对应的id编码
for _ in range(tgt_len-len(dec_input)):
dec_input.append(0)
  1.     dec_output = [tgt_vocab[n] for n in sentences[i][2].split()]
  2.     #每次生成这一行sentence中decoder_output对应的id编码
  3.     for _ in range(tgt_len-len(dec_output)):
  4.         dec_output.append(0)
  5.     enc_inputs.append(enc_input)
  6.     dec_inputs.append(dec_input)
  7.     dec_outputs.append(dec_output)
复制代码
return torch.LongTensor(enc_inputs), torch.LongTensor(dec_inputs), torch.LongTensor(dec_outputs)
格式化输入的数据,把单词序列转换为数字序列,数据长度不够的使用0填充

enc_inputs, dec_inputs, dec_outputs = make_data(sentences)
定义 data loader,方便模型的训练

class MyDataSet(Data.Dataset):
def init(self, enc_inputs, dec_inputs, dec_outputs):
super(MyDataSet, self).init()
self.enc_inputs = enc_inputs
self.dec_inputs = dec_inputs
self.dec_outputs = dec_outputs
def len(self):
return self.enc_inputs.shape[0]
def getitem(self, idx):
return self.enc_inputs[idx], self.dec_inputs[idx], self.dec_outputs[idx]
加载数据集

loader = Data.DataLoader(MyDataSet(enc_inputs, dec_inputs, dec_outputs),batch_size=3, shuffle=True)
数据集处理完成后,还需要把数据集中英文与中文单词都删除,以便获取完全数字的数据。make_data函数的功能便是输入中英文数据集,获取编码器的数字输入数据及解码器的输入输出数字数据。由于定义了编码器与解码器最大句子长度,因此此函数执行完成后,其输入数据长度不足定义的句子长度的,需要使用数字“0”进行填充。代码执行完成后,输出如下:
enc_inputs:
tensor([[1, 2, 3, 0, 0, 0, 0, 0],
[3, 4, 5, 0, 0, 0, 0, 0],
[6, 7, 8, 9, 0, 0, 0, 0]])
dec_inputs:
tensor([[ 8,  1,  2,  3, 10,  0,  0],
[ 8,  4,  5,  3, 10,  0,  0],
[ 8,  6,  7, 10,  0,  0,  0]])
dec_outputs:
tensor([[ 1,  2,  3, 10,  9,  0,  0],
[ 4,  5,  3, 10,  9,  0,  0],
[ 6,  7, 10,  9,  0,  0,  0]])
可以看到编码器与解码器的输入数据都被格式化成了数字数据,使用此数据就可以执行Transformer模型相关的功能模块代码了,其代码如下:
第15章/15.1.1/基于Transformer模型的机器翻译模型训练-第三部分

词嵌入

class Embeddings(nn.Module):    #定义一个Embeddings类,继承自nn.Module
def init(self, vocab_size, d_model):
初始化函数,输入词汇表大小和词向量维度
  1.     super(Embeddings, self).__init__()  #调用父类的初始化函数
  2.     self.emb = nn.Embedding(vocab_size,d_model)
  3. #定义一个nn.Embedding对象,用于词向量映射
  4. def forward(self,x):  #前向传播函数,输入x
  5.     return self.emb(x)  #返回x的词向量映射结果
复制代码
位置编码 #定义一个PositionalEncoding类,继承自nn.Module

class PositionalEncoding(nn.Module):
#初始化函数,输入词向量维度、DropOut率和最大序列长度
def init(self, d_model, DropOut=0.1, max_len=5000):
super(PositionalEncoding, self).init()  #调用父类的初始化函数
#定义一个nn.DropOut对象,用于DropOut操作
self.DropOut = nn.DropOut(p=DropOut)
#初始化一个全零矩阵,用于位置编码
pe = torch.zeros(max_len, d_model)
#创建一个从0到max_len-1的位置向量
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 = x + self.pe[:x.size(0), :]  #将位置编码添加到x上
return self.DropOut(x)  #应用DropOut操作并返回结果
获取attention的pad mask,输入query序列和key序列 pad mask

def get_attn_pad_mask(seq_q, seq_k):
batch_size, len_q = seq_q.size()  #获取query序列的批次大小和序列长度
batch_size, len_k = seq_k.size()  #获取key序列的批次大小和序列长度
创建一个pad mask,1表示pad位置,0表示非pad位置

pad_attn_mask = seq_k.data.eq(0).unsqueeze(1)
扩展pad mask到[batch_size, len_q, len_k]的形状
  1. return pad_attn_mask.expand(batch_size, len_q, len_k)  
复制代码
获取attention的subsequence mask,输入序列 sequence mask

def get_attn_subsequence_mask(seq):
#获取attention的形状
attn_shape = [seq.size(0), seq.size(1), seq.size(1)]
创建一个上三角矩阵,1表示可以attention,0表示不可以attention

subsequence_mask = np.triu(np.ones(attn_shape), k=1)
将上三角矩阵转换为byte类型的tensor并返回

return torch.from_numpy(subsequence_mask).byte()
输入数据首先需要经过词嵌入与位置编码后,才可以传递给Transformer模型进行注意力机制的计算,这里并定义了pad_mask与sequence_mask矩阵的计算函数,方便计算编码器与解码器的掩码矩阵,然后搭建注意力机制计算代码,代码如下:
第15章/15.1.1/基于Transformer模型的机器翻译模型训练-第四部分

self attention 注意力机制,根据注意力机制的计算公式计算注意力机制

class ScaledDotProductAttention(nn.Module):
def init(self):
super(ScaledDotProductAttention, self).init()
def forward(self, Q, K, V, attn_mask):
#Q: [batch_size, len_q, d_k]                     #[2,5,512]
#K: [batch_size, len_k, d_k]                     #[2,5,512]
#V: [batch_size, len_v(=len_k), d_v]           #[ 2,5,512]
#attn_mask: [batch_size, seq_len, seq_len]    #[2,5,5]
#scores:[batch_size,len_q,len_k]                 #[2,5,5]
#计算注意力机制矩阵
scores = torch.matmul(Q, K.transpose(-1, -2)) / np.sqrt(d_k)
if attn_mask is not None: 判断是否存在掩码矩阵
#[2,5,5]若有掩码矩阵,需要置为一个很小的数
scores.masked_fill_(attn_mask, -1e9)
attn = nn.Softmax(dim=-1)(scores)#对最后一个维度(v)做softmax
#result: [batch_size, len_q, d_v]      #[2,5,512]
result = torch.matmul(attn, V)    #[2,5,512]  计算最终的注意力数据
return result, attn #attn注意力矩阵(用于可视化)
multi-head attention 多头注意力,分开8个头,分别做注意力机制

class MultiHeadAttention(nn.Module):
def init(self):
super(MultiHeadAttention, self).init()
#定义 Wq, Wk, Wv, Wo 四个矩阵
self.W_Q = nn.Linear(d_model, d_k * n_heads, bias=False)#512512
self.W_K = nn.Linear(d_model, d_k * n_heads, bias=False)#512
512
self.W_V = nn.Linear(d_model, d_v * n_heads, bias=False)#512512
self.W_O = nn.Linear(n_heads * d_v, d_model, bias=False)#512
512
def forward(self, input_Q, input_K, input_V, attn_mask):
#input_Q: [batch_size, len_q, d_model]           #[2, 5, 512]
#input_K: [batch_size, len_k, d_model]           #[2, 5, 512]
#input_V: [batch_size, len_v(=len_k), d_model]  #[2, 5, 512]
#attn_mask: [batch_size, seq_len, seq_len]       #[2, 5, 5]
residual, batch_size = input_Q, input_Q.size(0)
[ 25512]保存输入数据,便于计算残差
  1.     #B: batch_size, S:seq_len, D: dim
  2.     #(B,S,D)-proj-> (B,S,D_new)-split->(B,S,Head,W)-trans->(B,Head,S,W)
  3.     #Q: [batch_size, n_heads, len_q, d_k] #[2, 8, 5, 64]
  4.     #计算多头注意力机制的QKV矩
  5.     Q = self.W_Q(input_Q).view(batch_size, -1, n_heads, d_k).transpose(1, 2)
  6.     #K: [batch_size, n_heads, len_k, d_k]  #[2, 8, 5, 64]
  7.     K = self.W_K(input_K).view(batch_size, -1, n_heads, d_k).transpose(1, 2)
  8.     #V: [batch_size, n_heads, len_v(=len_k), d_v] #[2, 8, 5, 64]
  9.     V = self.W_V(input_V).view(batch_size, -1, n_heads, d_v).transpose(1, 2)
  10.     #attn_mask:[batch_size,seq_len,seq_len] ->->->->
  11.     #->->->->->[batch_size,n_heads,seq_len,seq_len]计算掩码矩阵
  12.     attn_mask = attn_mask.unsqueeze(1).repeat(1, n_heads, 1, 1)#[2,8,5,5]
  13.     #result:[batch_size,n_heads,len_q,d_v]                   #[2,8,5,64]
  14.     #attn:[batch_size,n_heads,len_q, len_k]                  #[2,8,5,5]
  15.     #计算多头注意力机制
  16.     result, attn = ScaledDotProductAttention()(Q, K, V, attn_mask)
  17.     #result:[batch_size,n_heads,len_q,d_v]->[batch_size,len_q,n_heads*d_v]
  18.     #contat heads  #result [2,5,512] #合并8个头的数据
  19.     result = result.transpose(1, 2).reshape(batch_size, -1, n_heads * d_v)
  20.     #[batch_size, len_q, d_model]#[2,5,512]#Wo线性变换
  21.     output = self.W_O(result)
  22.     #[2,5,512]残差连接与数据归一化
  23.     return nn.LayerNorm(d_model)(output + residual), attn  
复制代码
feed forward前馈神经网络

class PoswiseFeedForwardNet(nn.Module):
def init(self):
super(PoswiseFeedForwardNet, self).init()
self.fc = nn.Sequential(
nn.Linear(d_model, d_ff, bias=False), #W1 [512,2048]
nn.ReLU(),                                  #max(0,w1*x+b1)
nn.Linear(d_ff, d_model, bias=False))  #W2 [2048,512]
def forward(self, inputs):
#inputs: [batch_size, seq_len, d_model]
根据前馈神经网络的公式计算前馈神经网络数据
  1.     residual = inputs
  2.     output = self.fc(inputs)
  3.     #[batch_size, seq_len, d_model]
  4.     return nn.LayerNorm(d_model)(output + residual)  
复制代码
搭建编码器与解码器的功能模块代码,主要包含注意力机制与多头注意力机制的代码实现及前馈神经网络的代码实现,有了以上的功能代码模块,便可以搭建整个Transformer模型了,代码如下:
第15章/15.1.1/基于Transformer模型的机器翻译模型训练-第五部分

解码器搭建

class EncoderLayer(nn.Module):
def init(self):
super(EncoderLayer, self).init()
self.enc_self_attn = MultiHeadAttention()
self.pos_ffn = PoswiseFeedForwardNet()
def forward(self, enc_inputs, enc_self_attn_mask):
#enc_inputs: [batch_size, src_len, d_model]
#mask矩阵(pad mask or sequence mask)
#enc_self_attn_mask: [batch_size, src_len, src_len]
#enc_outputs: [batch_size, src_len, d_model]  [2,5,512]
#attn: [batch_size, n_heads, src_len, src_len]  [2,5,5]
enc_outputs, attn = self.enc_self_attn(enc_inputs, enc_inputs,
enc_inputs,enc_self_attn_mask)
enc_outputs = self.pos_ffn(enc_outputs)           #[2,5,512]
#enc_outputs: [batch_size, src_len, d_model]
return enc_outputs, attn
class Encoder(nn.Module):
def init(self):
super(Encoder, self).init()
self.src_emb = Embeddings(src_vocab_size, d_model)  #Embedding
self.pos_emb = PositionalEncoding(d_model)  #Transformer中位置编码
self.layers = nn.ModuleList([EncoderLayer() for _ in range(n_layers)])
  1. def forward(self, enc_inputs):
  2.     #enc_inputs: [batch_size, src_len]                       #[2,5]
  3.     enc_outputs = self.src_emb(enc_inputs)                    #[2, 5, 512]
  4.     #enc_outputs [batch_size, src_len, src_len]              #[2, 5, 512]
  5.     enc_outputs = self.pos_emb(enc_outputs.transpose(0,1)).transpose(0, 1)
  6.     #Encoder输入 pad mask矩阵 #[batch_size, src_len, src_len]    [2,5,5]
  7.     enc_self_attn_mask = get_attn_pad_mask(enc_inputs, enc_inputs)  
  8.     enc_self_attns = []  #这个主要是为了画热力图,用来看各个词之间的关系
  9.     for layer in self.layers:  #for循环访问nn.ModuleList,进行6次循环堆叠
  10.         #enc_outputs: [batch_size, src_len, d_model],         [2, 5, 512]
  11.         #enc_self_attn: [batch_size, n_heads, src_len, src_len] [2,8,5,5]
  12.         enc_outputs, enc_self_attn = layer(enc_outputs,enc_self_attn_mask)  
  13.         enc_self_attns.append(enc_self_attn)  #可视化
  14.     return enc_outputs, enc_self_attns #enc_outputs           [2, 5, 512]
复制代码
解码器搭建

class DecoderLayer(nn.Module):
def init(self):
super(DecoderLayer, self).init()
#decoder 自注意力机制
self.dec_self_attn = MultiHeadAttention()
#decoder enc_dec_attention交互层
self.dec_enc_attn =  MultiHeadAttention()
#decoder 前馈神经网络
self.pos_ffn = PoswiseFeedForwardNet()
def forward(self, dec_inputs, enc_outputs, dec_self_attn_mask, dec_enc_attn_mask):
#dec_inputs: [batch_size, tgt_len, d_model]              #[2,5,512]
#dec_self_attn_mask: [batch_size, tgt_len, tgt_len]    #[2,5,5]
#dec_outputs: [batch_size, tgt_len, d_model]             #[2,5,512]
#dec_self_attn: [batch_size, n_heads, tgt_len, tgt_len]  #[2,8,5,5]
#decoder 自注意力机制,Q,K,V来自Decoder的输入            #[2,5,512]
dec_outputs, dec_self_attn = self.dec_self_attn(dec_inputs, dec_inputs,
dec_inputs,dec_self_attn_mask)
#dec_outputs: [batch_size, tgt_len, d_model]             #[2,5,512]
#enc_outputs: [batch_size, src_len, d_model]             #[2,5,512]
#dec_enc_attn: [batch_size, h_heads, tgt_len, src_len]   #[2,8,5,5]
#dec_enc_attn_mask: [batch_size, tgt_len, src_len]      #[2,5,5]
#这里encoder输入长度与decoder输入句子长度不一定相等,
#dec_enc_Attention层的Q(来自decoder), K,V(来自encoder) #[2,5,512]
dec_outputs, dec_enc_attn = self.dec_enc_attn(dec_outputs, enc_outputs,
enc_outputs,dec_enc_attn_mask)
dec_outputs = self.pos_ffn(dec_outputs)                   #[2,5,512]
#dec_self_attn, dec_enc_attn两个矩阵是为了可视化
return dec_outputs, dec_self_attn, dec_enc_attn
class Decoder(nn.Module):
def init(self):
super(Decoder, self).init()
self.tgt_emb = Embeddings(tgt_vocab_size, d_model)
self.pos_emb = PositionalEncoding(d_model)
#DecoderLayer block 一共6层,跟encoder 相同
self.layers = nn.ModuleList([DecoderLayer() for _ in range(n_layers)])
def forward(self, dec_inputs, enc_inputs, enc_outputs):
#dec_inputs: [batch_size, tgt_len]           [2,5]
#enc_inputs: [batch_size, src_len]           [2,5]
#enc_outputs 用在Encoder-Decoder Attention交互层
#enc_outputs: [batch_size, src_len, d_model] [2,5,512]
dec_outputs = self.tgt_emb(dec_inputs)      #[2,5,512]
#dec_outputs 位置编码+embedding 词嵌入     #[2,5,512]
dec_outputs = self.pos_emb(dec_outputs.transpose(0, 1)).transpose(0, 1)
#Decoder输入序列的pad mask矩阵             #[2,5,5]
dec_self_attn_pad_mask = get_attn_pad_mask(dec_inputs, dec_inputs)
#Decoder输入序列的sequence mask矩阵        #[2,5,5]
dec_self_attn_subsequence_mask = get_attn_subsequence_mask(dec_inputs)
#Decoder中把pad mask + sequence mask
#既屏蔽了pad的信息,也屏蔽了未来的信息 #[2,5,5]
dec_self_attn_mask = torch.gt((dec_self_attn_pad_mask +
dec_self_attn_subsequence_mask),0)
#dec_enc mask主要用于encoder-decoder attention交互层
#因为dec_enc_attn输入是encoder的K,V,decoder的Q
#求Attention时是用v1,v2,..vm去加权,要把pad对应的v_i的相关系数设为0
#dec_inputs提供expand的size
#[batc_size, tgt_len, src_len]这里tgt_len与src_len不一定相等#[2,5,5]
dec_enc_attn_mask = get_attn_pad_mask(dec_inputs, enc_inputs)
#用于可视化的矩阵,一个Self-Attention 一个enc_dec_attention
dec_self_attns, dec_enc_attns = [], []
for layer in self.layers: #遍历decoder block n = 6
#dec_outputs:[batch_size,tgt_len,d_model]decoder的输入[2,5,512]
#enc_outputs:[batch_size,src_len,d_model]encoder的输入[2,5,512]
#dec_self_attn:[batch_size,n_heads,tgt_len,tgt_len]   [2,8,5,5]
#dec_enc_attn:[batch_size,h_heads,tgt_len,src_len]    [2,8,5,5]
#Decoder的Block是上一个Block的输出dec_outputs(变化矩阵)
#Encoder网络的输出enc_outputs(固定矩阵)
dec_outputs, dec_self_attn, dec_enc_attn = layer(dec_outputs,
enc_outputs, dec_self_attn_mask,dec_enc_attn_mask)
dec_self_attns.append(dec_self_attn)      #可视化矩阵 [2,8,5,5]
dec_enc_attns.append(dec_enc_attn)        #可视化矩阵 [2,8,5,5]
#dec_outputs: [batch_size, tgt_len, d_model] #[2,5,512]
return dec_outputs, dec_self_attns, dec_enc_attns
Transformer 模型搭建

class Transformer(nn.Module):
def init(self):
super(Transformer, self).init()
self.encoder = Encoder() #编码器
self.decoder = Decoder() #解码器
#最终模型的输出经过linear层进行shape转换
self.projection = nn.Linear(d_model, tgt_vocab_size, bias=False)
  1. def forward(self, enc_inputs, dec_inputs):
  2.     #enc_inputs: [batch_size, src_len] [2,5]
  3.     #dec_inputs: [batch_size, tgt_len] [2,5]
  4.     #enc_outputs: [batch_size, src_len, d_model], [2,5,512]
  5.     #enc_self_attns: [n_layers, batch_size, n_heads, src_len, src_len]
  6.     #经过Encoder网络后,输出[batch_size, src_len, d_model] [2,5,512]
  7.     enc_outputs, enc_self_attns = self.encoder(enc_inputs)
  8.     #dec_outputs: [batch_size, tgt_len, d_model]           [2,5,512]
  9.     #dec_self_attns: [n_layers, batch_size, n_heads, tgt_len, tgt_len]
  10.     #dec_enc_attn: [n_layers, batch_size, tgt_len, src_len][8,2,5,5]
  11.     dec_outputs, dec_self_attns, dec_enc_attns = self.decoder(dec_inputs, enc_inputs, enc_outputs)
  12.     #dec_outputs: [batch_size, tgt_len, d_model]       [2,5,512]->
  13.     #dec_logits: [batch_size, tgt_len, tgt_vocab_size] [2,5,10]
  14.     #线性变换,把输出数据维度转换到序列长度
  15.     dec_logits = self.projection(dec_outputs)
  16.     #softmax输出,得到每个输出的概率,概率和为1
  17.     dec_logits = F.log_softmax(dec_logits, dim=-1)
  18.     return (dec_logits.view(-1, dec_logits.size(-1)),
  19.                            enc_self_attns, dec_self_attns, dec_enc_attns)
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册