粒子羣PSO算法相比遺傳算法實現會簡單一點,核心就是根據算子更新個體歷史最優和全局最優。粒子羣用的很少,給個人感受是收斂很快的一種算法。這種算法較爲容易陷入局部最優,若問題具備欺騙性(具備多個假峯,且優化資源集中在其中一個峯上)就不容易找到全局最優。學院有個學長改進PSO發了篇論文,好像是將(全局最優-個體最優)加入到算子當中,這會必定程度上跳出局部最優。git
遺傳算法回顧github
核心算子:算法
v[i] = w * v[i] + c1 * rand() * (pbest[i] - present[i]) + c2 * rand() * (gbest - present[i]) present[i] = present[i] + v[i]
其中v[i]表明第i個粒子的速度,w表明慣性權值,c1和c2表示學習參數,rand()表示在0-1之間的隨機數,pbest[i]表明第i個粒子搜索到的歷史最優值,gbest表明整個集羣搜索到的最優值,present[i]表明第i個粒子的當前位置。segmentfault
模擬一羣鳥尋找食物的過程,每一個鳥就是PSO中的粒子,也就是咱們須要求解問題的可能解,這些鳥在尋找食物的過程當中,會不停改變地本身在空中飛行的位置與速度。改變的方向會根據個體的歷史最優p_best和全局最優g_best來作出改變,也就是上面的核心算子。能夠比喻爲每隻鳥會必定程度上追隨每次迭代中找食物最厲害的那隻鳥,這裏的找食物最厲害就是能最大可能解出目標函數。app
仍是解決遺傳算法當中的簡單單目標問題,求解函數f的最大值dom
max f (x1, x2) = 21.5 + x1·sin(4 pi x1) + x2·sin(20 pi x2) s. t. -3.0 <= x1 <= 12.1 4.1 <= x2 <= 5.8
種羣初始化:函數
import random import numpy as np pop_size = 100 dec_num = 2 #變量個數 dec_min_val = (-3, 4.1) #變量約束範圍 dec_max_val = (12.1, 5.8) pop_x = np.zeros((pop_size, dec_num)) # 全部粒子的位置 pop_v = np.zeros((pop_size, dec_num)) # 全部粒子的速度 p_best = np.zeros((pop_size, dec_num)) # 個體經歷的最佳位置 def init_population(pop_size, dec_num, dec_min_val, dec_max_val, pop_x, pop_v, p_best): for i in range(pop_size): for j in range(dec_num): pop_x[i][j] = random.uniform(dec_min_val[j], dec_max_val[j]) pop_v[i][j] = random.uniform(0, 1) p_best[i] = pop_x[i] # p_best存儲個體的歷史最優
迭代更新:學習
import random import matplotlib.pyplot as plt from Initialization import init_population max_gen = 100 w = 0.4 # 自身權重因子 c1 = 2 # 學習因子 c2 = 2 g_best = np.zeros((1, dec_num)) # 全局最佳個體的位置 popobj = [] def fitness(s): #個體適應值計算 x1 = s[0] x2 = s[1] y = 21.5 + x1 * math.sin(4 * math.pi * x1) + x2 * math.sin(20 * math.pi * x2) return y if __name__ == '__main__': init_population(pop_size, dec_num, dec_min_val, dec_max_val, pop_x, pop_v, p_best) temp = -1 # ------------更新全局最優------------- for i in range(pop_size): fit = fitness(p_best[i]) if fit > temp: g_best = p_best[i] temp = fit # ------------迭代優化------------- for i in range(max_gen): for j in range(pop_size): # ----------------更新個體位置和速度----------------- pop_v[j] = w * pop_v[j] + c1 * random.uniform(0, 1) * (p_best[j] - pop_x[j]) + \ c2 * random.uniform(0, 1) * (g_best - pop_x[j]) pop_x[j] = pop_x[j] + pop_v[j] for k in range(dec_num): # 越界保護 if pop_x[j][k] < dec_min_val[k]: pop_x[j][k] = dec_min_val[k] if pop_x[j][k] > dec_max_val[k]: pop_x[j][k] = dec_max_val[k] # -----------------更新p_best和g_best----------------- if fitness(pop_x[j]) > fitness(p_best[j]): p_best[j] = pop_x[j] if fitness(pop_x[j]) > fitness(g_best): g_best = pop_x[j] popobj.append(fitness(g_best)) print(fitness(g_best)) # -------------------畫圖-------------------- plt.figure(1) plt.title("Figure1") plt.xlabel("iterators", size=14) plt.ylabel("fitness", size=14) t = [t for t in range(0, 100)] plt.plot(t, popobj, color='b', linewidth=3) plt.show()
結果和遺傳算法差很少,但速度是快了,不須要像遺傳算法那樣交叉變異,另外一方面粒子羣的參數設置有點多。優化
Github源碼地址:https://github.com/kugua233/P...spa