前言
本文其实值属于:程序员的数学【AIoT阶段二】 的一部分内容,本篇把这部分内容单独截取出来,方便大家的观看,本文介绍 最优化,本文涵盖了一些计算的问题并使用代码进行了实现,安装代码运行环境见博客:最详细的Anaconda Installers 的安装【numpy,jupyter】(图+文),如果你只是想要简单的了解有关线代的内容,那么只需要学习一下博文:NumPy从入门到高级,如果你是跟着博主学习AIoT的小伙伴,建议先看博文:数据分析三剑客【AIoT阶段一(下)】(十万字博文 保姆级讲解),如果你没有Python基础,那么还需先修博文:Python的进阶之道【AIoT阶段一(上)】(十五万字博文 保姆级讲解)
一、最优化概念
1.1 最大值最小值
1.2 局部极小值
1.3 全局最小值
🚩其实初中我们就学求极值的问题了,比如二次函数抛物线的顶点就是极大值或者极小值,高中我们也会有求极值的题目,算一个非常复杂的函数的极值,借用初等数学一些的技巧来完成的。而真正的飞跃是发生在大学里面,微积分这门课为求解极值提供了一个统一的方法,就是找它导数等于 0 的点,如果是多元函数的话,我们说它的梯度等于 0 ,我们去解方程组就可以了,在机器学习里面我们遇到的几乎所有的函数都是可导的。光滑即可导f′(x)=0
局部最小值, 通过大量实践发现在高维度的优化问题中,局部最小值和全局最小值通常没有太大的区别,甚至在有些情况下局部最小值有更好的归纳能力(泛化能力)。
二、求导与迭代求解
2.1 求导遇到的问题
🚩前面咱们说了求极值就是导数或梯度等于 0 ,找到疑似的极值,就是驻点:ᐁf(x)=0,f′(x)=0
有了微积分里面这样的手段,只要函数可导,我们求解不就行了?
因为很多时候去求方程等于 0 或方程组等于0 的根并不是那么容易,比如:
分别对 x , y 求偏导:
令上面的导数为 0依然无法求解。对于 5 次或以上的代数方程它都没有求根公式了,所以这个思路看上去很美,但是实际上是行不通的,我们得想其它的办法。
2.2 近似迭代求解
在最优化中,这种迭代思想又叫梯度下降!
三、梯度下降
3.1 公式推导
🚩数值优化算法,是求近似解,而不是理论上面的精确解
这时要想下降的更快,就要让等式右边得到最小值,即当cosθ=−1,下降的幅度最大!
单位向量代表的是方向,长度为 1 的向量,即模为 1 的向量称为单位向量。
向量乘以标量不会改变它的方向,只会改变它的幅值。这就是缩放向量的方法。
所以一个向量可以表示为一个标量乘以一个单位向量。
实现细节问题:
- 初始值的设定,随机或者设定满足约束条件
- 步长的设定,一个比较小的,也可以动态的调整
- 循环终止的判定,达到maxiteration(最大迭代次数);上一次减下一次的更新,差异基本不变时
3.2 代码演示
3.2.1 创建模拟数据
import numpy as np import matplotlib.pyplot as plt # 构建方程 f = lambda x : (x - 3.5) ** 2 - 4.5 * x + 10 # 导函数 g = lambda x : 2 * (x - 3.5) - 4.5 # 创建模拟数据并可视化 x = np.linspace(0, 11.5, 100) y = f(x) plt.plot(x, y) _ = plt.scatter(5.75, f(5.75), color = 'red', s = 30)
3.2.2 迭代法求解(梯度下降)
eta = 0.3 # 学习率 # 随机(瞎蒙),初始值x0 x = np.random.randint(0, 12, size = 1)[0] # 多次while 循环,每次梯度下降,更新,记录一下上一次的值 # 比较精确度 # 一开始故意设置差异,目的为了有区分,不能一上来就停止 last_x = x + 0.1 # 精确度,人为设定 precision = 0.0001 print('-----------------随机x是:', x) # 每次梯度下降,求解出来的x值,一开始随机给的 x_ = [x] # Python中列表 count = 0 while True: if np.abs(x - last_x) < precision: # 更新时,变化甚微,满足精确度,终止 break # 更新,梯度下降 # x是当前数值,赋值给上一个值 last_x = x count += 1 x = x - eta * g(x) # 梯度下降公式 x_.append(x) print('+++++++++++++++更新之后的x是:%0.5f' % (x)) print('+++++++++++++++梯度下降次数:', count) # x1是NumPy数组 x1 = np.linspace(0, 11.5, 100) y1 = f(x1) plt.figure(figsize = (9, 6)) plt.plot(x1, y1) # 散点图 x_ = np.array(x_) _ = plt.scatter(x_, f(x_), color = 'red', s = 30)
3.2.3 迭代法求解(退出条件最大迭代次数)
eta = 0.2 # 学习率 # 随机(瞎蒙),初始值 x = np.random.randint(0, 12, size = 1)[0] # 多次while 循环,每次梯度下降,更新,记录一下上一次的值 # 一开始故意设置差异,目的为了有区分,不能一上来就停止 last_x = x + 0.1 # 最大迭代次数,人为设定 count = 30 print('-----------------随机x是:', x) # 每次梯度下降,求解出来的x值,一开始随机给的 x_ = [x] # Python中列表 for i in range(count): # 更新,梯度下降 # x是当前数值,赋值给上一个值 last_x = x x = x - eta * g(x) # 梯度下降公式 x_.append(x) print('+++++++++++++++更新之后的x是:%0.5f' % (x)) # x1是NumPy数组 x1 = np.linspace(0, 11.5, 100) y1 = f(x1) plt.figure(figsize = (9, 6)) plt.plot(x1, y1) # 散点图 x_ = np.array(x_) plt.scatter(x_, f(x_), color = 'red', s = 30)