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

1. 简介

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

Flair是什么:

  • 强大的语法 - 语义标记器/分类器。 Flair允许应用先进的模型进行命名实体识别(NER),词性标注(PoS),分块和分类文本。
  • 文本嵌入库。 Flair具有简单的界面,允许使用和组合不同的单词和文档嵌入。特别是,可以尝试提出的上下文字符串嵌入来构建自己的NLP方法。
  • Pytorch NLP框架。 框架直接在Pytorch上构建,使您可以轻松地训练自己的模型,并使用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训练的模型)

  • 用法
    通过TextClassifier加载模型,如:classifier = TextClassifier.load('en-sentiment')
  • 模型种类
    目前只有两个:

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

存放于~/.flair/models

4.1.2 Embedding

  • WordEmbeddings,包括:GloVe, EXTVec, Crawl, Twitter, Wiki,
  • FlairEmbeddings, 包括:
    multilingual forward (English, German, French, Italian, Dutch, Polish)
    multilingual backward (English, German, French, Italian, Dutch, Polish)
    multilingual forward fast (English, German, French, Italian, Dutch, Polish)
    multilingual backward fast (English, German, French, Italian, Dutch, Polish)
    news-english-forward
    news-english-backward
    news-english-forward-fast
    news-english-backward-backward
    mix-english-forward
    mix-english-backward
    mix-german-forward
    mix-german-backward
    common crawl Polish forward
    common crawl Polish backward
    Slovenian forward
    Slovenian backward
    Bulgarian forward
    Bulgarian backward
    Dutch forward
    Dutch backward
    Swedish forward
    Swedish backward
    French forward
    French backward
    Czech forward
    Czech backward
    Portuguese forward
    Portuguese backward
  • CharLMEmbeddings:即将被去除,与FlairEmbeddings作用一样,已经被其取代
    存放于~/.flair/embeddings

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容