Pytorch 中間 (3) RNN 分類

RNN を使用した MNIST 手書き数字の分類。RNN および LSTM モデルの構造

pytorch で LSTM を使用すると、少しめまいがするかもしれませんが、LSTM のモデル パラメーターの意味は次のとおりです。


1. データセットをロードします

import torch 
import torchvision
import torch.nn as nn
import torchvision.transforms as transforms
import torch.utils.data as Data 

device  = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

sequence_length = 28 
input_size = 28 
hidden_size = 128 
num_layers = 2 
num_classes = 10 
batch_size = 128 
num_epochs = 2 
learning_rate = 0.01 

train_dataset = torchvision.datasets.MNIST(root='./data/',train=True,transform=transforms.ToTensor(),download=True)
test_dataset = torchvision.datasets.MNIST(root='./data/',train=False,transform=transforms.ToTensor())

train_loader = Data.DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
test_loader = Data.DataLoader(dataset=test_dataset,batch_size=batch_size)

 2. RNN モデルの構築

  • input_size – 入力フィーチャの寸法

  • hidden_​​size – 隠れ状態のフィーチャの次元

  • num_layers – レイヤーの数 (タイミング拡張とは区別されます)

  • バイアス – の場合FalseLSTM使用されません。デフォルトは ですTrue

  • バッチ_ファースト – の場合True、入力と出力の形状は次のようにTensorなります。(batch, seq, feature)

  • Dropout – ゼロ以外の場合、最後のレイヤーを除く のRNN出力にドロップアウトが追加されます。dropout

  • 双方向 – の場合True、双方向になりますRNN。デフォルトはFalse

       1. 上記のパラメータはドキュメントからのもので、最も基本的なパラメータはinput_size、hidden_​​size、および num_layerです。input_size: 入力データ ベクトルの次元、ここでは 28; hidden_​​size: 出力フィーチャの次元でもある隠れ層フィーチャの次元、ここでは 128; num_layers: lstm モジュールの数、ここでは 2。

       2. h0 と c0 の初期化次元は ( num_layer、batch_size、hidden_​​size )です。

       3. lstm の出力には out と (hn, cn) が含まれます。ここで、out.shape = torch.Size([128, 28, 128])、(batch_size、タイミング番号、隠れた特徴の次元)、つまり 28 に対応します。時系列の出力フィーチャは分類されるため、最後の出力フィーチャのみが必要になります。したがって、最終的な出力特徴量を取り出して全結合計算を行うと、全結合計算の出力次元は 10 (10 カテゴリ) となります。

       4. パラメータbatch_firstは特別です。これがtrueの場合、入力データの次元は(batch、seq、feature)であり、それ以外の場合は(seq、batch、feature)です。

       5. num_layers: lstm モジュールの数 2 つある場合、最初のモジュールの出力が 2 番目のモジュールの入力になります。

       概要: LSTM モデルの構築に使用されるパラメーター (入力データの特徴次元、隠れ層の特徴次元、lstm モジュールの数)、時系列の数は X、X.shape = (batch_size、時系列) に反映されます。長さ、データ ベクトルの次元)。

       LSTM は、入力に応じて自動タイミング マッチングを実現し、さまざまな入力長の機能を実現できることがわかります。

class RNN(nn.Module):
    def __init__(self, input_size,hidden_size,num_layers, num_classes):
        super(RNN, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        #input_size - 输入特征维度
        #hidden_size - 隐藏状态特征维度
        #num_layers - 层数(和时序展开要区分开),lstm模块的个数
        #batch_first为true,输入和输出的形状为(batch, seq, feature),true意为将batch_size放在第一维度,否则放在第二维度
        self.lstm = nn.LSTM(input_size,hidden_size,num_layers,batch_first = True)  
        self.fc = nn.Linear(hidden_size, num_classes)
        
    def forward(self,x):
        #参数:LSTM单元个数, batch_size, 隐藏层单元个数 
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)   #h0.shape = (2, 128, 128)
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
         
        #输出output :  (seq_len, batch, hidden_size * num_directions)
        #(h_n, c_n):最后一个时间步的隐藏状态和细胞状态
        #对out的理解:维度batch, eq_len, hidden_size,其中保存着每个时序对应的输出,所以全连接部分只取最后一个时序的
        #out第一维batch_size,第二维时序的个数,第三维隐藏层个数,所以和lstm单元的个数是无关的
        out,_ = self.lstm(x, (h0, c0))  #shape = torch.Size([128, 28, 128])
        out = self.fc(out[:,-1,:])  #因为batch_first = true,所以维度顺序batch, eq_len, hidden_size
        return out

 トレーニングパート

model = RNN(input_size,hidden_size, num_layers, num_classes).to(device)
print(model)

#RNN(
#  (lstm): LSTM(28, 128, num_layers=2, batch_first=True)
#  (fc): Linear(in_features=128, out_features=10, bias=True)
#)

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

total_step = len(train_loader)
for epoch in range(num_epochs):
    for i,(images, labels) in enumerate(train_loader):
        #batch_size = -1, 序列长度 = 28, 数据向量维度 = 28
        images = images.reshape(-1, sequence_length, input_size).to(device)
        labels = labels.to(device)
        
        # Forward pass
        outputs = model(images)
        loss = criterion(outputs, labels)
        
        # Backward and optimize
        optimizer.zero_grad()
        loss.backward() 
        optimizer.step()
        
        if (i+1) % 100 == 0:
            print(outputs.shape)
            print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}' 
                   .format(epoch+1, num_epochs, i+1, total_step, loss.item()))

# Test the model
with torch.no_grad():
    correct = 0
    total = 0
    for images, labels in test_loader:
        images = images.reshape(-1, sequence_length, input_size).to(device)
        labels = labels.to(device)
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

    print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total)) 

おすすめ

転載: blog.csdn.net/qq_41828351/article/details/90758748