Advertisement

pytorch深度学习:RNN循环神经网络(二)

阅读量:

上一节了解到了RNN和LSTM的基础知识,这节我们使用LSTM网络对mnist手写数字数据集进行处理。重点了解LSTM网络的搭建方法以及各个参数所代表的含义。

1.问题的提出

众所周知,在处理带有时序特性的数据方面,RNN(循环神经网络)表现出了强大的能力。然而,在MNIST这样的图像分类任务中直接应用RNN可能会遇到挑战。为了解决这一问题,请考虑将MNIST中的手写字样本每一行视为不同的时序片段。具体而言,在这个案例中每张图片由28个连续的时间步组成(即Time_step=28),而每个时间步包含了28个像素信息(即Input_size=28)。接下来,请我们初始化一些超参数设置:

复制代码
    # 定义一些超参数
    EPOCH = 1           # 训练整批数据多少次, 为了节约时间, 我们只训练一次
    BATCH_SIZE = 64
    TIME_STEP = 28      # rnn 时间步数 / 图片高度
    INPUT_SIZE = 28     # rnn 每步输入值 / 图片每行像素
    LR = 0.01           # learning rate
    
    
      
      
      
      
      
      
    
    代码解读

该部分样本同样如前所述划分为测试样本与训练样本,在此不展开具体方法说明

2.LSTM网络的搭建

现有的PyTorch框架已经提供了现成的LSTM模块封装。为了构建模型时可直接调用nn.LSTM()函数完成搭建。我们构建了一个仅包含单个LSTM单元的一维RNN模型,并通过紧跟的一个全连接层对输入进行10类分类。

复制代码
    class RNN(nn.Module):
    def __init__(self):
        super(RNN,self).__init__()
        self.rnn = nn.LSTM(
            input_size=INPUT_SIZE,
            hidden_size=64,
            num_layers=1,
            batch_first=True
        )
        self.fc1 = nn.Linear(64,10)
    
    def forward(self,x):
        # x shape (batch, time_step, input_size)
        # r_out shape (batch, time_step, output_size)
        # h_n shape (n_layers, batch, hidden_size)   LSTM 有两个 hidden states, h_n 是分线, h_c 是主线
        # h_c shape (n_layers, batch, hidden_size)
        r_out, (h_n, h_c) = self.rnn(x, None)   # None 表示 hidden state 会用全0的 state
    
        # 选取最后一个时间点的r_out 输出
        # 这里 r_out[:, -1, :] 的值也就是最后一时刻 h_n (主线)的值
        out = self.fc1(r_out[:, -1, :])
        return out
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

来看下LSTM模块中的各个参数代表什么意义:

  • input_dimension: 输入维度为28,在这个特定案例中被设定。
  • hidden_units: 隐层单元数量被设定为64。
  • lstm_layers: 该模型中集成多少个LSTM单元?通常情况下只有一个。
  • batch_first参数: 是否设置为true?如果设置true,则输入与输出张量格式变为**[batch_size, time_step, input_size]**。
  • bidirectional功能: 是否启用双向LSTM?通常情况下未启用。

在向LSTM网络输入数据之前(因为)需要将数据x(按照)其形状定义为[batch_size,time_step,input_size]的要求(执行)必要的维度重塑操作(代码如下)

复制代码
    b_x = x.view(-1,28,28) # -1表示自动计算,第一个28为time_step,第二个28为input_size
    
    
      
    
    代码解读

经过LSTM处理后共有3个输出,分别为:

复制代码
    r_out, (h_n, h_c) = self.rnn(x, None)   # None 表示 hidden state 会用全0的 state
    
    
      
    
    代码解读

即为最终层在每个time_step上的输出结果h
代表各层中最后一个时间步的输出结果h
即为各层中对应最后一个时间步的记忆存储值c

它们的格式分别为:

复制代码
    r_out(batch_size, time_step, hidden_size*num_directions) 
    h_n(num_layers*num_directions, batch_size, hidden_size) 
    c_n(num_layers*num_directions, batch_size, hidden_size)
    
    
      
      
      
    
    代码解读

其中参数 num_directions 代表的是一个 LSTM 模型的方向性问题。如果是单方向的 LSTM 模型,则 num_directions=1;如果是双方向的 LSTM 架构,则 num_directions=2

在后续的全连接操作中,我们选择了最后一个time_step的输出作为全连接层的输入,这是因为LSTM网络具有hidden_size=64特性,因此全连接层设定为输入层64个单元和输出层10个单元(即10分类任务),具体实现代码如下所示

复制代码
    # 选取最后一个时间点的r_out 输出
    # 这里 r_out[:, -1, :] 的值也就是最后一时刻 h_n (主线)的值
    out = self.fc1(r_out[:, -1, :])
    
    
      
      
      
    
    代码解读

3.结果的展示

与之前相比,在这一阶段的训练过程没有发生明显的变化。无需额外展示这一现象的具体表现。接下来我们通过测试集进行评估。最终实验结果显示模型在测试集上的预测准确率达到**95%**左右,并完全符合我们的预期目标。为了进一步验证结果的有效性,我们选取了前十组数据进行具体分析。

第一行表示RNN网络预测的结果,第二行表示真实的结果:

复制代码
    [7 2 1 0 4 1 4 9 5 9] prediction number
    [7 2 1 0 4 1 4 9 5 9] real number
    
    
      
      
    
    代码解读

最终,在此处放置了完整且详细的代码,并源自于莫烦大神的教学材料。

复制代码
    # RNN 进行mnist手写数字集的判别 #
    import torch
    import torch.nn as nn
    import torch.utils.data as Data
    import torchvision
    
    # 定义一些超参数
    EPOCH = 1           # 训练整批数据多少次, 为了节约时间, 我们只训练一次
    BATCH_SIZE = 64
    TIME_STEP = 28      # rnn 时间步数 / 图片高度
    INPUT_SIZE = 28     # rnn 每步输入值 / 图片每行像素
    LR = 0.01           # learning rate
    DOWNLOAD_MNIST = False  # 如果你已经下载好了mnist数据就写上 Fasle
    
    # Mnist 手写数字数据集
    train_data = torchvision.datasets.MNIST(
    root='./mnist/',    # 保存或者提取位置
    train=True,  # this is training data
    transform=torchvision.transforms.ToTensor(),    # 转换 PIL.Image or numpy.ndarray 成
                                                    # torch.FloatTensor (C x H x W), 训练的时候 normalize 成 [0.0, 1.0] 区间
    download=DOWNLOAD_MNIST,          # 没下载就下载, 下载了就不用再下了
    )
    
    test_data = torchvision.datasets.MNIST(root='./mnist/', train=False)
    
    # 批训练 50samples, 1 channel, 28x28 (50, 1, 28, 28)
    train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)
    
    # 为了节约时间, 我们测试时只测试前2000个
    test_x = test_data.test_data.type(torch.FloatTensor)[:2000]/255.   # shape (2000, 28, 28) value in range(0,1)
    test_y = test_data.test_labels.numpy()[:2000]    # covert to numpy array
    
    class RNN(nn.Module):
    def __init__(self):
        super(RNN,self).__init__()
        self.rnn = nn.LSTM(
            input_size=INPUT_SIZE,
            hidden_size=64,
            num_layers=1,
            batch_first=True
        )
        self.fc1 = nn.Linear(64,10)
    
    def forward(self,x):
        # x shape (batch, time_step, input_size)
        # r_out shape (batch, time_step, output_size)
        # h_n shape (n_layers, batch, hidden_size)   LSTM 有两个 hidden states, h_n 是分线, h_c 是主线
        # h_c shape (n_layers, batch, hidden_size)
        r_out, (h_n, h_c) = self.rnn(x, None)   # None 表示 hidden state 会用全0的 state
    
        # 选取最后一个时间点的r_out 输出
        # 这里 r_out[:, -1, :] 的值也就是最后一时刻 h_n (主线)的值
        out = self.fc1(r_out[:, -1, :])
        return out
    
    
    rnn = RNN()
    print(rnn)
    
    optimizer = torch.optim.Adam(rnn.parameters(),lr=LR)
    loss_func = nn.CrossEntropyLoss()
    
    for epoch in range(EPOCH):
    for step,(x,y) in enumerate(train_loader):
        b_x = x.view(-1,28,28)
        b_y = y
    
        output = rnn(b_x)
        loss = loss_func(output,b_y)
    
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    
        if step % 50 == 0:
            test_output = rnn(test_x)  # (samples, time_step, input_size)
            pred_y = torch.max(test_output, 1)[1].data.numpy()
            accuracy = float((pred_y == test_y).astype(int).sum()) / float(test_y.size)
            print('Epoch: ', epoch, '| train loss: %.4f' % loss.data.numpy(), '| test accuracy: %.2f' % accuracy)
    
    # 取10个值来验证预测的正确与否
    test_output = rnn(test_x[:10].view(-1, 28, 28))
    pred_y = torch.max(test_output, 1)[1].data.numpy().squeeze()
    print(pred_y, 'prediction number')
    print(test_y[:10], 'real number')
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

全部评论 (0)

还没有任何评论哟~