机器/深度学习模型最优化问题详解及优化算法汇总

news2024/11/24 12:26:27

前言

其实最优化问题,从小学开始学习数学的时候就可以说已经接触到了,在我印象中有个问题,用一个平底锅煎饼,每次只能放2只饼,煎一只饼要2分钟(正反各用1分钟),煎三只饼要几分钟。这个问题其实已经可以归为最优化问题,我们实际计算出的时间,和真实最节省的时间不断对比去调整煎饼方案,得到时间花费最短的方案,得到最优解。其实这个问题将对象换一下,将煎饼时间换为损失函数,将煎饼换为训练模型,那这个问题就是最优化问题了。根据我们训练出的模型,不论是回归还是分类,总体上总归和原标签是有损失的,要得到更为优秀的模型就要不断的去降低损失值。深度学习系列文章已经把损失函数体系全部都讲解完毕,不论是回归模型、分类模型、聚类模型还是生成模型问题,如果有需要的同学不要错过。此章节将梳理模型训练最优化问题原理和基础理论,以及讲解常用的最优化算法设计和实现。
博主专注建模四年,参与过大大小小数十来次数学建模,理解各类模型原理以及每种模型的建模流程和各类题目分析方法。此专栏的目的就是为了让零基础快速使用各类数学模型、机器学习和深度学习以及代码,每一篇文章都包含实战项目以及可运行代码。博主紧跟各类数模比赛,每场数模竞赛博主都会将最新的思路和代码写进此专栏以及详细思路和完全代码。若你渴望突破数学建模的瓶颈,不要错过笔者精心打造的专栏。愿你能在这里找到你所需要的灵感与技巧,为你的建模之路添砖加瓦。
一文速学-数学建模常用模型

一、最优化问题基础

以文字去说明最优化问题理解起来是十分抽象且难以起到工程化总结归纳的效果,固我们用数学模型来表示,最优化问题的数学模型一般形式可以描述为下面的结构:

  • m i n i m i z e f ( x ) minimize f(x) minimizef(x)
  • s u b j e c t t o g i ( x ) ≤ 0 , i = 1 , . . . , m subject to g_{i}(x)≤0,i=1,...,m subjecttogi(x)0,i=1,...,m
  • h j ( x ) = 0 , j = 1 , . . . , p h_{j}(x)=0,j=1,...,p hj(x)=0,j=1,...,p

这里的各个组成部分含义如下:

  • f ( x ) f(x) f(x):目标函数,它是我们希望最小化(或最大化)的函数。在最大化问题中,通常将其取负后转化为最小化问题。
  • x x x:决策变量,可以是标量或向量。在多维情况下, x x x 表示一个决策向量。
  • g i ( x ) g_{i}(x) gi(x):不等式约束函数,它限制了决策变量的可行解必须位于一定的范围内。
  • h j ( x ) h_{j}(x) hj(x):等式约束函数,它精确地限制了某些变量的关系。

在没有约束的情况下,最优化问题可以简化为仅最小化(或最大化)目标函数 f ( x ) f(x) f(x)。可能讲到这里大家一看到数学公式又犯懵了,我们再来这么理解:

想象你在玩一款视频游戏,你的目标是得到尽可能多的分数(这就像是你的目标函数 f ( x ) f(x) f(x)),分数是由你的游戏行为(决策变量 x x x)决定的。但是,游戏中有一些规则:

  • 有一些任务你必须避免做到(这就是不等式约束 g i ( x ) ≤ 0 g_{i}(x)≤0 gi(x)0,比如说,你的角色不能掉入陷阱里,否则你会失分或者游戏结束。
  • 另外,有一些必须完成的任务(等式约束 h j ( x ) = 0 ℎ_{j}(x)=0 hj(x)=0,比如说,你需要收集所有的金币才能过关。.

在游戏的可行区域(就是你能在游戏规则下行动的空间)内,你需要找到最好的策略来完成关卡并且得到最高分。这就是你在最优化问题中尝试完成的任务:在一定的规则内,找到最佳的解决方案。在现实世界的问题中,你可能会寻找成本最低的生产策略、最快的路线或者最有效的广告投放方案,而这些都需要在特定的限制和规则下进行。

在不同的领域,这个一般形式的最优化问题可能有更具体的变体。例如:

  • 线性规划(Linear Programming, LP):目标函数和所有约束都是线性的。
  • 非线性规划(Nonlinear Programming, NLP):目标函数或某些约束是非线性的。
  • 整数规划(Integer Programming):所有或部分决策变量被限制为整数。
  • 混合整数线性规划(Mixed Integer Linear Programming, MILP):某些决策变量是整数,且目标函数和约束都是线性的。
  • 动态规划(Dynamic Programming):用于多阶段决策过程优化的方法,可以分解为一系列相互关联的子问题。

理解了以上最优化算法的大体框架之后,我们需要开始学习一些更细致化的理论知识。从最优化算法的建模步骤开始,我们来逐渐拆解建模过程:

  • 定义问题:明确目标函数,变量以及任何可能的约束条件。
  • 选择合适的优化方法:根据问题的特性,选择一个有效的优化算法。
  • 初始化参数:为变量选择一个初始值。
  • 迭代优化:通过迭代过程改进变量,以最小化目标函数。
  • 终止条件:设定一个停止标准,例如迭代次数、目标函数的变化量或计算资源限制。

1.目标函数

目标函数(或成本函数、损失函数)是最优化问题的核心,它是需要最大化或最小化的函数。在机器学习中,目标函数通常衡量模型预测值与实际值之间的差异,因为之前有详细讲过各个模型的类型函数,这里不过多讲解:

在这里插入图片描述

2. 变量

在最优化问题中,变量是决定目标函数值的因素。在机器学习模型中,变量通常指模型的参数,如权重和偏置。通过损失函数的值不断的调整变量权重,就是优化过程。

3.约束条件

在最优化问题中,约束条件定义了解决方案必须遵守的规则。这些规则可以限制解决方案的取值范围或指定某些变量之间的关系。约束条件通常分为两类:等式约束和不等式约束。

3.1等式约束

等式约束指定了变量之间必须满足的精确关系。举个例子,如果我们正在设计一个小工具,其中一个部件的长度加上另一个部件的两倍长度必须总共等于10厘米,那么这就是一个等式约束。数学表达为: h j ( x ) = 0 h_{j}(x)=0 hj(x)=0,其中 h j ( x ) h_{j}(x) hj(x)是一个函数,它描述了变量 x x x之间的关系,而 j j j只是一个索引,用于当有多个等式约束时进行区分。

3.2不等式约束

不等式约束定义了变量的取值范围,而不是确切的值。例如,如果你有一个背包,它的承重限制是20公斤,那么你放入背包的物品总重量就受到了一个不等式约束。数学表达为: g i ( x ) ≤ 0 g_{i}(x)≤0 gi(x)0,其中 g i ( x ) g_{i}(x) gi(x)表示变量 x x x与允许的极限值之间的差距, i i i是约束的索引,用于区分多个不等式约束。

3.3约束条件的重要性

约束条件在最优化问题中至关重要,因为它们确保了解决方案是可行的。在没有约束的情况下,最优化问题可能会导致不现实或不可行的解决方案。例如,在工程设计问题中,如果没有考虑材料的强度或成本,可能会得到理论上效率最高,但实际上无法构建或成本过高的设计。

4.最优化算法

最优化算法是一系列解决最优化问题的数学方法,它们的目标是在给定的条件下寻找最佳的决策变量值。这些变量值可以最小化或最大化一个目标函数。也就是找到最优权重的 x x x,这里简单介绍一下各类最优化算法:

4.1梯度下降(Gradient Descent)

梯度下降是最常见的最优化算法之一,特别是在机器学习领域。这种方法通过计算目标函数的梯度来找到函数值下降最快的方向。然后,它按照这个方向调整变量值,以此来减少函数值。梯度下降分为几种类型:

  • 批梯度下降:在每一步使用所有数据计算梯度。
  • 随机梯度下降(SGD):在每一步只使用一个数据样本来计算梯度。
  • 小批量梯度下降:介于批梯度下降和随机梯度下降之间,它在每一步使用一小批数据来计算梯度。

4.2牛顿法和拟牛顿法

这些方法利用了目标函数的二阶导数信息(即海森矩阵),提供了更快的收敛速率,特别是接近最优解时。拟牛顿法是一类不需要显式计算海森矩阵的方法,例如BFGS和L-BFGS,它们适用于大规模问题的优化。

4.3动量方法

动量方法在SGD的基础上增加了一个动量项,有助于加速SGD在相关方向上的导数,并抑制震荡,从而加快收敛速度。

4.4Adam(Adaptive Moment Estimation)

Adam结合了动量方法和RMSprop的优点。它计算了梯度的一阶矩(即平均值)和二阶矩(即未中心化的方差),然后用这些矩来调整每个参数的学习率。

4.5约束最优化

在有约束的情况下,拉格朗日乘数法是处理等式约束的经典方法。对于不等式约束,可以使用KKT(Karush-Kuhn-Tucker)条件,它是拉格朗日乘数法的一种推广。

4.6启发式和元启发式算法

对于某些复杂的或非凸优化问题,传统的梯度方法可能不适用或效率较低。启发式算法,如遗传算法、粒子群优化(PSO)和模拟退火,提供了替代的全局搜索策略。

4.7贝叶斯优化

贝叶斯优化是一种基于概率模型的全局优化策略,特别适用于那些目标函数评估代价很高的问题。它使用高斯过程来建立目标函数的代理模型,并使用这个模型来指导搜索。

5.凸性

凸性是最优化和数学分析中的一个核心概念。它描述了一个数学对象(如集合或函数)的形状特性。当我们说一个集合或函数是凸的,我们在描述其内部的结构和与其相关的直观几何属性。

5.1凸集

一个集合被称为凸集,如果它内部的任意两点之间的直线段都完全包含在该集合内部。形式化地说,一个集合 C C C是凸的,如果对于任意两点 x , y ∈ C x,y∈C x,yC 和任意 θ θ θ满足 0 ≤ θ ≤ 1 0≤θ≤1 0θ1,以下条件成立:
θ x + ( 1 − θ ) y ∈ C θx+(1-θ)y∈C θx+(1θ)yC

5.2凸函数

一个函数 f : R n − > R f:R^n->R f:Rn>R被称为凸函数,如果它的定义域是一个凸集,并且对于定义域内的任意两点x和y以及任意 θ θ θ满足 0 ≤ θ ≤ 1 0≤θ≤1 0θ1,以下不等式成立:
f ( θ x + ( 1 − θ ) y ) ≤ θ f ( x ) + ( 1 − θ ) f ( y ) f(θx+(1-θ)y)≤θf(x)+(1-θ)f(y) f(θx+(1θ)y)θf(x)+(1θ)f(y)
直观上,这意味着函数的图形之上的任意一点和图形上任意两点连线之间的区域也在图形之上。这也意味着凸函数的局部最小值也是全局最小值。

函数 f ( x ) = x 2 f(x)=x^2 f(x)=x2是一个典型的凸函数。我们可以观察到对于定义域内的任意两点,函数图像上的线段始终位于函数曲线的上方,这是凸函数的关键特性。在整个定义域内,这个函数的任何局部最小值也是全局最小值,而对于这个特定的函数,最小值在 x = 0 x=0 x=0处取得。

在这里插入图片描述

5.3凸性的重要性

凸性在最优化问题中非常重要,因为它保证了最优化问题具有良好的数学性质:

  • 全局最优解:凸优化问题的任何局部最优解也是全局最优解。
  • 优化算法:针对凸问题的优化算法通常更简单,更容易分析,并且更容易实现。
  • 稳定性:凸问题的解通常对问题数据的微小变化具有稳定性。

5.4凸优化

凸优化是研究凸函数或凸集合上的优化问题的一个子领域。由于凸问题的特殊性质,凸优化通常比一般的优化问题要容易解决得多。

5.5判断凸性

对于凸集,判断凸性相对直观。而对于凸函数,判断一个函数是否为凸可以通过计算其二阶导数(如果存在)来完成。如果函数的二阶导数是正的(对于一维函数)或者海森矩阵是半正定的(对于多维函数),那么这个函数是凸函数。

6.导数与梯度

在最优化问题中,导数和梯度是核心的数学概念,用来描述目标函数如何随变量变化而变化,并指导我们如何找到函数的最小值或最大值。

6.1导数(Derivative)

导数是单变量微积分中的基本概念,它描述了函数在某一点处随变量的变化率。对于函数 f ( x ) f(x) f(x),在点 x x x处的导数通常表示为 f ′ ( x ) f'(x) f(x) d f d x \frac{df}{dx} dxdf​。导数告诉我们函数在这一点的斜率,以及函数值是增加还是减少。如果导数为正,那么函数在这一点上随着变量增加而增加;如果导数为负,函数随变量增加而减少。如果导数为零,那么这一点可能是函数的局部极大值、局部极小值或鞍点。在最优化中,我们通常寻找使导数为零的点,因为这些点是潜在的最优点。

6.2梯度

梯度下降算法基于的思想是:要找到函数的最小值,最好的方法是沿着该函数的下降方向探寻。对此我们需要明白代表函数变化快慢的导数以及偏导数,在此基础上我们不仅要知道函数在坐标轴正方向上的变化率(即偏导数),而且还要设法求得函数在其他特定方向上的变化率。而方向导数就是函数在其他特定方向上的变化率。梯度与方向导数有一定的关联性,在微积分里面,对多元函数的参数求delta偏导数,把求得的各个参数的偏导数以向量的形式写出来,就是梯度。

纯数理化的知识可能比较难懂,我们可以结合实际例子来了解:一座高度在 ( x , y ) (x,y) (x,y)点是 H ( x , y ) H(x,y) H(x,y)的山。 H H H这一点的梯度是在该点坡度(或者说斜度)最陡的方向。梯度的大小告诉我们坡度到底有多陡。

梯度也可以告诉我们一个数量在不是最快变化方向的其他方向的变化速度。再次结合山坡的例子。可以有条直接上山的路其坡度是最大的,则其坡度是梯度的大小。也可以有一条和上坡方向成一个角度的路,例如投影在水平面上的夹角为60°。则,若最陡的坡度是40%,这条路的坡度小一点,是20%,也就是40%乘以60°的余弦。
这个现象可以如下数学的表示。山的高度函数 H H H的梯度点积一个单位向量给出表面在该向量的方向上的斜率。这称为方向导数。梯度的方向是函数在该点增长最快的方向,而梯度的大小(模)表示在该方向上函数增长的速率。在最优化问题中,我们通常希望找到函数的全局最小值(对于最小化问题)。通过计算梯度并沿着梯度的反方向(即最陡下降方向)迭代更新变量值,我们可以逼近函数的最小值。

那么了解了以上最优化问题的解答基础之后,可以开始逐步关联这些相关理论,学习一些最优化算法来达到融会贯通。

二、最优化算法计算原理和实现

1.梯度下降法(Gradient Descent)

梯度下降算法(GradientDescent Optimization)是常用的最优化方法之一,“最优化方法”属于运筹学方法,是指在某些约束条件下,为某些变量选取哪些值,可以使得设定的目标函数达到最优问题。最优化方法有很多种,常见的有梯度下降法、牛顿法、共轭梯度法,等等。

import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':
    plot_x = np.linspace(-1,6,141)#从-1到6选取141个点
    plot_y = (plot_x - 2.5)**2 -1 #二次方程的损失函数
    plt.scatter(plot_x[5],plot_y[5],color='r') #设置起始点,颜色为红色
    plt.plot(plot_x,plot_y)
    #设置坐标轴名称
    plt.xlabel('theta',fontproperties='simHei',fontsize=15)
    plt.ylabel('损失函数',fontproperties='simHei',fontsize=15)
    plt.show()

上述代码画出损失函数示意图,x轴代表的是参数theta,y轴代表的是损失函数的值(即Loss值),曲线y代表的是损失函数。我们的目标是希望通过大量的数据训练和调整参数theta,使得损失函数的值最小,可以通过求导数的方式,达到二次方程的最小值点,使得导数为0即可。梯度下降中有个比较重要的参数:学习率eta,它控制模型寻找最优解的速度。

在这里插入图片描述

首先定义损失函数以及导数:

def J(theta): #损失函数
    return (theta-2.5)**2-1
def dJ(theta): #损失函数的导数
    return 2*(theta-2.5)

通过matplotlib绘制梯度下降迭代过程

theta = 0.0 #初始点
theta_history = [theta]
eta = 0.1 #步长
epsilon = 1e-8  #精度问题或者eta的设置无法使得倒数为0
while True:
    gradient = dJ(theta)
    last_theta = theta #先记录下上一个theta的值
    theta = theta - eta * gradient #得到一个新的theta
    theta_history.append(theta)
    if(abs(J(theta)-J(last_theta))<epsilon):
        break #当两个theta值非常接近的时候,终止循环
plt.plot(plot_x,J(plot_x),color='r')
plt.plot(np.array(theta_history),J(np.array(theta_history)),color='b',marker='x')
plt.show() #一开始的时候导数比较大,因为斜率比较陡,后面慢慢平缓了
print(len(theta_history)) #一共走了46步

在这里插入图片描述

学习率对梯度下降法的影响

首先看两个例子,一个学习率为0.01,另一个为0.8

在这里插入图片描述
在这里插入图片描述

第一个例子很明显学习的速度变慢了,第二个例子蓝色的步长在损失函数之间发生了跳跃,不过在跳跃的过程中,损失函数的值依然在不断地变小,步数是22步,因此学习率为0.8时,优化过程的时间缩短。当学习率为1.1时:

在这里插入图片描述

一元二次函数不收敛。学习率是一个需要认真调整的参数,过小会导致收敛过慢,而过大又可能导致模型不收敛。

2.随机梯度下降(Stochastic Gradient Descent, SGD)

随机梯度下降(Stochastic Gradient Descent,简称SGD)是一种用于最优化目标函数的算法,尤其是在机器学习和深度学习中用于最小化损失函数。它是梯度下降算法的一种变体,主要区别在于SGD每次更新参数时只使用一个样本或一个小批量样本来计算梯度,而不是像标准梯度下降算法那样使用整个数据集。

SGD的基本步骤如下:

  1. 随机选择:从数据集中随机选择一个样本(或一小批样本)。
  2. 计算梯度:计算选中样本在当前参数下损失函数的梯度。
  3. 更新参数:根据梯度和学习率更新模型参数。

伪代码如下:

for each epoch:
    Shuffle the dataset
    for each sample in the dataset:
        gradient = compute_gradient(sample, parameters)
        parameters = parameters - learning_rate * gradient

这种每次只使用一个样本的更新方式使SGD特别适合大规模数据集的训练。SGD能更快地进行参数更新,因为它不需要在每次迭代中查看所有数据。此外,随机性有助于SGD跳出局部最小值,增加找到全局最小值的可能性。然而,SGD的缺点是它的更新可能会很嘈杂,导致目标函数的收敛路径变得非常波动。为了克服这一点,通常会随着时间逐渐减小学习率,或者使用SGD的变体,如带动量的SGD或者Adam优化器。

import numpy as np

# 假设我们有一个简单的线性关系 y = 2x + 3 + noise
# 我们将生成一些样本数据来模拟这一关系
np.random.seed(0)
x = np.random.rand(100, 1)
y = 2 * x + 3 + np.random.randn(100, 1) * 0.1

# 初始化参数
w = np.random.randn(1)
b = np.random.randn(1)

# 学习率
learning_rate = 0.1

# 进行100次迭代
for epoch in range(100):
    # 在所有样本中随机选择一个
    idx = np.random.randint(100)
    x_sample = x[idx]
    y_sample = y[idx]
    
    # 计算梯度
    gradient_w = -2 * x_sample * (y_sample - (w * x_sample + b))
    gradient_b = -2 * (y_sample - (w * x_sample + b))
    
    # 更新参数
    w = w - learning_rate * gradient_w
    b = b - learning_rate * gradient_b

# 输出学习到的参数值
print(f"Learned linear function: y = {w[0]}x + {b[0]}")

输出:Learned linear function: y = 2.127594940622086x + 2.941043061188159

在实际的深度学习应用中,梯度的计算会更复杂,并且通常会使用自动微分库(如TensorFlow或PyTorch)来计算梯度。此外,为了提高收敛速度和稳定性,通常会使用SGD的变体,如带动量的SGD、Adam或RMSprop等。

3.Adam(Adaptive Moment Estimation)

Adam(Adaptive Moment Estimation)算法是一种用于深度学习中的优化算法,它结合了Momentum(动量)和RMSprop(均方根传播)的思想。Adam 通过计算梯度的一阶矩(即均值)和二阶矩(即未中心化的方差)估计来自适应地调整每个参数的学习率。

Adam 算法的关键特点:

  • 动量:考虑了过去梯度的指数衰减平均,帮助加速学习过程。
  • 自适应学习率:为每个参数计算梯度平方的指数衰减平均,调整学习率。
  • 偏差校正:对一阶矩和二阶矩的估计进行校正,以防止它们在训练初期(接近于0)的偏差。

Adam 算法的更新规则:

对于每个参数 θ,在每个时间步 t

  1. 计算梯度 g t g_{t} gt
  2. 更新有偏一阶矩估计: m t = β 1 ∗ m t − 1 + ( 1 − β 1 ) ∗ g t m_{t}=β_{1}*m_{t-1}+(1-β_{1})*g_{t} mt=β1mt1+(1β1)gt
  3. 更新有偏二阶矩估计: v t = β 2 ∗ v t − 1 + ( 1 − β 2 ) ∗ g t 2 v_{t}=β_{2}*v_{t-1}+(1-β_{2})*g^2_{t} vt=β2vt1+(1β2)gt2
  4. 计算偏差校正后的一阶矩估计: m t ^ = m t 1 − β 2 t \hat{m_{t}}=\frac{m_{t}}{1-β^t_{2}} mt^=1β2tmt
  5. 计算偏差校正后的二阶矩估计: v t ^ = v t 1 − β 2 t \hat{v_{t}}=\frac{v_{t}}{1-β^t_{2}} vt^=1β2tvt
  6. 更新参数: θ t + 1 = θ t − α ∗ m t ^ / ( v t ^ + c ) θ_{t+1}=θ_{t}-α*\hat{m_{t}}/(\sqrt{\hat{v_{t}}+c}) θt+1=θtαmt^/(vt^+c )

其中, α α α是学习率, β 1 β_{1} β1 β 2 β_{2} β2是衰减率参数,通常取值接近1,ϵ 是为了保持数值稳定性而加入的一个小常数。下面我们来实现Adam算法:

import numpy as np

# 假设我们有一个简单的线性关系 y = 2x + 3 + noise
np.random.seed(0)
x = np.random.rand(100, 1)
y = 2 * x + 3 + np.random.randn(100, 1) * 0.1

# 初始化参数
params = np.random.randn(2)
m, v = np.zeros(2), np.zeros(2)

# Adam 参数
alpha, beta1, beta2, epsilon = 0.01, 0.9, 0.999, 1e-8

# 运行Adam优化
for t in range(1, 1001):
    # 随机获取样本
    idx = np.random.randint(100)
    x_i, y_i = x[idx], y[idx]
    
    # 计算梯度
    grads = 2 * np.array([x_i * (params[0] * x_i + params[1] - y_i), (params[0] * x_i + params[1] - y_i)]).squeeze()
    
    # 更新一阶和二阶矩估计
    m = beta1 * m + (1 - beta1) * grads
    v = beta2 * v + (1 - beta2) * (grads ** 2)
    
    # 计算偏差校正后的估计
    m_hat = m / (1 - beta1 ** t)
    v_hat = v / (1 - beta2 ** t)
    
    # 更新参数
    params -= alpha * m_hat / (np.sqrt(v_hat) + epsilon)

# 输出学习到的参数值
print(f"Learned parameters: {params}")

代码执行成功,并且经过Adam优化算法的迭代,Learned parameters: [2.68152662 2.64279962],我们得到了参数值[2.68152662,2.64279962]。

这意味着学习到的线性模型大致为 y = 2.68 x + 2.64 y=2.68x+2.64 y=2.68x+2.64,接近于我们模拟数据的真实关系。

4.遗传算法(Genetic Algorithms, GAs)

遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。

其主要特点是直接对结构对象进行操作,不存在求导和函数连续性的限定;具有内在的隐并行性和更好的全局寻优能力;采用概率化的寻优方法,不需要确定的规则就能自动获取和指导优化的搜索空间,自适应地调整搜索方向。

遗传算法以一种群体中的所有个体为对象,并利用随机化技术指导对一个被编码的参数空间进行高效搜索。其中,选择、交叉和变异构成了遗传算法的遗传操作;参数编码、初始群体的设定、适应度函数的设计、遗传操作设计、控制参数设定五个要素组成了遗传算法的核心内容。

遗传算法的基本步骤:

  1. 初始化:随机生成一开始的种群。种群由一系列候选解组成,每个候选解(个体)通常是问题解空间中的一个点。
  2. 评估:计算种群中每个个体的适应度(Fitness),适应度反映了个体解决问题的能力。
  3. 选择(Selection):根据个体的适应度选择较优秀的个体进行繁殖。常用的选择方法有轮盘赌选择、锦标赛选择等。
  4. 交叉(Crossover):随机选取一对个体作为父母,按照某种规则交换它们的部分基因,产生新的个体(子代)。这个过程模拟了生物的交配。
  5. 变异(Mutation):以较小的概率随机改变个体中的某些基因,这增加了种群的多样性,有助于算法跳出局部最优解。
  6. 替换:新一代的个体替换掉旧的个体,形成新的种群。这可能会完全替换,或是部分替换。
  7. 终止:重复以上步骤,直到满足某个终止条件,比如达到了最大迭代次数,或者种群已经足够优化。

下面我们来简单实现遗传算法:

import numpy as np

# 目标函数
def fitness_function(x):
    return np.sum(x**2)

# 初始化
def initialize_population(size, n):
    return np.random.rand(size, n)

# 选择
def selection(pop, fitness):
    idx = np.argsort(fitness)
    return pop[idx[:int(len(idx)/2)]]

# 交叉
def crossover(parents, n_children):
    children = []
    for _ in range(n_children):
        parent1, parent2 = parents[np.random.choice(len(parents), 2, replace=False)]
        child = parent1[:len(parent1)//2]
        child = np.concatenate((child, parent2[len(parent2)//2:]))
        children.append(child)
    return np.array(children)

# 变异
def mutation(children, mutation_rate=0.01):
    for child in children:
        if np.random.rand() < mutation_rate:
            idx = np.random.choice(len(child))
            child[idx] = np.random.rand()
    return children

# 遗传算法
def genetic_algorithm(fitness_function, n_iterations, population_size, n_variables):
    pop = initialize_population(population_size, n_variables)
    best_fit = float('inf')
    best_solution = None
    
    for _ in range(n_iterations):
        fitness = np.apply_along_axis(fitness_function, 1, pop)
        best_idx = np.argmin(fitness)
        if fitness[best_idx] < best_fit:
            best_fit = fitness[best_idx]
            best_solution = pop[best_idx]
        
        selected = selection(pop, fitness)
        children = crossover(selected, len(pop) - len(selected))
        children = mutation(children)
        pop = np.concatenate((selected, children))
    
    return best_solution, best_fit

# 使用遗传算法
best_solution, best_fitness = genetic_algorithm(
    fitness_function,
    n_iterations=100,
    population_size=50,
    n_variables=5
)

print(f"Best solution: {best_solution}")
print(f"Best fitness: {best_fitness}")

在上述代码中,目标函数 fitness_function 被定义为 np.sum(x**2),这意味着它会计算一个向量 x 中所有元素的平方和。在遗传算法的上下文中,该函数作为一个适应度函数,其目的是最小化这个函数值。因此,遗传算法在这里的目标是找到一个向量 x,使得 x 中元素的平方和尽可能小。由于 x 中的元素都是非负的(由于是平方),因此最小化平方和实际上等同于找到接近零的向量。上述代码执行结果为:

Best solution: [0.02683969 0.07490378 0.34308792 0.01243034 0.06044091]
Best fitness: 0.12784788404801556

遗传算法通过模拟自然选择的过程来逐步改进种群中个体的质量,最终找到能够产生最低适应度(在这个例子中,即最小的平方和)的解。代码中的 best_solution 就是算法找到的最佳解,而 best_fitness 是这个解的适应度值,即目标函数的最小值。

itness_function被定义为np.sum(x**2),这意味着它会计算一个向量 x中所有元素的平方和。在遗传算法的上下文中,该函数作为一个适应度函数,其目的是最小化这个函数值。因此,遗传算法在这里的目标是找到一个向量x,使得 x中元素的平方和尽可能小。由于x` 中的元素都是非负的(由于是平方),因此最小化平方和实际上等同于找到接近零的向量。上述代码执行结果为:

Best solution: [0.02683969 0.07490378 0.34308792 0.01243034 0.06044091]
Best fitness: 0.12784788404801556

遗传算法通过模拟自然选择的过程来逐步改进种群中个体的质量,最终找到能够产生最低适应度(在这个例子中,即最小的平方和)的解。代码中的 best_solution 就是算法找到的最佳解,而 best_fitness 是这个解的适应度值,即目标函数的最小值。

点关注,防走丢,如有纰漏之处,请留言指教,非常感谢

以上就是本期全部内容。我是fanstuck ,有问题大家随时留言讨论 ,我们下期见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1191487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言C位出道心法(四):文件操作

C语言C位出道心法(一):基础语法 C语言C位出道心法(二):结构体|结构体指针|链表 C语言C位出道心法(三):共用体|枚举 C语言C位出道心法(四):文件操作 一:C语言操作文件认知升维: 二:文件打开 三:文件读写操作 忙着去耍帅,后期补充完整.................................

力扣第1035题 不相交的线中等 c++ (最长公共子序列) 动态规划 附Java代码

题目 1035. 不相交的线 中等 相关标签 数组 动态规划 在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在&#xff0c;可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线&#xff0c;这些直线需要同时满足满足&#xff1a; nums1[i] nums2[j]…

双编码器构建机器人零力拖动/导纳控制思路

前言 这篇博客主要记录昨日与实验室大佬针对UR5机器人拖动示教功能实现的思路。由于本人并非主攻力控方面。直到昨天在做实验的时候&#xff0c;与力控组的大佬讨论过后才了解UR机器人实现导纳控制的思路。 关于导纳控制/零力拖动 导纳控制与阻抗控制单从字面去理解很容易记…

ROS中的节点与包

ROS中的节点与包 超声波传感器节点创建Package包 创建node节点运行node节点 安装的基本单位是包 一个包就是一组节点 超声波传感器节点 创建Package包 catkin_create_pkg ssr_pkg rospy roscpp std_msgs软件包回访 其实&#xff0c;在/opt/ros/noetic/share 里面都是软件包…

【沁恒蓝牙mesh】CH58x USB功能开发记录(0)

本文主要介绍基于【沁恒蓝牙mesh】CH58x USB功能&#xff0c;结合CH583m 评估板的软硬件为二次开发作一系列说明 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是喜欢记录零碎知识点的小菜鸟。&#x1f60e;&#x1f4dd; 个人主页&#xff1a;欢迎访问我的 Etherne…

java多线程文件下载器

文章目录 1.简介2.文件下载的核心3.文件下载器的基础代码3.1 HttpURLConnection3.2 用户标识 4.下载信息4.1 计划任务4.2 ScheduledExecutorService&#x1f340; schedule方法&#x1f340; scheduleAtFixedRate方法&#x1f340; scheduleWithFixedDelay方法 5.线程池简介5.1…

多维时序 | MATLAB实现SOM-BP自组织映射结合BP神经网络的多变量时间序列预测

多维时序 | MATLAB实现SOM-BP自组织映射结合BP神经网络的多变量时间序列预测 目录 多维时序 | MATLAB实现SOM-BP自组织映射结合BP神经网络的多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现SOM-BP自组织映射结合BP神经网络的多变量时…

Qt 自定义分页控件

目录 前言1、功能描述2、代码实现2.1 ui文件2.1 头文件2.2 源码文件2.3 设计思路 4、示例5、总结 前言 在应用程序开发时经常会遇到数据分页的需求&#xff0c;每一页展示特定数量的数据&#xff0c;通过点击按钮翻页或者输入页码跳转到指定页。 本文介绍一个自定义分页控件&a…

微服务-开篇-个人对微服务的理解

从吃饭说起 个人理解新事物的时候喜欢将天上飞的理念转换成平常生活中的实践&#xff0c;对比理解这些高大上的名词&#xff0c;才能让我们减少恐慌的同时加深理解。废话不多说&#xff0c;我们从吃饭开始说起&#xff0c;逐渐类比出微服务的思想。 &#xff08;个人见解&…

计蒜客详解合集(1)期

以后对于简单题目&#xff0c;大致6道题目出一期&#xff0c;稍有难度的才单独一期发布~ 目录 T1266——出勤记录 T1170——人民币支付 T1122——最长最短单词 T1115——字符串判等 T1116——验证子串 T1118——删除单词后缀 T1266——出勤记录 小蒜的算法课老师每次…

任正非说:段到段而不是端到端的变革,一定会局部优秀了,而全局灾难了。

你好&#xff01;这是华研荟【任正非说】系列的第34篇文章&#xff0c;让我们聆听任正非先生的真知灼见&#xff0c;学习华为的管理思想和管理理念。 一、执行一个良好的流程和建立一个良好的流程同样重要。业务部门的一把手要担负起建设和优化流程的责任&#xff0c;而不是流程…

NFS服务器的搭建

架设一台NFS服务器&#xff0c;并按照以下要求配置 准备阶段&#xff1a;准备两台虚拟机&#xff0c;一台作为服务端&#xff0c;一台作为客户端 服务端&#xff08;Server&#xff09;&#xff1a;192.168.75.139 客户端&#xff08;Client&#xff09;:192.168.75.160 两…

【Java 进阶篇】Java Filter 执行流程及生命周期详解

引言 在 Java Web 开发中&#xff0c;Filter 是一种强大的组件&#xff0c;它允许我们在请求到达 Servlet 之前或者响应返回给客户端之前执行一些操作。Filter 的应用场景非常广泛&#xff0c;例如日志记录、权限验证、字符编码转换等。本文将深入讨论 Java Filter 的执行流程…

element-Cascader级联选择器用法?

html <el-form-item label"行业选择" :label-width"formLabelWidth"><div class"m-4"><el-cascader v-model"form.tradeid" :options"options" :props"props" /></div></el-form-ite…

【仿真动画】人机协作机器人自动化产线仿真动画欣赏

人机协作机器人自动化产线仿真动画 动画部分思维导图 机器人自动化产线仿真动画是利用三维动画技术对机器人自动化产线进行仿真模拟&#xff0c;以直观、形象的方式展示产线的运行情况。它具有以下作用&#xff1a; 提高沟通效率 机器人自动化产线的设计、实施和维护涉及多个部…

19.9 Boost Asio 同步字典传输

这里所代指的字典是Python中的样子&#xff0c;本节内容我们将通过使用Boost中自带的Tokenizer分词器实现对特定字符串的切割功能&#xff0c;使用Boost Tokenizer&#xff0c;可以通过构建一个分隔符或正则表达式的实例来初始化tokenizer。然后&#xff0c;可以使用该实例对输…

阿里云服务器u1和e实例有什么区别?哪个比较好?

阿里云服务器u1和e实例有什么区别&#xff1f;哪个比较好&#xff1f;通用算力型u1比较好&#xff0c;因为u1服务器是独享型云服务器&#xff0c;e实例是共享型。 阿里云服务器ECS经济型e实例和通用算力型u1实例有什么区别&#xff1f;如何选择&#xff1f;ECS经济型e实例是共…

Modern C++ 转换构造函数和类型转换函数

在 C/C 中&#xff0c;不同的数据类型之间可以相互转换。无需用户指明如何转换的称为自动类型转换&#xff08;隐式类型转换&#xff09;&#xff0c;需要用户显式地指明如何转换的称为强制类型转换。 不管是自动类型转换还是强制类型转换&#xff0c;前提必须是编译器知道如何…

U盘插在电脑上显示要格式化磁盘怎么办

U盘是一种便携式存储设备&#xff0c;广泛应用于各种场合。然而&#xff0c;有时候我们可能会遇到一些问题&#xff0c;比如将U盘插入电脑后显示要格式化磁盘&#xff0c;这通常意味着U盘的分区出现了问题或者U盘的文件系统已经损坏。这种情况下&#xff0c;我们应该如何解决呢…

linux 显卡驱动 cuda 离线安装

1、 安装显卡驱动&#xff1a; Download NVIDIA, GeForce, Quadro, and Tesla Drivers &#xff08;1&#xff09;注意选择对应的cuda版本&#xff0c;和系统版本&#xff0c;并下载 &#xff08;2&#xff09;