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时报错,不知道为什么。)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐