天天看點

NLP實戰之ELMo詞向量文本分類

ELMo詞向量文本分類

原理講解

ELMo出處:論文Deep contextualized word representations

NLP實戰之ELMo詞向量文本分類

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時報錯,不知道為什麼。)

繼續閱讀