字符级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()

第二种方式使用自带的优化器,需要注意梯度清空

posted @ 2019-07-06 20:48  静_渊  阅读(476)  评论(0编辑  收藏  举报