使用scikit-opt中粒子群算法求解约束优化问题

一、有约束情况下的粒子群算法函数寻优思想

粒子群算法求解约束优化问题,关键是约束的处理,初始化将粒子历史最优位置设为 + ∞ +\infty +,每次迭代若粒子位置满足约束且优于历史最优位置,则更新位置,逐步引导粒子在可行域内搜索最优解。

或者采用罚函数法、增广拉格朗日函数法将约束优化问题转化为无约束优化问题后,可以采用梯度类、粒子群算法进行求解。https://blog.csdn.net/qq_43276566/article/details/136810660

二、官网例题求解

scikit-opt库中,从sko.PSO中导入PSO算法,可以用来求解不等式约束优化问题(目前还不能求解等式约束优化问题),官网例题如下:
min ⁡ f ( x 1 , x 2 ) = − 20 × e − 0.2 0.5 ( x 1 2 + x 2 2 ) − e 0.5 ( cos ⁡ 2 π x 1 + ( cos ⁡ 2 π x 2 ) ) + 20 + e s.t. ( x 1 − 1 ) 2 + x 2 2 − 0. 5 2 ≤ 0 x 1 , x 2 ∈ [ − 2 , 2 ] \begin{align} \min & \quad f(x_1, x_2) = -20 \times \text{e}^{-0.2\sqrt{0.5(x_1^2+ x_2^2)}} -\text{e}^{0.5 (\cos 2 \pi x_1 + (\cos 2 \pi x_2))}+20+ \text e \\ \text{s.t.} & \quad (x_1-1)^2 + x_2^2 - 0.5^2 \leq 0 \\ & \quad x_1,x_2 \in [-2,2] \end{align} mins.t.f(x1,x2)=20×e0.20.5(x12+x22) e0.5(cos2πx1+(cos2πx2))+20+e(x11)2+x220.520x1,x2[2,2]
该问题的最优解为 f ( 0.95 , 0 ) = 2.58 f(0.95,0)=2.58 f(0.95,0)=2.58

官网代码如下:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from sko.PSO import PSO


def demo_func(x):
    x1, x2 = x
    return -20 * np.exp(-0.2 * np.sqrt(0.5 * (x1 ** 2 + x2 ** 2))) - np.exp(
        0.5 * (np.cos(2 * np.pi * x1) + np.cos(2 * np.pi * x2))) + 20 + np.e


constraint_ueq = (
    lambda x: (x[0] - 1) ** 2 + (x[1] - 0) ** 2 - 0.5 ** 2
    ,
)

max_iter = 50


pso = PSO(func=demo_func, n_dim=2, pop=40, max_iter=max_iter, lb=[-2, -2], ub=[2, 2]
          , constraint_ueq=constraint_ueq, verbose=True)

pso.record_mode = True
pso.run()
print(pso.gbest_y)
print('best_x is ', pso.gbest_x, 'best_y is', pso.gbest_y)

# %% Now Plot the animation


record_value = pso.record_value
X_list, V_list = record_value['X'], record_value['V']

fig, ax = plt.subplots(1, 1)
ax.set_title('title', loc='center')
line = ax.plot([], [], 'b.')

X_grid, Y_grid = np.meshgrid(np.linspace(-2.0, 2.0, 40), np.linspace(-2.0, 2.0, 40))
Z_grid = demo_func((X_grid, Y_grid))
ax.contour(X_grid, Y_grid, Z_grid, 30)

ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)

t = np.linspace(0, 2 * np.pi, 40)
ax.plot(0.5 * np.cos(t) + 1, 0.5 * np.sin(t), color='r')

plt.ion()
p = plt.show()


def update_scatter(frame):
    i, j = frame // 10, frame % 10
    ax.set_title('iter = ' + str(i))
    X_tmp = X_list[i] + V_list[i] * j / 10.0
    plt.setp(line, 'xdata', X_tmp[:, 0], 'ydata', X_tmp[:, 1])
    return line


ani = FuncAnimation(fig, update_scatter, blit=True, interval=25, frames=max_iter * 10)
plt.show()

ani.save('pso.gif', writer='pillow')

在这里插入图片描述

三、scikit-opt源码复现

scikit-opt有中文文档,并且可以查看源码,遂进行复现:

from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

mpl.rcParams['font.sans-serif'] = ['Times New Roman']  # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题


class PSO:
    def __init__(self, function, constraints, lb, ub):
        self.w = 1  # 惯性权重
        self.c1 = 0.5  # 加速系数
        self.c2 = 0.5  # 加速系数
        self.dimension = 2
        self.pop_size = 50
        self.max_iteration = 100

        self.lb = np.array(lb)
        self.ub = np.array(ub)
        assert np.all(self.ub > self.lb), 'upper-bound must be greater than lower-bound'

        self.max_speed = self.ub - self.lb  # 限制粒子的最大速度
        self.function = function
        self.constraints = constraints

    def evaluate(self, X):
        x = X[:, 0]
        y = X[:, 1]
        return self.function(x, y).reshape(-1, 1)

    def check_constraint(self, x):
        # gather all unequal constraint functions
        for constraint_func in self.constraints:
            if constraint_func(x) > 0:
                return False
        return True

    def update_velocity(self, X, V, pbest, gbest):
        """
           根据速度更新公式更新每个粒子的速度
           :param V: 粒子当前的速度矩阵,20*2 的矩阵
           :param X: 粒子当前的位置矩阵,20*2 的矩阵
           :param pbest: 每个粒子历史最优位置,20*2 的矩阵
           :param gbest: 种群历史最优位置,1*2 的矩阵
        """
        r1 = np.random.random(size=(self.pop_size, self.dimension))
        r2 = np.random.random(size=(self.pop_size, self.dimension))
        V = self.w * V + self.c1 * r1 * (pbest - X) + self.c2 * r2 * (gbest - X)  # 直接对照公式写就好了
        return V

    def update_position(self, X, V):
        X = X + V
        X = np.clip(X, self.lb, self.ub)
        return X

    def update_pbest(self, X):
        pass

    def run(self):
        history = []
        # 初始化粒子的位置和速度
        X = np.random.uniform(low=self.lb, high=self.ub, size=(self.pop_size, self.dimension))
        V = np.random.uniform(low=-self.max_speed, high=self.max_speed, size=(self.pop_size, self.dimension))
        pbest_x = X
        pbest_y = np.array([[np.inf]] * self.pop_size)  # pbest_y = Y 不收敛, 必须设置为无穷大
        gbest_x = X[0]
        gbest_y = np.inf

        for i in range(0, self.max_iteration):
            V = self.update_velocity(X, V, pbest_x, gbest_x)  # 更新速度
            X = self.update_position(X, V)  # 更新位置
            Y = self.evaluate(X)  # 计算目标函数值
            # 更新每个粒子的历史最优位置
            need_update = Y < pbest_y
            # print(need_update[0])
            for idx, x in enumerate(X):
                if need_update[idx,]:
                    need_update[idx] = self.check_constraint(x)

            pbest_x = np.where(need_update, X, pbest_x)
            pbest_y = np.where(need_update, Y, pbest_y)

            # 更新群体的最优位置
            idx_min = pbest_y.argmin()
            if gbest_y > pbest_y[idx_min]:
                gbest_x = pbest_x[idx_min, :].copy()
                gbest_y = pbest_y[idx_min]
            history.append((gbest_x, gbest_y))

        x1, x2 = gbest_x
        print(f'x1={x1:.2f}, x2={x2:.2f} 全局最小值:{np.around(gbest_y, 3)}')
        self.plot_objective_value(history)

    def plot_objective_value(self, history):
        obj_list = [gbest_y for gbest_x, gbest_y in history]
        print(obj_list)
        if obj_list[0] == np.inf:
            i = None
            e = None
            for idx, obj in enumerate(obj_list):
                if obj != np.inf:
                    i = idx
                    e = obj
                    break
            for j in range(i):
                obj_list[j] = e
        plt.figure(figsize=(5, 4))
        plt.plot(np.arange(self.max_iteration), obj_list, color="#191970", linewidth=1.5, alpha=1.)
        plt.grid(True)
        plt.xlabel("iteration")
        plt.ylabel("objective value")
        plt.show()


if __name__ == '__main__':
    def demo_func(x1, x2):
        return -20 * np.exp(-0.2 * np.sqrt(0.5 * (x1 ** 2 + x2 ** 2))) - np.exp(
            0.5 * (np.cos(2 * np.pi * x1) + np.cos(2 * np.pi * x2))) + 20 + np.e


    constraint_ueq = (
        lambda x: (x[0] - 1) ** 2 + (x[1] - 0) ** 2 - 0.5 ** 2
        ,
    )

    pso = PSO(function=demo_func,
              constraints=constraint_ueq,
              lb=[-2, -2],
              ub=[2, 2]
              )
    pso.run()

求解结果为:

x1=0.94, x2=0.01 全局最小值:[2.583]

目标函数收敛图:
在这里插入图片描述

参考

  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hyperopt-sklearn是基于scikit-learn项目的一个子集,其全称是:Hyper-parameter optimization for scikit-learn,即针对scikit-learn项目的超级参数优化工具。由于scikit-learn是基于Python的机器学习开源框架,因此Hyperopt-sklearn也基于Python语言。Hyperopt-sklearn的文档称:对于开发者而言,针对不同的训练数据挑选一个合适的分类器(classifier)通常是困难的。而且即使选好了分类器,后面的参数调试过程也相当乏味和耗时。更严重的是,还有许多情况是开发者好不容易调试好了选定的分类器,却发现一开始的选择本身就是错误的,这本身就浪费了大量的精力和时间。针对该问题,Hyperopt-sklearn提供了一种解决方案。Hyperopt-sklearn支持各种不同的搜索算法(包括随机搜索、Tree of Parzen Estimators、Annealing等),可以搜索所有支持的分类器(KNeightborsClassifier、KNeightborsClassifier、SGDClassifier等)或者在给定的分类器下搜索所有可能的参数配置,并评估最优选择。并且Hyperopt-sklearn还支持多种预处理流程,包括TfidfVectorizer,Normalzier和OneHotEncoder等。那么Hyperopt-sklearn的实际效果究竟如何?下表分别展示了使用scikit-learn默认参数和Hyperopt-sklearn优化参数运行的分类器的F-score分数,数据源来自20个不同的新闻组稿件。可以看到,经过优化的分类器的平均得分都要高于默认参数的情况。另外,Hyperopt-sklearn的编码量也很小,并且维护团队还提供了丰富的参考样例。 标签:Hyperopt
粒子群算法(Particle Swarm Optimization,PSO)是一种优化算法,常用于数学建模和问题求解。在Python,有一些库和模块可以使用粒子群算法进行数学建模。 其一个常用的库是scikit-optscikit-opt是一个优化算法库,对于新手来说十分友好,代码简洁易懂,上手简单。它包含了多种优化算法,包括粒子群算法。此外,scikit-opt的代码和官方文档都是由国人编写的,有大量的案例可以参考,学习起来也不会有太大压力。 下面是一个使用scikit-opt粒子群算法(PSO)求解问题的示例代码: ```python import numpy as np from sko.PSO import PSO def demo_func(x): x1, x2 = x return -20 * np.exp(-0.2 * np.sqrt(0.5 * (x1 ** 2 + x2 ** 2))) - np.exp(0.5 * (np.cos(2 * np.pi * x1) + np.cos(2 * np.pi * x2))) + 20 + np.e constraint_ueq = (lambda x: (x - 1) ** 2 + (x - 0) ** 2 - 0.5 ** 2, ) # 定义约束条件 max_iter = 50 pso = PSO(func=demo_func, n_dim=2, pop=40, max_iter=max_iter, lb=[-2, -2], ub=[2, 2], constraint_ueq=constraint_ueq) pso.record_mode = True # 记录每一代的最优解 pso.run() print('最优解为: x =', pso.gbest_x, ', y =', pso.gbest_y) ``` 这段代码使用粒子群算法(PSO)求解了一个数学模型的最优解。其,`demo_func`是待求解的目标函数,`constraint_ueq`是约束条件。通过设置适当的参数,如`max_iter`(迭代次数)、`pop`(种群大小)等,可以得到相应的优化结果。在代码的最后,打印出了求解出的最优解的x和y的值。 请注意,以上代码只是一个示例,实际应用可能需要根据具体问题进行适当的修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值