[软件工程应用与实践]lingvo学习笔记
2021SC@SDUSC
lingvo.core.egdd module
指数梯度Delta-Delta优化器 Exponentiated Gradient Delta-Delta optimizer
classlingvo.core.egdd.EGDD(
learning_rate,
momentum,
beta=0.9,
gain_learning_rate=0.01,
scale_learning_rate=0.001,
initial_gain=1.0,
min_gain=0.01,
max_gain=100.0,
initial_scale=1.0,
min_scale=0.1,
max_scale=10.0,
use_directions=True,
use_signs=True,
name='EGDD')
基于tensorflow.python.training.optimizer.Optimizer
, GD momentum的一个版本,具有自适应增益和学习速率。
Exponentiated Gradient Delta-delta优化器开始时,每个权重的局部增益为1.0,所有权重的lr_scale为1.0。EGDD更新规则适用于 :
- momentum <- mu * momentum + learning_rate * gain * grad var <- var - lr_scale * momentum
- 增益和lr_scale使用非归一化指数梯度算法进行更新
参数列表
- learning_rate :
float
或Tensor
, 学习率 - momentum :
float
或Tensor
- beta :
float
, EMA 梯度下降率
指数移动平均(Exponential Moving Average)也叫权重移动平均(Weighted Moving Average),是一种给予近期数据更高权重的平均方法。
- gain_learning_rate :
float
, 知识增益率 - scale_learning_rate :
float
, 规模学习速率 - initial_gain :
float
, 初始增益 - min_gain :
float
, 最小增益 - max_gain :
float
, 最大增益 - initial_scale :
float
, 初始规模 - min_scale :
float
, 最小学习规模 - max_scale :
float
, 最大规模 - use_directions :
bool
, 判断方向是否仅应用于更新规模 - use_signs :
bool
, 判断更新增益时是否有符号 - name : 应用时创建的操作的可选名称前缀梯度
方法
_create_slots(var_list)
参数列表 :
- var_list :
variable
对象列表
函数作用 : 创建变量所需的所有槽。
源码:
def _create_slots(self, var_list):
遍历参数列表并创建所需的槽
for v in var_list:
self._zeros_slot(v, "momentum", self._name)
self._zeros_slot(v, "gbar", self._name)
g_tensor = ops.convert_to_tensor(v)
gain_init = self._initial_gain * array_ops.ones_like(g_tensor)
_ = self._get_or_make_slot(v, self._initial_scale * array_ops.ones((1)),
"lr_scale", self._name)
_ = self._get_or_make_slot(v, gain_init, "gain", self._name)
_ = self._get_or_make_slot(v, array_ops.zeros((1)), "counter", self._name)
_prepare()
函数作用 : 在应用梯度之前创建所有需要的张量。使用用户为梯度选择的“name”来调用name_scope。
源码 :
def _prepare(self):
创建 learning_rate 的张量
learning_rate = self._call_if_callable(self._learning_rate)
self._learning_rate_tensor = ops.convert_to_tensor(
learning_rate, name="learning_rate")
创建 momentum 的张量
momentum = self._call_if_callable(self._momentum)
self._momentum_tensor = ops.convert_to_tensor(momentum, name="momentum")
_apply_dense(grad, var)
参数 :
- grad :
Tensor
- var :
variable
对象 - 返回 :
Operation
函数作用 : 添加 ops 以应用梯度密度函数到 var
。
def _apply_dense(self, grad, var):
获得变量的槽
lr_scale = self.get_slot(var, "lr_scale")
momentum = self.get_slot(var, "momentum")
gbar = self.get_slot(var, "gbar")
gain = self.get_slot(var, "gain")
计数更新次数
counter = self.get_slot(var, "counter")
counter_updated = state_ops.assign(counter, counter + 1)
lr_scale 更新使用归一化梯度和 momentum 而独立于维度
normalized_grad = grad / (linalg_ops.norm(grad) + 1e-10)
normalized_momentum = momentum / (linalg_ops.norm(momentum) + 1e-10)
在 lr_scale 上应用 EG 更新 :
公式 :
- grad_lr_scale = -inner_product(current_grad, old_momentum)
- lr_scale <- lr_scale * exp(-scale_learning_rate * grad_lr_scale)
lr_scale_unnormalized_updated = clip_ops.clip_by_value(
lr_scale * math_ops.exp(
self._scale_learning_rate * math_ops.reduce_sum(grad * momentum)),
self._min_scale, self._max_scale)
lr_scale_normalized_updated = clip_ops.clip_by_value(
lr_scale * math_ops.exp(self._scale_learning_rate * math_ops.reduce_sum(
normalized_grad * normalized_momentum)), self._min_scale,
self._max_scale)
lr_scale_updated = state_ops.assign(
lr_scale,
array_ops.where(self._use_directions, lr_scale_normalized_updated,
lr_scale_unnormalized_updated))
移除 gbar 中初始化为零的 bias
corrected_gbar = gbar / (
1.0 - self._beta**math_ops.maximum(counter_updated - 1, 1))
应用EG更新增益 :
公式 :
- grad_gain = - current_grad * old_gbar
- gain <- gain * exp(-gain_learning_rate * grad_gain)
gain_unnormalized_updated = clip_ops.clip_by_value(
gain * math_ops.exp(self._gain_learning_rate * grad * corrected_gbar),
self._min_gain, self._max_gain)
规范化----使用 sign(grad) *sign(gbar) 代替 grad_gain。
gain_normalized_updated = clip_ops.clip_by_value(
gain * math_ops.exp(self._gain_learning_rate * math_ops.sign(grad) *
math_ops.sign(gbar)), self._min_gain,
self._max_gain)
gain_updated = state_ops.assign(
gain,
array_ops.where(self._use_signs, gain_normalized_updated,
gain_unnormalized_updated))
scaled_g = self._learning_rate_tensor * gain_updated * grad
返回Operation
with ops.control_dependencies([lr_scale_updated, scaled_g]):
momentum_updated = state_ops.assign(
momentum, self._momentum_tensor * momentum + scaled_g)
gbar_updated = state_ops.assign(
gbar, self._beta * gbar + (1.0 - self._beta) * grad)
with ops.control_dependencies([gbar_updated]):
return state_ops.assign_sub(var, lr_scale_updated * momentum_updated)
_resource_apply_dense(grad, var)
参数 :
- grad :
Tensor
, 表示梯度 - handle : 数据类型为
resource
的Tensor
, 指向要更新的变量 - 返回 :
operation
, 更新变量值
添加 operation 以将密度梯度应用于变量句柄。
源码 :
调用_apply_dense方法
def _resource_apply_dense(self, grad, var):
return self._apply_dense(grad, var)
_resource_apply_sparse(grad_values, var, grad_indices)
参数 :
- grad :
Tensor
, 表示受影响指数的梯度 - handle : 数据类型为
resource
的Tensor
, 指向要更新的变量 - indices : 表示梯度不为零的指标的整型
Tensor
。indices
是唯一的。 - 返回 :
operation
, 更新变量值
源码 :
# Sparse gradients are not handled currently and is part of future work.
def _resource_apply_sparse(self, grad_values, var, grad_indices):
return control_flow_ops.no_op()
_apply_sparse(grad, var)
参数 :
- grad :
IndexedSlices
, 没有重复的指标 - var :
Variable
对象 - 返回 :
operation
源码 :
def _apply_sparse(self, grad, var):
return control_flow_ops.no_op()
该 module 重点为使用了梯度下降算法