Bag of words model又称为词袋模型,顾名思义,一段文本可以用一个装着这些词的袋子来表示。词袋模型通常将单词和句子表示为数字向量的形式,其中向量元素为句子中此单词在词袋表出现的次数。然后将数字向量输入分类器(例如Naive Bayes),进而对输出进行预测。这种表示方式不考虑文法以及词的顺序。
例如以下两个句子:
John likes to watch movies. Mary likes movies too.
假设有一句子"The quick brown fox jumps over the lazy dog" ,设定的窗口大小为2(),也就是说仅选中心词(input word)前后各两个词和中心词(input word)进行组合。如下图所示,以步长为1对中心词进行滑动,其中蓝色代表input word,方框代表位于窗口列表的词。
所以,我们可以使用Skip-Gram构建出神经网络的训练数据。
我们需要明白,不能把一个词作为文本字符串输入到神经网络中,所以我们需要一种方法把词进行编码进而输入到网络。为了做到这一点,首先从需要训练的文档中构建出一个词汇表,假设有10,000个各不相同的词组成的词汇表。那么需要做的就是把每一个词做One hot representation。此外神经网络的输出是一个单一的向量(也有10000个分量),它包含了词汇表中每一个词随机选择附近的一个词的概率。
3.4 Skip-Gram网络结构
下图是需要训练的神经网络结构。左侧的神经元Input Vector是词汇表中进行One hot representation后的一个词,右侧的每一个神经元则代表着词汇表的每一个词。实际上,在对该神经网络feed训练数据进行训练时,不仅输入词input word(中心词)是用One hot representation表示,输出词output word也是用One hot representation进行表示。但当对此网络进行评估预测时,输出向量实际上是通过softmax()函数计算得到的一个词汇表所有词的概率分布(即一堆浮点值,而不是一个One hot representation)。
你可能会问自己,难道真的分别要把每一个One hot representation的词(1 x 10000)与一个10000 x 300的权矩阵相乘吗?实际上,并不是这样。由于One hot representation的词具有只有一个元素这为1,其余元素值为0的特性,所以可以通过查找One hot representation中元素为1的位置索引,进而获得对应要乘以的10000 x 300的权矩阵的向量值,从而解决计算速度缓慢的问题。下图的例子,可帮助我们进一步理解。
可以看到,One hot representation中元素为1的位置索引为3,所以只需要乘以10000 x 300的权矩阵中位置索引同样为3的向量值即可得到相应的输出。
3.6 Word2Vec Model输出层
下面是计算“car”这个单词的输出神经元的输出的例子:
4. 基于Tensorflow的Skip-Gram极简实现
网上找了一些Tensorflow版本的skip-gram实现,但都有一个问题,输入单词并没有按照论文的要求做One hot representation,不知道是不是出于计算速度方面的考虑。因此,本小节的代码还是遵循原论文的描述,对输入单词及输出单词首先做了One hot representation。
首先,是训练数据的构造,包括skip_window上下文参数、词的One hot representation以及中心词、输出词对的构造。
import numpy as np
corpus_raw = 'He is the king . The king is royal . She is the royal queen ’
# 大小写转换 corpus_raw = corpus_raw.lower() words = [] for word in corpus_raw.split(): if word != ‘.’: words.append(word)
# 创建一个字典,将单词转换为整数,并将整数转换为单词。 words = set(words) word2int = {} int2word = {} vocab_size = len(words) for i, word in enumerate(words): word2int[word] = i int2word[i] = word
raw_sentences = corpus_raw.split(’.’) sentences = [] for sentence in raw_sentences: sentences.append(sentence.split())
# 构造训练数据
WINDOW_SIZE = 2 data = [] for sentence in sentences: for word_index, word in enumerate(sentence): for nb_word in sentence[max(word_index - WINDOW_SIZE, 0): min(word_index + WINDOW_SIZE, len(sentence)) + 1]: if nb_word != word: data.append([word, nb_word])