雖然花了很多篇幅在介紹 Transformer 模組,但到現在其實我們都沒有在訓練它,只是將架構給建立了起來。後續要為這個架構建立一個評估方式,並讓他持續學習直到越來越好。
說到在訓練模型中的評估,不外乎就是要去定義這個大模型的 Loss Function 是什麼樣子並實做出來?由於模型現在內部的權重矩陣都是隨機值,我們希望訓練過後的模型,可以讓產生出來的 ID 索引機率分布(Logit) 與正確的 ID 索引位置是越接近越好。
先以一個很小的案例為例,這是一個僅有三個字的文本:
inputs = torch.tensor([[16833, 3626, 6100], # ["every effort moves",
[40, 1107, 588]]) # "I really like"]
targets = torch.tensor([[3626, 6100, 345 ], # [" effort moves you",
[1107, 588, 11311]]) # " really like chocolate"]
如果將三個字的結果送進模型後,在將模型產出的 Logit 經過 Softmax 來看機率分數,最後透過 argmax 轉回 token ID,在 decode 回文字:
logits = model(inputs)
probas = torch.softmax(logits, dim=-1)
token_ids = torch.argmax(probas, dim=-1, keepdim=True)
print(f"Targets batch 1: {token_ids_to_text(targets[0], tokenizer)}")
print(f"Outputs batch 1: {token_ids_to_text(token_ids[0].flatten(), tokenizer)}")
這是一個將 model 輸出結果反向轉回文字的過程,如果中間有什麼步驟可以先抓出來當作 Loss Function 要比較的對象,那就是輸出的機率分數,讓我們想要出現的 token 的機率分數越大越好:
text_idx = 0
target_probas_1 = probas[text_idx, [0, 1, 2], targets[text_idx]]
text_idx = 1
target_probas_2 = probas[text_idx, [0, 1, 2], targets[text_idx]]
首先因為一些數學上的理由,這裡很多數字都變得很小,先透過取 log 讓數字回歸到比較好計算的大小:
log_probas = torch.log(torch.cat((target_probas_1, target_probas_2)))
接著將這些數字,加總並取平均,目的是要看這些差的總分,而我們會統一讓值落在正值,並在計算上期待是一個正值怎麼透過數學計算逐漸趨於 0,這就是 Cross Entropy:
avg_log_probas = torch.mean(log_probas)
neg_avg_log_probas = avg_log_probas * -1