粒子位置在群体中未正确参数化



我在为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]将返回:

array([ 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="precomputed")行失败,因此它们不相关。另外,我知道它总是返回1,我只是想让它在完成功能之前运行而不会出错(

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

array([-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="precomputed")失败,因为它将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:FILESboatesAnacondaenvswarping_pso_dbscanlibsite-packagespyswarmssingleglobal_best.py", line 184, in optimize
self.swarm.current_cost = compute_objective_function(self.swarm, objective_func, pool=pool, **kwargs)
File "C:FILESboatesAnacondaenvswarping_pso_dbscanlibsite-packagespyswarmsbackendoperators.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:FILESboatesAnacondaenvswarping_pso_dbscanlibsite-packagessklearnclusterdbscan_.py", line 351, in fit
**self.get_params())
File "C:FILESboatesAnacondaenvswarping_pso_dbscanlibsite-packagessklearnclusterdbscan_.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;博士

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

错误消息说明

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

[...]
File "C:FILESboatesAnacondaenvswarping_pso_dbscanlibsite-packagessklearnclusterdbscan_.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 错误消息。 当您尝试使用数组作为条件时,它会出现。 正如消息所解释的,什么是真值 像[True, False]这样的数组. 您必须使用像all()这样的函数 或any()将数组转换为单个布尔值。

那么,为什么会这样呢? 因为eps不打算成为数组

DBSCAN类的文档中, 参数epsmin_samples是可选的整数。 在这里,您向他们传递数组。

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

示例比较

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

但是,您的新optimize_eps_and_mp函数尝试对数组执行一些不受支持的操作。 特别是,您使用数组的一个维度作为需要标量的DBSCANeps参数。

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

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

分布式执行

你说 那:

pyswarms库应该独立地多次运行它[目标函数](对于群中的每个粒子(并评估它们的结果,它通过一次将函数分发到多组输入来以某种方式做到这一点。

pyswarm实际上可以使用optimizen_processes参数并行化您的群执行 功能。 在这种情况下,您的函数在不同的进程中被多次调用,但仍以数组作为输入。 在您的情况下,有 10 个颗粒、2 个维度和n_processes作为None(默认值(,您的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

最新更新