第2回 Kerasで実践! Cats vs. Dogs (4/6)

技術特集

1_tensorflow_keras1_tit

tit_tensorflow_keras

4) 学習をやってみる

学習した結果を利用する部分の実装はさておき、とりあえず学習を実行してみましょう。

データの取得と準備

犬と猫の判別をディープラーニングするには、大量の犬の画像と、大量の猫の画像が必要になります。
今回は、Kaggleというサイトで奇遇にも目的にぴったりのデータセットが配布されていますので、利用させてもらいましょう。

データは下記URLから取得可能です。
https://www.kaggle.com/c/dogs-vs-cats/data
ダウンロードするにはKaggleのアカウントを作成する必要があります。
Kaggleにサインインしたあとに「train.zip」をクリックし、「Download」ボタンを押します。

train.zipを解凍すると、「dog.123.jpg」「cat.123.jpg」のような画像ファイルが合計25000枚得られます。
上述の通り、今回は下記のようなディレクトリ構造になるようにデータを準備していきます。

    ./
    cat_dog_dnn_keras.py
    mydnn_keras.py
    data/
        train/ →学習データを格納
            cat/ →学習データのうち猫の画像を格納
            dog/ →学習データのうち犬の画像を格納
        valid/ →検証データを格納
            cat/ →検証データのうち猫の画像を格納
            dog/ →検証データのうち犬の画像を格納

手作業で準備してもよいのですが、自動で画像を振り分けるスクリプトを作成しましたのでご利用ください:

import os
import re
import random
 
random.seed(873675312)
 
source_dir = "./train"
train_dir = "./data/train"
valid_dir = "./data/valid"
 
os.makedirs("%s/dog" % train_dir)
os.makedirs("%s/cat" % train_dir)
os.makedirs("%s/dog" % valid_dir)
os.makedirs("%s/cat" % valid_dir)
 
source_files = os.listdir(source_dir)
source_dog = [f for f in source_files if re.match('dog', f)]
source_cat = [f for f in source_files if re.match('cat', f)]
 
random.shuffle(source_dog)
random.shuffle(source_cat)
 
# 検証データとして1000枚使用
for d, c in zip(source_dog[:1000], source_cat[:1000]):
    os.rename("%s/%s" % (source_dir, d),
              "%s/dog/%s" % (valid_dir, d))
    os.rename("%s/%s" % (source_dir, c),
              "%s/cat/%s" % (valid_dir, c))
 
# 残りを学習データとして利用
for d, c in zip(source_dog[1000:], source_cat[1000:]):
    os.rename("%s/%s" % (source_dir, d),
              "%s/dog/%s" % (train_dir, d))
    os.rename("%s/%s" % (source_dir, c),
              "%s/cat/%s" % (train_dir, c))

cat_dog_dnn_keras.pyと同じ階層に

  • train.zipを解答したtrainディレクトリ
  • move_data.py

を配置し、move_data.pyを実行すると、全データから犬と猫の画像それぞれ1000枚を検証データとして抜き出した上で今回必要なディレクトリ構造を構成します。

さあ、これで準備は整いました!

学習の実行

操作としてはcat_dog_dnn_keras.pyを実行するのみです。
実行すると以下のようなログが出るでしょう(環境により他のメッセージがまじることもあります)。

$ python cat_dog_dnn_keras.py
Using TensorFlow backend.
学習モード
Found 23000 images belonging to 2 classes.
Found 2000 images belonging to 2 classes.
Epoch 1/10
1150/1150 [==============================] - 44s - loss: 0.7404 - acc: 0.6617 - val_loss: 0.5359 - val_acc: 0.7435
Epoch 2/10
1150/1150 [==============================] - 43s - loss: 0.4934 - acc: 0.7605 - val_loss: 0.4790 - val_acc: 0.7675
Epoch 3/10
1150/1150 [==============================] - 43s - loss: 0.4271 - acc: 0.8034 - val_loss: 0.4617 - val_acc: 0.7910
Epoch 4/10
1150/1150 [==============================] - 43s - loss: 0.3885 - acc: 0.8261 - val_loss: 0.4276 - val_acc: 0.8000
Epoch 5/10
1150/1150 [==============================] - 43s - loss: 0.3521 - acc: 0.8467 - val_loss: 0.4939 - val_acc: 0.7855
Epoch 6/10
1150/1150 [==============================] - 43s - loss: 0.3255 - acc: 0.8578 - val_loss: 0.4387 - val_acc: 0.8180
Epoch 7/10
1150/1150 [==============================] - 43s - loss: 0.3003 - acc: 0.8742 - val_loss: 0.3833 - val_acc: 0.8310
Epoch 8/10
1150/1150 [==============================] - 43s - loss: 0.2760 - acc: 0.8843 - val_loss: 0.3847 - val_acc: 0.8315
Epoch 9/10
1150/1150 [==============================] - 43s - loss: 0.2501 - acc: 0.8965 - val_loss: 0.4182 - val_acc: 0.8050
Epoch 10/10
1150/1150 [==============================] - 43s - loss: 0.2172 - acc: 0.9098 - val_loss: 0.3793 - val_acc: 0.8355

先にも触れましたが、Epochというのは学習データ全体を一巡する量の処理を示します。
何Epoch分処理を回せばよいかというのはデータ量や処理の複雑さなどさまざまな条件で変化するため、
基本的には各種の評価値の推移を観察し、これ以上学習しても精度が上がらないだろうというところで処理を打ち切るというのがセオリーです。

出力を読み解く

上記のログで注目したいのは「acc」と「val_acc」という値です。
これはどちらも正解率、つまり今回の場合は犬と猫の分類が正しく出来た割合を示します。
「acc」は学習精度、つまり学習データにおける正解率であり、この値が1に近づいていくことで、学習が進捗していることが確認できます。
「val_acc」は検証精度、つまり検証データにおける正解率を示します。学習済みモデルを実戦に投入した際にはこの程度の正解率が期待できるという目安です。

基本的な傾向として、学習精度はどんどん1に近づいていきますが、
検証精度はある一定のところで打ち止めになります。またやりすぎると逆に悪くなっていくこともあります。
上記のログを見ると、学習精度はどんどん上がっていますが、Epoch 7あたりから検証精度の改善が鈍っていることが見て取れます。
もう少し続けても良いがそろそろ打ち切ってもいいかな、という微妙な状況です。

今回は「とりあえずKerasでディープラーニングができること」が目的ですので、8割の精度でよしとすることにします。
さらに精度を上げたい場合には、以下のような方策をとることになります:

  • 学習データを増やす(新規追加する、加工によって増幅する)
  • Epoch数を増やしてみる
  • DNNの構造を変更する(層を増やす、層を広げる、正則化などのテクニックを加える etc.)