• ud730深度学习(二)——Word2Vec and CBOW


    近年来,基于神经网络来得到词表示的模型备受青睐。这类模型所得到的词的向量表示是分布式表示distributed representation,通常被称为wordembedding(词嵌入;词向量)。2013年的开源工具包word2vec包含了CBOW(Continuous Bag-of-Words)和Skip-gram这两个直接以得到词向量为目标的模型。

    word2vec的流程是这样的:词汇嵌入表示成一个短向量,然后把短向量传给带有权值和偏置的简单线性模型,得到softmax概率,这个softmax概率和context中的词进行比较,由于周围词可能非常多,因此只挑选一小部分,假装其他非目标词不存在。我们用一个大型文本语料库,对其中每个词做嵌入表示,再去预测在其附近出现的词,由此得到词到向量的映射,词义相近,映射出来的向量也相近。

    在CBOW/Skip-gram模型中,target(目标词或中心词)是一个词串中间的词而不是最后一个词,其拥有的context(上下文或周围词)为前后各m个词。任一个词将得到两个word embedding(设维度为n):作为中心词时的词向量,也称为输出词向量;以及作为周围词时的词向量,也称为输入词向量。词表中每个词的词向量都存在一个矩阵中。由于存在两套词向量,因此就有两个矩阵:输入词矩阵,其每一列都是一个词作为周围词时的词向量;输出词矩阵,其每一行都是一个词作为中心词时的词向量。比如说若想取出词作为周围词时的词向量,只要知道词在词表中的编号即可,取出的操作相当于用输入词矩阵乘以词的one-hot representation。

    CBOW通过上下文来预测中心词。

    CBOW的代码已上传到github:https://github.com/Mandalalala/lesson/tree/master/ud730

    任务 5: Word2Vec and CBOW

    使用 Text8 的数据训练一个 skip-gram 模型并可视化输出

    注意: 这个课程中的任务是相互关联的,请按顺序完成。

    初始代码

    打开 IPython notebook 中的这个任务 (https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/udacity/5_word2vec.ipynb),按照指导去完成和运行每一个步骤。第一个模型 (Word2Vec) 已经提供给你,请以此作为参考,训练一个CBOW (Continuous Bag of Words) 模型。

    使用text8作为训练的文本数据集。text8中只包含27种字符:小写的从a到z,以及空格符。如果把它打出来,读起来就像是去掉了所有标点的wikipedia。

    初始代码训练的是Skip-gram模型,是根据目标词汇预测上下文,而word2vec还有一种方式,CBOW,根据上下文预测目标词汇。

    数据处理,构建索引

    defbuild_dataset(words)

    可以看出,索引反映了该单词在文中出现的次数。其中data中的索引存在着上下文的关系。其中UNK是较少使用的单词。

    大小

    格式

    含义

    data

    words_size

    [5234, 3082, 12, 6, 195,…]

    Words中的单词对应dictionary中的索引

    count

    vocabulary_size

    ['UNK', 418391], ('the', 1061396), ('of', 593677),…]

    按出现次数排序

    dictionary

    vocabulary_size

    ['removable': 21031, 'bush': 1820, 'ames': 15348,…]

    根据单词查索引

    reverse_dictionary

    vocabulary_size

    {0: 'UNK', 1: 'the', 2: 'of', 3: 'and',…}

    根据索引查单词

    产生训练对

    defgenerate_batch(batch_size, num_skips, skip_window)

    在skip-gram中,输入是目标词汇,输出是上下文。

    batch_size:每次训练的单词数。声明batch_size % num_skips == 0。

    num_skips:从span中选择的上下文的个数,比如num_skips为4,则单词as有4个。也就是找num_skips个上下文。因此声明num_skips <= 2 *skip_window。

    skip_window:规定上文大小或者下文大小。

    span:目标词和它的上下文的大小之和。

    buffer:大小为span,存储目标词和它的上下文。这里隐含着词语和词语之间的联系信息。比如buffer[0]索引指向的单词在buffer[1]对应单词的前面。并且规定了最大长度,随着新词的涌入,最旧的词会被挤出去。

    buffer.append(data[data_index])
    data_index = (data_index + 1) % len(data)
    

    batch:目标词的索引。

    label:目标词的上下文所对应的索引。

    data_index:从0开始,按顺序取words中的词。

    打印出索引所对应的单词:

    看到num_skips决定了中心词出现的次数。

    在CBOW中,输入是上下文,输出是目标词汇。

    因此需要改变batch的大小。

    batch:shape=(batch_size, num_skips)。batch[i,j]中,i是验证样本序号,j是上下文的序号,通过num_skips个上下文来推断中心词,batch[i,j]指第i个中心词的第j个上下文的索引。

    labels:对应目标词的索引。

    num_skips:上下文的个数。

    建立图

    embeddings是一个大小为[vocabulary_size, embedding_size]的矩阵,设置里面的元素大小为-1到1之间,每一行表示一个词,所以一共有vocabulary_size。调用tf.nn.embedding_lookup,索引与train_dataset对应的向量,相当于用train_dataset作为一个id,去检索矩阵中与这个id(词)对应的embedding。

    embed =tf.nn.embedding_lookup(embeddings, train_dataset)

    返回的embed是一个大小为(batch_size,embedding_size)的矩阵,表示训练集中的词对应的词向量。然后计算softmax损失(由于数据量比较大,因此选择tf.nn.sampled_softmax_loss),通过最小化损失进行优化。优化器会优化softmax权值和词向量。

    接下来计算样本和所有词向量之间的相似度,采用cosine距离。对embeddings的每个元素进行平方,然后将一个词的所有上下文的平方相加,即tf.reduce_sum(tf.square(embeddings), 1,keep_dims=True)。这样得出的是大小为vocabulary_size的向量,对该向量开根号得到norm,将原始embeddings除以norm得到标准化之后的词向量normalized_embeddings。整个过程如下:

    norm =tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))

    normalized_embeddings= embeddings / norm

    计算相似度:将valid_embeddings和标准化之后的向量进行乘积。sim是一个大小为[valid_size,vocabulary]的数组。sim[i,:]是valid_dataset[i]和其它元素的相似程度。

    在CBOW中,由于输入是一个二维向量,每一行表示词的上下文,因此在检索完id对应的词向量之后,embeddingss是一个大小为[vocabulary_size, num_skips, embedding_size]的三维数组,把vocabulary_size和embedding_size相同的元素相加,使之大小降为[vocabulary_size, embedding_size]。

    验证

    当经过一定时间训练,计算词之间的相似度,对验证集中的词i,选择和验证集相似度最高的前top_k个元素,nearest = (-sim[i, :]).argsort()[1:top_k+1],这里取1到top_k+1是因为0的位置是词本身。

    对CBOW,由于词是多个词表示的,因此选择多个词预测相似度。

    降维可视化

    从sklearn.manifold引入TSNE。

    class sklearn.manifold.TSNE(n_components=2, perplexity=30.0,early_exaggeration=4.0, learning_rate=1000.0, n_iter=1000,n_iter_without_progress=30, min_grad_norm=1e-07, metric='euclidean',init='random', verbose=0, random_state=None, method='barnes_hut', angle=0.5)

    n_components:向量空间的维度。

    perplexity:混乱程度。该参数并不是很重要,因为TSNE对此不敏感。

    early_exaggeration:放大度。

    n_iter:优化过程中最多的迭代次数。

    init:词向量的初始化。可选:random,PCA,以及(n_samples,n_components)的数组。PCA初始化不能够使用预先计算的距离,通常比随机初始化更加稳定。

    fit_transform(X, y=None)

    将X放进一个向量空间,返回转换后的结果。

    小结

    经过10000次训练,loss从7降到3,打印出结果发现使用CBOW,返回的中心词属于上下文的情况非常多。这种情况出现的原因是验证集的输入采用的是随机选词的方法,随机选择的词与词之间可能没有相关性,因此导致结果不准确。

    参考资料:

    http://www.cnblogs.com/Determined22/p/5804455.html

    http://www.jianshu.com/p/45dbfe5809d4

    http://www.jeyzhang.com/tensorflow-learning-notes-3.html

  • 相关阅读:
    参考文献怎么写~(这个老是忘,所以贴在这里)
    STL 容器之 priority_queue小结
    新闻发布系统-项目总结
    【DataStructure In Python】Python模拟二叉树
    【HDOJ】2062 Subset sequence
    【POJ】1054 The Troublesome Frog
    【Pyhton Network】使用poll()或select()实现非阻塞传输
    【Python Network】分解DNS查询结果
    【DataStructure In Python】Python实现各种排序算法
    【Python Network】权威域名服务器级联查询
  • 原文地址:https://www.cnblogs.com/mandalalala/p/6798259.html
Copyright © 2020-2023  润新知