PytorchでCNNのサンプルプログラム-digitsデータセット

ディープラーニング




PytorchでCNN

ディープラーニングで最近人気が出てきているPytorchで、CNNを学習していきます。

プログラムはブロックごとに分けて、紹介します。

今回使用するデータセットは、scikit-learnのdigitsデータセットです。

このdigitsは、手書き文字のMNISTと似ていますが、画像サイズが(8,8)とかなり小さいです。

ちなみに、MNISTの画像サイズは、(28, 28)です。

また、データ数は、1797です。

プログラムの解説と流れ

importするライブラリ

# データを訓練用と検証用に分割
import numpy as np

from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split

import torch
from torch import nn, optim
from torch.utils.data import Dataset, DataLoader,TensorDataset

import time

import matplotlib.pyplot as plt
%matplotlib inline

digitsデータセットの整形

digits.dataが入力で、digits.targetが正解ラベルになります。
まず、正規化します。
次に、digits.dataを、2次元(画像)として扱うために、reshapeします。

PytorchのConv層は、(batch_size, channel, W, H)となっていることに注意してください。

Kerasの場合は、(batch_size, W, H, channel)となっています。

データを学習用とテスト用に分けるために、train_test_splitを使って、データを分割します。

digits = load_digits()

# 全体の30%は検証用
X = digits.data
y = digits.target
#正規化0~1
X = X/255
print(X.shape)
#shape=(1797, 64)
X = X.reshape(-1, 1, 8, 8)
print(X.shape)
#shape=(1797, 1, 8, 8)
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.3, random_state=1)

tensorに変換

Pytorchのtensorにデータを変換します。

#テンソル型に変換する
X_train = torch.tensor(train_X, dtype=torch.float32)
y_train = torch.tensor(train_y, dtype=torch.int64) 
X_test = torch.tensor(test_X, dtype=torch.float32)
y_test = torch.tensor(test_y, dtype=torch.int64) 

DatasetとDataLoader

#データセット
train = torch.utils.data.TensorDataset(X_train,y_train)
test = torch.utils.data.TensorDataset(X_test,y_test)

#データローダー
train_loader = torch.utils.data.DataLoader(train, batch_size = 32, shuffle = False)
test_loader = torch.utils.data.DataLoader(test, batch_size = 32, shuffle = False)

ネットワークの定義

#ネットワークの定義
class net(nn.Module):
    def __init__(self):
        super(net,self).__init__()
        #畳み込み層
        self.conv_layers = nn.Sequential(
            nn.Conv2d(in_channels = 1, out_channels = 16, kernel_size = 2, stride=1, padding=0),
            nn.Conv2d(in_channels = 16, out_channels = 32, kernel_size = 2, stride=1, padding=0),
        )
        #全結合層
        self.dence = nn.Sequential(
            nn.Linear(32 * 6 *6, 128),
            nn.Dropout(p=0.2),
            nn.Linear(128, 64),
            nn.Dropout(p=0.2),
            nn.Linear(64, 10),
        )
        
    #順伝播
    def forward(self,x):
        
        out = self.conv_layers(x)
        #Flatten
        out = out.view(out.size(0), -1)
        #全結合層
        out = self.dence(out)
        
        return out
    
    #畳み込み層の出力サイズのチェック
    def check_cnn_size(self, size_check):
        out = self.conv_layers(size_check)
        
        return out

デバイス選択と畳み込み層の出力サイズの確認

#デバイスの状態を確定
device = 'cuda' if torch.cuda.is_available() else 'cpu'

#net()をデバイスに渡す
net = net().to(device)

#畳み込み層の出力サイズ=全結合層のinput_sizeの確認
size_check = torch.FloatTensor(10, 1, 8, 8)
size_check = size_check.to(device)
print(net.check_cnn_size(size_check).size())

損失関数と最適化の選択

損失関数を選択します。

最適化を選択します。

#損失関数
criterion = nn.CrossEntropyLoss()
#最適化
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4)

学習

num_epochs = 100

train_loss_list = []
train_acc_list = []
val_loss_list = []
val_acc_list = []
import time
start = time.time()
for epoch in range(num_epochs):
    train_loss = 0
    train_acc = 0
    val_loss = 0
    val_acc = 0
    
    #train
    net.train()
    for i, (images, labels) in enumerate(train_loader):
        images, labels = images.to(device), labels.to(device)
        optimizer.zero_grad()
        outputs = net.forward(images)
        loss = criterion(outputs, labels)
        train_loss += loss.item()
        train_acc += (outputs.max(1)[1] == labels).sum().item()
        loss.backward()
        optimizer.step()
    
    avg_train_loss = train_loss / len(train_loader.dataset)
    avg_train_acc = train_acc / len(train_loader.dataset)
    
    #val
    net.eval()
    with torch.no_grad():
        for images, labels in test_loader:
            images = images.to(device)
            labels = labels.to(device)
            outputs = net.forward(images)
            loss = criterion(outputs, labels)
            val_loss += loss.item()
            val_acc += (outputs.max(1)[1] == labels).sum().item()
    avg_val_loss = val_loss / len(test_loader.dataset)
    avg_val_acc = val_acc / len(test_loader.dataset)
    
    print ('Epoch [{}/{}], Loss: {loss:.4f}, val_loss: {val_loss:.4f}, val_acc: {val_acc:.4f}' 
                   .format(epoch+1, num_epochs, i+1, loss=avg_train_loss, val_loss=avg_val_loss, val_acc=avg_val_acc))
    train_loss_list.append(avg_train_loss)
    train_acc_list.append(avg_train_acc)
    val_loss_list.append(avg_val_loss)
    val_acc_list.append(avg_val_acc)

end = time.time() - start

精度のグラフ化

plt.plot(train_acc_list, color='orange')
plt.plot(val_acc_list)
plt.legend;

参考

タイトルとURLをコピーしました