如何在深度學習中使用開源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. 問題解決方式
- 詞向量文件本身是以文本方式存儲的,第一行是詞向量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
- 詞表重複問題,是實際加載詞向量中遇到的比較麻煩的問題,重複的詞表導致無法用字典來索引每個詞對應的詞向量,所以上一步的詞向量加載,實際上應該考慮重複問題:
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"])
- 如何將得到的此向量矩陣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過程中,儘量要匹配好自己的需求。