文書の過去の版を表示しています。
画像分類
はじめに
DeepLearningによる画像分類タスクの実験です。 ResNet50を使って、画像分類を行ないます。
今回は下記の2種類のタスクを行ないました。 予想通り前者は難しく学習が安定しなかったので、後者のタスクを加えました。
- イラストの著者分類
- イラストのキャラクター分類
環境はGoogle Colabを利用します。 毎回データをアップロードするのが手間だったりしますが、実験用途で使う分には、トータルで利便が勝ります。
データの準備
ResNet50に入力できる画像のサイズは224×224となります。そのためイラスト全体を使用すると縦横比がおかしくなったり、細かいパーツやタッチに関する情報が潰れてしまう懸念がありました。そこで学習の対象を「顔」のみとするべく、縦横1対1の比率で切り抜きを行ないました。画像サイズは学習時の事前処理でリサイズするので、この段階で揃えません。
著者分類では、自分が描いたイラストとその他の著者が描いたイラストを約50枚ずつ用意しました。描かれているキャラクターはある程度重複するようにしています。
Google Colabへのアップロードは、ファイル単位のみみたいなので、ローカルでzip圧縮してからアップロードして、Google Colab上で展開しました。
!unzip data.zip
自分が描いたイラストはサンプルとして提供しても良いのですが、他人が描いたイラストの方は当然提供できないので、保留します。
ライブラリインストール
標準では入っていないライブラリを利用するので、インストールしておきます。
pip install pytorch-gradcam
学習モデルの用意
ここからコーディングとなります。まずは学習モデルを用意します。 torchvisionから構築済のResNet50モデルを利用できます。 さらにImageNetで事前学習した重みも利用可能ですが、今回は汎用課題を対象としていないので、事前学習の重みは使いません。
import torch import torch.nn as nn import torch.optim as optim import torchvision from torchvision.models import ResNet50_Weights import torchvision.models as models import torchvision.transforms as transforms from PIL import Image import os import pickle from sklearn.metrics import accuracy_score def get_device(): if torch.cuda.is_available(): return torch.device('cuda') else: return torch.device('cpu') device= get_device() # 学習済の重みは使わないので、引数でWeight指定なし model = models.resnet50().to(device)
学習モデルの構造を確認
下記で学習モデルの構造を確認できます。 動作させる上で必須ではありませんが、後段で学習モデル内の特定の層を指定する必要があるので、ここで情報を出力しておきます。
from torchvision.models import feature_extraction feature_extraction.get_graph_node_names(model) model
データセットとデータローダの用意
学習データを扱えるように、データセットとデータローダを用意します。 データセットは生データと正解ラベルを構造化するもので、自前で用意する必要があるのですが、 torchvisionのImageFolder機能を使えば、自動的にデータセットを作成してくれます。 正解ラベル名のフォルダの配下にそのラベルと対応する画像を入れる、というルールに従って、データセットのフォルダを用意すれば、簡単にデータセットが作れます。
データローダはデータセットを指定して、ミニバッチ数やシャッフルの有無など、データの提供方法をパラメータで調整します。 併せて、画像に対する事前処理も実施します。 この事前処理にあるNormalize(正規化)の値は、今回はスクラッチ学習のため、全チャネルについて平均と標準偏差を0.5に設定します。 事前学習済モデルを用いる場合は、そのモデルが使用したデータセットに適した値を設定する必要があります。 正規化をすると色合いがおかしくなりますが、正規化しないと学習精度が割と大きく悪化しますので、設定が必要です。
# 画像に対する事前処理 # ResNet50向けに、224*224にリサイズする preprocess = transforms.Compose([ transforms.Resize(224), transforms.ToTensor(), transforms.Normalize( mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5] ) ]) train_image_dir = './data/train' test_image_dir = './data/test' train_dataset = torchvision.datasets.ImageFolder(root=train_image_dir, transform=preprocess) test_dataset = torchvision.datasets.ImageFolder(root=test_image_dir, transform=preprocess) batch_size = 2 train_dataLoader = torch.utils.data.DataLoader( train_dataset, batch_size=batch_size, shuffle=True ) test_dataLoader = torch.utils.data.DataLoader( test_dataset, batch_size=batch_size, shuffle=False )
考察
著者分類は全く上手くいきませんでしたが、自分以外の著者のイラストについて、特定の著者に統一しなかったことが学習が安定しなかった原因かもしれません。まあ、元々難しいタスクなので、それだけが原因とは思いません。しかし、自分以外の著者のイラストの範囲が広すぎて、自分に近い画風の人とかけ離れた画風の人があった場合、上手くいかないように思えます。
