深度学习随机梯度下降法

1.SGD

更新策略:

代码:

def sgd(w,dw,config=None):
    if config is None:
        config = {}
    config.setdefault('learning_rate',1e-2)
    
    w -= config['learning_rate'] * dw
    
    return w,config
    

2.SGD+Momentum

更新策略:

 

此外,还有一种等价的迭代法,如下:

 

引入中间变量 , 并令其满足:

故而得到新的迭代形式:

 

 

def sgd_moment(w,dw,config=None):
    if not config:
        config = {}
    config.setdefault('learning_rate',1e-1)
    config.setdefault('momentum',0.9)
    v = config.get('velocity',np.zeros_like(w))
    
    v = config['momentum'] * v - config['learning_rate'] * dw
    w = w + v
    
    config['velocity'] = v
    
    return w,config

3. Nesterov动量

SGD + Momentum的一种变种,理论研究表明,对于凸函数能更快收敛,相比于普通动量。

核心思想:当参数向量位于某个位置 ​x 时,动量部分会通过mu *  v  稍微改变 x  的位置,因此应该在 x + mu * v的位置 处计算梯度。与普通动量写为同样的形式:

x_head = x + mu * v
v = mu * v - lr * dx_head
x += v

如果实际存储的参数向量总是向前一步的,将x_head写成x,则可以写成:(其实得到是的x_head)

v_prev = v
v = mu * v - lr * dx
x += -mu * v_prev + (1+mu)*v

代码:

def nesterov(w,dw,config=None):
    if not config:
        config = {}
    config.setdefault('learning_rate',1e-1)
    config.setdefault('momentum',0.9)
    v = config.get('velocity',np.zeros_like(w)) 
    
    v_next = config.get("momentum") * v - config.get("learning_rate") * dw
    netx_w = w -config.get("momentum") * v + (1 + config.get("momentum")) * v_next
    
    config["velocity"] = v_next
    
    return next_w,config

小结

上述3种方法,对学习率进行全局地操作,对于每个参数而言学习率一样。调参比较费时。因此,有很多工作在研究怎么适应性地调节学习率,甚至是逐个参数适应学习率调参(即每个参数可能学习率都不一样)。

4.Adagrad

是一种适应性学习率算法,根据累计梯度来决定每一步每个参数的学习率的大小:

cache += dx ** 2
x += -learning_rate * dx / (np.sqrt(cache)+eps)

缺点:实践中发现单调的学习率通常过于激进且过早停止学习。

5. RMSProp

是对Adagrad进行调整,使用了滑动平均的方法:

cache = decay_rate * cache + (1-decay_rate)*(dx ** 2)
x += -learning_rate * dx / (np.sqrt(cache)+eps)
def rmsprop(w,dw,config=None):
    if not config:
        config = {}
    config.setdefault("learning_rate",1e-2)
    config.setdefault("decay_rate",0.9)
    config.setdefault("epsilon",1e-8)
    config.setdefault("cache",np.zeros_like(w))
    
    cache = config["cache"]
    cache = config["decay_rate"] * cache + (1-config["decay_rate"])*(dw**2)
    lr = config["learning_rate"] / (np.sqrt(cache)+config["epsilon"])
    next_w = w - lr * dw
    
    config["cache"] = cache
    
    return next_w,config

decay_rate常用值[0.9,0.99,0.999],与Adagrad相比,learning_rate不会一直单调下降。

6.Adam

可以理解为RMSProp的动量版本

m = beta1 * m + (1-beta1) * dx # 梯度平滑
v = beta2 * v + (1-beta2) * (dx**2) 
mt = m / (1-beta1**t)
vt = v / (1-beta2**t)
x += -learning_rate * mt / (np.sqrt(vt)+eps)
t += 1

eps=1e-8, beta1 =0.9, beta2=0.999

实际上,实现可能考虑到迭代次数

deft adam(w,dw,config=None):
    if not config:
        config = {}
    config.setdefault("learning_rate",1e-2)
    config.setdefault("beta1",0.9)
    config.setdefault("beta2",0.999)
    config.setdefault("epsilon",1e-8)
    config.setdefault("m",np.zeros_like(w))
    config.setdefault("v",np.zeros_like(w))
    config.setdefault("t",0)
    
    m,v,t = config["w"],config["v"],config["t"]+1
    m = config["beta1"]*m + (1-config["beta1"])*dw
    v = config["beta2"]*v + (1-config["beta2"])*(dw**2)
    mt = m / (1 - config["beta1"]**t)
    #vt = v / (1 - config["beta2"]**t)
    lr = config["learning_rate"]*np.sqrt(1-config["beta2"]**t)/(np.sqrt(v)+config["epsilon"])
    next_w = w - config["learning_rate"]*mt
    
    config["m"] = m
    config["v"] = v
    config["t"] = t
    
    
    return next_w, t

从效果来看, Adam, RMSProp逐参数适应学习率的算法,与SGD,SGD+ Momentum,Nesterous学习算法相比,更快收敛。

 

posted @ 2021-04-15 09:44  gele00  阅读(215)  评论(0编辑  收藏  举报