NLP的项目流程比较繁琐,正好现在又AllenNLP这个基于PyTorch的工具可以用于规范数据处理,模型构建、训练和测试,感觉不错。之前看了一篇论文,作者用TensorFlow 1.13版本写的一个NLP项目,感觉实在是复杂。

目录

  • AllenNLP概要
  • AllenNLP官方样例代码
    • 导入库
    • 读取数据集
    • 构建模型
    • 训练、测试模型
  • 更详细的教程

AllenNLP概要

先看一下AllenNLP(https://allennlp.org/)在GitHub页面中的概要,关键就是下面这个表格:

allennlp an open-source NLP research library, built on PyTorch
allennlp.commands functionality for a CLI and web service
allennlp.data a data processing module for loading datasets and encoding strings as integers for representation in matrices
allennlp.models a collection of state-of-the-art models
allennlp.modules a collection of PyTorch modules for use with text
allennlp.nn tensor utility functions, such as initializers and activation functions
allennlp.training functionality for training models

AllenNLP主要分为六个模块:

  • commands:处理命令行和网络服务的一些函数;
  • data:数据处理,数据集加载,将字符串表示为整数;
  • models:一些state-of-the-art模型;
  • modules:一些用于处理文本的PyTorch模块;
  • nn:张量操作的一些函数,包括初始化、激活函数等等;
  • training:用于训练模型的一些函数;

AllenNLP官方样例代码

先看看官方给出的样例代码,简化版的tutorial。这份代码是写在一个Python文件中的,实际项目中会分成各个文件和文件夹。

导入库

from typing import Iterator, List, Dict
import torch
import torch.optim as optim
import numpy as np
from allennlp.data import Instance
from allennlp.data.fields import TextField, SequenceLabelField
from allennlp.data.dataset_readers import DatasetReader
from allennlp.common.file_utils import cached_path
from allennlp.data.token_indexers import TokenIndexer, SingleIdTokenIndexer
from allennlp.data.tokenizers import Token
from allennlp.data.vocabulary import Vocabulary
from allennlp.models import Model
from allennlp.modules.text_field_embedders import TextFieldEmbedder, BasicTextFieldEmbedder
from allennlp.modules.token_embedders import Embedding
from allennlp.modules.seq2seq_encoders import Seq2SeqEncoder, PytorchSeq2SeqWrapper
from allennlp.nn.util import get_text_field_mask, sequence_cross_entropy_with_logits
from allennlp.training.metrics import CategoricalAccuracy
from allennlp.data.iterators import BucketIterator
from allennlp.training.trainer import Trainer
from allennlp.predictors import SentenceTaggerPredictortorch.manual_seed(1)
  • typing库是Python标准库中用于提供类型注释的,torch库就是PyTorch。
  • allennlp.data用来组织模型处理的数据,其中每个训练样本被组织成Instance,每个Instance中有不同的字段Fields,这里用的是TxetFieldSequenceLabelField
  • allennlp.data.dataset_readers.DatasetReader是用于读取数据的类,大多数AllenNLP代码必须实现的两个类之一,另一个是allennlp.models.Model
  • allennlp.common.file_utils.cached_path是用于下载文件的,也可以指定本地的文件;
  • allennlp.data中的几个token相关的类是用来将文本的token映射为indices(就当是一个token映射到一个整数,token->id),allennlp.data.vocabularly用来将这些映射组合起来构成单词表;
  • allennlp.modulesallennlp.nn.util中的几个Embedding相关的类,是用来给模型添加词嵌入层的;
  • allennlp.training.metrics中的类是用来评测模型的;
  • allennlp.data.iterator中的DataIterator类是数据读取的迭代器,可以用来进行批处理之类的操作;
  • allennlp.training.trainer.Trainerallennlp.predictors.SentenceTaggerPredictro用来训练模型和进行预测;

读取数据集

class PosDatasetReader(DatasetReader):"""DatasetReader for PoS tagging data, one sentence per line, likeThe###DET dog###NN ate###V the###DET apple###NN"""def __init__(self, token_indexers: Dict[str, TokenIndexer] = None) -> None:super().__init__(lazy=False)self.token_indexers = token_indexers or {"tokens": SingleIdTokenIndexer()}def text_to_instance(self, tokens: List[Token], tags: List[str] = None) -> Instance:sentence_field = TextField(tokens, self.token_indexers)fields = {"sentence": sentence_field}if tags:label_field = SequenceLabelField(labels=tags, sequence_field=sentence_field)fields["labels"] = label_fieldreturn Instance(fields)def _read(self, file_path: str) -> Iterator[Instance]:with open(file_path) as f:for line in f:pairs = line.strip().split()sentence, tags = zip(*(pair.split("###") for pair in pairs))yield self.text_to_instance([Token(word) for word in sentence], tags)
  • PosDatasetReader实现DatasetReader类,用于读取词性标注(Part-of-Speech)数据,每行一句话,用###分隔开(比如The的词性为DET)。类初始化时的参数只有一个从token(字符串)到TokenIndexer的字典映射(应该是单词表);
  • text_to_instance函数将每个句子的token和tag(分别是模型的输入和输出),转换为一个实例Instance(其实就是组织在一个fields字典里);
  • _read函数(单下划线开头为默认的模块内部函数),这里读取整个文件,返回一个实例的迭代器(注意这里是生成器yield)。多数时候这部分内容写在text_to_instance中;

构建模型

class LstmTagger(Model):def __init__(self,word_embeddings: TextFieldEmbedder,encoder: Seq2SeqEncoder,vocab: Vocabulary) -> None:super().__init__(vocab)self.word_embeddings = word_embeddingsself.encoder = encoderself.hidden2tag = torch.nn.Linear(in_features=encoder.get_output_dim(),out_features=vocab.get_vocab_size('labels'))self.accuracy = CategoricalAccuracy()def forward(self,sentence: Dict[str, torch.Tensor],labels: torch.Tensor = None) -> Dict[str, torch.Tensor]:mask = get_text_field_mask(sentence)embeddings = self.word_embeddings(sentence)encoder_out = self.encoder(embeddings, mask)tag_logits = self.hidden2tag(encoder_out)output = {"tag_logits": tag_logits}if labels is not None:self.accuracy(tag_logits, labels, mask)output["loss"] = sequence_cross_entropy_with_logits(tag_logits, labels, mask)return outputdef get_metrics(self, reset: bool = False) -> Dict[str, float]:return {"accuracy": self.accuracy.get_metric(reset)}
  • 模型构建中Model基类实际上就是PyTorch中的torch.nn.Module的子类,所以如何实现基本取决于使用者。关键还是其中的前向传播函数forward。这里还有一个初始化函数,和一个获取评测指标的get_metrics函数。模型定义包含一个embedding层和一个Seq2Seq的encoder层,最后用一个torch.nn.Linear单层网络输出(输出的应该是一个label大小的向量),同时输入的还有单词表。

训练、测试模型

reader = PosDatasetReader()
train_dataset = reader.read(cached_path('https://raw.githubusercontent.com/allenai/allennlp''/master/tutorials/tagger/training.txt'))
validation_dataset = reader.read(cached_path('https://raw.githubusercontent.com/allenai/allennlp''/master/tutorials/tagger/validation.txt'))
vocab = Vocabulary.from_instances(train_dataset + validation_dataset)
EMBEDDING_DIM = 6
HIDDEN_DIM = 6
token_embedding = Embedding(num_embeddings=vocab.get_vocab_size('tokens'),embedding_dim=EMBEDDING_DIM)
word_embeddings = BasicTextFieldEmbedder({"tokens": token_embedding})
lstm = PytorchSeq2SeqWrapper(torch.nn.LSTM(EMBEDDING_DIM, HIDDEN_DIM, batch_first=True))
model = LstmTagger(word_embeddings, lstm, vocab)
if torch.cuda.is_available():cuda_device = 0model = model.cuda(cuda_device)
else:cuda_device = -1
optimizer = optim.SGD(model.parameters(), lr=0.1)
iterator = BucketIterator(batch_size=2, sorting_keys=[("sentence", "num_tokens")])
iterator.index_with(vocab)
trainer = Trainer(model=model,optimizer=optimizer,iterator=iterator,train_dataset=train_dataset,validation_dataset=validation_dataset,patience=10,num_epochs=1000,cuda_device=cuda_device)
trainer.train()
predictor = SentenceTaggerPredictor(model, dataset_reader=reader)
tag_logits = predictor.predict("The dog ate the apple")['tag_logits']
tag_ids = np.argmax(tag_logits, axis=-1)
print([model.vocab.get_token_from_index(i, 'labels') for i in tag_ids])
# Here's how to save the model.
with open("/tmp/model.th", 'wb') as f:torch.save(model.state_dict(), f)
vocab.save_to_files("/tmp/vocabulary")
# And here's how to reload the model.
vocab2 = Vocabulary.from_files("/tmp/vocabulary")
model2 = LstmTagger(word_embeddings, lstm, vocab2)
with open("/tmp/model.th", 'rb') as f:model2.load_state_dict(torch.load(f))
if cuda_device > -1:model2.cuda(cuda_device)
predictor2 = SentenceTaggerPredictor(model2, dataset_reader=reader)
tag_logits2 = predictor2.predict("The dog ate the apple")['tag_logits']
np.testing.assert_array_almost_equal(tag_logits2, tag_logits)
  • 实例化DatasetReader,读取训练集和验证集的数据(这个网址好像要科学上网,所以直接下载下来本地调用就是了,改掉cached_path中的路径),生成单词表;
  • 实例化模型model,包括构建词嵌入,还用一个类包装了一下;
  • 实例化训练器trainer,训练,实例化预测器predictor,预测。
  • 保存模型,用PyTorch的方法,保存单词表,重新加载模型和单词表,设置GPU训练

更详细的教程

更为详细的教程在官方文档中:https://allenai.github.io/allennlp-docs/
目前就是AllenNLP的一个概览,可以看到,整个流程的两个关键就是数据读取和自定义模型,就是实现两个基类allennlp.data.dataset_readers.DatasetReaderallennlp.models.Model
后续再根据详细教程分析。
BTW, AllenNLP还有一种基于Jsonnet文件格式定义模型,用命令行直接运行的方式,后续再看吧。

AllenNLP入门笔记(一)相关推荐

  1. vue router 入门笔记

    vue router 入门笔记 tips: components优先级大于component,即当一个route对象里同时配置了component和components时component视为无效 即 ...

  2. 十年公务员转行IT,自学AI三年,他淬炼出746页机器学习入门笔记

    整理 | Jane 编辑 | Just 出品 | AI科技大本营(ID:rgznai100) 近期,梁劲传来该笔记重大更新的消息.<机器学习--从入门到放弃>这本笔记的更新没有停止,在基于 ...

  3. html缩进快捷键_HTML 入门笔记

    HTML 入门笔记 HTML (HyperText Markup Language) 不是一门编程语言,而是一种用来告知浏览器如何组织页面的标记语言. HTML 可复杂.可简单,一切取决于开发者. 它 ...

  4. Python3入门笔记(1) —— windows安装与运行

    Python3入门笔记(1) -- windows安装与运行 Python的设计哲学是"优雅"."明确"."简单".这也是我喜欢Python ...

  5. [Java入门笔记] 面向对象编程基础(二):方法详解

    2019独角兽企业重金招聘Python工程师标准>>> 什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能 ...

  6. React.js入门笔记

    # React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...

  7. python3入门与进阶笔记_我的Python3萌新入门笔记

    Python3萌新入门笔记是一系列真实的自学笔记. 当然,它也是比较全面的入门教程,共包括54篇笔记. 从第一篇笔记开始,大半年的时间我都是在自学和组织教程内容. 我觉得有必要,把我自己的学习过程和大 ...

  8. MySql入门笔记二~悲催的用户

    这些是当年小弟的MySql学习笔记,木有多么复杂的结构操作,木有多炫丽的语句开发,木有...总之就是木有什么技术含量... 日复一日,彪悍的人生伴随着彪悍的健忘,运维操作为王,好记性不如烂笔头,山水有 ...

  9. 2接口详解_TS入门笔记2——TS接口进阶详解

    TS入门笔记--TS接口进阶详解 一.为什么需要接口? let obj:object; // 定义了一个只能保存对象的变量 // obj = 1; // obj = "123"; ...

  10. 深度学习入门笔记系列(三)——感知器模型和 tensorboard 的使用方法

    本系列将分为 8 篇 .今天是第三篇 .主要讲讲感知器模型和 tensorboard 的基本使用方法 . 1. 感知器模型 因为小詹之前写过一篇感知器模型的介绍 ,这里就不赘述了 .有需要巩固的点击如 ...

最新文章

  1. python调用nacos账号密码,Python脚本,使用私钥(如果可用)或用户名密码
  2. 启明云端分享| 2.4寸磁编码旋钮屏
  3. 提取图片名称 c 语言,【图片】给词法元素分析提取的程序跪了【c语言吧】_百度贴吧...
  4. ASM元数据备份与恢复:md_backup和md_restore
  5. java B2B2C Springcloud多租户电子商城系统-Spring Cloud Sleuth
  6. 计算机网络实验1线缆制作,计算机网络技术实验报告1双绞线的制作
  7. shell脚本不换行刷新数据
  8. CentOS下NTP安装配置
  9. ios3怎么取消长按弹出菜单_针对数码打印机中叠印怎么处理
  10. 【缺陷检测】基于区域生长算法实现对焊接孔隙检测matlab源码
  11. PHP BC 函数
  12. ethz-asl Hand-Eye-Calibration 实验之hand_eye_calibration_batch_estimation模块
  13. gcc ld链接脚语法简明讲解
  14. missing external certificate的解决方案
  15. json解析天气预报java_JAVA操作json实战--获得天气预报信息
  16. CORBA 简单了解和JAVA与C++互操以及C++调用Java web service
  17. POJ - 3069 Saruman's Army 萨鲁曼的大军 贪心 重庆一中高2018级竞赛班第三次测试 2016.7.24 Problem 2
  18. “hulu客厅”开放,Spark培训计划报名啦
  19. qfn封装怎么焊接_qfn封装焊接教程
  20. 脉冲当量与电子齿轮比疑惑

热门文章

  1. html中字体 楷体_css怎么设置字体为楷体?
  2. arcmap 10.2 shp合并
  3. java 程序员职业规划,详细说明
  4. Python爬取携程和同程的景点评论并实现词云
  5. Remote Desktop Connection Manager (RDCMan) 介绍
  6. matlab的开方算法_常见算法的MATLAB实现
  7. c语言补码取反后什么意思,补码为什么取反加一
  8. 前端常见的安全问题及防范措施
  9. GMS 地下水数值模拟
  10. PS-elevenday-仿制图章工具组