ディープラーニング入門にぴったりな図形データセットで画像分類してみた

シェアする

  • このエントリーをはてなブックマークに追加
スポンサーリンク

はじめに

 今回も、Kaggleに公開されているデータセットを使っていきたいとおもいます。今回は、画像分類をkaggleのデータセットにあった図形のデータを使って行なっていきたいと思います。このデータセットには4つの図形の16,000の画像が含まれています。四角形、星形、円、三角形などがあります。このデータセット、MNISTの次に扱うのにいいのではないかと考え、今回はできる限りMNISTに近づけてあまり変更なく書けるようにしたいと思います。では、GoogleColaboratory上でskorchを使って画像分類をしていきたいと思います。

今回のデータセットのリンク

Four Shapes

合わせて読みたい記事:

データセットの説明

図形の種類

四角形、星形、円、三角形

データセットの内訳

  • 画像サイズ: 200×200
  • 画像枚数:4000×4=16000枚
  • グレイスケール画像
  • ファイルのフォーマット: png
  • 4クラス (四角形、星形、円、三角形)

ソースコード

表示→目次→ファイルをおすとGoogleColaboratory上のファイルを見ることができます。そしてアップロードの表示があると思うので、そこからファイルをアップロードできます。

データセット準備

まず、データセットを解凍していきます。

In[1]:

!unzip four-shapes.zip

In[2]:

!unzip shapes.zip

ディレクトリを扱いやすいように変えたいと思います。shapeというディレクトリを作り、その中に解凍してできたcircle、triangle、star、squareを放り込んでいきます。

In[3]:

!mkdir shape

In[4]:

!mv circle shape
!mv square shape
!mv triangle shape
!mv star shape

ライブラリの準備

PyTorch、skorchをインストールしておきます。

In[5]:

!pip install http://download.pytorch.org/whl/cu80/torch-0.4.1-cp36-cp36m-linux_x86_64.whl  !pip install torchvision

In[6]:

import torch  
import numpy as np  
import torch.nn as nn  
import torch.optim as optim  
import torch.nn.functional as F  
import torch.utils.data  
import torch.backends.cudnn as cudnn 
import torchvision  
from torchvision import datasets, models, transforms  
from sklearn.metrics import confusion_matrix, accuracy_score  
import random  
import os  
import time 
import skorch 
from skorch import NeuralNetClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report 
from PIL import Image 
import matplotlib.pyplot as plt 
% matplotlib inline

これをしないとGoogleColaboratory上でPIL周りでエラーを吐くのでやっておきます。

In[7]:

!pip install Pillow==4.0.0 
!pip install PIL 
!pip install image 
import PIL 
import image

データセットを変換

画像ディレクトリを指定し、Numpy配列のリストに変換します。今回、画像サイズは200×200でしたが、MNISTに近づけるため、28×28にリサイズしています。

In[8]:

from keras.preprocessing.image import load_img,img_to_array 
img_size = (28,28) 
dir_name = 'shape/' 
labels = os.listdir(dir_name) 
print(labels) 
temp_img_array_list = [] 
temp_label_array_list = [] 
for label in labels:
     img_list = dir_name + label+ '/'
     imgs = os.listdir(img_list)
     for img in imgs:
       img_path = img_list + img
       try:
         img = PIL.Image.open(img_path)
         img_resize = img.resize(img_size)
         temp_img_array = img_to_array(img_resize) /255
         temp_img_array_list.append(temp_img_array)
         temp_label_array_list.append(label)
       except:
         print('not_jpg')
X_train = np.array(temp_img_array_list)
Y_train = np.array(temp_label_array_list)

次に、Y_trainの中身がstring型で怒られてしまうので変えておきます。

In[9]:

from sklearn import preprocessing 
le = preprocessing.LabelEncoder()
le.fit(['star', 'circle', 'square', 'triangle']) 
Y_train = le.transform(Y_train)

X_trainも同様にreshapeしておきます。

In[10]:

X_train = X_train.reshape(-1, 1, 28, 28)
print(X_train.shape)

Out[10]:

(14970, 1, 28, 28)

適当に出力させてみましょう。

In[11]:

import random
for i in range(3):
    plt.imshow(random.choice(X_train).reshape(28, 28))
    plt.show()

Out[11]:

あとは、学習用と検証用にデータセットを8:2の割合で分けます。

In[12]:

x_train, x_test, y_train, y_test = train_test_split(X_train, Y_train, test_size=0.2, stratify=Y_train)

これで準備はOKです。

ネットワーク構成

今回使ったネットワークはこちらになります。

In[13]:

class Net(nn.Module):
         def __init__(self):
         super(Net, self).__init__()
         self.features = nn.Sequential(
             nn.Conv2d(1, 32, kernel_size=5, stride=1, padding=2),
             nn.ReLU(inplace=True),
             nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1),
             nn.BatchNorm2d(32),
             nn.ReLU(inplace=True),
             nn.MaxPool2d(kernel_size=2, stride=2),
             nn.Dropout(p = 0.25),
             nn.Conv2d(32, 64, kernel_size=3, stride=1,padding=1),
             nn.BatchNorm2d(64),
             nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
             nn.BatchNorm2d(64),
             nn.Conv2d(64, 128, kernel_size=3, stride=1,padding=1),
             nn.Conv2d(128, 128, kernel_size=3, stride=1,padding=1),
             nn.BatchNorm2d(128),
             nn.ReLU(inplace=True),
             nn.MaxPool2d(kernel_size=2, stride=2),
             nn.Dropout(p = 0.25),
         )
         self.classifier = nn.Sequential(
             nn.Dropout(p = 0.25),
             nn.Linear(128 * 7 * 7, 512),
             nn.ReLU(inplace=True),
             nn.Dropout(p = 0.25),
             nn.Linear(512, 10),
         )
     def forward(self, x):
         x = self.features(x)
         x = x.view(x.size(0), -1)
         x = self.classifier(x)
         return x 

gpu使えるようにしておきます。

In[14]:

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

学習

skorchで学習させる書き方はsklearnライクに書けるので楽でいいですね。理想としてはデータセット作りとネットワークをPyTorchのように書くことなんですが、PyTorchのデータセットでうまく学習させられない…

In[15]:

net = NeuralNetClassifier(
     model,
     optimizer=torch.optim.Adam,
     criterion=torch.nn.CrossEntropyLoss,
     max_epochs=3, 
    lr=0.01,  
    iterator_train__batch_size=32, 
    iterator_train__shuffle=True, 
    device='cuda', 
) 
net.fit(x_train, y_train) 
y_pred = net.predict(x_test) 
print(classification_report(y_test, y_pred))

色分けを見てほしくて画像にしてみました。値がうまく更新できたら色付けされていることがわかりますね。

Out[15]:

クロスバリデーション

クロスバリデーションもさせていきます。注意ですが、ネットワークを初期化して試してください。そうしないといきなりパラメータがフィットすることになります。

In[16]:

from sklearn.model_selection import cross_val_predict 
y_pred = cross_val_predict(net, x_train, y_train, cv=5)

Out[16]:

  epoch    train_loss    valid_acc    valid_loss     dur
-------  ------------  -----------  ------------  ------
      1        1.3434       0.9025        0.2016  4.2686
      2        0.1447       0.9943        0.0220  4.1791
      3        0.0807       1.0000        0.0003  4.1682
  epoch    train_loss    valid_acc    valid_loss     dur
-------  ------------  -----------  ------------  ------
      1        1.3261       0.5099        1.1078  4.1828
      2        0.2648       0.9755        0.0548  4.1691
      3        0.0663       0.7784        1.0881  4.1831
      4        0.0629       0.9917        0.0291  4.1789
      5        0.0475       0.5850        3.8713  4.2008
      6        0.0347       0.9995        0.0009  4.2212
      7        0.0270       0.9520        0.2029  4.1984
      8        0.0373       0.9969        0.0281  4.2047
      9        0.0420       0.9995        0.0027  4.1919
     10        0.0100       0.9995        0.0043  4.2012
  epoch    train_loss    valid_acc    valid_loss     dur
-------  ------------  -----------  ------------  ------
      1        1.3383       0.9447        0.2169  4.1576
      2        0.1343       0.8884        0.4438  4.1873
      3        0.1072       0.9964        0.0153  4.2117
      4        0.0481       0.9745        0.1041  4.1953
      5        0.0688       0.9948        0.0191  4.2305
      6        0.0357       0.9984        0.0050  4.1959
      7        0.0287       0.9995        0.0010  4.1960
      8        0.0564       0.9896        0.0414  4.1984
      9        0.0324       0.9990        0.0018  4.2019
     10        0.0220       0.9995        0.0017  4.2069
  epoch    train_loss    valid_acc    valid_loss     dur
-------  ------------  -----------  ------------  ------
      1        1.3012       0.6601        0.6910  4.1845
      2        0.2643       0.9896        0.0403  4.1900
      3        0.2043       0.7518        0.9719  4.1919
      4        0.1427       0.9875        0.0600  4.1880
      5        0.0916       0.9948        0.0533  4.2025
      6        0.0571       0.9953        0.0396  4.2266
      7        0.0462       0.9979        0.0122  4.2185
      8        0.0506       0.9953        0.0130  4.2337
      9        0.0330       0.7643        1.9964  4.2049
     10        0.0609       0.9995        0.0014  4.1858
  epoch    train_loss    valid_acc    valid_loss     dur
-------  ------------  -----------  ------------  ------
      1        1.1768       0.7138        0.8318  4.1600
      2        0.1820       0.9473        0.1309  4.1634
      3        0.0486       0.9984        0.0041  4.1864
      4        0.0410       0.9802        0.0507  4.1888
      5        0.0582       0.9990        0.0041  4.1932
      6        0.0102       0.9995        0.0007  4.1938
      7        0.0516       0.9943        0.0153  4.1946
      8        0.0559       0.9995        0.0017  4.1843
      9        0.0049       0.9995        0.0009  4.1889
     10        0.0053       0.9995        0.0015  4.1871

モデル保存

今回学習してできたモデルを保存しておきましょう。

import pickle
filename = "shape_model.pkl"
with open(filename, "wb") as f:
    pickle.dump(model, f)

ローカルにダウンロードしておきます。

from google.colab import files
files.download('shape_model.pkl')


いかがだったでしょうか。この図形のデータセットはすごく入門にぴったりだと思うのでぜひ使ってみてください。

最後まで読んでいただきありがとうございました。よろしければこの記事をシェアしていただけると励みになります。よろしくお願いします。

スポンサーリンク
レクタングル広告(大)
レクタングル広告(大)

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク
レクタングル広告(大)