字符级RNN教程
CLASSIFYING NAMES WITH A CHARACTER-LEVEL RNN
从这个教程学到的主要内容
- 如何读取一个文件夹下的全部文件;
- 如何把Unicode字符转成纯ascii字符;
- pytorch的训练流程
- 创建输入和目标;
- 前向传播;
- 计算损失;
- 后向更新;
- 返回损失;
整体代码如下:
import matplotlib.pyplot as plt
import torch
import unicodedata
import string
from __future__ import unicode_literals,print_function,division
from io import open
import os
all_files = "/home/dataset/data/names/*.txt"
all_letters = string.ascii_letters + ".,;'"
def unicodeToAscii(s):
return ''.join(
c for c in unicodedata.normalize("NFD",s)
if unicodedata.category(c) != "Mn"
and c in all_letters
)
# 在Unicode中,某些字符能够用多个合法的编码表示。
# 在需要比较字符串的程序中使用字符的多种表示会产生问题。 为了修正这个问题,你可以使用unicodedata模块先将文本标准化:
# normalize() 第一个参数指定字符串标准化的方式。 NFC表示字符应该是整体组成(比如可能的话就使用单一编码),而NFD表示字符应该分解为多个组合字符表示。
category_lines = {}
all_categories = []
import glob
def findFiles(filepath):
return glob.glob(filepath)
def readlines(filename):
lines = open(filename,encoding="utf-8").read().strip().split("\n")
return [unicodeToAscii(line) for line in lines]
网络结构的定义如下:
import torch.nn as nn
class RNN(nn.Module):
def __init__(self,input_size,hidden_size,output_size):
super(RNN,self).__init__()
self.hidden_size = hidden_size
self.i2h = nn.Linear(input_size + hidden_size,hidden_size)
self.i2o = nn.Linear(input_size + hidden_size,output_size)
self.softmax = nn.LogSoftmax(dim=1)
def forward(self,input,hidden):
combined = torch.cat((input,hidden),1)
output = self.i2o(combined)
hidden = self.i2h(combined)
output = self.softmax(output)
return output,hidden
def initHidden(self):
return torch.zeros(1,self.hidden_size)
具体的计算损失和梯度回传的过程,有两种写法
- 前向传播;
- prediction = net(x)
- 计算损失;
- loss = loss_func(prediction, y)
- 清空上一步的残余更新参数值
- optimizer.zero_grad()
- 误差反向传播, 计算参数更新值
- loss.backward()
- 将参数更新值施加到 net 的 parameters 上
- optimizer.step()
learning_rate = 0.006
optimizer = torch.optim.SGD(rnn.parameters(),lr =learning_rate)
def train(category_tensor,line_tensor):
hidden = rnn.initHidden()
rnn.zero_grad()
for i in range(line_tensor.size()[0]):
output, hidden = rnn(line_tensor[i], hidden)
loss = criterion(output,category_tensor)
loss.backward()
for p in rnn.parameters():
p.data.add_(-learning_rate, p.grad.data)
return output,loss.item()
第一种方法手动更新参数,即使用SGD算法;
learning_rate = 0.006
optimizer = torch.optim.SGD(rnn.parameters(),lr =learning_rate)
def train(category_tensor,line_tensor):
hidden = rnn.initHidden()
optimizer.zero_grad()
for i in range(line_tensor.size()[0]):
output, hidden = rnn(line_tensor[i], hidden)
loss = criterion(output,category_tensor)
loss.backward()
optimizer.step()
return output,loss.item()
第二种方式使用自带的优化器,需要注意梯度清空