[Kaggle]PyTorchでDigit Recognizerに挑戦

ディープラーニング




Digit Recognizerに挑戦

KaggleのDigit Recognizerに挑戦します。

使用言語は、Pythonです。

学習のモデルは”CNN”を使うので、ニューラルネットワークのライブラリ”PyTorch”を使っていきます。

※私的に、Kerasが一番簡単にモデルを構築できると思います。

プログラムの解説

ここでは、次の順でソースコードを分けて紹介します。

  1. インポートするリスト
  2. 訓練データの読み込み
  3. 訓練データの前処理
  4. ネットワークの構築
  5. 学習
  6. 学習結果
  7. テストデータの読み込み
  8. ラベルの推測
  9. 提出ファイル作成

インポートするもの

import time
import numpy as np
import pandas as pd

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

from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt
%matplotlib inline

訓練データの読み込み&前処理

train = pd.read_csv('train.csv') 
X = train.drop('label', axis=1).values
y = train.label.values
X = X.reshape(-1, 1, 28, 28)
X = X/255

train_X, val_X, train_y, val_y = train_test_split(X, y, test_size=0.2, random_state=0)


train_X = torch.tensor(train_X, dtype=torch.float32)
train_y = torch.tensor(train_y, dtype=torch.int64) 

val_X= torch.tensor(val_X, dtype=torch.float32)
val_y = torch.tensor(val_y, dtype=torch.int64) 

train_set = torch.utils.data.TensorDataset(train_X,train_y)
test_set = torch.utils.data.TensorDataset(val_X, val_y)

batch_sizes = 128
train_loader = torch.utils.data.DataLoader(train_set, batch_size = batch_sizes, shuffle = False)
test_loader = torch.utils.data.DataLoader(test_set, batch_size = batch_sizes, 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 = 32, kernel_size = 5, stride=1, padding=0),
            nn.ReLU(),
            nn.Conv2d(in_channels = 32, out_channels = 32, kernel_size = 5, stride=1, padding=0),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size = 2, stride=2),
            nn.Dropout(p=0.25),
            nn.Conv2d(in_channels = 32, out_channels = 64, kernel_size = 3, stride=1, padding=0),
            nn.ReLU(),
            nn.Conv2d(in_channels = 64, out_channels = 64, kernel_size = 3, stride=1, padding=0),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size = 2, stride=2),
            nn.Dropout(p=0.25)
        )
        #全結合層
        self.dence = nn.Sequential(
            nn.Linear(64 * 3 *3, 256),
            nn.Dropout(p=0.5),
            #nn.Linear(256, 128),
            #nn.Dropout(p=0.25),
            nn.Linear(256, 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().to(device)

畳み込み層の出力サイズチェック

size_check = torch.FloatTensor(10, 1, 28, 28)
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 =30

train_loss_list = []
train_acc_list = []
val_loss_list = []
val_acc_list = []
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)

print(time.time() - start)

学習結果

plt.plot(train_acc_list, label='Training loss')
plt.plot(val_acc_list, label='Validation loss')
plt.legend();

テストデータの読み込みと前処理

test = pd.read_csv('test.csv')
test = test.values
test = test.reshape(-1, 1, 28, 28)
test = test/255

batch_sizes = 1
test = torch.tensor(test, dtype=torch.float32)
test_sets = torch.utils.data.TensorDataset(test)
new_test_loader = torch.utils.data.DataLoader(test, batch_size = batch_sizes, shuffle = False)

ラベルの推測

pred_list = []
start = time.time()
with torch.no_grad():
    net.eval()
    c = 0
    for images in new_test_loader:
        images = images.to(device)
        output = net.forward(images)
        _, pred = torch.max(output.data, 1) 
        pred_list.append(pred.item())
print(time.time() - start)

提出用ファイルの作成

pred_list = np.array(pred_list)
ID_lists= np.arange(1, pred_list.shape[0]+1) 

submissions=pd.DataFrame({"ImageId": ID_lists,
                         "Label": pred_list})
submissions.to_csv("submissions.csv", index=False, header=True)

Kaggleのテスト結果

Kaggleでの、本番のテスト結果は、
0.98428
でした。

最高スコアが、1.00になっています。。。
全問正解、つまり、acc=100%

過学習なしのこの結果って。。。

Kernel見て、勉強します。。。

[amazonjs asin=”4873117984″ locale=”JP” title=”Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎”][amazonjs asin=”4295003379″ locale=”JP” title=”第2版Python 機械学習プログラミング 達人データサイエンティストによる理論と実践 (impress top gear)”]

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