免疫算法
免疫算法源於生物免疫系統的基本機制, 是一種具有生成+檢測的迭代過程的羣智能搜索算法.
生物免疫系統的運行機制和遺傳算法的求解有很高的相似度. 在抵禦抗原時, 免疫細胞增殖分化, 進而產生大量抗體. 倘若將所求的目標函數和約束條件視爲抗原, 將問題的解視作抗體, 那麼遺傳算法求解的過程就是生物免疫系統抵禦抗原的過程.
1. 基本原理
免疫算法的基本思想是在傳統遺傳算法的基礎上加入一個免疫算子, 從而防止出現種羣退化的現象. 免疫算子由 接種疫苗 和 免疫選擇 組成.
免疫算法解決了遺傳算法的早熟收斂問題, 該問題一般出現在實際工程優化計算中. 遺傳算法的交叉和變異算子本身是具有一定的盲目性的. 若在遺傳算法中引入"免疫"的方法和概念, 對遺傳算法全局搜索的過程進行一定強度的干預, 就可以避免很多重複無效的操作, 從而提高算法效率.
在免疫算法中, 合理提取"疫苗"是算法的核心. 免疫算法還可以針對羣體進化過程中的一些退化現象進行抑制, 從而更加穩定地提高羣體適應度.
一般而言, 免疫算法可分爲三種情況:
- 模仿免疫系統抗原抗體識別, 結合抗體生成過程抽象而得到的免疫算法
- 基於免疫系統中其餘特殊機制抽象出的算法, 如 克隆選擇算法.
- 與遺傳算法等其餘算法融合產生的新算法, 如 免疫遺傳算法.
2. 程序設計
免疫算法和遺傳算法的結構基本一致, 最大的差異之處在於, 免疫算法中引入了 “濃度調節機制”:
進行選擇操作時, 遺傳算法只利用適應度值單一指標對個體進行評價, 在免疫算法中則改爲: 適應度越高且濃度越小, 個體被選擇的概率越大, 適應度越低且濃度越高的個體被選擇的概率越小.
2.1 免疫算法的步驟流程
免疫算法主要步驟如下:
-
抗原識別:
將所求的目標函數和約束條件當作抗原進行"識別",來判斷是否曾經解決過類似問題. -
生成初始抗體:
這一步對應於遺傳算法就是得到解的初始值. 經過對抗原的識別這一步驟, 如果算法曾經解決過這類問題, 則直接尋找相應的"記憶細胞", 從而產生初始抗體. -
更新記憶單元:
選擇親和度更高的抗體進行存儲記憶. -
抑制和促進抗體:
在算法中插入新的策略以避免羣體進化單一的現象, 保持羣體的多樣性. -
遺傳操作:
在考慮抗體親和度和羣體多樣性的基礎上選擇抗體羣體, 進行交叉編譯, 產生新一代抗體.
2.2 在MATLAB中實現免疫算法
MATLAB是一門基於矩陣的科學計算語言, 具有強大的處理矩陣運算的功能, 因此它很適合用於實現免疫算法.
免疫算法中的標準遺傳操作: 選擇, 交叉, 變異, 基於生物免疫機制的免疫記憶, 多樣性保存, 自我調節功能等均是針對抗體 (即遺傳算法中所指的染色體, 個體) 的. 抗體就可以很方便地用行向量表示. 因此, 在MATLAB實現的免疫算法中, 上述操作和功能均是由矩陣運算實現的.
[例] 設計一個免疫算法, 實現對下圖所示單閾值圖像的分割, 並畫圖比較分割前後圖片的結果.
- 主程序:
clc; clear all;
tic
popsize = 15;
lanti = 10;
maxgen =50; %最大迭代次數
cross_rate = 0.4; %交叉概率
mutation_rate = 0.1; %變異概率
a0 = 0.7;
zpopsize = 5;
bestf = 0;
nf = 0;
number = 0;
I = imread('esu.bmp');
q = isrgb(I); %判斷是否爲RGB真彩色圖像
if q == 1
I = rgb2gray(I); %轉換爲灰度圖像
end
[m,n] = size(I);
p = imhist(I); %顯示圖像數據直方圖
p = p'; %轉置
p = p/(m*n); %圓整p,將其值變爲(0,1)
figure(1)
subplot(1,2,1);
imshow(I);
title('Original Grayscale Image');
hold on
%% 抗原羣體初始化
pop = 2*rand(popsize,lanti)-1; %pop爲每個元素值在(-1,1)之間的隨機陣
pop = hardlim(pop); %將圖像單閾值化,元素大於等於0轉換爲1,其餘的轉爲0
%% 進行免疫操作
for gen = 1:maxgen
[fitness,threshould,number] = fitnessty(pop,lanti,I,popsize,m,n,number);
%計算抗原-抗體親和度
if max(fitness) > bestf
bestf = max(fitness);
nf = 0;
for i = 1:popsize
if fitness(1,i) == bestf
v = i;
end
end
yu = threshould(1,v);
elseif max(fitness) == bestf
nf = nf + 1;
end
if nf >= 20
break;
end
A = shontt(pop); %計算抗體-抗體的相似度
f = fit(A,fitness); %計算抗體的聚合適應度
pop = select(A,fitness); %進行選擇操作
pop = cross(pop,cross_rate,popsize,lanti); %交叉
pop = mutation_compute(pop,mutation_rate,lanti,popsize); %變異
a = shonqt(pop); %計算抗體羣體相似度
if a > a0
zpop = 2*rand(zpopsize,lanti)-1;
zpop = hardlim(zpop);
pop(popsize+1:popsize+zpopsize,:) = zpop(:,:);
[fitness,threshould,number] = fitnessty(pop,lanti,I,popsize,m,n,number);
%計算抗原-抗體親和度
A = shontt(pop); %計算抗體-抗體相似度
f = fit(A,fitness); %計算抗體的聚合適應度
pop = select(A,fitness); %進行選擇操作
end
if gen == maxgen
[fitness,threshould,number] = fitnessty(pop,lanti,I,popsize,m,n,number);
%計算抗原-抗體親和度
end
end
imshow(I);
subplot(1,2,2);
fresult(I,yu);
title('Splited Image');
- 均勻雜交函數
%%均勻雜交函數
function pop = cross(pop,cross_rate,popsize,~)
j = 1;
for i = 1:popsize
p = rand;
if p < cross_rate
parent(j,:) = pop(i,:);
a(1,j) = i;
j = j+1;
end
end
j = j-1;
if rem(j,2)~=0
j = j-1;
end
for i = 1:2:j
p = 2*rand(1,lanti)-1; %隨機生成一個模板
p = hardlim(p);
for k = 1:lanti
if p(1,k) == 1
pop(a(1,j),k) = parent(i+1,k);
pop(a(1,i+1),k) = parent(i,k);
end
end
end
- 抗體聚合適應度計算函數
%%抗體的聚合適應度計算函數
function f = fit(A,fitness)
t = 0.8;
[~,m] = size(A);
k = -0.8;
for i = 1:m
n = 0;
for j = 1:m
if A(i,j) > t
n = n+1;
end
C(1,i) = n/m; %計算抗體濃度
end
end
f = fitness.*exp(k.*C); %抗體的聚合適應度
- 適應度計算函數
%%適應度計算函數
function [fitness,b,number] = fitnessty(pop,lanti,I,popsize,m,n,number)
num = m*n;
for i = 1:popsize
number = number + 1;
anti = pop(i,:);
lowsum = 0; %低於閾值的灰度值之和
lownum = 0; %低於閾值的像素點個數
highsum = 0; %高於閾值的灰度值之和
highnum = 0; %高於閾值的像素點個數
a = 0;
for j = 1:lanti
a = a + anti(i,j) * (2^(j-1)); %加權求和
end
b(1,i) = a * 255/(2^lanti - 1);
for x = 1:m
for y = 1:n
if I(x,y) < b(1,i)
lowsum = lowsum + double(I(x,y));
lownum = lownum + 1;
else
highsum =highsum + double(I(x,y));
highnum = highnum + 1;
end
end
end
u = (lowsum + highsum)/num;
if lownum~ = 0;
u0 = lowsum/lownum;
else
u0 = 0;
end
if hoighnum~=0
u1 = highsum/highnum;
else
u1 = 0;
end
w0 = lownum/(num);
w1 = highnum/(num);
fitness(1,i) = w0*(u0-u)^2 + w1*(u1-u)^2;
end
end
- 圖像分割輸出函數
%% 根據最佳閾值進行圖像分割,輸出結果
function fresult(I,f,m,n)
[m,n] = size(I);
for i = 1:m
for j = 1:n
if I(i,j) <= f
I(i,j) = 0;
else
I(i,j) = 255;
end
end
end
imshow(I);
- 圖像判斷函數
%% 判斷圖像是否爲RGB真彩色
function y = isrgb(x)
wid = sprintf('Images: %s:obsoleteFunction',mfilename);
str1 = sprintf('% s is pbsolete and may be removed in the future',mfilename);
str2 = 'See product release notes for more information.';
warning(wid,'%s\n%s',str1,str2);
y = size(x,3) == 3;
if y
if isa(x,'logical')
y = false
elseif isa(x,'double')
m = size(x,1);
n = size(x,2);
chunk = x(1:min(m,10),1:min(n,10),:);
y = (min(chunk(:)) >= 0 && max(chunk(:)) <= 1);
if y
y = (min(x(:)) >= 0 && max(x(:)) <= 1);
end
end
end
- 變異算子
%% 變異算子
function pop = mutation_compute(pop,mutation_rate,lanti,popsize)%均勻變異
for i = 1:popsize
s = rand(1,lanti);
for j = 1:lanti
if s(1,j) < mutation_rate
if pop(i,j) == 1
pop(i,j) = 0;
else
pop(i,j) = 1;
end
end
end
end
- 選擇算子
%選擇算子
function v = select(v,fit)
[px,~] =size(v);
for i = 1:px
pfit(i) = fit(i) ./ sum(fit);
end
pfit = cumsum(pfit);
if pfit(px) < 1
pfit(px) = 1;
end
rs = rand(1,10);
for i = 1:10
ss = 0;
for j = 1:px
if rs(i) <= pfit(j)
v(i,:) = v(j,:);
ss = 1;
end
if ss == 1
break;
end
end
end
- 羣體相似度計算函數
%%計算羣體相似度
function a = shonqt(pop)
[m,n] = size(pop);
h = 0;
for i = 1:n
s = sum(pop(:,i));
if s == 0 || s == m
h = h;
else
h = h - s/m * log2(s/m) - (m-s)/m * log2((m-s)/m);
end
end
a = 1/(1+h);
- 抗體相似度計算函數
%%計算抗體相似度函數
function A = shontt(pop)
[m,n] = size(pop);
for i = 1:m
for j = 1:m
if 1 == j
A(i,j) = 1;
else
H(i,j) = 0;
for k = 1:n
if pop(i,k) ~= pop(j,k)
H(i,j) = H(i,j) + 1;
end
end
H(i,j) = H(i,j)/n;
A(i,j) = 1/(1 + H(i,j));
end
end
end
程序模擬輸入輸出如下:
[注]
閾值分割法適用於目標和背景灰度有較強對比的情況, 尤其是背景或物體的灰度較爲單一, 且總可得到封閉且連同區域的邊界. 否則, 圖片經過閾值分割後的前後對比效果不會非常強烈.