質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.13%

CNNで学習が進まない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 3,488

gakusyusuruzo

score 11

acc,val_accを上げたい、loss,val_lossを下げたいです。

Python、機械学習および画像認識超初心者です。
自分で用意した2クラスの画像を、CNNで学習をして分類をするプログラムを書きたいと思いました。

1クラスにつき、訓練用に130枚ずつ、評価用に40枚ずつ、写真を撮って用意しました。下が用意した写真です。(2クラスなので合計260枚、80枚です)

イメージ説明
イメージ説明
それをgoogle drive に入れ、colaboratoryでマウントし、読み込んでいます。

見よう見まねでコードを書いて実行してみたのですが、acc,val_accが上がらず、loss,val_lossも下がりません。それらの値の変化をプロットしたグラフも振れ幅が大きく正しく学習を行えていると思えません。学習回数を増やしても同様の結果でした。
イメージ説明
イメージ説明

1.学習がうまくいかない原因
2.バッチサイズ、およびステップ数の決め方(今は決め方が分からなくて適当な値を入れています)
3.学習させるにはどうしたらよいのか

この3点について、ご教授お願いします。そのほかコードに変なところがあれば指摘いただきたいです。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

from google.colab import drive
drive.mount('/content/drive')

from keras.models import Sequential, Model
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D, BatchNormalization


num_classes = 2
img_height, img_width =64, 64

#モデルを定義

model = Sequential()
model.add(Conv2D(32, (3, 3), padding='same', activation='relu', input_shape=(img_height, img_width, 3)))
model.add(Conv2D(32, (3, 3), padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))

model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))

model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(num_classes))
model.add(Activation('softmax'))

#ここなに?
for layer in model.layers:
  layer.trainable = True


from keras import optimizers    
model.compile(loss='categorical_crossentropy',
                  optimizer=optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True),
                  metrics=['accuracy'])

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    featurewise_center=True,
    featurewise_std_normalization=True,
    zca_whitening=True
)

test_datagen = ImageDataGenerator(
    rescale=1. / 255,
    featurewise_center=True,
    featurewise_std_normalization=True,
    zca_whitening=True
)

#訓練用データを作る
train_generator = train_datagen.flow_from_directory(
    '/content/drive/My Drive/takekino/train',
    target_size=(img_height, img_width),
    batch_size= 26, #バッチサイズ分かりません
    class_mode='categorical')

#検証用データ
validation_generator = test_datagen.flow_from_directory(
    '/content/drive/My Drive/takekino/val',
    target_size=(img_height, img_width),
    batch_size= 8, #バッチサイズ分かりません
    class_mode='categorical')

#学習
history = model.fit_generator(
    train_generator,
    steps_per_epoch=10, #これも適当です (訓練データサイズ)/(訓練バッチサイズ)?
    epochs=50,
    validation_data=validation_generator,
    validation_steps=10 #これも適当です (評価データサイズ)/(評価バッチサイズ)?
)


# モデルを保存
print("Model saving... at ./drive/My Drive/model.json")
from keras.utils import plot_model
model_json = model.to_json()
with open("./drive/My Drive/takekino_model.json", mode='w') as f:
  f.write(model_json)

# 学習済みの重みを保存
print("Weight saving... at ./drive/My Drive/weights.hdf5")
model.save_weights("./drive/My Drive/takekino_weights.hdf5")


import matplotlib.pyplot as plt
print("plotting...")
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend(['acc', 'val_acc'], loc='lower right')
plt.show()

print("plotting...")
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['loss', 'val_loss'], loc='upper right')
plt.show()

試したこと

回答を受けてまずデータサンプル数を1クラスにつき訓練用200枚、評価用100枚(2クラスで400枚、200枚)に増やしました。
そのうえで、ImageDataGeneratorでの操作を色々変えてみました。

変更1.サンプル数を増やし、ImageDataGeneratorの操作はそのままにしたもの
変更1

変更2.サンプル数を増やしImageDataGeneratorの操作を次のように変更したもの
train_datagen = ImageDataGenerator(
rescale=1. / 255,
horizontal_flip=True
)
test_datagen = ImageDataGenerator(
rescale=1. / 255,
)
変更2

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

1.学習がうまくいかない原因

1から学習するにはデータ枚数が少なすぎるかもしれません。
例えば、サンプルとしてよく使われる MNIST は1クラス5000枚ぐらいあります。

2.バッチサイズ、およびステップ数の決め方(今は決め方が分からなくて適当な値を入れています)

バッチサイズは 1 ~ 100 ぐらいの間で適当に決めてください。
GPU は一度に大量の計算をしたほうが効率がよいので、バッチサイズが大きくするほど学習時間が早くなります。(とはいえ、大きくしすぎると GPU メモリに乗り切らなくなるかもしれない)
しかし、バッチサイズを大きくすると局所解に陥りやすくなるので、結局どの値がいいかは問題によります。
いくつかの値を試して良い値を採用しましょう。

ステップ数はサンプル数 / バッチサイズで決めます。

3.学習させるにはどうしたらよいのか

今回のように学習データのサンプル数が少ない場合は、フルスクラッチで学習するのではなく、学習済みのモデルを使って転移学習をしたほうが精度がでるかもしれません。

Applications - Keras Documentation

Keras では VGG 等の学習済みモデルが提供されているので、これを使うのがよいでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/08 21:03

    >それは過学習です。

    そうなんですね。「学習ができている」と判断していました…

    >Data Argumentation は確かに精度向上に効果はあるのですが、パラメータをたくさん指定して闇雲に増やせばいいというわけではありません

    穴埋めによっていらない情報が増えたことでAugmentationを行う前よりおかしな挙動をするようになったのかもしれないと思いました。気を付けて使う必要があるようですね。

    >まずは rescale=1. / 255 とhorizontal_flip=True だけで試されてはどうでしょうか。
    サンプル数を増やし、この条件で実行してみたところ、追記画像のような結果になりました。
    とりあえずサンプル数が増えたことでハチャメチャなグラフがでることはなくなりました。ありがとうございます。

    >ImageDataGenerator は予め n 倍に増やしたりするわけではなく、ミニバッチに対してリアルタイムに変換を行い、モデルにわたすようになっています。

    そうだったんですね。

    キャンセル

  • 2019/05/09 11:15 編集

    追記された画像を拝見しましたが、バリデーションの精度も80%は超えていおり、グラフの推移を見ても学習できているように思えます。
    ここからさらに精度を上げるためには、サンプル増やす、フルスクラッチでなく、転移学習をする等いろいろ試されるとよいと思います。

    もし質問内容が解決されたようでしたら、お手数ですが、質問をクローズしていただけますか。

    キャンセル

  • 2019/05/09 20:07

    転移学習も試してみたところ、val_acc = 0.9550 と、より精度を上げることができました。
    ありがとうございます。

    キャンセル

+1

読み込みの際に1/255してさらにImageDataGeneratorで
rescale=1. / 255 してないでしょうか。

他のものも効くやつと効かないやつがあるかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/08 12:56

    daesakaさん、回答ありがとうございます。

    rescale しているのは ImageDataGeneratorの部分のみだと思っていましたが、私自身コードの意味がまだよくわかっていないので調べてみます。

    「他のものも効くやつと効かないやつがあるかもしれない」について、ImageDataGeneratorによるデータ拡張が効かない場合、あるいは学習を妨げるような場合があるのでしょうか?

    キャンセル

  • 2019/05/08 13:33

    > あるいは学習を妨げるような場合があるのでしょうか?
    多少学習の妨げになった経験があります。rescaleが原因じゃなかったら1つ1つ確認してみても良いかもしれません。

    キャンセル

  • 2019/05/08 20:52

    >多少学習の妨げになった経験があります。
    そうなんですね。一つ一つ確認してみたところ、違いはあまりありませんでした。
    ただ、有効性はデータにもよるらしいと知ったので、今回の画像に対しては適切な操作ではなかったのかもしれません。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる