【變形金剛03】使用 Pytorch 開始構建transformer

?

一、說明

????????在本教程中,我們將使用 PyTorch 從頭開始構建一個基本的轉換器模型。Vaswani等人在論文“注意力是你所需要的一切”中引入的Transformer模型是一種深度學習架構,專為序列到序列任務而設計,例如機器翻譯和文本摘要。它基于自我注意機制,已成為許多最先進的自然語言處理模型的基礎,如GPT和BERT。

二、準備活動

????????若要生成轉換器模型,我們將按照以下步驟操作:

  1. 導入必要的庫和模塊
  2. 定義基本構建塊:多頭注意力、位置前饋網絡、位置編碼
  3. 構建編碼器和解碼器層
  4. 組合編碼器和解碼器層以創建完整的轉換器模型
  5. 準備示例數據
  6. 訓練模型

????????讓我們從導入必要的庫和模塊開始。

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import math
import copy

現在,我們將定義轉換器模型的基本構建基塊。

三、多頭注意力

圖2.多頭注意力(來源:作者創建的圖像)

????????多頭注意力機制計算序列中每對位置之間的注意力。它由多個“注意頭”組成,用于捕獲輸入序列的不同方面。

class MultiHeadAttention(nn.Module):def __init__(self, d_model, num_heads):super(MultiHeadAttention, self).__init__()assert d_model % num_heads == 0, "d_model must be divisible by num_heads"self.d_model = d_modelself.num_heads = num_headsself.d_k = d_model // num_headsself.W_q = nn.Linear(d_model, d_model)self.W_k = nn.Linear(d_model, d_model)self.W_v = nn.Linear(d_model, d_model)self.W_o = nn.Linear(d_model, d_model)def scaled_dot_product_attention(self, Q, K, V, mask=None):attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)if mask is not None:attn_scores = attn_scores.masked_fill(mask == 0, -1e9)attn_probs = torch.softmax(attn_scores, dim=-1)output = torch.matmul(attn_probs, V)return outputdef split_heads(self, x):batch_size, seq_length, d_model = x.size()return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)def combine_heads(self, x):batch_size, _, seq_length, d_k = x.size()return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)def forward(self, Q, K, V, mask=None):Q = self.split_heads(self.W_q(Q))K = self.split_heads(self.W_k(K))V = self.split_heads(self.W_v(V))attn_output = self.scaled_dot_product_attention(Q, K, V, mask)output = self.W_o(self.combine_heads(attn_output))return output

????????MultiHeadAttention 代碼使用輸入參數和線性變換層初始化模塊。它計算注意力分數,將輸入張量重塑為多個頭部,并將所有頭部的注意力輸出組合在一起。前向方法計算多頭自我注意,允許模型專注于輸入序列的某些不同方面。

四、位置前饋網絡

class PositionWiseFeedForward(nn.Module):def __init__(self, d_model, d_ff):super(PositionWiseFeedForward, self).__init__()self.fc1 = nn.Linear(d_model, d_ff)self.fc2 = nn.Linear(d_ff, d_model)self.relu = nn.ReLU()def forward(self, x):return self.fc2(self.relu(self.fc1(x)))

PositionWiseFeedForward 類擴展了 PyTorch 的 nn。模塊并實現按位置的前饋網絡。該類使用兩個線性轉換層和一個 ReLU 激活函數進行初始化。forward 方法按順序應用這些轉換和激活函數來計算輸出。此過程使模型能夠在進行預測時考慮輸入元素的位置。

五、位置編碼

????????位置編碼用于注入輸入序列中每個令牌的位置信息。它使用不同頻率的正弦和余弦函數來生成位置編碼。

class PositionalEncoding(nn.Module):def __init__(self, d_model, max_seq_length):super(PositionalEncoding, self).__init__()pe = torch.zeros(max_seq_length, d_model)position = torch.arange(0, max_seq_length, 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)self.register_buffer('pe', pe.unsqueeze(0))def forward(self, x):return x + self.pe[:, :x.size(1)]

PositionalEncoding 類使用 d_model 和 max_seq_length 輸入參數進行初始化,從而創建一個張量來存儲位置編碼值。該類根據比例因子div_term分別計算偶數和奇數指數的正弦和余弦值。前向方法通過將存儲的位置編碼值添加到輸入張量中來計算位置編碼,從而使模型能夠捕獲輸入序列的位置信息。

現在,我們將構建編碼器層和解碼器層。

六、編碼器層

圖3.變壓器網絡的編碼器部分(來源:圖片來自原文)

編碼器層由多頭注意力層、位置前饋層和兩個層歸一化層組成。

class EncoderLayer(nn.Module):def __init__(self, d_model, num_heads, d_ff, dropout):super(EncoderLayer, self).__init__()self.self_attn = MultiHeadAttention(d_model, num_heads)self.feed_forward = PositionWiseFeedForward(d_model, d_ff)self.norm1 = nn.LayerNorm(d_model)self.norm2 = nn.LayerNorm(d_model)self.dropout = nn.Dropout(dropout)def forward(self, x, mask):attn_output = self.self_attn(x, x, x, mask)x = self.norm1(x + self.dropout(attn_output))ff_output = self.feed_forward(x)x = self.norm2(x + self.dropout(ff_output))return x

類使用輸入參數和組件進行初始化,包括一個多頭注意模塊、一個 PositionWiseFeedForward 模塊、兩個層規范化模塊和一個 dropout 層。前向方法通過應用自注意、將注意力輸出添加到輸入張量并規范化結果來計算編碼器層輸出。然后,它計算按位置的前饋輸出,將其與歸一化的自我注意輸出相結合,并在返回處理后的張量之前對最終結果進行歸一化。

七、解碼器層

圖4.變壓器網絡的解碼器部分(Souce:圖片來自原始論文)

解碼器層由兩個多頭注意力層、一個位置前饋層和三個層歸一化層組成。

class DecoderLayer(nn.Module):def __init__(self, d_model, num_heads, d_ff, dropout):super(DecoderLayer, self).__init__()self.self_attn = MultiHeadAttention(d_model, num_heads)self.cross_attn = MultiHeadAttention(d_model, num_heads)self.feed_forward = PositionWiseFeedForward(d_model, d_ff)self.norm1 = nn.LayerNorm(d_model)self.norm2 = nn.LayerNorm(d_model)self.norm3 = nn.LayerNorm(d_model)self.dropout = nn.Dropout(dropout)def forward(self, x, enc_output, src_mask, tgt_mask):attn_output = self.self_attn(x, x, x, tgt_mask)x = self.norm1(x + self.dropout(attn_output))attn_output = self.cross_attn(x, enc_output, enc_output, src_mask)x = self.norm2(x + self.dropout(attn_output))ff_output = self.feed_forward(x)x = self.norm3(x + self.dropout(ff_output))return x

解碼器層使用輸入參數和組件進行初始化,例如用于屏蔽自我注意和交叉注意力的多頭注意模塊、PositionWiseFeedForward 模塊、三層歸一化模塊和輟學層。

轉發方法通過執行以下步驟來計算解碼器層輸出:

  1. 計算掩蔽的自我注意輸出并將其添加到輸入張量中,然后進行 dropout 和層歸一化。
  2. 計算解碼器和編碼器輸出之間的交叉注意力輸出,并將其添加到規范化的掩碼自注意力輸出中,然后進行 dropout 和層規范化。
  3. 計算按位置的前饋輸出,并將其與歸一化交叉注意力輸出相結合,然后是壓差和層歸一化。
  4. 返回已處理的張量。

這些操作使解碼器能夠根據輸入和編碼器輸出生成目標序列。

現在,讓我們組合編碼器和解碼器層來創建完整的轉換器模型。

八、變壓器型號

圖5.The Transformer Network(來源:圖片來源于原文)

將它們全部合并在一起:

class Transformer(nn.Module):def __init__(self, src_vocab_size, tgt_vocab_size, d_model, num_heads, num_layers, d_ff, max_seq_length, dropout):super(Transformer, self).__init__()self.encoder_embedding = nn.Embedding(src_vocab_size, d_model)self.decoder_embedding = nn.Embedding(tgt_vocab_size, d_model)self.positional_encoding = PositionalEncoding(d_model, max_seq_length)self.encoder_layers = nn.ModuleList([EncoderLayer(d_model, num_heads, d_ff, dropout) for _ in range(num_layers)])self.decoder_layers = nn.ModuleList([DecoderLayer(d_model, num_heads, d_ff, dropout) for _ in range(num_layers)])self.fc = nn.Linear(d_model, tgt_vocab_size)self.dropout = nn.Dropout(dropout)def generate_mask(self, src, tgt):src_mask = (src != 0).unsqueeze(1).unsqueeze(2)tgt_mask = (tgt != 0).unsqueeze(1).unsqueeze(3)seq_length = tgt.size(1)nopeak_mask = (1 - torch.triu(torch.ones(1, seq_length, seq_length), diagonal=1)).bool()tgt_mask = tgt_mask & nopeak_maskreturn src_mask, tgt_maskdef forward(self, src, tgt):src_mask, tgt_mask = self.generate_mask(src, tgt)src_embedded = self.dropout(self.positional_encoding(self.encoder_embedding(src)))tgt_embedded = self.dropout(self.positional_encoding(self.decoder_embedding(tgt)))enc_output = src_embeddedfor enc_layer in self.encoder_layers:enc_output = enc_layer(enc_output, src_mask)dec_output = tgt_embeddedfor dec_layer in self.decoder_layers:dec_output = dec_layer(dec_output, enc_output, src_mask, tgt_mask)output = self.fc(dec_output)return output

類組合了以前定義的模塊以創建完整的轉換器模型。在初始化期間,Transformer 模塊設置輸入參數并初始化各種組件,包括源序列和目標序列的嵌入層、位置編碼模塊、用于創建堆疊層的編碼器層和解碼器層模塊、用于投影解碼器輸出的線性層以及 dropout 層。

generate_mask 方法為源序列和目標序列創建二進制掩碼,以忽略填充標記并防止解碼器處理將來的令牌。前向方法通過以下步驟計算轉換器模型的輸出:

  1. 使用 generate_mask 方法生成源掩碼和目標掩碼。
  2. 計算源和目標嵌入,并應用位置編碼和丟棄。
  3. 通過編碼器層處理源序列,更新enc_output張量。
  4. 通過解碼器層處理目標序列,使用enc_output和掩碼,并更新dec_output張量。
  5. 將線性投影層應用于解碼器輸出,獲取輸出對數。

這些步驟使轉換器模型能夠處理輸入序列,并根據其組件的組合功能生成輸出序列。

九、準備樣本數據

????????在此示例中,我們將創建一個用于演示目的的玩具數據集。實際上,您將使用更大的數據集,預處理文本,并為源語言和目標語言創建詞匯映射。

src_vocab_size = 5000
tgt_vocab_size = 5000
d_model = 512
num_heads = 8
num_layers = 6
d_ff = 2048
max_seq_length = 100
dropout = 0.1transformer = Transformer(src_vocab_size, tgt_vocab_size, d_model, num_heads, num_layers, d_ff, max_seq_length, dropout)# Generate random sample data
src_data = torch.randint(1, src_vocab_size, (64, max_seq_length))  # (batch_size, seq_length)
tgt_data = torch.randint(1, tgt_vocab_size, (64, max_seq_length))  # (batch_size, seq_length)

十、訓練模型

????????現在,我們將使用示例數據訓練模型。在實踐中,您將使用更大的數據集并將其拆分為訓練集和驗證集。

criterion = nn.CrossEntropyLoss(ignore_index=0)
optimizer = optim.Adam(transformer.parameters(), lr=0.0001, betas=(0.9, 0.98), eps=1e-9)transformer.train()for epoch in range(100):optimizer.zero_grad()output = transformer(src_data, tgt_data[:, :-1])loss = criterion(output.contiguous().view(-1, tgt_vocab_size), tgt_data[:, 1:].contiguous().view(-1))loss.backward()optimizer.step()print(f"Epoch: {epoch+1}, Loss: {loss.item()}")

????????我們可以使用這種方式在 Pytorch 中從頭開始構建一個簡單的轉換器。所有大型語言模型都使用這些轉換器編碼器或解碼器塊進行訓練。因此,了解啟動這一切的網絡非常重要。希望本文能幫助所有希望深入了解LLM的人。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/39350.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/39350.shtml
英文地址,請注明出處:http://en.pswp.cn/news/39350.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

iOS Epub閱讀器改造記錄

六個月前在這個YHEpubDemo閱讀器的基礎上做了一些優化,這里做一下記錄。 1.首行縮進修復 由于分頁的存在,新的一頁的首行可能是新的一行,則應該縮進;也可能是前面一頁段落的延續,這時候不應該縮進。YHEpubDemo基于XDS…

pycharm,VSCode 幾個好用的插件

pycharm Tabnine AI Code 可以在編寫程序的時候為你提供一些快捷方式,增加編程速度 Chinese 對英文不好的程序員來說是個不錯的選擇,可以將英文狀態下的pycharm變為中文版的 ChatGPT 可以跟ai聊天,ai可以解決你80%的問題 ,也可以幫…

變形金剛:從零開始【01/2】

一、說明 在我們的日常生活中,無論你是否是數據科學家,你都在單向地使用變壓器模型。例如。如果您使用的是 ChatGPT 或 GPT-4 或任何 GPT,那么在為您回答問題的框中是變壓器的一部分。如果您是數據科學家或數據分析師,則可能正在使…

【BASH】回顧與知識點梳理(二十九)

【BASH】回顧與知識點梳理 二十九 二十九. 進程和工作管理29.1 什么是進程 (process)進程與程序 (process & program)子進程與父進程:fork and exec:進程呼叫的流程系統或網絡服務:常駐在內存的進程 29.2 Linux 的多人多任務環境多人環境…

SAP MM學習筆記23-購買發注的賬戶分配類型(勘定Category)

SAP中控制財務憑證過賬科目的是 賬號分配類型(勘定Category)欄目。 ?賬號分配類型(勘定Category)有: 1,K 原價Center(成本中心。用于消耗物料采購 的過賬) 2,E 得意先…

【云原生之Docker實戰】使用Docker部署Syncthing同步程序及基本使用

【云原生之Docker實戰】使用Docker部署Syncthing同步程序及基本使用 一、Syncthing介紹1.1 Syncthing簡介1.2 Syncthing特點1.3 備份和同步區別二、本地環境介紹2.1 本地環境規劃2.2 本次實踐介紹三、本地環境檢查3.1 檢查Docker服務狀態3.2 檢查Docker版本3.3 檢查docker comp…

LabVIEW對并行機器人結構進行建模仿真

LabVIEW對并行機器人結構進行建模仿真 為了對復雜機器人結構的數學模型進行建模、搜索、動畫和驗證,在工業機器人動態行為實驗室中,設計并實現了具有五個自由度的單臂型機器人。在研究臺上可以區分以下元素:帶有直流電機和編碼器的機器人;穩…

nvm管理node版本

nvm是什么? NVM全名叫做 nodejs version manage,即Node的版本管理工具。 使用NVM,可以通過命令很方便地在多個NodeJS版本之間進行切換。 nvm的下載與安裝 下載地址:Releases coreybutler/nvm-windows (github.com) windows系統下載nvm-setup…

Arcgis中直接通過sde更新sqlserver空間數據庫失敗

問題 背景 不知道有沒有人經歷過這樣一個情況,我們直接在Arcgis中通過sde更新serserver數據庫會失敗,就是雖然在sde更新sqlserver數據庫,但是在Navicat中通過sql語句來查詢,發現數據并沒有更新,如:上圖中,更新數據庫后,第一張圖是sde打開的sqlserver數據庫,它的數據庫…

項目管理工具和方法有哪些:了解項目管理的必備工具和有效方法

先談談什么是項目管理,簡單直白,就是對項目進行管理。項目管理涉及有效的計劃和對工作的系統管理,但很多工具可以使項目管理更有效、更高效。比如,Zoho Projects項目管理工具。 1.項目合理拆解 當確定了項目目標后,無疑…

我國農機自動駕駛系統需求日益增長,北斗系統賦能精準農業

中國現代農業的發展,離不開智能化、自動化設備,迫切需要自動駕駛系統與農用機械的密切結合。自動駕駛農機不僅能夠緩解勞動力短缺問題,提升勞作生產效率,同時還能對農業進行智慧化升級,成為解決當下農業痛點的有效手段…

Pycharm社區版連接WSL2中的Mysql8.*

當前時間2023.08.13,Windows11中默認的WSL版本已經是2了,在WSL2中默認的Ubuntu版本已經是22.04,而Ubuntu22.04中默認的Mysql版本已經是8.*。 Wsl 2 中安裝mysql WSL2中安裝Mysql的方法參考自微軟官方文檔【開始使用適用于 Linux 的 Windows …

vector【2】模擬實現(超詳解哦)

vector 引言(實現概述)接口實現詳解默認成員函數構造函數析構函數賦值重載 迭代器容量size與capacityreserveresizeempty 元素訪問數據修改inserterasepush_back與pop_backswap 模擬實現源碼概覽總結 引言(實現概述) 在前面&…

分布式定時任務系列5:XXL-job中blockingQueue的應用

傳送門 分布式定時任務系列1:XXL-job安裝 分布式定時任務系列2:XXL-job使用 分布式定時任務系列3:任務執行引擎設計 分布式定時任務系列4:任務執行引擎設計續 Java并發編程實戰1:java中的阻塞隊列 引子 這篇文章的…

MATLAB計算一組坐標點的相互距離(pdist、squareform、pdist2函數)

如果有一組坐標P(X,Y),包含多個點的X和Y坐標,計算其坐標點之間的相互距離 一、坐標點 P[1 1;5 2;3 6;8 8;4 5;5 1; 6 9];二、pdist函數 輸出的結果是一維數組,獲得任意兩個坐標之間的距離,但沒有對應關系 Dpdist(P)三、square…

tensorflow學習筆記

tensorflow學習筆記 1. 安裝2. 驗證GPU是否可用3. 靜態圖說明 tensorflow學習過程中記錄的筆記 1. 安裝 cuda的安裝過程略,參考pytorch的那篇筆記。 一個穩定版本的tensorflow2.5版本匹配: conda create -n hi_hand_det python3.7.0 conda install c…

JavaWeb-Servlet服務連接器(二)

目錄 Request(獲取請求信息) 1.獲取請求行內容 2.解決亂碼問題 3.獲取請求頭部分 4.獲取請求體 5.其他功能 Request(獲取請求信息) 工作流程: 1.通過請求的url的資源路徑,tomcat會生成相應的Servlet實…

【單片機】DS2431,STM32,EEPROM讀取與寫入

芯片介紹: https://qq742971636.blog.csdn.net/article/details/132164189 接線 串口結果: 部分代碼: #include "sys.h" #include "DS2431.h"unsigned char serialNb[8]; unsigned char write_data[128]; unsigned cha…

STM32入門學習之定時器輸入捕獲

1.定時器的輸入捕獲可以用來測量脈沖寬度或者測量頻率。輸入捕獲的原理圖如下: 假設定時器是向上計數。在圖中,t1~t2之間的便是我們要測量的高電平的時間(脈沖寬度)。首先,設置定時器為上升沿捕獲,如此一來,在t1時刻可…

使用Cinemachine制作固定路徑動畫

固定路徑配置 選擇一個游戲對象添加CinemachineSmoothPath腳本選擇添加腳本的對象。路徑腳本需要是展開狀態,才可以看到路徑添加點,使用移動工具,調節路徑 對象在路徑上移動 移動對象添加CinemachineDollyCart腳本設置移動路徑(帶有Path腳…