简介:本资源是一份面向计算智能初学者与算法实践者的粒子群优化(PSO)算法Python复现代码,适用于智能优化、函数寻优、工程参数调参等典型应用场景,帮助读者快速理解PSO核心机制并开展基础实验验证。压缩包仅含1个Python源文件(.py),体积精简至1KB,代码完整实现粒子初始化、速度/位置更新、适应度评估及迭代终止逻辑,结构清晰、注释详实,便于逐行调试与原理对照。目前已有11575人学习下载,反映出其在教学入门与算法复现环节的广泛认可。读者可直接运行该脚本完成经典测试函数(如Sphere、Rastrigin)的优化过程,获取收敛曲线、最优解坐标及迭代日志等关键结果,是掌握群体智能算法底层实现的理想轻量级参考范例。
1. 项目概述:从“黑盒”到“白盒”的算法理解之旅
最近在整理一些经典优化算法的笔记,发现粒子群优化算法(PSO)虽然原理听起来简单,但真要自己动手从零写一个能稳定工作、效果不错的代码,里面门道还真不少。网上能找到的代码要么封装得太好像个黑盒,要么就是过于简化的教学版本,参数调不好,稍微复杂点的问题就“趴窝”了。所以,我决定花点时间,彻底把PSO的代码复现一遍,目标不是简单地跑通一个demo,而是要写出一个结构清晰、可配置性强、便于调试和性能分析的“工业级”教学代码。这个过程,实际上是把论文里的数学公式和流程图,翻译成真正可控、可观测的计算机指令,对于深入理解群体智能算法的收敛行为、参数敏感度至关重要。无论你是刚接触优化算法的学生,想通过动手来加深理解;还是有一定经验的开发者,需要为一个具体问题定制优化器,这篇从零开始的复现记录和踩坑心得,应该都能给你提供直接的参考。
2. PSO核心原理与算法设计拆解
在动手敲代码之前,我们必须把PSO的“发动机”工作原理彻底搞明白。粒子群优化模仿的是鸟群或鱼群寻找食物的社会行为。想象一下,一群鸟在随机搜索一片区域的食物,每只鸟(粒子)都有自己的位置和速度。它们一方面会记住自己飞过的最好位置(个体最优pbest),另一方面也会知道鸟群中所有鸟发现过的最好位置(全局最优gbest)。下一次飞行时,每只鸟的速度就会由三个因素决定:一是“惯性”,让它保持原来的飞行方向;二是“认知”部分,驱动它飞向自己曾找到的好地方;三是“社会”部分,驱动它飞向群体公认的好地方。最后,用速度去更新位置,完成一次迭代。
2.1 算法数学模型与关键参数
标准的PSO速度与位置更新公式是核心:
v_i(t+1) = w * v_i(t) + c1 * r1 * (pbest_i - x_i(t)) + c2 * r2 * (gbest - x_i(t))x_i(t+1) = x_i(t) + v_i(t+1)
这里每一个符号和参数都至关重要:
v_i,x_i: 第i个粒子的速度和位置。这是我们需要在代码中维护的核心状态。w: 惯性权重。它控制着粒子保持原有速度的倾向。w值过大,粒子探索能力强,但容易飞过最优解;w值过小,则开发能力强,但容易陷入局部最优。常见的策略是使用线性递减的w,初期大(如0.9)以探索,后期小(如0.4)以收敛。c1,c2: 加速常数(认知系数和社会系数)。通常设为相等的正值,如2.0。c1促使粒子飞向自身历史最佳,c2促使粒子飞向群体历史最佳。如果c1=0,粒子失去“自我”,容易陷入局部最优;如果c2=0,粒子之间没有信息共享,退化为随机搜索。r1,r2: 介于[0, 1)之间的随机数。这是引入随机性的关键,确保搜索过程的随机性和多样性。
在代码设计时,我们必须为这些参数预留清晰的接口。同时,还需要考虑一些工程实现细节:速度是否需要钳制(v_max)以防止粒子“飞散”?位置是否需要在定义域内进行边界处理?这些都是在设计类和方法时需要提前规划好的。
2.2 代码整体架构设计
一个好的复现代码不应该是一堆函数的堆砌。采用面向对象的设计会让逻辑更清晰,也更容易进行扩展(比如以后想实现多种拓扑结构的PSO变体)。我计划的核心类结构如下:
Particle(粒子类):代表单个粒子。属性包括:当前位置position、当前速度velocity、适应度值fitness、个体历史最佳位置best_position及其适应度best_fitness。方法主要是一个更新自身状态的方法。PSO(优化器类):这是主控制器。属性包括:粒子群列表particles、全局最佳位置gbest_position及其适应度gbest_fitness、所有算法参数(w,c1,c2,pop_size,max_iter等)。核心方法就是optimize(),它控制整个迭代循环。- 目标函数:作为一个可调用的函数或函数对象传入PSO优化器。这样我们的PSO代码就与具体问题解耦了,可以用于优化任何能给出标量输出的函数。
这样的设计使得代码模块化程度高,Particle负责个体行为,PSO负责群体协调和流程控制,非常符合算法本身的逻辑。
注意:在初始化粒子位置和速度时,一定要在问题的定义域内进行均匀随机初始化,而不是全零初始化。全零初始化会严重限制搜索的初始多样性,可能导致早熟收敛。速度的初始值可以设为0,或者一个较小的随机值。
3. 核心代码模块实现与逐行解析
接下来,我们进入具体的代码实现环节。我将使用Python进行实现,因为它简洁易懂,且拥有强大的科学计算生态(如NumPy),便于我们进行向量化运算以提高效率。
3.1 粒子(Particle)类的实现
粒子是算法的基本单元,它需要记录自己的状态和记忆。
import numpy as np class Particle: def __init__(self, dim, bounds): """ 初始化一个粒子。 :param dim: 问题维度(决策变量个数) :param bounds: 列表,每个元素为(min, max),表示每个维度的边界 """ self.dim = dim self.bounds = np.array(bounds) # 转换为数组便于计算 # 位置初始化:在边界内随机生成 self.position = np.random.uniform(self.bounds[:, 0], self.bounds[:, 1], size=self.dim) # 速度初始化:通常初始速度为0,或在较小范围内随机 self.velocity = np.zeros(self.dim) # 当前适应度,初始化为无穷大(对于最小化问题) self.fitness = np.inf # 个体历史最佳位置和适应度 self.best_position = self.position.copy() self.best_fitness = np.inf def evaluate(self, objective_func): """评估粒子当前位置的适应度,并更新个体最优。""" self.fitness = objective_func(self.position) # 如果是更优解,则更新个体历史最佳 if self.fitness < self.best_fitness: # 假设是最小化问题 self.best_position = self.position.copy() self.best_fitness = self.fitness def update_velocity(self, gbest_position, w, c1, c2): """根据PSO公式更新速度。""" r1, r2 = np.random.rand(2) # 生成两个随机数 cognitive = c1 * r1 * (self.best_position - self.position) social = c2 * r2 * (gbest_position - self.position) self.velocity = w * self.velocity + cognitive + social def update_position(self, bounds): """用速度更新位置,并进行边界处理。""" self.position = self.position + self.velocity # 边界处理:反射边界或夹紧边界。这里采用简单的夹紧边界。 self.position = np.clip(self.position, bounds[:, 0], bounds[:, 1])关键点解析:
evaluate方法:这里将目标函数作为参数传入,实现了PSO算法与具体优化问题的分离。update_velocity方法:严格实现了PSO的速度更新公式。注意这里r1和r2是标量,意味着对向量的每个维度使用了相同的随机数。有些实现会为每个维度生成独立的随机数,这会使搜索更具随机性,两种方式都是可行的。update_position方法:更新位置后,立即进行边界处理。np.clip函数将超出边界的值直接设置为边界值。这是一种简单粗暴但有效的“夹紧”边界处理方式。你也可以实现“反射”或“随机重置”等更复杂的策略。
3.2 PSO优化器类的实现
优化器类负责管理整个粒子群,组织迭代流程,并记录优化历史。
class PSO: def __init__(self, objective_func, dim, bounds, pop_size=30, max_iter=100, w=0.8, c1=2.0, c2=2.0, verbose=True): """ 初始化PSO优化器。 :param objective_func: 目标函数,接受一个位置向量,返回一个标量适应度(最小化)。 :param dim: 问题维度。 :param bounds: 每个变量的上下界列表,如 [(lb1, ub1), (lb2, ub2), ...]。 :param pop_size: 粒子群大小。 :param max_iter: 最大迭代次数。 :param w: 惯性权重。 :param c1: 个体学习因子。 :param c2: 社会学习因子。 :param verbose: 是否打印迭代信息。 """ self.objective_func = objective_func self.dim = dim self.bounds = np.array(bounds) self.pop_size = pop_size self.max_iter = max_iter self.w = w self.c1 = c1 self.c2 = c2 self.verbose = verbose # 初始化粒子群 self.particles = [Particle(dim, bounds) for _ in range(pop_size)] # 初始化全局最优 self.gbest_position = np.zeros(dim) self.gbest_fitness = np.inf # 记录历史最佳适应度,用于绘制收敛曲线 self.best_fitness_history = [] def optimize(self): """执行优化主循环。""" # 初始评估,并找到初始全局最优 for particle in self.particles: particle.evaluate(self.objective_func) if particle.best_fitness < self.gbest_fitness: self.gbest_position = particle.best_position.copy() self.gbest_fitness = particle.best_fitness self.best_fitness_history.append(self.gbest_fitness) # 主迭代循环 for iter in range(self.max_iter): # 可选:动态调整惯性权重,例如线性递减 # current_w = self.w_start - (self.w_start - self.w_end) * (iter / self.max_iter) for particle in self.particles: # 更新速度和位置 particle.update_velocity(self.gbest_position, self.w, self.c1, self.c2) particle.update_position(self.bounds) # 评估新位置 particle.evaluate(self.objective_func) # 更新全局最优(可以在粒子循环内实时更新,也可以循环结束后统一更新) if particle.best_fitness < self.gbest_fitness: self.gbest_position = particle.best_position.copy() self.gbest_fitness = particle.best_fitness # 记录本次迭代后的全局最优 self.best_fitness_history.append(self.gbest_fitness) if self.verbose and (iter % 20 == 0 or iter == self.max_iter - 1): print(f"Iter {iter:4d}, Best Fitness: {self.gbest_fitness:.6e}") return self.gbest_position, self.gbest_fitness def get_convergence_curve(self): """返回历史全局最优适应度列表,用于绘制收敛曲线。""" return self.best_fitness_history关键点解析:
- 初始化与评估分离:在
__init__中只创建粒子,不进行评估。评估放在optimize开始处。这样设计更清晰,允许用户在优化前对粒子进行其他操作。 - 全局最优更新时机:代码中在每次粒子更新并评估后,立即检查并更新全局最优。这种方式是“异步”更新,即一旦有粒子发现更好的解,其他粒子在下一次速度更新时就能立即利用这个新信息,通常收敛更快。另一种是“同步”更新,即等所有粒子都更新完位置并评估后,再统一找出
gbest。异步更新更接近原始PSO思想。 - 收敛曲线记录:
best_fitness_history列表记录了每一代(迭代)后的全局最优适应度。这是分析算法性能、绘制收敛图不可或缺的数据。 - 动态参数:注释中给出了动态惯性权重
w的示例。在实际复杂问题中,动态调整w、c1、c2甚至种群大小,是提升性能的常用技巧。
4. 算法测试、可视化与性能分析
代码写完了,但它真的工作吗?效果如何?我们需要用标准测试函数来验证,并通过可视化直观地感受优化过程。
4.1 测试函数与基准测试
我们选用两个经典的单峰和多峰测试函数:
- Sphere函数:
f(x) = sum(x_i^2)。这是一个简单的凸函数,全局最优点在原点(0,0,...),最小值为0。主要用于测试算法的收敛精度和速度。 - Rastrigin函数:
f(x) = 10*n + sum( x_i^2 - 10*cos(2*pi*x_i) )。这是一个高度多峰、震荡剧烈的函数,存在大量局部最优点,全局最优点同样在原点,最小值为0。主要用于测试算法跳出局部最优、进行全局探索的能力。
def sphere(x): return np.sum(x**2) def rastrigin(x): n = len(x) return 10 * n + np.sum(x**2 - 10 * np.cos(2 * np.pi * x)) # 测试配置 dim = 2 bounds = [(-5.12, 5.12)] * dim # Rastrigin的常用定义域 pop_size = 30 max_iter = 100 print("=== 测试 Sphere 函数 ===") pso_sphere = PSO(sphere, dim, bounds, pop_size=pop_size, max_iter=max_iter, w=0.8, c1=2.0, c2=2.0) best_pos, best_fit = pso_sphere.optimize() print(f"找到的最优解: {best_pos}") print(f"对应的最优值: {best_fit}") print("\n=== 测试 Rastrigin 函数 ===") pso_rast = PSO(rastrigin, dim, bounds, pop_size=pop_size, max_iter=max_iter, w=0.8, c1=2.0, c2=2.0) best_pos, best_fit = pso_rast.optimize() print(f"找到的最优解: {best_pos}") print(f"对应的最优值: {best_fit}")运行这段代码,你会看到算法在迭代过程中打印出的最优值变化。对于Sphere函数,PSO应该能非常快速且精确地收敛到接近0的值。对于Rastrigin函数,结果可能会有波动,有时能找到接近0的解,有时会陷入某个局部最优。这正体现了多峰函数的挑战性。
4.2 优化过程可视化
“一图胜千言”。绘制粒子群的搜索动画和收敛曲线,能让我们对PSO的动态行为有更深刻的理解。
import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation # 假设我们保存了某次运行Rastrigin函数时每一代的粒子位置和全局最优 # 这里需要修改PSO类,增加记录每一代所有粒子位置的历史功能(为了演示,简化处理) def visualize_optimization_2d(pso_instance, func, bounds, interval=100): """ 二维问题优化过程动画可视化(简化版,需在PSO类中记录历史数据)。 此处仅为展示思路,完整实现需扩展PSO类的数据记录功能。 """ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) # 左图:函数等高线及粒子散点图 x = np.linspace(bounds[0][0], bounds[0][1], 100) y = np.linspace(bounds[1][0], bounds[1][1], 100) X, Y = np.meshgrid(x, y) Z = np.zeros_like(X) for i in range(X.shape[0]): for j in range(X.shape[1]): Z[i, j] = func(np.array([X[i, j], Y[i, j]])) ax1.contourf(X, Y, Z, levels=50, cmap='viridis', alpha=0.6) ax1.set_xlim(bounds[0]) ax1.set_ylim(bounds[1]) ax1.set_title('Particle Swarm Search') ax1.set_xlabel('x1') ax1.set_ylabel('x2') # 右图:收敛曲线 convergence_curve = pso_instance.get_convergence_curve() line, = ax2.plot([], [], 'b-', linewidth=2, label='Best Fitness') ax2.set_xlim(0, len(convergence_curve)) ax2.set_ylim(min(convergence_curve)*0.9, max(convergence_curve)*1.1) ax2.set_xlabel('Iteration') ax2.set_ylabel('Fitness') ax2.set_title('Convergence Curve') ax2.legend() ax2.grid(True) # 初始化散点(假设有历史位置数据,这里用空数据初始化) scat = ax1.scatter([], [], c='red', s=30, edgecolor='k', label='Particles') gbest_point = ax1.scatter([], [], c='gold', s=100, marker='*', edgecolor='k', label='Global Best') def init(): scat.set_offsets(np.empty((0, 2))) gbest_point.set_offsets(np.empty((0, 2))) line.set_data([], []) return scat, gbest_point, line def update(frame): # 假设 pso_instance.history_positions[frame] 保存了第frame代的所有粒子位置 # 假设 pso_instance.history_gbest[frame] 保存了第frame代的全局最优位置 # positions = pso_instance.history_positions[frame] # gbest = pso_instance.history_gbest[frame] # 此处为演示,使用随机数据代替 positions = np.random.uniform(bounds[:,0], bounds[:,1], size=(pso_instance.pop_size, 2)) gbest = np.mean(positions, axis=0) # 仅作演示,非真实gbest scat.set_offsets(positions) gbest_point.set_offsets([gbest]) line.set_data(range(frame+1), convergence_curve[:frame+1]) ax2.set_xlim(0, len(convergence_curve)) ax2.set_ylim(min(convergence_curve)*0.9, max(convergence_curve)*1.1) return scat, gbest_point, line ani = FuncAnimation(fig, update, frames=len(convergence_curve), init_func=init, blit=True, interval=interval, repeat=False) plt.tight_layout() plt.show() # 如需保存动画:ani.save('pso_optimization.gif', writer='pillow') # 绘制静态收敛曲线则简单很多 def plot_convergence_curve(pso_instance): """绘制收敛曲线。""" history = pso_instance.get_convergence_curve() plt.figure(figsize=(8,5)) plt.plot(history, 'b-', linewidth=2) plt.xlabel('Iteration') plt.ylabel('Best Fitness') plt.title('PSO Convergence Curve') plt.grid(True) plt.yscale('log') # 对数坐标能更清晰地展示后期的细微变化 plt.show() # 使用上面测试得到的 pso_rast 实例绘制收敛曲线 plot_convergence_curve(pso_rast)可视化不仅是为了好看,更是重要的调试和分析工具。通过动画,你可以直观地看到粒子群是如何从随机散布,逐渐向最优区域聚集,以及gbest是如何引导整个群体的。收敛曲线则定量地告诉你算法是否在稳步优化,以及何时趋于稳定。
5. 参数调优、常见问题与实战心得
PSO算法原理简单,但想让它在实际问题上发挥出色,参数调优和应对各种“坑”的经验至关重要。
5.1 关键参数影响与调优指南
参数没有绝对的最优值,但有其经验范围和调整逻辑:
| 参数 | 典型范围/值 | 影响 | 调优建议 |
|---|---|---|---|
种群大小pop_size | 20 - 50 | 粒子越多,探索能力越强,但每次迭代计算成本越高。 | 简单问题(如低维、单峰)用小种群(20-30);复杂、多峰、高维问题用大种群(40-100)。这是最值得首先调整的参数之一。 |
惯性权重w | 0.4 - 0.9 | 控制全局与局部搜索平衡。高w(~0.9)利于全局探索,低w(~0.4)利于局部开发。 | 强烈推荐使用线性递减策略:从较高的值(如0.9)开始,随着迭代线性降低到较低的值(如0.4)。这能在早期广泛探索,后期精细收敛。公式:w = w_max - (w_max - w_min) * (iter / max_iter)。 |
加速常数c1,c2 | 1.5 - 2.5 | c1(认知)控制粒子向自身历史最佳移动的强度;c2(社会)控制粒子向群体最佳移动的强度。 | 通常设为相等,如2.0。若想强调个体探索,可适当增大c1;若想强调群体协作,可适当增大c2。也有研究使用非对称或自适应调整。 |
最大速度v_max | 变量范围的10%-50% | 限制粒子速度,防止其飞离搜索空间。 | 通常设为每个维度变量范围的20%。例如,变量范围是[-5, 5],则v_max可设为2.0。在update_velocity后添加:self.velocity = np.clip(self.velocity, -v_max, v_max)。 |
最大迭代次数max_iter | 问题而定 | 算法停止条件之一。 | 观察收敛曲线,当曲线在连续很多代(如50-100代)都几乎平缓时,即可停止。可以结合适应度阈值(如<1e-6)作为停止条件。 |
实操心得:调参时,建议采用“控制变量法”。先固定其他参数,用收敛曲线作为主要评判标准,观察某个参数变化对收敛速度和精度的影响。种群大小和动态惯性权重是提升性能最有效的两个杠杆。
5.2 常见问题与排查技巧
在复现和应用PSO时,你肯定会遇到下面这些问题:
早熟收敛(Premature Convergence)
- 现象:算法很快(几十代)就停滞了,适应度不再下降,且远离理论最优解。
- 原因:粒子多样性过早丧失,所有粒子迅速聚集到某个局部最优点。
- 解决:
- 增加种群大小:提供更多的探索者。
- 增大惯性权重
w:特别是在初期,让粒子保持探索惯性。 - 引入扰动:当群体最优解长时间不变时,对部分粒子或全局最优解施加小的随机扰动。
- 使用更复杂的拓扑结构:如环形拓扑、冯·诺依曼拓扑,限制信息的传播速度,避免过早一致。
粒子“爆炸”(Divergence)
- 现象:粒子的速度或位置变得极大(NaN或Inf),算法崩溃。
- 原因:速度更新不受控制,尤其是当
w、c1、c2较大且gbest与当前位置距离很远时。 - 解决:
- 钳制速度(
v_max):这是必须的!确保速度在合理范围内。 - 收缩因子(Constriction Factor):使用带收缩因子的PSO变体(如Clerc‘s PSO),其参数能保证收敛性。公式略有不同,但能数学上保证粒子速度不会爆炸。
- 钳制速度(
收敛速度慢
- 现象:收敛曲线下降缓慢,需要非常多代才能达到满意精度。
- 原因:探索能力过强,或开发能力不足。
- 解决:
- 减小惯性权重
w:特别是在后期,加速收敛。 - 调整
c1/c2比例:增大c2(社会部分)可以加速向已知好区域聚集。 - 局部搜索:在PSO找到近似最优区域后,可以引入一个简单的局部搜索(如梯度下降、Nelder-Mead)进行精细调优。
- 减小惯性权重
边界处理不当导致性能下降
- 现象:大量粒子被“卡”在边界上,搜索空间被浪费。
- 原因:使用简单的“夹紧”边界处理,粒子撞墙后速度分量被置零,失去了沿边界切线方向探索的能力。
- 解决:实现更智能的边界处理策略。例如“反射边界”:当粒子超出边界时,将其位置拉回边界内,并反转该维度上的速度分量。这能让粒子沿着边界“滑动”,更充分地探索边界附近的区域。
# 反射边界处理示例 def update_position_with_reflection(self, bounds): self.position = self.position + self.velocity for d in range(self.dim): if self.position[d] < bounds[d, 0]: self.position[d] = 2 * bounds[d, 0] - self.position[d] self.velocity[d] = -self.velocity[d] * 0.5 # 反射并阻尼 elif self.position[d] > bounds[d, 1]: self.position[d] = 2 * bounds[d, 1] - self.position[d] self.velocity[d] = -self.velocity[d] * 0.5调试技巧:在开发初期,务必在关键步骤后添加断言或打印语句,检查粒子位置、速度、适应度值是否在合理范围内(非NaN,非Inf,在边界内)。可视化(如每一代的粒子位置散点图)是发现群体行为异常(如早熟、爆炸)的最快方法。
6. 高级扩展与工程化思考
一个基础的PSO复现完成后,我们可以从工程和学术两个角度思考如何让它变得更强大、更实用。
6.1 性能优化与并行计算
当问题维度很高或目标函数计算非常耗时(例如调用一次仿真软件)时,标准PSO的串行评估会成为瓶颈。此时,并行化评估是首要的优化手段。
评估并行化:在每一代中,所有粒子的适应度评估是相互独立的。我们可以利用
multiprocessing库或joblib来并行计算。from joblib import Parallel, delayed def evaluate_population_parallel(particles, objective_func, n_jobs=-1): """并行评估整个种群。""" fitnesses = Parallel(n_jobs=n_jobs)(delayed(objective_func)(p.position) for p in particles) for p, fit in zip(particles, fitnesses): p.fitness = fit if fit < p.best_fitness: p.best_position = p.position.copy() p.best_fitness = fit return fitnesses在
PSO.optimize()的主循环中,将串行评估替换为这个并行函数,可以极大缩短运行时间,尤其是当objective_func计算复杂时。向量化运算:我们当前的实现是循环遍历每个粒子进行更新。对于维度不高但种群很大的情况,可以将所有粒子的位置、速度存储在一个矩阵中(
pop_size x dim),利用NumPy的广播机制进行向量化更新,减少Python循环开销。
6.2 PSO变体简介与实践方向
标准PSO有很多改进版本,针对其不同缺陷:
- 带收缩因子的PSO(PSO with Constriction Factor):通过一个计算出的收缩系数χ来更新速度,公式为
v = χ * (v + φ1 * r1 * (pbest - x) + φ2 * r2 * (gbest - x)),其中χ由φ1和φ2计算得出。这种方法能更好地保证算法收敛,通常不需要设置v_max。 - 自适应PSO:让参数
w、c1、c2根据算法的搜索状态(如种群多样性、进化代数)动态变化,实现搜索策略的自适应调整。 - 多目标PSO(MOPSO):用于解决具有多个冲突目标优化问题。核心在于如何定义“最优”(帕累托最优),以及如何维护一个外部档案来存储非支配解,并从中选取全局引导粒子
gbest。 - 离散PSO:标准PSO用于连续空间。对于组合优化问题(如旅行商问题TSP),需要重新定义位置和速度的含义(如位置表示访问顺序的概率,速度表示顺序交换的倾向),以及相应的更新操作。
如果你想挑战更复杂的复现任务,例如网络热词中提到的fixmatch、adalora、vit等,你会发现它们虽然领域不同(半监督学习、参数高效微调、计算机视觉),但其代码复现的核心逻辑是相通的:深入理解论文中的算法流程图和数学公式,将其拆解为可编程的模块(数据流、模型结构、损失函数、训练循环),然后用清晰、可调试的代码实现,最后用标准数据集验证结果是否正确。PSO的这次复现,正是锻炼这种“从理论到实现”能力的绝佳起点。
本文还有配套的精品资源,点击获取