详细分解Transformer各部件总结
生活随笔
收集整理的這篇文章主要介紹了
详细分解Transformer各部件总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Transformer的介紹
-
Transformer的優勢
- # 1. Transformer能夠利用分布式GPU進行并行訓練,提升模型訓練效率 # 2. 在分析預測更長文本時,捕捉間隔較長的語義關聯效果更好, 作用:基于seq2seq架構的transformer模型可以完成NLP領域研究的典型任務,如機器翻譯,文本生成等,同時又可以構建預訓練語言模型,用于其他任務
-
Transformer架構
-
輸入部分
- 源文本嵌入層及其位置編碼器
- 文本嵌入(Embedding)作用:無論源文本嵌入還是目標文本嵌入,都是為了將文本中詞匯的數字表示轉變為向量表示,希望在這樣的高維空間捕捉詞匯之間的關系
- 位置編碼器的作用:在編碼器結構中,并沒有對詞匯位置信息進行處理,因此需要在Embdeding層后加入位置編碼器,將詞匯位置不同可能會產生不同語義的信息加入到詞嵌入張量中,以彌補位置信息的缺失
- 目標文本嵌入層及其位置編碼器
- 源文本嵌入層及其位置編碼器
-
輸出部分
- 線性層
- softmax層
-
編碼器部分
- N個編碼器層堆疊而成
- 每個編碼器由兩個子層連接結構組成
- 第一個子層鏈接包含一個多頭自注意力層和規范化層及一個殘差連接
- 第二個子層連接結構包含一個前饋全連接子層和規范化層及一個殘差連接
-
解碼器部分
- N個解碼器層堆疊而成
- 每個解碼器由三個子層連接結構組成
- 第一個子層鏈接包含一個多頭自注意力層和規范化層及一個殘差連接
- 第二個子層鏈接包含一個多頭自注意力層和規范化層及一個殘差連接
- 第三個子層連接結構包含一個前饋全連接子層和規范化層及一個殘差連接
1. 輸入部分
-
文本詞嵌入
-
作用:對輸入文本數值化以方便擬合算法
- import math import torch import torch.nn as nn class Embeddings(nn.Module):def __init(self, d_model, vocab):"""d_model: 詞嵌入的維度vocab: 詞表的大小"""super(Emdedings,self).__init()self.lut = nn.Embedding(vocab, d_model)self.d_model = d_modeldef forward(self, x):return self.lut(x) * math.sqrt(self.d_model)
-
-
位置編碼器
-
作用:因為在transformer的編碼器結構中,并沒有對詞匯位置信息的處理,所以需要在embedding層后加入位置編碼器,將詞匯位置不同可能會產生不同語義的信息加入到詞嵌入張量中,以彌補位置信息的缺失
- class PositionalEncoding(nn.Module):"""d_model: 詞嵌入的維度dropout: 置0比率max_len: 句子最大長度"""def __init__(self, d_model, dropout, max_len=5000):super(PositionalEncoding, self).__init__()self.dropout = nn.Dropout(p=dropout)# 初始化一個位置編碼矩陣,它是0陣,大小維max_len * d_modelpe = torch.zeros(max_len, d_model)# 絕對位置矩陣,詞匯的絕對位置就是用它的索引去表示position = torch.arange(0, max_len).unsqueeze(1)# 將位置信息加入到位置編碼矩陣中,將絕對位置矩陣有max_len*1變成max_len*d_model, 覆蓋原來的初始化位置編碼矩陣# 先需要一個1*d_model的變換矩陣div_term,其實div_term是一個1*d_model/2的矩陣div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(10000.)/d_model))# 位置編碼數值控制在-1,1之間有助于梯度下降pe[:, 0::2] = torch.sin(position*div_term)pe[:, 1::2] = torch.cos(position*div_term)# 現在pe是一個二維矩陣,embedded之前要擴展一個維度pe = pe.unsqueeze(0)# 將位置編碼矩陣注冊成模型的buffer,對模型效果有幫助,卻不是模型結構中的超參數,不需要隨著優化步驟進行更新的增益對象# 注冊之后我們可以在模型保存后重加載時和模型結構與參數一同加載self.register_buffer('pe', pe)def forward(self, x):# x.size(1),根據輸入句子的長度,截取pe的范圍print("位置編碼:", Variable(self.pe[:, :x.size(1)]).size())x = x + Variable(self.pe[:, :x.size(1)], requires_grad=False)return self.dropout(x)
-
2. 編碼器部分
-
多頭注意力機制
-
作用:多頭的本質是多個獨立的attention計算,作為一個集成的作用,防止過擬合
- # 注意力機制 def attention(query, key, value, mask=None, dropout=None):# 詞嵌入維度大小d_k = query.size(-1)# 計算注意力矩陣scorescores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)# 判斷是否使用掩碼張量if mask:scores = scores.masked_fill(mask == 0, -1e9)# 對scores進行最后一維進行softmaxp_atten = F.softmax(scores, dim=-1)if dropout:p_atten = dropout(p_atten)return torch.matmul(p_atten, value), p_attendef clone(module, N):"""實現模型深拷貝:param module:要拷貝的目標網絡層:param N: 拷貝數量"""return nn.ModuleList([copy.deepcopy(module) for _ in range(N)])class MultiHeadedAttention(nn.Module):"""多頭注意力機制head:頭數embedding_dim: 詞嵌入維度dropout: 置零率"""def __init__(self, head, embedding_dim, dropout=0.1):super(MultiHeadedAttention, self).__init__()self.head = headself.attn = Noneself.dropout = nn.Dropout(p=dropout)# 判斷head能否整除詞嵌入維度assert embedding_dim % head == 0self.d_k = embedding_dim // head# 4表示多頭注意力中Q,K,V各需要一個,最后拼接的矩陣還需要一個self.linears = clone(nn.Linear(embedding_dim, embedding_dim), 4)def forward(self, query, key, value, mask=None):if mask:mask = mask.unsqueeze(1)# 獲取batch size大小batch_size = query.size(0)# 多頭處理環節, 將embedding.size變為head.size * d_k.size# 對二、三維進行轉置操作,讓句子長度維度和詞向量維度能夠相鄰,這樣注意力機制才能找到詞義與句子的位置關系query, key, value = [model(x).view(batch_size, -1, self.head, self.d_k).transpose(1, 2) for model, x in zip(self.linears, (query, key, value))]# 接下來傳入attentionx, self.attn = attention(query, key, value, mask=mask, dropout=self.dropout)# 獲得每個頭計算結果組成的4維張量x = x.transpose(1, 2).contiguous().view(batch_size, -1, self.head*self.d_k)return self.linears[-1](x)
-
-
前饋全連接層
-
作用:考慮注意力機制擬合程度不夠,故意增加兩層網絡來增強模型的能力
- class PositionWiseFeedForward(nn.Module):"""前饋全連接層d_model: 詞嵌入的維度d_ff: 全連接層維度"""def __init__(self, d_model, d_ff, dropout=0.1):super(PositionWiseFeedForward, self).__init__()self.fc1 = nn.Linear(d_model, d_ff)self.fc2 = nn.Linear(d_ff, d_model)self.dropout = nn.Dropout(p=dropout)def forward(self, x):return self.fc2(self.dropout(F.relu(self.fc1(x))))
-
-
規范化層
-
作用:有助于模型收斂,防止過擬合
- class LayerNorm(nn.Module):"""數據規范化features: 詞嵌入的維度"""def __init__(self, features, eps=1e-6):super(LayerNorm, self).__init__()# nn.parameter代表模型參數self.a = nn.Parameter(torch.ones(features))self.b = nn.Parameter(torch.zeros(features))self.eps = epsdef forward(self, x):mean = x.mean(-1, keepdim=True)std = x.std(-1, keepdim=True)return self.a*(x-mean) / (std+self.eps) + self.b
-
-
殘差連接
-
作用:很好解決深度模型退化問題,同時使模型收斂更快,前后向傳播更加順暢
- class sublayerConnection(nn.Module):"""子層殘差連接結構size: 詞嵌入的維度"""def __init__(self, size, dropout=0.1):super(SublayerConnection, self).__init__()# 規范化層self.norm = LayerNorm(size)self.dropout = nn.Dropout(p=dropout)def forward(self, x, sublayer):return x + self.dropout(sublayer(self.norm(x)))
-
-
編碼器層
-
作用:作為編碼器組成部分,完成對輸入的特征提取
- class EncoderLayer(nn.Module):"""編碼器size: 詞嵌入維度self_attn: 多頭自注意力機制feed_forward: 前饋全連接層dropout: 置零比例"""def __init__(self, size, self_attn, feed_forward, dropout):super(EncoderLayer, self).__init__()self.self_attn = self_attnself.feed_forward = feed_forwardself.size = size# 編碼器層有兩個殘差連接結構self.sublayer = clone(SublayerConnection(size, dropout), 2)def forward(self, x, mask):x = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, mask))return self.sublayer[1](x, self.feed_forward)
-
-
編碼器
-
作用:對輸入的特征提取,由若干個編碼層組成
- class Encoder(nn.Module):"""實現編碼器encoder_layer: 編碼器層num_layer: 編碼器層的個數"""def __init__(self, encoder_layer, num_layer):super(Encoder, self).__init__()self.layers = clone(encoder_layer, num_layer)self.norm = LayerNorm(encoder_layer.size)def forward(self, x, mask):for layer in self.layers:x = layer(x, mask)return self.norm(x)
-
3. 解碼器部分
-
解碼器層:
-
作用:根據給定的輸入向目標進行特征提取
- class DecoderLayer(nn.Module):"""解碼器層size: 詞嵌入的維度大小self_attn: 多頭自注意力機制src_attn: 多頭注意力機制feed_forward: 前饋神經網絡"""def __init__(self, size, self_attn, src_attn, feed_forward, dropout):super(DecoderLayer, self).__init__()self.size = sizeself.self_attn = self_attnself.src_attn = src_attnself.feed_forward = feed_forwardself.dropout = dropoutself.sublayer = clone(SublayerConnection(size, dropout), 3)def forward(self, x, memory, source_mask, target_mask):"""x: 上一層輸出memory: 編碼器語義存儲變量source_mask: 源數據掩碼張量, 遮掩住對結果沒有意義的字符target_mask: 目標數據掩碼張量,不希望模型利用后續信息"""m = memoryx = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, target_mask))x = self.sublayer[1](x, lambda x: self.src_attn(x, m, m, source_mask))return self.sublayer[3](x, self.feed_forward)
-
-
編碼器
-
作用:提取encoder輸出的特征
- class Decoder(nn.Module):"""解碼器decoder_layer: 解碼器層num_layer: 解碼器層個數"""def __init__(self, decoder_layer, num_layer):super(Decoder, self).__init__()self.layers = clone(decoder_layer, num_layer)self.norm = LayerNorm(decoder_layer.size)def forward(self, x, memory, source_mask, target_mask):for layer in self.layers:x = layer(x, memory, source_mask, target_mask)return self.norm(x)
-
4. 輸出部分
-
輸出結構
- class Generator(nn.Module):"""輸出層結構d_model: 詞嵌入維度vocab_size: 詞表大小"""def __init__(self, d_model, vocab_size):super(Generator, self).__init__()self.project = nn.Linear(d_model, vocab_size)def forward(self, x):return F.log_softmax(self.project(x), dim=-1)
總結
以上是生活随笔為你收集整理的详细分解Transformer各部件总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 模型训练加速方法
- 下一篇: python的模块、包、库区别。导入包/