当在现实生活中的遇到问题时, 我们总是希望找到最佳的解决方案. 制造软件产品也是一样的道理, 最优化的程序才是最理想的产品.
最优化意味着获得最佳输出. 它既是一个数学的重要分支, 也在现实生活中有着重要的作用. 现代的计算机科学和人工智能科学把最优化作为一个重要的领域来研究. 我们也认为人工智能的一些算法, 就是模拟了人类寻求实际问题最优解的过程. 例如, 利用人工智能算法设计软件, 配合外部的电子设备例如摄像头识别人脸; 利用数据挖掘和神经网络算法来寻找投资的最佳时机等等, 都是利用了最优化的原理.
机器学习中的最优化和其他学科的应用比起来有轻微的差异. 一般来说, 在优化的同时, 我们确切地知道数据的外观以及我们想要改进的地方. 但是在机器学习中, 我们不知道 "新数据" 是怎么样的, 更别提对其进行优化了. 为了解决这个问题, 在机器学习中, 我们对训练数据 (training data) 执行优化, 并检查由此新创造出的验证数据(validation data).
最优化的广泛应用
机械学: 设计航空航天产品的表面;
经济学: 成本最小化;
物理学: 量子计算中的优化时间;
决定最佳运输路线, 货架空间优化等等.
许多流行的机器算法都依赖于线性回归, k 最近邻, 神经网络等技术. 优化的应用是无限的, 因此它成为了学术界和工业界广泛研究的课题. 在本文中, 我们将介绍一种称为梯度下降 (Gradient Descent) 的优化技术. 这是机器学习时最常用的优化技术.
1. 什么是梯度下降?
我们来看一下经典的登山示例: 假设你在山顶, 你必须到达山谷最低点的一个湖. 但是你被蒙住眼睛, 看不到你的目标. 那么, 你会采取什么方法到达湖边?
最简单的方法是检查你附近的地面, 找到土地向下倾斜的方向. 这是你该迈出第一步的方向. 沿着下坡路线一直走, 很有可能你会到达湖泊. 下图表示你走过的路:
现在我们来用数学术语来描述一下这个场景.
假设我们想要找出学习算法的最佳参数 (θ0) 和(θ1). 与上面的登山示例类似, 当我们绘制成本空间 J(θ)函数的 3D 图像时发现了类似的山脉和山谷. 当 z 轴代表成本 J(θ),x 轴和 z 轴分别对应参数θ0 和θ1 时, 丘陵由红色地区代表成本高, 而山谷以蓝色地区代表成本低. 成本空间不过是算法在某个参数选择特定值时的表现.
现在主要有两种类型的梯度下降算法:
1.1 数据摄入基准法
全批梯度下降算法(Full Batch)
随机梯度下降算法(Stochastic)
全批梯度下降算法一次使用所有数据来计算梯度, 而随机梯度下降算法可以在计算梯度时进行采样.
1.2 分化技巧基准法
一阶微分
二阶微分
梯度下降需要通过成本函数 J(θ)的微分方程来计算梯度. 我们可以使用一阶微分或二阶微分.
2. 执行梯度下降法所面临的挑战
梯度下降是一种适用于大多数情况的技术. 但也有时候梯度下降也不能正常工作, 或完全不能工作. 发生这种情况时有三个主要原因:
2.1 来自数据的挑战
如果数据的排列方式会造成非凸优化问题(non-convex optimization problem), 使用梯度下降来执行优化会非常困难.
即使在优化凸优化问题时, 也可能存在许多最小值. 最低点称为全局最小值(Global Minima), 其余点称为局部最小值(Local Minima). 我们的目标是在避免局部最小值的同时到达全局最小值.
还有鞍点 (Saddle Point) 问题. 这是数据中梯度为零但不是最优点的点. 目前并没有具体的方法来避免这一点, 这仍然是一个非常活跃的研究领域.
2.2 来自梯度的挑战
如果梯度下降执行的不正确, 则可能导致像梯度消失 (vanishing gradient) 或梯度爆炸 (exploding gradient) 之类的问题. 这些问题会在梯度过小或过大时发生, 导致算法不会收敛(Converge).
2.3 来自实际应用难度的挑战
大多数神经网络从业人员不大关注实际应用. 但是网络的资源利用率之类的事情也是非常重要的. 在实施梯度下降时, 具体需要多少资源是非常重要的. 如果内存对于应用程序来说太小就一定会失败.
此外, 梯度下降算法对于浮点和硬件 / 软件的要求也很高.
3. 梯度下降算法的变体
最常用的梯度下降算法及其实施.
3.1 Vanilla(香草)梯度下降法
这是梯度下降技术的最简单形式. 香草意味着纯粹 / 没有任何掺假. 其主要特点是通过采用成本函数的梯度向最小值方向不断迈出小步. 它的伪代码如下:
update = learning_rate * gradient_of_parameters
parameters = parameters - update
我们通过获取旧参数的梯度来不断更新参数. 把它乘以一个学习速率(learning_rate, 一个常数), 表明我们想要达到最低点的速度. 学习速率是一个超参数(hyper-parameter), 在选择它的大小时应该十分小心谨慎.
3.2 动量梯度下降(Gradient Descent with Momentum)
通过调整 Vanilla 算法, 可以在每次进行下一步之前注意前一步骤.
- update = learning_rate * gradient
- velocity = previous_update * momentum
- parameter = parameter + velocity - update
在这里, update 与香草梯度下降法相同. 但是引入了一个名为 velocity 的新术语, 它考虑了之前的 update 和一个称为 momentum 的常量.
3.3 Adagrad
Adagrad 使用自适应技术进行学习速率的更新. 这个算法根据以前所有迭代的梯度变化情况来改变学习速率. 伪代码如下:
- grad_component = previous_grad_component + (gradient * gradient)
- rate_change = square_root(grad_component)+epsilon
- adapted_learning_rate = learning_rate * rate_change
- update = adapted_learning_rate * gradient
- parameter = parameter - update
其中, epsilon 是一个常量, 用于保持学习速率的变化率.
3.4 Adam
Adam 是一种基于 Adagrad 的自适应技术, 进一步缓解了它的不足. 换句话说, 它就是 Momentum + Adagrad. 伪代码如下:
- adapted_gradient = previous_gradient +
- ((gradient - previous_gradient) * (1 - beta1))
- gradient_component = (gradient_change - previous_learning_rate)
- adapted_learning_rate = previous_learning_rate +
- (gradient_component * (1 - beta2))
- update = adapted_learning_rate * adapted_gradient
- parameter = parameter - update
其中, beta1 和 beta2 是常量, 用于检查梯度和学习速率的变化.
4. 梯度下降算法的实际应用
使用 python 进行梯度下降的基本应用.
接下来我们使用梯度下降优化来找到深度学习模型的最佳参数, 并将其用于图像识别问题. 我们的问题是: 识别来自给定的 28*28 图像里的数字. 准备的图片中, 有一部分图像用于训练, 其余部分用于测试模型.
如下是定义 Vanilla 梯度下降的主要代码:
- params = [weights_hidden, weights_output, bias_hidden, bias_output]
- def sgd(cost, params, lr=0.05):
- grads = T.grad(cost=cost, wrt=params)
- updates = []
- for p, g in zip(params, grads):
- updates.append([p, p - g * lr])
- return updates
- updates = sgd(cost, params)
我们来拆分理解一下这段代码. 定义函数 sgd 作为 cost,params 和 lr 的因变量, 它和如前所述的 J(θ)同出一辙; 而之前的θ0,θ1 在这里是深度学习算法的参数和学习速率. 我们将默认学习速率设置为 0.05, 但该值可随时被更改.
def sgd(cost, params, lr=0.05):
然后我们定义了关于成本函数 J(θ)的参数的梯度. 在这里, 我们使用 theano 库来找到相应梯度, 并且我们将 theano 作为 T 导入
grads = T.grad(cost=cost, wrt=params)
最后把所有可能的参数更新, 这里应使用 Vanilla 梯度下降.
- for p, g in zip(params, grads):
- updates.append([p, p - g * lr]
我们可以使用这个函数来为神经网络找到最佳参数. 在使用这个函数时, 该神经网络出色地完成了任务, 如下所示:
Prediction is: 8
在这个应用中, 梯度下降法为深度学习算法找到了最优参数.
5. 应用梯度下降的实用技巧
上面提到的每个梯度下降算法都有其优点和缺点. 下面的一些小提示可能会帮助您选择正确的算法.
为了快速建立原型, 请使用 Adam / Adagrad 等自适应技术. 他们很短时高效, 并且不需要太多的超参数调整.
要获得最佳效果, 您应该使用 Vanilla 梯度下降法或 Momentum. 虽然计算速度超级慢, 但是这些结果大多比自适应技术得来的结果更准确.
如果数据很小并且适合一次迭代, 则可以使用二阶技术, 如 l-BFGS. 因为二阶技术对于足够小的数据的处理非常快速和准确.
神经网络无法成功学习的原因有很多. 但是如果可以找到算法出错的地方, 对未来的工作还是非常有帮助的.
在应用梯度下降法时, 有以下几点常见注意事项:
错误率 - 应该在特定迭代后检查训练错误率, 测试错误率, 并确保它们都成减小趋势. 如果错误率并未减小, 算法很有可能出了问题.
隐藏层中的梯度流 - 检查是否有梯度消失或梯度爆炸的问题.
学习速率 - 使用自适应技术时应该检查.
希望您阅读本文后, 将熟练掌握有关梯度下降及其变体的基础知识. 希望你觉得我对这些算法的实际应用的解读也有所帮助!
来源: https://juejin.im/post/5c94d60b5188252db02e4ce2