人工知能に関する断創録

このブログでは人工知能のさまざまな分野について調査したことをまとめています(更新停止: 2019年12月31日)

VGG16のFine-tuningによる犬猫認識 (1)

VGG16はILSVRCのコンペ用に学習されたニューラルネットなのでImageNetの1000クラスを認識できる。しかし、前の記事(2017/1/4)で実験したように「ひまわり」のようなImageNetに存在しないクラスはそのままでは認識できない。

この問題を解決するためVGG16の高い認識能力を継承しつつ、新しい独自のクラス(今回は犬か猫かの2クラス)を認識できるように少量のデータでニューラルネットの重みを再調整することをFine-tuningという*1。「少量のデータで」というところがすごく重要。もし大量データでないとダメだったらAWSの利用料で破産するのでこの記事は書けない(^^;;

今回は、Keras Blogの - Building powerful image classification models using very little dat を参考に犬と猫の2クラス認識を例としてVGGのFine-tuningについて実験した。このKeras Blogの記事はKeras 1.2.0の公開より前に書かれており、keras.applications.vgg16が使われていない。この記事ではKeras 1.2.0に合わせて一部を書き直した。

リポジトリ:dogs_vs_cats

セットアップ

タスクは犬と猫の分類。犬か猫の画像をニューラルネットに入力して犬または猫を出力する2クラス分類のタスク。ILSVRCの1000クラス分類に比べたらずっと簡単だけどVGG16は1000クラス分類のニューラルネットなので犬と猫の2クラス分類はそのままではできない。

f:id:aidiary:20170107203445j:plain
Dogs vs. Cats Redux: Kernels Edition | Kaggle

このデータセットはKaggleのDogs vs. Catsで提供されているためダウンロードするにはKaggleに登録する必要がある*2

訓練データのtrain.zipを解凍すると犬の画像が12500枚、猫の画像が12500枚含まれている。解凍してしばらく癒されてた(笑)

今回は、小規模データを使ったFine-tuningの実験なのでここから犬1000枚、猫1000枚を訓練データ、犬400枚、猫400枚をバリデーションデータとして用いた。テストデータのtest.zipは正解ラベルが付いていなかったので今回は使わない。正解ラベルがついてたらコンテストにならないからだと思われる。

train.zipを解凍するとtrainディレクトリができる。その後にsetup.pyを実行すると下のようにデータを振り分けられる。

data
├── train
│   ├── cats   cat0001.jpg - cat1000.jpg
│   └── dogs   dog0001.jpg - dog1000.jpg
└── validation
    ├── cats   cat0001.jpg - cat0400.jpg
    └── dogs   dog0001.jpg - dog0400.jpg

分類クラスごとにサブディレクトリ(ここではcatsdogs)を作るのが重要。KerasのImageDataGeneratorが自動的にcats/dogsをクラス名と認識してくれるのだ。

Kerasで画像ファイルを直接ロード

これまでMNIST(2016/11/9)やCIFAR-10(2016/11/27)のようにPythonのNumPy array形式のデータを直接ダウンロードできる例ばかり扱ってきた。今回は、NumPy arrayのデータは提供されておらず、画像ファイルしか提供されていない。このようなケースでは、先にデータ拡張(2016/12/12)で使ったImageDataGeneratorが非常に役立つ。このクラスにはディレクトリを指定するとそこの画像ファイルを読み込む関数が提供されている。

下のような感じで使う。

    # 訓練データとバリデーションデータを生成するジェネレータを作成
    train_datagen = ImageDataGenerator(
        rescale=1.0 / 255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)

    test_datagen = ImageDataGenerator(rescale=1.0 / 255)

    train_generator = train_datagen.flow_from_directory(
        'data/train',
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')

    validation_generator = test_datagen.flow_from_directory(
        'data/validation',
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')
  • ImageDataGeneratorでどのような画像拡張をするかオプションで指定できる。
  • flow_from_directory()に画像が含まれるディレクトリ名を指定してジェネレータを作成。このディレクトリに含まれる画像が「種画像」になる。
  • 指定したディレクトリの下にクラスごとにディレクトリ(dogs/cats)を作っておくとクラスも認識する。
  • 画像ファイルのサイズが異なっていてもtarget_sizeで指定した大きさにリサイズする。
  • 今回はcats/dogsの2クラス分類なのでclass_modeにはbinaryを指定する。あとで別の例を紹介するが多クラス分類の場合はcategoricalを指定する。

あとはこのジェネレータが4Dテンソル形式(samples, rows, cols, channels)に変換した画像データをじゃんじゃん生成してくれるのだ!実際には自分で生成する必要さえなく、下のように訓練用の関数fit_generator()にジェネレータを渡すだけでよい。これは楽できていいね。画像の読み込みとか地味に面倒だから。

    # 訓練
    history = model.fit_generator(
        train_generator,
        samples_per_epoch=2000,
        nb_epoch=nb_epoch,
        validation_data=validation_generator,
        nb_val_samples=800)

三種類の方法を比較

前置きが長かったけどここからが本題。次の3つのニューラルネットを学習して精度を比較してみたい。

  1. 小さな畳み込みニューラルネットをスクラッチから学習する
  2. VGG16が抽出した特徴を使って多層パーセプトロンを学習する
  3. VGG16をFine-tuningする

ちょっと長くなりそうなので次回へ。

参考

*1:Fine-tuningは転移学習(transfer learning)とも呼ばれる。音声分野だと似たような技術は適応(adaptation)と呼ぶけど関連あるのかしら?今回の話は平均声と話者適応の関係に似ていると思った。

*2:このタスクでKaggleに興味が出てきたので初めて登録した