免疫算法源于生物免疫系统的基本机制, 是一种具有生成+检测的迭代过程的群智能搜索算法.
生物免疫系统的运行机制和遗传算法的求解有很高的相似度. 在抵御抗原时, 免疫细胞增殖分化, 进而产生大量抗体. 倘若将所求的目标函数和约束条件视为抗原, 将问题的解视作抗体, 那么遗传算法求解的过程就是生物免疫系统抵御抗原的过程.
免疫算法的基本思想是在传统遗传算法的基础上加入一个免疫算子, 从而防止出现种群退化的现象. 免疫算子由 接种疫苗 和 免疫选择 组成.
免疫算法解决了遗传算法的早熟收敛问题, 该问题一般出现在实际工程优化计算中. 遗传算法的交叉和变异算子本身是具有一定的盲目性的. 若在遗传算法中引入"免疫"的方法和概念, 对遗传算法全局搜索的过程进行一定强度的干预, 就可以避免很多重复无效的操作, 从而提高算法效率.
在免疫算法中, 合理提取"疫苗"是算法的核心. 免疫算法还可以针对群体进化过程中的一些退化现象进行抑制, 从而更加稳定地提高群体适应度.
一般而言, 免疫算法可分为三种情况:
免疫算法和遗传算法的结构基本一致, 最大的差异之处在于, 免疫算法中引入了 “浓度调节机制”:
进行选择操作时, 遗传算法只利用适应度值单一指标对个体进行评价, 在免疫算法中则改为: 适应度越高且浓度越小, 个体被选择的概率越大, 适应度越低且浓度越高的个体被选择的概率越小.
免疫算法主要步骤如下:
抗原识别:
将所求的目标函数和约束条件当作抗原进行"识别",来判断是否曾经解决过类似问题.
生成初始抗体:
这一步对应于遗传算法就是得到解的初始值. 经过对抗原的识别这一步骤, 如果算法曾经解决过这类问题, 则直接寻找相应的"记忆细胞", 从而产生初始抗体.
更新记忆单元:
选择亲和度更高的抗体进行存储记忆.
抑制和促进抗体:
在算法中插入新的策略以避免群体进化单一的现象, 保持群体的多样性.
遗传操作:
在考虑抗体亲和度和群体多样性的基础上选择抗体群体, 进行交叉编译, 产生新一代抗体.
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
[注]
阈值分割法适用于目标和背景灰度有较强对比的情况, 尤其是背景或物体的灰度较为单一, 且总可得到封闭且连同区域的边界. 否则, 图片经过阈值分割后的前后对比效果不会非常强烈.