- 导入所需要的包
import collections
import os
import random
import tarfile
import torch
from torch import nn
import torchtext.vocab as Vocab
import torch.utils.data as Data
import time
- 基本参数配置
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
DATA_ROOT = "E:\data" # 数据集所在路径
- 1、读取数据集
(1)解压数据集文件
fname = os.path.join(DATA_ROOT, 'aclImdb_v1.tar.gz')
# 将压缩文件进行解压
if not os.path.exists(os.path.join(DATA_ROOT, 'aclImdb')):
print("从压缩包解压...")
with tarfile.open(fname, 'r') as f:
f.extractall(DATA_ROOT) # 解压文件到此指定路径
(2)读取数据集文件中的数据并存入data列表中
from tqdm import tqdm # 可查看读取数据的进程
def read_imdb(folder='train', data_root=r'E:\data\aclImdb'):
data = []
for label in ['pos', 'neg']:
folder_name = os.path.join(data_root, folder, label) # 拼接文件路径 如:E:\data\aclImdb\train\pos\
for file in tqdm(os.listdir(folder_name)): # os.listdir(folder_name) 读取文件路径下的所有文件名,并存入列表中
with open(os.path.join(folder_name, file), 'rb') as f:
review = f.read().decode('utf-8').replace('\n', ' ').lower()
data.append([review, 1 if label == 'pos' else 0]) # 将每个文本读取的内容和对应的标签存入data列表中
random.shuffle(data) # 打乱data列表中的数据排列顺序
return data
(3)读取训练数据集和测试数据集
train_data, test_data =read_imdb('train'), read_imdb('test')
- 2、对读取的数据进行预处理
(1)用空格进行分词
# 空格分词
def get_tokenized_imdb(data):
'''
:param data: list of [string, label]
'''
def tokenizer(text):
return [tok.lower() for tok in text.split(' ')]
return [tokenizer(review) for review,_ in data] # 只从data中读取review(评论)内容而不读取标签(label),对review使用tokenizer方法进行分词
(2)创建词典
# 创建词典
def get_vocab_imdb(data):
tokenized_data = get_tokenized_imdb(data) # 调用get_tokenized_imdb()空格分词方法获取到分词后的数据tokenized_data
counter = collections.Counter([tk for st in tokenized_data for tk in st]) # 读取tokenized_data列表中每个句子的每个词,放入列表中。
# collections.Counter()方法可计算出列表中所有不重复的词数总和
return Vocab.Vocab(counter, min_freq=5) # 去掉词频小于5的词
(3)获取处理后的词典
vocab = get_vocab_imdb(train_data)
# print(len(vocab)) # 46152
# print(vocab.stoi['hello']) # 8950
(4)对data列表中的每行数据进行处理,将词转换为索引,并使每行数据等长
# 对data列表中的每行数据进行处理,将词转换为索引,并使每行数据等长
def process_imdb(data, vocab):
max_len = 500 # 每条评论通过截断或者补0,使得长度变成500
def pad(x):
return x[:max_len] if len(x) > max_len else x + [0]*(max_len - len(x)) # x[:max_len] 只获取前max_len个词
# x + [0]*(max_len - len(x)) 词数小于max_len,用pad=0补长到max_len
tokenized_data = get_tokenized_imdb(data) # 调用方法获取分词后的数据
features = torch.tensor([pad([vocab.stoi[word] for word in words]) for words in tokenized_data]) # 将词转换为vocab词典中对应词的索引
labels = torch.tensor([score for _, score in data])
return features, labels
- 3、创建数据迭代器
# 3、创建数据迭代器
batch_size = 64
train_set = Data.TensorDataset(*process_imdb(train_data, vocab))
test_set = Data.TensorDataset(*process_imdb(test_data, vocab))
train_iter = Data.DataLoader(train_set, batch_size, True)
test_iter = Data.DataLoader(test_set, batch_size)
- 4、创建循环神经网络
# 4、创建循环神经网络
class BiRNN(nn.Module):
def __init__(self, vocab, embed_size, num_hiddens, num_layers):
super(BiRNN, self).__init__()
self.embedding = nn.Embedding(len(vocab), embed_size)
self.encoder = nn.LSTM(
input_size=embed_size,
hidden_size=num_hiddens,
num_layers=num_layers