概要
まず、PFNの得居さんの記事を参照。
データにランダムにノイズを乗せたものを入力として、元のデータを正解とするDNNを学習することでデータからノイズを取り除く(denoiseする)モデルを学習する。中央のレイヤーの次元を少なくすることで、それをある種の潜在ベクトルとして他モデルの入力として利用することが最終的な目的。
今回はノイズのあるデータ = -1 としています。つまり、欠けているデータは -1というデータになっています。
モデル定義
%matplotlib inline import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy as sc import seaborn as sns from keras.layers import Input, Dense from keras.models import Model from keras.callbacks import Callback import codecs as cd # first: build simple auto encoder X = load_data() dimension = X.shape[1] encoding_dim = 200 train_test_rate = .9 train_num = int(X.shape[0]*train_test_rate) loss_history = [] train_X, test_X = X[:train_num, :], X[train_num:, :] print(train_X.shape) class LossHistory(Callback): def on_train_begin(self, logs={}): self.losses = [] def on_batch_end(self, batch, logs={}): self.losses.append(logs.get('loss')) input_v = Input(shape=(dimension,)) encoded = Dense(dimension, activation='relu')(input_v) encoded = Dense(encoding_dim, activation='relu')(encoded) decoded = Dense(encoding_dim, activation='relu')(encoded) decoded = Dense(dimension, activation='relu')(encoded) autoencoder = Model(input=input_v, output=decoded) plotdata = LossHistory() autoencoder.compile(optimizer='adadelta', loss='mse') autoencoder.fit(train_X, train_X, nb_epoch=10, batch_size=20, shuffle=True, validation_data=(test_X, test_X), verbose=2, callbacks=[plotdata]) # save weight autoencoder.save_weights('../param/autoencoder_a.w') loss_history += list(plotdata.losses)
データを適当にロードしてきて、それを元にモデルを学習する。encoding_dim=200としているので入力のベクトルは200以上を想定。 loss_historyに学習のバッチごとの損失を記録していく。初めはおおよそのパラメータを決定するためにノイズを乗せていないデータで学習してパラメータを適当に定める。
ノイズ付加
# next: add noise and learn weight import random def add_noise(X, rate=1): _X = X.copy() (N, M) = _X.shape for r in _X: for i in np.arange(rate): r[random.randint(0, M-1)] = -1 return _X def append_matrix(matrix_list): temp = matrix_list[0] for m in matrix_list[1:]: temp = np.r_[temp, m] print ('append matrix:', temp.shape) return temp noise_X = add_noise(X, rate=1) noise_X2 = add_noise(X, rate=2) X_train_noise = append_matrix([X, noise_X, noise_X2]) X_train_clean = append_matrix([X, X, X])
add_noiseはrateの数だけノイズをランダムにのせる関数。X_train_noiseがノイズのあるデータで X_train_clean がそれに対応するノイズなしのデータ。X_train_noiseを入力に、X_train_cleanを教師データにしてモデルを訓練する。
デノイジングオートエンコーダーの訓練
# retrain model autoencoder.fit(X_train_noise, X_train_clean, nb_epoch=50, batch_size=30, shuffle=True, validation_data=(test_X, test_X), verbose=2, callbacks=[plotdata]) # save weight autoencoder.save_weights('../param/autoencoder_a.w') loss_history += list(plotdata.losses)
fit(X_train_noise, X_train_clean ...の箇所以外はこれまでと同一。
損失関数の推移
plt.figure(figsize=(10, 4)) plt.plot(loss_history) plt.ylim(0, 10) plt.xlabel('#batch') plt.ylabel('rms')

なんだか順調に誤差を減らしてってるようす。もう少しノイズを増やしたりして実データに適用できるように調整の必要あり。
Snoek, Jasper, Hugo Larochelle, and Ryan P. Adams. "Practical bayesian optimization of machine learning algorithms." Advances in neural information processing systems. 2012. らを参考にしながらパラメータの最適な選択を今後どっかでする、かも?