TorchText-DAY1
TorchText是一种处理文本的工具,它是Pytorch的一个子项目。
官方文档:https://pytorch.org/text/stable/data.html
它有以下组件:
-
torchtext.data.Field:该类用来定义字段的一些处理方法(字段包含文本字段、标签字段)
-
torchtext.data.Datasets:数据集类。根据【数据文件的路径】、【Field】生成数据集。使用__ getitem __方法得到Example实例。
-
torchtext.data.Iterator:迭代器。根据【Datasets】实例获取有 batch 的Loader。
-
torchtext.data.Example:用来表示一个样本,数据+标签。
-
torchtext.vocab.Vocab:词汇表相关。(字典)
我们训练使用的是迭代器类型的数据。
从上面这张图可以看出迭代器是由【Datasets】生成的;
Datasets是根据file path读取到data.csv中的数据,根据Field进行解析后的到的数据;
Field包含一个Vocab对象(就是词典对象);
而从Datasets中又可以抽离出一个个的样本Example;
Field组件
Field组件是TorchText的核心组件。用户可以根据该组件指定如何处理字段!,它包含一个Vocab词典对象 {词:词向量}
Field对象还包含 数据如何数字化的相关参数, 例如标记化方法(也就是分词方法)、应生成的Tensor的类型(例如:LongTensor、FloatTensor)
上面说了Field包含文本字段和标签字段,对于文本字段是序列化的、可以分词的,所以我们可以设置sequential=True、use_vocab=True(不过他们默认就是True的)。但是对于标签字段,我们并不需要分词,所以要设置sequential=False、use_vocab=False。
import torchtext
from torchtext.data import Field
tokenize = lambda x: x.split()
TEXT = Field(tokenize=tokenize)
LABEL = Field(sequential=False, use_vocab=False)
# TEXT.vocab_cls.load_vectors()
这样就创建了两个Fielter了,一个是处理序列化文本的TEXT;另一个是不分词的LABLE。tokenizer是用来对字段样本进行标记化,也就是分词的一个函数(在这里每个字段的数据是中文且分过词用空格隔开的)
从被注释掉的那句代码可以看到【Field】中是存在一个字段对象【vector】的(在源码的init方法中声明的)可以进行【load_vectors】进行加载字典。这里需注意的是:这个字典是TorchText自己写的字典,并不是gensim中的那个word2vec.wv对象!
- Field构造方法所拥有的参数(Field类所拥有的属性)
属性 | 作用 |
---|---|
tokenize | 分词函数. 默认值: str.split. |
sequential | 是否把数据表示成序列,如果是False, 不能使用分词 默认值: True. |
use_vocab | 是否使用词典对象. 如果是False 数据的类型必须已经是数值类型. 默认值: True. |
lower | 是否把数据转化为小写 默认值: False. |
tensor_type | 把数据转换成的tensor类型 默认值: torch.LongTensor. |
fix_length | 修改每条数据的长度为该值,不够的用pad_token补全. 默认值: None. |
include_lengths | 是否返回一个已经补全的最小batch的元组和和一个包含每条数据长度的列表 . 默认值: False. |
batch_first | 数据是否批量优先(就是批量是最外层的)默认值: False. |
preprocessing | 在分词之后和数值化之前使用的管道 默认值: None. |
postprocessing | 数值化之后和转化成tensor之前使用的管道默认值: None. |
init_token | 每一条数据的起始字符 默认值: None. |
eos_token | 每条数据的结尾字符 默认值: None. |
pad_token | 用于补全的字符. 默认值: “<pad>”. |
unk_token | unk_token |
pad_first | 是否补全第一个字符. 默认值: False. |
需要注意的一点是训练集的Field必须构建词表后,才能使用迭代器(否则迭代器进行迭代会报Field没有vocab属性)!!!!!!!!!!!!
TEXT.build_vocab(train)
# train为训练集,可以是Dataset类型也可以是TabularDataset类型
Vocab组件
【Vocab】组件作用是字典,它可以直接放到【Field】中作为分词直接使用,通过【fieldObj.vocab = vocab】。
词典中拥有两种存储方式:一种是字典存储,另一种是列表存储
-
列表存储:将词存入列表中,列表的索引作为词的索引。通过下标取词(可能是通过哈希表存的)
vocab.stoi['qwe'] # result:10
-
字典存储:将词存入字典中,键为词、值为列表中的词索引。通过词取列表索引
vocab.itos[10] # result:qwe
例子:
data:
news author classify
0 asdf a 1
1 qwe b 2
2 6 c 3
3 ert d 4
4 tyiu e 5
from torchtext.data import Iterator, BucketIterator
TEXT.build_vocab(train[0])
train_iter = Iterator(train[0],
batch_size=1,
device=-1,
sort=False,
sort_within_batch=False,
repeat=False)
for batch in train_iter:
print(batch, type(batch))
x = batch.news
y = batch.classify
print(x, y)
print(TEXT.vocab.itos[x])
result:
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[2]]) tensor([3])
6
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[11]]) tensor([5])
tyiu
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[9]]) tensor([4])
ert
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[4]]) tensor([1])
asdf
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[10]]) tensor([2])
qwe
这样存储的好处是:只需将词的索引存入dataset中,减小了内存使用。
Dataset组件
根据Field程序就知道怎样处理数据了,然后将Field与file path以同传入Dataset中,Field就知道处理哪里的数据了,并将处理后的数据转换成Dataset类型。
在这里注意!Field只是一个模板告诉程序怎样处理数据。我们如果传入数据对于每个字段我们都需要知道怎样处理,所以需要一个处理列表。(csv格式而言)
在这里使用【TabularDataset】,它是继承自【Dataset】的。使用它的静态方法【splits】得到数据。
方法原型:
def splits(cls, path=None, root='.data', train=None, validation=None, test=None, **kwargs)
'''
path:数据文件的前缀
root:根数据集的存储目录
train:训练数据文件名(如果不写path就必须写全路径)
validation:验证集数据文件名(如果不写path就必须写全路径)
test:测试集数据文件名(如果不写path就必须写全路径)
'''
工作原理:根据 path+[train, validation, test] 获取文件的路径,根据文件路径使用【download】读取数据,最后判断是否读取数据了,返回已读取数据的字段。
示例1:
from torchtext.data import TabularDataset
# 训练集的字段列表
trainDataFieldList = [('id', None),
('news_title', TEXT),
('author', LABLE),
('classify', LABLE)]
# 得到训练集,验证集,测试集的 Dataset
train, validation, text = TabularDataset.splits(
path=r'D:\poject\test\data',
root=".data",
train="train.csv",
validation="validation.csv",
format="csv",
skip_header=True,
fields=trainDataFieldList
)
# 测试集字段列表。因为测试集只需要数据不需要标签
testDataFieldList = [('id', None),
('news_title', TEXT)]
test = TabularDataset.splits(
path=r'D:\poject\test\data',
root=".data",
test="test.csv",
format="csv",
skip_header=True,
fields=testDataFieldList
)
示例2:
-
样本
news author classify 0 asdf a 1 1 qwe b 2 2 wer c 3 3 ert d 4 4 tyiu e 5
from torchtext.data import TabularDataset
# 训练集的字段列表
trainDataFieldList = [('id', None),
('news', TEXT),
('author', TEXT),
('classify', LABEL)]
# 得到训练集,验证集,测试集的 Dataset
train = TabularDataset.splits(
path=r'./data',
root=".data",
train="data3.csv",
format="csv",
skip_header=True,
fields=trainDataFieldList
)
# 建立一个字典 拆离字典使用:TEXT.vocab
TEXT.build_vocab(train[0])
print(train[0].__dict__.keys())
print(train[0].comment_text)
结果:
(<torchtext.data.dataset.TabularDataset object at 0x000001B521021FD0>,)
dict_keys(['examples', 'fields'])
<generator object Dataset.__getattr__ at 0x000001B520DF58E0>
Example组件
【Dataset】中的每一项是一个【Example】实例。【Example】实例就是一行,拥有每个字段的一个值构成一行。
可以从中这样获取数据:
print(train[0].examples[0].news)
result:
['asdf']
这个是没有打乱的数据,【Dataset】经过【Iterator】才会打乱!
Iterator组件
现在有了【Dataset】数据了,现在需要将数据转换成一批量一批量的迭代器才能用于训练!
from torchtext.data import Iterator, BucketIterator
train_iter = Iterator(train[0],
batch_size=1,
device=-1,
sort=False,
sort_within_batch=False,
repeat=False)
Batch组件
Iterator组件每次迭代返回的是Batch组件!
for batch in train_iter:
print(batch, type(batch))
result:
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
可以看出【batch】中的是三个字段。因为【batch_size】是1,所以每个字段中拥有一个数据;假如【batch_size】为2,那么数据的格式应该是【1*2】。
[torchtext.data.batch.Batch of size 2]
[.news]:[torch.LongTensor of size 1x2]
[.author]:[torch.LongTensor of size 1x2]
[.classify]:[torch.LongTensor of size 2] <class 'torchtext.data.batch.Batch'>
可以通过字段名取出batch中的数据,通过词典转换成词:
for batch in train_iter:
print(batch, type(batch))
x = batch.news
y = batch.classify
print(x, y)
print(TEXT.vocab.itos[x])
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[2]]) tensor([3])
6
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[11]]) tensor([5])
tyiu
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[9]]) tensor([4])
ert
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[4]]) tensor([1])
asdf
[torchtext.data.batch.Batch of size 1]
[.news]:[torch.LongTensor of size 1x1]
[.author]:[torch.LongTensor of size 1x1]
[.classify]:[torch.LongTensor of size 1] <class 'torchtext.data.batch.Batch'>
tensor([[10]]) tensor([2])
qwe
【Iterator】返回的是一个【Batch】实例,如果要进行训练需要将其中的值取出。取出的值为【tensor】类型。再进行封装即可!
class DataIterator:
def __init__(self, iterator):
self.iterator = iterator
def __iter__(self):
for batch in self.iterator:
x = batch.news
y = batch.classify
yield x, y
def __len__(self):
return len(self.iterator)
dataIterator = DataIterator(train_iter)
for x, y in dataIterator:
print(x, y)
result:
tensor([[10]]) tensor([2])
tensor([[4]]) tensor([1])
tensor([[2]]) tensor([3])
tensor([[11]]) tensor([5])
tensor([[9]]) tensor([4])
这样就可以进行训练了。说白了【torchtext】就是一个数据集构建工具,它比【torch.utils.data】中的【DataLoader, Dataset】更便捷一些,可以读取cvs等格式的数据。
这只是一个小入门,更多的操作请看官方文档!