Tensorflow Optimizer介绍


训练常规做法:

1. 定义损失函数loss

2. 使用optimizer进行minimize损失函数loss

minimize loss的由两部分组成:compute_gradients和apply_gradients

(1) compute_gradients
compute_gradients(
    loss,
    var_list=None,
    gate_gradients=GATE_OP,
    aggregation_method=None,
    colocate_gradients_with_ops=False,
    grad_loss=None
)
loss: 损失函数
var_list: 用于求梯度的变量
gate_gradients: 有三个可选项GATE_NONE,GATE_OP,GATE_GRAPH。GATE_NONE最高级别并发,代价是可能不可复现;GATE_OP在每个节点内部,计算完本节点全部梯度才更新参数,节点内部不并发,避免race condition;GATE_GRAPH最低级别并发,在计算好所有的梯度之后才更新参数
aggregation_method: 指定组合梯度的方法AggregationMethod
colocate_gradients_with_ops: 是否在多台gpu上并行计算梯度
grad_loss: Optional. A `Tensor` holding the gradient computed for `loss`.
(2) apply_gradients
apply_gradients(
    grads_and_vars,
    global_step=None,
    name=None
)
grads_and_vars: List of (gradient, variable) pairs as returned by
  `compute_gradients()`.
global_step: Optional `Variable` to increment by one after the
  variables have been updated.
name: Optional name for the returned operation.  Default to the
  name passed to the `Optimizer` constructor.

以AdamOptimizer为例:
原论文的伪代码:
在这里插入图片描述
Tensorflow实现:
l r t : = learning_rate ∗ ( 1 − β 2 t ) / ( 1 − β 1 t ) lr_t := \text{learning\_rate} * \sqrt{(1 - \beta_2^t) / (1 - \beta_1^t)} lrt:=learning_rate(1β2t)/(1β1t)
m t : = β 1 ∗ m t − 1 + ( 1 − β 1 ) ∗ g m_t := \beta_1 * m_{t-1} + (1 - \beta_1) * g mt:=β1mt1+(1β1)g
v t : = β 2 ∗ v t − 1 + ( 1 − β 2 ) ∗ g ∗ g v_t := \beta_2 * v_{t-1} + (1 - \beta_2) * g * g vt:=β2vt1+(1β2)gg
v a r i a b l e : = v a r i a b l e − l r t ∗ m t / ( v t + ϵ ) variable := variable - lr_t * m_t / (\sqrt{v_t} + \epsilon) variable:=variablelrtmt/(vt +ϵ)

代码见:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/training/adam.py
稠密向量的操作:

  def _apply_dense(self, grad, var):
    m = self.get_slot(var, "m")# optiminzer额外参数加入_non_slot_dict
    v = self.get_slot(var, "v")
    beta1_power, beta2_power = self._get_beta_accumulators() # 获取t次方
    return training_ops.apply_adam(
        var,
        m,
        v,
        math_ops.cast(beta1_power, var.dtype.base_dtype),
        math_ops.cast(beta2_power, var.dtype.base_dtype),
        math_ops.cast(self._lr_t, var.dtype.base_dtype),
        math_ops.cast(self._beta1_t, var.dtype.base_dtype),
        math_ops.cast(self._beta2_t, var.dtype.base_dtype),
        math_ops.cast(self._epsilon_t, var.dtype.base_dtype),
        grad,
        use_locking=self._use_locking).op
  def _finish(self, update_ops, name_scope):
    # Update the power accumulators.
    with ops.control_dependencies(update_ops):
      beta1_power, beta2_power = self._get_beta_accumulators()
      with ops.colocate_with(beta1_power):
        update_beta1 = beta1_power.assign(
            beta1_power * self._beta1_t, use_locking=self._use_locking)
        update_beta2 = beta2_power.assign(
            beta2_power * self._beta2_t, use_locking=self._use_locking)
    return control_flow_ops.group(
        *update_ops + [update_beta1, update_beta2], name=name_scope)

其中beta1_power表示 β 1 t \beta_1^t β1t,beta2_power表示 β 2 t \beta_2^t β2t,t次方的实现在_finish函数中。
apply_adam具体实现代码见:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/kernels/training_ops.cc

template <typename T>
struct ApplyAdam<CPUDevice, T> : ApplyAdamNonCuda<CPUDevice, T> {};

template <typename T>
struct ApplyAdamWithAmsgrad<CPUDevice, T> {
  void operator()(const CPUDevice& d, typename TTypes<T>::Flat var,
                  typename TTypes<T>::Flat m, typename TTypes<T>::Flat v,
                  typename TTypes<T>::Flat vhat,
                  typename TTypes<T>::ConstScalar beta1_power,
                  typename TTypes<T>::ConstScalar beta2_power,
                  typename TTypes<T>::ConstScalar lr,
                  typename TTypes<T>::ConstScalar beta1,
                  typename TTypes<T>::ConstScalar beta2,
                  typename TTypes<T>::ConstScalar epsilon,
                  typename TTypes<T>::ConstFlat grad) {
    const T alpha = lr() * Eigen::numext::sqrt(T(1) - beta2_power()) /
                    (T(1) - beta1_power());
    m.device(d) += (grad - m) * (T(1) - beta1()); # 更新m
    v.device(d) += (grad.square() - v) * (T(1) - beta2()); # 更新v
    vhat.device(d) = vhat.cwiseMax(v); 
    var.device(d) -= (m * alpha) / (vhat.sqrt() + epsilon()); # 更新参数
  }
};

稀疏向量的操作:

  def _apply_sparse_shared(self, grad, var, indices, scatter_add):
    beta1_power, beta2_power = self._get_beta_accumulators() # 获取t次方
    beta1_power = math_ops.cast(beta1_power, var.dtype.base_dtype)
    beta2_power = math_ops.cast(beta2_power, var.dtype.base_dtype)
    lr_t = math_ops.cast(self._lr_t, var.dtype.base_dtype)
    beta1_t = math_ops.cast(self._beta1_t, var.dtype.base_dtype)
    beta2_t = math_ops.cast(self._beta2_t, var.dtype.base_dtype)
    epsilon_t = math_ops.cast(self._epsilon_t, var.dtype.base_dtype)
    lr = (lr_t * math_ops.sqrt(1 - beta2_power) / (1 - beta1_power))
    # m_t = beta1 * m + (1 - beta1) * g_t
    m = self.get_slot(var, "m")
    m_scaled_g_values = grad * (1 - beta1_t)
    m_t = state_ops.assign(m, m * beta1_t, use_locking=self._use_locking)
    with ops.control_dependencies([m_t]):
      m_t = scatter_add(m, indices, m_scaled_g_values)
    # v_t = beta2 * v + (1 - beta2) * (g_t * g_t)
    v = self.get_slot(var, "v")
    v_scaled_g_values = (grad * grad) * (1 - beta2_t)
    v_t = state_ops.assign(v, v * beta2_t, use_locking=self._use_locking)
    with ops.control_dependencies([v_t]):
      v_t = scatter_add(v, indices, v_scaled_g_values)
    v_sqrt = math_ops.sqrt(v_t)
    var_update = state_ops.assign_sub(
        var, lr * m_t / (v_sqrt + epsilon_t), use_locking=self._use_locking)
    return control_flow_ops.group(*[var_update, m_t, v_t])
  def _finish(self, update_ops, name_scope):
    # Update the power accumulators.
    with ops.control_dependencies(update_ops):
      beta1_power, beta2_power = self._get_beta_accumulators()
      with ops.colocate_with(beta1_power):
        update_beta1 = beta1_power.assign(
            beta1_power * self._beta1_t, use_locking=self._use_locking)
        update_beta2 = beta2_power.assign(
            beta2_power * self._beta2_t, use_locking=self._use_locking)
    return control_flow_ops.group(
        *update_ops + [update_beta1, update_beta2], name=name_scope)

返回更新参数操作op的group(包括slot和non_slot)。

Bert实现AdamWeightDecayOptimizer的时候少了偏差纠正项,加入正则项。

  def apply_gradients(self, grads_and_vars, global_step=None, name=None):
    """See base class."""
    assignments = []
    for (grad, param) in grads_and_vars:
      if grad is None or param is None:
        continue
      param_name = self._get_variable_name(param.name)
      m = tf.get_variable(
          name=param_name + "/adam_m",
          shape=param.shape.as_list(),
          dtype=tf.float32,
          trainable=False,
          initializer=tf.zeros_initializer())
      v = tf.get_variable(
          name=param_name + "/adam_v",
          shape=param.shape.as_list(),
          dtype=tf.float32,
          trainable=False,
          initializer=tf.zeros_initializer())
      # Standard Adam update.
      next_m = (
          tf.multiply(self.beta_1, m) + tf.multiply(1.0 - self.beta_1, grad))
      next_v = (
          tf.multiply(self.beta_2, v) + tf.multiply(1.0 - self.beta_2,
                                                    tf.square(grad)))
      update = next_m / (tf.sqrt(next_v) + self.epsilon)
      # Just adding the square of the weights to the loss function is *not*
      # the correct way of using L2 regularization/weight decay with Adam,
      # since that will interact with the m and v parameters in strange ways.
      #
      # Instead we want ot decay the weights in a manner that doesn't interact
      # with the m/v parameters. This is equivalent to adding the square
      # of the weights to the loss with plain (non-momentum) SGD.
      if self._do_use_weight_decay(param_name):
        update += self.weight_decay_rate * param
      update_with_lr = self.learning_rate * update
      next_param = param - update_with_lr
      assignments.extend(
          [param.assign(next_param),
           m.assign(next_m),
           v.assign(next_v)])
    return tf.group(*assignments, name=name)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: TensorFlow优化器是一种用于训练神经网络的算法,它可以自动调整模型参数以最小化损失函数。TensorFlow提供了多种优化器,包括梯度下降、Adam、Adagrad等。这些优化器可以根据不同的场景和需求进行选择和调整,以提高模型的性能和效率。 ### 回答2: TensorFlow中的优化器(Optimizer)是一个用于优化神经网络模型的算法。它帮助我们根据训练数据来更新模型的参数,使得模型的预测结果更加准确。TensorFlow提供了多种优化器,每个优化器都有自己的特点和适用场景。 其中最常用的优化器之一是梯度下降法(Gradient Descent)。梯度下降法通过计算参数的梯度,并按照其相反方向调整参数的值,以最小化训练数据的损失函数。TensorFlow中的GradientDescentOptimizer就是梯度下降法的一种实现。我们可以通过指定学习率(learning rate)来控制参数的调整速度。 除了梯度下降法外,TensorFlow还提供了其他的优化器,如Adam、Adagrad、RMSProp等。这些优化器在不同的场景下可能表现更好,具体选择哪个优化器取决于模型和数据的特点。 优化器的使用非常简单,我们可以先定义一个优化器对象,然后在训练过程中调用其minimize方法,传入损失函数和要优化的参数。优化器会自动计算梯度并更新模型参数。 除了基本的优化器,TensorFlow还提供了其他辅助类来帮助优化模型。例如,tf.train.exponential_decay可以根据训练步数自动降低学习率,以提高训练效果。另外,tf.train.Checkpoint和tf.train.Saver可以用来保存和恢复模型的参数,方便模型的训练和使用。 总而言之,TensorFlow的优化器是用于优化神经网络模型的重要工具。通过选择合适的优化器和调整参数,我们能够更好地训练模型,提高预测性能。 ### 回答3: TensorFlow中的optimizer是一种用于优化神经网络模型参数的工具。在深度学习中,优化器扮演着重要的角色,它的作用是通过调整模型的权重和偏差,使模型的损失函数最小化。 TensorFlow提供了多种不同的优化器,包括随机梯度下降(SGD)、Adam、Adagrad等。这些优化器的实现基于不同的算法和原理,每个优化器都具有不同的特性和适用场景。 使用优化器有几个关键步骤。首先,需要定义一个损失函数,通常是模型的预测值与实际标签之间的差异。然后,选择一个合适的优化器,并设置适当的超参数如学习率等。接下来,通过调用optimizer的minimize或apply_gradients函数,计算和应用梯度更新。这样,模型的参数就会根据损失函数的梯度进行更新。最后,循环执行该过程,直到达到某个停止条件。 优化器的选择取决于具体的问题和数据。例如,SGD是最简单的优化器之一,适用于大规模数据集,但收敛速度相对较慢。Adam是一种基于自适应矩估计的优化器,可以在不同的学习率下自动调整梯度。Adagrad则根据参数历史梯度的平方和自动调整学习率。 总之,TensorFlow的优化器是优化神经网络模型参数的重要工具,对模型的训练和性能具有重要影响。选择合适的优化器和调整超参数是深度学习中的关键步骤,可以帮助改善模型的性能和收敛速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值