2017-12-02 15 views
0

私はこのmachinelearningmasteryチュートリアルに示すLSTMモデルの出力にわたって注意ラッパーを実装しようとしている:LSTMに適用されたアテンションラッパーの出力をTimeDistributedレイヤーの入力として使用する方法、Keras?

from numpy import array 
from keras.models import Sequential 
from keras.layers import Dense 
from keras.layers import TimeDistributed 
from keras.layers import LSTM 
# prepare sequence 
length = 5 
seq = array([i/float(length) for i in range(length)]) 
X = seq.reshape(1, length, 1) 
y = seq.reshape(1, length, 1) 
# define LSTM configuration 
n_neurons = length 
n_batch = 1 
n_epoch = 1000 
# create LSTM 
model = Sequential() 
model.add(LSTM(n_neurons, input_shape=(length, 1), return_sequences=True)) 
model.add(TimeDistributed(Dense(1))) 
model.compile(loss='mean_squared_error', optimizer='adam') 
print(model.summary()) 
# train LSTM 
model.fit(X, y, epochs=n_epoch, batch_size=n_batch, verbose=2) 
# evaluate 
result = model.predict(X, batch_size=n_batch, verbose=0) 
for value in result[0,:,0]: 
    print('%.1f' % value) 

出力LSTMの(samples, steps, features)return_sequences = trueとは形状を出力する(注目ラッパーによって受信されます(サンプル、機能))。ここに私の修正コードは次のとおりです。

model = Sequential() 
model.add(LSTM(n_neurons, input_shape=(length, 1), return_sequences=True)) 
model.add(Attention()) 
model.add(TimeDistributed(Dense(1))) 

hereを説明するように、私が注目ラッパーを使用している:

def dot_product(x, kernel): 


     if K.backend() == 'tensorflow': 
      # todo: check that this is correct 
      return K.squeeze(K.dot(x, K.expand_dims(kernel)), axis=-1) 
     else: 
      return K.dot(x, kernel) 


class Attention(Layer): 
    def __init__(self, 
       W_regularizer=None, b_regularizer=None, 
       W_constraint=None, b_constraint=None, 
       bias=True, **kwargs): 

     self.supports_masking = True 
     self.init = initializers.get('glorot_uniform') 

     self.W_regularizer = regularizers.get(W_regularizer) 
     self.b_regularizer = regularizers.get(b_regularizer) 

     self.W_constraint = constraints.get(W_constraint) 
     self.b_constraint = constraints.get(b_constraint) 

     self.bias = bias 
     super(Attention, self).__init__(**kwargs) 

    def build(self, input_shape): 
     assert len(input_shape) == 3 

     self.W = self.add_weight((input_shape[-1],), 
           initializer=self.init, 
           name='{}_W'.format(self.name), 
           regularizer=self.W_regularizer, 
           constraint=self.W_constraint) 
     if self.bias: 
      self.b = self.add_weight((input_shape[1],), 
            initializer='zero', 
            name='{}_b'.format(self.name), 
            regularizer=self.b_regularizer, 
            constraint=self.b_constraint) 
     else: 
      self.b = None 

     self.built = True 

    def compute_mask(self, input, input_mask=None): 
     # do not pass the mask to the next layers 
     return None 

    def call(self, x, mask=None): 
     eij = dot_product(x, self.W) 

     if self.bias: 
      eij += self.b 

     eij = K.tanh(eij) 

     a = K.exp(eij) 

     # apply mask after the exp. will be re-normalized next 
     if mask is not None: 
      # Cast the mask to floatX to avoid float64 upcasting in theano 
      a *= K.cast(mask, K.floatx()) 

     # in some cases especially in the early stages of training the sum may be almost zero 
     # and this results in NaN's. A workaround is to add a very small positive number ε to the sum. 
     # a /= K.cast(K.sum(a, axis=1, keepdims=True), K.floatx()) 
     a /= K.cast(K.sum(a, axis=1, keepdims=True) + K.epsilon(), K.floatx()) 

     a = K.expand_dims(a) 
     weighted_input = x * a 
     return K.sum(weighted_input, axis=1) 

    def get_output_shape_for(self, input_shape): 
     return input_shape[0], input_shape[-1] 

しかし、私が手にエラーがある:

ValueError: Input 0 is incompatible with layer time_distributed_1: expected ndim=3, found ndim=2

どのような方法がありますTimeDistributedレイヤーを使用するようにアテンションラッパーの出力の形状を再調整するにはどうすればよいですか?

+0

get_output_shape_for compute_output_shape? – Ajjo

答えて

1

call()で返されるテンソルの形状を調整するには、K.reshapeまたはK.expand_dimsを使用します。 TDレイヤーは3次元を、K.sumは2次元を返します。 a = K.sum(weighted_input、axis = 1)と仮定して、K.expand_dims(a、axis = 2)またはK.reshape(a、shape =( - 1,5,1))を試すか、

+0

あなたは 'weighted_input'を詳しく教えてもらえますか? –

+0

次のレイヤーが期待しているのはシーケンスです。expand_dim 'a'を3次元に変換し、それをWに掛けてシーケンスを返します。軸= 1に沿ってそれを合計して、それを2Dに戻します。これは、次のレイヤーが期待しているものではありません。ここではexpand_dimに気づいていませんでした。 TD層を直接的に形成する。 – Ajjo

関連する問題