kaggleチャレンジ 10日目 花のデータセットを使ってPytorchで画像分類をしてみた

シェアする

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

はじめに

 今回は、いつもとは異なり、コンペではなく、Kaggleに公開されているデータセットを使っていきたいとおもいます。今回は、画像分類をkaggleのデータセットにあった花のデータを使って行なっていきたいと思います。

また、今回はSkorchを使って実装していきたいと思います。Skorchとは、PyTorchのsklearnラッパーで、sklearnのインターフェースでPyTorchを使うことができます。

Skorchで実装しようとしましたが、データセット周りでうまく動かせなかったのでまた違うときにやりたいと思います。(文献少なすぎる)

ということで、今回は、GoogleColaboratory上でPytorchを使って画像分類をしていきたいと思います。

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

Flowers Recognition

関連のおすすめ記事:

Kaggleチャレンジ8日目 pytorchでフルーツの画像分類をしてみた

データセットの説明

スタイルの種類

  • カモミール
  • チューリップ
  • バラ
  • ヒマワリ
  • タンポポ

各クラス約800枚ずつ

データセットの内訳

  • 総画像数:4323
  • 画像サイズ:約320×240ピクセル

ソースコード

綺麗なコードではありませんが許してください。

データの準備

GoogleColaboratory上にzipファイルを共有して解凍しましょう。

!pip install pydrive
from pydrive.auth import GoogleAuth 
from pydrive.drive import GoogleDrive 
from google.colab import auth 
from oauth2client.client import GoogleCredentials 
auth.authenticate_user() 
gauth = GoogleAuth() 
gauth.credentials = GoogleCredentials.get_application_default() 
drive = GoogleDrive(gauth)
id = '*****************' # 共有リンクで取得した id= より後の部分を*の部分に入力 
downloaded = drive.CreateFile({'id': id}) 
downloaded.GetContentFile('flower.zip') #ファイルの名前

!unzip flower.zip

これで、flowersというファイルができたと思います。表示タブの目次でファイルを選択することで、現在のディレクトリの中身を見ることができます。

Pytorchのインストール

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

torchsummaryも一緒に入れときましょう。

!pip install torchsummary

ライブラリの準備

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 torchsummary import summary 
import torchvision from torchvision 
import datasets, models, transforms 
from sklearn.metrics import confusion_matrix, accuracy_score 
import random 
import os 
import time

学習したモデルを保存、読み込む関数

def save_checkpoint(path, epoch, model):
 	save_path = os.path.join(path, "model_epoch_{}.pkl".format(epoch))
 	torch.save(model.state_dict(), save_path)
 	print("Checkpoint saved to {}".format(save_path))

 def load_checkpoint(model_dir,epoch,model):
     load_path = os.path.join(model_dir,"model_epoch_{}.pkl".format(epoch))
     checkpoint = torch.load(load_path)     model.load_state_dict(checkpoint)
     print("Checkpoint loaded to {}".format(load_path))

初期化

np.random.seed(1) 
random.seed(1) 
torch.manual_seed(1) 
torch.cuda.manual_seed(1)

ネットワーク設定

今回、すぐに精度が高くなったのでエポック数を少なくしてあります。

batchsize = 32 
epochs = 10 
epoch_start =1

GPU

use_gpu = torch.cuda.is_available()
 if use_gpu:
     print("cuda is available!")
     cudnn.benchmark = True
     cudnn.deterministic = True

モデルの保存フォルダ

checkout_dir = "./checkout" 
if os.path.exists(checkout_dir) is False:
     os.mkdir(checkout_dir)

ネットワーク

今回クラス数が5なので出力数を変えています。

n_classes = 5
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 
model = models.resnet18(pretrained=True).to(device) 
n_filters = model.fc.in_features 
model.fc = nn.Linear(n_filters, n_classes)
if use_gpu:
    model.cuda()

モデル読み込み(学習再開)

もし、学習を中断してしまった場合、Trueにし、再開するエポック数を入れることで再開できます。

model_load = True 
if model_load:
     epoch_start = 2
     load_checkpoint(checkout_dir,epoch_start,model)

オプティマイザ

optimizer = optim.SGD(model.parameters(), lr=1e-2, momentum=0.9, weight_decay=5e-4)
use_scheduler = False
if use_scheduler:
    scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.1)

クロスエントロピー

今回は分類タスクなので、CrossEntropyLoss()を使います。

criterion = nn.CrossEntropyLoss()

PILエラー

GoogleColaboratoryには、現在特有のバグみたいなものがあるらしく、PILで画像を開こうとするとエラーを吐きます。そのため、次のコードを使ってください。

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

データセット

今回、データセットが学習データとテストデータに分かれていないので、random_splitを使って分けていきます。

data_transform = transforms.Compose([
 transforms.Resize([224, 224]), transforms.RandomHorizontalFlip(),
 transforms.ToTensor(),
 transforms.Normalize((0.4914, 0.4822, 0.4465),
 (0.2023, 0.1994, 0.2010)), 
]) 
full_Dataset = datasets.ImageFolder(root='flowers',transform=data_transform) 
print(len(full_Dataset)) 
train_size = int(0.8 * len(full_Dataset)) 
test_size = len(full_Dataset) - train_size 
train_Dataset, test_Dataset = torch.utils.data.random_split(full_Dataset, [train_size, test_size]) 
print(len(train_Dataset)) 
print(len(test_Dataset)) 
train_loader = torch.utils.data.DataLoader(train_Dataset,batch_size=batchsize, shuffle=True) 
test_loader = torch.utils.data.DataLoader(test_Dataset,batch_size=batchsize, shuffle=False) 
print("train images: {}".format(len(train_Dataset)))
print("test images: {}".format(len(test_Dataset))) 
print("epoch: {}".format(epochs))
print("batch size: {}".format(batchsize))

train関数

def train(model, train_loader,epoch):
   model.train()
   print('\nEpoch: %d' % epoch)
   train_loss = 0
   correct = 0
   total = 0
   if use_scheduler:
     scheduler.step()
   for batch_idx, (image, label) in enumerate(train_loader):
     image, label = image.to(device), label.to(device)
     optimizer.zero_grad()
     outputs = model(image)
     loss = criterion(outputs, label)
     loss.backward()
     optimizer.step()
     train_loss += loss.item()
     _, predicted = outputs.max(1)
     total += label.size(0)
     correct += predicted.eq(label).sum().item()
   print('Loss:{} | Acc:{} ({}/{})'.format((train_loss/(batch_idx+1)), 100.*correct/total, correct, total))

test関数

def test(model, test_loader,epoch):
   model.eval()
   running_loss = 0
   test_loss = 0
   correct = 0
   total = 0
   for batch_idx,(image, label) in enumerate(test_loader):
     image, label = image.to(device), label.to(device)
     outputs = model(image)
     loss = criterion(outputs, label)
     test_loss += loss.item()
     _, predicted = outputs.max(1)
     total += label.size(0)
     correct += predicted.eq(label).sum().item()
   print('Loss:{} | Acc:{} ({}/{})'.format((test_loss/(batch_idx+1)), 100.*correct/total, correct, total))

evaluation関数

def evaluation(model_dir,epoch,model,test_loader):
     load_checkpoint(model_dir,epoch,model)
     model.eval()
     y_test = []
     y_pred = []
     for batch_idx,(image, label) in enumerate(test_loader):
         image, label = image.to(device), label.to(device)
         outputs = model(image)
         _, predictions = outputs.max(1)
         y_test.append(label.data.cpu().numpy())
         y_pred.append(predictions.data.cpu().numpy())
     y_test = np.concatenate(y_test)
     y_pred = np.concatenate(y_pred)
     print(accuracy_score(y_test, y_pred))

ネットワーク表示

summary(model, (3, 224, 224))      

学習

train_loss_log = [] 
test_loss_log = [] 
train_acc_log = [] 
test_acc_log = [] 
for epoch in range(epoch_start, epochs+1):
   train_loss,train_acc= train(model, train_loader,epoch)
   test_loss,test_acc = test(model, test_loader,epoch)
   train_loss_log.append(train_loss)
   test_loss_log.append(test_loss)
   train_acc_log.append(train_acc)
   test_acc_log.append(test_acc)
   save_checkpoint(checkout_dir, epoch, model)
 evaluation(checkout_dir,epochs,model,test_loader)

結果表示

import numpy as np 
import matplotlib.pyplot as plt 
epoch = range(1,11)
plt.plot(epoch, train_loss_log, marker = 'o',label = 'train') 
plt.plot(epoch, test_loss_log, marker = 'x',label = 'test') 
# plt.xticks(epoch, months) 
plt.xlim(0, 11) 
plt.ylim(0, 1) 
plt.xlabel('epoch', fontsize = 16) 
plt.ylabel('loss', fontsize = 16) 
plt.tick_params(labelsize=14) 
plt.grid(True) 
plt.legend(loc = 'upper right') 
plt.show()

import numpy as np 
import matplotlib.pyplot as plt 
epoch = range(1,11) 
plt.plot(epoch, train_acc_log,label = 'train') 
plt.plot(epoch, test_acc_log,label = 'test') 
# plt.xticks(epoch, months) 
plt.xlim(0, 11)
plt.ylim(80, 100) 
plt.xlabel('epoch', fontsize = 16) 
plt.ylabel('accuracy', fontsize = 16) 
plt.tick_params(labelsize=14) 
plt.grid(True) 
plt.legend(loc = 'upper right') 
plt.show()


もっとスマートなコードを書きたい…

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

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

シェアする

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

フォローする

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