読者です 読者をやめる 読者になる 読者になる

pythonでdenoising auto encoderを使ってデータを前処理する

python データ解析 機械学習 深層学習 前処理 自然言語処理

概要

まず、PFNの得居さんの記事を参照。

www.beam2d.net

データにランダムにノイズを乗せたものを入力として、元のデータを正解とする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_noiserateの数だけノイズをランダムにのせる関数。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')

f:id:misos:20161023022037p:plain

なんだか順調に誤差を減らしてってるようす。もう少しノイズを増やしたりして実データに適用できるように調整の必要あり。

Snoek, Jasper, Hugo Larochelle, and Ryan P. Adams. "Practical bayesian optimization of machine learning algorithms." Advances in neural information processing systems. 2012. らを参考にしながらパラメータの最適な選択を今後どっかでする、かも?