使用TorchText处理我们自己的数据集
作者:互联网
TorchText可以读取三种数据格式:json, tsv (tab separated values 制表分隔值)和csv(comma separated values 逗号分隔值)。
处理JSON数据
从json开始,你的数据必须是json行格式,也就是说,它必须是这样的:
{"name": "John", "location": "United Kingdom", "age": 42, "quote": ["i", "love", "the", "united kingdom"]}
{"name": "Mary", "location": "United States", "age": 36, "quote": ["i", "want", "more", "telescopes"]}
也就是说,每一行都是一个json对象。data/trian.json为例。
然后我们定义字段:
from torchtext import data
from torchtext import datasets
NAME = data.Field()
SAYING = data.Field()
PLACE = data.Field()
接下来,我们必须告诉TorchText哪个字段应用于json对象的哪个元素。
对于json数据,我们必须创建一个字典:
- 键与json对象的键匹配
- 值为元组,其中:
- 第一个元素成为batch对象的属性名
- 第二个元素是字段的名称
一些注意事项:
- fields字典中键的顺序并不重要,只要它的键与json数据键匹配即可。
- 字段名不必与json对象中的键匹配,例如,我们使用PLACE来表示“location”字段。
- 当处理json数据时,并不是所有的键都必须使用,例如,我们没有使用“age”字段。
- 同样,如果json字段的值是一个字符串,那么将应用字段标记化(默认情况下是将字符串按空格分隔),然而,如果值是一个列表,则不应用标记化。通常情况下,将数据标记为一个列表是一个好主意,这节省了时间,因为您不必等待TorchText来做这件事。
- json字段的值不必是相同的类型。有些例子的“引号”可以是字符串,有些则是列表。标记化将只应用于那些以“引号”表示字符串的字符串。
- 如果你正在使用一个json字段,每个例子必须有一个该字段的实例,例如在这个例子中所有的例子必须有一个name,location和quote。但是,由于我们没有使用age字段,因此示例中没有age字段也没有关系。
fields = {'name': ('n', NAME), 'location': ('p', PLACE), 'quote': ('s', SAYING)}
现在,在训练循环中,我们可以通过数据迭代器进行迭代并且通过batch.n访问name,通过batch.p访问location,通过batch.s访问quote。
然后我们使用TabularDataset.splits函数创建我们的数据集(train_data和test_data)
path参数指定两个数据集中共同的顶级文件夹,train和test参数指定每个数据集的文件名,例如,这里的train数据集位于data/train.json。
我们告诉函数我们正在使用json数据,并将前面定义的fields字典传递给它。
train_data, test_data = data.TabularDataset.splits(
path = 'data',
train = 'train.json',
test = 'test.json',
format = 'json',
fields = fields
)
如果已经有验证数据集,则可以将其路径作为validation 参数传递。
train_data, valid_data, test_data = data.TabularDataset.splits(
path = 'data',
train = 'train.json',
validation = 'valid.json',
test = 'test.json',
format = 'json',
fields = fields
)
然后,我们可以查看一个示例,以确保它已经正确地工作。
请注意字段名(n、p和s)是如何与fields字典中定义的内容匹配的。
还请注意p中的单词“United Kingdom”是如何被标记化分开的,而s中的“United Kingdom”则没有。这是由于前面提到的原因,TorchText假设任何作为列表的json字段都已经被标记化了,并且不再应用进一步的标记化。
print(vars(train_data[0]))
{'n': ['John'], 'p': ['United', 'Kingdom'], 's': ['i', 'love', 'the', 'united kingdom']}
现在我们可以使用train_data、test_data和valid_data来构建词汇表并创建迭代器。我们可以使用batch.n, batch.p and batch.s访问分别表示names、places和sayings的所有属性。
处理CSV/TSV数据
csv和tsv非常相似,只是csv的元素用逗号分隔,而tsv用制表符分隔。
用上面的例子,我们的tsv数据将会是:
name location age quote
John United Kingdom 42 i love the united kingdom
Mary United States 36 i want more telescopes
也就是说,每一行的元素都由制表符分隔,每行有一个示例。第一行通常是标题(即每个列的名称),但你的数据也可能没有标题。
tsv或csv数据中不能有列表。
字段的定义方式与json稍有不同。现在我们使用一个元组列表,其中每个元素也是一个元组。这些内部元组的第一个元素将成为batch对象的属性名,第二个元素是字段名。
与json数据不同,元组必须与tsv数据中的顺序相同。因此,当跳过一列数据时,需要使用一个none元组,如果没有,那么我们的SAYING字段将应用到tsv数据的age列,而quote列将不会被使用。
但是,如果您只想使用name和age列,您可以只使用两个元组,因为它们是前两个列。
我们更改TabularDataset以读取正确的.tsv文件,并将format参数更改为’tsv’。
如果你的数据有一个标题头,我们的数据就有,它必须通过传递skip_header = True来跳过。如果没有,TorchText会认为头部是一个例子。默认情况下,skip_header为False。
fields = [('n', NAME), ('p', PLACE), (None, None), ('s', SAYING)]
train_data, valid_data, test_data = data.TabularDataset.splits(
path = 'data',
train = 'train.tsv',
validation = 'valid.tsv',
test = 'test.tsv',
format = 'tsv',
fields = fields,
skip_header = True
)
print(vars(train_data[0]))
{'n': ['John'], 'p': ['United', 'Kingdom'], 's': ['i', 'love', 'the', 'united', 'kingdom']}
最后,我们将讨论csv文件。
这与tsv文件几乎完全相同,只是格式参数设置为“csv”。
fields = [('n', NAME), ('p', PLACE), (None, None), ('s', SAYING)]
train_data, valid_data, test_data = data.TabularDataset.splits(
path = 'data',
train = 'train.csv',
validation = 'valid.csv',
test = 'test.csv',
format = 'csv',
fields = fields,
skip_header = True
)
print(vars(train_data[0]))
{'n': ['John'], 'p': ['United', 'Kingdom'], 's': ['i', 'love', 'the', 'united', 'kingdom']}
为什么JSON好于CSV/TSV?
- csv或tsv数据无法存储列表。这意味着数据不能被标记化,因此每次运行通过TorchText读取数据的Python脚本时,数据都必须被标记化。使用高级的标记器,如spaCy标记器,需要不可忽略的大量时间。因此,最好是对数据集进行标记并以json行格式存储它们。
- 如果tsv数据中出现制表符,或csv数据中出现逗号,TorchText会认为它们是列之间的分隔符。这将导致数据被错误地解析。最糟糕的是,TorchText不会提醒你这一点,因为它无法分辨字段中的制表符/逗号和作为分隔符的制表符/逗号之间的区别。由于json数据本质上是一个字典,您可以通过它的键访问字段中的数据,所以不必担心“surprise”分隔符。
迭代器
使用上面的任何数据集,我们就可以构建词汇表并创建迭代器。
NAME.build_vocab(train_data)
SAYING.build_vocab(train_data)
PLACE.build_vocab(train_data)
然后,我们可以在定义批处理大小和设备后,创建迭代器。
默认情况下,训练数据在每个epoch进行洗牌,但验证/测试数据是排序的。然而,TorchText不知道该用什么来排序我们的数据,如果我们不告诉它,它就会抛出错误。
有两种方法来处理这个问题,你可以通过传递sort = False来告诉迭代器不要对验证/测试数据进行排序,或者你可以通过传递sort_key来告诉迭代器如何对数据进行排序。sort key是一个函数,它返回一个用于对数据进行排序的键。例如,lambda x: x.s将根据它们的s属性(即它们的quote)对示例进行排序。理想情况下,您希望使用sort key,因为BucketIterator将能够对示例进行排序,然后最小化每个批处理中的填充量。
然后,我们可以遍历迭代器来获得批量数据。注意,默认情况下TorchText的批处理维度是在第二维。
import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
BATCH_SIZE = 1
train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
(train_data, valid_data, test_data),
sort = False, #don't sort test/validation data
batch_size=BATCH_SIZE,
device=device)
train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
(train_data, valid_data, test_data),
sort_key = lambda x: x.s, #sort by s attribute (quote)
batch_size=BATCH_SIZE,
device=device)
print('Train:')
for batch in train_iterator:
print(batch)
print('Valid:')
for batch in valid_iterator:
print(batch)
print('Test:')
for batch in test_iterator:
print(batch)
Train:
[torchtext.data.batch.Batch of size 1]
[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.p]:[torch.cuda.LongTensor of size 2x1 (GPU 0)]
[.s]:[torch.cuda.LongTensor of size 5x1 (GPU 0)]
[torchtext.data.batch.Batch of size 1]
[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.p]:[torch.cuda.LongTensor of size 2x1 (GPU 0)]
[.s]:[torch.cuda.LongTensor of size 4x1 (GPU 0)]
Valid:
[torchtext.data.batch.Batch of size 1]
[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.p]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.s]:[torch.cuda.LongTensor of size 2x1 (GPU 0)]
[torchtext.data.batch.Batch of size 1]
[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.p]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.s]:[torch.cuda.LongTensor of size 4x1 (GPU 0)]
Test:
[torchtext.data.batch.Batch of size 1]
[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.p]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.s]:[torch.cuda.LongTensor of size 3x1 (GPU 0)]
[torchtext.data.batch.Batch of size 1]
[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
[.p]:[torch.cuda.LongTensor of size 2x1 (GPU 0)]
[.s]:[torch.cuda.LongTensor of size 3x1 (GPU 0)]
标签:处理,数据,torch,json,batch,TorchText,train,data,size 来源: https://blog.csdn.net/weixin_40605573/article/details/113191026