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;