【问题标题】:On the implementation of a simple ant colony algorithm一种简单蚁群算法的实现
【发布时间】:2020-12-15 15:59:58
【问题描述】:

this paper 中,描述了一个非常简单的模型来说明蚁群算法的工作原理。简而言之,它假设两个节点通过两条链路连接,其中一条链路较短。然后,给定信息素增量和信息素蒸发动力学,人们预计所有蚂蚁最终都会选择较短的路径。

现在,我正在尝试复制与上述场景相对应的本文的模拟,其结果应该(或多或少)如下所示。

这是我的一个实现(采用与上面测试相同的规范)。

import random
import matplotlib.pyplot as plt

N = 10
l1 = 1
l2 = 2
ru = 0.5
Q = 1
tau1 = 0.5
tau2 = 0.5

epochs = 150

success = [0 for x in range(epochs)]

def compute_probability(tau1, tau2):
    return tau1/(tau1 + tau2), tau2/(tau1 + tau2)

def select_path(prob1, prob2):
    if prob1 > prob2:
        return 1
    if prob1 < prob2:
        return 2
    if prob1 == prob2:
        return random.choice([1,2])

def update_accumulation(link_id):
    global tau1
    global tau2
    if link_id == 1:
        tau1 += Q / l1
        return tau1
    if link_id == 2:
        tau2 += Q / l2
        return tau2

def update_evapuration():
    global tau1
    global tau2
    tau1 *= (1-ru)
    tau2 *= (1-ru)
    return tau1, tau2

def report_results(success):
    plt.plot(success)
    plt.show()

for epoch in range(epochs-1):
    temp = 0
    for ant in range(N-1):
        prob1, prob2 = compute_probability(tau1, tau2)
        selected_path = select_path(prob1,prob2)
        if selected_path == 1:
            temp += 1
        update_accumulation(selected_path)
        update_evapuration()
    success[epoch] = temp

report_results(success)

但是,我得到的结果很奇怪,如下所示。

看来我对信息素应该如何更新的理解是有缺陷的。

那么,可以解决我在这个实现中缺少的东西吗?

【问题讨论】:

  • 一个大问题是您没有根据概率选择路径 1 或 2。例如,如果 prob1 是 .50001 而 prob2 是 0.49999,那么您将总是选择 p1,而实际上这些概率应该非常接近随机。你可以考虑random.choices([1, 2], weights=[prob1, prob2])[0]
  • @MarkMeyer:感谢您抓住这一点,尽管结果没有改变。我觉得问题的主要来源是我的主循环中的某个地方。
  • 下面我的答案的旁注:论文的链接似​​乎已死,可能需要刷新或指向 DOI 链接或添加论文的名称,如果更容易的话。
  • @Andrei:我更新了链接,该链接现在指向其发布者网站中的网页。
  • 在已发布的图中我发现不清楚的是,在某些情况下,最高观察值高于 1 (100 %),这意味着超过所有蚂蚁报告使用最短路径。我不知道这会是什么解释,或者情节是否有错误。

标签: python ant-colony


【解决方案1】:

建议方法中的三个问题:

  1. 正如@Mark 在他的评论中提到的,你需要一个加权随机选择。否则,建议的方法可能总是会选择其中一条路径,并且该图将导致如上所示的一条直线。但是,我认为这是解决方案的一部分,因为即使这样,由于早期收敛,您可能仍然会得到一条直线,这导致了两个问题二。

  2. 蚁群优化是一种元启发式算法,需要配置多个(超)参数来指导搜索某个解决方案(例如,来自上方的 tau 或蚂蚁数量)。微调此参数很重要,因为您可以及早收敛到特定结果(这在某种程度上很好 - 如果您想将其用作启发式)。但是元启发式的目的是在精确算法和启发式算法之间为您提供一些中间立场,这使得持续探索/利用成为其工作的重要部分。这意味着需要根据您的问题大小/类型仔细优化参数。

  3. 鉴于 ACO 使用概率方法来指导搜索(并且正如参考论文中的图所示),您需要多次运行实验并计算这些数字的一些统计数据。在下面的例子中,我计算了 100 个样本的平均值。

    import random
    import matplotlib.pyplot as plt
    
    N = 10
    l1 = 1.1
    l2 = 1.5
    ru = 0.05
    Q = 1
    tau1 = 0.5
    tau2 = 0.5
    
    samples = 10
    epochs = 150
    
    success = [0 for x in range(epochs)]
    
    def compute_probability(tau1, tau2):
        return tau1/(tau1 + tau2), tau2/(tau1 + tau2)
    
    def weighted_random_choice(choices):
        max = sum(choices.values())
        pick = random.uniform(0, max)
        current = 0
        for key, value in choices.items():
            current += value
            if current > pick:
                return key
    
    
    def select_path(prob1, prob2):
        choices = {1: prob1, 2: prob2}
        return weighted_random_choice(choices)
    
    def update_accumulation(link_id):
        global tau1
        global tau2
        if link_id == 1:
            tau1 += Q / l1
        else:
            tau2 += Q / l2
    
    def update_evaporation():
        global tau1
        global tau2
        tau1 *= (1-ru)
        tau2 *= (1-ru)
    
    def report_results(success):
        plt.ylim(0.0, 1.0)
        plt.xlim(0, 150)
        plt.plot(success)
        plt.show()
    
    for sample in range(samples):
        for epoch in range(epochs):
            temp = 0
            for ant in range(N):
                prob1, prob2 = compute_probability(tau1, tau2)
                selected_path = select_path(prob1, prob2)
                if selected_path == 1:
                    temp += 1
                update_accumulation(selected_path)
                update_evaporation()
            ratio = ((temp + 0.0) / N)
            success[epoch] += ratio
        # reset pheromone values here to evaluate new sample
        tau1 = 0.5
        tau2 = 0.5
    
    success = [x / samples for x in success]
    
    for x in success:
        print(x)
    
    report_results(success)
    

上面的代码应该返回接近所需情节的东西。

【讨论】:

  • 感谢您的回答。关于您的第二点,对于这种情况,是否有任何参数优化方法比网格搜索更可取(类似于我们在机器学习算法中的超参数调整中所做的)?
  • @Roboticist 需要对此进行一些挖掘,因为我没有答案。该领域的文献提到使用其他一些元启发式算法,如遗传算法来找到最合适的参数集。如果您遇到什么,请在此处发布。
猜你喜欢
  • 2017-06-16
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-23
  • 1970-01-01
  • 2023-04-03
相关资源
最近更新 更多