树种优化算法(Tree seed algorithm(TSA)) 原理+代码(逐字逐句)+思考 保姆级教程

一,介绍:

TSA树种优化算法(TSA),是一种新型的演化算法,该算法是模拟大树通过种子进行繁衍的过程。Kiran在2015年提出了TSA算法。以下就是套话,该算法的收敛速度快,收敛精度高,等等....这几乎是每一种新型的优化算法提出来都会说的。

但是TSA相对于传统的GA,PSO和新型的WOA等算法相比确实有一些优势,这个后面会提到。

二,流程

先贴一张论文中给出的流程图

感觉有点困难?没关系,下面开始逐字逐句的讲解:

  1. 初始化种群及相关参数:
    种群中的个数(N),
    种群中个体的维度(D),
    进化方式的概率(ST(现在看不懂没关系,后面马上会提及)),
    设置终止条件(这里的终止条件和其他的进化算法不同,不是通过迭代次数来控制结束的)。

    生成随机个体,生成方式为:T_{i,j} = L_{j,min} + r_{i,j}(H_{j,max} - L_{j,min}),
    按照这种方法就生成N组个体
  2. 设置适应度函数,求出对应的适应值,挑选出适应度值最小的个体:B = min(f(\vec{T}_i))) i = 1,2...N
  3. For 所有的树:
    1. 决定当前的树产生多少种子(这里有一套规则,后面会讲解)
    2. For 所有的种子
      1. For 所有的维度
        1. IF rand < ST(之前设置的一个参数):
          1. S_{i,j} = iw * T_{i,j} + \alpha_{i,j} *(B_j - T_{r,j})(S为种子的个体,T为树的个体,alpha为提前设置的参数,i为当前的种子,j 为当前维度,B为当前记录最好的个体,r为随机数)
        2. ELSE
          1. S_{i,j} = iw * T_{i,j} + \alpha_{i,j} *(T_{i,j} - T_{r,j})(S为种子的个体,T为树的个体,alpha为提前设置的参数,i为当前的种子,j 为当前维度
    3. 选择最优的种子,如果这个种子的适应度优于当前的树,则替代当前的树
  4. 所有的树迭代完之后,挑选最优的个体。如果该最优个体优于B,则进行替换
  5. 看是否达到终止条件(这里的终止条件不是迭代次数,而是看产生的种子个数是否达到一定的量,在代码中会详细的讲到),如果未达到终止条件,则返回第二步
  6. 输出最优个体

整个流程还是相当简单的,TSA的算法的收敛效果也确实比较优秀。

三,代码(matlab)

  一,matlab代码

function [minimum,bestParams]=TSA(iw,maxrun,N,D,ST,maxFEs,dmin,dmax,func_num)

iterdosyaadi=strcat('F',num2str(func_num),'_IW',num2str(iw*10),'_N',num2str(N),'_D',num2str(D),'_',num2str(maxFEs),'_iters');
dosyaadi=strcat('F',num2str(func_num),'_IW',num2str(iw*10),'_N',num2str(N),'_D',num2str(D),'_',num2str(maxFEs));

% low和high是控制每一代树的产生的种子的上限和下限
low=ceil(N*0.1);
high=ceil(N*0.25);

iterasyonlar=zeros(maxrun,maxFEs);

for run=1:maxrun
    % 重复的次数
    rand('state',sum(100*clock));
    trees=zeros(N,D);
    obj_trees=zeros(1,N);
    
    % 初始化个体
    for i=1:N
        for j=1:D
            trees(i,j)=dmin+(dmax-dmin)*rand;
        end;
        obj_trees(i)=bildiriseti(trees(i,:),func_num);
    end
    FEs = N;
    
    [minimum]=min(obj_trees);
    mins=zeros(1,maxFEs);
    iter=0;
    while(FEs<=maxFEs)
        %% 相当于是挑选选中的树木,对数目产生的seed进行处理
        iter=iter+1;
        %% 对种群中的每一颗树进行遍历
        for i=1:N
            ns=fix(low+(high-low)*rand)+1;
            FEs = FEs + ns;  
            if(ns>high)
                ns=high;
            end;
            
            seeds=zeros(ns,D);
            obj_seeds=zeros(1,ns);
            
            [minimum,min_indis]=min(obj_trees);
            bestParams=trees(min_indis,:);
            %% 对每一颗树产生种子进行更新
            for j=1:ns
                komsu=fix(rand*N)+1;
                while(i==komsu) % 选中的种子不能和当前的树相同
                    komsu=fix(rand*N)+1;
                end
                seeds(j,:)=trees(j,:);% 将这个树的直接赋值给这个种子
                for d=1:D
                    if(rand<ST)
                        seeds(j,d)=iw*trees(i,d)+(bestParams(d)-trees(komsu,d))*(rand-0.5)*2;
                        %在这里可以看出seeds的特点,种群的每一维度在更新的时候不收影响
                        if(seeds(j,d)>dmax)
                            seeds(j,d)=dmax;
                        end;
                        if(seeds(j,d)<dmin)
                            seeds(j,d)=dmin;
                        end;
                    else
                        seeds(j,d)=iw*trees(i,d)+(trees(i,d)-trees(komsu,d))*(rand-0.5)*2;
                        if(seeds(j,d)>dmax)
                            seeds(j,d)=dmax;
                        end;
                        if(seeds(j,d)<dmin)
                            seeds(j,d)=dmin;
                        end;
                    end;
                end;
                obj_seeds(j)=bildiriseti(seeds(j,:),func_num);
                
            end;
            
            [mintohum,mintohum_indis]=min(obj_seeds);
            if(mintohum<obj_trees(i))
                trees(i,:)=seeds(mintohum_indis,:);
                obj_trees(i)=mintohum;                
            end;
        end;        
             
        
        [min_tree,min_tree_index]=min(obj_trees);
        if(min_tree<minimum)
            minimum=min_tree;
            bestParams=trees(min_tree_index,:);
        end;
        iterasyonlar(run,iter)=minimum;
        save(iterdosyaadi,'iterasyonlar');
        fprintf('Iter=%d .... min=%g .... FES=%d .... \n',iter,minimum,FEs);
    end;
    fprintf('Run=%d .... min=%g ....\n',run,minimum);
    dosya(run,1)=minimum;
end;
dosya(maxrun+1,1)=mean(dosya(1:maxrun,1));
dosya(maxrun+1,2)=std(dosya(1:maxrun,1));
dosya(maxrun+1,3)=median(dosya(1:maxrun,1));
dosya(maxrun+1,4)=min(dosya(1:maxrun,1));
dosya(maxrun+1,5)=max(dosya(1:maxrun,1));
save(dosyaadi,'dosya');
end

参数讲解:

iw:种子更新时,位于T_{i,j}的系数
maxrun: 算法执行的重复次数(这个不是迭代次数,也不是终止条件)
N:种群的大小                   D:个体的维度
maxFEs :在这里,设置maxFEs = D * 10000。这里就是真正的中止条件,所有在树的迭代过程中,产生的种子数如果达到了maxFEs,则停止产生,中止迭代
dmin,dmax:维度的限制

在代码中变量均已经做出相关的解释。

二,python代码

import numpy as np


def func(x):
    return np.sum(x ** 2)


def TSA(iw, maxrun, N, D, ST, maxFEs, dmin, dmax):
    low = int(N * 0.1)
    high = int(N * 0.25)

    iterasyonlar = np.zeros((maxrun, maxFEs))  # 存放每一个重复的循环下,种子的适应度
    dosya = np.zeros((maxrun, 1))
    for run in range(maxrun):
        np.random.seed(0)
        # 重复的次数
        trees = np.zeros((N, D))
        obj_trees = np.zeros((N, 1))  # 存放每个个体的目标值

        for i in range(N):
            for j in range(D):
                trees[i, j] = dmin + np.random.rand() * (dmax - dmin)
            obj_trees[i] = func(trees[i, :])
        FEs = N  # 因为当前已经产生了N个个体

        minimum = np.min(obj_trees)
        iter1 = 0

        while (FEs <= maxFEs):
            iter1 = iter1 + 1
            for i in range(N):
                # i是树木
                ns = int(low + (high - low) * np.random.rand()) + 1
                FEs = FEs + ns
                if ns > high:
                    ns = high

                seeds = np.zeros((ns, D))  # 记录当前的种子的具体形式
                obj_seeds = np.zeros((ns, 1))
                minimum, min_index = np.min(obj_trees), np.argmin(obj_trees)
                bestParams = trees[min_index, :]

                for j in range(ns):
                    # j 是种子
                    komus = int(np.random.rand() * N) + 1
                    while komus == i or komus >=N or komus < 0 :
                        komus = int(np.random.rand() * N) + 1
                    seeds[j, :] = trees[j, :]

                    for d in range(D):
                        if np.random.rand() < ST:
                            seeds[j, d] = iw * trees[i, d] + (bestParams[d] - trees[komus, d]) * (
                                        np.random.rand() - 0.5) * 2
                            if seeds[j, d] > dmax:
                                seeds[j, d] = dmax
                            if seeds[j, d] < dmin:
                                seeds[j, d] = dmin
                        else:
                            seeds[j, d] = iw * trees[i, d] + (trees[i, d] - trees[komus, d]) * (
                                        np.random.rand() - 0.5) * 2
                            if seeds[j, d] > dmax:
                                seeds[j, d] = dmax
                            if seeds[j, d] < dmin:
                                seeds[j, d] = dmin
                    obj_seeds[j] = func(seeds[j, :])

                mini_seeds, mini_seeds_ind = np.min(obj_seeds), np.argmin(obj_seeds)

                if mini_seeds < obj_trees[i]:
                    trees[i, :] = seeds[mini_seeds_ind, :]
                    obj_trees[i] = mini_seeds

            min_tree, min_tree_index = np.min(obj_trees), np.argmin(obj_trees)
            if min_tree < minimum:
                minimum = min_tree
                bestParams = trees[min_tree_index, :]

            iterasyonlar[run, iter1] = minimum
            print('Iter={} .... min={} .... FES={} .... \n'.format(iter1, minimum, FEs))

        print('Run={} .... min={} ....\n'.format(run, minimum))
        dosya[run] = minimum

    print(dosya)
    return np.min(dosya), bestParams

TSA(1,30,10,10,0.1,10*10000,-10,10)

代码流程和matlab的流程差不多,不做赘述。

思考:

TSA本身的有点很明显:在处理个体的不同维度时,它可以做到维度之间相互独立。什么意思呢?就比如我在做一个优化问题时,要求第1维的单位为1,范围在[-10,10],第2维的精度为0.00001,范围为[0.1,0.00001]。以GA为例,在处理时存在交叉等操作,就会导致不同维度之间产生干扰,需要设计更加复杂的编码方式。

                

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值