过去的几年里,在NLP(天然语言处理)领域,咱们已经见证了多项使人难以置信的突破,如ULMFiT、ELMo、Facebook的PyText以及谷歌的BERT等等。浏览器
这些技术大大推动了NLP的前沿性研究,尤为是语言建模。只要给出前几个单词的顺序,咱们就能够预测下一个句子。app
但更重要的是,机器也找到了长期没法实现推测语句的关键因素。框架
那就是:语境!dom
对语境的了解打破了阻碍NLP技术进步的障碍。而今天,咱们就来讨论这样的一个库:Flair。机器学习
至今为止,单词要么表示为稀疏矩阵,要么表示为嵌入式词语,如GLoVe,Bert和ELMo。可是,事物总有改进的空间,Flair就愿意更正不足。oop
在本文中,首先咱们将了解Flair是什么以及其背后的概念。而后将深刻讨论使用Flair实现NLP任务。学习
一. 什么是Flair库?测试
Flair是由Zalando Research开发的一个简单的天然语言处理(NLP)库。 Flair的框架直接构建在PyTorch上,PyTorch是最好的深度学习框架之一。 Zalando Research团队还为如下NLP任务发布了几个预先训练的模型:优化
1. 名称-实体识别(NER):它能够识别单词是表明文本中的人,位置仍是名称。google
2. 词性标注(PoS):将给定文本中的全部单词标记为它们所属的“词性”。
3. 文本分类:根据标准对文本进行分类(标签)。
4. 培训定制模型:制做咱们本身的定制模型。
全部的这些模型,看起来颇有前景。但真正引发我注意的是,当我看到Flair在NLP中超越了几项最早进成绩的时候。看看这个目录:
注意:F1评分主要是用于分类任务的评估指标。在评估模型时,它一般用于机器学习项目中的精度度量。F1评分考虑了现有项目的分布。
二. Flair库的优点是什么?
Flair库中包含了许多强大的功能,如下是最突出的一些方面:
· 它包括了最通用和最早进的单词嵌入方式,如GloVe,BERT,ELMo,字符嵌入等。凭借Flair API技术,使用起来很是容易。
· Flair的界面容许咱们组合不一样的单词嵌入并嵌入文档,显著优化告终果。
· 'Flair 嵌入'是Flair库提供的签名嵌入。它由上下文字符串嵌入提供支持,咱们将在下一节中详细了解这一律念。
· Flair支持多种语言,并有望添加新语种。
三. 用于序列标记的上下文字符串嵌入简介
在处理NLP任务时,上下文语境很是重要。经过先前字符预测下一个字符,这一学习过程构成了序列建模的基础。
上下文字符串的嵌入,是经过熟练利用字符语言模型的内部状态,来产生一种新的嵌入类型。简单来讲,它经过字符模型中的某些内部原则,使单词在不一样的句子中能够具备不一样的含义。
注意:语言和字符模型是单词/字符的几率分布,所以每一个新单词或新字符都取决于前面的单词或字符。
有两个主要因素驱动了上下文字符串的嵌入:
1. 这些单词被理解为字符(没有任何单词的概念)。也就是说,它的工做原理相似于字符嵌入。
2. 嵌入是经过其周围文本进行语境化的。这意味着根据上下文,相同的单词能够有不一样的嵌入意义。很像天然的人类语言,不是吗?在不一样的状况下,同一个词可能有不一样的含义。
让咱们看个例子来理解这个意思:
· 案例1:读一本书(Reading a book)
· 案例2:请预订火车票(Please book a train ticket)
说明:
· 在案例1中,book是一个名词
· 在案例2中,book是动词
语言是如此奇妙而复杂的东西啊!
四. 使用Flair在Python中执行NLP任务
是时候让Flair进行测试了!咱们已经了解了这个神奇图书馆的所有内容。如今让咱们亲眼看看它在机器上是如何运行的。
咱们将使用Flair在Python中执行如下全部NLP任务:
1.使用Flair对嵌入的文本分类
2.词性标记(PoS)与NLTK库的比较
创建环境
咱们将使用Google Colaboratory运行咱们的代码。Colab最棒的一点就是它免费提供GPU支持!这极大地方便了学习模型的深度培训。
为何使用Colab?
· 彻底免费
· 具备至关不错的硬件配置
· 你的Web浏览器上都有,即便是硬件过期的旧机器也能够运行
· 链接到你的Google云端硬盘
· 很好地与Github集成
你只须要一个稳定的互联网链接。
关于数据集
咱们将努力研究Twitter Sentiment Analysis(推特敏感度分析)的实践问题。
而这一挑战带来的问题是:
这项任务的目的是检测推文中的仇恨言论。为了简单起见,若是它带有相关的种族主义或性别歧视情绪,咱们则判断这条推文包含仇恨言论。所以,这项任务是将带有种族主义或性别歧视地推文与其余推文分类。
1.使用Flair嵌入进行文本分类
第1步:将数据导入Colab的本地环境:
# Install the PyDrive wrapper & import libraries.
# This only needs to be done once per notebook.
!pip install -U -q PyDrive
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials
# Authenticate and create the PyDrive client.
# This only needs to be done once per notebook.
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
# Download a file based on its file ID.
# A file ID looks like: laggVyWshwcyP6kEI-y_W3P8D26sz
file_id = '1GhyH4k9C4uPRnMAMKhJYOqa-V9Tqt4q8' ### File ID ###
data = drive.CreateFile({'id': file_id})
#print('Downloaded content "{}"'.format(downloaded.GetContentString()))
你能够在驱动器中数据集文件的可共享连接中找到文件ID。
将数据集导入Colab笔记本:
import io
Import pandas as pd
data = pd.read_csv(io.StringIO(data.GetContentString()))
data.head()
已从数据中删除全部表情符号和符号,而且字符已转换为小写。
第2步:安装Flair
# download flair library #
import torch
!pip install flair
import flair
简要介绍一下Flair数据类型
这个库的对象有两种类型—句子和标记对象。一个句子持有一个文本句子,基本上是标记列表:
from flair.data import Sentence
# create a sentence #
sentence = Sentence('Blogs of Analytics Vidhya are Awesome.')
# print the sentence to see what’s in it. #
print(Sentence)
第3步:准备文本以使用Flair
#extracting the tweet part#
text = data['tweet']
## txt is a list of tweets ##
txt = text.tolist()
print(txt[:10])
第4步:使用Flair嵌入单词
## Importing the Embeddings ##
from flair.embeddings import WordEmbeddings
from flair.embeddings import CharacterEmbeddings
from flair.embeddings import StackedEmbeddings
from flair.embeddings import FlairEmbeddings
from flair.embeddings import BertEmbeddings
from flair.embeddings import ELMoEmbeddings
from flair.embeddings import FlairEmbeddings
### Initialising embeddings (un-comment to use others) ###
#glove_embedding = WordEmbeddings('glove')
#character_embeddings = CharacterEmbeddings()
flair_forward = FlairEmbeddings('news-forward-fast')
flair_backward = FlairEmbeddings('news-backward-fast')
#bert_embedding = BertEmbedding()
#elmo_embedding = ElmoEmbedding()
stacked_embeddings = StackedEmbeddings( embeddings = [
flair_forward-fast,
flair_backward-fast
])
你会注意到,咱们刚刚使用了一些上面最流行的单词嵌入。你能够删除评论'#'以使用全部嵌入。
如今你可能会问,到底什么是“堆叠嵌入”?在这里,咱们能够结合多个嵌入来构建一个功能强大的单词表示模型,不须要太复杂。很像合唱,不是吗?
咱们使用Flair的堆叠嵌入只是为了减小本文中的计算时间。使用你喜欢的任何组合能够随意地使用这个和其余嵌入。
测试堆叠嵌入:
# create a sentence #
sentence = Sentence(‘ Analytics Vidhya blogs are Awesome .')
# embed words in sentence #
stacked.embeddings(sentence)
for token in sentence:
print(token.embedding)
# data type and size of embedding #
print(type(token.embedding))
# storing size (length) #
z = token.embedding.size()[0]
第5步:将文本矢量化
咱们将使用两种方法展现这一点。
· 在推文中嵌入词的意思
咱们将在这种方法中计算如下内容:
对于每一个句子:
1.为每一个单词生成单词嵌入
2.计算每一个单词嵌入的平均值以获取句子嵌入
from tqdm import tqdm ## tracks progress of loop ##
# creating a tensor for storing sentence embeddings #
s = torch.zeros(0,z)
# iterating Sentence (tqdm tracks progress) #
for tweet in tqdm(txt):
# empty tensor for words #
w = torch.zeros(0,z)
sentence = Sentence(tweet)
stacked_embeddings.embed(sentence)
# for every word #
for token in sentence:
# storing word Embeddings of each word in a sentence #
w = torch.cat((w,token.embedding.view(-1,z)),0)
# storing sentence Embeddings (mean of embeddings of all words) #
s = torch.cat((s, w.mean(dim = 0).view(-1, z)),0)
· 文档嵌入:将整个推文矢量化
from flair.embeddings import DocumentPoolEmbeddings
### initialize the document embeddings, mode = mean ###
document_embeddings = DocumentPoolEmbeddings([
flair_embedding_backward,
flair_embedding_forward
])
# Storing Size of embedding #
z = sentence.embedding.size()[1]
### Vectorising text ###
# creating a tensor for storing sentence embeddings
s = torch.zeros(0,z)
# iterating Sentences #
for tweet in tqdm(txt):
sentence = Sentence(tweet)
document_embeddings.embed(sentence)
# Adding Document embeddings to list #
s = torch.cat((s, sentence.embedding.view(-1,z)),0)
你能够为模型选择任一种方法。如今咱们的文本已经矢量化过,咱们能够将其提供给咱们的机器学习模型了!
第6步: 为训练集和测试集划分数据
## tensor to numpy array ##
X = s.numpy()
## Test set ##
test = X[31962:,:]
train = X[:31962,:]
# extracting labels of the training set #
target = data['label'][data['label'].isnull()==False].values
第7步:构建模型并定义自定义评估程序(用于F1分数)
· 为XGBoost定义自定义F1评估程序
def custom_eval(preds, dtrain):
labels = dtrain.get_label().astype(np.int)
preds = (preds >= 0.3).astype(np.int)
return [('f1_score', f1_score(labels, preds))]
· 构建XGBoost模型
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
### Splitting training set ###
x_train, x_valid, y_train, y_valid = train_test_split(train, target,
random_state=42,
test_size=0.3)
### XGBoost compatible data ###
dtrain = xgb.DMatrix(x_train,y_train)
dvalid = xgb.DMatrix(x_valid, label = y_valid)
### defining parameters ###
params = {
'colsample': 0.9,
'colsample_bytree': 0.5,
'eta': 0.1,
'max_depth': 8,
'min_child_weight': 6,
'objective': 'binary:logistic',
'subsample': 0.9
}
### Training the model ###
xgb_model = xgb.train(
params,
dtrain,
feval= custom_eval,
num_boost_round= 1000,
maximize=True,
evals=[(dvalid, "Validation")],
early_stopping_rounds=30
)
至此,咱们的模型已经经过训练,能够进行评估了!
第8步: 能够预测了!
### Reformatting test set for XGB ###
dtest = xgb.DMatrix(test)
### Predicting ###
predict = xgb_model.predict(dtest) # predicting
咱们能够把预测上传到练习题界面,其中,0.2是几率阈值。
注意:根据Flair的官方文档显示,一个嵌入和其余嵌入堆叠时,效果更佳。可是存在一个问题。
在CPU上计算可能须要很是长的时间,强烈建议利用GPU来得到更快的结果,你能够在Colab中使用免费的。
2.词性标注(POS)
咱们将使用Conll-2003数据集的一个子集,是一个预先标记的英文数据集。
第1步:导入数据集
### file was uploaded manually to local environment of Colab ###
data = open('pos-tagged_corpus.txt','r')
txt = data.read()
#print(txt)
数据文件每行包含一个单词,空行表示句子边界。
第2步:从数据集中提取句子和PoS标签
### converting text in form of list of (words with their tags) ###
txt = txt.split(' ')
### removing DOCSTART (document header)
txt = [x for x in txt if x != '-DOCSTART- -X- -X- O']
### check ###
for i in range(10):
print(txt[i])
print(‘-’*10)
### Extracting Sentences ###
# Initialize empty list for storing words
words = []
# initialize empty list for storing sentences #
corpus = []
for i in tqdm(txt):
## if blank sentence encountered ##
if i =='':
## previous words form a sentence ##
corpus.append(' '.join(words))
## Refresh Word list ##
words = []
else:
## word at index 0 ##
words.append(i.split()[0])
# did it work? #
for i in range(10):
print(corpus[i])
print(‘-’*10)
### Extracting POS ###
# Initialize empty list for storing word pos
w_pos = []
#initialize empty list for storing sentence pos #
POS = []
for i in tqdm(txt):
## blank sentence = new line ##
if i =='':
## previous words form a sentence POS ##
POS.append(' '.join(w_pos))
## Refresh words list ##
w_pos = []
else:
## pos tag from index 1 ##
w_pos.append(i.split()[1])
# did it work? #
for i in range(10):
print(corpus[i])
print(POS[i])
### Removing blanks form sentence and pos ###
corpus = [x for x in corpus if x!= '']
POS = [x for x in POS if x!= '']
### Check ###
For i in range(10):
print(corpus[i])
print(POS[i])
咱们从数据集中提取了咱们须要的基本方面。让咱们继续第3步。
第3步:使用NLTK和Flair标记文本
· 使用NLTK进行标记
首先,输入所需的库资源:
import nltk
nltk.download('tagsets')
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
from nltk import word_tokenize
这将会下载全部所需的文件,用于使用NLTK进行标记。
### Tagging the corpus with NLTK ###
#for storing results#
nltk_pos = []
##for every sentence ##
for i in tqdm(corpus):
# Tokenize sentence #
text = word_tokenize(i)
#tag Words#
z = nltk.pos_tag(text)
# store #
nltk_pos.append(z)
POS标签采用如下格式:
[(‘token_1’, ‘tag_1’), ………….. , (‘token_n’, ‘tag_n’)]
让咱们从中提取POS:
### Extracting final pos by nltk in a list ###
tmp = []
nltk_result = []
## every tagged sentence ##
for i in tqdm(nltk_pos):
tmp = []
## every word ##
for j in i:
## append tag (from index 1) ##
tmp.append(j[1])
# join the tags of every sentence #
nltk_result.append(' '.join(tmp))
### check ###
for i in range(10):
print(nltk_result[i])
print(corpus[i])
NLTK标签已准备就绪。
· 如今,关注一下使用Flair进行标记
首先,输入库资源:
!pip install flair
from flair.data import Sentence
from flair.models import SequenceTagger
使用Flair进行标记:
# initiating object #
pos = SequenceTagger.load('pos-fast')
#for storing pos tagged string#
f_pos = []
## for every sentence ##
for i in tqdm(corpus):
sentence = Sentence(i)
pos.predict(sentence)
## append tagged sentence ##
f_pos.append(sentence.to_tagged_string())
###check ###
for i in range(10):
print(f_pos[i])
print(corpus[i])
结果将为如下格式:
token_1 <tag_1> token_2 <tag_2> ………………….. token_n <tag_n>
注意:咱们能够在Flair库中使用不一样的标记器,能够随意修补和实验。
用NLTK的方式提取句子标签
Import re
### Extracting POS tags ###
## in every sentence by index ##
for i in tqdm(range(len(f_pos))):
## for every words ith sentence ##
for j in corpus[i].split():
## replace that word from ith sentence in f_pos ##
f_pos[i] = str(f_pos[i]).replace(j,"",1)
## Removing < > symbols ##
for j in ['<','>']:
f_pos[i] = str(f_pos[i]).replace(j,"")
## removing redundant spaces ##
f_pos[i] = re.sub(' +', ' ', str(f_pos[i]))
f_pos[i] = str(f_pos[i]).lstrip()
### check ###
for i in range(10):
print(f_pos[i])
print(corpus[i])
啊哈!咱们终于标记了语料库并从其中按顺序提取出句子。咱们能够自由删除全部的标点和特殊符号。
### Removing Symbols and redundant space ###
## in every sentence by index ##
for i in tqdm(range(len(corpus))):
# Removing Symbols #
corpus[i] = re.sub('[^a-zA-Z]', ' ', str(corpus[i]))
POS[i] = re.sub('[^a-zA-Z]', ' ', str(POS[i]))
f_pos[i] = re.sub('[^a-zA-Z]', ' ', str(f_pos[i]))
nltk_result[i] = re.sub('[^a-zA-Z]', ' ', str(nltk_result[i]))
## Removing HYPH SYM (they are for symbols) ##
f_pos[i] = str(f_pos[i]).replace('HYPH',"")
f_pos[i] = str(f_pos[i]).replace('SYM',"")
POS[i] = str(POS[i]).replace('SYM',"")
POS[i] = str(POS[i]).replace('HYPH',"")
nltk_result[i] = str(nltk_result[i].replace('HYPH',''))
nltk_result[i] = str(nltk_result[i].replace('SYM',''))
## Removing redundant space ##
POS[i] = re.sub(' +', ' ', str(POS[i]))
f_pos[i] = re.sub(' +', ' ', str(f_pos[i]))
corpus[i] = re.sub(' +', ' ', str(corpus[i]))
nltk_result[i] = re.sub(' +', ' ', str(nltk_result[i]))
咱们使用NLTK和Flair标记了语料库,提取并删除了全部没必要要的元素,让咱们一块儿看看:
for i in range(1000):
print('corpus '+corpus[i])
print('actual '+POS[i])
print('nltk '+nltk_result[i])
print('flair '+f_pos[i])
print('-'*50)
输出:
结果看起来很是有说服力!
第4步:针对标记数据集评估来自NLTK和Flair的PoS标记
在这里,咱们将在定制评估器的帮助下对标签进行逐字评估。
请注意,在上面的示例中,与NLTK和flair标签相比,实际的POS标签包含冗余(如粗体所示)。所以,咱们不会考虑句子长度不等的POS标记句子。
### EVALUATION FUNCTION ###
def eval(x,y):
# correct match #
count = 0
#Total comparisons made#
comp = 0
## for every sentence index in dataset ##
for i in range(len(x)):
## if the sentence length match ##
if len(x[i].split()) == len(y[i].split()):
## compare each word ##
for j in range(len(x[i].split())):
if x[i][j] == y[i][j] :
## Match! ##
count = count+1
comp = comp + 1
else:
comp = comp + 1
return (count/comp)*100
最后,咱们根据数据集提供的POS标签评估NLTK和Flair的POS标签。
print("nltk Score ", eval2(POS,nltk_result))
print("Flair Score ", eval2(POS,f_pos))
结果是:
NLTK评估分数: 85.38654023442645
Flair 评估分数: 90.96172124773179
Flair显然在字嵌入和堆叠字嵌入方面占据优点。因为其高级的API,这些嵌入能够绝不费力地实现。