開発のヒホ

iOSとかAndroidとかのアプリを開発するのに四苦八苦するブログ

TheanoのAutoEncoder実装例のcaglar/autoencodersを動かす四苦八苦

 Theanoを使った機械学習の勉強に励む中、とりあえず実装例を見たいと思いAutoEncoderをTheanoで実装したらしい一連のリポジトリを見つけて喜んでいました。
 caglar/autoencoders · GitHub

 このプログラムを動かす中で行った四苦八苦をメモに残しておこうと思います。
 とりあえずこちらの環境ではPython3.4.3で、caglar/autoencodersのcommitは16a65a0fd4c2b61917ae60432011f1702ce0d8f8です。

Python3に対応させる

 いつものxrange(->range(print hoge->print(hoge)の他、ae.pyなどの下記一行を修正します。

# n_batches = data.shape[0] / batch_size
n_batches = data.shape[0] // batch_size

 これでn_batchesが整数になり、range(n_batches)でエラーを出さなくなります。

ae.pyを実行可能にする

 ae.pyを実行しようとすると下記エラーに阻まれました。

ValueError: Input dimension mis-match. (input[0].shape[1] = 784, input[1].shape[1] = 30)
Apply node that caused the error: Elemwise{Composite{tanh((i0 + i1))}}[(0, 0)](Dot22.0, InplaceDimShuffle{x,0}.0)
Inputs types: [TensorType(float64, matrix), TensorType(float64, row)]
Inputs shapes: [(10000, 784), (1, 30)]
Inputs strides: [(6272, 8), (240, 8)]
Inputs values: ['not shown', 'not shown']

HINT: Re-running with most Theano optimization disabled could give you a back-trace of when this node was created. This can be done with by setting the Theano flag 'optimizer=fast_compile'. If that does not work, Theano optimizations can be disabled with 'optimizer=None'.
HINT: Use the Theano flag 'exception_verbosity=high' for a debugprint and storage map footprint of this apply node.

 どうやらdecode()内で、入力値のshapeと隠れ層出力値のshapeが合ってないようです。ということでlayer.pyファイル内の132行目あたりを以下のように修正。 layer.py

        if bhid is not None:
            self.b_prime = bhid
        else:
            if n_in_dec is not None:
                b_values = numpy.zeros((n_out_dec), dtype=theano.config.floatX)
            else:
#                b_values = numpy.zeros((self.n_out/num_pieces), dtype=theano.config.floatX)
                b_values = numpy.zeros((self.n_in/num_pieces), dtype=theano.config.floatX)

            self.b_prime = theano.shared(value=b_values, name='b_prime')

sa.pyを修正する

 sa.pyもこのままでは正常に動作しません。最初の方のcost_typeのデフォルト値がクロスエントロピーになっているせいです。MeanSquaredに変更します。

# cost_type=CostType.CrossEntropy,
cost_type=CostType.MeanSquared,

 更に、updates部分でdict型を与えてしまっているのでOrderedDictに変更し、最初の方でimportします。

from collections import OrderedDict

# updates = {}
updates = OrderedDict({})

 あと、KL値を計算する際にlogを用いますが、負の数が入ると計算結果がNaNになるので小さい値を足すようにします。

# def kl_divergence(self, p, p_hat):
def kl_divergence(self, p, p_hat, epsilon=1e-6):
    term1 = p * T.log(p)
#     term2 = p * T.log(p_hat)
    term2 = p * T.log(p_hat+epsilon)
    term3 = (1-p) * T.log(1 - p)
    term4 = (1-p) * T.log(1 - p_hat)
    return term1 - term2 + term3 - term4

 encode関数の出力値からスパース項を計算するが、デフォルトでは出力値を正規化するようになっていてスパース項の計算値が狂うので変更。

def get_sa_sgd_updates(self, learning_rate, sparsity_level, sparse_reg, x_in=None):
#         h = self.encode(x_in)
        h = self.encode(x_in, center=False)

 また四苦八苦した部分があれば書き足します。