python - 粒子群中的粒子位置未正确参数化

标签 python particle-swarm

我在为 pyswarms 设计一个健身函数时遇到了麻烦,该函数实际上会迭代粒子。我的设计基于此(工作)示例代码:

# import modules
import numpy as np

# create a parameterized version of the classic Rosenbrock unconstrained optimzation function
def rosenbrock_with_args(x, a, b, c=0):
    f = (a - x[:, 0]) ** 2 + b * (x[:, 1] - x[:, 0] ** 2) ** 2 + c
    return f

from pyswarms.single.global_best import GlobalBestPSO

# instatiate the optimizer
x_max = 10 * np.ones(2)
x_min = -1 * x_max
bounds = (x_min, x_max)
options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9}
optimizer = GlobalBestPSO(n_particles=10, dimensions=2, options=options, bounds=bounds)

# now run the optimization, pass a=1 and b=100 as a tuple assigned to args

cost, pos = optimizer.optimize(rosenbrock_with_args, 1000, a=1, b=100, c=0)

kwargs={"a": 1.0, "b": 100.0, 'c':0}

似乎通过编写 x[:, 0]x[:, 1],这以某种方式参数化了优化函数的粒子位置矩阵。例如,在调试器中执行 x[:, 0] 返回:

数组([ 9.19955426, -5.31471451, -2.28507312, -2.53652044, -6.29916204, -8.44170591, 7.80464884, -6.42048159, 9.77440842, -9.06991295])

现在,跳到我的代码(摘自),我有这个:

def optimize_eps_and_mp(x):

    clusterer = DBSCAN(eps=x[:, 0], min_samples=x[:, 1], metric="precomputed")
    clusterer.fit(distance_matrix)
    clusters = pd.DataFrame.from_dict({index_to_gid[i[0]]: [i[1]] for i in enumerate(clusterer.labels_)},
                                      orient="index", columns=["cluster"])
    settlements_clustered = settlements.join(clusters)
    cluster_pops = settlements_clustered.loc[settlements_clustered["cluster"] >= 0].groupby(["cluster"]).sum()["pop_sum"].to_list()
    print()

    return 1


options = {'c1': 0.5, 'c2': 0.3, 'w':0.9}
max_bound = [1000, 10]
min_bound = [1, 2]
bounds = (min_bound, max_bound)
n_particles = 10

optimizer = ps.single.GlobalBestPSO(n_particles=n_particles, dimensions=2, options=options, bounds=bounds)
cost, pos = optimizer.optimize(optimize_eps_and_mp, iters=1000)

(变量 distance_matrixsettlements 已在代码前面定义,但在 clusterer = DBSCAN(eps=x[:, 0], min_samples=x[:, 1], metric="precompulated") 所以它们不相关。另外,我知道它总是返回 1,我只是在完成该功能之前尝试使其运行没有错误)

当我在调试器中执行x[:, 0]时,它返回:

数组([-4.54925788, 3.94338766, 0.97085618, 9.44128746, -2.1932764, 9.24640763, 9.18286758, -8.91052863, 0.637599, -2.28228841])

因此,在结构方面与工作示例相同。但它在 clusterer = DBSCAN(eps=x[:, 0], min_samples=x[:, 1], metric="precompulated") 行失败,因为它传递了 x[:, 0]DBSCAN 函数,而不是像工作示例中那样对其进行参数化。

这些示例之间是否存在我没​​有看到的差异?

我还尝试将工作示例 (rosenbrock_with_args) 中的适应度函数粘贴到我的代码中并对其进行优化,以消除我设置实现的某种方式不正确的任何可能性。然后解决方案正常收敛,因此我完全不知道为什么它不适用于我的函数 (optimize_eps_and_mp)

我得到的确切堆栈跟踪指的是 dbscan 算法中的错误,我假设由于它以某种方式传递了整个粒子群值集而不是单个值:

pyswarms.single.global_best:   0%|          |0/1000Traceback (most recent call last):
  File "C:/FILES/boates/work_local/_code/warping-pso-dbscan/optimize_eps_and_mp.py", line 63, in <module>
    cost, pos = optimizer.optimize(optimize_eps_and_mp, iters=1000)
  File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\pyswarms\single\global_best.py", line 184, in optimize
    self.swarm.current_cost = compute_objective_function(self.swarm, objective_func, pool=pool, **kwargs)
  File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\pyswarms\backend\operators.py", line 239, in compute_objective_function
    return objective_func(swarm.position, **kwargs)
  File "C:/FILES/boates/work_local/_code/warping-pso-dbscan/optimize_eps_and_mp.py", line 38, in optimize_eps_and_mp
    clusterer.fit(distance_matrix)
  File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\sklearn\cluster\dbscan_.py", line 351, in fit
    **self.get_params())
  File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\sklearn\cluster\dbscan_.py", line 139, in dbscan
    if not eps > 0.0:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
pyswarms.single.global_best:   0%|          |0/1000

最佳答案

TL;DR

粒子群优化使用批处理。 给定一批粒子,优化函数必须返回一批成本。

错误信息说明

这是错误消息中有趣的部分:

  [...]
  File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\sklearn\cluster\dbscan_.py", line 139, in dbscan
    if not eps > 0.0:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

这是一个非常常见的 Numpy 错误消息。 当您尝试使用数组作为条件时,它就会出现。 正如消息所解释的,truth value 是什么? 像 [True, False] 这样的数组。 您必须使用类似 all() 的函数 或 any() 将数组转换为单个 bool 值。

那么,为什么会发生这种情况呢? 因为eps并不是一个数组

摘自 DBSCAN class 的文档, 参数epsmin_samples是可选整数。 在这里您向它们传递数组。

clusterer = DBSCAN(eps=x[:, 0], min_samples=x[:, 1], metric="precomputed")

示例比较

您询问为什么您的代码可以与 rosenbrock_with_args 一起使用功能。 这是因为它执行的操作可以很好地处理数组。 您向其传递一个二维数组 x (颗粒批处理)形状[10, 2] (10 个维度 2 的粒子)和 a, b, c标量。 由此,它计算出形状为 [10] 的一维数组。 ,这是每个粒子的成本值。

您的新optimize_eps_and_mp但是,函数尝试对数组执行一些不支持的操作。 特别是,您使用数组的一维作为 eps DBSCAN的参数期望一个标量。

要使其正常工作,您应该自己处理批处理,实例化许多 DBSCAN对象:

for row in x:
  clusterer = DBSCAN(eps=row[0], min_value=row[1], [...])

分布式执行

You said 那:

the pyswarms library is supposed to run it [the objective function] many times independently (for each particle in the swarm) and evaluate their results, and it does this somehow by distributing the function to multiple sets of inputs all at once.

pyswarm实际上可以使用 n_processes 并行化您的集群执行 optimize 的参数 功能。 在这种情况下,您的函数在不同的进程中被多次调用,但仍然以数组作为输入。 在你的例子中,有 10 个粒子,2 个维度和 n_processesNone (默认),您的x输入的形状为 [10, 2] 。 如果您设置n_processes发送至 2 您的x输入的形状为 [5, 2] 。 最后如果你设置n_processes到 10,您的 x输入的形状为 [1, 2] 。 无论哪种情况,您都必须“展开”粒子群 DBSCAN实例化。

import pyswarms as ps


def foo(x):
    print(x.shape)
    return x[:,0]


if __name__ == "__main__":
    options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9}
    max_bound = [1000, 10]
    min_bound = [1, 2]
    bounds = (min_bound, max_bound)
    n_particles = 10

    optimizer = ps.single.GlobalBestPSO(n_particles=n_particles, dimensions=2, options=options, bounds=bounds)
    for n_processes in [None, 1, 2, 10]:
        print("\nParallelizing on {} processes.".format(n_processes))
        optimizer.optimize(foo, iters=1, n_processes=n_processes)
Parallelizing on None processes.
(10, 2)

Parallelizing on 1 processes.
(10, 2)

Parallelizing on 2 processes.
(5, 2)
(5, 2)

Parallelizing on 10 processes.
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)

所以,这是有关如何使用 DBSCAN 的完整示例在你的情况下。

def optimize_eps_and_mp(x):
    num_particles = x.shape[0]
    costs = np.zeros([num_particles])
    print("Particles swarm", x)

    for idx, particle in enumerate(x):
        print("Particle", particle)
        clusterer = DBSCAN(eps=x[0], min_samples=x[1], metric="precomputed")
        clusterer.fit(distance_matrix)
        clusters = pd.DataFrame.from_dict({index_to_gid[i[0]]: [i[1]] for i in enumerate(clusterer.labels_)},
                                      orient="index", columns=["cluster"])
        settlements_clustered = settlements.join(clusters)
        cluster_pops = settlements_clustered.loc[settlements_clustered["cluster"] >= 0].groupby(["cluster"]).sum()["pop_sum"].to_list()

        cost = 1  # Update this to compute cost value of the current particle
        costs[idx] = cost

    return costs

关于python - 粒子群中的粒子位置未正确参数化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59106677/

相关文章:

python - 使用粒子群优化进行适当的编码

algorithm - 具有多个参数的粒子群优化和函数

python - 分组和计数以获得 Pandas 的比率

python - 错误消息: "int object is not callable" when trying to make a double comprehension list

python - 如何在我自己的类方法中使用 `with open`?

artificial-intelligence - 量子 PSO 和带电 PSO(PSO = 粒子群优化器)

python - 在 psycopg2 中的游标内线程化

python - Facebook Messenger 机器人通用模板不起作用

algorithm - 粒子群优化(PSO)算法中位置向量和速度向量的内容(元素)是什么?

algorithm - 粒子群优化算法中的粒子