本文对AllenNLP中关于数据的基本概念 Fields,Instances做一个简单的介绍,同时对Dataset readers类做较为详细的介绍。

Fields 与 Instances

Fields,即字段, 是Instances的组成部分,在将字段转换为ID并进行批处理和填充后,它们会作为输入或输出转换为模型中的张量。

AllenNLP中有多种类型的字段,具体取决于它们表示的数据类型。其中,最重要的是TextFields,它代表一段分词后的文本,这个在后续章节中将会详细描述。

其他常用字段类型包括:

字段类型 含义
LabelField 分类标签
MultiLabelField 是LabelField的扩展,允许多个标签,可用于多标签分类
SequenceLabelField 序列标签,可用于词性标注
SpanField 一对表示文本范围的索引,可用于表示阅读理解,语义角色标签或共指解析的范围。
ArrayField 一个数组,表示已转换为矩阵的某些数据,例如图像和手工特征向量。

只需提供数据即可创建字段。字段对象提供了创建空白字段,统计词汇量,创建张量和批处理张量的API。示例代码如下:

from collections import Counter, defaultdictfrom allennlp.data.fields import TextField, LabelField, SequenceLabelField
from allennlp.data.token_indexers import SingleIdTokenIndexer
from allennlp.data.tokenizers import Token
from allennlp.data.vocabulary import Vocabulary# 输入token
tokens = [Token('The'), Token('best'), Token('movie'), Token('ever'), Token('!')]
token_indexers = {'tokens': SingleIdTokenIndexer()}
text_field = TextField(tokens, token_indexers=token_indexers)# 整句话的情感倾向
label_field = LabelField('pos')# 每个token的词性
sequence_label_field = SequenceLabelField(['DET', 'ADJ', 'NOUN', 'ADV', 'PUNKT'],text_field
)print(text_field)
print(label_field)
print(sequence_label_field)print(len(sequence_label_field))
print(label for label in sequence_label_field)# 如何创建空字段类型
print(text_field.empty_field())
print(label_field.empty_field())
print(sequence_label_field.empty_field())# 统计字段中的文本,形成词库
counter = defaultdict(Counter)
text_field.count_vocab_items(counter)
print(counter)label_field.count_vocab_items(counter)
print(counter)sequence_label_field.count_vocab_items(counter)
print(counter)vocab = Vocabulary(counter)# 为field建立相对于vocab的索引,从而将文本映射为tensor
text_field.index(vocab)# 获得需要填充的长度,一般是取数组中的最大长度,这里就一维,即为本身的长度
padding_lengths = text_field.get_padding_lengths()
print(text_field.as_tensor(padding_lengths))label_field.index(vocab)
print(label_field.as_tensor(label_field.get_padding_lengths()))sequence_label_field.index(vocab)
padding_lengths = sequence_label_field.get_padding_lengths()
print(sequence_label_field.as_tensor(padding_lengths))# 将两个tensor进行拼接
tensor1 = label_field.as_tensor(label_field.get_padding_lengths())label_field2 = LabelField('pos')
label_field2.index(vocab)
tensor2 = label_field2.as_tensor(label_field2.get_padding_lengths())batched_tensors = label_field.batch_tensors([tensor1, tensor2])
print(batched_tensors)

Instances,即实例,是机器学习中预测的原子单位,在allennlp中,InstancesFields的集合,而数据集则是Instances的集合。

如图所示:

可以通过将字段名称和相应字段组成成字典传递给构造函数来创建InstancesInstances知道如何将其转换为字段名称与对应张量的字典。每个字段的张量之后将组合在一起,然后传递给模型。 字段名称很重要,因为结果张量字典是按名称传递给模型的,所以它们必须与模型的forward()参数完全匹配。示例代码如下:

# 创建 Fields
tokens = [Token('The'), Token('best'), Token('movie'), Token('ever'), Token('!')]
token_indexers = {'tokens': SingleIdTokenIndexer()}
text_field = TextField(tokens, token_indexers=token_indexers)label_field = LabelField('pos')sequence_label_field = SequenceLabelField(['DET', 'ADJ', 'NOUN', 'ADV', 'PUNKT'],text_field
)# 创建 Instance
fields = {'tokens': text_field,'label': label_field,
}
instance = Instance(fields)# 为instance增加字段
instance.add_field('label_seq', sequence_label_field)# 重写类的__str__方法,所以可以通过print获得详细的信息
print(instance)# 创建vocab
counter = defaultdict(Counter)
instance.count_vocab_items(counter)
vocab = Vocabulary(counter)# 将所有文本映射成为id
instance.index_fields(vocab)# 将instance转换为tensor字典,这个方法可以指定padding_lengths,padding_lengths样例如下
# {'tokens': {'tokens___tokens': 5}, 'label': {}, 'label_seq': {'num_tokens': 5}}
tensors = instance.as_tensor_dict()
print(tensors)# 将token长度改为4
tensors_test = instance.as_tensor_dict(padding_lengths={'tokens': {'tokens___tokens': 4}, 'label': {}, 'label_seq': {'num_tokens': 5}})
print(tensors_test)

Dataset readers

DatasetReader,读数据模块,在不同文件中抽取必要的信息,在使用的时候通过重写_read 方法来实现数据集的读取,输出Instance的集合。在allennlp的项目中,已经实现了许多常用nlp任务的读取器子类,包括:文本分类,序列标注,语言模型,自然语言推理,语义角色标注,Seq2Seq任务,句法依存解析,阅读理解,语义解析。示例如下:

# 最好也重写text_to_instance方法,让训练与预测可以共享逻辑
@DatasetReader.register('classification-tsv')
class ClassificationTsvReader(DatasetReader):def __init__(self,tokenizer: Tokenizer = None,token_indexers: Dict[str, TokenIndexer] = None,max_tokens: int = None,**kwargs):super().__init__(**kwargs)self.tokenizer = tokenizer or WhitespaceTokenizer()self.token_indexers = token_indexers or {'tokens': SingleIdTokenIndexer()}self.max_tokens = max_tokensdef text_to_instance(self, text: str, label: str = None) -> Instance:tokens = self.tokenizer.tokenize(text)if self.max_tokens:tokens = tokens[:self.max_tokens]text_field = TextField(tokens, self.token_indexers)fields = {'text': text_field}if label:fields['label'] = LabelField(label)return Instance(fields)def _read(self, file_path: str) -> Iterable[Instance]:with open(file_path, 'r') as lines:for line in lines:text, sentiment = line.strip().split('\t')yield self.text_to_instance(text, sentiment)# 初始化类并读取文件路径
reader = ClassificationTsvReader()
dataset = reader.read('quick_start/data/movie_review/train.tsv')# 返回instance的集合
print('type of dataset: ', type(dataset))
print('type of its first element: ', type(dataset[0]))
print('size of dataset: ', len(dataset))

DatasetReader有两个容易混淆的方法_read()read()_read()被定义为抽象方法,在为数据集构建DatasetReader子类时,必须重写并实现自己的方法。 read()是数据集读取器的客户端调用的主要方法。它实现了额外的功能,例如缓存和延迟加载,并在内部调用_read()。两种方法都返回一个可迭代的Instances

主要方法read()以文件名作为参数。这会将DatasetReader的参数化(发生在构造函数中)与读取器所应用的数据解耦。这样,就可以将单个DatasetReader应用于所需的任何文件,而不必重复参数。

数据集读取器旨在从本地文件读取数据,尽管在某些情况下,您可能希望从URL读取数据。allennlp提供了一种称为cached_path的实用方法来支持此功能。如果将URL传递给该方法,它将把资源下载到本地文件并返回其路径。如果希望数据集读取器支持本地路径和URL,则可以在_read()方法中使用cached_path来包装file_path,如下所示:

from allennlp.common.file_utils import cached_path...def _read(self, file_path: str) -> Iterable[Instance]:with open(cached_path(file_path), 'r') as lines:for line in lines:

懒惰模式

数据集读取器还支持以惰性方式读取数据,其中DatasetReader根据需要产生Instances,而不是一次返回所有Instances的列表。 当数据集太大而无法放入内存时,或者需要立即开始训练模型时,这种模式将很方便。 如果希望每个epoch的有不同的表现,也可以使用惰性模式,例如,给数据进行某种采样。

lazy = True传递给数据集读取器的构造函数时,其read()方法将返回AllennlpLazyDataset的对象(正常返回AllennlpDataset的对象),该对象是内部调用_read()的迭代器的包装。调用如下:

from itertools import islice
from typing import Dict, Iterable
from allennlp.data import DatasetReader, Instance
from allennlp.data.fields import LabelField, TextField
from allennlp.data.token_indexers import TokenIndexer, SingleIdTokenIndexer
from allennlp.data.tokenizers import Token, Tokenizer, WhitespaceTokenizer@DatasetReader.register('classification-tsv')
class ClassificationTsvReader(DatasetReader):def __init__(self,tokenizer: Tokenizer = None,token_indexers: Dict[str, TokenIndexer] = None,max_tokens: int = None,**kwargs):super().__init__(**kwargs)self.tokenizer = tokenizer or WhitespaceTokenizer()self.token_indexers = token_indexers or {'tokens': SingleIdTokenIndexer()}self.max_tokens = max_tokensdef text_to_instance(self, text: str, label: str = None) -> Instance:tokens = self.tokenizer.tokenize(text)if self.max_tokens:tokens = tokens[:self.max_tokens]text_field = TextField(tokens, self.token_indexers)fields = {'text': text_field}if label:fields['label'] = LabelField(label)return Instance(fields)def _read(self, file_path: str) -> Iterable[Instance]:with open(file_path, 'r') as lines:for line in lines:text, sentiment = line.strip().split('\t')yield self.text_to_instance(text, sentiment)reader = ClassificationTsvReader(lazy=True)
dataset = reader.read('../data/train.tsv')# 查看对象类型,为`AllennlpLazyDataset`
print('type of dataset: ', type(dataset))# 查看前2个instance,dataset只有第一次被call的时候会调用_read()方法
first_two = list(islice(dataset, 2))
print('first 2 instances: ', first_two)last_two = list(islice(dataset, 3, 5))
print('last 2 instances: ', last_two)

由于存在惰性模式,在写子类_read()方法的时候必须使用yield语句,不能直接返回Instance,否则惰性模式将失效。

缓存实例

读取和预处理大型数据集可能需要很长时间。 DatasetReader可以通过序列化需要创建的实例并将其写入磁盘的方式来缓存数据集。 下次请求相同文件时,将从磁盘反序列化实例,而不是从文件中创建实例。

# 初始化
reader = ClassificationTsvReader(cache_directory='dataset_cache')
dataset = reader.read('../data/train.tsv')# 检查是否建立好缓存
print(os.listdir('dataset_cache'))# 下次调用read()时,将从缓存中读取instance
dataset = reader.read('../data/train.tsv')

序列化格式如下:

{"py/object": "allennlp.data.instance.Instance", "fields": {"text": {"py/object": "allennlp.data.fields.text_field.TextField", "tokens": [{"py/object": "allennlp.data.tokenizers.token.Token", "text": "I", "idx": null, "idx_end": null, "lemma_": null, "pos_": null, "tag_": null, "dep_": null, "ent_type_": null, "text_id": null, "type_id": null}, {"py/object": "allennlp.data.tokenizers.token.Token", "text": "like", "idx": null, "idx_end": null, "lemma_": null, "pos_": null, "tag_": null, "dep_": null, "ent_type_": null, "text_id": null, "type_id": null}, {"py/object": "allennlp.data.tokenizers.token.Token", "text": "this", "idx": null, "idx_end": null, "lemma_": null, "pos_": null, "tag_": null, "dep_": null, "ent_type_": null, "text_id": null, "type_id": null}, {"py/object": "allennlp.data.tokenizers.token.Token", "text": "movie", "idx": null, "idx_end": null, "lemma_": null, "pos_": null, "tag_": null, "dep_": null, "ent_type_": null, "text_id": null, "type_id": null}, {"py/object": "allennlp.data.tokenizers.token.Token", "text": "a", "idx": null, "idx_end": null, "lemma_": null, "pos_": null, "tag_": null, "dep_": null, "ent_type_": null, "text_id": null, "type_id": null}, {"py/object": "allennlp.data.tokenizers.token.Token", "text": "lot!", "idx": null, "idx_end": null, "lemma_": null, "pos_": null, "tag_": null, "dep_": null, "ent_type_": null, "text_id": null, "type_id": null}], "_token_indexers": {"tokens": {"py/object": "allennlp.data.token_indexers.single_id_token_indexer.SingleIdTokenIndexer", "_token_min_padding_length": 0, "namespace": "tokens", "lowercase_tokens": false, "_start_tokens": [], "_end_tokens": [], "_feature_name": "text", "_default_value": "THIS IS A REALLY UNLIKELY VALUE THAT HAS TO BE A STRING"}}, "_indexed_tokens": null}, "label": {"py/object": "allennlp.data.fields.label_field.LabelField", "label": "positive", "_label_namespace": "labels", "_label_id": null, "_skip_indexing": false}}, "indexed": false}

默认情况下,Instancejsonpickle序列化,如果需要修改,可以重写DatasetReader中的serialize_instancedeserialize_instance方法。存储的对象比较大,因此,只有在预处理速度特别慢的情况下,这么干才有意义。

参考资料

  • allennlp官方文档1.2.2
  • allennlp指南

AllenNLP框架学习笔记(数据篇之一)相关推荐

  1. Vue学习笔记入门篇——数据及DOM

    本文为转载,原文:Vue学习笔记入门篇--数据及DOM 数据 data 类型 Object | Function 详细 Vue 实例的数据对象.Vue 将会递归将 data 的属性转换为 getter ...

  2. Spring Boot 框架学习笔记(二)(配置文件与数据注入 yaml基本语法 JSR303数据验证 多环境切换 )

    Spring Boot 框架学习笔记(二) 六.appliaction.properties配置与数据注入 6.1 `@Value`注解 测试注入数据 读取输入流 6.2 读取配置文件数据注入 单文件 ...

  3. JavaSE中Map框架学习笔记

    前言:最近几天都在生病,退烧之后身体虚弱.头疼.在床上躺了几天,什么事情都干不了.接下来这段时间,要好好加快进度才好. 前面用了三篇文章的篇幅学习了Collection框架的相关内容,而Map框架相对 ...

  4. PhalAPI学习笔记拓展篇 ———ADM模式中NotORM实现简单CURD

    PhalAPI学习笔记拓展篇 ---ADM模式中NotORM实现简单CURD 前言 内容 ADM模式 ADM简单介绍 准备工作 PhalAPI提供的CURD操作方法 业务实现 结束语 前言 公司业务需 ...

  5. vue-resource post php,Vue学习笔记进阶篇——vue-resource安装及使用

    简介 vue-resource是Vue.js的一款插件,它可以通过XMLHttpRequest或JSONP发起请求并处理响应.也就是说,$.ajax能做的事情,vue-resource插件一样也能做到 ...

  6. ET服务器框架学习笔记(十)

    ET服务器框架学习笔记(十) 文章目录 ET服务器框架学习笔记(十) 前言 一.ET之Service 1.Service主要数据 2.Service主要逻辑 3.Service其他逻辑 二.ET之Ne ...

  7. kratos mysql_kratos微服务框架学习笔记一(kratos-demo)

    本文将为您描述kratos微服务框架学习笔记一(kratos-demo),教程操作步骤: 目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服 ...

  8. ET6.0服务器框架学习笔记(二、一条登录协议)

    ET6.0服务器框架学习笔记(二.一条登录协议) 上一篇主要记录ET6.0的服务器启动功能,本篇主要记录ET6.0完整的一条协议,从配置到生成协议数据,到从客户端发送给服务端,再发送回客户端的流程 文 ...

  9. 27Vert.X框架学习笔记

    vert.x框架学习笔记 文章目录 1 Vert.x简明介绍 1.1 Vert.x能干什么 1.2 Vert.x快速体验 1.3 Vert.x的简单介绍 1.4 Vert.x的一些优势 1.4.1 异 ...

  10. [mmu/cache]-ARM MMU的学习笔记-一篇就够了

    ★★★ 个人博客导读首页-点击此处 ★★★ . 说明: 在默认情况下,本文讲述的都是ARMV8-aarch64架构,linux kernel 64位 . 相关文章 1.ARM cache的学习笔记-一 ...

最新文章

  1. python图表交互控件_用djang中的交互式控件制作bokeh图表
  2. R显卡VR性能如何?AMD发布 VRMark Cyan Room 测试结果
  3. 2022年全球及中国建筑隔震系统行业设施布局与十四五应用决策建议报告
  4. 数据可视化模板_10分钟,做一份数据可视化分析报表
  5. WPF in Visual Studio 2010
  6. 普通话测试系统_普通话
  7. springboot三层架构_几张图让你快速了解数据中台技术架构
  8. MySQL的基本命令
  9. 干货 | 你是不是希望一月入门深度学习,三月中一篇顶会?-- 关于做科研的态度和方法的一点感想...
  10. word手动设置编号起始值
  11. 机器学习强化(数据清洗、实战理解)
  12. 浅谈测试小白到测试大牛的成长历程(分四个境界)
  13. python报错:RuntimeError
  14. “豫”见超融合,私有云浪潮开启新一线
  15. 移动硬盘无法读取是怎么回事?
  16. Maven自动更新SNAPSHOT包
  17. 信号强度诊断(系统架构)
  18. matlab 人人,matlab pivlab
  19. 跨境电商七大模式的优势与痛点
  20. 漫画 | 哈哈哈哈哈哈哈哈…

热门文章

  1. 华为版计算机软件,Huawei华为手机PC客户端软件
  2. 语言模型(NNLM)
  3. SPFA算法(最短路径算法)
  4. python打包的exe反编译_反编译python打包的exe到源代码
  5. 计算机网络考研常见 复试题总结
  6. USB加密狗复制USBTrace数据截取工具分享
  7. fat,uat,pre等环境含义
  8. php正则表达式 w3c,正则表达式 – 匹配规则 | w3cschool菜鸟教程
  9. Navicat15 安装激活
  10. vue生产环境使用localhost请求端口号不是自己设置的?来试试这个