Distribution temporelle (Dense) vs Dense dans les Kéras-même nombre de paramètres

je construis un modèle qui convertit une chaîne en une autre chaîne en utilisant des couches récurrentes (GRUs). J'ai essayé à la fois une couche Dense et une couche distribuée dans le temps(Dense) comme dernière couche avant Une, mais je ne comprends pas la différence entre les deux lorsqu'on utilise return_sequences=True, d'autant plus qu'elles semblent avoir le même nombre de paramètres.

Mon modèle simplifié est le suivant:

InputSize = 15
MaxLen = 64
HiddenSize = 16

inputs = keras.layers.Input(shape=(MaxLen, InputSize))
x = keras.layers.recurrent.GRU(HiddenSize, return_sequences=True)(inputs)
x = keras.layers.TimeDistributed(keras.layers.Dense(InputSize))(x)
predictions = keras.layers.Activation('softmax')(x)

Le résumé de ce réseau est:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 64, 15)            0         
_________________________________________________________________
gru_1 (GRU)                  (None, 64, 16)            1536      
_________________________________________________________________
time_distributed_1 (TimeDist (None, 64, 15)            255       
_________________________________________________________________
activation_1 (Activation)    (None, 64, 15)            0         
=================================================================

cela a du sens pour moi comme ma compréhension de temps distribué est qu'il applique la même couche à tous les points de temps, et donc la couche Dense a 16*15+15 = 255 paramètres (poids+biais).

par contre, si je passe à une simple couche Dense:

inputs = keras.layers.Input(shape=(MaxLen, InputSize))
x = keras.layers.recurrent.GRU(HiddenSize, return_sequences=True)(inputs)
x = keras.layers.Dense(InputSize)(x)
predictions = keras.layers.Activation('softmax')(x)

je n'ai encore que 255 paramètres:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 64, 15)            0         
_________________________________________________________________
gru_1 (GRU)                  (None, 64, 16)            1536      
_________________________________________________________________
dense_1 (Dense)              (None, 64, 15)            255       
_________________________________________________________________
activation_1 (Activation)    (None, 64, 15)            0         
=================================================================

je me demande si C'est parce que Dense() n'utilisera que la dernière dimension de la forme, et traitera effectivement tout le reste comme une dimension discontinue. Mais alors je ne suis plus sûr de ce que la différence est entre Dense et distribuée dans le temps(Dense).

mise à Jour en regardant https://github.com/fchollet/keras/blob/master/keras/layers/core.py Il semble que Dense n'utilise la dernière dimension que pour se dimensionner:

def build(self, input_shape):
    assert len(input_shape) >= 2
    input_dim = input_shape[-1]

    self.kernel = self.add_weight(shape=(input_dim, self.units),

il utilise aussi des keras.dot d'appliquer les poids:

def call(self, inputs):
    output = K.dot(inputs, self.kernel)

les docs de keras.dot implique que cela fonctionne très bien sur les tenseurs n-dimensionnels. Je me demande si son comportement exact signifie que Dense () effet être appelée à chaque pas de temps. Si c'est le cas, la question reste de savoir ce que TimeDistributed() obtient dans ce cas.

11
demandé sur thon 2017-06-18 04:41:08

2 réponses

TimeDistributedDense applique une même densité à chaque pas de temps pendant le déroulement de la cellule GRU/LSTM. Donc la fonction d'erreur sera entre la séquence prédite de l'étiquette et la séquence réelle de l'étiquette. (Qui est normalement l'exigence pour les problèmes d'étiquetage de séquence à séquence).

cependant, avec return_sequences=False, la couche Dense n'est appliquée qu'une seule fois à la dernière cellule. C'est normalement le cas lorsque les RNR sont utilisées pour des problèmes de classification. Si return_sequences=True, puis Dense layer est appliqué à chaque pas de temps comme TimeDistributedDense.

ainsi, selon vos modèles, les deux sont identiques, mais si u change votre second modèle en "return_sequences=False" alors la densité ne sera appliquée qu'à la dernière cellule. Essayez de le changer et le modèle jettera comme erreur parce que alors le Y sera de taille [Batch_size, InputSize], il n'est plus une séquence à la séquence mais une séquence complète au problème d'étiquette.

from keras.models import Sequential
from keras.layers import Dense, Activation, TimeDistributed
from keras.layers.recurrent import GRU
import numpy as np

InputSize = 15
MaxLen = 64
HiddenSize = 16

OutputSize = 8
n_samples = 1000

model1 = Sequential()
model1.add(GRU(HiddenSize, return_sequences=True, input_shape=(MaxLen, InputSize)))
model1.add(TimeDistributed(Dense(OutputSize)))
model1.add(Activation('softmax'))
model1.compile(loss='categorical_crossentropy', optimizer='rmsprop')


model2 = Sequential()
model2.add(GRU(HiddenSize, return_sequences=True, input_shape=(MaxLen, InputSize)))
model2.add(Dense(OutputSize))
model2.add(Activation('softmax'))
model2.compile(loss='categorical_crossentropy', optimizer='rmsprop')

model3 = Sequential()
model3.add(GRU(HiddenSize, return_sequences=False, input_shape=(MaxLen, InputSize)))
model3.add(Dense(OutputSize))
model3.add(Activation('softmax'))
model3.compile(loss='categorical_crossentropy', optimizer='rmsprop')

X = np.random.random([n_samples,MaxLen,InputSize])
Y1 = np.random.random([n_samples,MaxLen,OutputSize])
Y2 = np.random.random([n_samples, OutputSize])

model1.fit(X, Y1, batch_size=128, nb_epoch=1)
model2.fit(X, Y1, batch_size=128, nb_epoch=1)
model3.fit(X, Y2, batch_size=128, nb_epoch=1)

print(model1.summary())
print(model2.summary())
print(model3.summary())

dans l'exemple ci-dessus architecture du model1 et model2 sont de l'échantillon (séquence de séquence de modèles) et model3 est une séquence complète de l'étiquette de modèle.

7
répondu mujjiga 2017-06-19 11:58:32

voici un morceau de code qui vérifie TimeDistirbuted(Dense(X)) est identique à Dense(X):

import numpy as np 
from keras.layers import Dense, TimeDistributed
import tensorflow as tf

X = np.array([ [[1, 2, 3],
                [4, 5, 6],
                [7, 8, 9],
                [10, 11, 12]
               ],
               [[3, 1, 7],
                [8, 2, 5],
                [11, 10, 4],
                [9, 6, 12]
               ]
              ]).astype(np.float32)
print(X.shape)

(2, 4, 3)

dense_weights = np.array([[0.1, 0.2, 0.3, 0.4, 0.5],
                          [0.2, 0.7, 0.9, 0.1, 0.2],
                          [0.1, 0.8, 0.6, 0.2, 0.4]])
bias = np.array([0.1, 0.3, 0.7, 0.8, 0.4])
print(dense_weights.shape)

(3, 5)

dense = Dense(input_dim=3, units=5, weights=[dense_weights, bias])
input_tensor = tf.Variable(X, name='inputX')
output_tensor1 = dense(input_tensor)
output_tensor2 = TimeDistributed(dense)(input_tensor)
print(output_tensor1.shape)
print(output_tensor2.shape)

(2, 4, 5)

(2,?, 5)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    output1 = sess.run(output_tensor1)
    output2 = sess.run(output_tensor2)

print(output1 - output2)

Et la différence est:

[[[0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]]

 [[0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]]]
0
répondu user263387 2018-07-14 19:45:43