手把手教你PaddlePaddle 做詞向量模型 SkipGram實戰

2021-02-13 機器學習算法與自然語言處理

在做 NLP 的任務時,一個非常 basic 的操作就是如何編碼自然語言中的符號,例如詞、短語,甚至詞綴。目前流行的方法有大約三種:

• 特徵工程:這類方法依賴於手工特徵,例如 tf-idf 同時考慮詞頻和詞的稀缺度;

 統計方法:統計上常常通過矩陣分解(如 SVD、EVD)來建模大規模文檔集合;

• 神經網絡:目前非常流行通過神經網絡端到端的建模語言模型,得到詞向量副產品;

今天要講解的就是 SkipGram 模型就屬於第三種方法,它的主要思想是利用的詞義的分布式表示。除了讓您徹底弄懂什麼是語言模型以及 SkipGram 的基本原
理。我們還會詳細的說明如何一步步的用 PaddlePaddle 實現它。

1、什麼是詞向量

首先我們需要了解什麼是詞向量。NLP 和圖像不太一樣,圖像的輸入本身就是一個有數值特徵的矩陣,而 NLP 的輸入通常只是一堆自然語言的符號,它們本身是不具備數學特性的。因此,在計算語言學中,我們通常會希望用數值向量來表示這些符號。例如現在我們希望比較詞彙「米飯」與「豬肉」和「家具」之間詞義的相似性,可以考慮用下面這樣的 two-stage 範式。

從上面這個例子可以看出,使用向量數值表示法最關鍵的地方在於如何獲取詞彙的 向量的表示,而 SkipGram 就是一個良方。

2、什麼是語言模型

詞向量一般不是直接獲取的,而是某些任務的副產品。它們通常是隨機初始化的, 然後通過不斷的數值優化過程中獲得語義信息,例如上述的相似性。因此,訓練詞 向量的辦法可以有很多,但是如何高效的獲得高質量的詞向量很重要,另外任務也 應該有一定的可拓展性,例如語料充足,不需要額外標註。

語言模型是一個非常好的選擇。因為它語料充足,只要有文章,有帖子,那就有數 據;同時由於其任務的特殊性,不需要人工進行額外的數據標註(網上有很多稱這 是無監督,但我覺得不是特別合適,不需要數據標註和無監督概念有所差異)。那 麼什麼是語言模型呢?

3、什麼是 SkipGram

經過前兩節的解釋,相信您對詞向量有了很深的認識了。這一小節中我將會介紹 SkipGram,一種有效訓練語言模型的方法。

說到 SkipGram,一定有同學會想到 CBOW。實際上 CBOW 更符合常人的思考邏 輯,它建模詞語上下文的方法很簡單,如下圖所示:

雖然看起來 CBOW 更合理,但很多文獻指出,用 SkipGram 訓出來的詞向量效果更 好。筆者分析可能存在下面一些原因:

 SkipGram 用一個中心詞去預測上下文,這樣相當於對這個中心詞的表示要求更高,這就好像 一個學生(中心詞)同時受到了多個老師(上下文)的教導(這個學習的過程可以被理解為 中間的梯度傳播),效果肯定比一個老師教導多個學生(因此梯度是均分的,沒有區分性, 而且由於梯度均分,容易破壞一個窗口中詞向量的異構性)效果要好得多;

 其次,SkipGram 這種強調中心詞的結構對某些具有較低頻率的生僻詞比較友好,因此低頻詞 也可以學到質量較高的向量表示;

但可能是因為 CBOW 的結構相對簡單些, 經驗顯示,CBOW 的訓練速度要比 SkipGram 快的多,因此兩者其實各有優勢。

拿上面提到的例子 「Can you please come here ?」 說明 SkipGram 的流程。假設滑動 窗口的長度為 5,那麼現在窗口 cover 住了片段 「can you please come here」。此時 以中心詞 please 為輸入並度量與上下文 can, you, come, here 的相似度,優化時希 望這個值儘量高。

在工程上,實現詞向量模型有很多 trick,例如概率平滑化,高頻詞抽樣等。但如 果做個 demo 不需要考慮太多這些細節。不過無論是 CBOW 還是 SkipGram 都無法 規避一個問題,就是過高的詞典容量。正常情況下,英語詞典的容量在 3000 ~ 4000 上下,因此當訓練語料很大時會造成巨大的計算負擔。為了權衡質量和效率,目前最常用的方法就是負採樣。

通俗的來說,就是我不再把整個詞典當成負 樣本了,而是隨機抽取若干詞作為負樣本。實現時,這個隨機抽取的數量是一個超 參數,大概是 20 ~ 30 之間,這樣很明顯大大提高了計算效率。另外,也有人指 出,用一些重要性採樣的技術可以進一步改善效果。

4、用PaddlePaddle實現

現在你已經基本了解了什麼是 SkipGram,而實現它需要藉助現有的深度學習框 架。PaddlePaddle 是百度自主研發的深度學習框架,功能非常強大,同時支持稠 密參數、稀疏參數並行訓練;靜態網絡、動態網絡等。而且有非常豐富的中英文文 檔,非常方便您使用。下面我們就用強大的 PaddlePaddle 一步一步實現它

首先,我們需要導入一些必要的計算庫。

# PaddlePaddle 計算引擎.
import paddle
from paddle import fluid

# 一些常用的科學計算庫.
import numpy as np
import matplotlib.pyplot as plt
然後設置定義一些超參數,用於控制網絡結構和訓練邏輯。
EMBEDDING_DIM = 64 # 詞向量維度.
WINDOW_SIZE = 5 # 滑動窗口大小.
BATCH_SIZE = 200 # 迭代 batch 大小.
EPOCH_NUM = 10 # 訓練的輪數.
RANDOM_STATE = 0 # 設置偽隨機數種子.


# 然後就是文本數據,這裡使用 PaddlePaddle 自帶(會自動下載)的 PTB 數據集,導入如下:
from paddle.dataset import imikolov

word_vocab = imikolov.build_dict()
vocab_size = len(word_vocab)

# 列印 PTB 數據字典的容量大小.
print("imikolov 字典大小為 " + str(vocab_size))

# 類似 Pytorch 的 DataLoader, 用於在訓練時做 batch, 很方便.
data_loader = paddle.batch(imikolov.test(word_vocab, WINDOW_SIZE), BATCH_SIZE)

imikolov 字典大小為 2074
# 下面我們需要搭建 SkipGram 的網絡結構,我們用一個函數打包如下:
def build_neural_network():
assert WINDOW_SIZE % 2 == 1
medium_num = WINDOW_SIZE // 2

# 定義輸入變量, 是從文本中截取的連續的文本段.
var_name_list = [str(i) + "-word" for i in range(0, WINDOW_SIZE)]
word_list = [fluid.layers.data(name=n, shape=[1], dtype="int64") for n in var_name_list]

# 取中心詞作為輸入, 而周圍上下文作為輸出.
input_word = word_list[medium_num]
output_context = word_list[:medium_num] + word_list[medium_num + 1:]

# 將輸入輸出都做詞向量表示, 並且將輸出拼起來.
embed_input = fluid.layers.embedding(
input=input_word, size=[vocab_size, EMBEDDING_DIM],
dtype="float32", is_sparse=True, param_attr="input_embedding")
embed_output_list = [fluid.layers.embedding(
input=w, size=[vocab_size, EMBEDDING_DIM], dtype="float32",
is_sparse=True, param_attr="output_embedding") for w in output_context]
concat_output = fluid.layers.concat(input=embed_output_list, axis=1)

# 用 -log(sigmoid(score)) 作為度量損失函數.
var_score = fluid.layers.matmul(embed_input, concat_output, transpose_x=True)
avg_loss = 0 - fluid.layers.mean(fluid.layers.log(fluid.layers.sigmoid(var_score)))

# 使用 Adam 優化算法, 並注意需要返回變量定義名.
fluid.optimizer.AdamOptimizer().minimize(avg_loss)
return avg_loss, var_name_list
# 運行 PaddlePaddle 計算引擎前需要一些熱身代碼。
# 確定執行的環境, 如果支持 CUDA 可以調用 GPUPlace 函數.
device_place = fluid.CPUPlace()
executor = fluid.Executor(device_place)

main_program = fluid.default_main_program()
star_program = fluid.default_startup_program()

# 固定偽隨機數種子, 一般用於保證論文效果可復現.
main_program.random_seed = RANDOM_STATE
star_program.random_seed = RANDOM_STATE

# 定義模型的架構 (之前定義函數輸出) 以及模型的輸入.
train_loss, tag_list = build_neural_network()
feed_var_list = [main_program.global_block().var(n) for n in tag_list]
data_feeder = fluid.DataFeeder(feed_list=feed_var_list, place=device_place)
# 下面開始訓練模型的流程,將迭代器產生的 batch 不斷餵入網絡中:
executor.run(star_program)
for epoch_idx in range(EPOCH_NUM):
total_loss, loss_list = 0.0, []

for batch_data in data_loader():
total_loss += float(executor.run(
main_program, feed=data_feeder.feed(batch_data),
fetch_list=[train_loss])[0])
loss_list.append(total_loss)
print("[迭代輪數 {:4d}], 在訓練集的損失為 {:.6f}".format(epoch_idx, total_loss))

[迭代輪數 0], 在訓練集的損失為 75.395110

[迭代輪數 1], 在訓練集的損失為 2.346059

[迭代輪數 2], 在訓練集的損失為 0.797208

[迭代輪數 3], 在訓練集的損失為 0.413886

[迭代輪數 4], 在訓練集的損失為 0.254423

[迭代輪數 5], 在訓練集的損失為 0.171255

[迭代輪數 6], 在訓練集的損失為 0.121907

[迭代輪數 7], 在訓練集的損失為 0.090095

[迭代輪數 8], 在訓練集的損失為 0.068378

[迭代輪數 9], 在訓練集的損失為 0.052923
# 我們可以將剛才訓練過程中的損失用 matplotlib 的庫函數畫出來。
plt.plot(np.array(range(0, len(loss_list))), loss_list)


好啦,以上就是本次所要分享。總的來說,本節我們主要講述了什麼是詞向量,什麼是語言模型,SkipGram 算法的內容以及其特性,相對 CBOW 來說它對低頻詞更友好,而且詞向量質量更佳,最後我們還細緻的教您一步一步用 PaddlePaddle 實現一個簡單的 SkipGram 模型。希望您多多支持,咱們下期再會。

推薦閱讀:

transformer中的attention為什麼scaled?

如何評價Word2Vec作者提出的fastText算法?深度學習是否在文本分類等簡單任務上沒有優勢?

從Word2Vec到Bert,聊聊詞向量的前世今生(一)

相關焦點

  • 手把手教你用飛槳做詞向量模型 SkipGram
    得到詞向量副產品;今天要講解的就是SkipGram 模型就屬於第三種方法,它的主要思想是利用的詞義的分布式表示。除了讓您徹底弄懂什麼是語言模型以及 SkipGram 的基本原理。我們還會詳細的說明如何一步步的用飛槳(PaddlePaddle)實現它。1.什麼是詞向量首先我們需要了解什麼是詞向量。
  • 基於PaddlePaddle的詞向量實戰 | 深度學習基礎任務教程系列(二)
    詞向量是自然語言處理中常見的一個操作,是搜尋引擎、廣告系統、推薦系統等網際網路服務背後常見的基礎技術。在這些網際網路服務裡,我們經常要比較兩個詞或者兩段文本之間的相關性。為了做這樣的比較,我們往往把詞表示成計算機適合處理的方式。最自然的方式莫過於向量空間模型(vector space model)。
  • 基於PaddlePaddle的詞向量實戰 | 深度學習基礎任務教程系列
    詞向量是自然語言處理中常見的一個操作,是搜尋引擎、廣告系統、推薦系統等網際網路服務背後常見的基礎技術。  在這些網際網路服務裡,我們經常要比較兩個詞或者兩段文本之間的相關性。為了做這樣的比較,我們往往把詞表示成計算機適合處理的方式。最自然的方式莫過於向量空間模型 (vector space model)。
  • 深度學習與PaddlePaddle的應用-個性化推薦
    詞向量(word embedding)詞向量技術是是推薦系統、搜尋引擎、廣告系統等網際網路服務必不可少的基礎技術,多用於這些服務的自然語言處理過程中。在這些網際網路服務裡,一個常見任務是要比較兩個詞或者兩段文本之間的相關性,要完成這個任務就需要把詞或文字表示成計算機能識別和處理的「語言」,如果在機器學習領域裡選擇問題的解決方法,通常會選擇詞向量模型。
  • PaddlePaddle實戰 | 情感分析算法從原理到實戰全解
    今天是5月20日,PaddlePaddle教你用情感分析算法體會女神心意。在下文中,我們將以情感分析為例,介紹使用深度學習的方法進行端對端的短文本分類,並使用PaddlePaddle完成全部相關實驗。在深度學習的方法出現之前,主流的文本表示方法為詞袋模型BOW(bag of words),話題模型等等;分類方法有SVM(support vector machine), LR(logistic regression)等等。對於一段文本,BOW表示會忽略其詞順序、語法和句法,將這段文本僅僅看做是一個詞集合,因此BOW方法並不能充分表示文本的語義信息。
  • 520禮包 | 情感分析算法從原理到PaddlePaddle實戰全解
    今天是5月20日,PaddlePaddle教你用情感分析算法體會女神心意。在下文中,我們將以情感分析為例,介紹使用深度學習的方法進行端對端的短文本分類,並使用PaddlePaddle完成全部相關實驗。在本教程中,我們所要介紹的深度學習模型克服了BOW表示的上述缺陷,它在考慮詞順序的基礎上把文本映射到低維度的語義空間,並且以端對端(end to end)的方式進行文本表示及分類,其性能相對於傳統方法有顯著的提升[1]。
  • PaddlePaddle入門:從對話系統中的情感分析談起
    在做了如下一番交涉後,該青年發現為自己服務的是一個機器人,並且答非所問,他怒火中燒,直接辱罵機器人。若你正好是開發該智能導購機器人的算法工程師,應該怎樣應對這種情況呢? 本文只使用CPU版本,讀者只需在自己的Linux/Mac上執行如下命令即可:pip install paddlepaddle在python腳本中導入paddle:import paddle.v2 as paddle若能導入成功,恭喜你,安裝成功。
  • 教程| 如何用百度深度學習框架PaddlePaddle做數據預處理
    輸入特徵是一個稀疏向量,這個向量的每個元素要麼是 0, 要麼是 1參數:同上返回類型:同上paddle.v2.data_type.sparse_vector(dim, seq_type=0)說明:稀疏向量,向量裡大多數元素是 0,其他的值可以是任意的浮點值參數:同上返回類型:同上paddle.v2.data_type.integer_value
  • 雲腦科技-實習僧文本匹配模型及基於百度PaddlePaddle的應用
    在圖像的應用中,卷積核的長寬一般均小於圖像矩陣,而在文本的應用中,卷積核長度雖然小於文本矩陣的長度,但其寬度一定等於文本矩陣寬度,即詞向量的維度。於是卷積核只在長度的方向上做卷積。雖然 DSSM 相比較於之前的匹配模型有著顯著的效果提升,但是 DSSM 的輸入是普通的詞哈希向量,並且其 DNN Unit 是疊加的全連接層,並沒有考慮文本的上下文聯繫。
  • 教程 | 如何用百度深度學習框架PaddlePaddle做數據預處理
    api 如下:說明:稠密向量的序列格式參數:dim(int):稠密向量的維度返回類型:InputTypedim(int):稀疏向量的維度seq_type(int):輸入的序列格式dim(int):稀疏向量的維度seq_type(int):輸入的序列格式不同的數據類型和序列模式返回的格式不同
  • 【深度學習系列】關於PaddlePaddle的一些避「坑」技巧
    博客專欄:https://www.cnblogs.com/charlotte77/前文傳送門:【好書推薦&學習階段】三個月教你從零入門深度學習【深度學習系列】PaddlePaddle之手寫數字識別【深度學習系列】卷積神經網絡CNN原理詳解(一)——基本原理【深度學習系列】PaddlePaddle之數據預處理
  • 深度學習系列:PaddlePaddle之手寫數字識別
    上周在搜索關於深度學習分布式運行方式的資料時,無意間搜到了paddlepaddle,發現這個框架的分布式訓練方案做的還挺不錯的,想跟大家分享一下。不過呢,這塊內容太複雜了,所以就簡單的介紹一下paddlepaddle的第一個「hello word」程序----mnist手寫數字識別。下一次再介紹用PaddlePaddle做分布式訓練的方案。
  • 基於飛槳PaddlePaddle的語義角色標註任務全解析
    在一個句子中,謂詞是對主語的陳述或說明,指出「做什麼」、「是什麼」或「怎麼樣,代表了一個事件的核心,跟謂詞搭配的名詞稱為論元。語義角色是指論元在動詞所指事件中擔任的角色。方式的謂詞序列和句子序列通過詞表,轉換為實向量表示的詞向量序列;將步驟 2 中的 2 個詞向量序列作為雙向 LSTM 的輸入,學習輸入序列的特徵表示;CRF 以步驟 3 中模型學習到的特徵為輸入,以標記序列為監督信號,實現序列標註;大家可以嘗試上面這種方法
  • 一行命令啟動,十分鐘完成部署,PaddleServing開放模型即服務功能
    本文將帶你一睹為快。古人云:行百裡者半九十。相信在深度學習領域中,不少做算法的小夥伴都會對這句話產生共鳴。辛辛苦苦搭建好網絡,望眼欲穿得訓練調試好模型,等到最後要部署,面對紛繁複雜的實際部署環境時,才發現原來終極大魔王在這裡!
  • PaddlePaddle升級解讀 | PaddleHub輕鬆完成遷移學習
    PaddleHub目前的預訓練模型覆蓋了圖像分類、目標檢測、詞法分析、Transformer、情感分析五大類別。 未來會持續開放更多類型的深度學習模型,如語言模型、視頻分類、圖像生成等預訓練模型。PaddleHub的功能全景如圖1所示。
  • PaddlePaddle深度學習開源平臺:等待眾人划槳的中國AI大船
    一個更方便閱讀的網址在:http://www.paddlepaddle.org/docs/develop/book/index.cn.html 能相信麼,還自帶視頻課堂,確實誠意滿滿了:http://bit.baidu.com/Course/datalist/column/117.html 2、 模型庫http://www.paddlepaddle.org
  • 乘風破浪的Paddle之LSTM
    實際上除了ERNIE,PaddlePaddle官方還有很多其他的NLP模型,覆蓋了包括語義表示、語義匹配、閱讀理解、機器翻譯、語言模型、情感傾向分析、詞法分析等各項NLP任務。Paddle提供了基於Penn Tree Bank (PTB)數據集的經典循環神經網絡LSTM語言模型實現,通過學習訓練數據中的序列關係,可以預測一個句子出現的的概率。Paddle也提供了基於Penn Tree Bank (PTB)數據集的經典循環神經網絡GRU語言模型實現,在LSTM模型基礎上做了一些簡化,保持效果基本持平的前提下,模型參數更少、速度更快。
  • Linux編譯安裝PaddlePaddle
    docker run --name paddle-test -v $PWD:/paddle --network=host -it docker.paddlepaddlehub.com/paddle:latest-dev /bin/bash進入docker編譯GPU版本的PaddlePaddle,執行命令如下:mkdir build && cd build
  • 用PaddlePaddle 和 Tensorflow 實現經典 CNN 網絡 GoogLeNet
    人的高矮、胖瘦、青老信息被聚合後做下一步判斷。像 NIN 一樣使用 Global Average Pooling,使得 Top 1 準確率提高 0.6%,但由於 GAP 與類別數目有關係,為了方便大家做模型 fine-tuning,最後加了一個全連接層;與前面的 ResNet 類似,實驗觀察到,相對淺層的神經網絡層對模型效果有較大的貢獻,訓練階段通過對 Inception(4a、4d) 增加兩個額外的分類器來增強反向傳播時的梯度信號
  • PaddlePaddle 2.0.0 Beta 發布,API 體系升級,命令式編程完善
    本版本系統優化了飛槳基礎API的目錄結構,全面修復了歷史遺留的相關問題,並對API做了充分補充,特別是提供了更為完善的高層API功能;同時提供了對動態圖的量化訓練、混合精度訓練的支持,動靜轉換實現了完備的語法支持,並且易用性大幅提升,動態圖相關功能趨於完善,推薦使用動態圖模式。此外,推理庫的C++接口也做了升級優化,推理庫對量化模型的支持以及推理性能都有了全面增強。