tau-2020-pytorch-tutorial/pytorch11.py

99 lines
2.7 KiB
Python
Raw Normal View History

#!/usr/bin/python3
# https://pytorch.org/tutorials/beginner/nlp/word_embeddings_tutorial.html
import torch
from torch import nn, optim
history_length = 32
history_encoded = [ord('\n')] * history_length
nb_of_char_codes = 128
embedding_size = 30
step = 1000
device = torch.device('cpu')
f = open('shakespeare.txt')
def char_source():
for line in f:
for c in line:
c_code = ord(c)
if c_code < nb_of_char_codes:
yield(c_code)
class EncoderRNN(nn.Module):
def __init__(self, input_size, hidden_size, embedding_size):
super(EncoderRNN, self).__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.embedding = nn.Embedding(input_size, embedding_size)
self.gru = nn.GRU(embedding_size, nb_of_char_codes)
self.softmax = nn.LogSoftmax(dim=1)
def forward(self, input, hidden):
embedded = self.embedding(input)
output = embedded
output, hidden = self.gru(output, hidden)
output = self.softmax(output)
return output, hidden
def initHidden(self):
return torch.zeros(1, self.hidden_size, self.input_size, device=device)
def generate(self, n, encoder_hidden):
t = (" " * 200 + "To be or not to be")[-history_length:]
history = [ord(c) for c in t]
with torch.no_grad():
for _ in range(n):
x = torch.tensor(history, dtype=torch.long, device=device)
x = x.unsqueeze(0)
y = model(x,encoder_hidden)[0][:,-1,:][0]
y = torch.exp(y)
best = (sorted(range(nb_of_char_codes), key=lambda i: -y[i]))[0:2]
yb = torch.tensor([(y[ix] if ix in best else 0.0) for ix in range(nb_of_char_codes)])
c = torch.multinomial(yb, 1)[0].item()
t += chr(c)
history.pop(0)
history.append(c)
print(t)
model = EncoderRNN(nb_of_char_codes, history_length, embedding_size).to(device)
criterion = nn.NLLLoss().to(device)
optimizer = optim.Adam(model.parameters())
counter = 0
losses = []
for c in char_source():
x = torch.tensor(history_encoded, dtype=torch.long, device=device)
model.zero_grad()
x = x.unsqueeze(0)
encoder_hidden = model.initHidden()
y = model(x,encoder_hidden)[0][:,-1,:]
loss = criterion(y, torch.tensor([c]).to(device))
losses += [loss.item()]
if len(losses) > step:
losses.pop(0)
counter += 1
if counter % step == 0:
avg_loss = sum(losses)/len(losses)
print(f"{counter}: {loss} {avg_loss}")
model.generate(200, encoder_hidden)
loss.backward()
optimizer.step()
history_encoded.pop(0)
history_encoded.append(c)