在大語言模型(如 GPT)中,單詞嵌入(Word Embeddings)是一個極為重要的概念。它不僅是語言模型理解自然語言的基礎,也是模型捕獲語義關系的關鍵環節。通過單詞嵌入,模型能夠將離散的單詞表示為高維連續向量,從而更高效地處理和生成自然語言。以下從理論與實踐的結合角度,詳細解析單詞嵌入的概念、實現以及應用。
單詞嵌入的定義與直觀解釋
單詞嵌入是將單詞映射到向量空間的一種技術。在這種空間中,語義相似的單詞往往會被映射到相鄰或接近的位置。具體來說,每個單詞通過一個向量(通常是高維的浮點數數組)表示。例如:
中文 “蘋果” 和 “橘子” 都屬于水果類別,它們在嵌入空間中的位置相對較近,而與 “汽車” 的位置較遠。
這種表示方式可以捕捉語義、語法等語言特性。模型基于嵌入向量,可以完成更復雜的自然語言任務。
理論基礎:如何構建單詞嵌入
共現矩陣與分布假設
單詞嵌入的構建與分布假設密切相關:一個單詞的意義由其上下文決定。例如,在句子 “我喜歡吃蘋果” 和 “他討厭橘子” 中,“蘋果” 和 “橘子” 常在相似的上下文中出現,這表明它們語義相近。
基于這種假設,可以構建一個共現矩陣,每行表示一個單詞,每列表示其上下文單詞,共現值為計數。比如:
| 喜歡 | 吃 | 他 | 討厭 | 橘子 | 蘋果 | |
|---|---|---|---|---|---|---|
| 蘋果 | 3 | 5 | 0 | 0 | 1 | 0 |
| 橘子 | 2 | 4 | 1 | 3 | 0 | 0 |
盡管這種方式簡單直觀,但維度過高且稀疏性嚴重。因此,需要通過降維和優化生成更高效的嵌入。
神經網絡方法:Word2Vec
Word2Vec 是一種流行的生成單詞嵌入的神經網絡模型,主要包括兩種訓練方法:
- CBOW(Continuous Bag of Words):預測一個單詞的上下文中包含哪些單詞。
- Skip-gram:給定一個單詞,預測其上下文。
以 CBOW 模型為例,假設我們有一個句子 “我喜歡吃蘋果”。
- 輸入:上下文單詞
“我”和“吃”。 - 輸出:目標單詞
“喜歡”。
通過訓練,模型學會將語義相似的單詞映射到相近的向量空間。
以下是一個基于 Python 和 TensorFlow 的簡化實現:
import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import skipgrams
# 示例語料
corpus = ["我 喜歡 吃 蘋果", "他 討厭 橘子"]
# 文本標記化
tokenizer = Tokenizer()
tokenizer.fit_on_texts(corpus)
word2idx = tokenizer.word_index
vocab_size = len(word2idx) + 1
# 生成 skip-gram 數據
sequences = tokenizer.texts_to_sequences(corpus)
data = []
for seq in sequences:
pairs, labels = skipgrams(seq, vocab_size, window_size=2)
data.extend(pairs)
# 構建簡單的嵌入模型
embedding_dim = 8
inputs = tf.keras.Input(shape=(2,))
input_target, input_context = tf.unstack(inputs, axis=1)
embedding = tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=embedding_dim)
target_embed = embedding(input_target)
context_embed = embedding(input_context)
dot_product = tf.reduce_sum(target_embed * context_embed, axis=1)
outputs = tf.keras.layers.Activation('sigmoid')(dot_product)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
model.compile(optimizer='adam', loss='binary_crossentropy')
# 模型訓練
x_train = np.array(data)
y_train = np.ones(len(data))
model.fit(x_train, y_train, epochs=5)
訓練后,可以提取嵌入向量:
word_embeddings = embedding.get_weights()[0]
print(word_embeddings)
嵌入向量的屬性分析
嵌入向量有以下幾個顯著屬性:
1. 語義相似性
嵌入向量能夠捕捉語義關系。例如,如果 “蘋果” 和 “橘子” 的嵌入向量在歐幾里得距離上較近,這表明它們的語義相似。
2. 線性可組合性
在嵌入空間中,許多語義關系具有線性可組合性。例如:
向量(“國王”) - 向量(“男人”) + 向量(“女人”) ≈ 向量(“女王”)。
這種屬性可以通過數學運算直接驗證:
king = word_embeddings[word2idx['國王']]
man = word_embeddings[word2idx['男人']]
woman = word_embeddings[word2idx['女人']]
queen = king - man + woman
3. 局限性與改進
盡管單詞嵌入性能優異,但也存在以下問題:
- 詞義模糊性:同一個單詞在不同語境下可能有不同含義(如
“蘋果”既可以指水果,也可以指品牌)。 - 上下文獨立性:傳統嵌入方法無法捕捉動態上下文。
為了解決這些問題,模型如 ELMo 和 BERT 引入了上下文敏感的嵌入方法。
真實世界案例:GPT 模型中的單詞嵌入
GPT 模型中的單詞嵌入進一步發展,在語料預處理和訓練過程中,采用了子詞單元(Subword Units)技術。與傳統方法相比,這種技術可以更高效地處理低頻詞和新詞。
Byte-Pair Encoding(BPE)
BPE 是 GPT 嵌入的重要組成部分,通過將單詞分解為子詞單元,緩解了詞表膨脹的問題。例如:
- 單詞
“喜歡”被分解為“喜”和“歡”。 - 新單詞
“機器學習”可以分解為“機”、“器”、“學”、“習”。
這種方式不僅減小了嵌入矩陣的尺寸,還增強了模型對新詞的泛化能力。
以下是一個簡單的 BPE 分解例子:
from collections import Counter
def bpe_encode(corpus, num_merges):
vocab = Counter(" ".join(corpus).split())
for _ in range(num_merges):
pairs = Counter()
for word, freq in vocab.items():
chars = list(word)
for i in range(len(chars)-1):
pairs[chars[i], chars[i+1]] += freq
most_common = max(pairs, key=pairs.get)
vocab = Counter({word.replace("".join(most_common), "".join(most_common)): freq for word, freq in vocab.items()})
return vocab
bpe_vocab = bpe_encode(["我喜歡吃蘋果", "他討厭橘子"], num_merges=10)
print(bpe_vocab)
總結
單詞嵌入是語言模型的基石,通過將單詞表示為連續向量,可以捕捉語義、語法等多維信息。在實際應用中,嵌入技術經歷了從靜態方法到動態方法的演進,如 Word2Vec 到 BERT,再到 GPT 模型中的子詞嵌入,展現了語言理解的更高水平。通過理論結合實踐,我們能夠更深刻地理解大語言模型中單詞嵌入的核心原理和應用場景。