1. 程式人生 > >數學建模方法-粒子群算法

數學建模方法-粒子群算法

title 消息 優先 輸出結果 初始化 社會 -s 進行 1.5

一、引言

  哈嘍大家好,有一段時間沒更新Blog了,最近身體不太舒服哈,今天開始繼續更了。言歸正傳,這次要講的是“粒子群算法”。這個算法是由兩個科學家在1995年,根據對鳥類捕食行為的研究所得到啟發而想出來的。好的,接下來讓我們開始吧。

二、鳥類捕食行為

技術分享圖片

  鳥媽媽有7個鳥寶寶,有一天,鳥媽媽讓鳥寶寶們自己去找蟲子吃。於是鳥寶寶們開始了大範圍的捕食行為。一開始鳥寶寶們不知道哪裏可以找得到蟲子,於是每個鳥寶寶都朝著不同的方向獨自尋找。

  但是為了能夠更快的找到蟲子吃,鳥寶寶們協商好,誰發現了蟲子,就互相說一聲。

  找了一會,終於有一個鳥寶寶(稱之為小藍),似乎發現在他附近不遠處有蟲子的蹤跡。於是它傳話給其他鳥寶寶,其他鳥寶寶,收到消息後,邊開始改變軌跡,飛到小藍這邊。最終,隨著小藍越來越接近蟲子。其他蟲寶寶也差不多都聚集到了小藍這邊。最終,大家都吃到了蟲子。

三、粒子群算法

3.1 故事分析

  鳥寶寶捕食的故事,正是這個粒子群算法存在的原因。因此,如果想更好的了解粒子群算法,我們就要來分析鳥寶寶捕食的故事。首先,我們來分析分析鳥寶寶們的運動狀態,即鳥寶寶自身是怎麽決定自己的飛翔速度和位置的。

  (1) 吶首先,我們知道物體是具有慣性的,鳥寶寶在一開始飛翔的時候,無論它下一次想怎麽飛,往哪個方向飛,它都有一個慣性,它必須根據當前的速度和方向來進行下一步的調整。對吧,這個可以理解吧,因此,“慣性”——當前的速度$v_{current}$是一個因素。

  (2) 其次,由於鳥寶寶長期捕食,因此鳥寶寶有經驗,它雖然不知道具體哪裏是有蟲子的存在,但是它能大概知道蟲子分布在哪裏。比如當鳥寶寶飛到貧瘠的地方,它肯定知道這裏是不會有蟲子的,因此,在鳥寶寶的心中,它每次飛,都會根據自己的經驗來找,比如以往蟲子分布的地區,它肯定優先對這部分的地方進行搜索。因此,自己的“認知

”——經驗,也是一個因素。

  (3) 最後,每個鳥寶寶發現自己離蟲子更接近的時候,便會發出信號給同伴,在遇到這樣的信號,其余還在找的鳥寶寶們就會想著,同伴的位置更接近蟲子,我要往它那邊過去看看。我們稱之為“社會共享”,這也是鳥寶寶在移動時考慮的一個因素。

  綜上所述,鳥寶寶每次在決定下一步移動的速度和方向時,腦子裏是由這三個因素影響的。我們想,如果能夠用一條公式來描述著三個因素的影響的話,那不就能寫出每個鳥寶寶的移動方向和速度麽。但是,每一個鳥寶寶,對這三個因素的考慮都是不一致的,比如對於捕食經驗不高的鳥寶寶,移動的時候會更看重同伴分享的信息,而對於捕食經驗高的鳥寶寶,則更看重自己的經驗。因此,我們的公式,在“認知”和“社會共享”這部分,是具有隨機性的。

3.2 公式表達

  我們的粒子群算法是這樣的:

  (1) 每一個鳥寶寶,都是我們的,稱之為“粒子”,而我們的蟲子,就是我們問題的最優解。也就是說,鳥寶寶捕食過程,也就是所有的粒子在解空間內尋找到最優解的過程。

  (2) 每一個粒子,都由一個fitness function來確定fitness value,以此來確定粒子位置的好壞。(這個其實就是模仿鳥寶寶的“經驗”判斷部分,通過fitness function來確定這個位置是不是所謂的貧瘠地或是蟲子可能出現的位置)。

  (3) 每一個粒子被賦予了記憶功能,能夠記憶所搜尋過的最佳位置。

  (4) 每一個粒子都有一個速度以及決定飛行的距離和方向,這個根據它本身的飛行經驗和同伴共享的信息所決定。

  現在,在d維空間中,有n個粒子。其中:

  粒子i的位置:

$X_{i} = (x_{i1}, x_{i2}, \cdot \cdot \cdot, x_{id})$

  粒子i的速度:

$V_{i} = (v_{i1}, v_{i2}, \cdot \cdot \cdot, v_{id})$

  粒子i所搜尋到的最好的位置(personal best):

$Pbest_{id} = (pbest_{i1}, pbest_{i2}, \cdot \cdot \cdot, pbest_{id})$

  種群所經歷的最好的位置(global best):

$Gbest_{d} = (gbest_{1}, gbest_{2}, \cdot \cdot \cdot, gbest_{d})$

  另外,我們要給我們的粒子速度和位置做一個限制,畢竟我們不希望鳥寶寶的速度過快或者以及飛出我們要搜尋的範圍。因此對於每個粒子i,有:

$X_{i} \in [X_{min}, X_{max}]$

$V_{i} \in [V_{min}, V_{max}]$

根據前面的分析,我們可以寫出下面兩條公式:

  • 在d維空間中,粒子i的速度更新公式為:

$V_{i}^{k} = wV_{i}^{k-1}+c_{1}rand()\left (Pbest_{i} - X_{i}^{k-1} \right ) + c_{2}Rand() \left( Gbest_{i} - X_{i}^{k-1} \right )$

  • 在d維空間中,粒子i的位置更新公式為:

$X_{i}^{k} = X_{id}^{k-1}+ V_{i}^{k-1}$

  在上式中,上標k-1和k表示粒子從k-1次飛行操作到下一次飛行操作的過程。

  (1) 我們先來看看速度更新公式,可以看出包含三部分,分別是我們前面分析的“慣性”、“認知”、“社會共享”這三大塊。而rand()和Rand()分別給“認知”和“社會共享”提供隨機性,即每個粒子對這兩部分的看重是不一樣的。其中c_{1}和c_{2}是我們自己加的,表示我們自己對這兩部分的分量的控制。另外w是一個慣性的權重,是用於調節對解空間的搜索範圍。關於這個w的出現還有一段歷史,大家感興趣的可以去查查論文,這裏就不細講了。

  (2) 接著是位置更新公式,這部分很簡單,我們都知道$x = x_{0} + vt$。可是這裏為什麽少了個$t$呢,這裏我們可以簡單理解為從k-1次飛行到下一次飛行,耗費了一個單位時間$t$,因此就沒有$t$出現了。

  好了,上面那兩個公式就是粒子群算法的核心了。

3.3 算法流程

  (1) Initial:

  初始化粒子群體(群體規模為n),每個粒子的信息包括隨機位置和隨機速度。

  (2) Evaluation

  根據fitness function,算出每個粒子的fitness value。

  (3) Find the Pbest

  對於每個粒子,將其當前的fitness value與歷史最佳的位置(Pbest)所對應的fitness value做比較。若當前的fitness value更高,則將當前的位置更新Pbest。

  (4) Find the Gbest

  對於每個粒子,將其當前的fitness value與群體歷史最佳的位置(Gbest)所對應的fitness value做比較。若當前的fitness value更高,則將當前的位置更新Gbest。

  (5) Update the Velocity and Position:

  根據公式更新每個粒子的速度和位置

  (6) 如果未找到最佳值,則返回步驟2。(若達到了最佳叠代數量或者最佳fitness value的增量小於給定的閾值,則停止算法)

四、粒子群算法Matlab代碼示例

4.1 利用粒子群算法計算一元函數的最大值

%% 題目1:利用粒子群算法計算一元函數的最大值

%% I. 清空環境
clc
clear all

%% II. 繪制目標函數曲線圖
x = 1: 0.01: 2;
y = sin(10*pi*x) ./ x;
figure
plot(x, y)
hold on

%% III. 參數初始化
c1 = 1.49445;
c2 = 1.49445;

maxgen = 50;                                        % 進化次數(叠代次數)  
sizepop = 10;                                       % 種群規模(粒子數數目)
dimension = 1;                                      % 這裏因為是一元函數的求解,即一維,故列數為1
% 速度的邊界
Vmax = 0.5;
Vmin = -0.5;
% 種群的邊界
popmax = 2;
popmin = 1;
% 用於計算慣性權重,經驗值
ws = 0.9;
we = 0.4;

% 給矩陣預分配內存
pop = zeros(sizepop, dimension);
V = zeros(sizepop, dimension);
fitness = zeros(sizepop, 1);
yy = zeros(maxgen);
w = zeros(maxgen);
%% IV. 產生初始粒子和速度
for i = 1: sizepop
    % 隨機產生一個種群
    pop(i, :) = (rands(1) + 1) / 2 + 1;             % 初始種群
    V(i, :) = 0.5 * rands(1);                       % 初始化速度
    % 計算適應度
    fitness(i) = fun(pop(i, :));   
end

%% V. 初始化Personal best和Global best
[bestfitness, bestindex] = max(fitness);
gbest = pop(bestindex,:);                           % Global best
pbest = pop;                                        % 一開始的個體數據都是最佳的
fitnesspbest = fitness;                             % 個體最佳適應度值
fitnessgbest = bestfitness;                         % 全局最佳適應度值

%% VI. 叠代尋優
for i = 1: maxgen                                   % 叠代循環
    w(i) = ws - (ws - we) * (i / maxgen);           % 讓慣性權重隨著叠代次數而動態改變,控制搜索精度
    for j = 1: sizepop                              % 遍歷所有粒子
        % 速度更新
        V(j, :) = w(i)*V(j, :) + c1*rand*(pbest(j, :) - pop(j, :)) + c2*rand*(gbest - pop(j, :));
        if V(j, :) > Vmax
            V(j, :) = Vmax;
        end
        if V(j, :) < Vmin
            V(j, :) = Vmin;
        end
        
        % 種群更新(位置更新)
        pop(j, :) = pop(j, :) + V(j, :);
        if pop(j, :) > popmax
            pop(j, :) = popmax;
        end
        if pop(j, :) < popmin
            pop(j, :) = popmin;
        end
        
        % 適應度值更新
        fitness(j) = fun(pop(j, :)); 
    end
    
    for j = 1: sizepop    
        % 個體最優更新
        if fitness(j) > fitnesspbest(j)
            pbest(j, :) = pop(j, :);
            fitnesspbest(j) = fitness(j);
        end
        
        %群體最優更新
        if fitness(j) > fitnessgbest
            gbest = pop(j, :);
            fitnessgbest = fitness(j);
        end
    end 
    yy(i) = fitnessgbest;                               % 記錄每次叠代完畢的群體最優解
end

%% VII. 輸出結果並繪圖
[fitnessgbest gbest]                                    % 輸出數據
figure
plot(yy)
title(‘最優個體適應度‘, ‘fontsize‘,12);
xlabel(‘進化代數‘, ‘fontsize‘, 12);
ylabel(‘適應度‘, ‘fontsize‘,12);

  其中,適應值函數被封裝到fun.m中,如下:

function y = fun(x)
% 函數用於計算粒子適應度值
%x           input           輸入粒子 
%y           output          粒子適應度值 
y = sin(10 * pi * x) / x;

  運行上述代碼,得到的數據和圖如下:

ans =
    0.9528    1.0490

技術分享圖片

  可以看到,紅點處正是我們函數的最大值處。

4.2 利用粒子群算法計算二元函數的最大值

%% 題目2: 利用粒子群算法計算二元函數的最大值

%% I. 清空環境
clc
clear

%% II. 繪制目標函數曲線
figure
[x, y] = meshgrid(-5: 0.1: 5, -5: 0.1: 5);
z = x.^2 + y.^2 - 10*cos(2*pi*x) - 10*cos(2*pi*y) + 20;
mesh(x,y,z)
hold on


%% III. 參數初始化
c1 = 1.49445;
c2 = 1.49445;

maxgen = 1000;                                                  % 進化次數  
sizepop = 100;                                                  % 種群規模
dimension = 2;                                                  % 這裏因為是二元函數的求解,即二維,故列數為2

% 速度的邊界
Vmax = 1;
Vmin = -1;
% 種群的邊界
popmax = 5;
popmin = -5;
% 用於計算慣性權重,經驗值
ws = 0.9;
we = 0.4;

% 給矩陣預分配內存
pop = zeros(sizepop, dimension);
V = zeros(sizepop, dimension);
fitness = zeros(sizepop, 1);
yy = zeros(maxgen);
w = zeros(maxgen);
%% IV. 產生初始粒子和速度
for i = 1: sizepop
    % 隨機產生一個種群
    pop(i, :) = 5 * rands(1, 2);                                % 初始種群
    V(i, :) = rands(1, 2);                                      % 初始化速度
    % 計算適應度
    fitness(i) = fun(pop(i, :));
end

%% V. 初始化Personal best和Global best
[bestfitness, bestindex] = max(fitness);
gbest = pop(bestindex, :);                                      % Global best
pbest = pop;                                                    % 個體最佳
fitnesspbest = fitness;                                         % 個體最佳適應度值
fitnessgbest = bestfitness;                                     % 全局最佳適應度值

%% VI. 叠代尋優
for i = 1: maxgen
    w(i) = ws - (ws - we) * (i / maxgen);                       % 讓慣性權重隨著叠代次數而動態改變,控制搜索精度    
    for j = 1: sizepop
        % 速度更新
        V(j, :) = w(i)*V(j, :) + c1*rand*(pbest(j, :) - pop(j, :)) + c2*rand*(gbest - pop(j, :));
        for k = 1: dimension
            if V(j, k) > Vmax
                V(j, k) = Vmax;
            end
            if V(j, k) < Vmin
                    V(j, k) = Vmin;
            end
        end
        
        % 種群更新(位置更新)
        pop(j, :) = pop(j, :) + V(j, :);
        for k = 1: dimension
            if pop(j, k) > popmax
                pop(j, k) = popmax;
            end
            if pop(j, k) < popmin
                pop(j, k) = popmin;
            end
        end
        % 適應度值更新
        fitness(j) = fun(pop(j, :)); 
    end
    
    for j = 1: sizepop    
        % 個體最優更新
        if fitness(j) > fitnesspbest(j)
            pbest(j, :) = pop(j, :);
            fitnesspbest(j) = fitness(j);
        end
        
        %群體最優更新
        if fitness(j) > fitnessgbest
            gbest = pop(j, :);
            fitnessgbest = fitness(j);
        end
    end 
    yy(i) = fitnessgbest;                                           % 記錄每次叠代完畢的群體最優解
end
%% VII.輸出結果
[fitnessgbest, gbest]
plot3(gbest(1), gbest(2), fitnessgbest, ‘bo‘,‘linewidth‘, 1.5)

figure
plot(yy)
title(‘最優個體適應度‘, ‘fontsize‘, 12);
xlabel(‘進化代數‘, ‘fontsize‘, 12);
ylabel(‘適應度‘, ‘fontsize‘, 12);

  其中,適應值函數被封裝到fun.m中,如下:

function y = fun(x)
%函數用於計算粒子適應度值
%x           input           輸入粒子 
%y           output          粒子適應度值 
y = x(1).^2 + x(2).^2 - 10*cos(2*pi*x(1)) - 10*cos(2*pi*x(2)) + 20;

  運行上述代碼,得到的數據和圖如下:

ans =
   80.7066    4.5230    4.5230

技術分享圖片

  可以看到,圖中標註的地方是我們求得的最大值處。其實我們知道,對於這個函數,因為是對稱的,所以4個點都是同樣的最大值,這就是粒子群算法的缺點了。很容易陷入局部最優解。因為我們的粒子群算法其實並不知道什麽是最優解,它只是讓粒子不斷的找一個相對之前所有的解都是最好的一個解。所以,這樣的粒子群算法是有局限性的,用的時候要根據場合來選擇。

數學建模方法-粒子群算法