天天看點

基于騰訊AI Lab詞向量進行未知詞、短語向量補齊與域内相似詞搜尋1 Tencent_AILab_ChineseEmbedding讀入與高效查詢2 未知詞、短語向量補齊與域内相似詞搜尋

AI Lab開源大規模高品質中文詞向量資料,800萬中文詞随你用,品質非常高,就是一個詞向量.txt檔案都有16G之多,太誇張了。。不過的确非常有特點:

  • ⒈ 覆寫率(Coverage):

該詞向量資料包含很多現有公開的詞向量資料所欠缺的短語,比如“不念僧面念佛面”、“冰火兩重天”、“煮酒論英雄”、“皇帝菜”、“喀拉喀什河”等。以“喀拉喀什河”為例,利用騰訊AI Lab詞向量計算出的語義相似詞如下:

墨玉河、和田河、玉龍喀什河、白玉河、喀什河、葉爾羌河、克裡雅河、瑪納斯河

  • ⒉ 新鮮度(Freshness):

該資料包含一些最近一兩年出現的新詞,如“戀與制作人”、“三生三世十裡桃花”、“打call”、“十動然拒”、“供給側改革”、“因吹斯汀”等。以“因吹斯汀”為例,利用騰訊AI Lab詞向量計算出的語義相似詞如下:

一顆賽艇、因吹斯聽、城會玩、厲害了word哥、emmmmm、紮心了老鐵、神吐槽、可以說是非常爆笑了

  • ⒊ 準确性(Accuracy):

由于采用了更大規模的訓練資料和更好的訓練算法,所生成的詞向量能夠更好地表達詞之間的語義關系。

騰訊AI Lab采用自研的Directional Skip-Gram (DSG)算法作為詞向量的訓練算法。DSG算法基于廣泛采用的詞向量訓練算法Skip-Gram (SG),在文本視窗中詞對共現關系的基礎上,額外考慮了詞對的相對位置,以提高詞向量語義表示的準确性。

文章目錄

  • 1 Tencent_AILab_ChineseEmbedding讀入與高效查詢
  • 2 未知詞、短語向量補齊與域内相似詞搜尋
    • 網絡用語挖掘:
    • 評論觀點
    • 同義詞挖掘

1 Tencent_AILab_ChineseEmbedding讀入與高效查詢

來看一下一個比較常見的讀入方式:lvyufeng/keras_text_sum/load_embedding.py

import numpy as np

def load_embedding(path):
    embedding_index = {}
    f = open(path,encoding='utf8')
    for index,line in enumerate(f):
        if index == 0:
            continue
        values = line.split(' ')
        word = values[0]
        coefs = np.asarray(values[1:],dtype='float32')
        embedding_index[word] = coefs
    f.close()

    return embedding_index

load_embedding('/home/lv/data_set/Tencent_AILab_ChineseEmbedding/Tencent_AILab_ChineseEmbedding.txt')           

複制

這樣純粹就是以字典的方式讀入,當然用于模組化沒有任何問題,但是筆者想在之中進行一些相似性操作,最好的就是重新載入gensim.word2vec系統之中,但是筆者發現載入半天都會報錯:

ValueError: invalid vector on line 418987 (is this really the text format?)           

複制

仔細一檢視,發現原來一些詞向量的詞就是數字,譬如

-0.2121

57851

,是以一直導入不進去。隻能自己用txt讀入後,删除掉這一部分,儲存的格式參考下面。

5 4
是 -0.119938 0.042054504 -0.02282253 -0.10101332
中國人 0.080497965 0.103521846 -0.13045108 -0.01050107
你 -0.0788643 -0.082788676 -0.14035964 0.09101376
我 -0.14597991 0.035916027 -0.120259814 -0.06904249           

複制

第一行是一共5個詞,每個詞次元為4.

然後清洗完畢之後,就可以讀入了:

wv_from_text = gensim.models.KeyedVectors.load_word2vec_format('Tencent_AILab_ChineseEmbedding_refine.txt',binary=False)           

複制

但是又是一個問題,占用記憶體太大,導緻不能查詢相似詞,是以這裡可以用一下這個神奇的函數,可以高效運作,這樣就可以順利使用

most_similar

這類函數了:

wv_from_text.init_sims(replace=True)  # 神奇,很省記憶體,可以運算most_similar           

複制

該操作是指model已經不再繼續訓練了,那麼就鎖定起來,讓Model變為隻讀的,這樣可以預載相似度矩陣,對于後面得相似查詢非常有利。

2 未知詞、短語向量補齊與域内相似詞搜尋

這邊未知詞語、短語的補齊手法是參考FastText的用法:極簡使用︱Gemsim-FastText 詞向量訓練以及OOV(out-of-word)問題有效解決

這邊筆者借鑒了fasttext之中的方式,當出現未登入詞或短語的時候,會:

  • 先将輸入詞進行n-grams
  • 然後去詞表之中查找
  • 查找到的詞向量進行平均

主要函數可見:

import numpy as np

def compute_ngrams(word, min_n, max_n):
    #BOW, EOW = ('<', '>')  # Used by FastText to attach to all words as prefix and suffix
    extended_word =  word
    ngrams = []
    for ngram_length in range(min_n, min(len(extended_word), max_n) + 1):
        for i in range(0, len(extended_word) - ngram_length + 1):
            ngrams.append(extended_word[i:i + ngram_length])
    return list(set(ngrams))


def wordVec(word,wv_from_text,min_n = 1, max_n = 3):
    '''
    ngrams_single/ngrams_more,主要是為了當出現oov的情況下,最好先不考慮單字詞向量
    '''
    # 确認詞向量次元
    word_size = wv_from_text.wv.syn0[0].shape[0]   
    # 計算word的ngrams詞組
    ngrams = compute_ngrams(word,min_n = min_n, max_n = max_n)
    # 如果在詞典之中,直接傳回詞向量
    if word in wv_from_text.wv.vocab.keys():
        return wv_from_text[word]
    else:  
        # 不在詞典的情況下
        word_vec = np.zeros(word_size, dtype=np.float32)
        ngrams_found = 0
        ngrams_single = [ng for ng in ngrams if len(ng) == 1]
        ngrams_more = [ng for ng in ngrams if len(ng) > 1]
        # 先隻接受2個單詞長度以上的詞向量
        for ngram in ngrams_more:
            if ngram in wv_from_text.wv.vocab.keys():
                word_vec += wv_from_text[ngram]
                ngrams_found += 1
                #print(ngram)
        # 如果,沒有比對到,那麼最後是考慮單個詞向量
        if ngrams_found == 0:
            for ngram in ngrams_single:
                word_vec += wv_from_text[ngram]
                ngrams_found += 1
        if word_vec.any():
            return word_vec / max(1, ngrams_found)
        else:
            raise KeyError('all ngrams for word %s absent from model' % word)
    
vec = wordVec('千奇百怪的詞向量',wv_from_text,min_n = 1, max_n = 3)  # 詞向量擷取
wv_from_text.most_similar(positive=[vec], topn=10)    # 相似詞查找           

複制

compute_ngrams

函數是将詞條N-grams找出來,譬如:

compute_ngrams('萌萌的哒的',min_n = 1,max_n = 3)
>>> ['哒', '的哒的', '萌的', '的哒', '哒的', '萌萌的', '萌的哒', '的', '萌萌', '萌']           

複制

這邊沒有沿用fasttext之中的

<>

來區分詞頭、詞尾。

wordVec

函數是計算未登入詞的,其中筆者小小加了一些内容,就是:當出現oov的情況下,最好先不考慮單字詞向量,如果能比對到兩個字以上的内容就優先進行平均。

在得到未登入詞或短語的向量之後,就可以快速進行查找,gensim裡面是支援給入向量進行相似詞查找:

wv_from_text.most_similar(positive=[vec], topn=10)           

複制

其實,有了這麼一個小函數 + 稍微大記憶體的伺服器,就可以開始挖金礦了,筆者在此給出一部分可供參考與使用的小案例,案例中找出來的相似肯定還是不那麼幹淨,需要自行清洗一下:

網絡用語挖掘:

vec = wordVec('天了噜',wv_from_text,min_n = 1, max_n = 3)
wv_from_text.most_similar(positive=[vec], topn=20)

[('天了噜', 1.0),
 ('天啦噜', 0.910751223564148),
 ('天惹', 0.8336831331253052),
 ('我的天呐', 0.8315592408180237),
 ('天哪噜', 0.8200887441635132),
 ('也是醉了', 0.8048921823501587),
 ('哦買噶', 0.7951157093048096),
 ('我也是醉了', 0.7925893664360046),
 ('我的天哪', 0.7903991937637329),
 ('天呐', 0.7862901091575623)
......
]           

複制

評論觀點

vec = wordVec('真難吃',wv_from_text,min_n = 1, max_n = 3)
wv_from_text.most_similar(positive=[vec], negative=['好吃'], topn=20)

[('真難', 0.8344259858131409),
 ('難吃', 0.8344259262084961),
 ('不好吃', 0.7413374185562134),
 ('難啊', 0.7120314836502075),
 ('難喝', 0.6996017694473267),
 ('難以下咽', 0.6920732259750366),
 ('好難', 0.6856701374053955),
 ('挺好吃', 0.6801191568374634),
 ('真不容易', 0.6788320541381836),
 ('真的很難', 0.671592116355896),
 ('真的很好吃', 0.6692471504211426),
...           

複制

例子2:

vec = wordVec('環境幹淨',wv_from_text,min_n = 1, max_n = 3)
wv_from_text.most_similar(positive=[vec], topn=20)

[('環境幹淨', 0.9999998807907104),
 ('環境幹淨整潔', 0.8523852825164795),
 ('環境舒适', 0.8281853199005127),
 ('環境幹淨衛生', 0.8241869211196899),
 ('衛生幹淨', 0.8118663430213928),
 ('幹淨衛生', 0.7971832156181335),
 ('幹淨舒适', 0.796349287033081),
 ('環境清新', 0.7937666773796082),
 ('衛生好', 0.7925254702568054),
 ('環境整潔', 0.7919654846191406),
 ('環境好', 0.7814522981643677),
 ('房間幹淨', 0.7802159786224365),
 ('環境優雅', 0.7685255408287048),           

複制

同義詞挖掘

vec = wordVec('蘋果',wv_from_text,min_n = 1, max_n = 3)
wv_from_text.most_similar(positive=[vec],negative=['水果'], topn=20)

[('蘋果公司', 0.5877306461334229),
 ('蘋果開發', 0.5226757526397705),
 ('高通', 0.5215991735458374),
 ('谷歌', 0.5213730335235596),
 ('蘋果的iphone', 0.5150437355041504),
 ('微軟', 0.5127487778663635),
 ('蘋果新', 0.5012987852096558),
 ('pixel手機', 0.49072039127349854),
 ('蘋果高管', 0.4897959530353546),
 ('蘋果iphone', 0.4875335991382599),
 ('蘋果手機iphone', 0.4791686534881592),
 ('蘋果晶片', 0.47766292095184326),
 ('iphone', 0.4754045307636261),           

複制