优化器就是引导神经网络更新参数的工具。
待优化参数w,损失参数loss,学习率lr,每次迭代一个batch,t表示当前batch迭代的总次数:
1.计算t时刻损失函数关于当前参数的梯度:
2.计算t时刻一阶动量和二阶动量
一阶动量:与梯度相关的函数,二阶动量:与梯度平方相关的函数。
3.计算t时刻下降梯度:
4.计算t+1时刻参数:
不同的优化器实质上只是定义了不同的一阶动量和二阶动量公式。
1.随机梯度下降SGD(无momentum)最常用
# 实现梯度更新 w1 = w1 - lr * w1_grad b = b - lr * b_grad
w1.assign_sub(lr * grads[0]) # 参数w1自更新
b1.assign_sub(lr * grads[1]) # 参数b自更新
2.SGDM(含momentum)在SGD上增加一阶动量
是一个接近于1的数,一般取0.9。
m_w, m_b = 0, 0
beta = 0.9
# sgd-momentun
m_w = beta * m_w + (1 - beta) * grads[0]
m_b = beta * m_b + (1 - beta) * grads[1]
w1.assign_sub(lr * m_w)
b1.assign_sub(lr * m_b)
3.Adagrad ,在SGD上增加二阶动量
v_w, v_b = 0, 0
v_w += tf.square(grads[0])
v_b += tf.square(grads[1])
w1.assign_sub(lr * grads[0] / tf.sqrt(v_w))
b1.assign_sub(lr * grads[1] / tf.sqrt(v_b))
4.RMSProp ,SGD基础上增加二阶动量
v_w, v_b = 0, 0
beta = 0.9
# rmsprop
v_w = beta * v_w + (1 - beta) * tf.square(grads[0])
v_b = beta * v_b + (1 - beta) * tf.square(grads[1])
w1.assign_sub(lr * grads[0] / tf.sqrt(v_w))
b1.assign_sub(lr * grads[1] / tf.sqrt(v_b))
5.Adam ,同时结合SGDM一阶动量和RMSProp 的二阶动量
修正一阶动量的偏差:
修正二阶动量的偏差:
把修正后的动量带入参数更新,实现参数自更新:
m_w, m_b = 0, 0
v_w, v_b = 0, 0
beta1, beta2 = 0.9, 0.999
delta_w, delta_b = 0, 0
global_step = 0
# adam
m_w = beta1 * m_w + (1 - beta1) * grads[0]
m_b = beta1 * m_b + (1 - beta1) * grads[1]
v_w = beta2 * v_w + (1 - beta2) * tf.square(grads[0])
v_b = beta2 * v_b + (1 - beta2) * tf.square(grads[1])
m_w_correction = m_w / (1 - tf.pow(beta1, int(global_step)))
m_b_correction = m_b / (1 - tf.pow(beta1, int(global_step)))
v_w_correction = v_w / (1 - tf.pow(beta2, int(global_step)))
v_b_correction = v_b / (1 - tf.pow(beta2, int(global_step)))
w1.assign_sub(lr * m_w_correction / tf.sqrt(v_w_correction))
b1.assign_sub(lr * m_b_correction / tf.sqrt(v_b_correction))