机器学习Python机器学习和人工智能入门

Flair~快速构建迁移学习的自然语言学习组件

2019-01-21  本文已影响42人  blade_he

1. 简介

一个非常简单的框架,用于最先进的NLP。由Zalando Research开发。

Flair是什么:

其GitHub的项目地址位于: Flair

2. 安装

Flair安装需要Python 3.6
直接通过pip install flair即可

flairinstall.png
如果之前没有安装PyTorch,可以先按照官方的说明,通过如下方式安装(之前PyTorch不支持Windows版本,2018年已经支持Windows安装并应用了):
pip3 install https://download.pytorch.org/whl/cu90/torch-1.0.0-cp36-cp36m-win_amd64.whl
pip3 install torchvision

3. Flair的最主要特性 - 基于预训练模型做迁移学习

Flair的最主要特性,是基于预训练模型做迁移学习。

预训练模型的声明,集中在:python安装路径\Lib\site-packages\flair\embeddings.py中:


flairembeddings.png

由模块包含的类可以发现除了基础的WordEmbedding之外,还有最近的新贵ELMo,甚至Bert。

值得一提的是,所有支持的预训练模型,都在代码提供了下载地址,除了Bert之外,预训练模型都来自AllenNLP: 如:ELMo_2x_1024_128_2048cnn_1xhighway_options

Bert相关的预训练模型处理部分,位于:Python安装路径\Lib\site-packages\pytorch_pretrained_bert\modeling.py


flairbert.png

其也提供了下载地址,如:bert-base-uncased

具体的使用部分,可以参考官方文档

4. Flair预训练模型的存放路径

Flair相关的目录存放在登录用户的主目录,如:
Windows位于C:\Users\登录用户名\.flair
Linux对应于~/.flair

4.1 除了Bert与Elmo之外的可直接使用模型以及Embedding的存放路径

4.1.1 可直接使用模型(.pt扩展名,即pytorch训练的模型)

en-sentiment: 情绪识别,基于imdb的英文语料训练
de-offensive-language:基于德语的是否有攻击语言判断分类

存放于~/.flair/models

4.1.2 Embedding

4.2 ElMo预训练模型的存放路径

ELMo预训练的模型包括:small, medium两种,此外还有一个葡萄牙语的模型。

存放于~/.allennlp/cache

4.3 Bert预训练模型的存放路径

Bert预训练模型的类型:bert-base-uncased, bert-large-uncased,bert-base-cased,bert-base-multilingual,bert-base-chinese
存放于~/.pytorch_pretrained_bert
可以先根据:Python安装路径\Lib\site-packages\pytorch_pretrained_bert\modeling.py中的PRETRAINED_MODEL_ARCHIVE_MAP所声明的路径:

PRETRAINED_MODEL_ARCHIVE_MAP = {
    'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased.tar.gz",
    'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased.tar.gz",
    'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased.tar.gz",
    'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased.tar.gz",
    'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased.tar.gz",
    'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased.tar.gz",
    'bert-base-chinese': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-chinese.tar.gz",
}

将预训练模型先下载到本地,如~/.pytorch_pretrained_bert,然后再进行使用,否则在国内下载速度非常慢。
下载完毕后,现在Flair的版本居然不检测bert模型存放地址是否已经下载,还会从AWS S3下载,吐血。。。
出于改配置,不改代码的原则,我们修改配置字典:PRETRAINED_MODEL_ARCHIVE_MAP的bert-base-uncased的值(默认对应这个模型):

 'bert-base-uncased': Path.home() / ".pytorch_pretrained_bert/bert-base-uncased.tar.gz"

然后就OK了。

5 使用训练好的预置分类模型

最新的Flair 0.4版本包含有两个预先训练好的模型。一个基于IMDB数据集训练的情感分析模型和一个攻击性语言探测模型(当前仅支持德语)。

只需一个命令就可以下载、存储并使用模型,这使得预置模型的使用过程异常简单。例如,下面的代码将使用情感分析模型:

当第一次运行以下代码时,Flair将下载情感分析模型,默认情况下会保存到本地用户主目录的.flair子目录,下载可能需要几分钟。(作者太皮了,我下载到本地预估至少用了3个小时!!强烈建议先找到需要下载的预训练模型路径,通过迅雷等工具,下载下来,并拷贝到对应目录,从而缩短等待时间!)

from flair.models import TextClassifier
from flair.data import Sentence
print('load en-sentiment begin')
classifier = TextClassifier.load('en-sentiment')
print('load en-sentiment end')

sentence = Sentence('Flair is pretty neat!')
print('load predict begin')
classifier.predict(sentence)
print('load predict end')

# print sentence with predicted labels
print('Sentence above is: ', sentence.labels)

上面的代码首先载入必要的库,然后载入情感分析模型到内存中(必要时先下载),接下来就可以预测“Flair is pretty neat!”的情感分值了(0~1之间)。最后的命令输入结果为:
The sentence above is: [Positive (1.0)].
就是这么简单!现在你可以将上述代码整合为一个REST API,提供类似于google云端情感分析API的功能了!

6. 迁移学习练习

使用预训练模型,并创建自己的分类模型。
要训练一个自定义的文本分类器,首先需要一个标注文本集。Flair的分类数据集格式基于Facebook的FastText格式,要求在每一行的开始使用label前缀定义一个或多个标签。格式如下:

__label__<class_1> <text>
__label__<class_2> <text>

在这篇文章中我们将使用Kaggle的SMS垃圾信息检测数据集来用Flair构建一个垃圾/非垃圾分类器。这个数据集很适合我们的学习任务,因为它很小,只有5572行数据,可以在单个CPU上只花几分钟就完成模型的训练。

6.1 预处理 - 构建数据集

首先下载Kaggle上的数据集,得到spam.csv;然后再数据集目录下,运行我们的处理脚本,得到训练集、开发集和测试集:

import pandas as pd
# The frac keyword argument specifies the fraction of rows to return in the random sample, 
# so frac=1 means return all rows (in random order).
data = pd.read_csv("./csv/spam.csv", encoding='latin-1').sample(frac=1).drop_duplicates()

data = data[['v1', 'v2']].rename(columns={"v1":"label", "v2":"text"})
 
data['label'] = '__label__' + data['label'].astype(str)

data.iloc[0:int(len(data)*0.8)].to_csv('./csv/spamtrain.csv', sep='\t', index = False, header = False)
data.iloc[int(len(data)*0.8):int(len(data)*0.9)].to_csv('./csv/spamtest.csv', sep='\t', index = False, header = False)
data.iloc[int(len(data)*0.9):].to_csv('./csv/spamdev.csv', sep='\t', index = False, header = False)

上面的脚本会进行剔重和随机乱序处理,并按照80/10/10的比例进行数据集的分割。

脚本成功执行后,就会得到FastText格式的三个数据文件:train.csv、dev.csv和test.csv。

如果需要支持多标签分类,标签之间用空格分隔。

最简单的方式就是通过label标签1 label标签2实现,如下面所示实现了三标签分类:

__label__add __label__close __label__merge

6.2 训练自定义文本分类模型

这里使用了WordEmbeddings: GloVe作为预训练模型,不过DocumentLSTMEmbeddings类,是支持Emedding列表的,所以按照如下代码去定义包含Bert预训练模型的embedding列表,然后实例化DocumentLSTMEmbeddings也是可以的:

# BertEmbeddings模型使用base uncase预训练模型
word_embeddings = [BertEmbeddings(), 
  FlairEmbeddings('news-forward-fast'), 
  FlairEmbeddings('news-backward-fast')]

document_embeddings = DocumentLSTMEmbeddings(word_embeddings,   
  hidden_size=512,
  reproject_words=True,
  reproject_words_dimension=256,
  bidirectional=True)

通过GloVe作为预训练模型进行迁移学习的源码:

from flair.data_fetcher import NLPTaskDataFetcher
from flair.embeddings import WordEmbeddings, FlairEmbeddings, DocumentLSTMEmbeddings
from flair.models import TextClassifier
from flair.trainers import ModelTrainer
from pathlib import Path
import os

if not os.path.exists('./nlpmodel/flair/spam/best-model.pt'):
    corpus = NLPTaskDataFetcher.load_classification_corpus(Path('./csv'), 
                                                           test_file='spamtrain.csv', 
                                                           dev_file='spamdev.csv', 
                                                           train_file='spamtest.csv')

    word_embeddings = [WordEmbeddings('glove'), 
                       FlairEmbeddings('news-forward-fast'), 
                       FlairEmbeddings('news-backward-fast')]

    document_embeddings = DocumentLSTMEmbeddings(word_embeddings, 
                                                 hidden_size=512, 
                                                 reproject_words=True, 
                                                 reproject_words_dimension=256)

    classifier = TextClassifier(document_embeddings, 
                                label_dictionary=corpus.make_label_dictionary(), 
                                multi_label=False)

    trainer = ModelTrainer(classifier, corpus)

    trainer.train('./nlpmodel/flair/spam', max_epochs=20)
else:
    print('model: {0} existed!'.format('./nlpmodel/flair/spam/best-model.pt'))

第一次运行上面这个脚本时,Flair会自动下载所需要的嵌入模型,这可能需要一段时间(如果预先下载,并放入上述提到的Embedding的存放路径,就可以直接训练模型),然后接下来的整个训练过程还需要大约5分钟。

脚本首先载入需要的库和数据集,得到一个corpus对象。

接下来,我们创建一个嵌入列表,包含两个Flair上下文字符串嵌入和一个GloVe单词嵌入,这个列表接下来将作为我们文档嵌入对象的输入。

具体训练的截图如下:


flairtrain.png

堆叠和文本嵌入是Flair中最有趣的感念之一,它们提供了将不同的嵌入整合在一起的手段,你可以同时使用单词嵌入(例如GloVe、word2vector、ELMo,Bert)和Flair的上下文字符串嵌入。

在上面的示例中我们使用一个基于LSTM的方法来生成文档嵌入,关于该方法的详细描述可以参考这里
下面进行简单的垃圾信息预测,简直是惊天地泣鬼神的简易:

classifier = TextClassifier.load_from_file('./nlpmodel/flair/spam/best-model.pt')
textlist= ["Hi. Yes mum, I will...", 
           "Want 2 get laid tonight? Want real Dogging locations sent direct 2 ur mob? Join the UK's largest Dogging Network bt Txting GRAVEL to 69888! Nt. ec2a. 31p.msg@150p"
          ]
for text in textlist:
    sentence = Sentence(text)
    classifier.predict(sentence)
    print('Text: {0} is belong to: {1}'.format(text, sentence.labels))

输入大致如下:

Text: Hi. Yes mum, I will... is belong to: [ham (1.0)]
Text: Want 2 get laid tonight? Want real Dogging locations sent direct 2 ur mob? Join the UK's largest Dogging Network bt Txting GRAVEL to 69888! Nt. ec2a. 31p.msg@150p is belong to: [spam (1.0)]

值得一提的是,经过加载预处理的GloVe单词嵌入生成的模型非常大,即使是Spam这种只有几千句,492K的训练集,生成的模型,也有200多M,至少比嵌入的预训练模型要大一丢丢。(通过Bert Base预训练模型进行迁移学习,训练得到的模型将近500M)


flairmodel.png
上一篇 下一篇

猜你喜欢

热点阅读