【笔记3-2】CS224N课程笔记+作业参考代码 - 词向量表示 word2vec

CS224N(二)Word Vectors

  • 如何表示字的含义
  • 基于SVD的方法
  • 基于迭代的方法 - Word2vec
    • CBOW (continuous bag of words)
    • skip-gram
  • 梯度的推导过程
  • skip-gram和CBOW的改进
  • Assignment 1 参考代码

【笔记3-1】CS224N课程笔记 - 深度自然语言处理
【笔记3-3】CS224N课程笔记 - 高级词向量表示
【笔记3-4】CS224N课程笔记 - 分类与神经网络
【笔记3-5】CS224N课程笔记 - 依存分析
【笔记3-6】CS224N课程笔记 - RNN和语言模型
【笔记3-7】CS224N课程笔记 - 神经机器翻译seq2seq注意力机制
【笔记3-8】CS224N课程笔记 - 卷积神经网络

CS224n:深度学习的自然语言处理(2017年冬季)1080p https://www.bilibili.com/video/av28030942/

涉及到的论文:

Efficient Estimation of Word Representations in Vector Space (2013,Tomas Mikolov, Kai Chen, Greg Corrado, Jeffrey Dean)
https://arxiv.org/pdf/1301.3781.pdf

Distributed Representations of Words and Phrases and their Compositionality (2013, Tomas Mikolov, Ilya Sutskever, Kai Chen, Greg Corrado, Jeffrey Dean)
https://arxiv.org/pdf/1310.4546.pdf
关键词:词向量,SVD,skip-gram,CBOW,负采样,word2vec,hierarchical softmax

如何表示字的含义

meaning=denotation:
signifier (symbol) ⇔ \Leftrightarrow signified (idea or thing)
Usable meaning in computer:
以往会使用WordNet来查找同义词以及重名词

WorldNet的缺点:

  1. 缺乏字词之间的细微差别
  2. 丢失字词的新含义
  3. 带有主观色彩
  4. 需要大量的人力劳动进行标注
  5. 难以准确计算字词之间的相似性

出发点:字典里面有许多不同的单词,如果要对字典里的N个单词进行表示,需要将其映射到一个N维的空间,但是,实际上很多单词之间存在关联,由此出发,必定存在一个K维的空间,K<

字词的离散型符号表示:
独热码向量表示: 向量的维度 = 字典当中单词的个数。
根据字典中单词的个数N构造一个N维的向量,对于第i个单词,在第i维对该单词赋值为1,其余值为零。由于只有一个数字为1,称为独热码,即one-hot vector。

缺点: 所有向量之间都是正交的,无法获取词语之间的相似性。
解决方法: 自动学习向量之间的相似性表示,用更低维度的向量来表示每一个单词。

用上下文来表示单词:
由于单词的意思可以通过上下文来得到反映,因此可以使用单词周边的上下文来对中心词的词表示进行构建。

构建词向量的方法: (word embedding/representation)
对每一个单词构建一个密集向量,使得会出现在相同的上下文当中的具有相同含义的词语具有相似的向量表示。

基于SVD的方法

对于SVD构造的词向量,先对整个数据集进行遍历,并统计所有单词的共现现象,来生成一个矩阵X。然后对这个矩阵进行奇异值分解,即 X = U S V T X = USV^T X=USVT,然后取矩阵U的行向量作为整个字典中单词的词向量表示。

矩阵X的构造方法:

  1. 构造单词-文档矩阵
    这个矩阵构造方法基于一个假设,即认为相似的单词总是会经常在一个文档当中同时出现,所以在构造的时候会遍历所有的M个文档,看字典中的V个单词是否在文档中出现过,对于每个单词i在文档j中出现一次,就对Xij加一。但是这样构造出来的矩阵会十分庞大 X ∈ R V ∗ M X \in \mathbb{R}^{V*M} XRVM因此需要采用一个更好的X矩阵的构造方式。
  2. 基于窗口的共现矩阵
    这个方法的思想和前面所述的方法类似,但是不再是对所有文档进行遍历,而是对单词窗口内的共现单词进行统计。步骤如下:
    (1)构造一个维度V x V的共现矩阵X
    (2)对X进行SVD,得到 X = U S V T X = USV^T X=USVT
    (3)选择矩阵U的前K列作为K维的单词向量表示
    (4)得到K维的向量表示之后, ∑ i = 1 k σ i ∑ i = 1 ∣ V ∣ σ i \frac{\sum_{i=1}^{k}\sigma_i}{\sum_{i=1}^{|V|}\sigma_i} i=1Vσii=1kσi代表该K维向量表示所包含的字典整体的方差比例。

上述方法能够给我们提供单词的语义和词性信息,但是这个方法依旧存在一定的问题

  1. X矩阵的经常需要根据新单词的加入而不断改变
  2. 由于很多词语是不经常一起出现的,因此构造出来的X矩阵会十分稀疏
  3. 构造出来的矩阵往往维度很高
  4. 对矩阵X进行SVD分解时,计算量较大
  5. 需要处理X构造时某些词语经常出现的问题,如the, a等

因此提出基于迭代的方法-word2vec来解决上述问题。

基于迭代的方法 - Word2vec

与上述需要遍历整个文档库的SVD方法不同,word2vec的方法每次迭代都会对单词基于上下文的概率进行更新。

大致思想:设计一个模型,用模型的参数来作为单词的向量表示,然后对模型进行训练,在每次迭代中根据loss对参数进行更新,最终得到的更新过后的参数就是单词的向量表示。

word2vec当中包含两种算法:CBOW(根据上下文词汇的词向量来预测中心词)skip-gram(根据中心词来预测上下文单词的概率分布)
还包含两种训练方法:负采样(通过采集负样本来构造新的目标函数)分层softmax(使用不对称的树结构来高效地计算每个词出现的概率)

CBOW (continuous bag of words)

CBOW是根据上下文预测或生成中心词的方法。

  1. 对于输入的上下文单词(窗口大小为m)生成其对应的独热码 ( x ( c − m ) , . . . . . . , x ( c − 1 ) , x ( c + 1 ) , . . . . . . , x ( c + m ) ) ∈ R ∣ V ∣ (x^{(c-m)},......,x^{(c-1)},x^{(c+1)},......,x^{(c+m)})\in \mathbb{R}^{|V|} (x(cm),......,x(c1),x(c+1),......,x(c+m))RV
  2. 构建两个矩阵, V ∈ R n ∗ ∣ V ∣ , U ∈ R ∣ V ∣ ∗ n V\in\mathbb{R}^{n*|V|},U\in\mathbb{R}^{|V|*n} VRnV,URVn,其中,n为构造的词嵌入空间的维度,V为输入单词矩阵,其中第i列为单词 w i w_i wi作为模型输入时的n维词嵌入向量 v i v_i vi,U为输出单词矩阵,第j行为单词 w i w_i wi作为模型输出时的n维词嵌入向量 u i u_i ui,因此每个单词作为输入和输出时分别有两个向量。据此得到上下文的词嵌入向量 ( v c − m = V x ( c − m ) , v c − m + 1 = V x ( c − m + 1 ) , . . . . . . , v c + m = V x ( c + m ) ∈ R n ) (v_{c-m}=Vx^{(c-m)},v_{c-m+1}=Vx^{(c-m+1)},......,v_{c+m}=Vx^{(c+m)}\in \mathbb{R}^n) (vcm=Vx(cm),vcm+1=Vx(cm+1),......,vc+m=Vx(c+m)Rn)
  3. 对上下文向量进行平均 v ^ = v c − m + v c − m + 1 + . . . + v c + m 2 m ∈ R n \hat{v}=\frac{v_{c-m}+v_{c-m+1}+...+v_{c+m}}{2m}\in\mathbb{R}^n v^=2mvcm+vcm+1+...+vc+mRn
  4. 生成一个分值向量 z = U v ^ ∈ R ∣ V ∣ z=U\hat{v}\in\mathbb{R}^{|V|} z=Uv^RV
  5. 将分值向量转换成概率 y ^ = s o f t m a x ( z ) ∈ R ∣ V ∣ \hat{y}=softmax(z)\in \mathbb{R}^{|V|} y^=softmax(z)RV,使输出的概率向量向真实输出的独热码靠近。

了解CBOW的算法之后,就是对矩阵U和V的构造过程,需要根据目标损失函数使用梯度下降的方法求解。

根据信息论当中对两个分布的距离的计算方法,使用交叉熵来计算损失函数: H ( y ^ , y ) = − ∑ j = 1 ∣ V ∣ y j l o g ( y ^ j ) = − y i l o g ( y ^ i ) H(\hat{y},y)=-\sum_{j=1}^{|V|}y_jlog(\hat{y}_j)=-y_ilog(\hat{y}_i) H(y^,y)=j=1Vyjlog(y^j)=yilog(y^i)因此优化目标为: m i n J = − l o g P ( w c ∣ w c − m , . . . , w c − 1 , w c + 1 , . . . , w c + m ) = − l o g P ( u c ∣ v ^ ) = − l o g e x p ( u c T v ^ ) ∑ j = 1 ∣ V ∣ e x p ( u j T v ^ ) = − u c T v ^ + l o g ∑ j = 1 ∣ V ∣ e x p ( u j T v ^ ) min J = -logP(w_c|w_{c-m},...,w_{c-1},w_{c+1},...,w_{c+m})\\ =-logP(u_c|\hat{v})=-log\frac{exp(u_c^T\hat{v})}{\sum_{j=1}^{|V|}exp(u_j^T\hat{v})}\\ =-u_c^T\hat{v}+log\sum_{j=1}^{|V|}exp(u_j^T\hat{v}) minJ=logP(wcwcm,...,wc1,wc+1,...,wc+m)=logP(ucv^)=logj=1Vexp(ujTv^)exp(ucTv^)=ucTv^+logj=1Vexp(ujTv^)优化的过程中使用SGD对参数进行更新。

skip-gram

思想与CBOW类似,但是这里是利用中心词来对上下文单词出现的概率进行预测。

  1. 对中心词生成其对应的独热码向量 x ∈ R ∣ V ∣ x\in \mathbb{R}^{|V|} xRV
  2. 对中心词生成其对应的词嵌入向量 v c = V x ∈ R n v_c=Vx\in \mathbb{R}^n vc=VxRn
  3. 生成一个分值向量 z = U v c z = Uv_c z=Uvc
  4. 将分值向量变成概率分布 y ^ = s o f t m a x ( z ) \hat{y}=softmax(z) y^=softmax(z),需要注意的是,这里生成的概率 y ^ c − m , . . . , y ^ c − 1 , y ^ c + 1 , . . . , y ^ c + m \hat{y}_{c-m},...,\hat{y}_{c-1},\hat{y}_{c+1},...,\hat{y}_{c+m} y^cm,...,y^c1,y^c+1,...,y^c+m是每一个上下文单词对应的概率
  5. 要使得上面生成的上下文单词的概率接近真实的上下文单词的独热码

同样的,定义目标函数: m i n J = − l o g P ( w c − m , . . . , w c − 1 , w c + 1 , . . . , w c + m ∣ w c ) = − l o g ∏ j = 0. j ≠ m 2 m P ( w c − m + j ∣ w c ) = − l o g ∏ j = 0 , j ≠ m 2 m P ( u c − m + j ∣ v c ) = − l o g ∏ j = 0 , j ≠ m 2 m e x p ( u c − m + j T v c ) ∑ k = 1 ∣ V ∣ e x p ( u k T v c ) = − ∑ j = 0 , j ≠ m 2 m u c − m + j T v c + 2 m l o g ∑ k = 1 ∣ V ∣ e x p ( u k T v c ) minJ=-logP(w_{c-m},...,w_{c-1},w_{c+1},...,w_{c+m}|w_c)\\=-log\prod_{j=0.j\neq m}^{2m}P(w_{c-m+j}|w_c)\\=-log\prod_{j=0,j\neq m}^{2m}P(u_{c-m+j}|v_c)\\=-log\prod_{j=0,j\neq m}^{2m}\frac{exp(u_{c-m+j}^Tv_c)}{\sum_{k=1}^{|V|}exp(u_k^Tv_c)}\\=-\sum_{j=0,j\neq m}^{2m}u_{c-m+j}^Tv_c+2mlog\sum_{k=1}^{|V|}exp(u_k^Tv_c) minJ=logP(wcm,...,wc1,wc+1,...,wc+mwc)=logj=0.j̸=m2mP(wcm+jwc)=logj=0,j̸=m2mP(ucm+jvc)=logj=0,j̸=m2mk=1Vexp(ukTvc)exp(ucm+jTvc)=j=0,j̸=m2mucm+jTvc+2mlogk=1Vexp(ukTvc)同样的,对于这个目标函数,也可以使用SGD来进行优化和参数更新。

skip-gram示例:
【笔记3-2】CS224N课程笔记+作业参考代码 - 词向量表示 word2vec_第1张图片
本例中, w t w_t wt = “into”, 是前面提到过的中心词 c.
中心词会随着遍历位置的改变而不断改变 (中心词: “into” --> “banking” --> “crises”…)

注意: 最小化目标函数 ⇔ \Leftrightarrow 最大化预测准确率

梯度的推导过程

【笔记3-2】CS224N课程笔记+作业参考代码 - 词向量表示 word2vec_第2张图片

为什么要用到两个向量?
优化的过程当中会更简单,最后会对两个向量取平均,作为最后的向量表示。

skip-gram和CBOW的改进

提高训练效率的方法: 负采样

在前文中,对单词预测时计算的概率是一个softmax函数(max: 表示放大最大值的概率; soft: 表示对较小的值依旧分配一定的概率)在计算的过程中,分母包含对所有点乘的加和,每一次迭代都需要对分母进行一次计算,这样会导致巨大的计算量,因此需要找到更加高效的训练方法——负采样,negative sampling

使用负采样的方法对loss进行近似,此时参数的求解就变成了对下述问题的求解: θ = a r g m a x θ ∏ ( w , c ) ∈ D P ( D = 1 ∣ w , c , θ ) ∏ ( w , c ) ∈ D ~ P ( D = 0 ∣ w , c , θ ) = a r g m a x θ ∏ ( w , c ) ∈ D P ( D = 1 ∣ w , c , θ ) ∏ ( w , c ) ∈ D ~ ( 1 − P ( D = 1 ∣ w , c , θ ) ) = a r g m a x θ ∑ ( w , c ) ∈ D l o g P ( D = 1 ∣ w , c , θ ) + ∑ ( w , c ) ∈ D ~ l o g ( 1 − P ( D = 1 ∣ w , c , θ ) ) = a r g m a x θ ∑ ( w , c ) ∈ D l o g 1 1 + e x p ( − u w T v c ) + ∑ ( w , c ) ∈ D ~ l o g ( 1 − 1 1 + e x p ( − u w T v c ) ) = a r g m a x θ ∑ ( w , c ) ∈ D l o g 1 1 + e x p ( − u w T v c ) + ∑ ( w , c ) ∈ D ~ l o g ( 1 1 + e x p ( u w T v c ) ) \theta = argmax_{\theta}\prod_{(w,c)\in D}P(D=1|w,c,\theta)\prod_{(w,c)\in \tilde{D}}P(D=0|w,c,\theta)\\=argmax_{\theta}\prod_{(w,c)\in D}P(D=1|w,c,\theta)\prod_{(w,c)\in \tilde{D}}(1-P(D=1|w,c,\theta))\\=argmax_{\theta}\sum_{(w,c)\in D}logP(D=1|w,c,\theta)+\sum_{(w,c)\in \tilde{D}}log(1-P(D=1|w,c,\theta))\\=argmax_{\theta}\sum_{(w,c)\in D}log\frac{1}{1+exp(-u_w^Tv_c)}+\sum_{(w,c)\in \tilde{D}}log(1-\frac{1}{1+exp(-u_w^Tv_c)})\\=argmax_{\theta}\sum_{(w,c)\in D}log\frac{1}{1+exp(-u_w^Tv_c)}+\sum_{(w,c)\in \tilde{D}}log(\frac{1}{1+exp(u_w^Tv_c)}) θ=argmaxθ(w,c)DP(D=1w,c,θ)(w,c)D~P(D=0w,c,θ)=argmaxθ(w,c)DP(D=1w,c,θ)(w,c)D~(1P(D=1w,c,θ))=argmaxθ(w,c)DlogP(D=1w,c,θ)+(w,c)D~log(1P(D=1w,c,θ))=argmaxθ(w,c)Dlog1+exp(uwTvc)1+(w,c)D~log(11+exp(uwTvc)1)=argmaxθ(w,c)Dlog1+exp(uwTvc)1+(w,c)D~log(1+exp(uwTvc)1)进而损失函数为: J = − ∑ ( w , c ) ∈ D l o g 1 1 + e x p ( − u w T v c ) + ∑ ( w , c ) ∈ D ~ l o g ( 1 1 + e x p ( u w T v c ) ) J=-\sum_{(w,c)\in D}log\frac{1}{1+exp(-u_w^Tv_c)}+\sum_{(w,c)\in \tilde{D}}log(\frac{1}{1+exp(u_w^Tv_c)}) J=(w,c)Dlog1+exp(uwTvc)1+(w,c)D~log(1+exp(uwTvc)1)

softmax的改进:分层softmax
另外还有一个对softmax进行改进的方法,即分层softmax(hierarchical softmax)

一般而言,分层softmax适用于对非常用词,非频繁词的改进,而负采样则更适用于频繁词即低纬向量。

分层softmax的思想是根据词频构造一棵二叉树,词汇越频繁,该词汇对应的叶节点距离根节点就越近。每次需要根据一个给定的词去预测另外一个词时,只需要对二叉树上位于被预测的词路径上的节点向量进行更新。因此,对于频繁词汇的更新比较快速,且整个模型的算法复杂度低

给定词汇 w i w_i wi预测词汇 w w w的概率为 P ( w ∣ w i ) = ∏ j = 1 L ( w ) − 1 σ ( [ n ( w , j + 1 ) = c h ( n ( w , j ) ) ] v n ( w , j ) T v w i ) P (w|w_i)=\prod_{j=1}^{L(w)-1}\sigma([n(w,j+1)=ch(n(w,j))]v_{n(w,j)}^Tv_{w_i}) P(wwi)=j=1L(w)1σ([n(w,j+1)=ch(n(w,j))]vn(w,j)Tvwi)其中, σ \sigma σ表示sigmoid函数, L ( w ) L(w) L(w)代表从根节点到词汇w的叶节点路径上所需要经过的节点总数。 n ( w , j ) n(w,j) n(w,j)表示从根节点到词汇w叶节点路径上的第j个节点,其中 n ( w , 1 ) n(w,1) n(w,1)表示根节点。 c h ( ) ch() ch()表示某一个节点的子节点,可能是左子节点也可能是右子节点。函数 [ x ] [x] [x]的含义是,当x为真时,该函数值取1,否则取0, v n ( w , j ) v_{n(w,j)} vn(w,j)是节点 n ( w , j ) n(w,j) n(w,j)的向量表示,即需要学习的向量。

模型训练的目标函数则为 − l o g P ( w ∣ w i ) -logP(w|w_i) logP(wwi),训练过程中只需要对二叉树中位于路径上的节点的向量进行更新。

Assignment 1 参考代码

Question 1.1: Implement distinct_words

def distinct_words(corpus):
    """ Determine a list of distinct words for the corpus.
        Params:
            corpus (list of list of strings): corpus of documents
        Return:
            corpus_words (list of strings): list of distinct words across the corpus, sorted (using python 'sorted' function)
            num_corpus_words (integer): number of distinct words across the corpus
    """
    corpus_words = []
    num_corpus_words = -1
    
    # ------------------
    # Write your implementation here.
    flattened_corpus = [y for x in corpus for y in x]
    num_corpus_words += 1
    for word in flattened_corpus:
        if word not in corpus_words:
            corpus_words.append(word)
            num_corpus_words += 1
    corpus_words.sort()
    # ------------------

    return corpus_words, num_corpus_words

Question 1.2: Implement compute_co_occurrence_matrix

def compute_co_occurrence_matrix(corpus, window_size=4):
    """ Compute co-occurrence matrix for the given corpus and window_size (default of 4).
    
        Note: Each word in a document should be at the center of a window. Words near edges will have a smaller
              number of co-occurring words.
              
              For example, if we take the document "START All that glitters is not gold END" with window size of 4,
              "All" will co-occur with "START", "that", "glitters", "is", and "not".
    
        Params:
            corpus (list of list of strings): corpus of documents
            window_size (int): size of context window
        Return:
            M (numpy matrix of shape (number of corpus words, number of corpus words)): 
                Co-occurence matrix of word counts. 
                The ordering of the words in the rows/columns should be the same as the ordering of the words given by the distinct_words function.
            word2Ind (dict): dictionary that maps word to index (i.e. row/column number) for matrix M.
    """
    words, num_words = distinct_words(corpus)
    M = None
    word2Ind = {}
    # ------------------
    # Write your implementation here.
    flattened_corpus = [y for x in corpus for y in x]
    for index, word in enumerate(words):
        word2Ind[word] = index
    M = np.zeros((len(words),len(words)))
    for index, word in enumerate(flattened_corpus):
        left = max(0,index-window_size)
        right = min(len(flattened_corpus),index+window_size)
        for i in range(left,right):
            if i != index:
                co_word = flattened_corpus[i]
                if word in ["START","END"] and co_word in ["STRAT","END"]:
                    pass
                else:
                    M[word2Ind[word]][word2Ind[co_word]] += 1.
                    M[word2Ind[co_word]][word2Ind[word]] += 1.
    # ------------------
    return M, word2Ind

Question 1.3: Implement reduce_to_k_dim

def reduce_to_k_dim(M, k=2):
    """ Reduce a co-occurence count matrix of dimensionality (num_corpus_words, num_corpus_words)
        to a matrix of dimensionality (num_corpus_words, k) using the following SVD function from Scikit-Learn:
            - http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.TruncatedSVD.html
    
        Params:
            M (numpy matrix of shape (number of corpus words, number of corpus words)): co-occurence matrix of word counts
            k (int): embedding size of each word after dimension reduction
        Return:
            M_reduced (numpy matrix of shape (number of corpus words, k)): matrix of k-dimensioal word embeddings.
                    In terms of the SVD from math class, this actually returns U * S
    """    
    n_iters = 10     # Use this parameter in your call to `TruncatedSVD`
    M_reduced = None
    print("Running Truncated SVD over %i words..." % (M.shape[0]))
    
        # ------------------
        # Write your implementation here.
    svd = TruncatedSVD(n_components=k, n_iter=n_iters)
    M_reduced = svd.fit_transform(M)
        # ------------------

    print("Done.")
    return M_reduced

Question 1.4: Implement plot_embeddings

def plot_embeddings(M_reduced, word2Ind, words):
    """ Plot in a scatterplot the embeddings of the words specified in the list "words".
        NOTE: do not plot all the words listed in M_reduced / word2Ind.
        Include a label next to each point.
        
        Params:
            M_reduced (numpy matrix of shape (number of unique words in the corpus , k)): matrix of k-dimensioal word embeddings
            word2Ind (dict): dictionary that maps word to indices for matrix M
            words (list of strings): words whose embeddings we want to visualize
    """
    # ------------------
    # Write your implementation here.
    for i,type in enumerate(words):
        x = M_reduced[i][0]
        y = M_reduced[i][1]
        plt.scatter(x, y, marker='x', color='red')
        plt.text(x, y, type, fontsize=9)
    plt.show()
    # ------------------

你可能感兴趣的:(笔记,CS224N)