TSP问题蚁群算法详细解读与python实现

写在前面

蚁群算法是一种求解NPC问题的启发式算法,属于仿生进化算法族的一员。仿生进化算法是受生物行为启发而发明的智能优化算法,往往是人们发现某种生物的个体虽然行为较为简单,但生物集群通过某种原理却能表现出智能行为。于是不同的人研究不同的生物行为原理,受到启发而发明出新的仿生进化算法。比如免疫优化算法,遗传算法,模拟退火算法等。遗传算法详解与Python实现在上一篇博客里已经介绍,蚁群算法与遗传算法等仿生进化算法均有共通之处,读者只需要明白透彻其中一种算法的原理和细节,便能触类旁通。因此,今天介绍的是蚁群算法,作为余兴节目,会在最后简单介绍类似的仿生进化算法:模拟退火算法和免疫优化算法。
蚁群算法的名字揭示了算法的起源。人们发现,单个蚂蚁的行为较为简单,但蚁群聚集在一起,却总能通过某种方式,在众多食物源与巢穴之间寻找到最优路径。于是人们研究了这一现象的原理,发现蚂蚁会在运动轨迹上留下信息素,并且路径越短,留下的信息素便越浓。信息素能吸引更多的蚂蚁在路径上运动,从而形成正反馈调节,最后越来越多的蚂蚁聚集在了较短的路径上。基于此,发明了蚁群算法,并将其用于TSP等优化问题上。

蚁群算法解TSP问题原理

一、TSP问题

旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
想要求解出TSP问题的最优解,目前唯一的方法是穷举出所有的路径。然而,路径的数量级是n!,也就是目标点数量的阶乘。当n为14时,n!已经大于800亿。当n更大,为30,40 时,更是天文数字,即使计算机一秒钟计算一亿次,其求解时间也远大于我们的寿命。因此,穷举法解TSP问题根本不可行,需要别的启发式算法来代替。

二、蚁群算法解TSP原理

2.1 现状简介

笔者在公司业务上遇到了TSP问题,因此将所有的仿生进化优化算法都过了一遍。在学习这些算法的时候,笔者发现现有资料的解释大多有些晦涩,高深莫测。往往上来就是一些不明就里的专有名词:信息素启发因子,衰减因子等。对于我这样的初学者来说有点不知所云,于是不得不直接看源码,一行一行地理解代码的意思,才弄懂了原理。这种方法对于初学者和编程基础薄弱者颇为困难,而且费时费力,苦不堪言。同时,由于读者可能熟练掌握的是不同的语言,因此若代码是某一种语言编写的,那么掌握其他语言的读者很可能难以吸收,浪费了资源。因此,本文旨在用通俗详尽的语言深入浅出地解释蚁群算法解TSP问题的原理及应用。

2.2 TSP问题重述

对于TSP问题,我们拿到的是n个目标点的坐标,作为例子,我们视为面对的是n=10个城市。有了坐标,我们便可以计算出n个城市之间的距离,得到一个n*n的矩阵,这个矩阵表示的是城市之间两两连接形成的无向图,边的权重是城市之间的距离,而TSP问题则是从图中找出一个包含所有城市的最小的环。

2.3 种群初始化

蚁群算法的初始化与其他仿生进化算法类似,其实就是一个长度为n=10的包含1~n(这个例子里为10)且不含重复元素的序列,其意义就是一只蚂蚁从某个点出发,随机访问下一个未访问过的城市,直到所有的城市都访问完毕,这只蚂蚁再从最后一个城市返回出发城市。蚂蚁的轨迹就是一个包含了所有城市且没有重复访问的环。种群数量设为M,那么该种群初始化的意义就是M只蚂蚁独立、随机、不重复地访问一遍各个城市,单个个体轨迹构成一个环。

2.4 信息素播撒

我们以10个城市,种群(蚂蚁)数量为30为例,让我们再熟悉下现在的情形:30只蚂蚁被随机散步到30个城市里的某一个,有的城市被分配了多于一只蚂蚁,而有的城市没有蚂蚁。这些蚂蚁从起点出发,随机但不重复地选择前往下一个城市,遍历完10个城市之后,回到出发点,形成回路。值得一提的是,对于10个城市(或者说目标点),其中任意两个城市之间可能有多只蚂蚁途经,也可能从来没有一只蚂蚁在这两座城市之间直接行走过,而是途经了其他中间城市。
对于每一个单只蚂蚁,都形成了一条回路,并且这些回路是随机不重复游走形成的。这些回路随机生成的,但路径距离之间总是有长有短的。设一只蚂蚁访问的路径序列为向量 x x x,那么该序列的路径长度便是 d ( x ) d(x) d(x)
重点来了,信息素播撒:在每轮游走中,所有蚂蚁播撒的信息素量均为常数Q,因此,若单只蚂蚁本轮的访问序列为 x x x,那么这只蚂蚁本轮在其路径上留下的信息素浓度为 Q Q Q/ d ( x ) d(x) d(x)。蚂蚁的环路径越短,其留下的信息素浓度就越浓。
因此,城市之间的信息素浓度取决于两点:1.两个城市之间通过的蚂蚁数;2.这些蚂蚁的环路径长度。再次啰嗦提醒:有的城市之间有多只蚂蚁经过,有多轮信息素叠加;而有的城市之间可能没有蚂蚁直接经过,没有信息素。

2.5 后续迭代中蚂蚁访问路径的选择

这一步骤是蚁群算法的关键。在随后的迭代中,每只蚂蚁从各自的起点城市出发,按如下策略选择下一个前往的城市:蚂蚁将从未访问过的所有城市中按轮盘赌的方式选择一个城市前往。设蚂蚁现在在城市A,未访问过的城市nextcity_set为{B,C,D,E};每个城市的轮盘概率按如下公式决定: p r o b ( A , n e x t c i t y ) = p h e r o m o n e ( A , n e x t c i t y ) β / d ( A , n e x t c i t y ) α prob(A,nextcity)=pheromone(A,nextcity)^{\beta}/d(A,nextcity)^{\alpha} prob(A,nextcity)=pheromone(A,nextcity)β/d(A,nextcity)α
其中 α \alpha α β \beta β是人工指定的常数超参数。观察该公式可知,备选城市与现在蚂蚁所在城市之间的信息素浓度越大,城市被选择的概率越大;备选城市与现在蚂蚁所在城市之间的距离越大,备选城市被选择的概率越小。距离是已知的,所有城市之间的信息素浓度也由上一轮迭代之后给出, α \alpha α β \beta β是调节距离和信息素浓度影响程度的常数超参数,由人工指定。因此利用上述公式便能得到城市A到城市B,C,D,E的未经归一化的概率。
举个例子,假如根据上述公式得到的prob(A,B),prob(A,C),prob(A,D),prob(A,E)分别为4,3,2,1,那么将B,C,D,E四个城市放到轮盘上,转动一次选出下一个城市。B,C,D,E被选择的概率分别为0.4,0.3,0.2,0.1。
选出下一个城市之后,蚂蚁便前往这座城市。假如这一轮我们轮盘赌选择到了城市C,那么蚂蚁到达D之后,未访问过的城市就变成了B,C,E。随后,蚂蚁将开始新一轮的轮盘赌,计算城市D与B,C,E的访问概率,从B,C,E中用轮盘赌的方式选择出一个城市。假如这轮选到城市B,那么蚂蚁到达城市B之后,还剩下城市C,E。此时再计算城市B与C,E之间的访问概率,进行轮盘赌。不论选择谁,到了最后一轮,蚂蚁只剩下一个未访问城市,直接前往即可。最后,蚂蚁从最后一个城市返回出发点,完成这一轮巡游。至此,蚂蚁的选择策略基本厘清。
值得一提的是,前文中反复强调过,两个城市之间有可能没有蚂蚁直接经过,因此按上述公式算出来起点城市访问其的概率为0。再举个例子,假如现在蚂蚁在城市A,B、C城市与A之间的访问概率为0.8,0.2。而A与D,E之间从未有蚂蚁直接经过,那么蚂蚁怎样选择遍历呢?
蚂蚁将先从有信息素和距离的城市之间以轮盘赌的策略选择,将优先从有信息素的城市之间选择访问。若此刻起始城市与所有备选城市之间都没有信息素,即与所有城市之间的访问概率都为0,那么就随机选择一个城市访问。还是刚才的例子,假如A城市出发到达城市D之后,D与B、C、E之间都没有信息素,那么蚂蚁随机选择B,C,E之间的一个城市访问。假如选择到B,B与C、E之间可能是有信息素的,那么就采用轮盘赌方式选择下一个城市。如果只与其中一个有信息素,那么就选择这个城市访问。若与二者都没有,则随机选择一个访问。至此,蚂蚁的选择访问方式确定了。

2.6 信息素浓度的更新与后续迭代

上述步骤说明了新一轮迭代中蚂蚁的巡游策略,每只蚂蚁的路径仍然是一个不重复的环,只不过路径选择方式由完全随机更换为了信息素与距离指引的随机访问。新一轮巡游之后,每只蚂蚁又在城市之间撒下了浓度为 Q Q Q/ d ( x ) d(x) d(x)的信息素,每个城市之间本轮留下的信息素浓度均可计算出,得到一个n*n的信息素矩阵 p h e r o m o n e _ m a t r i x _ n o w pheromone\_matrix\_now pheromone_matrix_now,其中n为城市数目。
在随后的每一轮迭代中,信息素矩阵(所有城市两两之间的信息素浓度)按以下方式更新:
p h e r o m o n e _ m a t r i x = p h e r o m o n e _ m a t r i x ∗ R H O + p h e r o m o n e _ m a t r i x _ n o w pheromone\_matrix=pheromone\_matrix*RHO+pheromone\_matrix\_now pheromone_matrix=pheromone_matrixRHO+pheromone_matrix_now
其中右端pheromone_matrix为上一轮的信息素矩阵,RHO为常数超参数,是0到1之间的一个小数,表示的是以前的信息素矩阵保留的比例。pheromone_matrix_now为当前一轮迭代留下的信息素矩阵。RHO越大,信息素更新受以前信息影响越大。RHO越小,信息素更新受当前轮迭代情况影响越大。
随后,蚂蚁则按上述规则进行一轮轮的迭代,并存储每轮迭代中路径最短的蚂蚁的访问序列和距离信息,直到最短路径长时间不再变化或者达到规定迭代次数停止。

三、蚁群算法解TSP的python实现

下面是激动人心的python代码实现.初始化了50只蚂蚁和50个城市的位置信息,按上述过程搜索迭代.并设计了GUI模块可视化搜索过程.GUI不是本文讨论的重点,因此不再赘述.

import random
import copy
import time
import sys
import math
import tkinter 
import threading
from functools import reduce

(ALPHA, BETA, RHO, Q) = (1.0,2.0,0.5,100.0)
# 城市数,蚁群
(city_num, ant_num) = (50,50)
distance_x = [
    178,272,176,171,650,499,267,703,408,437,491,74,532,
    416,626,42,271,359,163,508,229,576,147,560,35,714,
    757,517,64,314,675,690,391,628,87,240,705,699,258,
    428,614,36,360,482,666,597,209,201,492,294]
distance_y = [
    170,395,198,151,242,556,57,401,305,421,267,105,525,
    381,244,330,395,169,141,380,153,442,528,329,232,48,
    498,265,343,120,165,50,433,63,491,275,348,222,288,
    490,213,524,244,114,104,552,70,425,227,331]
#城市距离和信息素
distance_graph = [ [0.0 for col in range(city_num)] for raw in range(city_num)]
pheromone_graph = [ [1.0 for col in range(city_num)] for raw in range(city_num)]
 
 
 
#----------- 蚂蚁 -----------
class Ant(object):
 
    # 初始化
    def __init__(self,ID):
        
        self.ID = ID                 # ID
        self.__clean_data()          # 随机初始化出生点
 
    # 初始数据
    def __clean_data(self):
    
        self.path = []               # 当前蚂蚁的路径           
        self.total_distance = 0.0    # 当前路径的总距离
        self.move_count = 0          # 移动次数
        self.current_city = -1       # 当前停留的城市
        self.open_table_city = [True for i in range(city_num)] # 探索城市的状态
        
        city_index = random.randint(0,city_num-1) # 随机初始出生点
        self.current_city = city_index
        self.path.append(city_index)
        self.open_table_city[city_index] = False
        self.move_count = 1
    
    # 选择下一个城市
    def __choice_next_city(self):
        
        next_city = -1
        select_citys_prob = [0.0 for i in range(city_num)]  #存储去下个城市的概率
        total_prob = 0.0
 
        # 获取去下一个城市的概率
        for i in range(city_num):
            if self.open_table_city[i]:
                try :
                    # 计算概率:与信息素浓度成正比,与距离成反比
                    select_citys_prob[i] = pow(pheromone_graph[self.current_city][i], ALPHA) * pow((1.0/distance_graph[self.current_city][i]), BETA)
                    total_prob += select_citys_prob[i]
                except ZeroDivisionError as e:
                    print ('Ant ID: {ID}, current city: {current}, target city: {target}'.format(ID = self.ID, current = self.current_city, target = i))
                    sys.exit(1)
        
        # 轮盘选择城市
        if total_prob > 0.0:
            # 产生一个随机概率,0.0-total_prob
            temp_prob = random.uniform(0.0, total_prob)
            for i in range(city_num):
                if self.open_table_city[i]:
                    # 轮次相减
                    temp_prob -= select_citys_prob[i]
                    if temp_prob < 0.0:
                        next_city = i
                        break
 
        # 未从概率产生,顺序选择一个未访问城市
        # if next_city == -1:
        #     for i in range(city_num):
        #         if self.open_table_city[i]:
        #             next_city = i
        #             break
 
        if (next_city == -1):
            next_city = random.randint(0, city_num - 1)
            while ((self.open_table_city[next_city]) == False):  # if==False,说明已经遍历过了
                next_city = random.randint(0, city_num - 1)
 
        # 返回下一个城市序号
        return next_city
    
    # 计算路径总距离
    def __cal_total_distance(self):
        
        temp_distance = 0.0
 
        for i in range(1, city_num):
            start, end = self.path[i], self.path[i-1]
            temp_distance += distance_graph[start][end]
 
        # 回路
        end = self.path[0]
        temp_distance += distance_graph[start][end]
        self.total_distance = temp_distance
        
    
    # 移动操作
    def __move(self, next_city):
        
        self.path.append(next_city)
        self.open_table_city[next_city] = False
        self.total_distance += distance_graph[self.current_city][next_city]
        self.current_city = next_city
        self.move_count += 1
        
    # 搜索路径
    def search_path(self):
 
        # 初始化数据
        self.__clean_data()
 
        # 搜素路径,遍历完所有城市为止
        while self.move_count < city_num:
            # 移动到下一个城市
            next_city =  self.__choice_next_city()
            self.__move(next_city)
 
        # 计算路径总长度
        self.__cal_total_distance()
 
#----------- TSP问题 -----------
        
class TSP(object):
 
    def __init__(self, root, width = 800, height = 600, n = city_num):
 
        # 创建画布
        self.root = root                               
        self.width = width      
        self.height = height
        # 城市数目初始化为city_num
        self.n = n
        # tkinter.Canvas
        self.canvas = tkinter.Canvas(
                root,
                width = self.width,
                height = self.height,
                bg = "#EBEBEB",             # 背景白色 
                xscrollincrement = 1,
                yscrollincrement = 1
            )
        self.canvas.pack(expand = tkinter.YES, fill = tkinter.BOTH)
        self.title("TSP蚁群算法(n:初始化 e:开始搜索 s:停止搜索 q:退出程序)")
        self.__r = 5
        self.__lock = threading.RLock()     # 线程锁
 
        self.__bindEvents()
        self.new()
 
        # 计算城市之间的距离
        for i in range(city_num):
            for j in range(city_num):
                temp_distance = pow((distance_x[i] - distance_x[j]), 2) + pow((distance_y[i] - distance_y[j]), 2)
                temp_distance = pow(temp_distance, 0.5)
                distance_graph[i][j] =float(int(temp_distance + 0.5))
 
    # 按键响应程序
    def __bindEvents(self):
 
        self.root.bind("q", self.quite)        # 退出程序
        self.root.bind("n", self.new)          # 初始化
        self.root.bind("e", self.search_path)  # 开始搜索
        self.root.bind("s", self.stop)         # 停止搜索
 
    # 更改标题
    def title(self, s):
 
        self.root.title(s)
 
    # 初始化
    def new(self, evt = None):
 
        # 停止线程
        self.__lock.acquire()
        self.__running = False
        self.__lock.release()
 
        self.clear()     # 清除信息 
        self.nodes = []  # 节点坐标
        self.nodes2 = [] # 节点对象
 
        # 初始化城市节点
        for i in range(len(distance_x)):
            # 在画布上随机初始坐标
            x = distance_x[i]
            y = distance_y[i]
            self.nodes.append((x, y))
            # 生成节点椭圆,半径为self.__r
            node = self.canvas.create_oval(x - self.__r,
                    y - self.__r, x + self.__r, y + self.__r,
                    fill = "#ff0000",      # 填充红色
                    outline = "#000000",   # 轮廓白色
                    tags = "node",
                )
            self.nodes2.append(node)
            # 显示坐标
            self.canvas.create_text(x,y-10,              # 使用create_text方法在坐标(30277)处绘制文字
                    text = '('+str(x)+','+str(y)+')',    # 所绘制文字的内容
                    fill = 'black'                       # 所绘制文字的颜色为灰色
                )
            
        # 顺序连接城市
        #self.line(range(city_num))
        
        # 初始城市之间的距离和信息素
        for i in range(city_num):
            for j in range(city_num):
                pheromone_graph[i][j] = 1.0
                
        self.ants = [Ant(ID) for ID in range(ant_num)]  # 初始蚁群
        self.best_ant = Ant(-1)                          # 初始最优解
        self.best_ant.total_distance = 1 << 31           # 初始最大距离
        self.iter = 1                                    # 初始化迭代次数 
            
    # 将节点按order顺序连线
    def line(self, order):
        # 删除原线
        self.canvas.delete("line")
        def line2(i1, i2):
            p1, p2 = self.nodes[i1], self.nodes[i2]
            self.canvas.create_line(p1, p2, fill = "#000000", tags = "line")
            return i2
        
        # order[-1]为初始值
        reduce(line2, order, order[-1])
 
    # 清除画布
    def clear(self):
        for item in self.canvas.find_all():
            self.canvas.delete(item)
 
    # 退出程序
    def quite(self, evt):
        self.__lock.acquire()
        self.__running = False
        self.__lock.release()
        self.root.destroy()
        print (u"\n程序已退出...")
        sys.exit()
 
    # 停止搜索
    def stop(self, evt):
        self.__lock.acquire()
        self.__running = False
        self.__lock.release()
        
    # 开始搜索
    def search_path(self, evt = None):
 
        # 开启线程
        self.__lock.acquire()
        self.__running = True
        self.__lock.release()
        
        while self.__running:
            # 遍历每一只蚂蚁
            for ant in self.ants:
                # 搜索一条路径
                ant.search_path()
                # 与当前最优蚂蚁比较
                if ant.total_distance < self.best_ant.total_distance:
                    # 更新最优解
                    self.best_ant = copy.deepcopy(ant)
            # 更新信息素
            self.__update_pheromone_gragh()
            print (u"迭代次数:",self.iter,u"最佳路径总距离:",int(self.best_ant.total_distance))
            # 连线
            self.line(self.best_ant.path)
            # 设置标题
            self.title("TSP蚁群算法(n:随机初始 e:开始搜索 s:停止搜索 q:退出程序) 迭代次数: %d" % self.iter)
            # 更新画布
            self.canvas.update()
            self.iter += 1
 
    # 更新信息素
    def __update_pheromone_gragh(self):
 
        # 获取每只蚂蚁在其路径上留下的信息素
        temp_pheromone = [[0.0 for col in range(city_num)] for raw in range(city_num)]
        for ant in self.ants:
            for i in range(1,city_num):
                start, end = ant.path[i-1], ant.path[i]
                # 在路径上的每两个相邻城市间留下信息素,与路径总距离反比
                temp_pheromone[start][end] += Q / ant.total_distance
                temp_pheromone[end][start] = temp_pheromone[start][end]
 
        # 更新所有城市之间的信息素,旧信息素衰减加上新迭代信息素
        for i in range(city_num):
            for j in range(city_num):
                pheromone_graph[i][j] = pheromone_graph[i][j] * RHO + temp_pheromone[i][j]
 
    # 主循环
    def mainloop(self):
        self.root.mainloop()
 
                
if __name__ == '__main__':
 
    print (u""" 
--------------------------------------------------------
    程序:蚁群算法解决TPS问题程序 
-------------------------------------------------------- 
    """)
    TSP(tkinter.Tk()).mainloop()
    

四、总结

4.1 算法分析

蚁群算法是一种启发式算法。模仿蚁群通过信息素进行正反馈调节,在TSP问题中,蚂蚁每次巡游过程中洒下信息素,当次路径越短,单位路径上留下的信息素就越浓。这些信息素能够吸引更多的蚂蚁在下一轮迭代中以较大概率访问较短的路径。这样的调节方式能较好地淘汰那些距离太远的路径,从而减少算法的复杂度,使得每轮迭代的计算量控制在可以接受的范围,并能不断地向更优解逼近。

4.2 类比

蚁群算法与遗传算法有很多相似之处,如种群的初始化,轮盘赌选择.不过遗传算法是直接使用访问顺序作为启发因子,而蚁群算法则是利用信息素和距离作为启发因子.二者都是启发式算法,也都不能保证收敛到最优点.都有陷入局部最优的可能性.而这也是所有仿生进化算法的共性.虽然目前已经有证明遗传算法等算法收敛的探索性研究,但在我看来,还处于比较困难的阶段.目前还没有能完全解决NPC问题的有效算法。

4.3 拓展延伸

如果仔细理解了蚁群算法或遗传算法,再学习其他智能计算、仿生进化算法会是一件较为轻松的事。这些进化算法的共性是,都随机初始化一定数量的种群;都根据一些启发式信息来优化个体;都不保证收敛到全局最优、都有可能陷入局部最优;都需要大量迭代,等等。基于此,本文再简略介绍两种仿生进化算法,分别是免疫优化算法和模拟退火算法。

4.3.1 免疫优化算法

免疫优化算法是一种比较简单的仿生进化算法,其步骤如下:
1.种群初始化。与蚁群算法一样,初始化一个种群数量m,每个个体随机不重复访问各个城市并返回起点,形成一个个体序列以及对应的距离;
2.对于上一轮中的每一个个体,克隆其访问序列n次,得到n+1个相同个体。将新生成的n个数据采用一些算子进行变异,详情可以参考遗传算法的变异操作。一种简单的算子是随机选择该序列上的两个位置上的数进行交换。比如,一个序列为134567892,被随机选择的位置为第二个数和第三个数,那么变异后的序列为:143567892。注意,对m个个体中的每一个,都要对其克隆n次,对新生成的n个个体进行上述变异操作。
3.对于每组个体,由一个原序列和n个变异序列构成。将每个组内的n+1个个体,计算其路径的总距离,然后只保留路径距离最短、适应度最大的个体。也就是说,对于得到的m组序列,每组选出最优的个体保留,淘汰其他的序列,得到m个个体。
4.对m个个体的适应度(路径距离)进行排序,保留m/2个距离最短、适应度最大的优秀个体进入下一代,而舍弃排在后面1/2的个体。随后,再随机生成m/2个个体序列,与被保留的m/2个个体组成新的大小同为m的种群。
5.重复步骤2,3,4,记录每轮迭代中最优个体的适应度及其访问序列,直到达到规定迭代次数或得到满足条件的最优解。

以上便是免疫优化算法的整个流程。

4.3.2 模拟退火算法

模拟退火算法模拟的是金属液体凝固的过程。其算法流程如下:
1.随机初始化一个访问序列 x x x,定义初始超参数温度T,T为一个较大的常数。
2.定义每轮迭代次数N,温度衰减因子 α \alpha α,中止温度超参数 t t t
3.对该序列利用特定算子进行变异,得到序列 y y y。变异算子有很多种,读者可以参考上一篇博文遗传算法的几种变异法则,也可以用上文提到的简单的变异方法。比较序列 x x x y y y的适应度大小。在本TSP例中,也即比较路径距离。若d(x)>d(y),则直接将序列 x x x更新为 y y y,也即令 x x x= y y y
若d(x)<=d(y),则序列 x x x p = e − [ d ( y ) − d ( x ) ] / K ∗ T p=e^{-[d(y)-d(x)]/K*T} p=e[d(y)d(x)]/KT的概率接受新解,也即令 x x x= y y y。以 ( 1 − p ) (1-p) (1p)的概率保持不变。K为归一化概率的一个常数,此处的T表示当前温度。
4.重复上述3过程,直到本轮迭代次数达到规定次数N。
5.令 T = T ∗ α T=T*\alpha T=Tα,其中 α \alpha α为一个小于1的常数,一般取0.9及以上。
6.重复上述3,4,5过程,直到 T = t T=t T=t,迭代终止。
7.选择整个迭代中出现的最优序列作为最终的最优解。

模拟退火算法的关键在于公式:
p = e − [ d ( y ) − d ( x ) ] / K ∗ T p=e^{-[d(y)-d(x)]/K*T} p=e[d(y)d(x)]/KT

这个公式的含义为,当温度较高的时候,此时还在迭代的初始阶段,此时如果 x x x所处的地方如果很难变异得到新的更优的解,也很可能只是一个局部最优点,所以当我们得到比 x x x更差的序列 y y y,我们也应该以较大的概率接受新解,从而挑出局部最优。
当温度慢慢变小,冷却,说明迭代搜索已经进行了较长的时间,此时序列 x x x所处的位置应该是较低的较为优秀的位置。因此此时如果遇到更优解,我们依然毫不犹豫地往更低的方向走。但是如果遇到更差的解,更高的地方,我们就应该慎重,不以较大的概率前往更差的地方,因为此时大概率已经处在很优的位置了。这便是模拟退火算法的核心思想:迭代开始时,以较大的概率挑出,避免陷入局部最优;当迭代进行了较多次数,则接受新解的概率变小,跳出策略变得保守。

以上便是本文的全部内容。看到这里一定累了吧,注意休息哟!
创作不易,点个赞再走叭!!

你可能感兴趣的:(算法,算法,python,人工智能,动态规划)