Help us understand the problem. What is going on with this article?

optunaとkerasによるCNNのハイパーパラメータの最適化

簡単な自己紹介
2019/09現在 画像分類の課題に取り組んでいるエンジニア

会社の方針で画像認識に取り組んでいる。
畳み込みを用いたモデルで認識させようとしているが、ハーパーパラメータの探索がめんどくさい。
optunaが便利そうという記事をいくつか読んだので、コピペで組んだものを有識者に見てほしい。(まだ本番用のモデルの性能が確認できていない)

今回のプログラムは、
①訓練データフォルダとテストデータフォルダを用意
②それぞれの中に同数のクラスフォルダを同順で配置
となっていれば動くと思います。

探索したいパラメータが、
①畳み込みの層数
②畳み込みのフィルター枚数
③畳み込みのストライド数
④ドロップアウト率
となっています。

元のプログラムはhttps://www.snova301.work/entry/2018/12/14/191025
の記事を参照しました(というかほぼ丸コピー、ご指摘ただければすぐに記事について対応いたします。)

sample.py
import numpy as np
import optuna
import os
from PIL import Image

from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D, BatchNormalization
from keras.utils import np_utils


def machine_learning_data(make_folder):
    train_data_folder_list = os.listdir("./" + make_folder)
    a = [] # 画像の絶対パス格納用配列
    b =[] # 画像のクラス番号格納用配列
    c=0

    for i in train_data_folder_list:
        train_data_file_list = os.listdir("./"+ make_folder + "/" + i)
        for l in train_data_file_list:
            a.append(os.path.abspath("./"+ make_folder + "/" + i + "/" + l))
            b.append(c)
        c = c + 1
    d = np.array(Image.open(a[0]))
    z = np.zeros((len(a),d.shape[0],d.shape[1]))
    b = np_utils.to_categorical(b,7) # クラス番号をOne Hot 表現に変換
    for i,l in enumerate(a):
        z[i] = np.array(Image.open(l))
    z = z.reshape(len(a),d.shape[0],d.shape[1],1)
    z = z.astype('float32')/255
    return z,b

x_train,y_train = machine_learning_data("notMNIST_small")
x_test,y_test = machine_learning_data("sample")


def create_model(n_layer,n_filter,activation, filter_step, mid_units, dropout_rate):
    model = Sequential()

    for i in range(n_layer):
        print("n_layer",n_layer,"n_filter",n_filter,'stride',filter_step,"activation", activation, "mid_units", mid_units, "dropout_rate",dropout_rate)
        model.add(Conv2D(filters=n_filter, kernel_size=(3, 3), strides=(filter_step,filter_step), activation=activation, input_shape=(200, 200, 1)))
        model.add(MaxPooling2D(pool_size=(1, 1), strides=2))
        model.add(BatchNormalization())

    model.add(Flatten())
    model.add(Dropout(dropout_rate))

    model.add(Dense(7, activation=activation))

    return model

def objective(trial):
    x_train,y_train = machine_learning_data("notMNIST_small")
    x_test,y_test = machine_learning_data("sample")

    # 調整したいハイパーパラメータの設定
    n_layer = trial.suggest_int('n_layer', 1, 6) # 追加する層を1-3から選ぶ
    n_filter = trial.suggest_int('n_filter', 5, 25) # 畳み込みフィルターの数
    filter_step = trial.suggest_int('filter_step',1,3) # 畳み込みフィルターのストライド数
    mid_units = trial.suggest_int('mid_units', 10, 100) # ユニット数
    dropout_rate = trial.suggest_uniform('dropout_rate', 0, 1) # ドロップアウト率
    activation = trial.suggest_categorical('activation', ['relu','sigmoid']) # 活性化関数
    optimizer = trial.suggest_categorical('optimizer', ['sgd', 'adam', 'rmsprop']) # 最適化アルゴリズム

    # 学習モデルの構築と学習の開始
    model = create_model(n_layer,n_filter,activation, filter_step, mid_units, dropout_rate)
    model.compile(optimizer=optimizer,
                    loss='categorical_crossentropy',
                    metrics=['accuracy'])
    history = model.fit(x_train, y_train, 
                        verbose=1,
                        epochs=10,
                        validation_data=(x_test, y_test),
                        batch_size=100)

    # 学習モデルの保存
    model_json = model.to_json()
    with open('keras_model.json', 'w') as f_model:
        f_model.write(model_json)

    model.save_weights('keras_model.hdf5')

    # 最小値探索なので
    return -np.amax(history.history['val_acc'])

def main():
    study = optuna.create_study(sampler=optuna.samplers.TPESampler())
    study.optimize(objective, n_trials=100)
    print('best_params')
    print(study.best_params)
    print('-1 x best_value')
    print(-study.best_value)

    sortdict = sorted(study.best_params.items())
    z = np.zeros((len(sortdict),1))
    z = z.astype(np.unicode)
    for i,l in enumerate(sortdict):
        print(i,l)
        z[i,0] = l[0]

    np.save("best_params_item",z)

    sortdict = sorted(study.best_params.items())
    z = np.zeros((len(sortdict),1))
    z = z.astype(np.unicode)
    for i,l in enumerate(sortdict):
        print(i,l)
        z[i,0] = l[1]

    np.save("best_params_value",z)

    print('\n --- sorted --- \n')
    sorted_best_params = sorted(study.best_params.items(), key=lambda x : x[0])
    for i, k in sorted_best_params:
        print(i + ' : ' + str(k))

if __name__ == '__main__':
    main()

普段はchainerを使っているのでkerasのモデルの組み方がまだあまり分かっておらず勉強しようかと思ってます。
多分層ごとにフィルターの枚数やストライドは変えてないと思うので、その辺も探索できるようにしたいけど、知ってる方いたらご教授願います。

どなたかの参考になれば幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした