一、什么是Negative Sampling
Negative Sampling是一种用于训练神经网络的技术,主要用于解决softmax函数在处理大规模多分类问题时计算复杂度高的问题。在Word2Vec模型中,为了避免对每个可能的上下文或者中心词计算所有单词的softmax概率,可以通过负采样(Negative Sampling)的方式来加速代码执行速度。
二、Negative Sampling的实现方式
对于所有的上下文和中心词单词,我们需要把它们表示为向量形式,比如在Word2Vec中,可以使用词向量来表示。另外,我们需要使用sigmoid函数来计算每个单词是否出现在文本序列中的概率。
假设我们有一个单词w和它的上下文单词wc1, wc2, …, wcn。为了训练我们的模型,我们需要把w和每个上下文单词表示为向量形式。假设w的向量为v_w,上下文单词wc1的向量为v_wc1,那么我们可以使用以下公式计算这两个向量之间的相似度:
sim(w, wc1) = dot(v_w, v_wc1) / ||v_w|| * ||v_wc1||
其中dot(v_w, v_wc1)是向量v_w和v_wc1的点积(内积),||v_w||和||v_wc1||分别是向量v_w和v_wc1的模长。
接着,我们需要使用sigmoid函数来计算单词w是否在上下文中出现的概率。
P(wc1 in context of w) = 1 / (1 + exp(-sim(w, wc1)))
然而,这个函数需要计算整个词汇表中每个单词作为上下文单词出现的概率,这是计算复杂度非常高的。因此,我们使用Negative Sampling技术来解决这个问题,即在每个训练样本中选择一部分单词作为negative的样本。这些样本对应于不在上下文中的单词,我们希望让神经网络能够将它们判定为负样本。为了实现这个过程,我们需要定义一个大小为k的unigram(均匀分布)概率分布。该分布是指从词库中随机选择k个单词作为negative样本的概率,注意,这个分布是按照单词的词频进行归一化的。
选定unigram分布后,我们可以按以下方式计算正样本和负样本的概率:
P(wc in context of w) = 1 / (1 + exp(-sim(w, wc))) P(neg in context of w) = 1 - P(wc in context of w)
其中,wc是正样本单词,neg是负样本单词。接着,我们可以定义代价函数来训练模型,计算正样本和负样本对于代价函数的贡献:
J(w, wc1, ... wcn) = -log(P(wc1, ... wcn in context of w)) - sum_{i=1}^{k}log(P(neg_i in context of w))
最终希望的是将代价函数最小化,使得神经网络可以较好地判断哪些单词是上下文单词,哪些单词是负样本。
三、Negative Sampling的代码实现
下面是利用Negative Sampling的Word2Vec模型的代码实现,代码实现了一个简单的模型,模型使用one-hot编码的方式来表示单词,使用随机梯度下降(SGD)方法进行训练。代码实现基于Python和numpy库。
import numpy as np import random class Word2Vec: def __init__(self, vocab_size, embedding_size): self.vocab_size = vocab_size self.embedding_size = embedding_size self.W = np.random.uniform(-1, 1, (vocab_size, embedding_size)) self.C = np.random.uniform(-1, 1, (embedding_size, vocab_size)) def train(self, data, window_size, negative_samples, learning_rate): num_samples = 0 total_loss = 0 for idx, word in enumerate(data): # randomly sample a window around word start = max(0, idx - window_size) end = min(len(data), idx + window_size + 1) context_words = set(data[start:idx] + data[idx+1:end]) for context_word in context_words: # update positive example sim = np.dot(self.W[word], self.C[:,context_word]) p = 1 / (1 + np.exp(-sim)) error = p - 1 self.W[word] -= learning_rate * error * self.C[:,context_word] self.C[:,context_word] -= learning_rate * error * self.W[word] # randomly sample negative examples sampled_words = [word] while len(sampled_words) < negative_samples + 1: w = random.randint(0, self.vocab_size - 1) if w not in context_words and w not in sampled_words: sampled_words.append(w) # update negative examples for neg_word in sampled_words[1:]: sim = np.dot(self.W[neg_word], self.C[:,context_word]) p = 1 / (1 + np.exp(-sim)) error = p self.W[neg_word] -= learning_rate * error * self.C[:,context_word] self.C[:,context_word] -= learning_rate * error * self.W[neg_word] # increment loss and sample counter total_loss += -np.log(p) num_samples += 1 # return average loss per sample return total_loss / num_samples
四、总结
Negative Sampling是加速神经网络处理多分类问题的一种方法,可以用于训练诸如Word2Vec模型等自然语言处理技术。它通过随机选择负采样样本,避免了对整个词汇表计算softmax函数的复杂度高问题,进而提高了代码的执行速度。在代码实现上,我们需要设计相应的代价函数和采样方式。因为Negative Sampling对于高纬度数据应用极为有效,所以在自然语言处理中是非常重要的一种工具。
原创文章,作者:UOUTY,如若转载,请注明出处:https://www.506064.com/n/329891.html