机器学习的优化算法

梯度下降法

梯度下降法(Gradient Descent)是一种优化算法,用于求解最小化损失函数的问题,特别是在机器学习和深度学习中广泛使用。其核心思想是通过迭代的方式,沿着损失函数关于模型参数的负梯度方向更新参数,以逐渐减小损失函数的值,从而找到最小化损失函数的参数。

梯度下降法的优点是简单、稳定且容易实现,适用于大规模数据集和复杂

详细:python深度学习--梯度下降算法(附完整代码)-CSDN博客

随机梯度下降法

随机梯度下降法(Stochastic Gradient Descent,SGD)是一种常用的优化算法,特别适用于大规模数据集和在线学习场景。它是梯度下降法的一种变种,基本思想是在每次迭代时只使用一个样本的梯度来更新模型参数,而不是使用所有样本的梯度。

SGD的优点在于:

  1. 训练速度快:由于每次迭代只需要计算一个样本的梯度,SGD的训练速度非常快,特别适用于大规模数据集。
  2. 可跳出局部最优:由于SGD每次只考虑一个样本,因此更容易跳出局部最优点,从而有助于找到全局最优解。

然而,SGD也存在一些缺点

  1. 更新不稳定:由于SGD只考虑一个样本,每次更新都有一定的随机性,可能导致更新不稳定。
  2. 容易陷入局部最优:虽然SGD容易跳出局部最优,但由于随机性的影响,也容易再次陷入局部最优点。
  3. 需要调整学习率:SGD的收敛速度很快,但学习率的设置对算法性能至关重要。如果学习率设置不当,可能导致模型无法收敛或收敛速度过慢。

在实际应用中,SGD是机器学习,特别是深度学习领域的重要工具。通过适当调整学习率和优化策略,SGD可以有效地在大数据集上进行模型训练,并找到损失函数的最小化参数。

代码

import numpy as np

def loss(w,x,y):
    return np.sum(np.square(x.dot(x)-y))/len(y)

def gradient(w,x,y):
    return x.T.dot(x.dot(w)-y)/len(y)

def SGD(w,x,y,lr=0.01,epoches=100):
    n_features=x.shape[1]
    w=np.zeros(n_features)
    n_samples=x.shape[0]

    for epoch in range(epoches):
        for i in range(n_samples):
            grad=gradient(w,x[i],y[i])
            w=w-lr*grad
            print("epoch:%d   loss:%f "%(epoch,loss(w,x,y)))

我们可以结合数学原理进行理解 

动量法(Momentum)和Nesterov 动量法

动量法(Momentum)和Nesterov动量法都是优化算法中的技术,用于加速梯度下降过程,特别是在处理具有大量参数的复杂问题时,如深度学习模型的训练。

动量法的基本思想是模拟物理中的动量概念,即在梯度下降过程中,不仅考虑当前梯度的方向,还考虑之前的梯度方向。这使得在梯度方向一致的情况下,参数更新的速度会加快,而在梯度方向改变的情况下,参数更新会减缓,从而有助于平滑地穿越“山谷”,抑制振荡,加快收敛速度。

具体来说,动量法在每一步迭代中,都会积累之前的梯度信息,形成一个“动量”,然后用这个动量来更新参数。这样做的好处是,当梯度方向一致时,动量会增大,使得参数更新更快;而当梯度方向改变时,动量会减小,使得参数更新更稳定

Nesterov动量法是动量法的一种变种。与标准的动量法不同,Nesterov动量法在计算梯度时,会先根据上一步的动量方向进行部分更新,然后再计算梯度。这种做法实际上是在一个“预测”的位置计算梯度,而不是在当前位置。这样做的好处是,可以使得参数更新更加准确,进一步加速收敛。

在实际应用中,Nesterov动量法常用于训练深度神经网络。由于深度神经网络的参数众多,优化过程复杂,Nesterov动量法的应用可以使得训练过程更加稳定,并且有助于防止参数更新过程中的震荡现象。

总的来说,动量法和Nesterov动量法都是用于加速梯度下降过程的优化技术,它们在处理具有大量参数的复杂问题时非常有效,特别是在深度学习的训练过程中。Nesterov动量法作为动量法的变种,通过提前进行部分更新来改进参数更新的准确性,进一步提高了收敛速度。

 AdaGrad(Adaptive Gradient Algorithm)和RMSprop

AdaGrad算法通过为每个参数提供不同的学习率,实现了自适应学习率的功能。具体来说,AdaGrad为每个参数初始化一个变量,并在每次更新时将该参数的梯度平方求和累加到该变量上。学习率则根据累积的梯度平方进行归一化,使得对于经常更新的参数,学习率逐渐减小;而对于更新较少的参数,学习率逐渐增大。这种策略有助于平衡不同参数之间的更新速度,避免因为学习率设置不合理而导致的训练效果下降。然而,AdaGrad的一个缺点是它可能会因为累积的梯度平方越来越大而导致学习率过早地趋近于0,从而使得权值无法得到更新。

RMSprop算法则是对AdaGrad的一种改进,它通过计算梯度平方的移动平均值来调整学习率。RMSprop使用一个衰减率来控制历史梯度的权重,从而避免了AdaGrad中因为梯度累积而导致的学习率过早下降的问题。RMSprop的核心思想是利用历史梯度的指数衰减平均来自适应地调整学习率,这使得它在处理非平稳目标和嘈杂梯度时表现得更为出色。

Adam(Adaptive Moment Estimation)

Adam(Adaptive Moment Estimation)是一种优化算法,它结合了动量法(Momentum)和自适应学习率的优点,用于在训练神经网络等深度学习模型时自适应地调整学习率。Adam算法通过估计梯度的一阶矩(均值)和二阶矩(方差)来调整学习率,并在训练过程中自适应地更新参数。

动量法可以帮助算法在相关方向上加速收敛,同时抑制振荡,特别是在遇到噪声或者非凸优化问题时。而Adam算法进一步结合了自适应学习率的特性,使得在训练过程中可以自动调整学习率的大小,从而更有效地进行参数更新。

Adam算法的实现相对简单,计算效率较高,并且对内存需求较少。此外,它的超参数通常具有很好的解释性,通常无需进行大量的调整或微调。Adam算法也很适合应用于大规模的数据及参数的场景,特别是在不稳定目标函数、梯度稀疏或梯度存在很大噪声的问题中表现出色。

然而,Adam算法也有其局限性。首先,收敛速度与学习率设置有关,初始学习率的设置对收敛速度和效果有影响。其次,Adam算法对数据的分布和噪声较为敏感,在处理不平衡数据或含有噪声的数据时可能会产生较大的偏差。此外,在某些情况下,超参数(如权重衰减、动量等)的设置仍然需要经验和实践来调整。最后,虽然Adam算法的计算效率较高,但在大规模数据集和高维度参数空间的情况下,计算负担仍然较大。

牛顿法和拟牛顿法

原理

牛顿法是一种迭代算法,通过逐步逼近的方式求解极值,即最优解。它的基本思想是利用迭代点处的一阶导数(梯度)和二阶导数(Hessen矩阵)对目标函数进行二次函数近似,然后把二次模型的极小点作为新的迭代点,并不断重复这一过程,直至求得满足精度的近似极小值。拟牛顿法则使用正定矩阵来近似Hessen矩阵的逆,从而简化了运算的复杂度。

导包

import numpy as np
from scipy.linalg import inv

其中, from scipy.linalg import inv

是从 scipy 库的 linalg(线性代数)模块中导入 inv 函数。inv 函数用于计算一个方阵的逆矩阵

那么,什么是逆矩阵呢?

这样就得到了逆矩阵

逆矩阵*矩阵=单位矩阵 

不用多说,均方误差求损失函数

def loss_function(w,x,y):
    return np.sum(np.square(x.dot(w)-y))/len(y)

求海森矩阵

def hessian(w,x,y):
    return x.T.dot(x)/len(y)

我们要明白什么是海森矩阵,海森矩阵就是对函数求·一阶偏导后再求二阶偏导 ,最终格式为

而海森矩阵在代码中就是通过矩阵*矩阵的转置/样本的数量得到的,即x.T.dot(x)/len(y)

求梯度

def gradient(w,x,y):
    return x.T.dot(x.dot(w)-y)/len(y)

利用牛顿法更新梯度

def newton(x,y,lr=0.01,epoches=100):
    n_features = x.shape[1]
    w=np.zeros(n_features)
    for epoch in range(epoches):
        H=hessian(w,x,y)
        w=w-inv(H).dot(gradient(w,x,y))
        print("epoch:%d loss:%f"%(epoch+1,loss_function(w,x,y)))
    return w

要记得初始化w为0!!! 

原理是反复计算函数在处的Hessian矩阵和梯度向量,再进行迭代

使用损失函数的二阶导数信息(海森矩阵 H)和一阶导数信息(梯度 gradient(w, x, y))来更新权重 w

inv(H) 是海森矩阵 H 的逆。海森矩阵包含了损失函数关于权重的二阶导数信息,即损失函数的曲率。通过求逆,我们得到的是一 个矩阵,该矩阵能够将梯度向量转换成一个方向,这个方向指向损失函数减小的最快方向

inv(H).dot(gradient(w, x, y)) 计算的是牛顿法的更新方向。这里,我们通过将梯度向量与海森矩阵的逆相乘,得到的是一个能够最大程度减小损失函数的权重更新量。

w = w - inv(H).dot(gradient(w, x, y)) 最后,我们将当前的权重 w 减去这个更新量,得到新的权重向量。这个新的权重向量应该更接近使损失函数最小化的最优解

完整代码

import numpy as np
from scipy.linalg import inv

def loss_frunction(w,x,y):
    return np.sum(np.square(x.dot(w)-y))/len(y)

def gradient(w,x,y):
    return x.T.dot(x.dot(w)-y)/len(y)

def hessian(w,x,y):
    return x.T.dot(x)/len(y)

def newton(x,y,lr=0.01,epoches=100):
    n_features = x.shape[1]
    w=np.zeros(n_features)
    for epoch in range(epoches):
        H=hessian(w,x,y)
        w=w-inv(H).dot(gradient(w,x,y))
        print("epoches:%d  loss:%f"%(epoch+1,loss_frunction(w,x,y)))
        return w

共轭梯度法

共轭梯度法(Conjugate Gradient)是介于最速下降法与牛顿法之间的一个方法。它仅需利用一阶导数信息,克服了最速下降法收敛慢的缺点,又避免了牛顿法需要存储和计算Hesse矩阵并求逆的缺点。共轭梯度法不仅是解决大型线性方程组最有用的方法之一,也是解大型非线性最优化最有效的算法之一。

下面是一个简单的代码演示

import numpy as np  
  
# 定义目标函数  
def f(x):  
    return x**2  
  
# 定义目标函数的导数(梯度)  
def df(x):  
    return 2*x  
  
# 初始化参数  
x = 0.5  
learning_rate = 0.1  
epochs = 100  
  
# 梯度下降法  
for i in range(epochs):  
    grad = df(x)  
    x -= learning_rate * grad  
    print(f"Epoch {i+1}, x={x}, f(x)={f(x)}")  
  
print(f"Local minimum occurs at x={x}, f(x)={f(x)}")

 LBFGS

LBFGS特别适合处理大规模问题。LBFGS算法的目标是最小化一个给定的函数,通常用于机器学习中的参数估计。

from scipy.optimize import minimize 

导包,求解最小化问题

def object_function(x):
    return x**2-4*x+4

定义目标函数

result=minimize(object_function,x0=1,method='L-BFGS-B')
x_min=result.x
print("L-BFGS-B 找到的 x 的最小值为:", x_min)
print("L-BFGS-B 方法找到的最小函数值为:", object_function(x_min))
  • x0=1 是优化过程的初始点,即算法从 x=1 这个点开始搜索最小值。
  • method='L-BFGS-B' 指定了使用的优化算法为 L-BFGS-B。L-BFGS-B 是一个用于求解有界变量的优化问题的算法,尽管在这个例子中目标函数是无界的,但 L-BFGS-B 也可以用来求解无界问题。

然后用x_min来存储找到目标函数最小值时x的值

object_function(x_min也可以写为result.fun

在这里,我们可以拓展一下result的用法

SA

from scipy.optimize import basinhopping
def object_function(x):
    return (x-2)**2

result=basinhopping(object_function,x0=1)
print(f"SA的最小值为:{result.x}")
result=basinhopping(object_function,x0=1)

不论初始猜测值 x0 是多少,basinhopping 都应该能够找到这个最小值点

basinhopping 是一种用于寻找全局最小值的算法,它通过结合局部优化和随机扰动来避免陷入局部最小值

 AC-SA

一种基于自适应聚类的模拟退火算法。通过模拟物理退火过程,利用聚类技术来组织解空间并控制解的移动。该方法适用于处理大规模、高维度的优化问题,尤其适用于那些具有多个局部最优解的问题。

遗传算法是一种基于自然选择和遗传学机理的生物进化过程的模拟算法,适用于解决优化问题,特别是组合优化问题。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。

PSO

PSO是一种基于种群的随机优化技术,模拟了鸟群觅食的行为。粒子群算法模仿昆虫、兽群、鸟群和鱼群等的群集行为,这些群体按照一种合作的方式寻找食物,群体中的每个成员通过学习它自身的经验和其他成员的经验来不断改变其搜索模式。PSO算法适用于处理多峰函数和离散优化问题,具有简单、灵活和容易实现的特点。

各类算法优缺点

  • 梯度下降类的优化算法:优点是简单、快速,常用于深度神经网络模型;缺点是可能得到的是局部最优解。

  • 牛顿法:优点是二阶收敛,收敛速度快;缺点是需要计算目标函数的Hessian矩阵,计算复杂度高。

  • 模拟退火算法:优点是避免陷入局部最优解,能够找到全局最优解;缺点是收敛速度慢,需要大量时间。

  • 遗传算法:优点是通过变异机制避免陷入局部最优解,搜索能力强;缺点是编程复杂,需要设置多个参数,实现较为复杂。

  • 粒子群优化算法:优点是简单、收敛快、计算复杂度低;缺点是多样性丢失、容易陷入局部最优,实现较为复杂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值