ELMo詞向量文本分類
原理講解
ELMo出處:論文Deep contextualized word representations

ELMo無需标注。
原理可參考:從Word Embedding到Bert模型—自然語言進行中的預訓練技術發展史-張俊林
模型建構與訓練
中文預訓練模型:github上有哈工大的HIT-SCIR/ELMoForManyLangs,多種語言,注意區分有繁體中文和簡體中文(網盤下載下傳)兩種。
該模型是基于pytorch架構的。
初始化ELMo變換器
配置ELMo環境
安裝torch
pip3 install torch torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple
注意:在安裝中可能會報錯
ERROR: Failed building wheel for torch
。由于需要版本是大于1.4的,找不到對應的whl檔案,是以建議老老實實按pytorch官網選擇對應自己環境的指令安裝。
安裝elmoformanylangs
需要先裝上pytorch、h5py、numpy、overrides。
注意:我這裡遇到了運作python無反應的問題,且在指令行裡輸入python會跳轉到應用商店。這是由于在環境變量中path配置了
%USERPROFILE%\AppData\Local\Microsoft\WindowsApps
導緻,隻需要将該環境變量的配置去除,并保證已添加python的路徑到環境變量中即可解決。
# git clone https://github.com/HIT-SCIR/ELMoForManyLangs.git
cd ELMoForManyLangs
python setup.py install
導入
from elmoformanylangs import Embedder
e = Embedder('../ELMo_Chinese_text_classifier/zhs.model/')
如果在Windows上這一步有問題,可能是因為路徑中的左斜杠或右斜杠,絕對路徑或相對路徑。
用兩個句子做測試
sents = [['我', '在', '學習', '新', '的', '知識'],
['誰', '知道','預', '訓練', '模型', '的', '效果', '如何', '呢']]
results = e.sents2elmo(sents)
type(results)
type(results[0])
results[0].shape
手寫padding過程
def pad_sent(x, max_len):
if len(x)>max_len:
return x[:max_len]
else:
return x+['']*(max_len-len(x))
手寫使用ELMo變換後的生成器generator
由于哈工大的ELMo是用pytorch寫的,是以我們這裡用它當做一個變換器,不斷産出變換後的樣本。
def batch_generator(x, y, batch_size=64):
n_batches_per_epoch = len(x)//batch_size # 計算多少個batch
for i in range(n_batches_per_epoch):
x_batch = e.sents2elmo([pad_sent(sent,30) for sent in x[batch_size*i:batch_size*(i+1)]]) # 切片後截斷
y_batch = y[batch_size*i:batch_size*(i+1),:]
yield np.array(x_batch), y_batch
定義網絡結構
from tensorflow.keras import Input, Model
from tensorflow.keras.layers import Embedding, Dense, Conv1D, GlobalMaxPooling1D, Concatenate, Dropout
import numpy as np
class ELMoTextClassifier(object):
# 基于ELMO預訓練詞向量的TextCNN
def __init__(self, maxlen, max_features, embedding_dims,
class_num=5,
last_activation='softmax'):
self.maxlen = maxlen
self.max_features = max_features
self.embedding_dims = embedding_dims
self.class_num = class_num
self.last_activation = last_activation
def get_model(self):
embedding = Input((self.maxlen, self.embedding_dims,))
convs = []
for kernel_size in [3, 4, 5]:
c = Conv1D(128, kernel_size, activation='relu')(embedding)
c = GlobalMaxPooling1D()(c)
convs.append(c)
x = Concatenate()(convs)
output = Dense(self.class_num, activation=self.last_activation)(x)
model = Model(inputs=embedding, outputs=output)
return model
資料處理與訓練
注意這裡用的是
fit_generator
而不是
fit
。
Windows下同樣需要修改
import sys
sys.path.append('../data/lesson2_data')
from tensorflow.keras.preprocessing import sequence
import random
from sklearn.model_selection import train_test_split
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from tensorflow.keras.utils import to_categorical
from utils import *
# 資料檔案夾
data_dir = "../data/lesson2_data/data"
# 神經網絡配置
maxlen = 30
batch_size = 64
max_features = 40001
embedding_dims = 1024
epochs = 8
print('資料預處理與加載資料...')
# 獲得 詞彙/類别 與id映射字典
categories, cat_to_id = read_category()
# 全部資料
x, y = read_files(data_dir)
data = list(zip(x,y))
del x,y
# 亂序
random.shuffle(data)
# 切分訓練集和測試集
train_data, test_data = train_test_split(data)
# 對文本的詞id和類别id進行編碼
x_train = [content[0] for content in train_data]
y_train = to_categorical(encode_cate([content[1] for content in train_data], cat_to_id))
x_test = [content[0] for content in test_data]
y_test = to_categorical(encode_cate([content[1] for content in test_data], cat_to_id))
print('構模組化型...')
model = ELMoTextClassifier(maxlen, max_features, embedding_dims).get_model()
model.compile('adam', 'categorical_crossentropy', metrics=['accuracy'])
print('訓練...')
# 設定callbacks回調函數
my_callbacks = [
ModelCheckpoint('./cnn_model.h5', verbose=1),
EarlyStopping(monitor='val_accuracy', patience=2, mode='max')
]
# fit拟合資料
history = model.fit_generator(generator=batch_generator(x_train, y_train),
epochs=epochs,
callbacks=my_callbacks,
validation_data=batch_generator(x_test, y_test),
steps_per_epoch=len(y_train)//batch_size,
validation_steps=len(y_test)//batch_size)
訓練中間資訊的輸出和模型結構的列印
略,和前文一樣。
(跑到一個batch時報錯,不知道為什麼。)