python

keras初心者チュートリアル【No.3 ファインチューニング】~CNNで車種判別モデルを作成~

このチュートリアルを一通り行うことで、

超初心者
超初心者
pythonってなに?ディープラーニングって美味しいの?

 

というレベルから

自分でモデル作れます!転移学習、ファインチューニングできます!

モデルの中身を可視化できます!

 

という状態になってもらえたらと思っています。

はじめに

本チュートリアルは、具体的な理解よりも、直感的な理解をして頂くことを目的としています。そのため、厳密性よりも、わかりやすさを優先した表現をすることをご了承願います。

本チュートリアルの対象者

友人
友人
  • if, for, 関数, 変数など基本的なプログラミングに関する知識は記憶の彼方にわずかにあるが、pythonおよびディープラーニングに関する知識は全く無い。
  • だけれども、ディープラーニングに興味がある!
  • 自力でモデルを作って評価して、またモデルを作ってという一連の流れを身につけたい!!

 

みたいな方にオススメです。

参考図書

チュートリアルを作成するに当たって参考にさせて頂いた本です。

この本は、個人的にかなりおすすめの本です。

理論的な部分と、実践的な部分が半々です。

しかも、コンピュータビジョン、自然言語、画像生成と幅広く対応しているので、いろんな分野を触って勉強してみたい!という方に向いていると思います。

本チュートリアルで扱う問題

「車の画像から、その画像に写っている車種を当てる」という問題を解くためにモデルを作成します。

本チュートリアルの構成

  1. 自作モデルで車種当て問題をといてみよう!
  2. 転移学習で車種当て問題をといてみよう!
  3. ファインチューニングで車種当て問題をといてみよう!
  4. 完成したモデルをテストデータで評価してみよう!
  5. 精度の高いモデルと低いモデルの違いを覗いてみよう!

 

本記事は3について解説をします。

全てのコードは僕のgithubに上がっているのでcloneをしていただければ実行することが可能です。

今回のコードはこちらこちらです。

 

それでは、チュートリアルを始めます!

3. ファインチューニングで車種当て問題を解いてみよう!

3-1. ファインチューニングとは?

ファインチューニングとは、学習済みモデルをベースに、出力層などを変更したモデルを構築し、自前のデータでニューラルネットワーク・モデルの結合パラメータを学習させる方法です。結合パラメータの初期値には学習済みモデルのパラメータを使用します。

広くデータが取得できる領域で学習したモデルを、データの収集が困難な別の領域に適応させる、などの使い方が可能です。

イメージとしては、

めっちゃ勉強した人なら、練習問題何回か解けばバリバリ解けるでしょ!

というやつです。(雑すぎて怒られそう)

図にするとこんな感じです。

転移学習ではたたみ込み層の重みの更新はしませんでしたが、ファインチューニングではたたみ込み層も重みの更新をします。

一般的に、画像から特徴を取り出す際、たたみ込み層の前半で輪郭や濃淡など外観の情報を、たたみ込み層の後半でこれはAudiぽい部分、TOYOTAぽい部分という抽象的な情報を抽出します。

そのため、たたみ込み層の前半は多くの画像分類問題に対して有効なフィルタの形状をしているので、ほとんど変化させないです。

ですが、後半部分はその問題特有の形状になってほしいので、パラメータの更新を行います。

パラメータの更新をする際、元の形状から劇的な変化をしてほしくないので、lr (learning rate) は通常時よりもかなり小さく設定します。

ファインチューニングは微調整というイメージです。

データセット、及び、使用する学習済みモデルは2章と同じなので省略します。

3-2. ファインチューニングの手順

  • 訓練済みたたみ込み層の最後に全結合分類器を追加する
  • たたみ込み層を凍結する
  • 追加した部分の訓練を行う
  • たたみ込み層の一部を解凍する
  • 凍結した層と追加した部分の訓練を同時に行う

大きくわけて5つの段階に分かれます。

ちなみに、2章の8の部分で上の3つ目までが終わっています!

まだ、2-8を行っていない人は2-8から実行をしてみてください。

 

それでは、ファインチューニングを実装していきます。

3-3. block5をファインチューニング

ライブラリのインポートと定数の定義

from keras.applications import VGG16
from keras.layers import Dense, GlobalAveragePooling2D,Input
import os.path,sys
from keras.models import Model
from keras.applications.vgg16 import VGG16
from keras.preprocessing.image import ImageDataGenerator
import keras.callbacks
from keras.applications import VGG16
from keras.optimizers import Adam
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import codecs
import pickle, json

N_CATEGORIES  = 20
IMAGE_SIZE = 256
BATCH_SIZE = 16

mini_metadata = pd.read_csv('mini_metadata.csv',index_col=0)
classes = list(mini_metadata["make_model"].value_counts().index)
classes = sorted(classes)
classes_num = len(mini_metadata.groupby("make_model"))

base_dir = 'mini_pictures'

train_dir = os.path.join(base_dir,'train')
valid_dir = os.path.join(base_dir,'valid')
test_dir = os.path.join(base_dir,'test')

from keras import models
from keras import layers
from keras.layers import Dense, GlobalAveragePooling2D,Input


pictures_files = os.listdir(train_dir)
NUM_TRAINING = 0
NUM_VALIDATION = 0
for i in range(classes_num):
    NUM_TRAINING += len(os.listdir(os.path.join(train_dir, pictures_files[i])))
    NUM_VALIDATION += len(os.listdir(os.path.join(valid_dir, pictures_files[i])))
print(NUM_TRAINING,NUM_VALIDATION)
1912 657


転移学習をしたモデルを読み込む

model = models.load_model('models/VGG16_mini_3.h5') 
model.summary()
Model: "model_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_4 (InputLayer)         (None, 256, 256, 3)       0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 256, 256, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 256, 256, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 128, 128, 64)      0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 128, 128, 128)     73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 128, 128, 128)     147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 64, 64, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 64, 64, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 32, 32, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 32, 32, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 16, 16, 512)       0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 8, 8, 512)         0         
_________________________________________________________________
global_average_pooling2d_5 ( (None, 512)               0         
_________________________________________________________________
dense_8 (Dense)              (None, 1024)              525312    
_________________________________________________________________
dense_9 (Dense)              (None, 20)                20500     
=================================================================
Total params: 15,260,500
Trainable params: 545,812
Non-trainable params: 14,714,688
_________________________________________________________________

最後の分類器以外は凍結されていることが分かります。

 

たたみ込み層の一部を解凍する

ファインチューニングのために、block5_conv1 (Conv2D)よりも下の部分を解凍します。

ちなみに、コンパイルをしないと、凍結や解凍をしてもsummaryをしたときに反映がされないので注意してください!

model.trainable = True

set_trainable = False
for layer in model.layers:
    if layer.name == 'block5_conv1':
        set_trainable = True
    if set_trainable:
        layer.trainable = True
    else:
        layer.trainable = False     

#コンパイルをしないとsummaryをしても反映されないので注意
model.compile(optimizer=Adam(lr=1e-5),#学習率が低いのはファインチューニングを行う3つの層の変更を制限するため
             loss='categorical_crossentropy',
             metrics=['acc'])
model.summary()

Model: "model_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_4 (InputLayer)         (None, 256, 256, 3)       0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 256, 256, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 256, 256, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 128, 128, 64)      0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 128, 128, 128)     73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 128, 128, 128)     147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 64, 64, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 64, 64, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 32, 32, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 32, 32, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 16, 16, 512)       0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 8, 8, 512)         0         
_________________________________________________________________
global_average_pooling2d_5 ( (None, 512)               0         
_________________________________________________________________
dense_8 (Dense)              (None, 1024)              525312    
_________________________________________________________________
dense_9 (Dense)              (None, 20)                20500     
=================================================================
Total params: 15,260,500
Trainable params: 7,625,236
Non-trainable params: 7,635,264
_________________________________________________________________

 

凍結した層と追加した分類器の訓練を同時に行う

学習の部分はいつもと同じです。

モデルと学習過程の記録は保存する様にしましょう!

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(
    rescale=1./255,
)

# 検証データは水増しするべきで無いことに注意
test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
    train_dir,               #ターゲットディレクトリ
    target_size=(IMAGE_SIZE,IMAGE_SIZE),   #全ての画像を256*256に変換
    batch_size=BATCH_SIZE,           #バッチサイズ
    class_mode='categorical',#損失関数としてcategorical_crossentropyを使用するため,
    classes=classes          #他クラスラベルが必要
    )

validation_generator = test_datagen.flow_from_directory(
    valid_dir,               #ターゲットディレクトリ
    target_size=(IMAGE_SIZE,IMAGE_SIZE),   #全ての画像を256*256に変換
    batch_size=BATCH_SIZE,           #バッチサイズ
    class_mode='categorical',#損失関数としてcategorical_crossentropyを使用するため,
    classes=classes          #他クラスラベルが必要
    )

history = model.fit_generator(train_generator,
                             steps_per_epoch=NUM_TRAINING//BATCH_SIZE,
                             epochs=30,
                             validation_data=validation_generator,
                             validation_steps=NUM_VALIDATION//BATCH_SIZE)

with open('histories/history_VGG16_mini_extended_fine12.pkl', 'wb') as f:
    pickle.dump(history.history, f)
    
model.save('models/VGG16_mini_extended_fine12.h5')


順調にtrainのlossが減少していることが分かります。

結果をグラフから評価する

転移学習をしたときと比較をして、validのlossも正解率も良くなりました。

ですが、グラフで見るとまだvalidとtrainの差はあるように見えます。

ここから精度を高めるか、それとも実験を終了するかという判断は、なぜこの問題を解くのかという目的によると思います。

 

少し話しは逸れますが、人工知能もプログラミングも課題を解決するための手段であって最終的な目的ではないということを考えさせられます。

実験を行っているとつい楽しくなって、

もっといい結果を出すためには何ができるだろうか。あれも、これも試してみたい!

という状態になってしまいまいます。

ですが、僕らは実験を始める前に冷静になって、この実験の目的は何でどういった状態になれば実験は成功で、どういった状態になれば失敗なのかを定量的に定義して実験という名のプロジェクトのスコープに従っていかなければならないですね。

この点がビジネスをしている人と研究をしている人で乖離してしまうと喧嘩になるんだと最近は思います。どちらも真剣に取り組んでいるのに、ビジネスをしている人からしたら無駄なことにリソースを割いているととらえられてしまう状態です。

せっかく、ビジネス一本の人にはできないスキルを持っているはずなので、それを受け身ではなく、こちらから課題を解決するための手段として提案できるようになりたいです。

今回は「実験期間でどれだけ精度を高めることができるか」という課題なので、リソースに余裕がある限り精度を高めていきます。(本来は、この裏に隠れている「なぜ精度を高めるのか」という部分に関わらないといけないということですね。)

3-4. 次の施策を考える

先ほどは、block5_conv1以降の層を解凍しました。

次は、block4_conv1以降の層を解凍してファインチューニングを行います。

現時点では、block4より前までの部分が外観の情報を取得するために使用されており、それ以降がより抽象的な表現を獲得しているのではないかと考えています。

そのため、抽象的な部分をより車に特化させることで精度が上がるのではないかと考えました。

 

もし、これでも結果が良くならなかった場合はファインチューニングをモデルの全体で行います。

これは、外観の情報の取得も車に特化させた方がいいかもしれないという仮説です。これで上手くのであれば、その後、追加で後半部分のみのファインチューニングを行うことも考えられます。

ですが、外観の情報の取得フィルタを壊してしまう可能性もあるので期待と不安半分ずつです。

3-5. block4, block5の追加ファインチューニング

モデルの作成

model = models.load_model('models/VGG16_mini_extended_fine12.h5')
model.trainable = True

set_trainable = False
for layer in model.layers:
    if layer.name == 'block4_conv1':
        set_trainable = True
    if set_trainable:
        layer.trainable = True
    else:
        layer.trainable = False     

#コンパイルをしないとsummaryをしても反映されないので注意
model.compile(optimizer=Adam(lr=1e-5),#学習率が低いのはファインチューニングを行う3つの層の変更を制限するため
             loss='categorical_crossentropy',
             metrics=['acc'])
model.summary()

Model: "model_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_4 (InputLayer)         (None, 256, 256, 3)       0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 256, 256, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 256, 256, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 128, 128, 64)      0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 128, 128, 128)     73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 128, 128, 128)     147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 64, 64, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 64, 64, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 32, 32, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 32, 32, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 16, 16, 512)       0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 8, 8, 512)         0         
_________________________________________________________________
global_average_pooling2d_5 ( (None, 512)               0         
_________________________________________________________________
dense_8 (Dense)              (None, 1024)              525312    
_________________________________________________________________
dense_9 (Dense)              (None, 20)                20500     
=================================================================
Total params: 15,260,500
Trainable params: 13,525,012
Non-trainable params: 1,735,488
_________________________________________________________________

 

「Trainable params: 13,525,012」の部分が劇的に増加したことが分かります。

解凍した部分と、追加した部分を学習する

history = model.fit_generator(train_generator,
                             steps_per_epoch=NUM_TRAINING//BATCH_SIZE,
                             epochs=30,
                             validation_data=validation_generator,
                             validation_steps=NUM_VALIDATION//BATCH_SIZE)


 

グラフから結果を評価する

悪くはないけれども、まだ改善することができそうな印象を受けます。

なので、次のモデルも作成をしてから評価をしたいと思います。

3-6. モデル全てを使ったファインチューニング

モデルの作成

conv_base = VGG16(weights='imagenet',
                 include_top=False,
                 input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3))

x = conv_base.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
predictions = Dense(N_CATEGORIES, activation='softmax')(x)
model = Model(inputs=conv_base.input, outputs=predictions)
model.compile(optimizer=optimizers.Adam(lr=2e-5),
             loss='categorical_crossentropy',
             metrics=['acc'])
model.summary()

Model: "model_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 256, 256, 3)       0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 256, 256, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 256, 256, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 128, 128, 64)      0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 128, 128, 128)     73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 128, 128, 128)     147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 64, 64, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 64, 64, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 32, 32, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 32, 32, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 16, 16, 512)       0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 8, 8, 512)         0         
_________________________________________________________________
global_average_pooling2d_1 ( (None, 512)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 1024)              525312    
_________________________________________________________________
dense_2 (Dense)              (None, 20)                20500     
=================================================================
Total params: 15,260,500
Trainable params: 15,260,500
Non-trainable params: 0
_________________________________________________________________

解凍した部分(全体)の訓練

history = model.fit_generator(
    train_generator,
    steps_per_epoch=NUM_TRAINING//BATCH_SIZE,
    epochs=30,
    validation_data=validation_generator,
    validation_steps=NUM_VALIDATION//BATCH_SIZE,
    verbose=1
)
with open('histories/history_VGG16_mini_extended_2.pkl', 'wb') as f:
    pickle.dump(history.history, f)

model.save('models/VGG16_mini_extended_2.h5')


結果をグラフで評価

正解率 損失関数
訓練データ 1.000 2.4217e-5
検証データ 0.9984 1.0960e-5

 

相当よくなったことが分かります。

3-7. 追加学習

block5_conv1より前を凍結

コンパイルの際に、学習率を前回よりも小さくすることでより精密な更新ができるように変更をしました。

model.trainable = True

set_trainable = False
for layer in model.layers:
    if layer.name == 'block5_conv1':
        set_trainable = True
    if set_trainable:
        layer.trainable = True
    else:
        layer.trainable = False

model.compile(optimizer=optimizers.Adam(lr=1e-5),#学習率が低いのはファインチューニングを行う3つの層の変更を制限するため
             loss='categorical_crossentropy',
             metrics=['acc'])
model.summary()

Model: "model_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 256, 256, 3)       0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 256, 256, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 256, 256, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 128, 128, 64)      0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 128, 128, 128)     73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 128, 128, 128)     147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 64, 64, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 64, 64, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 64, 64, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 32, 32, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 32, 32, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 32, 32, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 16, 16, 512)       0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 8, 8, 512)         0         
_________________________________________________________________
global_average_pooling2d_1 ( (None, 512)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 1024)              525312    
_________________________________________________________________
dense_2 (Dense)              (None, 20)                20500     
=================================================================
Total params: 15,260,500
Trainable params: 7,625,236
Non-trainable params: 7,635,264
_________________________________________________________________

モデルの訓練

history = model.fit_generator(train_generator,
                             steps_per_epoch=NUM_TRAINING//BATCH_SIZE,
                             epochs=30,
                             validation_data=validation_generator,
                             validation_steps=NUM_VALIDATION//BATCH_SIZE)
with open('histories/history_VGG16_mini_extended_fine2.pkl', 'wb') as f:
    pickle.dump(history.history, f)
    
model.save('models/VGG16_mini_extended_fine2.h5')


結果をグラフから評価

正解率 損失関数
訓練データ 1.000 4.6965e-6
検証データ 1.000 1.5616e-5

 

正解率は不安定に見えますが、lossは安定して減少をしていることが分かるのでよい学習をしていると判断をします。

また、validの正解率が高いこと、trainのlossがこの学習を加える前よりも減少することができたことを評価して、最終的なモデルをこれにします。

最後に

次の章では、

  1. 今まで作ってきたモデルで本当に精度を上げることができていたのか?
  2. 効果的な可視化の方法を習得しよう!

という構成でいきます。

 

最後まで読んで頂きありがとうございました。

続きも是非よろしくお願いします!

keras初心者チュートリアル【No.1 自作モデルの作成】~CNNで車種判別モデルを作成~このチュートリアルを一通り行うことで、 というレベルから という状態になってもらえたらと思っ...
keras初心者チュートリアル【No.2 転移学習】~CNNで車種判別モデルを作成~このチュートリアルを一通り行うことで、 というレベルから という状態になってもらえたらと思っ...
keras初心者チュートリアル【No.4 モデルの評価と可視化】~CNNで車種判別モデルを作成~このチュートリアルを一通り行うことで、 というレベルから という状態になってもらえたらと思っ...
keras初心者チュートリアル【No.5 モデルの内部を可視化】~CNNで車種判別モデルを作成~このチュートリアルを一通り行うことで、 というレベルから という状態になってもらえたらと思っ...

リクエストやコメントなどをいただけると嬉しいです!

Twitterから更新報告をしております!

いいね・フォローしていただけると泣いて喜びます。(´;ω;`)

 

 

オススメのプログラミングスクールをご紹介

タイピングもままならない完全にプログラミング初心者から

アホいぶきんぐ
アホいぶきんぐ
プログラミングってどこの国の言語なの~?

たった二ヶ月で

いぶきんぐ
いぶきんぐ
え!?人工知能めっちゃ簡単にできるじゃん!

応用も簡単にできる…!!

という状態になるまで、一気に成長させてくれたオススメのプログラミングスクールをご紹介します!

テックアカデミーのPython+AIコースを受講した僕が本音のレビュー・割引あり! というプログラミング完全初心者だった僕が Tech Academy(テックアカデミー)のPython×AIコース を二ヶ月間...

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です