詞向量word2vec(詞嵌入Word Embedding)極簡(jiǎn)原理介紹及TF實(shí)踐

詞向量也稱(chēng)為詞嵌入,是指將詞轉(zhuǎn)換成為向量的形式。

為何需要詞向量

對(duì)于非結(jié)構(gòu)化的數(shù)據(jù):音頻,圖片,文字。前面兩種的數(shù)據(jù)存儲(chǔ)方式是天然高維和高密度的,而且數(shù)據(jù)天然的就非常具有實(shí)際意義(相近的數(shù)據(jù)表示顏色或者音頻接近),幾乎可以直接進(jìn)入模型進(jìn)行處理。但是對(duì)于文字來(lái)說(shuō)不同的詞如果采用類(lèi)似LabelEncoder來(lái)做的,不同的詞ID取值接近并不能有實(shí)際的意義表示。而如果采用類(lèi)似OneHot編碼則會(huì)導(dǎo)致向量維度過(guò)高(詞匯量少說(shuō)也要幾萬(wàn)),也過(guò)于稀疏,同時(shí)也依然難以在數(shù)值上表示出不同詞之間的關(guān)系。
所以我們希望能找到一種詞與向量的映射關(guān)系,使得向量維度不需要過(guò)大,而且詞向量在向量空間中所表示的點(diǎn)具有實(shí)際的意義,也就是相似含義的詞在空間中的距離更近。
Word2Vec就是一個(gè)可以達(dá)到上述要求的一種方法,它可以從原始文本(語(yǔ)料庫(kù))中讀取詞語(yǔ)然后生成詞向量。word2vec從實(shí)現(xiàn)方法來(lái)看分為兩個(gè)大的框架:一、Hierarchical Softmax模型框架;二、Negative Sampling模型框架。

Hierarchical Softmax模型框架

模型大致由輸入層、投影層和輸出層構(gòu)成。
其中Hierarchical Softmax模型的輸出層由語(yǔ)料庫(kù)中詞出現(xiàn)的頻數(shù)當(dāng)作權(quán)值構(gòu)造出的哈夫曼樹(shù)作為輸出。具體實(shí)現(xiàn)由CBOW模型(Continuous Bag-of-Words Model)或者Skip-gram模型來(lái)完成。
假設(shè)詞w的上下文窗口長(zhǎng)度skip_window為c,那么對(duì)于模型的每一次迭代計(jì)算有【w之前c個(gè)詞,w,w之后c個(gè)詞】

- CBOW模型實(shí)現(xiàn)

CBOW考慮的主要思想是要P( w | Context(w) )的概率最大化,所以接下來(lái)看CBOW模型主要就是看如何定義和計(jì)算這個(gè)概率。(當(dāng)然對(duì)于語(yǔ)言模型來(lái)說(shuō),實(shí)際的目標(biāo)函數(shù)通常是對(duì)語(yǔ)料庫(kù)中的每個(gè)詞的概率P( w | Context(w) )取對(duì)數(shù)累加

輸入層: 2c個(gè)詞向量
投影層:2c個(gè)詞向量的累加
輸出層:哈夫曼樹(shù)(重點(diǎn)是詞w所在的葉子節(jié)點(diǎn),以及w到根節(jié)點(diǎn)的路徑)


CBOW模型的大致處理流

接下來(lái)就是重點(diǎn)了,也就是怎么計(jì)算P( w | Context(w) )

  • 2c個(gè)上下文詞向量的累加,與根節(jié)點(diǎn)的參數(shù)(系數(shù)theta_0和常數(shù)項(xiàng)bias_0)計(jì)算概率P(0)
    • 計(jì)算使用了Sigmoid函數(shù),假設(shè)計(jì)算結(jié)果為S(0)
    • 根據(jù)上面計(jì)算得到的S0以及詞w所在路徑對(duì)應(yīng)的分支,決定P(0)=S(0)或者P0=1-S(0)
  • 繼續(xù)使用2c個(gè)上下文詞向量的累加向量與路徑中下一個(gè)節(jié)點(diǎn)的參數(shù)計(jì)算概率P(1)
  • 一直計(jì)算到w所在的葉子節(jié)點(diǎn)直接相連的上面那個(gè)節(jié)點(diǎn)P(h)
  • P( w | Context(w) ) = P(0) * P(1) * ... * P(h)
    計(jì)算過(guò)程圖示(簡(jiǎn)書(shū)不好寫(xiě)公式,所以省略了很多公式記號(hào))

然后對(duì)P取對(duì)數(shù),求梯度,可以得到兩個(gè)部分的更新:

  • 詞w的路徑中各個(gè)非葉節(jié)點(diǎn)的參數(shù)(系數(shù)theta_i和常數(shù)項(xiàng)bias_i)的更新


    非葉節(jié)點(diǎn)的系數(shù)更新
  • 詞w的上下文詞向量的更新(所有w的上下文窗內(nèi)詞統(tǒng)一更新)


    所有w的上下文詞向量統(tǒng)一更新

最后當(dāng)把語(yǔ)料庫(kù)遍歷一遍或者幾遍后就得到了全部詞的詞向量。

- Skip-gram模型實(shí)現(xiàn)

Skip-gram考慮的主要思想是要P( Context(w) | w )的概率最大化,所以接下來(lái)看Skip-gram模型主要就是看如何定義和計(jì)算這個(gè)概率。(當(dāng)然對(duì)于語(yǔ)言模型來(lái)說(shuō),實(shí)際的目標(biāo)函數(shù)通常是對(duì)語(yǔ)料庫(kù)中的每個(gè)詞的概率P( Context(w) | w )對(duì)數(shù)累加

輸入層:詞w的向量
投影層:依舊是詞w的向量
輸出層:哈夫曼樹(shù)(重點(diǎn)是詞w的上下文窗內(nèi)2c個(gè)詞所在的葉子節(jié)點(diǎn),以及各自到根節(jié)點(diǎn)的路徑

Skip-gram的大致處理流

接下來(lái)的重點(diǎn)就是怎么定義和計(jì)算P( Context(w) | w )

  • 對(duì)于詞w的上下文窗內(nèi)的一個(gè)詞u(1):
    • 計(jì)算P( u(1) | w ),其計(jì)算過(guò)程和前面的類(lèi)似,都是先計(jì)算詞向量w與u(1)到根路徑中非葉節(jié)點(diǎn)的系數(shù)Sigmoid函數(shù)值,然后根據(jù)每個(gè)具體的分支得到P(i),然后將P(i)累乘得到。
  • 遍歷詞w的上下文窗內(nèi)的每個(gè)詞u(i),都計(jì)算得到P( u(i) | w )
  • P( Context(w) | w ) = P(u(1) | w) * P(u(2) | w) * ... * P(u(2c) | w)
    計(jì)算過(guò)程簡(jiǎn)易圖示

有了P( Context(w) | w )的計(jì)算,就可以通過(guò)取對(duì)數(shù)然后求梯度來(lái)對(duì)兩個(gè)部分的參數(shù)更新:

  • 每個(gè)上下文詞u(i)對(duì)應(yīng)的到根路徑的節(jié)點(diǎn)的參數(shù)的更新:


    每個(gè)上下文詞u所在路徑的非葉節(jié)點(diǎn)參數(shù)更新
  • 詞w的向量的更新:


    中心詞w的詞向量更新

同樣,把語(yǔ)料庫(kù)遍歷幾遍后就可以得到全部詞的詞向量。

- 總結(jié)
  • CBOW模型的一次更新是:輸入2c個(gè)詞向量的累加,然后對(duì)中心詞w上的路徑節(jié)點(diǎn)系數(shù)進(jìn)行更新,然后對(duì)所有的上下文詞的詞向量進(jìn)行整體一致更新。
  • Skip-gram模型的一次更新是:輸入中心詞w的詞向量,然后對(duì)每個(gè)上下文詞u(i)所在的路徑上的節(jié)點(diǎn)系數(shù)進(jìn)行更新,然后對(duì)詞w的詞向量進(jìn)行單獨(dú)更新。

可見(jiàn)CBOW的一次更新計(jì)算量要小,Skip-gram模型計(jì)算量大,而且更新的系數(shù)也多。

Negative Sampling模型框架

Negative Sampling模型的輸出層顧名思義,由對(duì)指定詞的負(fù)采樣來(lái)作為輸出(與Hierarchical Softmax最大的不同就是用負(fù)采樣替代了哈夫曼樹(shù),這樣也就改變了條件概率的計(jì)算過(guò)程)。具體實(shí)現(xiàn)也是由兩個(gè)算法模型CBOW和Skip-gram來(lái)實(shí)現(xiàn)。
為了解決新加入的概念帶來(lái)的困擾,我們先看下負(fù)采樣

- 負(fù)采樣

負(fù)采樣的算法思路其實(shí)還是比較簡(jiǎn)單,就是利用不同詞在語(yǔ)料中出現(xiàn)的頻次多少來(lái)決定被采樣到的概率。
簡(jiǎn)單說(shuō)就是每個(gè)詞由一個(gè)線段構(gòu)成(線段的長(zhǎng)度由詞頻決定),所有的詞構(gòu)成一個(gè)大的線段,然后在這個(gè)總線段上用非常細(xì)的刻度來(lái)進(jìn)行劃分,采樣的時(shí)候就是在這個(gè)細(xì)刻度的劃分中隨機(jī)選取一個(gè),看其屬于哪個(gè)詞的線段內(nèi)就表示本次采用選到了哪個(gè)詞。
多說(shuō)一句,方便接下來(lái)的算法理解,其實(shí)負(fù)采樣的作用就是采用出一些“負(fù)”詞(與采樣詞不同即為負(fù)),使得原來(lái)在哈夫曼樹(shù)中需要用到的非葉節(jié)點(diǎn)參數(shù)以及分支選擇的地方都替換成負(fù)采樣出來(lái)的詞。

- CBOW模型實(shí)現(xiàn)

輸入層: 2c個(gè)詞向量
投影層:2c個(gè)詞向量的累加
輸出層:負(fù)采樣詞集(重點(diǎn)是詞w的負(fù)詞詞集的參數(shù)(θ),負(fù)詞的概率永遠(yuǎn)是1-Sigmoid函數(shù)值)

接下來(lái)我們考慮的重點(diǎn)不是P( w | Context(w) )而是替換成g( w ):

g(w)為目標(biāo),要使其越大越好

其中:



把上面的公式用通俗的語(yǔ)言表達(dá)就是:

  • 輸入詞w的上下文詞向量的累加:X_w
  • 對(duì)詞w進(jìn)行負(fù)采樣(得到一組非w的負(fù)詞)
  • X_w與詞w的輔助向量(可訓(xùn)練的參數(shù)θ)的Sigmoid函數(shù)值越大越好
  • X_w與詞w的負(fù)詞的輔助向量(可訓(xùn)練的參數(shù)θ)的Sigmoid函數(shù)值越小越好
    也就是說(shuō)每個(gè)詞除了有自己的詞向量之外,還有一個(gè)輔助向量θ

有了g( w )的定義后,就可以計(jì)算梯度,然后更新兩個(gè)部分的參數(shù):

  • 每個(gè)詞包括w及其采樣得到的負(fù)詞詞集的參數(shù)θ更新:


  • 詞w的上下文詞向量的更新(所有上下文詞一致更新):


最后把語(yǔ)料庫(kù)遍歷幾遍后,就可以得到全部的詞向量。

- Skip-gram模型實(shí)現(xiàn)

輸入層:詞w的向量
投影層:依舊是詞w的向量
輸出層:每個(gè)上下文詞u的負(fù)采樣(重點(diǎn)是詞u的負(fù)詞詞集的參數(shù)(θ),負(fù)詞的概率永遠(yuǎn)是1-Sigmoid函數(shù)值)

接下來(lái)的重點(diǎn)不是P( Context(w) | w ),而是G




這里v(w)為詞w的詞向量。
通俗講解:

  • 輸入詞w的詞向量
  • 對(duì)于詞w的上下文詞u(i)進(jìn)行負(fù)采樣得到詞集z(i),計(jì)算g( u(i) )
    • 計(jì)算P( z(i)_j | w ),z(i)_j = u(i)時(shí)使用v(w)和z的θ的Sigmoid函數(shù)值,否則1 - Sigmoid函數(shù)值
    • g( u(i) ) = 對(duì)上面j的遍歷后的累積
  • 對(duì)上下文詞u(i)進(jìn)行遍歷,得到每個(gè)g( u(i) ),最后累積就是G

有了G之后就可以計(jì)算梯度進(jìn)行參數(shù)更新:

  • 每個(gè)負(fù)采樣出來(lái)的詞系數(shù)θ的更新
  • 詞w的詞向量更新

同樣把語(yǔ)料庫(kù)遍歷幾遍后可以得到所有的詞向量。

算法整體總結(jié)

  • Hierarchical Softmax主要是通過(guò)哈夫曼樹(shù)來(lái)計(jì)算,其中用到了非葉節(jié)點(diǎn)的系數(shù)θ。
  • Negative Sampling主要是對(duì)詞進(jìn)行負(fù)采樣,其中每個(gè)詞除了有自己的詞向量外還有輔助向量系數(shù)θ。
  • CBOW的思想是在Context(w)基礎(chǔ)上讓w的條件概率越大越好,輸入是w的上下文詞向量累加,更新也是上下文的詞向量一致更新。同時(shí)對(duì)于輔助向量θ的更新個(gè)數(shù)較少
  • Skip-gram的思想是在w的條件上讓Context(w)的條件概率越大越好,輸入是w的詞向量,更新的也是w的詞向量。同時(shí)對(duì)輔助向量θ的更新個(gè)數(shù)較多

所以CBOW看起來(lái)更新的更平滑,適合小量文本集上的詞向量構(gòu)建,Skip-gram每次更新都更加有針對(duì)性,所以對(duì)于大文本集上表現(xiàn)更好。
接下來(lái)的TF實(shí)踐,主要使用的就是Negative Sampling框架下的Skip-gram算法。

TensorFlow實(shí)踐

在TensorFlow的教學(xué)文檔中有一個(gè)關(guān)于詞向量的基礎(chǔ)代碼實(shí)踐:word2vec_basic.py。接下來(lái)提到的代碼也是圍繞這個(gè)進(jìn)行。

    1. 讀取語(yǔ)料構(gòu)成輸入數(shù)據(jù)集。
    • 讀語(yǔ)料文檔

    讀取的細(xì)節(jié)代碼就不細(xì)究了,這里想說(shuō)下,因?yàn)檎Z(yǔ)料第一次是需要下載的,如果直接用代碼下載的話會(huì)比較慢,建議先用迅雷把文檔下載下來(lái)text8.zip. 然后放入

    from tempfile import gettempdir 
    gettempdir()
    

    顯示的臨時(shí)文件夾中(程序中默認(rèn)在這個(gè)文件夾中尋找語(yǔ)料文件,也可以手動(dòng)修改成別的文件夾),再運(yùn)行代碼。

    • 構(gòu)建輸入數(shù)據(jù)
      def build_dataset(words, n_words):
          """Process raw inputs into a dataset."""
          count = [['UNK', -1]]  # 統(tǒng)計(jì)單詞和詞頻的二維列表:[[單詞,詞頻], ... ,[單詞,詞頻]]
          count.extend(collections.Counter(words).most_common(n_words - 1))
          dictionary = dict()  # 單詞和對(duì)應(yīng)的索引,不常出現(xiàn)的詞(排名在49999之后的),統(tǒng)統(tǒng)索引為0,用'NUK'表示
          for word, _ in count:
              dictionary[word] = len(dictionary)
          data = list()  # 語(yǔ)料中的單詞轉(zhuǎn)成索引的列表
          unk_count = 0
          for word in words:
              index = dictionary.get(word, 0)
              if index == 0:  # dictionary['UNK']
                  unk_count += 1
              data.append(index)
          count[0][1] = unk_count
          reversed_dictionary = dict(zip(dictionary.values(), dictionary.keys()))  # 索引->單詞
          return data, count, dictionary, reversed_dictionary
    

    輸入:words是語(yǔ)料庫(kù)中的詞組list,以及n_words最大詞數(shù)目的限制。
    輸出:data是語(yǔ)料文本中詞的Index的list,count是[[詞,詞頻], ... ,]組成的二維list,dictionary是詞->索引,reversed_dictionary是索引->詞。

    1. 為Skip-gram模型產(chǎn)生batch輸入
def generate_batch(batch_size, num_skips, skip_window):
    global data_index
    assert batch_size % num_skips == 0
    assert num_skips <= 2 * skip_window
    batch = np.ndarray(shape=(batch_size), dtype=np.int32)
    labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32)
    span = 2 * skip_window + 1  # [ skip_window target skip_window ] 前后skip窗長(zhǎng)加上中心詞自己后的個(gè)數(shù)
    buffer = collections.deque(maxlen=span)  # 雙端隊(duì)列,并設(shè)置最大長(zhǎng)度
    if data_index + span > len(data):
        data_index = 0
    buffer.extend(data[data_index:data_index + span])  # 接續(xù)上次讀入的位置,讀入span長(zhǎng)度的文本內(nèi)容
    data_index += span
    for i in range(batch_size // num_skips):  # 分塊總共采樣batch_size個(gè),其中每塊隨機(jī)選取上下文的詞num_skips次,每一塊的中心詞固定
        context_words = [w for w in range(span) if w != skip_window]  # 得到不包含中心詞的位置索引[0,1,3,4],假如skip窗長(zhǎng)為2
        words_to_use = random.sample(context_words, num_skips)  # 得到隨機(jī)選取的作為上下文的詞的位置
        for j, context_word in enumerate(words_to_use):
            batch[i * num_skips + j] = buffer[skip_window]  # 中心詞
            labels[i * num_skips + j, 0] = buffer[context_word]  # 上下文詞
        if data_index == len(data):
            buffer[:] = data[:span]
            data_index = span
        else:
            buffer.append(data[data_index])  # 繼續(xù)向后讀入一個(gè)詞,相當(dāng)于讀取下一塊,中心詞也向后偏移一個(gè)
            data_index += 1
    # Backtrack a little bit to avoid skipping words in the end of a batch
    data_index = (data_index + len(data) - span) % len(data)
    return batch, labels

輸入:batch_size為一個(gè)batch的大小,num_skips為每個(gè)中心詞選取上下文詞的次數(shù)(要保證batch_size能整除num_skips,因?yàn)閎atch_size // num_skips是一個(gè)batch中會(huì)偏移向后取詞的個(gè)數(shù)),skip_window是中心詞的上下文詞的范圍(比如skip_window=2是指中心詞的前面2個(gè)詞和后面2個(gè)詞共4個(gè)詞作為這個(gè)中心詞的上下文詞集)
輸出:batch是shape=(batch_size,)的中心詞Index的np數(shù)組,labels是shape=(batch_size,1)的上下文詞Index的np數(shù)組

    1. 構(gòu)造Skip-gram模型
      使用TF構(gòu)造任何模型核心都是定義計(jì)算loss的公式以及具體計(jì)算中使用的優(yōu)化方法。
with graph.as_default():
    # Input data.
    train_inputs = tf.placeholder(tf.int32, shape=[batch_size])
    train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1])
    valid_dataset = tf.constant(valid_examples, dtype=tf.int32)

    # Ops and variables pinned to the CPU because of missing GPU implementation
    with tf.device('/cpu:0'):
        # Look up embeddings for inputs.
        embeddings = tf.Variable(
            tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
        embed = tf.nn.embedding_lookup(embeddings, train_inputs)

        # Construct the variables for the NCE loss
        nce_weights = tf.Variable(
            tf.truncated_normal([vocabulary_size, embedding_size],
                                stddev=1.0 / math.sqrt(embedding_size)))
        nce_biases = tf.Variable(tf.zeros([vocabulary_size]))

    # Compute the average NCE loss for the batch.
    # tf.nce_loss automatically draws a new sample of the negative labels each
    # time we evaluate the loss.
    # Explanation of the meaning of NCE loss:
    #   http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/
    loss = tf.reduce_mean(
        tf.nn.nce_loss(weights=nce_weights,
                       biases=nce_biases,
                       labels=train_labels,
                       inputs=embed,
                       num_sampled=num_sampled,
                       num_classes=vocabulary_size))

    # Construct the SGD optimizer using a learning rate of 1.0.
    optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss)

    # Compute the cosine similarity between minibatch examples and all embeddings.
    norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))
    normalized_embeddings = embeddings / norm
    valid_embeddings = tf.nn.embedding_lookup(
        normalized_embeddings, valid_dataset)
    similarity = tf.matmul(
        valid_embeddings, normalized_embeddings, transpose_b=True)

    # Add variable initializer.
    init = tf.global_variables_initializer()
  • tf.nn.embedding_lookup
    這個(gè)函數(shù)功能是根據(jù)輸入的Index查找對(duì)應(yīng)的向量,然后返回Tensor出來(lái)。喂給下面的計(jì)算NCE損失作為Input用。

    • tf.nn.nce_loss
      這個(gè)函數(shù)是重中之重,因?yàn)樗苯幼鳛閘oss的計(jì)算(再套一個(gè)tf.reduce_mean而已)。理解這個(gè)函數(shù)需要用到上面我們講到Negative Sampling框架下的Skip-gram模型算法。
      這里我們?cè)倩仡櫹耂kip-gram模型都用到了哪些變量來(lái)計(jì)算:

      • 中心詞w的詞向量
      • 上下文詞u的輔助系數(shù)θ(以及bias)
      • 對(duì)每個(gè)上下文詞u進(jìn)行負(fù)采樣得到的其他詞u_neg的輔助系數(shù)θ

      然后我們?cè)倏聪潞瘮?shù)tf.nn.nce_loss都有哪些輸入:

      • weights:shape=[vocabulary_size, embedding_size]的Tensor,是全部詞典的輔助系數(shù)θ
      • biases:shape=[vocabulary_size]的Tensor,是全部詞典的偏置項(xiàng)bias
      • labels:中心詞w對(duì)應(yīng)的上下文詞u的Index
      • inputs:中心詞w的詞向量
      • num_sampled:每次對(duì)于一個(gè)上下文詞要采樣多少個(gè)負(fù)詞
      • num_classes:詞典的大小(詞的類(lèi)別個(gè)數(shù))

      通過(guò)對(duì)比可以發(fā)現(xiàn)tf.nn.nce_loss的輸入正好涵蓋了前面講到Skip-gram模型時(shí)用到的計(jì)算變量。然后具體內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)可以通過(guò)源碼或者查考其他資料。(與上面寫(xiě)的計(jì)算過(guò)程略有不同,除了計(jì)算Sigmoid的概率值之外,還計(jì)算了交叉熵?fù)p失,以及最后按行求和)

    • 計(jì)算余弦相似度
      最后還對(duì)詞向量做了正則化(方便后面計(jì)算余弦相似度,直接使用矩陣乘積即可,因?yàn)槌龜?shù)已經(jīng)被歸一化了),然后對(duì)隨機(jī)選取的詞與全字典進(jìn)行余弦相似度計(jì)算。

    • 另外需要注意的是不能用GPU來(lái)搭建模型,因?yàn)閠f.nn.sampled_softmax_loss使用了GPU不支持的op

    1. 開(kāi)始訓(xùn)練
with tf.Session(graph=graph) as session:
    # We must initialize all variables before we use them.
    init.run()
    print('Initialized')

    average_loss = 0
    for step in xrange(num_steps):
        batch_inputs, batch_labels = generate_batch(batch_size, num_skips, skip_window)
        feed_dict = {train_inputs: batch_inputs, train_labels: batch_labels}

        # We perform one update step by evaluating the optimizer op (including it
        # in the list of returned values for session.run()
        _, loss_val = session.run([optimizer, loss], feed_dict=feed_dict)
        average_loss += loss_val

        if step % 2000 == 0:
            if step > 0:
                average_loss /= 2000
            # The average loss is an estimate of the loss over the last 2000 batches.
            print('Average loss at step ', step, ': ', average_loss)
            average_loss = 0

        # Note that this is expensive (~20% slowdown if computed every 500 steps)
        if step % 10000 == 0:
            sim = similarity.eval()
            for i in xrange(valid_size):
                valid_word = reverse_dictionary[valid_examples[i]]
                top_k = 8  # number of nearest neighbors
                nearest = (-sim[i, :]).argsort()[1:top_k + 1]
                log_str = 'Nearest to %s:' % valid_word
                for k in xrange(top_k):
                    close_word = reverse_dictionary[nearest[k]]
                    log_str = '%s %s,' % (log_str, close_word)
                print(log_str)
    final_embeddings = normalized_embeddings.eval()

訓(xùn)練過(guò)程比較簡(jiǎn)單,就是從generate_batch中讀取數(shù)據(jù),然后設(shè)置好feed_dict后run得到loss,除了每隔2000打印一次平均loss外,還會(huì)每隔10000打印一次隨機(jī)選取的驗(yàn)證詞中余弦相似度最接近的詞語(yǔ)。
最后通過(guò)normalized_embeddings.eval()得到正則化后的詞向量final_embeddings

    1. 畫(huà)圖展示詞向量
def plot_with_labels(low_dim_embs, labels, filename):
    assert low_dim_embs.shape[0] >= len(labels), 'More labels than embeddings'
    plt.figure(figsize=(18, 18))  # in inches
    for i, label in enumerate(labels):
        x, y = low_dim_embs[i, :]
        plt.scatter(x, y)
        plt.annotate(label,
                     xy=(x, y),
                     xytext=(5, 2),
                     textcoords='offset points',
                     ha='right',
                     va='bottom')

    plt.savefig(filename)


try:
    # pylint: disable=g-import-not-at-top
    from sklearn.manifold import TSNE
    import matplotlib.pyplot as plt

    tsne = TSNE(perplexity=30, n_components=2, init='pca', n_iter=5000, method='exact')
    plot_only = 500
    low_dim_embs = tsne.fit_transform(final_embeddings[:plot_only, :])
    labels = [reverse_dictionary[i] for i in xrange(plot_only)]
    plot_with_labels(low_dim_embs, labels, os.path.join(gettempdir(), 'tsne.png'))

except ImportError as ex:
    print('Please install sklearn, matplotlib, and scipy to show embeddings.')
    print(ex)

通過(guò)使用t-SNE降維,來(lái)畫(huà)圖展示詞向量:


詞向量圖示
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,530評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,407評(píng)論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,981評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,759評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,204評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,415評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,955評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,650評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,892評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,675評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,967評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • 最近新接觸文本分類(lèi)問(wèn)題,對(duì)于我來(lái)數(shù)第一個(gè)問(wèn)題就是Word Embedding這個(gè)詞到底是什么意思,因此也就開(kāi)始學(xué)習(xí)...
    小松qxs閱讀 24,909評(píng)論 2 27
  • 前面的文章主要從理論的角度介紹了自然語(yǔ)言人機(jī)對(duì)話系統(tǒng)所可能涉及到的多個(gè)領(lǐng)域的經(jīng)典模型和基礎(chǔ)知識(shí)。這篇文章,甚至之后...
    我偏笑_NSNirvana閱讀 13,975評(píng)論 2 64
  • 本文關(guān)鍵詞:NLP、詞向量、word2vec、ELMo、語(yǔ)言模型該系列更新的第二篇已在個(gè)人微信公眾號(hào)「AI極客 」...
    流川楓AI閱讀 27,638評(píng)論 6 48
  • 一、詞嵌入背景 詞嵌入(Word Embedding)是一種將文本中的詞轉(zhuǎn)換成數(shù)字向量的方法,為了使用標(biāo)準(zhǔn)機(jī)器學(xué)習(xí)...
    rosyxiao閱讀 20,927評(píng)論 0 15
  • 1、堅(jiān)持瑜伽,在家選擇玉珠鉉瑜伽。 2、聽(tīng)非暴力溝通語(yǔ)音,做筆記,學(xué)習(xí)溝通能力,并分享給需要的小伙伴。 3、把家里...