深度學習模型的建立並非一蹴可幾,需經過資料處理、模型建構、訓練及評估等多個環節。本文以垃圾郵件分類別為例,逐步闡述如何從資料準備開始,到最終應用模型進行預測的完整流程。首先,需對原始資料進行清洗、轉換等預處理,再將其分割為訓練集、驗證集和測試集,以確保模型訓練的有效性。模型的初始化包含選擇合適的模型架構、設定超引數,並載入預訓練權重,以加速模型收斂。針對特定任務,需對模型進行修改,例如調整輸出層以適應分類別任務的需求,並加入 dropout 層以防止過擬合。模型訓練過程中,需持續監控評估指標,並根據結果調整模型引數,以提升模型效能。

深度學習模型的建立與應用在深度學習的應用中,建立一個有效的模型需要經過多個步驟。以下是建立和應用深度學習模型的詳細流程:

1. 資料準備資料是深度學習模型的基礎。首先,需要收集和預處理資料,以確保資料的品質和一致性。這包括了資料清洗、資料轉換和資料分割等步驟。

2. 資料載入在資料準備完成後,需要將資料載入到模型中。這通常涉及到建立資料載入器(loaders),以便能夠高效地將資料餵入模型中。

3. 建立資料集建立資料集是深度學習中的一個重要步驟。這涉及到將資料組織成適合模型訓練的格式,包括了訓練集、驗證集和測試集的分割。

4. 初始化模型初始化模型是指建立一個基本的模型結構,包括了層次、啟用函式和最佳化器等。這個步驟為後續的模型訓練和微調做好了準備。

5. 載入預訓練權重載入預訓練權重可以大大加速模型的訓練過程。預訓練權重是指在大規模資料集上預先訓練好的模型權重,可以作為我們自己的模型的起點。

6. 修改模型為細調修改模型為細調(fine-tuning)是指根據自己的具體需求對預訓練模型進行調整。這可能包括了新增或刪除層次、調整啟用函式等,以使模型更好地適應自己的資料和任務。

7. 實作評估工具評估工具是用來評估模型效能的方法,包括了精確度、召回率、F1分數等指標。實作評估工具可以幫助我們瞭解模型的強弱和需要改進的地方。

8. 細調模型細調模型是指使用自己的資料對模型進行微調。這個過程需要耐心和反覆試驗,目的是要找到最適合自己任務的模型引數。

9. 評估細調後的模型評估細調後的模型是指使用評估工具來評估模型在新的、未見過的資料上的效能。這個步驟可以幫助我們確定模型是否已經達到預期的效能。

10. 應用模型最後,當模型經過細調和評估後,就可以應用到新的資料上。這可能包括了影像分類別、語言翻譯、語音識別等各種應用場景。

內容解密:以上步驟展示瞭如何從零開始建立一個深度學習模型,並將其應用到實際問題中。每一步都非常重要,因為它們共同構成了深度學習模型的生命週期。從資料準備到模型評估,每一步都需要小心謹慎地進行,以確保最終得到一個高效能的模型。

圖表翻譯: graph LR

A[資料準備] --> B[資料載入]

B --> C[建立資料集]

C --> D[初始化模型]

D --> E[載入預訓練權重]

E --> F[修改模型為細調]

F --> G[實作評估工具]

G --> H[細調模型]

H --> I[評估細調後的模型]

I --> J[應用模型]

圖表翻譯:此圖表展示了深度學習模型建立和應用的流程。從左到右,各個步驟之間存在著明確的邏輯關係,每一步都是根據前一步的結果進行的。這個流程圖可以幫助我們更好地理解深度學習模型的生命週期,並提供了一個清晰的指導,告訴我們如何從零開始建立一個高效能的深度學習模型。

初始化與載入預訓練模型在上一節中,我們已經準備好了垃圾郵件預測的資料集,現在是時候初始化大語言模型(LLM)並對其進行微調以用於垃圾郵件分類別。以下是初始化和載入預訓練模型的步驟:

步驟1:定義基礎組態首先,我們需要定義基礎組態,這包括詞彙大小、上下文長度、丟棄率和QKV偏差等引數。

BASE_CONFIG = {

"vocab_size": 50257,

"context_length": 1024,

"drop_rate": 0.0,

"qkv_bias": True

}

步驟2:選擇模型組態接下來,我們需要選擇一個合適的模型組態。這裡我們提供了多個選擇,包括GPT2的小、 сред和大型模型,每個模型都有不同的嵌入維度、層數和頭數。

model_configs = {

"gpt2-small (124M)": {"emb_dim": 768, "n_layers": 12, "n_heads": 12},

"gpt2-medium (355M)": {"emb_dim": 1024, "n_layers": 24, "n_heads": 16},

"gpt2-large (774M)": {"emb_dim": 1280, "n_layers": 36, "n_heads": 20},

"gpt2-xl (1558M)": {"emb_dim": 1600, "n_layers": 48, "n_heads": 25},

}

步驟3:更新基礎組態根據選擇的模型,我們更新基礎組態以包含所選模型的具體引數。

BASE_CONFIG.update(model_configs[CHOOSE_MODEL])

步驟4:載入預訓練模型最後,我們載入預訓練模型的權重。這涉及到下載模型權重並將其載入到GPT模型中。

from gpt_download import download_and_load_gpt2

from chapter05 import GPTModel, load_weights_into_gpt

model_size = CHOOSE_MODEL.split(" ")[-1].lstrip("(").rstrip(")")

settings, params = download_and_load_gpt2(model_size=model_size, models_dir="gpt2")

model = GPTModel(BASE_CONFIG)

內容解密:以上步驟展示瞭如何初始化和載入預訓練的大語言模型。這些步驟對於後續的微調和使用至關重要。透過選擇合適的模型組態和載入預訓練權重,我們可以為特定的任務(如垃圾郵件分類別)建立一個強大的基礎模型。

如何使用預訓練模型進行文字分類別在進行文字分類別任務之前,瞭解預訓練模型的能力是非常重要的。這裡,我們將使用預訓練的GPT模型來進行簡單的文字分類別。

載入預訓練模型首先,我們需要載入預訓練模型的權重。這可以透過以下程式碼實作:

load_weights_into_gpt(model, params)

model.eval()

這裡,model是GPT模型的例項,params是模型的權重引數。

文字生成工具為了確保模型生成的文字是連貫的,我們將使用之前章節中介紹的文字生成工具:

from chapter04 import generate_text_simple

from chapter05 import text_to_token_ids, token_ids_to_text

這些工具將幫助我們生成連貫的文字。

測試模型現在,我們可以測試模型是否能夠生成連貫的文字。以下程式碼將生成一段文字:

text_1 = "Every effort moves you"

token_ids = generate_text_simple(

model=model,

idx=text_to_token_ids(text_1, tokenizer),

max_new_tokens=15,

context_size=BASE_CONFIG["context_length"]

)

print(token_ids_to_text(token_ids, tokenizer))

這裡,text_1是輸入文字,tokenizer是用於將文字轉換為token ID的工具。輸出結果應該是一段連貫的文字。

分類別任務接下來,我們將使用模型進行簡單的分類別任務。以下程式碼將生成一段文字,並要求模型判斷是否為垃圾郵件:

text_2 = (

"Is the following text 'spam'? Answer with 'yes' or 'no':"

" 'You are a winner you have been specially"

" selected to receive $1000 cash or a $2000 award.'"

)

token_ids = generate_text_simple(

model=model,

idx=text_to_token_ids(text_2, tokenizer),

max_new_tokens=23,

context_size=BASE_CONFIG["context_length"]

)

這裡,text_2是輸入文字,模型將生成一段文字作為回應。

圖表翻譯:以下是Mermaid圖表,展示了上述程式碼的執行流程:

flowchart TD

A[載入預訓練模型] --> B[生成文字]

B --> C[分類別任務]

C --> D[生成回應]

內容解密:上述程式碼的作用是載入預訓練模型,生成連貫的文字,並進行簡單的分類別任務。模型將生成一段文字作為回應,該文字應該能夠正確地判斷輸入文字是否為垃圾郵件。

分類別模型微調在進行分類別任務時,需要對預訓練的語言模型進行微調,以使其能夠有效地分類別文字。為了實作這一點,我們需要修改預訓練模型的輸出層,以使其適應分類別任務。

修改輸出層預訓練模型的原始輸出層將隱藏表示對映到一個包含 50,257 個單詞的詞彙表中。然而,在分類別任務中,我們只需要兩個類別:0(非垃圾郵件)和 1(垃圾郵件)。因此,我們需要替換原始輸出層,以一個較小的輸出層,該層將隱藏表示對映到這兩個類別中。

輸出節點數量在二元分類別任務中,我們可以使用單個輸出節點。然而,這需要修改損失函式,以適應二元分類別任務。為了簡化問題,我們可以使用兩個輸出節點,分別對應兩個類別。這種方法可以適用於多類別分類別任務,只需增加輸出節點數量即可。例如,在三類別分類別任務中(例如將新聞文章分類別為「科技」、「體育」或「政治」),我們需要使用三個輸出節點。

實作細節在實作中,我們需要確保輸出層的節點數量與類別數量相匹配。這樣可以使模型能夠有效地學習並分類別文字。同時,需要注意損失函式的選擇和修改,以適應特定的分類別任務。

程式碼實作import torch

import torch.nn as nn

class ClassificationHead(nn.Module):

def __init__(self, hidden_size, num_classes):

super(ClassificationHead, self).__init__()

self.fc = nn.Linear(hidden_size, num_classes)

def forward(self, x):

x = self.fc(x)

return x

# 假設 hidden_size = 768,num_classes = 2

hidden_size = 768

num_classes = 2

classification_head = ClassificationHead(hidden_size, num_classes)

圖表翻譯 graph LR

A[輸入文字] --> B[預訓練模型]

B --> C[修改輸出層]

C --> D[分類別頭]

D --> E[輸出類別]

圖表說明上述圖表展示瞭如何修改預訓練模型的輸出層,以適應分類別任務。首先,輸入文字被送入預訓練模型中。然後,修改輸出層以使其適應分類別任務。最後,分類別頭將隱藏表示對映到相應的類別中,並輸出最終的類別結果。

轉換輸出層以適應二元分類別任務在原始的線性輸出層中,我們將其替換為一層能夠從768個隱藏單元對映到僅2個單元的層,這2個單元分別代表「垃圾郵件」和「非垃圾郵件」兩類別。

import torch

import torch.nn as nn

class SpamClassifier(nn.Module):

def __init__(self):

super(SpamClassifier, self).__init__()

self.fc = nn.Linear(768, 2) # 將768個隱藏單元對映到2個單元

def forward(self, x):

x = self.fc(x)

return x

內容解密:上述程式碼定義了一個簡單的神經網路層(SpamClassifier),該層包含一個全連線層(nn.Linear),負責將輸入的768個隱藏單元對映到2個單元,代表二元分類別的兩個類別。這樣的設計使得模型能夠根據輸入的文字特徵進行垃圾郵件與非垃圾郵件的區分。

flowchart TD

A[輸入層] --> B[隱藏層]

B --> C[全連線層]

C --> D[輸出層]

D --> E[二元分類別]

圖表翻譯:此圖表展示了神經網路從輸入層到輸出層的流程。首先,輸入的文字資料被送入輸入層(A),然後被處理並傳遞到隱藏層(B),在這裡進行特徵提取和轉換。接著,資料被送入全連線層(C),這裡實作了從768個隱藏單元到2個單元的對映,最後,輸出層(D)產生二元分類別結果(E),即判斷輸入文字是否為垃圾郵件。這個過程展示瞭如何使用神經網路進行二元分類別任務。

自然語言處理中的深度學習模型應用在自然語言處理(NLP)領域,深度學習模型已經成為了一種重要的工具,尤其是在文字分類別、語言翻譯和文字生成等任務中。其中,Transformer模型是一種特別成功的模型結構,它透過自注意力機制來捕捉輸入序列之間的長距離依賴關係。

Transformer模型結構Transformer模型由多個相同的層組成,每一層都包含兩個子層:自注意力層和前向神經網路層。自注意力層允許模型同時處理輸入序列中的所有元素,而前向神經網路層則對輸入序列進行非線性轉換。

自注意力層自注意力層是Transformer模型中的一個關鍵元件,它允許模型捕捉輸入序列之間的長距離依賴關係。自注意力層透過計算輸入序列中每個元素與其他元素之間的注意力權重來實作這一功能。

前向神經網路層前向神經網路層是一個全連線神經網路,它對輸入序列進行非線性轉換。這一層可以幫助模型學習更複雜的模式和關係。

應用於垃圾郵件分類別在垃圾郵件分類別任務中,我們可以使用Transformer模型來對郵件文字進行分類別。為此,我們需要對原始模型進行修改,包括替換輸出層和新增dropout層。

修改輸出層原始的Transformer模型輸出層是設計用於語言模型任務的,它將768個隱藏單元對映到一個包含50,257個令牌的詞彙表中。然而,在垃圾郵件分類別任務中,我們只需要將輸出對映到兩個類別:垃圾郵件和非垃圾郵件。因此,我們需要替換原始的輸出層,以適應這一新的任務。

新增dropout層dropout層是一種正則化技術,用於防止過擬合。透過在模型中新增dropout層,我們可以隨機丟棄一些神經元,從而提高模型的泛化能力。

實作細節在實作上,我們可以使用以下步驟來修改原始的Transformer模型:

輸出層替換:替換原始的輸出層,以適應垃圾郵件分類別任務。新增dropout層:在模型中新增dropout層,以防止過擬合。訓練模型:使用標註資料集訓練修改後的模型。以下是使用Python和PyTorch實作這一過程的示例程式碼:

import torch

import torch.nn as nn

import torch.optim as optim

# 定義Transformer模型

class TransformerModel(nn.Module):

def __init__(self):

super(TransformerModel, self).__init__()

self.encoder = nn.TransformerEncoderLayer(d_model=768, nhead=8, dim_feedforward=2048, dropout=0.1)

self.decoder = nn.Linear(768, 2)

def forward(self, x):

x = self.encoder(x)

x = self.decoder(x)

return x

# 輸出層替換

model = TransformerModel()

model.decoder = nn.Linear(768, 2)

# 新增dropout層

model.dropout = nn.Dropout(p=0.1)

# 訓練模型

criterion = nn.CrossEntropyLoss()

optimizer = optim.Adam(model.parameters(), lr=0.001)

for epoch in range(10):

optimizer.zero_grad()

outputs = model(inputs)

loss = criterion(outputs, labels)

loss.backward()

optimizer.step()

在這個示例中,我們定義了一個簡單的Transformer模型,並替換了輸出層和增加了dropout層。然後,我們使用標註資料集訓練修改後的模型。

圖表翻譯: graph LR

A[輸入序列] --> B[自注意力層]

B --> C[前向神經網路層]

C --> D[輸出層]

D --> E[分類別結果]

在這個圖表中,我們展示了Transformer模型的基本結構,包括自注意力層、前向神經網路層和輸出層。輸入序列首先被送入自注意力層,然後被送入前向神經網路層,最後被送入輸出層以取得分類別結果。

深度學習模型的微調在進行深度學習模型的微調時,瞭解模型的架構和每個層的功能是非常重要的。以下是對模型架構的描述:

模型由多個層組成,包括嵌入層、編碼器層和輸出層。編碼器層又可以分為多個子層,每個子層包含自注意力機制(MultiHeadAttention)、前向神經網路(FeedForward)和層歸一化(LayerNorm)。

自注意力機制是用於處理輸入序列之間的關係,包括查詢(W_query)、鍵(W_key)和值(W_value)線性變換,以及輸出投影(out_proj)線性變換。前向神經網路則包含兩個線性變換層和一個GELU啟用函式。

在微調模型時,我們可以選擇微調所有層或只微調部分層。由於預訓練模型已經學習了基本的語言結構和語義,因此只微調最後幾層往往足夠。這不僅可以減少計算成本,也可以避免過度適應。

微調選擇選擇哪些層進行微調取決於具體任務和資料集。在一般情況下,微調最後幾層即可。但是,具體情況下可能需要根據實驗結果進行調整。

實作細節要進行微調,首先需要凍結模型的所有引數,使其不可訓練。然後,替換輸出層以適應新的任務需求。例如,若要進行二分類別任務,輸出層需要改為只有兩個輸出單元。

for param in model.parameters():

param.requires_grad = False

torch.manual_seed(123)

num_classes = 2

model.out_head = torch.nn.Linear(

in_features=BASE_CONFIG["emb_dim"],

out_features=num_classes

)

這樣,模型就準備好進行微調了。接下來,可以根據具體任務需求對模型進行微調和評估。

圖表翻譯: graph LR

A[嵌入層] --> B[編碼器層]

B --> C[自注意力機制]

C --> D[前向神經網路]

D --> E[層歸一化]

E --> F[輸出層]

內容解密:上述程式碼展示瞭如何對模型進行微調。首先,凍結所有引數,使其不可訓練。然後,替換輸出層以適應新的任務需求。在這個例子中,我們將輸出層改為只有兩個輸出單元,以進行二分類別任務。這樣,模型就準備好進行微調了。

新增分類別層在上一節中,我們瞭解瞭如何使用預先訓練好的GPT-2模型進行文字分類別任務。現在,我們將更進一步,新增一個分類別層,以便模型能夠根據輸入文字預測相應的分類別標籤。

首先,我們需要定義新增分類別層的輸出維度,這取決於我們的分類別任務中有多少個類別。假設我們有num_classes個類別,我們可以如下所示新增分類別層:

model.out_head = torch.nn.Linear(BASE_CONFIG["emb_dim"], num_classes)

這裡,BASE_CONFIG["emb_dim"]是GPT-2模型的嵌入維度,對於"gpt2-small (124M)“模型來說,這個值為768。

新增的分類別層只有當其requires_grad屬性設為True時,才會在訓練過程中被更新。技術上來說,只需訓練新增的分類別層即可,但透過實驗,我發現微調額外的層可以明顯提高模型的預測效能(詳見附錄B)。此外,我們還組態最後一個變換器塊和最終的LayerNorm模組,使其可訓練,如圖6.10所示。

為使最終的LayerNorm和最後一個變換器塊可訓練,我們設定其requires_grad屬性為True:

for param in model.trf_blocks[-1].parameters():

param.requires_grad = True

for param in model.final_norm.parameters():

param.requires_grad = True

儘管我們新增了一個分類別層,並標記某些層為可訓練或不可訓練,但我們仍然可以像之前一樣使用這個模型。例如,我們可以餵給它一個與之前使用的示例文字相同的文字:

inputs = tokenizer.encode("Do you have time")

inputs = torch.tensor(inputs).unsqueeze(0)

print("Inputs:", inputs)

print("Inputs dimensions:", inputs.shape)

這與我們在第5章中看到的完全一致。

練習6.2:微調整整個模型與其只微調最後一個變換器塊,不如嘗試微調整整個模型,並評估其對預測效能的影響。

從技術架構視角來看,本文深入探討了深度學習模型的建立、應用與微調,涵蓋了從資料準備到模型佈署的完整流程。分析段落詳細闡述了每個階段的關鍵步驟和技術細節,包括資料集的建立、預訓練權重的載入、模型架構的調整以及分類別層的新增等。模型微調策略的討論,特別是關於選擇性微調特定層以平衡效能和計算成本的分析,展現了務實的工程思維。技術限制深析部分,點明瞭單獨訓練分類別層的侷限性,並透過實驗結果佐證了微調更多層級的必要性,體現了作者的實踐經驗和嚴謹態度。

展望未來,預訓練模型的應用將持續深化,模型架構的最佳化和訓練策略的改進將是重要的發展方向。隨著模型規模的擴大和資料量的增加,更高效的訓練方法和更輕量化的模型佈署方案將成為研究熱點。模型的可解釋性和泛化能力的提升也將是未來研究的關鍵挑戰。

玄貓認為,善用預訓練模型和微調策略,能有效降低深度學習應用的門檻,加速AI技術在各領域的落地。開發者應關注模型架構的演進和最佳實務,持續精進模型訓練和佈署技巧,才能在快速發展的AI領域保持競爭力。