PyTorch Tutorial RNN 1

date:

19 oct 2019

download data

from io import open;import glob;import os
import unicodedata;import string
import torch;import torch.nn as nn
import random;import matplotlib.pyplot as plt
allLetters=string.ascii_letters+" .,;'"

def findFiles(path): return glob.glob(path)
def unicodeToAscii(s):
  return ''.join(
    c for c in unicodedata.normalize('NFD',s)
    if unicodedata.category(c)!='Mn' and c in allLetters)
def readLines(filename):
  lines=open(filename,encoding='utf-8').read().strip().split('\n')
  return [unicodeToAscii(line) for line in lines]
def lineToTensor(line):
  tensor=torch.zeros([len(line),1,len(allLetters)])
  for i,letter in enumerate(line):
    #print(i,letter)
    index=allLetters.find(letter)
    tensor[i][0][index]=1
  return tensor
def categoryFromOutput(output,allCategories):
  values,indices=output.topk(1)
  index=indices[0].item()
  return allCategories[index],index
def randomTrainingExample(allCategories,categoryLines):
  category=random.choice(allCategories)
  line=random.choice(categoryLines[category])
  categoryTensor=torch.tensor([allCategories.index(category)],dtype=torch.long)
  return category,line,categoryTensor,lineToTensor(line)

class GetData:
  def __init__(self):
    self.categoryLines={};self.allCategories=[]
    for filename in findFiles('*.txt'):
      category=os.path.splitext(os.path.basename(filename))[0]
      self.allCategories.append(category)
      self.categoryLines[category]=readLines(filename)
    #print(self.categoryLines['Chinese'])
    #print(lineToTensor('abc'))
class RNN(nn.Module):
  def __init__(self,inputSize,hiddenSize,outputSize):
    super(RNN,self).__init__()
    self.hiddenSize=hiddenSize
    self.i2h=nn.Linear(inputSize+hiddenSize,hiddenSize)
    self.i2o=nn.Linear(inputSize+hiddenSize,outputSize)
    self.softmax=nn.LogSoftmax(dim=1)
  def forward(self,input,hidden):
    combined=torch.cat((input,hidden),1)
    hidden=self.i2h(combined)
    output=self.softmax(self.i2o(combined))
    return output,hidden
  def initHidden(self):
    return torch.zeros([1,self.hiddenSize])
class Agent:
  def __init__(self,learnRate):
    self.learnRate=learnRate
    self.getData=GetData()
    self.rnn=RNN(len(allLetters),128,len(getData.allCategories))
    self.criterion=nn.NLLLoss()
  def trainOne(self,categoryTensor,lineTensor):
    hidden=self.rnn.initHidden()
    self.rnn.zero_grad()
    for i in range(lineTensor.shape[0]):
      output,hidden=self.rnn(lineTensor[i],hidden)
    loss=self.criterion(output,categoryTensor)
    loss.backward()
    for p in self.rnn.parameters():
      p.data.add_(-self.learnRate,p.grad.data)
    return output,loss.item()
  def train(self,numIterations):
    currentLoss=0;losses=[]
    for iter in range(1,numIterations+1):
      category,line,categoryTensor,lineTensor=randomTrainingExample(
        self.getData.allCategories,self.getData.categoryLines)
      output,loss=self.trainOne(categoryTensor,lineTensor)
      currentLoss+=loss
      if(iter%1000==0):
        losses.append(currentLoss);currentLoss=0
        print("loss",loss)
    plt.plot(losses);plt.show()

agent=Agent(learnRate=0.005)
agent.train(100000)
image.webp

image.webp