【问题标题】:How to handle gradients when training two sub-graphs simultaneously同时训练两个子图时如何处理梯度
【发布时间】:2016-08-12 22:09:21
【问题描述】:

我试图实现的总体思路是 seq2seq-model(取自模型中的 translate.py-example,基于 seq2seq-class)。这训练得很好。

此外,我正在使用 所有编码完成后的 rnn 的隐藏状态,就在解码开始之前(我称之为“编码结束时的隐藏状态”)。我在编码结束时使用这个隐藏状态来将其输入到另一个子图中,我称之为“价格”(见下文)。这个子图的训练梯度不仅通过这个额外的子图反向传播,而且还回到了 rnn 的编码器部分(这是我想要和需要的)。

计划是在编码结束时将更多这样的子图添加到隐藏状态,因为我想以多种方式分析输入短语。

现在在训练期间,当我同时评估和训练两个子图(编码器+价格和编码器+解码器)时,网络不会收敛。但是,如果我通过以下方式(伪代码)执行训练来进行训练:

if global_step % 10 == 0:
    execute-the-price-training_code
else:
    execute-the-decoder-training_code

所以我不会同时训练两个子图。现在它确实收敛了,但是编码器+解码器部分的收敛速度比我只训练这部分而不训练价格子图要慢得多。

我的问题是:我应该能够同时训练两个子图。但可能我必须在编码结束时重新调整梯度流回隐藏状态。在这里,我们从价格子图和解码器子图获得梯度。应该如何进行这种重新调整。我没有找到任何描述这种事业的论文,但也许我用错误的关键字搜索。

这是代码的训练部分:

这是(几乎是原始的)训练操作准备:

if not forward_only:
  self.gradient_norms = []
  self.updates = []
  opt = tf.train.AdadeltaOptimizer(self.learning_rate)

  for bucket_id in xrange(len(buckets)):
    tf.scalar_summary("seq2seq loss", self.losses[bucket_id])

    gradients = tf.gradients(self.losses[bucket_id], var_list_seq2seq)
    clipped_gradients, norm = tf.clip_by_global_norm(gradients, max_gradient_norm)
    self.gradient_norms.append(norm)
    self.updates.append(opt.apply_gradients(zip(clipped_gradients, var_list_seq2seq), global_step=self.global_step))

现在,另外,我正在运行第二个子图,它将编码结束时的隐藏状态作为输入:

  with tf.name_scope('prices') as scope:
    #First layer
    W_price_first_layer = tf.Variable(tf.random_normal([num_layers*size, self.prices_hidden_layer_size], stddev=0.35), name="W_price_first_layer")
    B_price_first_layer = tf.Variable(tf.zeros([self.prices_hidden_layer_size]), name="B_price_first_layer")
    self.output_price_first_layer = tf.add(tf.matmul(self.hidden_state, W_price_first_layer), B_price_first_layer)
    self.activation_price_first_layer = tf.nn.sigmoid(self.output_price_first_layer)
    #self.activation_price_first_layer = tf.nn.Relu(self.output_price_first_layer)

    #Second layer to softmax (price ranges)
    W_price = tf.Variable(tf.random_normal([self.prices_hidden_layer_size, self.prices_bit_size], stddev=0.35), name="W_price")
    W_price_t = tf.transpose(W_price)
    B_price = tf.Variable(tf.zeros([self.prices_bit_size]), name="B_price")

    self.output_price_second_layer = tf.add(tf.matmul(self.activation_price_first_layer, W_price),B_price)
    self.price_prediction = tf.nn.softmax(self.output_price_second_layer)
    self.label_price      = tf.placeholder(tf.int32, shape=[self.batch_size], name="price_label")

    #Remember the prices trainables
    var_list_prices       = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, "prices")
    var_list_all          = tf.trainable_variables()

    #Backprop
    self.loss_price        = tf.nn.sparse_softmax_cross_entropy_with_logits(self.output_price_second_layer, self.label_price)
    self.loss_price_scalar = tf.reduce_mean(self.loss_price)
    self.optimizer_price   = tf.train.AdadeltaOptimizer(self.learning_rate_prices)
    self.training_op_price = self.optimizer_price.minimize(self.loss_price, var_list=var_list_all)

谢谢一堆

【问题讨论】:

    标签: machine-learning neural-network tensorflow


    【解决方案1】:

    我预计同时运行两个优化器会导致公共变量的梯度更新不一致,这可能会导致您的训练不收敛。

    相反,如果您将每个子网络的标量损失添加到“损失集合”中(例如,通过tf.contrib.losses.add_loss()tf.add_to_collection(tf.GraphKeys.LOSSES, ...),您可以使用tf.contrib.losses.get_total_loss() 获得可以传递给的单个损失值单个标准 TensorFlow tf.train.Optimizer 子类。TensorFlow 将为您的拆分网络派生适当的反向传播计算。

    get_total_loss() 方法只是计算已添加到损失集合中的值的未加权总和。我不熟悉有关如何或是否应该缩放这些值的文献,但您可以使用任意(可微分)TensorFlow 表达式来组合损失并将结果传递给单个优化器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      • 2022-06-10
      • 2019-08-25
      • 2020-05-11
      • 2020-10-01
      相关资源
      最近更新 更多