使用Chinese-Word-Vectors作爲pytorch中的預訓練向量

如何在深度學習中使用開源Chinese Word Vectors

摘要:Chinese-Word-Vectors開源項目提供了100多種預訓練模型,但在深度學習中使用時,加載預訓練向量存在詞表重複項問題。本文着重於解決加載問題。

1. 起因

去年半年一直在搭建我的NLP練習項目——爲語音識別文本進行標點恢復,使用的技術如下所示:

  • 詞向量訓練
  • BiLSTM
  • CRF

但是上面的技術在訓練網絡的時候,詞向量是在訓練中不斷訓練得到的。一方面這樣的詞向量更配合網絡的結構,具有任務特定性;但是另一方面,受限於語料大小和計算資源,直接由自己的數據集訓練出的詞向量肯定是不夠泛化,不夠強健的

2. Chinese-Word-Vectors技術方案存在的問題

時至今日,在2019年bert橫掃NLP任務之後,使用預訓練模型已經不再稀奇。使用預訓練的模型可以用更少的訓練資源得到較好的效果。即使是使用傳統的word2vec也能有效提高模型的泛化性。

Chinese-Word-Vectors是北京師範大學和人民大學的研究者開源出來的100多箇中文預訓練詞向量,所有向量都是在word2vec和skip-gram上訓練出來的。

久仰大名,碼下很久,但是未嘗親自試用。親自使用後,便發現了一些問題。

  • 如何讀取從Chinese-Word-Vectors下載下來的詞向量?
  • 讀取時發現詞表有重複,導致存入python字典中後,導致詞表大小和訓練好的詞向量矩陣不一致?
  • 讀取到的詞向量矩陣如何載入到深度學習模型的詞嵌入矩陣embedding中?

果然紙上得來終覺淺,絕知此事要躬行

3. 問題解決方式

  1. 詞向量文件本身是以文本方式存儲的,第一行是詞向量size信息,後面每一行是每個詞和它的詞向量。通過使用ngram2vec工具中的代碼可以加載詞向量(Chinese-Word-Vectors也使用了ngram2vec工具來訓練):
def load_dense(path):
    vocab_size, size = 0, 0
    vocab = {}
    vocab["i2w"], vocab["w2i"] = [], {}
    with codecs.open(path, "r", "utf-8") as f:
        first_line = True
        for line in f:
            if first_line:
                first_line = False
                vocab_size = int(line.strip().split()[0])
                size = int(line.rstrip().split()[1])
                matrix = np.zeros(shape=(vocab_size, size), dtype=np.float32)
                continue
            vec = line.strip().split()
            vocab["i2w"].append(vec[0])
            # vocab的length不斷增長
            matrix[len(vocab["i2w"])-1, :] = np.array([float(x) for x in vec[1:]])
    for i, w in enumerate(vocab["i2w"]):
        vocab["w2i"][w] = i
    return matrix, vocab, size
  1. 詞表重複問題,是實際加載詞向量中遇到的比較麻煩的問題,重複的詞表導致無法用字典來索引每個詞對應的詞向量,所以上一步的詞向量加載,實際上應該考慮重複問題:
def load_dense_drop_repeat(path):
    vocab_size, size = 0, 0
    vocab = {}
    vocab["i2w"], vocab["w2i"] = [], {}
    count = 0
    with codecs.open(path, "r", "utf-8") as f:
        first_line = True
        for line in f:
            if first_line:
                first_line = False
                vocab_size = int(line.strip().split()[0])
                size = int(line.rstrip().split()[1])
                matrix = np.zeros(shape=(vocab_size, size), dtype=np.float32)
                continue
            vec = line.strip().split()
            if not vocab["w2i"].__contains__(vec[0]):
                vocab["w2i"][vec[0]] = count
                matrix[count, :] = np.array([float(x) for x in vec[1:]])
                count += 1
    for w, i in vocab["w2i"].items():
        vocab["i2w"].append(w)
    return matrix, vocab, size, len(vocab["i2w"])
  1. 如何將得到的此向量矩陣matrix載入到torch中的embedding中?(上一步中,爲了減少每次讀matrix的耗時,可以將matrix用numpy保存到npy文件):
    emb = np.load(emb)
    print('emb的shape:', emb.shape)
    self.embedding = nn.Embedding(vocab_size, embedding_size)
    self.embedding.weight.data.copy_(torch.from_numpy(emb))
    self.embedding.weight.requires_grad = True

4. 總結

總的來看Chinese-Word-Vectors預訓練數據是有其價值的,減少了很多的訓練資源。但是由於自然語言處理的文本本身具有非常大的噪聲,很難保證詞向量是完美的、不包含任何錯字和重複。

在使用Chinese-Word-Vectors過程中,儘量要匹配好自己的需求。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章