粒子群算法 | 启发式优化算法
粒子群优化PSO
1、算法原理背景(PSO:Particle swarm optimization)
是一种群体智能算法,通过模拟鸟群觅食寻找目标的过程来进行优化,利用群体中的个体对信息的共享,算法通过不断地更新算法中每个粒子的速度与位置来逼近最优解。每个粒子根据自己的历史最优解和群体的最优解来更新速度和位置,从而在搜索空间中寻找最优解。
2、粒子群算法中的基本概念
粒子:优化问题的候选解
位置:候选解所在的位置
速度:候选解移动的速度
适应度:评价粒子优劣的值,一般设置为目标函数值
个体最佳位置:单个粒子迄今为止找到的最佳位置
群体最佳位置:所有粒子迄今为止找到的最佳位置
3、算法流程
粒子群算法的具体流程包括以下步骤:
- 初始化粒子群(设置一群随机分布的鸟儿):
随机生成一系列具有随机速度和位置的粒子,惯性因子,加速常数,最大迭代次数,算法终止的最小误差,同时记录每个粒子的个体历史最优位置和全局历史最优位置。
2、判断每个鸟儿与食物的距离——评价每个粒子的初始适应值,即代入目标函数
3、找到初始时刻每个鸟儿与食物的距离——将初始适应值作为当前粒子的局部最优值(因变量),且将位置作为当前的局部最优所在的位置(自变量)
4、找到鸟群里距离食物最近的那个鸟以及对应的距离——将所有粒子中的最佳局部最优(初始适应值)作为当前全局最优值,并将其作为当前的全局最优值(最强的那个),最佳位置最为全局最优的位置
5、鸟儿根据三个不同地点调整飞行方向——代入速度更新关系式,更新粒子的飞行速度,并限幅处理,使其不能超过该粒子最大的粒子飞行速度
6、鸟儿开始起飞!鸟儿的位置开始变化——然后代入位移更新表达式,更新每个粒子的位置
7、鸟儿每飞一次,都反省一下自己这一次的位置有没有上一次的位置好——对每个粒子比较每个粒子的适应值是否比历史的局部最优值好,如果好的话则当前适应值作为粒子的局部最优值,对应位置作为粒子的局部最优的位置
8、飞一次后,鸟群里肯定有个鸟的位置最好,找到这个鸟以及对应的位置!——在当前粒子群中找出全局最优值,并将对应的位置作为全局最优的位置
9、鸟儿不断地飞飞飞,直到找到最多食物——重复5~9,直到满足设定的最小误差或达到最大迭代次数10、输出最优值和位置以及其他粒子的局部最优值和位置
4、参数影响
(1) 种群数量
粒子群算法的最大特点就是速度快,因此初始种群取50-1000都是可以的,虽然初始种群越大收敛性会更好,不过太大了也会影响速度;
(2) 迭代次数
一般取100~4000,太少解不稳定,太多浪费时间。对于复杂问题,进化代数可以相应地提高;
(3) 空间维数
粒子搜索的空间维数即为自变量的个数。比如求一元函数的最值就是一维空间,n元函数的最值就是n维空间
(4) 位置限制
限制粒子搜索的空间,即自变量的取值范围,对于无约束问题此处可以省略。
(5) 速度限制
如果粒子飞行速度过快,很可能直接飞过最优解位置,但是如果飞行速度过慢,会使得收敛速度变慢,因此设置合理的速度限制就很有必要了。
注意,参数的确定从来就不是绝对的,如果当前参数得到的结果并不理想的话,我们可以人为的更改某些参数
5、优缺点
优点
缺点
6、与其他算法区别
请谈一下粒子群算法和遗传算法的异同点?
PSO是一个群体优化而不是个体优化的搜索过程,而GA主要是个体基因在进化的过程。
7、python实现
在粒子群算法中,c1和c2被称为加速常数,它们是控制粒子运动的参数。c1和c2通常被设置为常数,在算法中保持不变。c1和c2的作用是控制粒子在搜索空间中移动的速度和方向。
c1和c2的具体定义如下:
- c1:粒子本身的历史最佳位置和当前位置的差值的权重, 表示粒子的认知因子。
- c2:粒子所在的群体历史最佳位置和当前位置的差值的权重,表示粒子与群体的社会因子。
particles什么意思
在粒子群算法中,particles指的是粒子的集合,也可以称为粒子群。在算法执行过程中,每个粒子都代表着问题空间中的一个可能解,而particles则代表着粒子群的集合。
每个粒子都有自己的位置和速度,通过更新位置和速度,粒子可以移动到新的位置,以期望找到更优秀的解决方案。粒子群中的所有粒子都是同时更新的,他们通过彼此之间的交换信息来实现全局搜索。
全局最佳位置(gbest)&历史最佳位置(pbest)
在粒子群算法中,每个粒子都有自己的历史最佳位置(pbest)和全局最佳位置(gbest)。
-
自身历史最佳位置是指当前粒子已知的它自己达到的最优位置,即粒子在搜索过程中达到的最佳解。每个粒子通过比较自己历史上所到达的最佳位置和当前位置,来更新自身历史最佳位置。每个粒子都会记录自己的历史最佳位置,以便在后续迭代过程中进行比较和更新。
-
全局最佳位置是指整个粒子群已知的所有粒子中,目前达到的最优位置。在算法开始时,通常会将第一个粒子视为全局最佳位置,然后在迭代过程中,通过比较每个粒子的自身历史最佳位置和当前全局最佳位置,来更新全局最佳位置。所有的粒子共享同一个全局最佳位置,以便在算法迭代的过程中,能够更好地指导粒子的搜索方向,帮助其更快地达到最优解。
# 实现,你可以借此更好地理解如何在粒子群算法中应用
# VRP:
#
# ```python
import randomclass Particle:def __init__(self, vrp, position):self.vrp = vrpself.position = positionself.velocity = self.__initialize_velocity() # 初始化时速度为0self.pbest = self.position # 初始最优解为当前位置self.pbest_cost = self.__evaluate(self.pbest) # 记录初始最优解的costself.gbest = Noneself.gbest_cost = float('inf')def __initialize_velocity(self):velocity = []for i in range(len(self.vrp.customers)):velocity.append(random.uniform(-1, 1)) # 初始化速度范围为-1到1return velocitydef __evaluate(self, solution):# 计算当前解的costcost = 0for route in solution:demand = 0route_cost = 0if isinstance(route, int):route = [route]for customer in route:demand += self.vrp.customers[customer][1]route_cost += self.vrp.distance_matrix[customer][route[-1]] # 路径长度 = 客户距离 + 已经服务的客户到仓库的距离route_cost += self.vrp.distance_matrix[0][route[0]] # 起点到第一个客户距离route_cost += self.vrp.distance_matrix[0][route[-1]] # 最后一个客户到仓库距离if demand > self.vrp.vehicle_capacity:route_cost += self.vrp.penalty * (demand - self.vrp.vehicle_capacity)cost += route_costreturn costdef update_velocity(self, w, c1, c2, gbest_position):# 更新速度# 先判断 gbest_position 和 pbest 是否为 Noneif not gbest_position:returnif not self.position or not self.pbest:returnvelocity_length = len(self.velocity)position_length = len(self.position)pbest_length = len(self.pbest)gbest_position_length = len(gbest_position)if velocity_length != position_length or velocity_length != pbest_length or velocity_length != gbest_position_length:returnfor i in range(len(self.velocity)):r1 = random.uniform(0, 1)r2 = random.uniform(0, 1)cognitive = c1 * r1 * (self.pbest[i] - self.position[i])print("velocity:", self.velocity)print("pbest:", self.pbest)print("position:", self.position)print("gbest_position:", gbest_position)social = c2 * r2 * (gbest_position[i] - self.position[i])self.velocity[i] = w * self.velocity[i] + cognitive + socialdef update_position(self):# 根据新速度更新当前位置if not self.position: # 如果 self.position 列表为空,则不进行更新操作returnnew_position = []for i in range(len(self.vrp.customers)):if i >= len(self.position): # 检查 i 是否超出了 self.position 的长度breakif self.position[i] == 0:continuenew_pos = self.position[i] + self.velocity[i]if new_pos < 1:new_pos = 1elif new_pos > len(self.vrp.customers) - 1:new_pos = len(self.vrp.customers) - 1new_position.append(int(new_pos))self.position = new_positiondef update_pbest(self):# 如果当前位置比已知最优解更好,则更新最优解new_cost = self.__evaluate(self.position)if new_cost < self.pbest_cost:self.pbest = self.positionself.pbest_cost = new_costdef update_gbest(self, gbest_position, gbest_cost):# 更新全局最优解if gbest_cost < self.gbest_cost:self.gbest = gbest_positionself.gbest_cost = gbest_costclass VRP:def __init__(self, distance_matrix, customers, num_vehicles, vehicle_capacity, max_iterations=100, penalty=1000,w=0.8, c1=0.5, c2=0.5, swarm_size=50):self.distance_matrix = distance_matrixself.customers = customersself.num_vehicles = num_vehiclesself.vehicle_capacity = vehicle_capacityself.max_iterations = max_iterationsself.penalty = penaltyself.w = wself.c1 = c1 #什么意思self.c2 = c2self.swarm_size = swarm_sizedef solve(self):particles = [Particle(self, self.__initialize_particle()) for i in range(self.swarm_size)]gbest = Nonegbest_cost = float('inf')for i in range(self.max_iterations):for particle in particles:particle.update_velocity(self.w, self.c1, self.c2, gbest)particle.update_position()particle.update_pbest()if particle.pbest_cost < gbest_cost:gbest = particle.pbestgbest_cost = particle.pbest_costparticle.update_gbest(gbest, gbest_cost)return gbest, gbest_costdef __initialize_particle(self):# 初始化一个解customers = list(range(1, len(self.customers)))random.shuffle(customers)routes = []for i in range(self.num_vehicles):route = []remaining_capacity = self.vehicle_capacityfor j in customers:if remaining_capacity >= self.customers[j][1]:route.append(j)remaining_capacity -= self.customers[j][1]routes.append(route)return [0] + sum(routes, []) + [0] * (len(self.customers) - len(sum(routes, [])))# ```
#
# 然后你可以创建一个
# VRP
# 对象,并调用
# solve()
# 方法来解决问题:
#
# ```python
distance_matrix = [[0, 10, 15, 20],[10, 0, 35, 25],[15, 35, 0, 30],[20, 25, 30, 0]
]
customers = [(0, 0),(1, 10),(2, 15),(3, 20)
]
vrp = VRP(distance_matrix, customers, num_vehicles=2, vehicle_capacity=30)
solution, cost = vrp.solve()
print("Solution: ", solution)
print("Cost: ", cost)
# ```
#
# 以上仅为一个简单实现,仍可进行参数调优以得到更好的结果。
参考链接
https://zhuanlan.zhihu.com/p/398856271