在FA标准算法的基础上,针对步长因子、最亮个体行为、吸引模型等对萤火虫算法进行改进
一、自适应步长因子
随着迭代次数的增加,步长因子自适应减小,使得刚开始萤火虫更注重全局探索,而后则注重局部探索。
在python实现时,需要注意浅复制的问题!!!
def alphat(self, t):
self.alpha = (1 - t/self.T) * self.alpha #自适应步长
(2)
def alphat(self):
self.alpha = 0.99 * self.alpha
(3)
def alphat3(self, t):
self.alpha = np.exp(-t/self.T) * self.alpha #自适应步长
二、最亮个体行为
在每轮迭代中,所有个体都会向着最亮个体飞行,这会导致最亮个体不会更新,直到有其他更亮的个体出现。因此,我们为最亮个体增加新的行为:向周围试探飞行,如果适应度改善,则飞到新的位置,否则保持在原来的位置。
(1)仅扰动一次
def FindNewBest(self, i):
FFi = self.FitnessFunction(self.X[i,:])
x_ = self.X[i, :] + self.alpha * (np.random.rand(self.D) - 0.5)
ffi = self.FitnessFunction(x_)
if ffi < FFi:
self.X[i,:] = x_
self.FitnessValue[i] = ffi
(2)扰动N次,相当于其他粒子能最优更新N次一样
def FindNewBest(self, i):
FFi = self.FitnessFunction(self.X[i,:])
for i in range(self.N):
x_ = self.X[i, :] + self.alpha * (np.random.rand(self.D) - 0.5)
ffi = self.FitnessFunction(x_)
if ffi < FFi:
self.X[i,:] = x_
self.FitnessValue[i] = ffi
可以看到,在发挥最优个体的局部探索作用后,效果出乎意料的好。同时,通过实验发现,扰动一次不仅所耗时间减少11.4%,解也更加稳定。
三、改进吸引模型
在标准萤火虫算法中,每只萤火虫是可以被群体中所有萤火虫吸引的,这种全吸引模型,每个个体在每一代中的移动次数为 (N - 1) / 2,而在粒子群算法中,每个粒子在每一代中移动一次,因此标准FA的时间复杂度是PSO的N倍。同时,个体的多次移动,会导致结果震荡,收敛速度下降。
(1)标准FA
import numpy as np
import matplotlib.pyplot as plt
import copy
import time
class FA:
def __init__(self, D, N, Beta0, gama, alpha, T, bound):
self.D = D #问题维数
self.N = N #群体大小
self.Beta0 = Beta0 #最大吸引度
self.gama = gama #光吸收系数
self.alpha = alpha #步长因子
self.T = T
self.X = (bound[1] - bound[0]) * np.random.random([N, D]) + bound[0]
self.X_origin = copy.deepcopy(self.X)
self.FitnessValue = np.zeros(N)
for n in range(N):
self.FitnessValue[n] = self.FitnessFunction(self.X[n, :])
def DistanceBetweenIJ(self, i, j):
return np.linalg.norm(self.X[i,:] - self.X[j,:])
def BetaIJ(self, i, j): # AttractionBetweenIJ
return self.Beta0 * \
np.math.exp(-self.gama * (self.DistanceBetweenIJ(i,j) ** 2))
def update(self,i,j):
self.X[i,:] = self.X[i,:] + \
self.BetaIJ(i,j) * (self.X[j,:] - self.X[i,:]) + \
self.alpha * (np.random.rand(self.D) - 0.5)
def FitnessFunction(self, x_):
return np.linalg.norm(x_) ** 2
def FindNewBest(self, i):
FFi = self.FitnessFunction(self.X[i,:])
x_ = self.X[i, :] + self.alpha * (np.random.rand(self.D) - 0.5)
ffi = self.FitnessFunction(x_)
if ffi < FFi:
self.X[i,:] = x_
self.FitnessValue[i] = ffi
def iterate(self):
t = 0
while t < self.T:
for i in range(self.N):
tag = 0
FFi = self.FitnessValue[i]
for j in range(self.N):
FFj = self.FitnessValue[j]
if FFj < FFi:
tag = 1
self.update(i, j)
self.FitnessValue[i] = self.FitnessFunction(self.X[i,:])
FFi = self.FitnessValue[i]
if tag == 0:
self.FindNewBest(i)
t += 1
def find_min(self):
v = np.min(self.FitnessValue)
n = np.argmin(self.FitnessValue)
return v, self.X[n,:]
if __name__ == '__main__':
t = np.zeros(10)
value = np.zeros(10)
for i in range(10):
fa = FA(10, 40, 1, 0.000001, 0.97, 100, [-100, 100])
time_start = time.time()
fa.iterate()
time_end = time.time()
t[i] = time_end - time_start
value[i], n = fa.find_min()
print("平均值:", np.average(value))
print("最优值:", np.min(value))
print("最差值:", np.max(value))
print("平均时间:", np.average(t))
(2)拓扑结构为环形的FA
def iterate(self):
t = 0
while t < self.T:
for i in range(self.N):
tag = 0
FFi = self.FitnessValue[i]
list = [(i-2)%self.N, (i-1)%self.N, (i+1)%self.N, (i+2)%self.N]
for j in list:
FFj = self.FitnessValue[j]
if FFj < FFi:
tag = 1
self.update(i, j)
self.FitnessValue[i] = self.FitnessFunction(self.X[i,:])
FFi = self.FitnessValue[i]
if tag == 0:
self.FindNewBest(i)
t += 1
(3)随机更新
def iterate(self):
t = 0
while t < self.T:
for i in range(self.N):
j = np.random.randint(0,self.N)
FFi = self.FitnessValue[i]
FFj = self.FitnessValue[j]
if FFj < FFi:
self.update(i, j)
self.FitnessValue[i] = self.FitnessFunction(self.X[i,:])
else:
self.FindNewBest(i)
t += 1
# 这里需要注意,虽然网上都是说np.random.randint(a,b)是生成[a,b]之间的整数,但实验生成的整数中不包括整数b。
可以看到,从标准FA到环形拓扑结构,再到随机更新,时间复杂度从变为了
,再到
。同时,我们也会发现,结果也逐渐震荡。
参考文献:
[1]王沈娟,高晓智.萤火虫算法研究综述[J].微型机与应用,2015,34(08):8-11.
[2] 魏伟一,文雅宏.一种精英反向学习的萤火虫优化算法[J]. 智能系统学报,2017,12(5):710-716.
https://www.jianshu.com/p/fc84f3febff7