中文NLP的第二步:分詞轉詞表ID,基於 PaddleHub 實現(學習心得)

上一步我們做了分詞:
中文NLP的第一步:分詞,基於 PaddleHub 實現,絕對小白友好(學習心得)

第二步是把分詞結果,對照詞錶轉化成 ID

詞表是什麼呢?

首先我們要知道,中文字元是沒辦法直接計算的,更不要說進一步的操作了,所以我們需要的是詞嵌入,獲得 word embedding,詳見:
為什麼NLP中需要詞嵌入 word embeddings(學習心得)

而詞語要轉化為 word embedding 之前,先要根據詞錶轉化為對應的序號 ID,這樣轉化程式才知道你轉化的是哪個詞

所以這裡面是 2 重對應關係:

graph LR
A[詞語] -- 對應到 --> B[詞語的ID]

B --對應到--> D[詞語的向量表示]

這裡我們直接使用 PaddleHub 提供的 word2vec_skipgram 模型

Word2vec 是常用的詞嵌入(word embedding)模型。該 PaddleHub Module 基於 Skip-gram 模型,在海量百度搜索數據集下預訓練得到中文單詞預訓練詞嵌入。其支援 Fine-tune。Word2vec 的預訓練數據集的辭彙表大小為 1700249,word embedding 維度為 128。

模型介紹:
word2vec_skipgram

模型論文:
Efficient Estimation of Word Representations in
Vector Space

程式實現:

import paddlehub as hub
from paddlehub.reader.tokenization import load_vocab

raw_data = [
    ["你覺得明天是個晴天嗎","我看還是下雨的可能性大"],
    ["中國哪家公司的人工智慧最牛呢"],
    ["我在山上看見愛因斯坦"],
    ["我把車把一把把住了"]
]

lac = hub.Module(name="lac")

tokens = []
for texts in raw_data:
    results = lac.lexical_analysis(texts=texts, use_gpu=False, batch_size=1)
    for result in results: # 取得結果列表中的一個元素
        print(result)
        tokens.append(result['word'])

# 這是把 中文詞語 轉化為 詞表 中對應 ID 的函數
def convert_tokens_to_ids(vocab, tokens): # 輸入為詞表,和要轉化的 text
    wids = [] # 初始化一個空的集合,用於存放輸出
    #tokens = text.split(" ") # 將傳入的 text 用 空格 做分割,變成 詞語字元串 的列表
    for token in tokens: # 每次從列表裡取出一個 詞語
        wid = vocab.get(token, None)
        if not wid:
            wid = vocab["unknown"]
        wids.append(wid)
    return wids

module = hub.Module(name="word2vec_skipgram") # 實例化 word2vec_skipgram 模型

vocab = load_vocab(module.get_vocab_path()) # 獲得 詞表 字典

# 我們要獲取詞表,直接利用 paddlehub.reader.tokenization 中的 load_vocab 函數即可
# load_vocab 函數的輸入是具體的詞表文件,這裡我們用 word2vec_skipgram 附帶的詞表
# 模組的實例化對象 module 下,用 get_vocab_path() 方法
# 該方法可以在指定的 Module 中(這裡就是word2vec_skipgram)查找 assets 文件夾下面有沒有 vocab.txt 文件
# 如果找到,則返回該文件的 具體文件路徑
# load_vocab 函數的返回值是一個 字典,裡面 key 為 詞語,value 是詞語對應的 ID

tokens_ids = []
for item in tokens:
    item_ids = convert_tokens_to_ids(vocab, item) # 獲得組成句子的 詞語 的 ID 列表
    tokens_ids.append(item_ids)

for i in range(len(tokens)):
    print("token: %s; id: %s" % (tokens[i], tokens_ids[i]))

運行結果:

token: ['你', '覺得', '明天', '是', '個', '晴天', '嗎']; id: [42, 1405, 3867, 10, 132, 15549, 19]
token: ['我', '看', '還是', '下雨', '的', '可能性', '大']; id: [28, 104, 155, 9785, 4, 15268, 76]
token: ['中國', '哪家', '公司', '的', '人工智慧', '最', '牛', '呢']; id: [38, 586, 99, 4, 3258, 115, 1721, 286]
token: ['我', '在', '山上', '看見', '愛因斯坦']; id: [28, 21, 19869, 4500, 18837]
token: ['我', '把', '車', '把', '一把把', '住', '了']; id: [28, 166, 244, 166, 400305, 1827, 17]

OK,詞語的 ID 轉化完成!