画像認識で「綾鷹を選ばせる」AIを作る【#Aidemynote AINOW賞】

AINOWはAIプログラミング学習サービス「Aidemy」を提供する株式会社アイデミーなどと共に完全オンラインの解析コンテスト #Aidemynoteを2018年6月に開催しました。

#Aidemynoteでは特別賞としてAINOW賞が設けられました。解析の新規性やインパクトを総合的に審査して2つの記事を選定させていただきました。

今回ご紹介するAINOW賞は「選ばれたのは綾鷹でした」で有名な綾鷹を選ばせるAIを作ったtomoさんです。

こんにちは、絶賛プログラミング勉強中のtomoです。
Aidemyで画像認識について勉強し始めて1ヶ月が経ったので、学習成果として投稿します。

はじめに

突然ですが、皆さん「緑茶の中でも選ばれてしまう緑茶は何か」と問われたら何と答えますか?

おそらく50%以上の人は「綾鷹」と答えるかと思います。
この記事では、そんな綾鷹を画像認識によって人々に選ばせるAIを作成します。

Aidemyで学習した内容

ディープラーニングで画像認識モデルを作ってみよう!」ルートで8つのコースを学びました。

特に「CNNを用いた画像認識」コースにおいて学んだ技術を複数使用しています。
(後述する目次の「⑵モデルを構築/学習する」の仕組みを学べます。)

実装概要

以下の3点を実装します。

・緑茶のペットボトルの写真から、商品名を予測
・予測結果が綾鷹である場合、「選ばれたのは、綾鷹でした。」と表示
・綾鷹でない場合、「綾鷹を選んでください。(もしかして:あなたが選んでいるのは
「(緑茶の名前)」ではありませんか?)」と表示

AIの作成

早速AIを作成していきます。
以下の流れで進めます。

⑴Iphoneで撮った写真を学習/検証データにする
⑵予測モデルを構築/学習する
⑶綾鷹を選ばせるプログラムを作る

⑴Iphoneで撮った写真を学習/検証データにする

今回予測の対象とする緑茶は以下の10種類とします。
ジャケ写のようになりました。

各種緑茶について、42枚ずつ撮影します。
ちなみに、お茶を500枚近く撮影する姿を家族に見られ、「お前大丈夫か?」と心配されました。

撮影したデータについて、以下のコードでラベリング(画像データと商品名の紐付け)を実施し、学習/検証データを用意します。

なお、各商品ごとにディレクトリを作成し、画像データを格納しているのを前提としてます。

#ラベリングによる学習/検証データの準備

from PIL import Image
import os, glob
import numpy as np
import random, math

#画像が保存されているルートディレクトリのパス
root_dir = "パス"
# 商品名
categories = ["綾鷹","お〜いお茶 抹茶入り","なごみ","お〜いお茶 新茶",
              "綾鷹 茶葉のあまみ","お〜いお茶","伊右衛門","お〜いお茶 濃い茶",
              "生茶","お〜いお茶 新緑"]

# 画像データ用配列
X = []
# ラベルデータ用配列
Y = []

#画像データごとにadd_sample()を呼び出し、X,Yの配列を返す関数
def make_sample(files):
    global X, Y
    X = []
    Y = []
    for cat, fname in files:
        add_sample(cat, fname)
    return np.array(X), np.array(Y)

#渡された画像データを読み込んでXに格納し、また、
#画像データに対応するcategoriesのidxをY格納する関数
def add_sample(cat, fname):
    img = Image.open(fname)
    img = img.convert("RGB")
    img = img.resize((150, 150))
    data = np.asarray(img)
    X.append(data)
    Y.append(cat)

#全データ格納用配列
allfiles = []

#カテゴリ配列の各値と、それに対応するidxを認識し、全データをallfilesにまとめる
for idx, cat in enumerate(categories):
    image_dir = root_dir + "/" + cat
    files = glob.glob(image_dir + "/*.jpg")
    for f in files:
        allfiles.append((idx, f))

#シャッフル後、学習データと検証データに分ける
random.shuffle(allfiles)
th = math.floor(len(allfiles) * 0.8)
train = allfiles[0:th]
test  = allfiles[th:]
X_train, y_train = make_sample(train)
X_test, y_test = make_sample(test)
xy = (X_train, X_test, y_train, y_test)
#データを保存する(データの名前を「tea_data.npy」としている)
np.save("保存先パス/tea_data.npy", xy)

⑵予測モデルを構築/学習する

モデルは畳み込みニューラルネットワーク(CNN)を使います。
シンプルなモデルから始め、精度をあげる工夫を追加していきます。

①シンプルにモデルを構築する

まずはシンプルにモデルを構築します。

#モデルの構築

from keras import layers, models

model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(150,150,3)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dense(512,activation="relu"))
model.add(layers.Dense(10,activation="sigmoid")) #分類先の種類分設定

#モデル構成の確認
model.summary()

「model.summary()」でモデル構成を確認できます。

続いて、モデルをコンパイルします。

#モデルのコンパイル

from keras import optimizers

model.compile(loss="binary_crossentropy",
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=["acc"])

先ほど作成した学習/検証データを読み込み、データの正規化といった学習に向けた準備をします。

#データの準備

from keras.utils import np_utils
import numpy as np

categories = ["綾鷹","お〜いお茶 抹茶入り","なごみ","お〜いお茶 新茶",
              "綾鷹 茶葉のあまみ","お〜いお茶","伊右衛門","お〜いお茶 濃い茶",
              "生茶","お〜いお茶 新緑"]
nb_classes = len(categories)

X_train, X_test, y_train, y_test = np.load("保存した学習データ・テストデータのパス")

#データの正規化
X_train = X_train.astype("float") / 255
X_test  = X_test.astype("float")  / 255

#kerasで扱えるようにcategoriesをベクトルに変換
y_train = np_utils.to_categorical(y_train, nb_classes)
y_test  = np_utils.to_categorical(y_test, nb_classes)

準備したデータを使ってモデルを学習させます。

#モデルの学習

model = model.fit(X_train,
                  y_train,
                  epochs=10,
                  batch_size=6,
                  validation_data=(X_test,y_test))

epochごとに学習結果が表示されます。

Train on 336 samples, validate on 84 samples
Epoch 1/10
336/336 [==============================] – 20s 59ms/step – loss: 0.3543 – acc: 0.8887 – val_loss: 0.3321 – val_acc: 0.9000
Epoch 2/10
336/336 [==============================] – 20s 60ms/step – loss: 0.3214 – acc: 0.9000 – val_loss: 0.3152 – val_acc: 0.9000
Epoch 3/10
336/336 [==============================] – 19s 57ms/step – loss: 0.2802 – acc: 0.9012 – val_loss: 0.2602 – val_acc: 0.9083
Epoch 4/10
336/336 [==============================] – 20s 59ms/step – loss: 0.2119 – acc: 0.9179 – val_loss: 0.2072 – val_acc: 0.9262
Epoch 5/10
336/336 [==============================] – 20s 60ms/step – loss: 0.1548 – acc: 0.9423 – val_loss: 0.1791 – val_acc: 0.9345
Epoch 6/10
336/336 [==============================] – 21s 63ms/step – loss: 0.1217 – acc: 0.9536 – val_loss: 0.1331 – val_acc: 0.9488
Epoch 7/10
336/336 [==============================] – 20s 59ms/step – loss: 0.0950 – acc: 0.9664 – val_loss: 0.1264 – val_acc: 0.9536
Epoch 8/10
336/336 [==============================] – 21s 62ms/step – loss: 0.0747 – acc: 0.9759 – val_loss: 0.1395 – val_acc: 0.9429
Epoch 9/10
336/336 [==============================] – 20s 60ms/step – loss: 0.0646 – acc: 0.9792 – val_loss: 0.1314 – val_acc: 0.9476
Epoch 10/10
336/336 [==============================] – 19s 58ms/step – loss: 0.0513 – acc: 0.9830 – val_loss: 0.1073 – val_acc: 0.9631

学習が完了しましたら、学習結果をグラフで表示します。

#学習結果を表示

import matplotlib.pyplot as plt

acc = model.history['acc']
val_acc = model.history['val_acc']
loss = model.history['loss']
val_loss = model.history['val_loss']

epochs = range(len(acc))

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.savefig('精度を示すグラフのファイル名')

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.savefig('損失値を示すグラフのファイル名')

6epoch目から精度が下がって(損失値が上がって)います。データ数が少なく、過学習を起こしていると思われます。

学習結果を保存しておきます。

#モデルの保存

json_string = model.model.to_json()
open('保存先パス/tea_predict.json', 'w').write(json_string)

#重みの保存

hdf5_file = "保存先パス/tea_predict.hdf5"
model.model.save_weights(hdf5_file)

続いて、学習させたモデルについて、未知のデータでテストします。(データ拡張は未実施)
一応、テストデータを準備するためのコードを貼っておきます。

from PIL import Image
import os, glob
import numpy as np
import random, math

# 画像が保存されているディレクトリのパス
root_dir = "パス"
# 画像が保存されているフォルダ名
categories = ["綾鷹","お〜いお茶 抹茶入り","なごみ","お〜いお茶 新茶",
              "綾鷹 茶葉のあまみ","お〜いお茶","伊右衛門","お〜いお茶 濃い茶",
              "生茶","お〜いお茶 新緑"]

X = [] # 画像データ
Y = [] # ラベルデータ

# フォルダごとに分けられたファイルを収集
#(categoriesのidxと、画像のファイルパスが紐づいたリストを生成)
allfiles = []
for idx, cat in enumerate(categories):
    image_dir = root_dir + "/" + cat
    files = glob.glob(image_dir + "/*.jpg")
    for f in files:
        allfiles.append((idx, f))

for cat, fname in allfiles:
    img = Image.open(fname)
    img = img.convert("RGB")
    img = img.resize((150, 150))
    data = np.asarray(img)
    X.append(data)
    Y.append(cat)

x = np.array(X)
y = np.array(Y)

np.save("保存先のパス/tea_data_test_X_150.npy", x)
np.save("保存先のパス/tea_data_test_Y_150.npy", y)

作成したテストデータを用いてモデルの予測精度を測ります。

# モデルの精度を測る

#評価用のデータの読み込み
eval_X = np.load("保存先のパス/tea_data_test_X_150.npy")
eval_Y = np.load("保存先のパス/tea_data_test_Y_150.npy")

#Yのデータをone-hotに変換
from keras.utils import np_utils

test_Y = np_utils.to_categorical(test_Y, 10)

score = model.model.evaluate(x=test_X,y=test_Y)

print('loss=', score[0])
print('accuracy=', score[1])

予測結果です。正解率は93.4%ですね。

100/100 [==============================] – 2s 20ms/step
loss= 1.02928255677
accuracy= 0.934000020027

その他、精度をあげるであろう手法をいくつか試していきます。

②データを拡張する

①では、画像数が少ないことから、過学習を起こしているように見えました。
そのため、KerasのImageDataGeneratorを使って画像を水増しします。

#画像の水増し

import os
import glob
import numpy as np
from keras.preprocessing.image import ImageDataGenerator,
                                      load_img, img_to_array, array_to_img

# 画像を拡張する関数
def draw_images(generator, x, dir_name, index):
    save_name = 'extened-' + str(index)
    g = generator.flow(x, batch_size=1, save_to_dir=output_dir,
                       save_prefix=save_name, save_format='jpeg')

    # 1つの入力画像から何枚拡張するかを指定(今回は50枚)
    for i in range(50):
        bach = g.next()

# 出力先ディレクトリの設定
output_dir = "出力先のディレクトリパス"

if not(os.path.exists(output_dir)):
    os.mkdir(output_dir)

# 拡張する画像の読み込み
images = glob.glob(os.path.join("画像の保存先ディレクトリのパス", "*.jpg"))

# ImageDataGeneratorを定義
datagen = ImageDataGenerator(rotation_range=30,
                            width_shift_range=20,
                            height_shift_range=0.,
                            zoom_range=0.1,
                            horizontal_flip=True,
                            vertical_flip=True)
:]
# 読み込んだ画像を順に拡張
for i in range(len(images)):
    img = load_img(images[i])
    img = img.resize((150, 150))
    x = img_to_array(img)
    x = np.expand_dims(x, axis=0)
    draw_images(datagen, x, output_dir, i)

うまく複製できているか確認します。


ん?、ちょっと画像が粗いように思えます。①の時点で確認して気付けって話ですが。

「img.resize((150, 150))」を「img.resize((250, 250))」に変更して再度水増しします。

このレベルであれば十分目で判断できますね。

①と同じようにモデルを学習させます。
(各種パスの修正、また、モデルのinput sizeを250*250*3に修正する必要があります。)

以下、学習結果です。

Train on 3360 samples, validate on 840 samples
Epoch 1/10
3360/3360 [==============================] – 604s 180ms/step – loss: 0.3157 – acc: 0.9002 – val_loss: 0.2828 – val_acc: 0.9008
Epoch 2/10
3360/3360 [==============================] – 618s 184ms/step – loss: 0.2446 – acc: 0.9086 – val_loss: 0.2084 – val_acc: 0.9198
Epoch 3/10
3360/3360 [==============================] – 608s 181ms/step – loss: 0.1824 – acc: 0.9320 – val_loss: 0.1750 – val_acc: 0.9323
Epoch 4/10
3360/3360 [==============================] – 613s 183ms/step – loss: 0.1400 – acc: 0.9470 – val_loss: 0.1241 – val_acc: 0.9551
Epoch 5/10
3360/3360 [==============================] – 1054s 314ms/step – loss: 0.1068 – acc: 0.9610 – val_loss: 0.1053 – val_acc: 0.9625
Epoch 6/10
3360/3360 [==============================] – 572s 170ms/step – loss: 0.0795 – acc: 0.9717 – val_loss: 0.0733 – val_acc: 0.9735
Epoch 7/10
3360/3360 [==============================] – 564s 168ms/step – loss: 0.0639 – acc: 0.9775 – val_loss: 0.0681 – val_acc: 0.9723
Epoch 8/10
3360/3360 [==============================] – 3426s 1s/step – loss: 0.0480 – acc: 0.9837 – val_loss: 0.0707 – val_acc: 0.9737
Epoch 9/10
3360/3360 [==============================] – 635s 189ms/step – loss: 0.0380 – acc: 0.9871 – val_loss: 0.0577 – val_acc: 0.9770
Epoch 10/10
3360/3360 [==============================] – 653s 194ms/step – loss: 0.0277 – acc: 0.9907 – val_loss: 0.0376 – val_acc: 0.9867

精度上がってますね。
テストデータを250*250に変更した上で作成し、予測精度を測ります。

100/100 [==============================] – 5s 51ms/step
loss= 0.377869169712
accuracy= 0.975000026226

正解率97.5%、水増し前より4%上昇しました。

③dropoutを追加する

過学習を抑制するdropoutをモデルに追加します。

#モデルの構築

from keras import layers, models

model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(250,250,3)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512,activation="relu"))
model.add(layers.Dense(10,activation="sigmoid"))

②と同様に学習させます。
以下、学習結果。

Train on 3360 samples, validate on 840 samples
Epoch 1/10
3360/3360 [==============================] – 568s 169ms/step – loss: 0.3291 – acc: 0.8956 – val_loss: 0.2981 – val_acc: 0.9000
Epoch 2/10
3360/3360 [==============================] – 596s 177ms/step – loss: 0.2635 – acc: 0.9058 – val_loss: 0.2276 – val_acc: 0.9129
Epoch 3/10
3360/3360 [==============================] – 647s 192ms/step – loss: 0.2097 – acc: 0.9197 – val_loss: 0.1930 – val_acc: 0.9274
Epoch 4/10
3360/3360 [==============================] – 694s 206ms/step – loss: 0.1734 – acc: 0.9338 – val_loss: 0.1612 – val_acc: 0.9400
Epoch 5/10
3360/3360 [==============================] – 710s 211ms/step – loss: 0.1406 – acc: 0.9457 – val_loss: 0.1403 – val_acc: 0.9446
Epoch 6/10
3360/3360 [==============================] – 669s 199ms/step – loss: 0.1135 – acc: 0.9565 – val_loss: 0.1111 – val_acc: 0.9550
Epoch 7/10
3360/3360 [==============================] – 597s 178ms/step – loss: 0.0921 – acc: 0.9654 – val_loss: 0.0819 – val_acc: 0.9731
Epoch 8/10
3360/3360 [==============================] – 592s 176ms/step – loss: 0.0736 – acc: 0.9736 – val_loss: 0.0707 – val_acc: 0.9773
Epoch 9/10
3360/3360 [==============================] – 596s 177ms/step – loss: 0.0583 – acc: 0.9793 – val_loss: 0.0585 – val_acc: 0.9790
Epoch 10/10
3360/3360 [==============================] – 588s 175ms/step – loss: 0.0474 – acc: 0.9836 – val_loss: 0.0496 – val_acc: 0.9819

テストデータで予測精度を測ります。

100/100 [==============================] – 5s 52ms/step
loss= 0.516686134338
accuracy= 0.967000012398

ありゃ、精度が下がりました。
②は過学習に至る前であり、単に学習効率が下がったということでしょうか。

損失率を0.25に下げて再度学習してみます。

Train on 3360 samples, validate on 840 samples
Epoch 1/10
3360/3360 [==============================] – 583s 173ms/step – loss: 0.3241 – acc: 0.8952 – val_loss: 0.2866 – val_acc: 0.9037
Epoch 2/10
3360/3360 [==============================] – 571s 170ms/step – loss: 0.2450 – acc: 0.9087 – val_loss: 0.2085 – val_acc: 0.9226
Epoch 3/10
3360/3360 [==============================] – 563s 167ms/step – loss: 0.1822 – acc: 0.9326 – val_loss: 0.1853 – val_acc: 0.9299
Epoch 4/10
3360/3360 [==============================] – 603s 180ms/step – loss: 0.1407 – acc: 0.9469 – val_loss: 0.1332 – val_acc: 0.9525
Epoch 5/10
3360/3360 [==============================] – 567s 169ms/step – loss: 0.1136 – acc: 0.9576 – val_loss: 0.1001 – val_acc: 0.9650
Epoch 6/10
3360/3360 [==============================] – 574s 171ms/step – loss: 0.0895 – acc: 0.9676 – val_loss: 0.0888 – val_acc: 0.9648
Epoch 7/10
3360/3360 [==============================] – 584s 174ms/step – loss: 0.0693 – acc: 0.9750 – val_loss: 0.0750 – val_acc: 0.9742
Epoch 8/10
3360/3360 [==============================] – 570s 170ms/step – loss: 0.0547 – acc: 0.9811 – val_loss: 0.0532 – val_acc: 0.9799
Epoch 9/10
3360/3360 [==============================] – 579s 172ms/step – loss: 0.0446 – acc: 0.9846 – val_loss: 0.0545 – val_acc: 0.9788
Epoch 10/10
3360/3360 [==============================] – 563s 168ms/step – loss: 0.0334 – acc: 0.9888 – val_loss: 0.0433 – val_acc: 0.9842

テストデータの予測結果。やはり②の方が精度が高いです。

100/100 [==============================] – 5s 53ms/step
loss= 0.432936085963
accuracy= 0.973000030518
[/aisde] ただ、グラフを見る限り、dropoutの損失率を0.5にした時が最もうまく学習できているようです。

今回はepoch数を10で固定していますが、epoch数を増やした時にdropoutが過学習を抑制し、さらに高い精度が出るのでは、、と思います。(後述の「(2018/06/23)追加検証」で検証しています。)

⑶綾鷹を選ばせるプログラムを作る

②のモデルを採択し、綾鷹を選ばせるプログラムを作ります。

#綾鷹を選ばせるプログラム

from keras import models
from keras.models import model_from_json
from keras.preprocessing import image
import numpy as np

#保存したモデルの読み込み
model = model_from_json(open('保存先のフォルダ/tea_predict.json').read())
#保存した重みの読み込み
model.load_weights('保存先のフォルダ/tea_predict.hdf5')

categories = ["綾鷹","お〜いお茶 抹茶入り","なごみ","お〜いお茶 新茶","綾鷹 茶葉のあまみ",
              "お〜いお茶","伊右衛門","お〜いお茶 濃い茶","生茶","お〜いお茶 新緑"]

#画像を読み込む
img_path = str(input())
img = image.load_img(img_path,target_size=(250, 250, 3))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)

#予測
features = model.predict(x)

#予測結果によって処理を分ける
if features[0,0] == 1:
    print ("選ばれたのは、綾鷹でした。")

elif features[0,4] == 1:
    print ("選ばれたのは、綾鷹(茶葉のあまみ)でした。")

else:
    for i in range(0,10):
          if features[0,i] == 1:
              cat = categories[i]
    message = "綾鷹を選んでください。(もしかして:あなたが選んでいるのは「" + cat + "」ではありませんか?)"
    print(message)

さて、テストしてみましょう。

出力結果:
選ばれたのは、綾鷹(茶葉のあまみ)でした。

出力結果:
綾鷹を選んでください。(もしかして:あなたが選んでいるのは「なごみ」ではありませんか?)

出力結果:
選ばれたのは、綾鷹でした。

出力結果:
綾鷹を選んでください。(もしかして:あなたが選んでいるのは「お〜いお茶 新緑」ではありませんか?)

問題なく予測できました。

おわりに

前述したepoch数の変更だけでなく、活性化関数、損失関数といったモデルの変更、画像データの白色化といった前処理など、まだまだ精度をあげる余地があります。
今回は一旦の投稿となりましたが、そういった機械学習の面白さに気づくとこができました。

今後は画像認識だけでなく、自然言語処理などにも挑戦し、また、kaggleにもチャレンジしようかと思います。

お読みいただき、ありがとうございました。
※記事にミスや改善点等ありましたら、ご指摘いただけると幸いです。

(2018/06/23)追加検証

epoch数を10から15に増やして精度を検証しました。
対象は②のモデル(画像水増しのみ)と、③のモデル(dropoutを追加)のうち損失率を0.5としたモデルです。

まずは②のモデルを再度学習させます。
学習結果は以下の通り。

Train on 3360 samples, validate on 840 samples
Epoch 1/15
3360/3360 [==============================] – 571s 170ms/step – loss: 0.3126 – acc: 0.8946 – val_loss: 0.2541 – val_acc: 0.9065
Epoch 2/15
3360/3360 [==============================] – 580s 173ms/step – loss: 0.2143 – acc: 0.9204 – val_loss: 0.1797 – val_acc: 0.9306
Epoch 3/15
3360/3360 [==============================] – 561s 167ms/step – loss: 0.1543 – acc: 0.9429 – val_loss: 0.1335 – val_acc: 0.9506
Epoch 4/15
3360/3360 [==============================] – 595s 177ms/step – loss: 0.1162 – acc: 0.9567 – val_loss: 0.1060 – val_acc: 0.9575
Epoch 5/15
3360/3360 [==============================] – 583s 174ms/step – loss: 0.0855 – acc: 0.9686 – val_loss: 0.0832 – val_acc: 0.9683
Epoch 6/15
3360/3360 [==============================] – 559s 166ms/step – loss: 0.0658 – acc: 0.9765 – val_loss: 0.0654 – val_acc: 0.9767
Epoch 7/15
3360/3360 [==============================] – 572s 170ms/step – loss: 0.0481 – acc: 0.9833 – val_loss: 0.0574 – val_acc: 0.9788
Epoch 8/15
3360/3360 [==============================] – 568s 169ms/step – loss: 0.0396 – acc: 0.9862 – val_loss: 0.0402 – val_acc: 0.9862
Epoch 9/15
3360/3360 [==============================] – 563s 168ms/step – loss: 0.0296 – acc: 0.9907 – val_loss: 0.0674 – val_acc: 0.9763
Epoch 10/15
3360/3360 [==============================] – 582s 173ms/step – loss: 0.0242 – acc: 0.9925 – val_loss: 0.0316 – val_acc: 0.9885
Epoch 11/15
3360/3360 [==============================] – 580s 173ms/step – loss: 0.0180 – acc: 0.9941 – val_loss: 0.0447 – val_acc: 0.9837
Epoch 12/15
3360/3360 [==============================] – 586s 174ms/step – loss: 0.0140 – acc: 0.9965 – val_loss: 0.0272 – val_acc: 0.9910
Epoch 13/15
3360/3360 [==============================] – 569s 169ms/step – loss: 0.0127 – acc: 0.9962 – val_loss: 0.0286 – val_acc: 0.9896
Epoch 14/15
3360/3360 [==============================] – 567s 169ms/step – loss: 0.0117 – acc: 0.9973 – val_loss: 0.0198 – val_acc: 0.9927
Epoch 15/15
3360/3360 [==============================] – 555s 165ms/step – loss: 0.0067 – acc: 0.9983 – val_loss: 0.0350 – val_acc: 0.9874

8epoch目からうまく学習が進んでいませんね。

100/100 [==============================] – 5s 51ms/step
loss= 0.384550094604
accuracy= 0.97600001812

正解率は97.6%。0.1%精度が上がりました。

続いて、③の損失率を0.5としたモデルを再度学習させます。

Train on 3360 samples, validate on 840 samples
Epoch 1/15
3360/3360 [==============================] – 577s 172ms/step – loss: 0.3261 – acc: 0.8910 – val_loss: 0.2827 – val_acc: 0.9006
Epoch 2/15
3360/3360 [==============================] – 568s 169ms/step – loss: 0.2429 – acc: 0.9095 – val_loss: 0.2026 – val_acc: 0.9261
Epoch 3/15
3360/3360 [==============================] – 578s 172ms/step – loss: 0.1865 – acc: 0.9318 – val_loss: 0.1787 – val_acc: 0.9342
Epoch 4/15
3360/3360 [==============================] – 564s 168ms/step – loss: 0.1458 – acc: 0.9458 – val_loss: 0.1369 – val_acc: 0.9474
Epoch 5/15
3360/3360 [==============================] – 572s 170ms/step – loss: 0.1184 – acc: 0.9563 – val_loss: 0.1229 – val_acc: 0.9521
Epoch 6/15
3360/3360 [==============================] – 566s 168ms/step – loss: 0.0937 – acc: 0.9662 – val_loss: 0.1051 – val_acc: 0.9642
Epoch 7/15
3360/3360 [==============================] – 559s 166ms/step – loss: 0.0750 – acc: 0.9735 – val_loss: 0.0887 – val_acc: 0.9664
Epoch 8/15
3360/3360 [==============================] – 561s 167ms/step – loss: 0.0629 – acc: 0.9784 – val_loss: 0.0599 – val_acc: 0.9776
Epoch 9/15
3360/3360 [==============================] – 560s 167ms/step – loss: 0.0500 – acc: 0.9827 – val_loss: 0.0586 – val_acc: 0.9771
Epoch 10/15
3360/3360 [==============================] – 573s 171ms/step – loss: 0.0408 – acc: 0.9857 – val_loss: 0.0434 – val_acc: 0.9844
Epoch 11/15
3360/3360 [==============================] – 638s 190ms/step – loss: 0.0362 – acc: 0.9873 – val_loss: 0.0350 – val_acc: 0.9877
Epoch 12/15
3360/3360 [==============================] – 568s 169ms/step – loss: 0.0272 – acc: 0.9910 – val_loss: 0.0392 – val_acc: 0.9865
Epoch 13/15
3360/3360 [==============================] – 561s 167ms/step – loss: 0.0234 – acc: 0.9926 – val_loss: 0.0483 – val_acc: 0.9825
Epoch 14/15
3360/3360 [==============================] – 579s 172ms/step – loss: 0.0220 – acc: 0.9932 – val_loss: 0.0332 – val_acc: 0.9869
Epoch 15/15
3360/3360 [==============================] – 562s 167ms/step – loss: 0.0161 – acc: 0.9945 – val_loss: 0.0262 – val_acc: 0.9901

これでも10epoch目から過学習気味のようです。

100/100 [==============================] – 6s 58ms/step
loss= 0.36878341198
accuracy= 0.97700001955
正解率は97.7%。今までで一番高い精度です。

「dropoutを追加して学習効率が下がっただけで、epoch数を増やせば高い精度が出るのではないか」と推測しましたが、その通りになったのではないかと思います。

あとは過学習を抑えるために損失率を少しずつあげていけば、より高い正解率になると思います。

おざけん

人工知能・AI専門メディア AINOWデスク ┃ カメラマン
┃ Twitterでも発信しています。@ozaken_AI ┃ AINOWのTwitterもぜひ@Ainow_ai┃
出演: 日経CNBC「日経カレッジ・ラボ」日本テレビ 「ZIP!」など┃

AIが人間と共存していく未来を作りたい。そのために発信していきます!

無料メールマガジン登録

週1回、注目のAIニュースやイベント情報を
編集部がピックアップしてお届けしています。

こちらの規約にご同意のうえチェックしてください。

規約に同意する