前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LineFlow:PyTorch或任何框架的简单NLP数据集处理程序

LineFlow:PyTorch或任何框架的简单NLP数据集处理程序

作者头像
代码医生工作室
发布2019-08-27 15:48:53
1.1K0
发布2019-08-27 15:48:53
举报
文章被收录于专栏:相约机器人相约机器人

作者 | Yasufumi TANIGUCHI

来源 | Medium

编辑 | 代码医生团队

对于NLP任务,可能需要在预处理中标记文本或构建词汇表。可能已经体验到预处理代码与桌面一样混乱。如这就是为什么创建LineFlow来缓解痛苦!它将使“桌面”尽可能干净。真正的代码如何?看看下图。预处理包括标记化,构建词汇表和索引。

https://github.com/tofunlp/lineflow

左边部分是来自PyTorch官方示例存储库的示例代码,它对文本数据进行常见的预处理。右边部分用LineFlow编写,以实现完全相同的处理。了解LineFlow如何减轻痛苦。可以从此链接查看完整代码。

https://gist.github.com/yasufumy/ba73b587bd3c516b66fb94b3a90bac71

在这篇文章中,将详细解释右边的代码并展示 LineFlow 的用法。开始一个干净的“桌面”生活!

1.加载文本数据

加载文本数据由上面代码的第8行完成。稍后会解释一下这张地图。lf.TextDataset 将文本文件的路径作为参数并加载它。

代码语言:javascript
复制
dataset = lf.TextDataset(path, encoding='utf-8').map(...)

lf.TextDataset 期望的数据格式是每行对应于一个数据。如果文本数据满足此条件,则可以加载任何类型的文本数据。

加载后,它将文本数据转换为列表。列表中的项目对应于文本数据中的行。请看下图。这是直观的形象 lf.TextDataset。该d图中表示dataset的代码。

LineFlow已经提供了一些公开可用的数据集。所以可以立即使用它。可以在此处查看提供的数据集。

https://github.com/tofunlp/lineflow#datasets

2.标记化

文本标记化也由第8行完成。map将作为参数传递的处理应用于文本数据的每一行。

代码语言:javascript
复制
dataset = lf.TextDataset(...).map(lambda x: x.split() + ['<eos>'])

请看下图。这是直观的形象 lf.TextDataset.map。该d图中表示 dataset 的代码。

深入了解下面的实际处理。

代码语言:javascript
复制
lambda x: x.split() + ['<eos>']

在这里,将文本数据中的每一行用空格分割为标记,然后添加<eos>到这些标记的末尾。按照WikiText官方页面中的处理方式进行操作。

在这个时候,str.split 用于标记化。可以使用其他标记化方法,如 spaCy,StanfordNLP 和 Bling Fire 等。例如如果想使用 Bling Fire ,将获得以下代码。

代码语言:javascript
复制
from blingfire import text_to_words
d = lf.TextDataset('/path/to/your/text')
d.map(text_to_words).map(str.split)

此外,只要处理将每行文本数据作为参数,就可以进行任何想要的处理。例如,可以计算令牌的数量。在以下代码中,标记的数量在第二个元素中定义。

代码语言:javascript
复制
d = lf.TextDataset('/path/to/text')
d.map(tokenize).map(lambda x: (x, len(x)))

当想要为注意机制或LSTM制作掩码时,这个处理很有用。

3.索引

索引从第9行到第12行完成。这些行如下图所示。在这个代码块中,构建了词汇表和索引。按顺序看看这些。

代码语言:javascript
复制
for word in dataset.flat_map(lambda x: x):
    self.dictionary.add_word(word)
return torch.LongTensor(dataset.flat_map(...))

首先,将看到构建词汇表的障碍。在下面的代码块中,构建了词汇表。flat_map 将作为参数传递的处理应用于数据中的每一行,然后将其展平。所以将获得个人令牌

代码语言:javascript
复制
dataset.flat_map(lambda x: x)。
for word in dataset.flat_map(lambda x: x):
self.dictionary.add_word(word)

请看下图。这是直观的形象dataset.flat_map(lambda x: x)。该d图中表示dataset的代码。

flat_map 有点令人困惑,但它等于以下代码。

代码语言:javascript
复制
from itertools import chain
chain.from_iterable(map(lambda x: x, dataset))


dataset.flat_map(lambda x: x) # same as above

通过使用提取每个标记后 flat_map,传递 self.dictionary.add_word 构建词汇表的标记。

代码语言:javascript
复制
self.dictionary.add_word(word)

接下来,将看到索引的代码块。索引由以下块完成。在这里还使用flat_map索引每个标记并展平它。这是因为PyTorch的例子需要扁平标记的张量。

代码语言:javascript
复制
dataset.flat_map(
    [lambda x: self.dictionary.word2idx[token] for token in x)])

请看下图。这是直观的形象 dataset.flat_map(indexer)。该 d 图中表示 dataset 的代码。

此代码等于以下代码。

代码语言:javascript
复制
from itertools import chain
chain.from_iterable(map(indexer, dataset))
 
dataset.flat_map(indexer) # same as above

最后,将其包装torch.LongTensor以使其tensor。完成了加载文本数据。

代码语言:javascript
复制
return torch.LongTensor(dataset.flat_map(...))

可以查看到目前为止已经看到的完整代码。

代码语言:javascript
复制
import os
import torch
import lineflow as lf
 
class Dictionary(object):
    def __init__(self):
        self.word2idx = {}
        self.idx2word = []
 
    def add_word(self, word):
        if word not in self.word2idx:
            self.idx2word.append(word)
            self.word2idx[word] = len(self.idx2word) - 1
        return self.word2idx[word]
 
    def __len__(self):
        return len(self.idx2word)
 
 
class Corpus(object):
    def __init__(self, path):
        self.dictionary = Dictionary()
        self.train = self.tokenize(os.path.join(path, 'train.txt'))
        self.valid = self.tokenize(os.path.join(path, 'valid.txt'))
        self.test = self.tokenize(os.path.join(path, 'test.txt'))
 
    def tokenize(self, path):
        assert os.path.exists(path)
        dataset = lf.TextDataset(path, encoding='utf-8').map(lambda x: x.split() + ['<eos>'])
        for word in dataset.flat_map(lambda x: x):
            self.dictionary.add_word(word)
        return torch.LongTensor(dataset.flat_map(
            lambda x: [self.dictionary.word2idx[token] for token in x]))

这就是解释的全部内容。LineFlow通过矢量化文本数据来完成less循环和较少嵌套的代码。可以使用Python的map完全相同。但 LineFlow 提供了可读和干净的代码,因为它构建了像管道(Fluent Interface)这样的处理。

如果喜欢LineFlow并想了解更多信息,请访问下面的存储库。

https://github.com/tofunlp/lineflow/tree/master/examples?source=post_page-----1caf7851125e----------------------

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 相约机器人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档