import torch.nn as nn from .attention import MultiHeadAttention #引进多头注意力模块 from .module import PositionalEncoding, PositionwiseFeedForward #位置编码和前馈网络 from .utils import get_non_pad_mask, get_attn_pad_mask #padding mask:填充补齐使得输入长度相同。attention mask: class Encoder(nn.Module): """Encoder of Transformer including self-attention and feed forward. """ def __init__(self, d_input=320, n_layers=6, n_head=8, d_k=64, d_v=64, d_model=512, d_inner=2048, dropout=0.1, pe_maxlen=5000): super(Encoder, self).__init__() # parameters self.d_input = d_input #输入维度 self.n_layers = n_layers #编码解码层数 self.n_head = n_head #自注意力头数 self.d_k = d_k #键矩阵维度 self.d_v = d_v #值矩阵维度 self.d_model = d_model #模型维度 self.d_inner = d_inner #前馈网络隐层神经元个数(维度) self.dropout_rate = dropout #信息漏失率 self.pe_maxlen = pe_maxlen #位置编码最大长度 # use linear transformation with layer norm to replace input embedding self.linear_in = nn.Linear(d_input, d_model) #全连接,输入为batch size 和size self.layer_norm_in = nn.LayerNorm(d_model) #层归一化 self.positional_encoding = PositionalEncoding(d_model, max_len=pe_maxlen) #位置编码 self.dropout = nn.Dropout(dropout) #dropout self.layer_stack = nn.ModuleList([ EncoderLayer(d_model, d_inner, n_head, d_k, d_v, dropout=dropout) for _ in range(n_layers)]) #实现n_layers次编码器 #nn.ModuleList,它是一个储存不同 module,并自动将每个 module 的 parameters 添加到网络之中的容器。 def forward(self, padded_input, input_lengths, return_attns=False): """ Args: padded_input: N x T x D input_lengths: N Returns: enc_output: N x T x H """ enc_slf_attn_list = [] # Prepare masks non_pad_mask = get_non_pad_mask(padded_input, input_lengths=input_lengths) #没有填充前 length = padded_input.size(1) #获得填充维度 slf_attn_mask = get_attn_pad_mask(padded_input, input_lengths, length) #获得填充结果 # Forward # 进入编码器前对数据的处理 enc_output = self.dropout( self.layer_norm_in(self.linear_in(padded_input)) + self.positional_encoding(padded_input)) #对数据线性变换(将320维的输入变为512维)后归一化,然后加上位置编码后的数据进行dropout for enc_layer in self.layer_stack: #进入编码器 enc_output, enc_slf_attn = enc_layer( enc_output, non_pad_mask=non_pad_mask, slf_attn_mask=slf_attn_mask)#经过编码器输出编码结果和注意力 if return_attns: #默认不对每层的注意力形成列表形式 enc_slf_attn_list += [enc_slf_attn] if return_attns: #默认为false return enc_output, enc_slf_attn_list return enc_output, #返回最后层编码器输出 class EncoderLayer(nn.Module): """Compose with two sub-layers. 1. A multi-head self-attention mechanism 2. A simple, position-wise fully connected feed-forward network. """ def __init__(self, d_model, d_inner, n_head, d_k, d_v, dropout=0.1): super(EncoderLayer, self).__init__() self.slf_attn = MultiHeadAttention( n_head, d_model, d_k, d_v, dropout=dropout) #多头注意力实例化 self.pos_ffn = PositionwiseFeedForward( d_model, d_inner, dropout=dropout) #前馈网络实例化 def forward(self, enc_input, non_pad_mask=None, slf_attn_mask=None): enc_output, enc_slf_attn = self.slf_attn( enc_input, enc_input, enc_input, mask=slf_attn_mask) #获得多头注意力的输出 enc_output *= non_pad_mask #防止经过注意力层后数据的长度发生变化 enc_output = self.pos_ffn(enc_output) #前馈网络的输出 enc_output *= non_pad_mask return enc_output, enc_slf_attn #返回一个编码器的输出