基于CBOW模型的詞向量訓練實戰:從原理到PyTorch實現
在自然語言處理(NLP)領域,詞向量是將單詞映射為計算機可處理的數值向量的重要方式。通過詞向量,單詞之間的語義關系能夠以數學形式表達,為后續的文本分析、機器翻譯、情感分析等任務奠定基礎。本文將結合連續詞袋模型(CBOW),詳細介紹如何使用PyTorch訓練詞向量,并通過具體代碼實現和分析訓練過程。
一、CBOW模型原理簡介
CBOW(Continuous Bag-of-Words)模型是一種用于生成詞向量的神經網絡模型,它基于上下文預測目標詞。其核心思想是:給定一個目標詞的上下文單詞,通過模型預測該目標詞。在訓練過程中,模型會不斷調整參數,使得預測結果盡可能接近真實的目標詞,最終訓練得到的詞向量能夠捕捉單詞之間的語義關系。
例如,在句子 “People create programs to direct processes” 中,如果目標詞是 “programs”,CBOW模型會利用其上下文單詞 “People”、“create”、“to”、“direct” 來預測 “programs”。通過大量類似樣本的訓練,模型能夠學習到單詞之間的語義關聯,從而生成有效的詞向量。
二、代碼實現與詳細解析
下面我會逐行解釋你提供的代碼,此代碼借助 PyTorch 實現了一個連續詞袋模型(CBOW)來學習詞向量。
1. 導入必要的庫
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from tqdm import tqdm, trange # 顯示進度條
import numpy as np
torch
:PyTorch 深度學習框架的核心庫。torch.nn
:用于構建神經網絡的模塊。torch.nn.functional
:提供了許多常用的函數,像激活函數等。torch.optim
:包含各種優化算法。tqdm
和trange
:用于在訓練過程中顯示進度條。numpy
:用于處理數值計算和數組操作。
2. 定義上下文窗口大小和原始文本
CONTEXT_SIZE = 2
raw_text = """We are about to study the idea of a computational process.
Computational processes are abstract beings that inhabit computers.
As they evolve, processes manipulate other abstract things called data.
The evolution of a process is directed by a pattern of rules called a program.
People create programs to direct processes.
In effect,we conjure the spirits of the computer with our spells.""".split()
CONTEXT_SIZE
:上下文窗口的大小,意味著在預測目標詞時,會考慮其前后各CONTEXT_SIZE
個單詞。raw_text
:原始文本,將其按空格分割成單詞列表。
3. 構建詞匯表和索引映射
vocab = set(raw_text) # 集合,詞庫,里面的內容獨一無二(將文本中所有單詞去重后得到的詞匯表)
vocab_size = len(vocab) # 詞匯表的大小word_to_idx = {word: i for i, word in enumerate(vocab)} # 單詞到索引的映射字典
idx_to_word = {i: word for i, word in enumerate(vocab)} # 索引到單詞的映射字典
vocab
:把原始文本中的所有單詞去重后得到的詞匯表。vocab_size
:詞匯表的大小。word_to_idx
:將單詞映射為對應的索引。idx_to_word
:將索引映射為對應的單詞。
4. 構建訓練數據集
data = [] # 獲取上下文詞,將上下文詞作為輸入,目標詞作為輸出,構建訓練數據集(用于存儲訓練數據,每個元素是一個元組,包含上下文詞列表和目標詞)
for i in range(CONTEXT_SIZE, len(raw_text) - CONTEXT_SIZE):context = ([raw_text[i - (2 - j)] for j in range(CONTEXT_SIZE)]+ [raw_text[i + j + 1] for j in range(CONTEXT_SIZE)]) # 獲取上下文詞target = raw_text[i] # 獲取目標詞data.append((context, target)) # 將上下文詞和目標詞保存到 data 中
data
:用于存儲訓練數據,每個元素是一個元組,包含上下文詞列表和目標詞。- 通過循環遍歷原始文本,提取每個目標詞及其上下文詞,然后將它們添加到
data
中。
5. 定義將上下文詞轉換為張量的函數
def make_context_vector(context, word_to_ix): # 將上下詞轉換為 one - hotidxs = [word_to_ix[w] for w in context]return torch.tensor(idxs, dtype=torch.long)
make_context_vector
:把上下文詞列表轉換為對應的索引張量。
6. 打印第一個上下文詞的索引張量
print(make_context_vector(data[0][0], word_to_idx))
- 打印第一個訓練樣本的上下文詞對應的索引張量。
7. 定義 CBOW 模型
class CBOW(nn.Module): # 神經網絡def __init__(self, vocab_size, embedding_dim):super(CBOW, self).__init__()self.embeddings = nn.Embedding(vocab_size, embedding_dim)self.proj = nn.Linear(embedding_dim, 128)self.output = nn.Linear(128, vocab_size)def forward(self, inputs):embeds = sum(self.embeddings(inputs)).view(1, -1)out = F.relu(self.proj(embeds)) # nn.relu() 激活層out = self.output(out)nll_prob = F.log_softmax(out, dim=1)return nll_prob
CBOW
:繼承自nn.Module
,定義了 CBOW 模型的結構。__init__
:初始化模型的層,包含一個嵌入層、一個線性層和另一個線性層。forward
:定義了前向傳播過程,將輸入的上下文詞索引轉換為嵌入向量,求和后經過線性層和激活函數,最后輸出對數概率。
8. 選擇設備并創建模型實例
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device") # 字符串的格式化
model = CBOW(vocab_size, 10).to(device)
device
:檢查當前設備是否支持 GPU(CUDA 或 MPS),若支持則使用 GPU,否則使用 CPU。model
:創建 CBOW 模型的實例,并將其移動到指定設備上。
9. 定義優化器、損失函數和損失列表
optimizer = optim.Adam(model.parameters(), lr=0.001) # 創建一個優化器,
losses = [] # 存儲損失的集合
loss_function = nn.NLLLoss()
optimizer
:使用 Adam 優化器來更新模型的參數。losses
:用于存儲每個 epoch 的損失值。loss_function
:使用負對數似然損失函數。
10. 訓練模型
model.train()for epoch in tqdm(range(200)):total_loss = 0for context, target in data:context_vector = make_context_vector(context, word_to_idx).to(device)target = torch.tensor([word_to_idx[target]]).to(device)# 開始向前傳播train_predict = model(context_vector)loss = loss_function(train_predict, target)# 反向傳播optimizer.zero_grad()loss.backward()optimizer.step()total_loss += loss.item()losses.append(total_loss)print(losses)
model.train()
:將模型設置為訓練模式。- 通過循環進行 200 個 epoch 的訓練,每個 epoch 遍歷所有訓練數據。
- 將上下文詞和目標詞轉換為張量并移動到指定設備上。
- 進行前向傳播得到預測結果。
- 計算損失。
- 進行反向傳播并更新模型參數。
- 累加每個 epoch 的損失值。
11. 進行預測
context = ['People', 'create', 'to', 'direct']
context_vector = make_context_vector(context, word_to_idx).to(device)model.eval() # 進入到測試模式
predict = model(context_vector)
max_idx = predict.argmax(1) # dim = 1 表示每一行中的最大值對應的索引號, dim = 0 表示每一列中的最大值對應的索引號print("CBOW embedding weight =", model.embeddings.weight) # GPU
W = model.embeddings.weight.cpu().detach().numpy()
print(W)
- 選擇一個上下文詞列表進行預測。
model.eval()
:將模型設置為評估模式。- 進行預測并獲取預測結果中概率最大的索引。
- 打印嵌入層的權重,并將其轉換為 NumPy 數組。
12. 構建詞向量字典
word_2_vec = {}
for word in word_to_idx.keys():word_2_vec[word] = W[word_to_idx[word], :]
print('jiesu')
word_2_vec
:將每個單詞映射到其對應的詞向量。
13. 保存和加載詞向量
np.savez('word2vec實現.npz', file_1 = W)
data = np.load('word2vec實現.npz')
print(data.files)
np.savez
:將詞向量保存為.npz
文件。np.load
:加載保存的.npz
文件,并打印文件中的數組名稱。
綜上所述,這段代碼實現了一個簡單的 CBOW 模型來學習詞向量,并將學習到的詞向量保存到文件中。 。運行結果
三、總結
通過上述代碼的實現和分析,我們成功地使用CBOW模型在PyTorch框架下完成了詞向量的訓練。從數據準備、模型定義,到訓練和測試,再到詞向量的保存,每一個步驟都緊密相連,共同構建了一個完整的詞向量訓練流程。
CBOW模型通過上下文預測目標詞的方式,能夠有效地學習到單詞之間的語義關系,生成的詞向量可以應用于各種自然語言處理任務。在實際應用中,我們還可以通過調整模型的超參數(如詞向量維度、上下文窗口大小、訓練輪數等),以及使用更大規模的數據集,進一步優化詞向量的質量和模型的性能。希望本文的內容能夠幫助讀者更好地理解CBOW模型和詞向量訓練的原理與實踐。