粒子羣算法的思想源於對鳥/魚羣捕食行爲的研究,模擬鳥集羣飛行覓食的行爲,鳥之間經過集體的協做使羣體達到最優目的,是一種基於Swarm Intelligence的優化方法。它沒有遺傳算法的「交叉」(Crossover) 和「變異」(Mutation) 操做,它經過追隨當前搜索到的最優值來尋找全局最優。粒子羣算法與其餘現代優化方法相比的一個明顯特點就是所須要調整的參數不多、簡單易行,收斂速度快,已成爲現代優化方法領域研究的熱點。html
設想這樣一個場景:一羣鳥在隨機搜索食物。已知在這塊區域裏只有一塊食物;全部的鳥都不知道食物在哪裏;但它們能感覺到當前的位置離食物還有多遠。那麼找到食物的最優策略是什麼呢?算法
1. 搜尋目前離食物最近的鳥的周圍區域 dom
2. 根據本身飛行的經驗判斷食物的所在。函數
PSO正是從這種模型中獲得了啓發,PSO的基礎是信息的社會共享學習
每一個尋優的問題解都被想像成一隻鳥,稱爲「粒子」。全部粒子都在一個D維空間進行搜索。優化
全部的粒子都由一個fitness function 肯定適應值以判斷目前的位置好壞。spa
每個粒子必須賦予記憶功能,能記住所搜尋到的最佳位置。code
每個粒子還有一個速度以決定飛行的距離和方向。這個速度根據它自己的飛行經驗以及同伴的飛行經驗進行動態調整。orm
粒子速度更新公式包含三部分: 第一部分爲「慣性部分」,即對粒子先前速度的記憶;第二部分爲「自我認知」部分,可理解爲粒子i當前位置與本身最好位置之間的距離;第三部分爲「社會經驗」部分,表示粒子間的信息共享與合做,可理解爲粒子i當前位置與羣體最好位置之間的距離。htm
第1步 在初始化範圍內,對粒子羣進行隨機初始化,包括隨機位置和速度
第2步 計算每一個粒子的適應值
第3步 更新粒子個體的歷史最優位置
第4步 更新粒子羣體的歷史最優位置
第5步 更新粒子的速度和位置
第6步 若未達到終止條件,則轉第2步
粒子羣算法流程圖以下:
以Ras函數(Rastrigin's Function)爲目標函數,求其在x1,x2∈[-5,5]上的最小值。這個函數對模擬退火、進化計算等算法具備很強的欺騙性,由於它有很是多的局部最小值點和局部最大值點,很容易使算法陷入局部最優,而不能獲得全局最優解。以下圖所示,該函數只在(0,0)處存在全局最小值0。
# -*- coding: utf-8 -*- import sys reload(sys) sys.setdefaultencoding('utf-8') import numpy as np import matplotlib.pyplot as plt # 目標函數定義 def ras(x): y = 20 + x[0]**2 + x[1]**2 - 10*(np.cos(2*np.pi*x[0])+np.cos(2*np.pi*x[1])) return y # 參數初始化 w = 1.0 c1 = 1.49445 c2 = 1.49445 maxgen = 200 # 進化次數 sizepop = 20 # 種羣規模 # 粒子速度和位置的範圍 Vmax = 1 Vmin = -1 popmax = 5 popmin = -5 # 產生初始粒子和速度 pop = 5 * np.random.uniform(-1,1,(2,sizepop)) v = np.random.uniform(-1,1,(2,sizepop)) fitness = ras(pop) # 計算適應度 i = np.argmin(fitness) # 找最好的個體 gbest = pop # 記錄個體最優位置 zbest = pop[:,i] # 記錄羣體最優位置 fitnessgbest = fitness # 個體最佳適應度值 fitnesszbest = fitness[i] # 全局最佳適應度值 # 迭代尋優 t = 0 record = np.zeros(maxgen) while t < maxgen: # 速度更新 v = w * v + c1 * np.random.random() * (gbest - pop) + c2 * np.random.random() * (zbest.reshape(2,1) - pop) v[v > Vmax] = Vmax # 限制速度 v[v < Vmin] = Vmin # 位置更新 pop = pop + 0.5 * v; pop[pop > popmax] = popmax # 限制位置 pop[pop < popmin] = popmin ''' # 自適應變異 p = np.random.random() # 隨機生成一個0~1內的數 if p > 0.8: # 若是這個數落在變異機率區間內,則進行變異處理 k = np.random.randint(0,2) # 在[0,2)之間隨機選一個整數 pop[:,k] = np.random.random() # 在選定的位置進行變異 ''' # 計算適應度值 fitness = ras(pop) # 個體最優位置更新 index = fitness < fitnessgbest fitnessgbest[index] = fitness[index] gbest[:,index] = pop[:,index] # 羣體最優更新 j = np.argmin(fitness) if fitness[j] < fitnesszbest: zbest = pop[:,j] fitnesszbest = fitness[j] record[t] = fitnesszbest # 記錄羣體最優位置的變化 t = t + 1 # 結果分析 print zbest plt.plot(record,'b-') plt.xlabel('generation') plt.ylabel('fitness') plt.title('fitness curve') plt.show()
輸出結果爲以下,能夠看到它陷入了局部最優解
[-9.95932740e-01 2.82240596e-04]
刪除自適應變異部分的註釋,運行後結果以下,能夠看出收斂到全局最優解。
[0.00081551 -0.00011209]
參數w,c1,c2的選擇分別關係粒子速度的3個部分:慣性部分、社會部分和自身部分在搜索中的做用。如何選擇、優化和調整參數,使得算法既能避免早熟又能比較快的收斂,對工程實踐有着重要意義。
1. 慣性權重w描述粒子上一代速度對當前代速度的影響。w值較大,全局尋優能力強,局部尋優能力弱;反之,則局部尋優能力強。當問題空間較大時,爲了在搜索速度和搜索精度之間達到平衡,一般作法是使算法在前期有較高的全局搜索能力以獲得合適的種子,而在後期有較高的局部搜索能力以提升收斂精度。因此w不宜爲一個固定的常數。
wmax最大慣性權重,wmin最小慣性權重,run當前迭代次數,runmax爲算法迭代總次數。較大的w有較好的全局收斂能力,較小的w則有較強的局部收斂能力。所以,隨着迭代次數的增長,慣性權重w應不斷減小,從而使得粒子羣算法在初期具備較強的全局收斂能力,而晚期具備較強的局部收斂能力。
2. 學習因子c2=0稱爲自我認識型粒子羣算法,即「只有自我,沒有社會」,徹底沒有信息的社會共享,致使算法收斂速度緩慢;學習因子c1=0稱爲無私型粒子羣算法,即「只有社會,沒有自我」,會迅速喪失羣體多樣性,容易陷入局部最優解而沒法跳出;c1,c2都不爲0,稱爲徹底型粒子羣算法,徹底型粒子羣算法更容易保持收斂速度和搜索效果的均衡,是較好的選擇。
3. 羣體大小m是一個整數,m很小時陷入局部最優解的可能性很大;m很大時PSO的優化能力很好,可是當羣體數目增加至必定水平時,再增加將再也不有顯著做用,並且數目越大計算量也越大。羣體規模m 通常取20~40,對較難或特定類別的問題 能夠取到100~200。
4. 粒子羣的最大速度Vmax對維護算法的探索能力與開發能力的平衡很重要,Vmax較大時,探索能力強,但粒子容易飛過最優解;Vmax較小時,開發能力強,可是容易陷入局部最優解。Vmax通常設爲每維變量變化範圍的10%-20%
參考: