文章目录
Using TorchText with Your Own Datasets
之前都是用的IMDB数据集,他是TorchText自带的。TorchText还有其他的数据集,包括分类,语言模型,是否是连续句子等等
然而大部分时间使用自己的数据,TorchText会帮你
一般步骤:
定义Fields
加载数据集
created the splits
TorchText可以读取3种格式的数据,json,tsv(用tab隔开的数据),csv(用逗号隔开)
作者的观点,最好的TorchText最好的格式是json,稍后解释
1.读取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"]}
定义fields
from torchtext import data
from torchtext import datasets
NAME = data.Field()
SAYING = data.Field()
PLACE = data.Field()
接下来要告诉TorchText,哪个field应用到json中的哪个元素
对于json数据,我们要创建一个字典,其中:
字典的键key,对应json对象中的key
字典的值value,是一个元组:其中元组的第一个元素是batch对象的属性名,第二个元素是Field的名称
fields = {'name': ('n', NAME), 'location': ('p', PLACE), 'quote': ('s', SAYING)}
注意点:
1.fields字典中的key的顺序无所谓,只要字典中的key对应上json数据中的key就行
2.Field名称不需要与json对象中的key的名称对应,例如我们用PLACE来对应location
3.处理json数据,并不是所有的keys都会被使用,例如,我们没有用age filed
4.如果json filed的值是字符串,那么Fields的tokenization 就会被应用(默认是根据空格分词),然而如果值是list列表,就不会tokenization。通常最好是先自己进行分词,分词成列表后在传入field,这样就不用等TorchText来处理
5.json fields 的值不一定要同一种格式,有些样本可以用“quote” 作为字符串,有些则是列表。tokenization只会应用于“quote’”作为字符串的
6.如果使用json field,样本必须有field的实例,在这个例子中,所有的元素都必须有name,location,和quote。 然而我们不使用age field,就无所谓是否有一个样本没有age field了
现在,在训练循环中,我们可以在data iterator上进行迭代,来通过batch.n
来获取name,通过batch.p
获取location,通过batch.s
来获取quote
2.创建数据集
接着我们使用 TabularDataset.splits
函数来创建数据集(text_data和train_data)
path 属性是明确数据文件夹所在的位置,train,和text指定其文件名,下面的例子中,训练集存储在 data/train.json这个位置
train_data, test_data = data.TabularDataset.splits(
path = 'data',
train = 'train.json',
test = 'test.json',
format = 'json',
fields = fields
)
如果已经有验证集
train_data, valid_data, test_data = data.TabularDataset.splits(
path = 'data',
train = 'train.json',
validation = 'valid.json', #验证集
test = 'test.json',
format = 'json',
fields = fields
)
查看一个样本
print(vars(train_data[0]))
{‘n’: [‘John’], ‘p’: [‘United’, ‘Kingdom’], ‘s’: [‘i’, ‘love’, ‘the’, ‘united kingdom’]}
注意到p中的"United Kingdom"是被分词了的,而s中的"United Kingdom"还保持原样,因为就像上面所说的,TorchText会对所有的json fields进行分词,除非它原本就是list格式
接下来就可以用train_data, test_data 和 valid_data 构建词汇表和迭代器了,就像之前的notebook一样。
3.读取TSV 文件
tsv和 csv格式很像,有如下样本
name location age quote
John United Kingdom 42 i love the united kingdom
Mary United States 36 i want more telescopes
第一行是header,也就是每一列的名称,在tsv和csv文件中,不能有list
创建fileds的方法跟json的不一样。我们现在使用的是由元组组成的列表,每个元组又是一个元组,
内部元组的第一个元素是batch对象的属性名,第二个元素是Field 名
fields = [('n', NAME), ('p', PLACE), (None, None), ('s', SAYING)]
并不像json数据,这个元组的数据顺序必须和原始文件里的列的顺序一致。当不用某列数据时,我们要用None,None来跳过那一列,
如果只用name,和locaton这两个属性,你只要设置前两个field元组就好,后面的不用设置为None,忽略即可
我们使用TabularDataset来读取tsv文件
train_data, valid_data, test_data = data.TabularDataset.splits(
path = 'data',
train = 'train.tsv',
validation = 'valid.tsv',
test = 'test.tsv',
format = 'tsv', #这里设置csv还是tsv
fields = fields, # 上面设置好了的
skip_header = True # 如果传入的数据有表头(属性名),必须设置为True,要不然会把第一行当样本
)
展示第一个样本
print(vars(train_data[0]))
4.读取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]))
5.为什么JSON比CSV、TSV更好
csv和tsv不能存储lists,这意味着数据之前没被tokenized, 因此每一次运行脚本,通过TorchText读取数据,就要进行一次分词操作。
会花很多时间,因此,最好是先对数据集进行分词,然后将其储存在json格式中
TorchText会误认为tsv数据中的tab和csv中的都好是分列符号,会导致不必要的问题。
6. 构建迭代器
构建词汇表
NAME.build_vocab(train_data)
SAYING.build_vocab(train_data)
PLACE.build_vocab(train_data)
构建迭代器
默认的,train data会在每轮epoch进行洗牌,但训练集和验证集是按顺序排列的。然而TorchText不知道如何进行排列,如果不设置的话会报错。
有两种方法来处理,
第一种:告诉迭代器不对验证集和测试集进行排序,传入sort = False即可
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)
第二种,传入sort_key告诉迭代器如何排序,例如 sort_key = lambda x: x.s, 就是告诉迭代器,按照s,也就是quote进行排序
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_key = lambda x: x.s, #sort by s attribute (quote)
batch_size=BATCH_SIZE,
device=device