优化算法 Caffe中的SGD的变种优化算法(2) 接上回,我们继续来看优化的算法。 Adam 关于adam的算法,我觉得它的复杂程度比前面的算法更高,但是它还是主要使用了和计算动量相同的方法,并把这种方法应用到梯度的一阶总量和二阶总量上: 它的代码如下所示: def adam(x_start, step, g, beta1 = 0.9, beta2 = 0.999,delta=1e-8): x = np.array(x_start, dtype='float64') sum_m = np.zeros_like(x) sum_v = np.zeros_like(x) passing_dot = [x.copy()] for i in range(50): grad = g(x) sum_m = beta1 * sum_m + (1 - beta1) * grad sum_v = beta2 * sum_v + (1 - beta2) * grad * grad correction = np.sqrt(1 - beta2 ** i) / (1 - beta1 ** i) x -= step * correction * sum_m / (np.sqrt(sum_v) + delta) passing_dot.append(x.copy()) if abs(sum(grad)) < 1e-6: break; return x, passing_dot 前面也说过,实际上这些算法背后都有些原理的,但是这些原理在我们看来可能都比较抽象,所以再我们看完实验再看原理可能会更有感觉。下面我们看看它的表现: res, x_arr = adam([5, 5], 0.1, g) contour(X,Y,Z, x_arr) 好吧,这一回它是唯一一个走得有点过头的算法,不过最后还是走上了正道。 这样除了Nesterov算法之外,我们把其他所有的算法都展示出来了。前面这个实验中,我们希望检验算法的“拐弯”能力。也就是说一开始算法冲着一个局部最优点而来,什么时候它会发现这是个骗局并掉头朝向真正的最优值呢?现在每一个算法都给我们交出了答案。仔细看来每个算法的表示还是不太一样的。有的算法比较灵敏,刚发现不对就调头逃跑,有的算法则是冲过了头才转过身来。有的算法做到这一切十分容易,并不需要很大的Learning rate,有的算法则需要强大的力量才能转过来,否则就会行动缓慢。 好了,各位童鞋,转弯赛到此结束,下面我们进入下一个比赛——爬坡赛。爬坡赛的比赛规则是,所有算法使用同样的参数,从鞍点附近出发,经过50轮迭代,看看它能走到哪里。 爬坡赛 首先是我们的老朋友梯度下降法: res, x_arr = gd([-0.23,0.0], 0.0008, g) contour(X,Y,Z, x_arr) 我们的老朋友在爬坡赛看来是要叫白卷了,说明它虽然很轻盈,但是动力不是很足啊。 下面是动量算法: res, x_arr = momentum([-0.23,0], 5e-4, g) contour(X,Y,Z, x_arr) 比梯度下降好一点,但是好的有限。 然后是Adagrad: res, x_arr = adagrad([-0.23, 0], 1.3, g) contour(X,Y,Z, x_arr) 好吧,表现得比转弯赛还好,省去夸赞的词语了。 下面是Rmsprop: res, x_arr = rmsprop([-0.23, 0], 0.3, g) contour(X,Y,Z, x_arr) 同样完成的不错! 下面我们再看AdaDelta: res, x_arr = adadelta([-0.23, 0], 0.4, g) contour(X,Y,Z, x_arr) 好吧,直接一骑绝尘而去了。 最后是我们今天登场的Adam: res, x_arr = adam([-0.23, 0], 0.1, g) contour(X,Y,Z, x_arr) 同样是跑出了我们原始规划的区域。 总结 经过两轮的比赛——转弯赛和爬坡赛,我们测试了几种算法在同一配置上的实力。测试的目标不是为了比较哪个算法更厉害,而是展示另外一个实力——哪个算法表现更稳定。 因为我们在实际使用过程中,learning rate是相对固定的,在优化过程中我们无法预料自己将会碰上什么样的情景,那么我们肯定希望一个算法又能转弯又能爬坡。如果一个算法转弯厉害但是爬坡比较弱,那一旦遇上爬坡它就会走得很慢,反之也是如此。 所以从刚才的表现来看,我们的新算法似乎表现更为平稳,现在也确实有越来越多的人抛弃了一些经典的算法,转而投入这些新算法的怀抱,而这些新算法也足够争气,拿出了它们的实力。关于算法性能的测试一直在进行,这些算法还需要经历更多的考验! |
|