LoginSignup
846

More than 5 years have passed since last update.

画像認識で「綾鷹を選ばせる」AIを作る

Last updated at Posted at 2018-06-22

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

はじめに

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

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

Aidemyで学習した内容

「ディープラーニングで画像認識モデルを作ってみよう!」ルートで8つのコースを学びました。
特に「CNNを用いた画像認識」コースにおいて学んだ技術を複数使用しています。
(後述する目次の「⑵モデルを構築/学習する」の仕組みを学べます。)

目次

・実装概要
・AIの作成
  ⑴Iphoneで撮った写真を学習/検証データにする
  ⑵モデルを構築/学習する
    ①シンプルにモデルを構築する
    ②データを拡張する
    ③dropoutを追加する
  ⑶綾鷹を選ばせるプログラムを作る
・おわりに
・(2018/06/23)追加検証

実装概要

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

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

AIの作成

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

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

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

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

IMG_0664.jpg

各種緑茶について、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('損失値を示すグラフのファイル名')

figure1.png
figure2.png

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)

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

extened-0_0_1146.jpeg

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

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

extened-4_0_9551.jpeg

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

①と同じようにモデルを学習させます。
(各種パスの修正、また、モデルの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

figure1.png
figure2.png

精度上がってますね。
テストデータを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

figure1.png
figure2.png

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

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

figure1.png
figure2.png

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

100/100 [==============================] - 5s 53ms/step
loss= 0.432936085963
accuracy= 0.973000030518

ただ、グラフを見る限り、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)

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

IMG_0045.jpg

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

IMG_0035.jpg

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

IMG_0078.jpg

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

IMG_0097.jpg

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

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

おわりに

前述した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

figure1.png
figure2.png

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

figure1_epoch15.png
figure2_epoch15.png

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

100/100 [==============================] - 6s 58ms/step
loss= 0.36878341198
accuracy= 0.97700001955

正解率は97.7%。今までで一番高い精度です。

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

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
846