代码以及注释
'''数据预处理'''
import torch
# 导入自带数据集
from torchtext.legacy import data
# 设置随机种子数
SEED = 1234
# 设置随机种子,保证可重复
torch.manual_seed(SEED)
#为GPU设置随机种子(来自知乎)
torch.cuda.manual_seed(SEED)
# 在程序刚开始加这条语句可以提升一点训练速度,没什么额外开销。
torch.backends.cudnn.deterministic = True
# 读取数据和标签
TEXT = data.Field(tokenize='spacy', tokenizer_language='en_core_web_sm')
LABEL = data.LabelField(dtype=torch.float)
# 首先,我们要创建两个Field 对象:这两个对象包含了我们打算如何预处理文本数据的信息
# 数据集格式为pos和neg两个文件夹,每个文件夹中含若干个txt文档(自带数据集)
# tokenize传入一个函数,表示如何将文本str变成token
# tokenizer_language告诉torchtext使用那个spaCy模型
# spaCy:英语分词器,类似于NLTK库,如果没有传递tokenize参数,则默认只是在空格上拆分字符串。
# LabelField是Field类的一个特殊子集,专门用于定义,处理标签
# 读取数据
from torchtext.legacy import datasets
# 切分数据集
train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)
# 代码会自动下载IMDb数据集,将数据集下载后放在数据集路径效果相同
# 然后分成train/test两个torchtext.datasets类别,数据被前面的Fields处理,即划分内容和标签
# IMDb数据集一共有50000电影评论,每个评论都被标注为正面的或负面的
# 查看训练集和测试集的大小
print(f'Number of training examoles: {len(train_data)}')
print(f'Number of testing examples: {len(test_data)}')
# 查看示例数据中一个example,其中label告诉我们当前评论标签
print(vars(train_data.examples[0]))
# 如果print(train_data.examples[0])只是打印这个对象所在的地址,这不是我们需要的
# 一种简单的方法是使用vars(),将对象的引用值打印
# 划分验证集
import random
train_data, valid_data = train_data.split(split_ratio=0.8, random_state=random.seed(SEED))
# IMDb数据集划分了训练集和测试集,这里还需要创建一个验证集,可以使用.split()方法来做
# 默认情况按7:3划分训练集和验证集,可以通过设置split_ratio参数来设置训练集和验证集的比例
# 这里split_ratio=0.8表示80%构成训练集,20%构成验证集
# 将之前设置的随机种子传给random_state参数,确保每次得到相同的训练集和验证集
# 分别查看训练集,验证集,测试集有多少数据
print(f'Number of training examples: {len(train_data)}')
print(f'Number of validation examples: {len(valid_data)}')
print(f'Number of testing examples: {len(test_data)}')
# 构建词汇表,只保留最常见的max_size标记
MAX_VOCAB_SIZE = 25000
TEXT.build_vocab(train_data, max_size=MAX_VOCAB_SIZE)
LABEL.build_vocab(train_data)
# 词汇表是一个查找表,其中数据集中的每个单词都有唯一对应的index(整数)
# 这样做的原因是模型不能对字符串进行操作,只能对数字进行操作
# 每个index用于为每个词构建一个one_hot向量,即index(序号)对应one_hot向量的相应位置为1,其他位置为0
# 在训练集中不同的单词数超过1000000,这意味着one_hot向量的维数超过1000000维
# 这将导致训练时间过长,甚至不适合在本地运行
# 两种优化方法优化one-hot向量,一是只取前n个出现次数最多的单词作为one-hot向量的基
# 二是忽略出现次数小于m的单词,本例使用第一种方法,使用最常见的25000个单词作为one_hot编码
# 这会导致出现一个问题,有些单词在数据集中出现了,但是无法用one_hot直接编码,这里用<unk>来编码它们
# 为什么只在训练集上建立词汇表,因为不能以任何方式影响测试集和验证集
# 查看词汇表维度以及标签集维度
print(f'Unique tokens in TEXT vocabulary: {len(TEXT.vocab)}')
print(f'Unique tokens in LABEL vocabulary: {len(LABEL.vocab)}')
# 词典大小为25002是因为额外的两个token是<unk>和<pad>
# 将句子输入模型时,一次输入一个batch,并且批次中所有的句子都需要有相同的长度
# 按照每个bs中最长的句子pad,填充部分设置为0
# 查看词汇表中最常见的单词以及他们在数据集中出现的次数
print(TEXT.vocab.freqs.most_com