kerasでオートエンコーダ試してみた【ゴーゴート編】

今日はオートエンコーダの実装してみました。

・はじめに

pythonには機械学習のライブラリが色々あるけど、最近はkerasを使ってます。kerasはとても直感的にモデルを記述できるので初心者にもやさしいです。詳しいことは下記リンクのドキュメンテーション参照です。

・オートエンコーダとは

スクリーンショット 2020-01-29 23.53.13

オートエンコーダとは、画像を一回圧縮して元に戻すっていうもの。エンコード前(入力)とデコード後(出力)が同じものになるように学習します。これの何がいいかっていうと、中間層に特徴が凝縮されているということ。オートエンコーダの中間層を取り出すことによって、元のデータの特徴を保持したままより小さなデータを手に入れることができるというわけです。このオートエンコーダはディープラーニングの最初期にブレイクしていたそうです。次元削減ができるということで、ディープラーニングに突っ込む事前学習としてこのオートエンコーダは重宝したそうです。しかし最近では昔以上に複雑なネットワークも組めるようになり、ディープラーニングではあまり利用されていないんだとか。代わりに最近はGANなどの'生成'に特化した分野で活躍しているそうです。

ゴーゴートとは

ゴーゴートとは、ポケモンXY(第六世代)から登場した山羊さんのポケモン。

画像4

くさタイプのポケモンです。かわいい。XYの冒険の舞台カロス地方では、ゴーゴートの背中に乗って移動する人も少なくないらしい。ヒヨクジムリーダーのフクジさんのエースポケモンでもある。

・実装

データを集める

スクレイピングで集めました。urllibとbeautiful soupを使いました。参考になるページ↓

結果はこんなかんじです。ゴーゴートの画像は80枚用意できました。ちょっと少ないですけど、まあ、とりあえずってかんじで。

スクリーンショット 2020-01-29 22.19.57

データの加工

ネットからとってきた画像たちはjpegとかpngとかいろんな拡張子だったので、まず全部pngファイルに統一しました。コードは以下のとおり。

def processing_files(n, ex):
   f_name = n + '*'
   f_path = ch_dir + '/' + n + '/'
   f_extension = ex

   #files = glob.glob(f_path + f_name)                                 
   files = glob.glob(f_path + '*')
   #print(files)                                                       
   for f in files:
       img = Image.open(f)
       img.save(f[:-3] + f_extension, f_extension)
       if (f[-3:] != f_extension):
           os.remove(f)

第一引数のnはファイルの名前(nameの頭文字)、第二引数のexは拡張子(extension)です。まずglobでディレクトリ内のすべてのファイル名を取得します。そして、ファイル一つ一つの拡張子を確認して、pngでなければpngに変換します。

次に、画像ファイルたちはピクセル数やチャンネル数も違うので、縦100*横100のグレースケールに統一しました。さらに、その後の学習のために正規化し、一次元配列に変換しました。

・
・
・
    for i, img in enumerate(imgs):
       img = img.convert('L')
       img = np.array(img.resize((100, 100)))
       imgs[i] = img.reshape(100 * 100)
       imgs[i] = imgs[i] / imgs[i].max()
   return np.array(imgs, dtype = 'float32')


モデルを作って学習

中間層は三層で、活性化関数はreluを選びました。

   mid_size = 500
   mid_size2 = 1000
   img_hei = 100
   img_wid = 100
   img_size = img_hei * img_wid

   model = keras.Sequential()
   model.add(keras.layers.Dense(mid_size2, activation = tf.nn.relu))
   model.add(keras.layers.Dense(mid_size, activation = tf.nn.relu))
   model.add(keras.layers.Dense(mid_size2, activation = tf.nn.relu))
   model.add(keras.layers.Dense(img_size, activation = tf.nn.sigmoid))

   model.compile(optimizer = tf.train.AdamOptimizer(),
                 loss = 'binary_crossentropy',
                 metrics = ['mean_squared_error', 'binary_crossentropy'])
   epochs = 1500
   batch_size = 32
   history = model.fit(l_train, l_train,
                       epochs = epochs, batch_size = batch_size)

学習したモデルで生成

pltで出力を可視化してみる。

   x_recon = model.predict(l_test)

   plt.figure(figsize = (20, 4))
   for i in range(n):
       ax = plt.subplot(2, n, i + 1)
       plt.imshow(l_test[i].reshape(100, 100), cmap = 'binary')
       ax.get_xaxis().set_visible(False)
       ax.get_yaxis().set_visible(False)

       ax = plt.subplot(2, n, i + 1 + n)
       plt.imshow(x_recon[i].reshape(100, 100), cmap = 'binary')
       ax.get_xaxis().set_visible(False)
       ax.get_yaxis().set_visible(False)

   plt.show()

結果はこんなかんじ↓

画像2

うーん・・・過学習してますね・・・完全に教師データに近いものを生成して出力してしまってるかんじがします。データ少ないのに1500回も回してるから当然かもしれないです。ドロップアウトとかしたらもう少し上手くいくかと試行錯誤しましたが大して成果はみられませんでした。畳み込み使ったり、モデルの構成とかもう少しうまく作れたらいいのかなと思いました。

この記事が気に入ったらサポートをしてみませんか?