深度學習模型的隨機性控制對於生成高品質文字至關重要。溫度縮放能調整 softmax 機率分佈的尖銳度,低溫使模型傾向於選擇機率最高的 token,而高溫則鼓勵更多樣化的輸出。Top k 取樣限制模型僅考慮機率最高的前 k 個 token,避免低機率 token 的幹擾,從而提升生成文字的連貫性和語義完整性。然而,Top k 取樣仍需注意引數調整,避免過度限制模型的創造力。在實際應用中,通常需要結合溫度縮放和 Top k 取樣,並根據特定任務需求微調引數,以在生成文字的多樣性和準確性之間取得平衡。
5.3 解碼策略:控制隨機性
在生成文字的過程中,控制隨機性是一個重要的方面。透過調整溫度引數,可以影響多元分佈的尖銳度。溫度越低,分佈越尖銳,模型越容易選擇最可能的token;溫度越高,分佈越均勻,模型越容易選擇其他token。
5.3.2 頂k取樣
為了增加生成文字的多樣性,我們可以使用頂k取樣方法。這種方法涉及限制取樣token的範圍,只考慮前k個最可能的token。透過這種方式,可以減少模型反覆選擇最可能token的可能性,從而探索更不可能但可能更有趣的生成路徑。
然而,這種方法也有一個缺點:它有時會導致生成文字語法錯誤或完全沒有意義。例如,使用溫度為5的頂k取樣方法可能會生成如"every effort moves you pizza"這樣的文字。
練習5.1
使用print_sampled_tokens
函式列印softmax機率在不同溫度下的取樣頻率。每種情況下,“pizza"這個詞被取樣的頻率是多少?你能想到一個更快、更準確的方法來確定"pizza"這個詞被取樣的頻率嗎?
圖5.14
溫度為1代表未經縮放的機率分數。降低溫度到0.1會使分佈變得更加尖銳,使得最可能的token(在這裡是"forward”)具有更高的機率分數。相反,提高溫度到5會使分佈變得更加均勻。
頂k取樣
頂k取樣方法可以與機率取樣和溫度縮放結合使用,以改善文字生成結果。在頂k取樣中,我們可以限制取樣token的範圍,只考慮前k個最可能的token,並排除所有其他token。
flowchart TD A[開始] --> B[計算softmax機率] B --> C[選擇前k個最可能的token] C --> D[將非選擇token的logits設為負無窮] D --> E[計算softmax值] E --> F[生成文字]
內容解密:
上述流程圖展示了頂k取樣方法的工作原理。首先,計算softmax機率;然後,選擇前k個最可能的token;接著,將非選擇token的logits設為負無窮;然後,計算softmax值;最後,生成文字。
圖表翻譯:
上述流程圖展示了頂k取樣方法的工作原理。透過限制取樣token的範圍,可以減少模型反覆選擇最可能token的可能性,從而探索更不可能但可能更有趣的生成路徑。
控制隨機性的解碼策略
在自然語言生成中,控制隨機性是一個重要的議題。為了確保生成的文字是有意義且相關的,我們需要使用特定的解碼策略來控制模型的輸出。其中一個常用的方法是使用 top-k sampling。
Top-k Sampling
Top-k sampling 是一種解碼策略,它只考慮輸出機率最高的 k 個 token。這樣可以避免模型生成無關或低機率的 token,從而提高生成文字的品質。
例如,假設我們有一個模型,它輸出了一個 9 個 token 的 logits 向量:
[4.51, 0.89, -1.90, 6.75, 1.63, -1.62, -1.89, 6.28, 1.79]
我們可以使用 top-k sampling 來選擇最高機率的 3 個 token。首先,我們需要找到最高機率的 3 個 token 的索引:
Top positions: tensor([3, 7, 0])
然後,我們可以使用 PyTorch 的 where
函式來設定低於最低 logit 值的 token 的 logit 值為負無窮大(-inf):
new_logits = torch.where(
condition=next_token_logits < top_logits[-1],
input=torch.tensor(float('-inf')),
other=next_token_logits
)
這樣就會得到新的 logit 值:
tensor([4.5100, -inf, -inf, 6.7500, -inf, -inf, -inf, 6.2800, -inf])
最後,我們可以使用 softmax 函式來轉換這些 logit 值為機率:
topk_probas = torch.softmax(new_logits, dim=0)
結果如下:
tensor([0.0615, 0.0000, 0.0000, 0.5775, 0.0000, 0.0000, 0.0000, 0.3610, 0.0000])
如您所見,使用 top-k sampling 的結果是隻有 3 個 token 有非零機率值。
圖示
下圖示範了使用 top-k sampling 的過程:
flowchart TD A[輸出 logit 值] --> B[選擇最高機率的 k 個 token] B --> C[設定低於最低 logit 值的 token 的 logit 值為負無窮大] C --> D[轉換 logit 值為機率] D --> E[輸出結果]
圖表翻譯
此圖示範了使用 top-k sampling 的過程。首先,模型輸出 logit 值,然後選擇最高機率的 k 個 token。接著,設定低於最低 logit 值的 token 的 logit 值為負無窮大。最後,轉換 logit 值為機率,並輸出結果。
修改文字生成函式以增加多樣性
在前面的章節中,我們探討瞭如何使用大語言模型(LLM)生成文字。然而,為了增加生成文字的多樣性和真實性,我們需要對原始的文字生成函式進行修改。這個修改過的函式將結合溫度取樣(temperature sampling)和Top-K取樣(top-k sampling)技術,以確保生成的文字更為多樣和有趣。
新的生成函式
以下是修改過的生成函式,名為generate
,它結合了溫度取樣和Top-K取樣:
def generate(model, idx, max_new_tokens, context_size, temperature=0.0, top_k=None, eos_id=None):
for _ in range(max_new_tokens):
idx_cond = idx[:, -context_size:]
with torch.no_grad():
logits = model(idx_cond)
logits = logits[:, -1, :]
這個函式的主要目的是根據給定的模型、輸入索引、最大新token數量、上下文大小、溫度引數和Top-K引數來生成新的文字。
過程解釋
- 溫度取樣和Top-K取樣:這兩種技術被用來增加生成文字的多樣性。溫度取樣透過調整機率分佈的溫度來控制生成的隨機性,而Top-K取樣則只考慮機率最高的K個token作為候選項。
- logits處理:函式首先獲得模型對輸入索引的logits輸出,然後只考慮最後一個時間步的logits。
- Top-K過濾:如果指定了Top-K引數,函式會過濾掉機率低於Top-K門檻的token,並將這些token的logits設為負無窮大,以確保它們不會被選中。
實作細節
在實作這個函式時,我們需要注意以下幾點:
- 溫度引數:溫度引數控制著生成的隨機性,當溫度為0時,模型會選擇機率最高的token;當溫度增加時,模型會考慮更多的token選擇。
- Top-K引數:Top-K引數決定了考慮多少個token作為候選項。當Top-K為None時,模型會考慮所有可能的token。
結合溫度取樣和Top-K取樣
透過結合溫度取樣和Top-K取樣,我們可以更好地控制生成文字的多樣性和真實性。溫度取樣提供了一種方法來控制生成的隨機性,而Top-K取樣則確保只考慮最有可能的token。
圖表翻譯
flowchart TD A[開始] --> B[獲得logits] B --> C[過濾logits] C --> D[應用溫度取樣] D --> E[應用Top-K取樣] E --> F[選擇token] F --> G[生成文字]
這個流程圖展示了修改過的生成函式的工作流程,從獲得logits開始,到過濾logits、應用溫度取樣和Top-K取樣,最終選擇token並生成文字。
瞭解生成模型的調整引數
在上述程式碼中,我們看到了一個名為 generate
的函式,它用於根據給定的模型和輸入文字生成新的文字。這個函式接受多個引數,包括 model
、idx
(輸入文字的token ID)、max_new_tokens
(生成的最大token數量)、context_size
(模型的上下文大小)、top_k
(選擇機率最高的前k個token)和 temperature
(控制生成隨機性的引數)。
測試生成函式
首先,我們設定了隨機種子以確保結果的一致性。然後,我們呼叫 generate
函式,傳入所需的引數,包括模型、輸入文字的token ID、最大生成token數量、上下文大小、選擇機率最高的前k個token和溫度引數。
torch.manual_seed(123)
token_ids = generate(
model=model,
idx=text_to_token_ids("Every effort moves you", tokenizer),
max_new_tokens=15,
context_size=GPT_CONFIG_124M["context_length"],
top_k=25,
temperature=1.4
)
print("Output text:\n", token_ids_to_text(token_ids, tokenizer))
分析生成結果
生成的文字是:“Every effort moves you stand to work on surprise, a one of us had gone with random-”。與之前透過 generate_simple
函式生成的文字相比,這段文字明顯不同,表明了模型在給定引數下的生成能力。
練習:探索不同引數設定
練習5.2要求我們嘗試不同的溫度和top-k設定,觀察生成文字的變化。低溫度和低top-k設定可能導致生成文字更為保守和可預測,而高溫度和高top-k設定可能會產生更為多樣和創新的文字。
低溫度和低top-k設定:在某些應用中,例如生成正式檔案或技術報告,可能需要更為可靠和一致的生成結果。這時候,低溫度和低top-k設定可能是合適的選擇,因為它們可以限制模型的生成範圍,減少隨機性。
高溫度和高top-k設定:在創意寫作、對話生成或需要多樣性和創新的應用中,高溫度和高top-k設定可能更為適合。這些設定允許模型探索更廣泛的可能性,從而產生更具創意和多樣性的文字。
透過這個練習,我們可以更深入地瞭解生成模型的引數如何影響其生成結果,並學習如何根據不同的應用需求調整這些引數以達到最佳效果。
模型權重的載入與儲存
在 PyTorch 中,模型的權重是神經網路中最重要的引數,決定了模型的效能和預測能力。因此,能夠有效地載入和儲存模型權重對於模型的訓練和佈署至關重要。
載入模型權重
PyTorch 提供了多種方式來載入模型權重,包括從檔案中載入和從其他模型中載入。以下是從檔案中載入模型權重的示例:
import torch
import torch.nn as nn
# 載入模型權重
model = nn.Sequential(
nn.Linear(5, 10),
nn.ReLU(),
nn.Linear(10, 5)
)
model.load_state_dict(torch.load('model_weights.pth'))
在這個示例中,我們首先定義了一個簡單的神經網路模型,然後使用 load_state_dict
方法從檔案中載入模型權重。
儲存模型權重
儲存模型權重也很簡單,可以使用 save
方法將模型權重儲存到檔案中:
# 儲存模型權重
torch.save(model.state_dict(), 'model_weights.pth')
在這個示例中,我們使用 state_dict
方法取得模型的權重,然後使用 save
方法將權重儲存到檔案中。
模型權重的格式
PyTorch 支援多種模型權重格式,包括 pth
、pt
和 pkl
。其中,pth
和 pt
格式是 PyTorch 的預設格式,而 pkl
格式則是 Python 的 pickle 格式。
載入和儲存模型權重的最佳實踐
在載入和儲存模型權重時,需要注意以下幾點:
- 使用
load_state_dict
方法載入模型權重時,需要確保模型的結構和權重的名稱與檔案中的權重相符。 - 使用
save
方法儲存模型權重時,需要確保檔案名稱和路徑正確。 - 在分散式訓練中,需要確保所有模型的權重都被正確地載入和儲存。
內容解密:
在上述程式碼中,我們使用 load_state_dict
方法載入模型權重,然後使用 save
方法儲存模型權重。這些方法都是 PyTorch 中的內建方法,能夠有效地管理模型的權重。
以下是 load_state_dict
方法的詳細解說:
load_state_dict
方法用於載入模型權重。- 該方法需要一個檔案路徑作為引數。
- 檔案路徑應該是包含模型權重的檔案的路徑。
以下是 save
方法的詳細解說:
save
方法用於儲存模型權重。- 該方法需要兩個引數:檔案路徑和模型權重。
- 檔案路徑應該是要儲存模型權重的檔案的路徑。
- 模型權重應該是要儲存的模型權重。
圖表翻譯:
graph LR A[載入模型權重] -->|使用 load_state_dict 方法|> B[模型] B -->|使用 save 方法|> C[儲存模型權重] C -->|傳回檔案路徑|> D[檔案] D -->|傳回模型權重|> B
在這個圖表中,我們展示了載入和儲存模型權重的流程。首先,我們使用 load_state_dict
方法載入模型權重,然後使用 save
方法儲存模型權重。最終,我們傳回檔案路徑和模型權重。
使用PyTorch儲存和載入模型權重
在前面的章節中,我們討論瞭如何評估訓練進度和從頭開始預訓練一個大語言模型(LLM)。儘管我們的LLM和資料集相對較小,但這個練習表明預訓練LLM是計算上昂貴的。因此,能夠儲存LLM以避免每次使用時都要重新訓練是非常重要的。
讓我們來看看如何儲存和載入一個預訓練模型,如圖5.16所示。稍後,我們將載入一個更強大的預訓練GPT模型從OpenAI到我們的GPTModel
例項中。
幸運的是,使用PyTorch儲存模型相對簡單。推薦的方法是儲存模型的state_dict
,它是一個將每一層對映到其引數的字典,使用torch.save
函式:
torch.save(model.state_dict(), "model.pth")
“model.pth"是儲存state_dict
的檔案名稱。.pth
副檔名是一個PyTorch檔案的慣例,雖然我們可以使用任何檔案副檔名。
然後,在儲存模型權重透過state_dict
之後,我們可以將模型權過載入到一個新的GPTModel
模型例項中:
model.load_state_dict(torch.load("model.pth"))
內容解密:
在上面的程式碼中,我們使用torch.save
函式儲存模型的state_dict
到一個檔案中。然後,我們使用torch.load
函式載入儲存的state_dict
,並使用load_state_dict
方法將其載入到一個新的模型例項中。
圖表翻譯:
flowchart TD A[儲存模型] --> B[使用torch.save] B --> C[儲存state_dict] C --> D[檔案名稱:model.pth] D --> E[載入模型] E --> F[使用torch.load] F --> G[載入state_dict] G --> H[載入到新模型例項]
在這個流程圖中,我們展示瞭如何儲存和載入一個PyTorch模型。首先,我們使用torch.save
函式儲存模型的state_dict
到一個檔案中。然後,我們使用torch.load
函式載入儲存的state_dict
,並使用load_state_dict
方法將其載入到一個新的模型例項中。
使用預訓練權重和模型儲存
在深度學習中,預訓練權重可以大大加速模型的訓練過程。這是因為預訓練權重已經學習到了很多通用的特徵和模式,可以作為我們自己的模型的起點。讓我們看看如何載入預訓練權重並儲存模型,以便於未來的使用或繼續訓練。
載入預訓練權重
首先,我們需要從OpenAI載入預訓練權重到我們的LLM(大語言模型)中。這可以透過以下步驟實作:
model = GPTModel(GPT_CONFIG_124M)
model.load_state_dict(torch.load("model.pth", map_location=device))
在這段程式碼中,我們首先建立一個GPTModel
例項,然後使用load_state_dict
方法載入預訓練權重。torch.load
函式用於載入模型權重,map_location=device
引數確保權重被載入到正確的裝置(CPU或GPU)上。
切換到評估模式
在訓練過程中,dropout是一種常用的正則化技術,透過隨機丟棄神經元來防止過擬合。然而,在推理過程中,我們不希望丟棄任何已經學習到的資訊。為了實作這一點,我們需要切換模型到評估模式:
model.eval()
這行程式碼告訴模型現在處於評估模式,dropout層將被停用,以確保所有學習到的資訊都被使用。
儲存模型
如果我們計劃稍後繼續訓練模型,儲存最佳化器的狀態也是非常重要的。這樣,我們就可以從上次訓練的位置繼續開始,而不是從頭開始。儲存模型可以透過以下步驟實作:
torch.save(model.state_dict(), "model.pth")
這行程式碼將模型的狀態字典(state dictionary)儲存到一個名為model.pth
的檔案中。
最佳化器的儲存和載入
在訓練模型的過程中,最佳化器(optimizer)扮演著非常重要的角色。最佳化器負責根據模型的損失函式更新模型引數,以達到最小化損失的目標。然而,在儲存和載入模型時,最佳化器的狀態也需要被儲存和還原。
最佳化器的儲存
使用 torch.save()
函式,可以儲存模型和最佳化器的狀態字典(state dictionary)。以下是儲存模型和最佳化器狀態字典的示例:
torch.save({
"model_state_dict": model.state_dict(),
"optimizer_state_dict": optimizer.state_dict(),
}, "model_and_optimizer.pth")
在這個例子中,model.state_dict()
和 optimizer.state_dict()
分別傳回模型和最佳化器的狀態字典。然後,使用 torch.save()
函式將這兩個狀態字典儲存到一個檔案中。
最佳化器的載入
要載入儲存的模型和最佳化器狀態字典,可以使用 torch.load()
函式。以下是載入模型和最佳化器狀態字典的示例:
checkpoint = torch.load("model_and_optimizer.pth", map_location=device)
model = GPTModel(GPT_CONFIG_124M)
model.load_state_dict(checkpoint["model_state_dict"])
optimizer = torch.optim.AdamW(model.parameters(), lr=5e-4, weight_decay=0.1)
optimizer.load_state_dict(checkpoint["optimizer_state_dict"])
model.train()
在這個例子中,torch.load()
函式載入儲存的模型和最佳化器狀態字典。然後,使用 load_state_dict()
方法將狀態字典載入到模型和最佳化器中。
從 OpenAI 載入預訓練權重
OpenAI 提供了預訓練的 GPT-2 模型權重,可以用於初始化模型引數。要載入這些權重,需要安裝 TensorFlow 和 tqdm 函式庫。然後,可以使用下面的程式碼載入預訓練權重:
import urllib.request
url = (
"LLMs-from-scratch/main/ch05/"
"01_main-chapter-code/gpt_download.py"
)
這個程式碼下載了 gpt_download.py
指令碼,該指令碼包含了載入預訓練權重的程式碼。
圖表翻譯:
flowchart TD A[開始] --> B[儲存模型和最佳化器狀態字典] B --> C[載入儲存的模型和最佳化器狀態字典] C --> D[初始化模型和最佳化器] D --> E[載入預訓練權重] E --> F[訓練模型]
這個流程圖描述了儲存和載入模型和最佳化器狀態字典的過程,以及載入預訓練權重的步驟。
內容解密:
在這個章節中,我們學習瞭如何儲存和載入模型和最佳化器的狀態字典。這個過程對於儲存和還原模型的訓練進度非常重要。另外,我們還學習瞭如何從 OpenAI 載入預訓練權重,這可以幫助我們快速初始化模型引數。
下載並載入GPT-2模型
首先,我們需要下載GPT-2模型的相關檔案。假設我們想要下載124M引數的GPT-2模型,我們可以使用以下Python程式碼:
import urllib.request
url = "https://example.com/gpt2_124M.tar.gz" # 請替換為實際的下載連結
filename = url.split('/')[-1]
urllib.request.urlretrieve(url, filename)
下載完成後,我們應該簡要檢查下載的檔案內容,以確保它們被正確儲存且包含有效的Python程式碼。
接下來,我們可以從gpt_download.py
檔案中匯入download_and_load_gpt2
函式,該函式會載入GPT-2模型的架構設定(settings)和權重引數(params):
from gpt_download import download_and_load_gpt2
settings, params = download_and_load_gpt2(
model_size="124M",
models_dir="gpt2"
)
執行這段程式碼會下載七個與124M引數GPT-2模型相關的檔案,包括:
- checkpoint
- encoder.json
- hprams.json
- model.ckpt.data-00000-of-00001
- model.ckpt.index
- model.ckpt.meta
- vocab.bpe
如果下載程式碼無法正常運作,可能是由於網路連線不穩定、伺服器問題或OpenAI分享開源GPT-2模型權重的方式發生變化。在這種情況下,請存取相關網站以取得替代和更新的指示,並透過Manning論壇提出進一步的問題。
假設前面的程式碼已經執行完成,讓我們檢查settings
和params
的內容:
print("Settings:", settings)
print("Parameter dictionary keys:", params.keys())
內容解密:
上述程式碼使用urllib.request.urlretrieve
函式下載GPT-2模型的相關檔案,並將其儲存到當前的工作目錄中。然後,匯入download_and_load_gpt2
函式以載入模型的架構設定和權重引數。最後,印出settings
和params
的內容,以便進一步檢查和使用。
圖表翻譯:
flowchart TD A[下載GPT-2模型] --> B[匯入download_and_load_gpt2函式] B --> C[載入模型架構設定和權重引數] C --> D[印出settings和params的內容]
此圖表展示了下載和載入GPT-2模型的流程,包括下載模型檔案、匯入相關函式、載入模型設定和權重引數,以及印出相關內容。
深入瞭解GPT模型架構
GPT(Generative Pre-trained Transformer)是一種由OpenAI開發的Transformer模型,主要用於自然語言生成任務。瞭解GPT模型的架構和設定對於掌握其工作原理至關重要。
GPT模型設定
GPT模型的設定通常包括以下幾個重要引數:
n_vocab
:詞彙表大小,決定了模型可以處理的唯一詞彙數量。n_ctx
:上下文視窗大小,決定了模型在生成文字時可以考慮的前後文長度。n_embd
:嵌入維度,決定了詞彙嵌入的維度大小。n_head
:多頭注意力機制中的頭數,影響了模型對不同語言特徵的關注能力。n_layer
:Transformer編碼器層數,決定了模型的深度和複雜度。
載入預訓練權重
OpenAI提供了多個不同大小的GPT模型,包括124M、355M、774M和1558M引數的模型。這些模型的架構相同,但引數數量和層數不同。載入預訓練權重可以讓我們直接使用這些模型進行文字生成、語言翻譯等任務。
Transformer塊重復
GPT模型透過重復Transformer塊來增加其深度和複雜度。不同大小的GPT模型有不同的Transformer塊重復次數:
- GPT-2小型模型(“gpt2-small”):12次重復。
- GPT-2中型模型(“gpt2-medium”):24次重復。
- GPT-2大型模型(“gpt2-large”):36次重復。
- GPT-2超大型模型(“gpt2-xl”):48次重復。
多頭注意力機制
多頭注意力機制是Transformer模型的一個關鍵元件,允許模型同時從不同的語言特徵中學習。不同大小的GPT模型有不同的多頭注意力頭數:
- GPT-2小型模型:12個頭。
- GPT-2中型模型:16個頭。
- GPT-2大型模型:20個頭。
- GPT-2超大型模型:25個頭。
嵌入維度
嵌入維度決定了詞彙嵌入的維度大小,不同大小的GPT模型有不同的嵌入維度:
- GPT-2小型模型:768維。
- GPT-2中型模型:1024維。
- GPT-2大型模型:1280維。
- GPT-2超大型模型:1600維。
圖表翻譯:
graph LR A[GPT-2小型] -->|12層|> B[Transformer塊] B -->|12頭|> C[多頭注意力] C -->|768維|> D[嵌入層] D --> E[文字生成] F[GPT-2中型] -->|24層|> G[Transformer塊] G -->|16頭|> H[多頭注意力] H -->|1024維|> I[嵌入層] I --> J[文字生成] K[GPT-2大型] -->|36層|> L[Transformer塊] L -->|20頭|> M[多頭注意力] M -->|1280維|> N[嵌入層] N --> O[文字生成] P[GPT-2超大型] -->|48層|> Q[Transformer塊] Q -->|25頭|> R[多頭注意力] R -->|1600維|> S[嵌入層] S --> T[文字生成]
這個圖表展示了不同大小的GPT模型的架構差異,包括Transformer塊的重復次數、多頭注意力機制的頭數和嵌入維度。這些差異直接影響了模型的效能和複雜度。
經過對溫度引數、Top-k 取樣、模型權過載入與儲存、預訓練權重使用以及 GPT 模型架構的深入探討,我們可以得出以下結論:從模型效能最佳化視角來看,有效控制隨機性對於提升大語言模型的生成品質至關重要。溫度引數和 Top-k 取樣提供了控制生成結果多樣性和一致性的有效手段,但需要根據具體應用場景仔細調整。此外,預訓練權重的使用顯著降低了訓練成本,而模型權重的儲存和載入機制則確保了研究的可重複性和效率。然而,模型大小和架構的選擇也需權衡計算資源和效能需求。對於資源有限的團隊,建議優先探索規模較小的模型,並逐步調整 Top-k 和溫度等引數以達到最佳平衡。展望未來,隨著硬體效能的提升和演算法的最佳化,更大規模的預訓練模型將更容易被應用,同時更精細的隨機性控制策略也將不斷湧現,進一步提升大語言模型的生成能力和應用價值。 玄貓認為,深入理解這些核心概念和技術細節,才能真正駕馭大語言模型的強大力量。