rnn-的最简单例子 hihello程序 pytorch教程之RNN

没有看到有人解释pytorch实现的RNN模型的hello,所以我来写一个。hello是一个很简单的RNN模型的程序,功能就是喂给模型hihell, 模型会输出ihello。

首先导入相关的包。

import sys
import torch
import torch.nn as nn
from torch.autograd import Variable

初始化参数和input、labels

torch.manual_seed(777)  # reproducibility
#            0    1    2    3    4
idx2char = ['h', 'i', 'e', 'l', 'o']
# Teach hihell -> ihello
x_data = [0, 1, 0, 2, 3, 3]   # hihell
one_hot_lookup = [[1, 0, 0, 0, 0],  # 0
                  [0, 1, 0, 0, 0],  # 1
                  [0, 0, 1, 0, 0],  # 2
                  [0, 0, 0, 1, 0],  # 3
                  [0, 0, 0, 0, 1]]  # 4

y_data = [1, 0, 2, 3, 3, 4]    # ihello
x_one_hot = [one_hot_lookup[x] for x in x_data]
inputs = Variable(torch.Tensor(x_one_hot))
labels = Variable(torch.LongTensor(y_data))
num_classes = 5
input_size = 5  # one-hot size
hidden_size = 5  # output from the RNN. 5 to directly predict one-hot
batch_size = 1   # one sentence
sequence_length = 1  # One by one
num_layers = 1  # one-layer rnn

idx2char可以利用索引取出对应的字母。只有打印的时候会用到这个数组。
x_data就是要喂给模型的数据,他的每一个元素作为idx2char的索引,就可以取出一个字母。但是要对他进行one-hot编码。
对这个离散型变量进行one-hot编码,也可以embedding编码,这里用了比较简单的one-hot
Y_data就是target data,希望model的输出会是这个数据。
接下来是一些变量的定义,一共五个字母,所以每个字母用一个五维的字母来表示。所以model的input_size和hidden_size都是5. batch_size=1表示一次喂一个句子。sequence_length = 1表示一次喂一个字母进去。

模型的定义

然后就是模型的定义,继承nn.Module,然后实现这三个函数就可以。初始化hidden是把第一个输入的hidden初始化为0.

class Model(nn.Module):

    def __init__(self):
        super(Model, self).__init__()
        self.rnn = nn.RNN(input_size=input_size,
                          hidden_size=hidden_size, batch_first=True)

    def forward(self, hidden, x):
        # Reshape input (batch first)
        x = x.view(batch_size, sequence_length, input_size)

        # Propagate input through RNN
        # Input: (batch, seq_len, input_size)
        # hidden: (num_layers * num_directions, batch, hidden_size)
        out, hidden = self.rnn(x, hidden) #out:torch.Size([1, 1, 5])
        return hidden, out.view(-1, num_classes)  #return 的out的大小torch.Size([1, 5])

    def init_hidden(self):
        # Initialize hidden and cell states
        # (num_layers * num_directions, batch, hidden_size)
        return Variable(torch.zeros(num_layers, batch_size, hidden_size))

创建这个model的实例,可以把它打印出来看一看。
CrossEntropyLoss来计算loss,Adam来做update。

# Instantiate RNN model
model = Model()
print(model)
# Set loss and optimizer function
# CrossEntropyLoss = LogSoftmax + NLLLoss
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.1)
optimizer.zero_grad()
hidden = model.init_hidden()
Model(
  (rnn): RNN(5, 5, batch_first=True)
)
    loss=0
    print("predicted string: ")
    for input, label in zip(inputs, labels):
        # print(input.size(), label.size())
        label=label.view(1)
        hidden, output = model(hidden, input)
        val, idx = output.max(1) #找到output里最大的值和他的索引,这就是预测的字符,然后再把他的值和label做crossentropy
        sys.stdout.write(idx2char[idx.data[0]])
        loss += criterion(output, label)
predicted string: 
llllee

首先看一看初始的参数,可以做出什么效果的预测。我们把hihell喂进去得到的是lllll

开始训练模型

optimizer.zero_grad()把梯度置零,也就是把loss关于weight的导数变成0. 因为当我们使用loss.backward()和opimizer.step()进行梯度下降更新参数的时候,梯度并不会自动清零。

然后依次喂这五个字母进去,分别把得到的output打印出来,计算loss,把loss累加起来再做反向传播,计算梯度,优化。
其中一个output可能是[[ 0.3700, -0.3483, -0.1920, 0.8472, 0.5825]]这样,一个label可能是【3】,这是预测正确的情况,这两个做crossentropy是因为pytorch对他的实现是包括softmax的。

for epoch in range(100):
    optimizer.zero_grad()
    loss = 0
    hidden = model.init_hidden()

    print("----------------------------predicted string: ")
    for input, label in zip(inputs, labels):
        # print(input.size(), label.size())
        label=label.view(1)
        hidden, output = model(hidden, input)
        val, idx = output.max(1) #找到output里最大的值和他的索引,这就是预测的字符,然后再把他的值和label做crossentropy
        sys.stdout.write(idx2char[idx.data[0]])
        loss += criterion(output, label)
        

    if epoch%10==0:
        print(", epoch: %d, loss: %1.3f" % (epoch + 1, loss.item()))

    loss.backward()
    optimizer.step()
----------------------------predicted string: 
llllee, epoch: 1, loss: 9.814
----------------------------predicted string: 
llllll----------------------------predicted string: 
llllll----------------------------predicted string: 
ihllll----------------------------predicted string: 
ihllll----------------------------predicted string: 
ihelll----------------------------predicted string: 
ihelll----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello, epoch: 11, loss: 4.266
----------------------------predicted string: 


ihello, epoch: 91, loss: 2.800
----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello----------------------------predicted string: 
ihello

预测

最后,用train好的模型来预测一发(虽然也是在这个hihell上面)

    loss=0
    print("predicted string: ")
    for input, label in zip(inputs, labels):
        # print(input.size(), label.size())
        label=label.view(1)
        hidden, output = model(hidden, input)
        val, idx = output.max(1) #找到output里最大的值和他的索引,这就是预测的字符,然后再把他的值和label做crossentropy
        sys.stdout.write(idx2char[idx.data[0]])
        loss += criterion(output, label)
predicted string: 
lhello
loss
tensor(3.9026, grad_fn=<AddBackward0>)

没有预测正确,原来是因为没有对hidden进行初始化

    hidden = model.init_hidden()
    loss=0
    print("predicted string: ")
    for input, label in zip(inputs, labels):
        # print(input.size(), label.size())
        label=label.view(1)
        hidden, output = model(hidden, input)
        val, idx = output.max(1) #找到output里最大的值和他的索引,这就是预测的字符,然后再把他的值和label做crossentropy
        sys.stdout.write(idx2char[idx.data[0]])
        loss += criterion(output, label)
predicted string: 
ihello
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值