概要
まず、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. らを参考にしながらパラメータの最適な選択を今後どっかでする、かも?