PyTorch实现用于文本生成的循环神经网络

自然语言处理(NLP)有很多有趣的应用 , 文本生成就是其中一个有趣的应用 。
当一个机器学习模型工作在诸如循环神经网络、LSTM-RNN、GRU等序列模型上时 , 它们可以生成输入文本的下一个序列 。
PyTorch提供了一组功能强大的工具和库 , 这些工具和库为这些基于NLP的任务增添了动力 。 它不仅需要较少的预处理量 , 而且加快了训练过程 。
PyTorch实现用于文本生成的循环神经网络文章插图
在本文中 , 我们将在PyTorch中训练几种语言的循环神经网络(RNN) 。 训练成功后 , RNN模型将预测属于以输入字母开头的语言的名称 。
PyTorch实现这个实现是在Google Colab中完成的 , 其中的数据集是从Google驱动器获取的 。 所以 , 首先 , 我们将用Colab Notebook安装Google驱动器 。
from google.colab import drivedrive.mount('/content/gdrive')现在 , 我们将导入所有必需的库 。
from __future__ import unicode_literals, print_function, divisionfrom io import openimport globimport osimport unicodedataimport stringimport torchimport torch.nn as nnimport randomimport timeimport mathimport matplotlib.pyplot as pltimport matplotlib.ticker as ticker下面的代码片段将读取数据集 。
all_let = string.ascii_letters + " .,;'-"n_let = len(all_let) + 1def getFiles(path):return glob.glob(path)# Unicode字符串到ASCIIdef unicodeToAscii(s):return ''.join(c for c in unicodedata.normalize('NFD', s)if unicodedata.category(c) != 'Mn'and c in all_let)# 读一个文件并分成几行def getLines(filename):lines = open(filename, encoding='utf-8').read().strip().split('\n')return [unicodeToAscii(line) for line in lines]# 建立cat_lin字典 , 存储每个类别的行列表cat_lin = {}all_ctg = []for filename in getFiles('gdrive/My Drive/Dataset/data/data/names/*.txt'):categ = os.path.splitext(os.path.basename(filename))[0]all_ctg.append(category)lines = getLines(filename)cat_lin[categ] = linesn_ctg = len(all_ctg)在下一步中 , 我们将定义module类来生成名称 。 该模块将是一个循环神经网络 。
class NameGeneratorModule(nn.Module):def __init__(self, inp_size, hid_size, op_size):super(NameGeneratorModule, self).__init__()self.hid_size = hid_sizeself.i2h = nn.Linear(n_ctg + inp_size + hid_size, hid_size)self.i2o = nn.Linear(n_ctg + inp_size + hid_size, op_size)self.o2o = nn.Linear(hid_size + op_size, op_size)self.dropout = nn.Dropout(0.1)self.softmax = nn.LogSoftmax(dim=1)def forward(self, category, input, hidden):inp_comb = torch.cat((category, input, hidden), 1)hidden = self.i2h(inp_comb)output = self.i2o(inp_comb)op_comb = torch.cat((hidden, output), 1)output = self.o2o(op_comb)output = self.dropout(output)output = self.softmax(output)return output, hiddendef initHidden(self):return torch.zeros(1, self.hid_size)以下函数将用于从列表中选择随机项 , 从类别中选择随机行
def randChoice(l):return l[random.randint(0, len(l) - 1)]def randTrainPair():category = randChoice(all_ctg)line = randChoice(cat_lin[category])return category, line以下函数将数据转换为RNN模块的兼容格式 。
def categ_Tensor(categ):li = all_ctg.index(categ)tensor = torch.zeros(1, n_ctg)tensor[0][li] = 1return tensordef inp_Tensor(line):tensor = torch.zeros(len(line), 1, n_let)for li in range(len(line)):letter = line[li]tensor[li][0][all_let.find(letter)] = 1return tensordef tgt_Tensor(line):letter_indexes = [all_let.find(line[li]) for li in range(1, len(line))]letter_id.append(n_let - 1) # EOSreturn torch.LongTensor(letter_id)以下函数将创建随机训练示例 , 包括类别、输入和目标张量 。
#损失criterion = nn.NLLLoss()#学习率lr_rate = 0.0005def train(category_tensor, input_line_tensor, target_line_tensor):target_line_tensor.unsqueeze_(-1)hidden = rnn.initHidden()rnn.zero_grad()loss = 0for i in range(input_line_tensor.size(0)):output, hidden = rnn(category_tensor, input_line_tensor[i], hidden)l = criterion(output, target_line_tensor[i])loss += lloss.backward()for p in rnn.parameters():p.data.add_(p.grad.data, alpha=-lr_rate)return output, loss.item() / input_line_tensor.size(0)为了显示训练期间的时间 , 定义以下函数 。
def time_taken(since):now = time.time()s = now - sincem = math.floor(s / 60)s -= m * 60return '%dm %ds' % (m, s)在下一步中 , 我们将定义RNN模型 。
model = NameGenratorModule(n_let, 128, n_let)我们将看到定义的RNN模型的参数 。
print(model)
PyTorch实现用于文本生成的循环神经网络文章插图
下一步 , 该模型将训练10000个epoch 。
epochs = 100000print_every = 5000plot_every = 500all_losses = []total_loss = 0 # 每次迭代时重置start = time.time()for iter in range(1, epochs + 1):output, loss = train(*rand_train_exp())total_loss += lossif iter % print_every == 0:print('Time: %s, Epoch: (%d - Total Iterations: %d%%),Loss: %.4f' % (time_taken(start), iter, iter / epochs * 100, loss))if iter % plot_every == 0:all_losses.append(total_loss / plot_every)total_loss = 0