- 取得連結
- X
- 以電子郵件傳送
- 其他應用程式
程式語言:Python
Package:pyswarm
pyswarm 官網
功能:最佳化參數演算法
Particle swarm optimization
PSO 粒子群演算法
Package:pyswarm
pyswarm 官網
功能:最佳化參數演算法
演算法
- 隨機初始化粒子的位置與速率
- 計算初始粒子的 fitness
- While (直到滿足 threshold)
- 更新粒子速度與位置
$$ \begin{align*} v_i^t &= w\cdot v_i^{t-1}+w_p\cdot rand()\cdot (p_i-x_i^{t-1})+w_g\cdot rand()\cdot (g-x_i^{t-1})\\ x_i^t &= x_i^{t-1} + v_i^t \end{align*} $$ - \(v_i\):粒子的速度
- \(x_i\):粒子的位置
- \(w\):慣性速度權重
- \(w_p\):本身最佳解速度權重
- \(p_i\):本身最佳解位置
- \(w_g\):全體最佳解速度權重
- \(g\) :全體最佳解位置
- 更新粒子的 fitness
概念來自於鳥群覓食
一群鳥在一個廣大的區域中,想找到最多食物的地方
於是大家都帶著手機出門去,一個留守在基地
一開始,大家先隨機分散出去找,然後用手機回報基地,更新自己所找到最多食物的地方
基地也會記錄目前找到最多食物的地方
所以每隻鳥都知道,自己曾經找到最多食物的地方,跟全體找到最多食物的地方
利用這兩個資訊,更新目前本身的飛行速度
慢慢地,大家會集合到同樣的位置上去,而此位置便可能是最多食物的地方
一群鳥在一個廣大的區域中,想找到最多食物的地方
於是大家都帶著手機出門去,一個留守在基地
一開始,大家先隨機分散出去找,然後用手機回報基地,更新自己所找到最多食物的地方
基地也會記錄目前找到最多食物的地方
所以每隻鳥都知道,自己曾經找到最多食物的地方,跟全體找到最多食物的地方
利用這兩個資訊,更新目前本身的飛行速度
慢慢地,大家會集合到同樣的位置上去,而此位置便可能是最多食物的地方
演算法程式碼
基本 PSO 與 pyswarm
import numpy as np
from pyswarm import pso
class PSO:
pBest = []
pBestFitness = []
gBest = None
gBestFitness = np.inf
# 初始化
def __init__(self, fitness, bounds, swarmSize=100, w=0.5, wp=0.5, wg=0.5):
'''
v = w*v + wp*(pBest-x) + wg*(gBest-x)
'''
self.swarmSize = swarmSize
self.fitness = fitness
self.pNum = len(bounds)
self.bounds = bounds
self.w = w
self.wp = wp
self.wg = wg
# 初始化粒子和速度
self.particles = np.zeros((self.swarmSize, self.pNum))
self.v = np.zeros((self.swarmSize, self.pNum))
for i, b in enumerate(self.bounds):
self.particles[:,i] = np.random.uniform(b[0], b[1], self.swarmSize)
self.v[:,i] = np.random.uniform(-b[1]+b[0], b[1]-b[0], self.swarmSize)
# 初始化 fitness
self.pBest = np.zeros((self.swarmSize, self.pNum))
self.pBestFitness = np.ones(self.swarmSize) * np.inf
self.updateFitness()
# 更新 fitness
def updateFitness(self):
for i, p in enumerate(self.particles):
fit = self.fitness(p)
if fit < self.pBestFitness[i]:
self.pBest[i] = p
self.pBestFitness[i] = fit
if fit < self.gBestFitness:
self.gBest = p
self.gBestFitness = fit
def run(self, threshold=0.01, updateThreshold=1e-4, maxiter=20):
n = 0
while self.gBestFitness > threshold and n < maxiter:
# 更新粒子速度
rp = np.random.rand()
rg = np.random.rand()
self.v = self.w*self.v + self.wp*rp*(self.pBest-self.particles) + self.wg*rg*(self.gBest-self.particles)
# 更新粒子
self.particles = self.particles + self.v
for i, b in enumerate(self.bounds):
self.particles[:,i] = np.clip(self.particles[:,i], b[0], b[1])
# 計算 fitness
old = self.gBestFitness
self.updateFitness()
# 若更新小於 0.001,持續 maxiter 次,則中止
if old - self.gBestFitness < 0.001:
n += 1
else:
n = 0
if n > maxiter:
break
return self.gBest, self.gBestFitness
if __name__ == "__main__":
def fitness(x):
return (x[0]-5)**2 + (x[1]-10)**2 + (x[2]+10)**2
xopt, fopt = PSO(fitness, [(-1e10,1e10), (-1e10,1e10), (-1e10,1e10)]).run(threshold=1e-6)
print("自製:{} {}".format(fopt, xopt))
xopt, fopt = pso(func=fitness, lb=(-1e10,-1e10,-1e10), ub=(1e10,1e10,1e10))
print("套件:{} {}".format(fopt, xopt))
PSO + 定期隨機
import numpy as np
class PSO:
pBest = []
pBestFitness = []
gBest = None
gBestFitness = np.inf
# 初始化
def __init__(self, fitness, bounds, swarmSize=100, w=0.5, wp=0.5, wg=0.5):
'''
v = w*v + wp*(pBest-x) + wg*(gBest-x)
'''
self.swarmSize = swarmSize
self.fitness = fitness
self.pNum = len(bounds)
self.bounds = bounds
self.w = w
self.wp = wp
self.wg = wg
# 初始化粒子和速度
self.init_particles()
# 初始化 fitness
self.pBest = np.zeros((self.swarmSize, self.pNum))
self.pBestFitness = np.ones(self.swarmSize) * np.inf
self.updateFitness()
# 初始化粒子
def init_particles(self):
self.particles = np.zeros((self.swarmSize, self.pNum))
self.v = np.zeros((self.swarmSize, self.pNum))
for i, b in enumerate(self.bounds):
self.particles[:,i] = np.random.uniform(b[0], b[1], self.swarmSize)
self.v[:,i] = np.random.uniform(-b[1]+b[0], b[1]-b[0], self.swarmSize)
# 增加粒子
def produce_particles(self, addSize):
self.swarmSize += addSize
ps = np.zeros((addSize, self.pNum))
vs = np.zeros((addSize, self.pNum))
pbests = np.zeros((addSize, self.pNum))
pBestFitness = np.ones(addSize) * np.inf
for i, b in enumerate(self.bounds):
ps[:,i] = np.random.uniform(b[0], b[1], addSize)
vs[:,i] = np.random.uniform(-b[1]+b[0], b[1]-b[0], addSize)
self.particles = np.concatenate((ps, self.particles))
self.v = np.concatenate((vs, self.v))
self.pBest = np.concatenate((pbests, self.pBest))
self.pBestFitness = np.concatenate((pBestFitness, self.pBestFitness))
# 取代粒子
def replace_particles(self, replaceSize):
# 重新排序
index = np.argsort(self.pBestFitness)[::-1]
self.particles = self.particles[index]
self.v = self.v[index]
self.pBest = self.pBest[index]
self.pBestFitness = self.pBestFitness[index]
ps = np.zeros((replaceSize, self.pNum))
vs = np.zeros((replaceSize, self.pNum))
pbests = np.zeros((replaceSize, self.pNum))
pBestFitness = np.ones(replaceSize) * np.inf
for i, b in enumerate(self.bounds):
ps[:,i] = np.random.uniform(b[0], b[1], replaceSize)
vs[:,i] = np.random.uniform(-b[1]+b[0], b[1]-b[0], replaceSize)
self.particles[:replaceSize] = ps
self.v[:replaceSize] = vs
self.pBest[:replaceSize] = pbests
self.pBestFitness[:replaceSize] = pBestFitness
# 更新 fitness
def updateFitness(self):
for i, p in enumerate(self.particles):
fit = self.fitness(p)
if fit < self.pBestFitness[i]:
self.pBest[i] = p
self.pBestFitness[i] = fit
if fit < self.gBestFitness:
self.gBest = p
self.gBestFitness = fit
def run(self, threshold=0.01, maxiter=100, randIter=20):
n = 0
try:
while self.gBestFitness > threshold and n < maxiter:
# 更新粒子速度
rp = np.random.rand()
rg = np.random.rand()
self.v = self.w*self.v + self.wp*rp*(self.pBest-self.particles) + self.wg*rg*(self.gBest-self.particles)
# 更新粒子
self.particles = self.particles + self.v
for i, b in enumerate(self.bounds):
self.particles[:,i] = np.clip(self.particles[:,i], b[0], b[1])
# 計算 fitness
old = self.gBestFitness
self.updateFitness()
# print(self.gBestFitness)
if old - self.gBestFitness < threshold/10:
n += 1
if n % randIter == 0:
self.replace_particles(self.swarmSize//3*2)
# print('replace, now Size: {}'.format(self.swarmSize))
self.produce_particles(self.swarmSize//10)
# print('produce, now Size: {}'.format(self.swarmSize))
else:
n = 0
if n > maxiter:
break
print(n)
except KeyboardInterrupt:
print("Interrupt by user")
return self.gBest, self.gBestFitness
if __name__ == "__main__":
def fitness(x):
return (x[0]-5)**2 + (x[1]-10)**2 + (x[2]+10)**2
pso = PSO(fitness, [(-1e10,1e10), (-1e10,1e10), (-1e10,1e10)])
print(pso.run(threshold=1e-6))
參考
[pso] 初步 - 粒子移動演算法精髓Particle swarm optimization
PSO 粒子群演算法
留言
張貼留言