1. 程式人生 > >Word Embeddings: Encoding Lexical Semantics(譯文)

Word Embeddings: Encoding Lexical Semantics(譯文)

air ams 缺陷 更新 rom sta ins less 但是

詞向量:編碼詞匯級別的信息

url:http://pytorch.org/tutorials/beginner/nlp/word_embeddings_tutorial.html?highlight=lookup

詞嵌入

詞嵌入是稠密向量,每個都代表了一個單詞表裏面的一個單詞。NLP中每個Feature都是單詞,但是怎麽在電腦中表示單詞呢??
ascii知識告訴我們每個單詞是啥,沒告訴我們是什麽意思。還有就是,怎麽融合這些表示呢?
第一步:通過one-hot編碼。w=[0,0,1,0,0]。其中1是表示w的獨一無二的維度。
但是缺點就是沒有語義信息。正交表示就沒有語義信息。
"出現在相似位置和相似語境中的單詞具有語義相關性!"這就是分布式假設

例子

假設每個維度是代表某種屬性(而不是one-hot中每種屬性都是一個單詞),那麽通過在每個維度上各種屬性的"調和",
就能夠獲取一個單詞,相似的單詞在某幾個"屬性上"類似,就會在向量空間距離變近。不相似的單詞夾角就會很大。
避免了每個維度大量出現0(one-hot的缺陷)
那麽問題就來了,每個維度代表什麽屬性怎麽設計,太難了,就讓神經網絡自己設計,不需要程序員設計了。
為啥不讓詞嵌入作為模型參數呢??在訓練中自己去更新!正是我們做的事情。
但是詞嵌入可解釋性不強,也就是說,訓練出來,每個維度代表什麽含義,不清楚。
但結果就是,近義詞在潛在語義維度上確實相近,卻難以解釋。
總而言之,詞嵌入是單詞的語義解釋。是高效的語義信息編碼。
當然可以去"embedding"其他任何事情:詞性標簽,解析樹。
特征嵌入的思想是這個領域的核心。

pytorch

通過PyTorch來進行Embedding。
類似於通過one-hot來對單詞進行索引,我們要使用Embedding去給每個單詞定義索引。
這是lookup table的關鍵所在。
這樣,embedding被存入|V|*D的矩陣,D是embedding的維度,就比如單詞的索引被存入矩陣的第i行。
在下面的代碼中,單詞到索引的映射是一個叫做word_to_ix的字典。
模塊是nn.Embedding,參數是詞匯表的size,和嵌入的維度
而且要註意,對於表的索引,使用torch.LongTensor,因為索引是整數,不是浮點數

CONTEXT_SIZE = 2
EMBEDDING_DIM = 10
# We will use Shakespeare Sonnet 2
test_sentence = """When forty winters shall besiege thy brow,
And dig deep trenches in thy beauty‘s field,
Thy youth‘s proud livery so gazed on now,
Will be a totter‘d weed of small worth held:
Then being asked, where all thy beauty lies,
Where all the treasure of thy lusty days;
To say, within thine own deep sunken eyes,
Were an all-eating shame, and thriftless praise.
How much more praise deserv‘d thy beauty‘s use,
If thou couldst answer ‘This fair child of mine
Shall sum my count, and make my old excuse,‘
Proving his beauty by succession thine!
This were to be new made when thou art old,
And see thy blood warm when thou feel‘st it cold.""".split()
# we should tokenize the input, but we will ignore that for now
# build a list of tuples.  Each tuple is ([ word_i-2, word_i-1 ], target word)
trigrams = [([test_sentence[i], test_sentence[i + 1]], test_sentence[i + 2])
            for i in range(len(test_sentence) - 2)]
# print the first 3, just so you can see what they look like
print(trigrams[:3])

vocab = set(test_sentence)#得到單詞的數量,編碼的基礎
word_to_ix = {word: i for i, word in enumerate(vocab)}#首先對單詞進行最簡單的編碼


class NGramLanguageModeler(nn.Module):

    def __init__(self, vocab_size, embedding_dim, context_size):
        super(NGramLanguageModeler, self).__init__()
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)#其實就是詞嵌入矩陣而已
        self.linear1 = nn.Linear(context_size * embedding_dim, 128)#由於是利用前面兩個詞進行預測的,因此需要將得到的單詞拼接起來,其實也可以加和,求平均什麽的
        self.linear2 = nn.Linear(128, vocab_size)#去分類

    def forward(self, inputs):
        embeds = self.embeddings(inputs).view((1, -1))#通過嵌入矩陣並且合並
        out = F.relu(self.linear1(embeds))
        out = self.linear2(out)
        log_probs = F.log_softmax(out)
        return log_probs


losses = []
loss_function = nn.NLLLoss()
model = NGramLanguageModeler(len(vocab), EMBEDDING_DIM, CONTEXT_SIZE)
optimizer = optim.SGD(model.parameters(), lr=0.001)

for epoch in range(10):
    total_loss = torch.Tensor([0])
    for context, target in trigrams:

        # Step 1. Prepare the inputs to be passed to the model (i.e, turn the words
        # into integer indices and wrap them in variables)
        context_idxs = [word_to_ix[w] for w in context]
        context_var = autograd.Variable(torch.LongTensor(context_idxs))

        # Step 2. Recall that torch *accumulates* gradients. Before passing in a
        # new instance, you need to zero out the gradients from the old
        # instance
        model.zero_grad()

        # Step 3. Run the forward pass, getting log probabilities over next
        # words
        log_probs = model(context_var)

        # Step 4. Compute your loss function. (Again, Torch wants the target
        # word wrapped in a variable)
        loss = loss_function(log_probs, autograd.Variable(
            torch.LongTensor([word_to_ix[target]])))

        # Step 5. Do the backward pass and update the gradient
        loss.backward()
        optimizer.step()

        total_loss += loss.data
    losses.append(total_loss)
print(losses)  # The loss decreased every iteration over the training data!

總結

之前還是一直沒有搞清詞向量的本質,拿捏不定,其實詞向量訓練的方法很多,但本質的思想是類似的。就是設置一個查詢表,也就是詞嵌入矩陣。通過這個查詢表,將原始稀疏的one-hot編碼成稠密向量。而查詢表需要通過訓練得到,也就是網絡中的參數。
技術分享圖片
那麽最終使用的就是這個權重矩陣的每行來表示對應位置的詞向量,和原始的索引相乘只是一個查表的操作。

Word Embeddings: Encoding Lexical Semantics(譯文)