Keras 中的 Adam 優化器(Optimizer)演算法+源碼研究
上篇文章《如何用 TensorFlow 實現 GAN》的代碼裡面用到了 Adam 優化器(Optimizer),深入研究了下,感覺很有趣,今天為大家分享一下,對理解深度學習訓練和權值學習過程、凸優化理論比較有幫助。
先看看上一篇用到的代碼(keras/examples/mnist_acgan.py):
# 手機上讀代碼時建議橫屏
# 從 keras.optimizers 導入 Adam 模塊
from keras.optimizers import Adam
# 創建鑒別器 (D) 和生成器 (G) 代碼略,見上一篇公眾號文章
# Adam 優化器超參(Hyper Parameter)
adam_lr = 0.0002
adam_beta_1 = 0.5
discriminator = build_discriminator()
discriminator.compile(
optimizer=Adam(lr=adam_lr, beta_1=adam_beta_1),
loss=[binary_crossentropy, sparse_categorical_crossentropy]
)
generator = build_generator(latent_size)
generator.compile(optimizer=Adam(lr=adam_lr, beta_1=adam_beta_1),
loss=binary_crossentropy)
上面代碼中,兩個模型 G 和 D 的優化器均選擇 Adam,超參數一樣,具體數值設置參考了【1】。
可能你會有疑問,什麼是優化器(Optimizer)?
很簡單~就是模型訓練的指導教練,能告訴模型權值該怎麼調整,調整多大量,最終目標是讓模型權值 theta 調整到最優,使得代價函數 f(theta) 最小。在所有優化演算法中,基於梯度(Gradient)的演算法最為常用,即首先計算 f(theta) 對 theta 的梯度 d(theta),theta 沿著梯度下降的方向進行調整。
Adam 也是一種基於基於梯度的優化演算法,該方法實現簡潔,計算高效,內存佔用少,適合非平穩目標函數,超參數有符合直覺的解釋,無需複雜的調參過程。
先看下 Adam 演算法的描述,需要閱讀文獻【2】。
Keras 對應的代碼實現位於 keras/keras/optimizers.py
# 手機上讀代碼時建議橫屏
class Adam(Optimizer):
"""
# 參數
lr: float >= 0. 學習速率、學習步長,值越大則表示權值調整動作越大,對應上圖演算法中的參數 alpha;
beta_1: 接近 1 的常數,(有偏)一階矩估計的指數衰減因子;
beta_2: 接近 1 的常數,(有偏)二階矩估計的指數衰減因子;
epsilon: 大於但接近 0 的數,放在分母,避免除以 0 ;
decay: 學習速率衰減因子,【2】演算法中無這個參數;
"""
def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999,
epsilon=1e-8, decay=0., **kwargs): # 【2】中的默認參數設置
super(Adam, self).__init__(**kwargs)
self.iterations = K.variable(0) # 迭代次數變數
self.lr = K.variable(lr) # 學習速率
self.beta_1 = K.variable(beta_1)
self.beta_2 = K.variable(beta_2)
self.epsilon = epsilon
self.decay = K.variable(decay)
self.initial_decay = decay
def get_updates(self, params, constraints, loss):
grads = self.get_gradients(loss, params) # 計算梯度 g_t
self.updates = [K.update_add(self.iterations, 1)] # 迭代次數加 1
lr = self.lr
if self.initial_decay > 0: # 如果初始學習速率衰減因子不為0,
# 則隨著迭代次數增加,學習速率將不斷減小
lr *= (1. / (1. + self.decay * self.iterations))
t = self.iterations + 1 # 就是公式中的 t
# 有偏估計到無偏估計的校正值
# 這裡將循環內的公共計算提到循環外面,提高速度
lr_t = lr * (K.sqrt(1. - K.pow(self.beta_2, t)) /
(1. - K.pow(self.beta_1, t)))
shapes = [K.get_variable_shape(p) for p in params] # 獲得權值形狀
ms = [K.zeros(shape) for shape in shapes] # 一階矩估計初始值
vs = [K.zeros(shape) for shape in shapes] # 二階矩估計初始值
self.weights = [self.iterations] + ms + vs
for p, g, m, v in zip(params, grads, ms, vs):
m_t = (self.beta_1 * m) + (1. - self.beta_1) * g # 一階矩估計
v_t = (self.beta_2 * v) + (1. - self.beta_2) * K.square(g) # 二階矩估計
p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon) # 權值更新
self.updates.append(K.update(m, m_t))
self.updates.append(K.update(v, v_t))
new_p = p_t
# 對權值加約束
if p in constraints:
c = constraints[p]
new_p = c(new_p)
self.updates.append(K.update(p, new_p))
return self.updates
# 獲取當前超參數
def get_config(self):
config = {lr: float(K.get_value(self.lr)),
beta_1: float(K.get_value(self.beta_1)),
beta_2: float(K.get_value(self.beta_2)),
decay: float(K.get_value(self.decay)),
epsilon: self.epsilon}
base_config = super(Adam, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
從上面實現可以看到,權值 theta 每個元素更新的調整幅度,與學習速率 alpha 成正比,與(無偏)一階矩估計值成正比,(無偏)二階矩估計值的平方根成反比。
文獻【2】 在 Adam 優化器基礎上提出了擴展的 Adamax 優化器,演算法上變化為將二階矩估計變為無窮階矩,感興趣的讀者可以繼續研究下演算法和 Keras 源碼實現。
Reference
【1】Alec Radford,Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks,[1511.06434] Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks
【2】Diederik, ADAM : A METHOD FOR STOCHASTIC OPTIMIZATION,A Method for Stochastic Optimization
如果你覺得本文對你有幫助,請關注公眾號,將來會有更多更好的文章推送!
http://weixin.qq.com/r/MDludlzEsAHPrRgV92wi (二維碼自動識別)
推薦閱讀:
※如何看待ACL2017 所有掛arxiv但是沒有在提交時註明的paper全部被拒稿?
※是否可把CNN用於一維的信號?
※如何評價 Caffe2go?
※梯度下降法的神經網路容易收斂到局部最優,為什麼應用廣泛?
※人臉驗證任務中的目標方程為什麼還要加入分類誤差?
TAG:深度学习DeepLearning |