KerasのコードをChainerに書き換えたい(LSTM Autoencoderの実装)
Kerasで次のようなLSTMオートエンコーダーが実装されています。
import numpy as np
from keras.layers import Input, GRU
from keras.models import Model
input_feat = Input(shape=(30, 2000))
l = GRU( 100, return_sequences=True, activation="tanh", recurrent_activation="hard_sigmoid")(input_feat)
l = GRU(2000, return_sequences=True, activation="tanh", recurrent_activation="hard_sigmoid")(l)
model = Model(input_feat, l)
model.compile(optimizer="RMSprop", loss="mean_squared_error")
feat = np.load("feat.npy")
model.fit(feat, feat[:, ::-1, :], epochs=200, batch_size=250)
ここで、featは3次元配列で、feat.shape = (269, 30, 2000) です。
このコードをChainerに書き直すために次のようなコードを書きましたが、学習結果をみるに、どこかが間違っているようです。どこに間違いがあるかわかるでしょうか。
import numpy as np
from chainer import Chain, Variable, optimizers
import chainer.functions as F
import chainer.links as L
class GRUAutoEncoder(Chain):
def __init__(self):
super().__init__()
with self.init_scope():
self.encode = L.GRU(2000, 100)
self.decode = L.GRU(100, 2000)
def __call__(self, h, mode):
if mode == "encode":
h = F.tanh(self.encode(h))
return h
if mode == "decode":
h = F.tanh(self.decode(h))
return h
def reset(self):
self.encode.reset_state()
self.decode.reset_state()
def main():
feat = np.load("feat.npy") #(269, 30, 2000)
gru_autoencoder = GRUAutoEncoder()
optimizer = optimizers.RMSprop(lr=0.01).setup(gru_autoencoder)
N = len(feat)
batch_size = 250
for epoch in range(200):
index = np.random.randint(0, N-batch_size+1)
input_feat = feat[index:index+batch_size] #(250, 30, 2000)
#Encoding
input_vector = np.zeros((30, batch_size, 2000), dtype="float32")
h = []
for i in range(frame_rate):
input_vector[i] = input_feat[:, i, :] #(250, 1, 2000)
tmp = Variable(input_vector[i])
h.append(gru_autoencoder(tmp, "encode")) #(250, 100)
#Decoding
output_vector = []
for i in range(frame_rate):
tmp = h[i]
output_vector.append(gru_autoencoder(tmp, "decode"))
x = input_vector[0]
t = output_vector[0]
for i in range(len(output_vector)):
x = F.concat((x,input_vector[i]), axis=1)
t = F.concat((t,output_vector[i]), axis=1)
loss = F.mean_squared_error(x, t)
gru_autoencoder.cleargrads()
loss.backward()
optimizer.update()
gru_autoencoder.reset()
if __name__ == "__main__":
main()
Kerasのコードではfit(feat, feat[:, ::-1, :])となっているので、x = input_vector[0]の直前でoutput_vector.reverse()とするべきかと思って、それで学習をさせてみましたが、やはり結果がおかしいです。
ご助言いただけると幸いです。
よろしくお願いします。
追記1
Motoki Satoさん、ご回答ありがとうございます。いろいろと調べましたが、上のKerasのコードをNStepGRUを使って書き直す場合は、n_layers=1にするという理解であっているでしょうか。つまり、ネットワークは
class GRUAutoEncoder(Chain):
def __init__(self):
super().__init__()
with self.init_scope():
self.encode = L.NStepGRU(1, 2000, 100, 0)
self.decode = L.NStepGRU(1, 100, 2000, 0)
def __call__(self, h, encode=False):
h = F.tanh(self.encode(h))
if encode:
return h
h = F.tanh(self.decode(h))
return h
def reset(self):
self.encode.reset_state()
self.decode.reset_state()
として、学習すればよいということで間違いないでしょうか。
よろしくお願いします。
追記2
追記1のネットワークを下のように学習させようとしたのですが、TypeError: forward() missing 1 required positional argument: 'xs'というエラーが出ますね。
def main():
feat = np.load("feat.npy")
gru_autoencoder = GRUAutoEncoder()
optimizer = optimizers.RMSprop(lr=0.01).setup(gru_autoencoder)
N = len(feat)
batch_size = 250
for epoch in range(200):
index = np.random.randint(0, N-batch_size+1)
batch = feat[index:index+batch_size] #(250, 30, 2000)
t = gru_autoencoder(batch)
loss = F.mean_squared_error(batch, t)
gru_autoencoder.cleargrads()
loss.backward()
optimizer.update()
gru_autoencoder.reset()