2017-06-26 3 views
2

Je suis curieux de savoir s'il existe un bon moyen de partager des poids entre différentes cellules RNN tout en alimentant chaque cellule différentes entrées.Comment partager des poids entre différentes cellules RNN qui alimentent différentes entrées dans Tensorflow?

Le graphique que je suis en train de construire est comme ceci:

enter image description here

où il y a trois cellules LSMC en orange qui fonctionnent en parallèle et entre lesquels je voudrais partager les poids.

J'ai réussi à implémenter quelque chose de similaire à ce que je veux en utilisant un espace réservé (voir ci-dessous pour le code). Toutefois, l'utilisation d'un espace réservé rompt les calculs de gradient de l'optimiseur et n'entraîne rien au-delà du point où j'utilise l'espace réservé. Est-il possible de faire cela mieux dans Tensorflow?

J'utilise tensorflow 1.2 et Python 3.5 dans un environnement Anaconda sous Windows 7.

code:

def ann_model(cls,data, act=tf.nn.relu): 
    with tf.name_scope('ANN'): 
     with tf.name_scope('ann_weights'): 
      ann_weights = tf.Variable(tf.random_normal([1, 
                 cls.n_ann_nodes])) 
     with tf.name_scope('ann_bias'): 
      ann_biases = tf.Variable(tf.random_normal([1])) 
     out = act(tf.matmul(data,ann_weights) + ann_biases) 
    return out 

def rnn_lower_model(cls,data): 
    with tf.name_scope('RNN_Model'): 
     data_tens = tf.split(data, cls.sequence_length,1) 
     for i in range(len(data_tens)): 
      data_tens[i] = tf.reshape(data_tens[i],[cls.batch_size, 
                cls.n_rnn_inputs]) 

     rnn_cell = tf.nn.rnn_cell.BasicLSTMCell(cls.n_rnn_nodes_lower) 

     outputs, states = tf.contrib.rnn.static_rnn(rnn_cell, 
                data_tens, 
                dtype=tf.float32) 

     with tf.name_scope('RNN_out_weights'): 
      out_weights = tf.Variable(
        tf.random_normal([cls.n_rnn_nodes_lower,1])) 
     with tf.name_scope('RNN_out_biases'): 
      out_biases = tf.Variable(tf.random_normal([1])) 

     #Encode the output of the RNN into one estimate per entry in 
     #the input sequence 
     predict_list = [] 
     for i in range(cls.sequence_length): 
      predict_list.append(tf.matmul(outputs[i], 
              out_weights) 
              + out_biases) 
    return predict_list 

def create_graph(cls,sess): 
    #Initializes the graph 
    with tf.name_scope('input'): 
     cls.x = tf.placeholder('float',[cls.batch_size, 
             cls.sequence_length, 
             cls.n_inputs]) 
    with tf.name_scope('labels'): 
     cls.y = tf.placeholder('float',[cls.batch_size,1]) 
    with tf.name_scope('community_id'): 
     cls.c = tf.placeholder('float',[cls.batch_size,1]) 

    #Define Placeholder to provide variable input into the 
    #RNNs with shared weights  
    cls.input_place = tf.placeholder('float',[cls.batch_size, 
               cls.sequence_length, 
               cls.n_rnn_inputs]) 

    #global step used in optimizer 
    global_step = tf.Variable(0,trainable = False) 

    #Create ANN 
    ann_output = cls.ann_model(cls.c) 
    #Combine output of ANN with other input data x 
    ann_out_seq = tf.reshape(tf.concat([ann_output for _ in 
              range(cls.sequence_length)],1), 
          [cls.batch_size, 
          cls.sequence_length, 
          cls.n_ann_nodes]) 
    cls.rnn_input = tf.concat([ann_out_seq,cls.x],2) 

    #Create 'unrolled' RNN by creating sequence_length many RNN Cells that 
    #share the same weights. 
    with tf.variable_scope('Lower_RNNs'): 
     #Create RNNs 
     daily_prediction, daily_prediction1 =[cls.rnn_lower_model(cls.input_place)]*2 

Lorsque des mini-lots de formation sont calculés en deux étapes:

RNNinput = sess.run(cls.rnn_input,feed_dict = { 
              cls.x:batch_x, 
              cls.y:batch_y, 
              cls.c:batch_c}) 
_ = sess.run(cls.optimizer, feed_dict={cls.input_place:RNNinput, 
             cls.y:batch_y, 
             cls.x:batch_x, 
             cls.c:batch_c}) 

Merci pour votre aide. Toute idée serait appréciée.

+0

Pourquoi vous avez deux feed_dict pour? –

+0

Le second est le même que le premier, mais inclut le 'RNNinput' qui était le résultat du premier 'sess.run'. C'est comment je passe la sortie de la couche inférieure avec des cellules RNN partagées à la couche supérieure. J'utilise l'espace réservé 'cls.input_place' pour le faire dans le second appel 'sess.run'. Malheureusement, cela brise les calculs de rétropropagation de tensorflow. – AlexR

+0

Vous ne devriez pas faire cela. Vous construisez un graphique comme vous l'avez mentionné dans le lien, alimentez les entrées une fois et laissez l'ensemble du réseau s'entraîner. Pour quelle raison, pourquoi n'avez-vous pas été capable de faire cela? –

Répondre

1

Vous avez 3 entrées différentes: input_1, input_2, input_3 l'a alimenté sur un modèle LSTM dont les paramètres sont partagés. Et puis vous concaténer les sorties du 3 lstm et le passer à une couche LSTM finale. Le code doit ressembler à ceci:

# Create input placeholder for the network 
input_1 = tf.placeholder(...) 
input_2 = tf.placeholder(...) 
input_3 = tf.placeholder(...) 

# create a shared rnn layer 
def shared_rnn(...): 
    ... 
    rnn_cell = tf.nn.rnn_cell.BasicLSTMCell(...) 

# generate the outputs for each input 
with tf.variable_scope('lower_lstm') as scope: 
    out_input_1 = shared_rnn(...) 
    scope.reuse_variables() # the variables will be reused. 
    out_input_2 = shared_rnn(...) 
    scope.reuse_variables() 
    out_input_3 = shared_rnn(...) 

# verify whether the variables are reused 
for v in tf.global_variables(): 
    print(v.name) 

# concat the three outputs 
output = tf.concat... 

# Pass it to the final_lstm layer and out the logits 
logits = final_layer(output, ...) 

train_op = ... 

# train 
    sess.run(train_op, feed_dict{input_1: in1, input_2: in2, input_3:in3, labels: ...} 
+0

Merci. C'est plus comme ce que je voulais faire. – AlexR

0

J'ai fini par repenser mon architecture et j'ai trouvé une solution plus pratique. Au lieu de dupliquer la couche intermédiaire des cellules LSTM pour créer trois cellules différentes avec les mêmes poids, j'ai choisi de faire tourner la même cellule trois fois. Les résultats de chaque exécution ont été stockés dans un 'buffer' comme tf.Variable, puis cette variable entière a été utilisée comme entrée dans la couche LSTM finale. I drew a diagram here

La mise en œuvre de cette façon autorisée pour les sorties valides après 3 pas de temps, et ne cassait pas tensorflows algorithme de rétropropagation (à savoir les nœuds du ANN pourraient encore entraîner.)

La seule chose difficile était de faire Assurez-vous que le tampon était dans l'ordre séquentiel correct pour le RNN final.