FakeOrange
预计阅读时间:20分钟8秒

用仿生学优化神经网络

从自然中寻找灵感,驱动算法设计

0
0


前言



本文属于搬运内容,原作者:Leon Fedden (Salute!)原文链接在文章末尾!


欢迎来到本周关于“受自然启发的算法”系列的文章。以下是前几周的内容链接:



本文是“研究受自然启发的算法”系列的第二部分。你可以在这里阅读第一部分,了解我们在为目标问题选择算法时可能面临的挑战及其含义。第三部分和第四部分可以通过对应的链接访问。


正如第一篇文章提到的,我将尝试将从 Goldsmiths 学习的自然计算课程中的主题,尽可能地应用于神经网络,以保持主题的新颖性,并与其他文章形成对比。在本文的结尾,我将尝试将第一部分的内容与本文结合起来,审视**无免费午餐定理(No Free Lunch Theorem)**如何适用于分散飞行优化(Dispersive Flies Optimisation, DFO)在解决网络权重优化问题中的表现。



从自然中寻找灵感,驱动算法设计



分散飞行优化(Dispersive Flies Optimisation, DFO)



自然是优化和搜索问题的重要灵感来源。分散飞行优化(DFO)便是受苍蝇在食物源上聚集行为启发而提出的一种算法。


苍蝇的群体规模可以从单只苍蝇到数千甚至数百万只,具体数量取决于物种。当群体受到干扰时,苍蝇会分散开来,然后再次聚集。这种行为正是 DFO 算法的核心:群体的形成和解散



数学模型


对于每个苍蝇个体,其位置向量的定义如下


data/78df2c1f-e442-415d-a382-fa7925af0c4b/cdcdd863-ef81-4547-a13a-93cfce7b5580image.png


注释:


  • t 表示当前时间步骤
  • i 表示群体中的个体,i 为独特标记
  • NP 为苍蝇的总数
  • D为空间的维度


初始位置定义


data/78df2c1f-e442-415d-a382-fa7925af0c4b/35988415-444b-4691-b77c-6ede1e4fc5ebimage.png


注释:


  • 其中 0 为初始时间
  • d 为当前的空间
  • min 表示当前空间的下界限(lower bound 即最低点)
  • max 表示当前空间的上界限  (upper bound 即最高点)
  • r 表示随机数


直观解释为每只苍蝇在每个维度上分配一个随机位置,该位置介于该维度的上下界之间。(上下界为Low bound , up bound, 理解为最小值与最大值。 )



迭代过程


data/78df2c1f-e442-415d-a382-fa7925af0c4b/d72491cd-acab-43bb-9341-2b54098b254cimage.png


每轮迭代中,算法会:


  • 计算适应度值(Fitness)计算每只苍蝇在当前环境中的适应度值(即目标函数的值)。


  • 更新群体最佳位置存储当前迭代中最优的苍蝇位置。作为算法的改进,我建议额外存储所有迭代中的全局最优位置,以便对最终解进行评估。


  • 更新苍蝇位置计算每只苍蝇的新位置,具体更新公式将在后续部分进一步描述。



分散飞行优化的细节解析



更新规则


在每次迭代中,苍蝇群体位置的更新机制包含以下几个核心步骤:


  • 随机扰动机制如果从均匀分布中抽取的随机数小于扰动阈值(dt),则当前苍蝇在该维度的坐标被重新初始化为搜索空间中的随机位置。这种随机性可以防止群体过早收敛到局部最优解。


  • 邻居选择机制如果随机数大于扰动阈值,则当前苍蝇会选择其左右邻居中适应度最优的个体作为参考(即最近邻最优)。然后,该苍蝇会朝着本轮迭代中适应度最优的个体(全局最优)移动一小步,步长由随机量决定。


群体智能的魅力


该算法,以及其他群体智能算法的一个迷人之处在于:简单的规则能够引发复杂的涌现行为。个体苍蝇只需遵守上述简单规则,就能够实现高度复杂的搜索与优化能力。



实现代码:Python 示例



以下是分散飞行优化算法的一个示例实现,目标是优化苍蝇群体的位置,直到找到与目标向量接近的可接受解。代码中注释已经很清晰,以下提供一个高级别概述:


优化目标


苍蝇群体需要优化位置向量,使其与目标向量(target_solution)的欧几里得距离为零,即达到全局最优解。


Python 示例代码


import numpy as np

# 美化输出
np.set_printoptions(precision=3, suppress=True)

# 群体规模
size = 100

# 苍蝇被扰动的频率(阈值)
disturbance_threshold = 0.01

# 目标解
target_solution = np.array([0.0, 1.0, -1.0, 1.0, 0.0]) 

# 初始化范围上下界
lower = -1.0
upper = 1.0

# 随机初始化群体位置
population = np.array([np.random.uniform(lower, upper, len(target_solution)) for _ in range(size)]) 

# 记录全局最优解
all_time_best = None
all_time_best_score = np.finfo(np.float32).max

# 存储每个苍蝇的最佳邻居
best_neighbour = np.zeros_like(population[0])

# 迭代次数
iteration_amount = 100
for _ in range(iteration_amount):
    # 计算每只苍蝇的适应度(欧几里得距离)
    fitnesses = np.zeros(len(population))
    for i in range(len(population)):
        fitnesses[i] = np.linalg.norm(target_solution - population[i])

    # 找到当前群体的最优苍蝇
    swarms_best_index = np.argmin(fitnesses)
    swarms_best = population[swarms_best_index]

    # 更新全局最优解
    if np.amin(fitnesses) <= all_time_best_score:
        all_time_best_score = np.amin(fitnesses)
        all_time_best = swarms_best

    # 为每只苍蝇生成随机数
    r = np.random.uniform(0.0, 1.0, population.shape)

    # 更新每只苍蝇的位置
    for i, p in enumerate(population):
        # 计算邻居索引(循环缓冲)
        left = (i - 1) if i != 0 else len(population) - 1
        right = (i + 1) if i != (len(population) - 1) else 0
        
        # 获取最佳邻居
        best_neighbour = population[left] if fitnesses[left] < fitnesses[right] else population[right]

        # 更新位置
        for x in range(len(p)):
            if r[i][x] < disturbance_threshold:
                # 随机初始化位置
                p[x] = np.random.uniform(lower, upper)
            else:
                # 朝着全局最优位置移动
                update = swarms_best[x] - best_neighbour[x]
                p[x] = best_neighbour[x] + np.random.uniform(0.0, 1.0) * update

# 计算最终适应度并输出结果
fitnesses = np.zeros(len(population))
for i in range(len(population)):
    fitnesses[i] = np.linalg.norm(target_solution - population[i])

swarms_best_index = np.argmin(fitnesses)
swarms_best = population[swarms_best_index]

print('target:', target_solution)  
print('best:  ', all_time_best)  
print('diff:  ', np.abs(all_time_best - target_solution)) 


输出示例


target: [ 0.    1.    -1.     1.     0.   ]
best:   [ 0.    0.992 -0.967  0.992 -0.   ]
diff:   [ 0.    0.008  0.033  0.008  0.   ]


总结


该实现展示了分散飞行优化算法在简单问题上的有效性。通过在搜索空间中不断更新苍蝇群体的位置,算法能够快速逼近目标解。尽管规则简单,但其随机扰动与邻居选择机制为避免陷入局部最优提供了强大的灵活性。你可以进一步修改代码以解决更复杂的问题!



面对更复杂的问题



之前的示例是一个非常简单的玩具问题,那如果换成更复杂的任务呢?


data/78df2c1f-e442-415d-a382-fa7925af0c4b/16cb682e-403d-43fb-96b4-c8f464e1ba25image.png



分散飞行优化 (DFO) 与神经网络权重优化



为了探索更复杂的应用,我选择用 DFO 优化神经网络的可训练权重,以解决经典的CartPole 问题


CartPole 问题是强化学习文献中的标准任务,而 OpenAI Gym 提供了一个 Python 环境,让神经网络可以与 CartPole 模型交互。以下是 OpenAI Gym 官网对该问题的描述:


  • 一根杆通过无动力的铰链连接到一辆小车上,小车在一个无摩擦的轨道上移动。


  • 通过施加 +1 或 -1 的力来控制小车的移动。


  • 杆的初始状态是直立的,目标是防止杆倒下。


  • 每次杆保持直立(不倒下)都会获得 +1 的奖励。


  • 当杆偏离垂直方向超过 15 度,或小车距离中心超过 2.4 个单位时,回合结束。



成功平衡的杆



在解决问题的过程中,神经网络的任务是保持杆直立。运行成功的示例如下图所示,网络能够平衡杆 200 个时间步长。在这种情况下,我们认为问题已被解决。


代码实现


以下是实现该任务的代码。请注意,这里不是讲解神经网络或 TensorFlow 的教程,因此代码中不会详细说明网络结构或 TensorFlow 的实现细节。如果你希望深入了解,可以参考 神经网络入门教程 或 TensorFlow 的官方文档


在使用代码时,值得注意的是你的TensorFlow和gym版本。API更改很快,因此如果你遇到问题,请检查你是否使用了相同版本,或者你的代码是否正确更新。目前我使用的是以下版本:


  • TensorFlow 版本:1.3.0
  • OpenAI Gym 版本:0.9.3


import tensorflow as tf
import numpy as np
from collections import deque
import matplotlib.pyplot as plt
import threading
import multiprocessing
import gym
import json
import os
from time import sleep

print('TensorFlow version:', tf.__version__)
print('OpenAI Gym version:', gym.__version__)

设置参数


网络使用修正线性单元(ReLU)作为激活函数。隐藏层的维度在列表中指定。


hidden_non_linearity = tf.nn.relu
hidden_sizes = [6, 3]
output_size = 2
input_size = 4
cpu_only = True
env_name = 'CartPole-v0'
number_iterations = 200

设置TensorFlow图


tf.reset_default_graph()方法用于清除图,以便尝试不同的维度。然后,使用for循环构建网络,并在代码的最后创建特殊张量,以便有效地并行插入权重。


tf.reset_default_graph()

model_input = tf.placeholder(dtype=tf.float32, shape=[None, input_size])
net = model_input

for hidden_size in hidden_sizes:
    net = tf.layers.dense(inputs=net, units=hidden_size, activation=hidden_non_linearity)

net = tf.layers.dense(inputs=net, units=output_size, activation=tf.nn.softmax)
model_output = net

graph = tf.get_default_graph()

restore_dict = {}
restore_ops = []
for var in graph.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES):
    place_holder = tf.placeholder(tf.float32, var.get_shape(), 'ph%s' % var.name.split(':')[0])
    restore_dict[var.name] = place_holder
    restore_ops.append(tf.assign(var, place_holder))

定义多线程DFO类


该类封装了主要的DFO算法。在创建TensorFlow会话时会使用它,值得查看的主要方法是run()函数。


class DFOStrategy(object):
    """管理DFO优化的类。"""

    def __init__(self, weights, get_reward_func, population_size=100, disturbance_threshold=0.01, name='CartPole-v0', sess=None, meta=None, mode=0):
        """初始化类的成员变量。
        种群是从一个与传入权重具有相同标准差和均值的高斯分布中创建的。
        注意:必须传递一个合法的tf.Session对象给类。
        """
        np.random.seed(0)
        self.weights = weights
        self.meta = meta
        self.get_reward = get_reward_func
        self.population_size = population_size
        dev = np.std(weights)
        mean = np.mean(weights)
        if mean < 0:
            mean = 0
        self.population = np.array([np.random.normal(dev, mean, len(weights)) for _ in range(self.population_size)])
        self.disturbance_threshold = disturbance_threshold
        self.env_name = name
        self.env = gym.make(self.env_name)
        self.sess = sess
        self.swarms_best = None
        self.swarms_best_score = np.finfo(np.float32).max
        self.all_time_best = None
        self.all_time_best_score = np.finfo(np.float32).max
        self.mode = mode
        self.best_reward_record = deque()
        self.reward_mean_record = deque()
        self.reward_sigma_record = deque()
        assert sess is not None

DFO优化算法


run()方法是优化过程的核心。该方法并行运行多个线程计算每个个体的奖励,然后根据这些奖励更新种群。


def run(self, iteration_amount, elitism=0, print_step=10, decay=0.98):
    """主要的优化方法。
    创建多个线程并计算环境中的奖励,接着计算DFO算法并更新飞行器的位置。
    """
    saver = tf.train.Saver()
    best_neighbour = np.zeros_like(self.population[0])

    envs = [gym.make(self.env_name) for _ in range(multiprocessing.cpu_count())]
    for iteration in range(iteration_amount):
        self.print_out(iteration, print_step)

        amount_per_thread = int(np.floor(self.population_size / multiprocessing.cpu_count()))
        left_over = self.population_size - amount_per_thread * multiprocessing.cpu_count()

        fitnesses = np.zeros(len(self.population))

        def get_weights_reward(begin, size, env):
            for i in range(begin, begin + size):
                fitnesses[i] = -self.get_reward(self.population[i], self.sess, env, self.meta)
        
        threads = []
        idx = 0
        for i in range(multiprocessing.cpu_count()):
            amt = (amount_per_thread + 1) if i < left_over else amount_per_thread
            thread = threading.Thread(target=get_weights_reward, args=[idx, amt, envs[i]])
            threads.append(thread)
            idx += amt

        for t in threads:
            t.start()
        for t in threads:
            t.join()

        swarms_best_index = np.argmin(fitnesses)
        self.swarms_best_score = np.amin(fitnesses)
        self.swarms_best = self.population[swarms_best_index]
                    
        if self.swarms_best_score <= self.all_time_best_score:
            self.all_time_best_score = self.swarms_best_score
            self.all_time_best = self.swarms_best
            self.get_reward(self.all_time_best, self.sess, self.env, self.meta)
            saver.save(self.sess, self.env_name + '_dfo')

        r = np.random.uniform(0.0, 1.0, self.population.shape)
        self.lower = np.amin(self.population)
        self.upper = np.amax(self.population)
        dev = np.std(self.population)
        mean = np.mean(self.population)
        self.best_reward_record.append(self.swarms_best_score) 
        self.reward_mean_record.append(mean) 
        self.reward_sigma_record.append(dev)
        if mean < 0:
            mean = 0

        # 更新飞行器位置的逻辑代码

获取和设置TensorFlow可训练变量


这些方法用于获取和设置优化的权重。它们是通过DFO优化过程更新权重的基础。


def get_weights(sess):
    """从会话获取权重。
    """
    all_variable_names = [v.name for v in tf.trainable_variables()]
    all_variable_values = sess.run(all_variable_names)
    all_variable_shapes = [v.shape for v in all_variable_values]
    all_variable_cutoffs = [np.prod(s) for s in all_variable_shapes]
    genotype = np.concatenate([v.flatten() for v in all_variable_values])
    return genotype, (all_variable_names, all_variable_shapes, all_variable_cutoffs)

def set_weights(sess, new_genotype, meta):
    """在会话中设置权重。
    """
    names, shapes, cutoffs = meta
    new_genotype = np.array(new_genotype)
    new_variable_values = []
    start = 0
    end = cutoffs[0]
    for i in range(1, len(cutoffs)):
        new_variable = new_genotype[start:end]
        new_variable_values.append(new_variable)
        start = end
        end += cutoffs[i]
    new_variable_values.append(new_genotype[:-start])

    feed_dict = {}
    for i in range(len(shapes)):
        new_variable_values[i] = new_variable_values[i].reshape(shapes[i])    
        feed_dict[restore_dict[names[i]]] = new_variable_values[i]
    sess.run(restore_ops, feed_dict=feed_dict)


奖励/适应度函数


此函数基于当前权重和环境运行情况计算奖励。


def get_reward(weights, sess, env, meta):
    """根据传入的权重和环境返回奖励。
    """
    set_weights(sess, weights, meta)

    total_reward = 0
    done = False
    observation = env.reset()

    while not done:
        feed_dict = {model_input: observation.reshape((1, -1))}
        prediction = sess.run(model_output, feed_dict=feed_dict)          
        action = prediction[0]
        action = np.argmax(action)

        observation, reward, done, info = env.step(action)
        total_reward += reward

    return total_reward

运行并优化MLP


使用DFO算法进行优化。每个优化步骤后,TensorFlow权重会被保存。


config = tf.ConfigProto(device_count={'GPU': 0}) if cpu_only else None

with tf.Session(config=config) as sess:
    sess.run(tf.global_variables_initializer())
    
    initial_weights, meta = get_weights(sess)

    es = DFOStrategy(initial_weights, 
                     get_reward,
                     population_size=1000, 
                     disturbance_threshold=0.1,
                     name=env_name,
                     sess=sess,
                     meta=meta,
                     mode='original')
    
    es.run(number_iterations, elitism=20, print_step=1, decay=0.99)
    
    best_weights = es.get_weights()


总结


通过将 DFO 应用于优化神经网络的权重,我们成功地解决了 CartPole 问题。这种方法虽然简单,但展示了分散飞行优化在更复杂场景中的潜力。尽管强化学习算法更常用于解决该问题,但这种尝试为 DFO 提供了一个新的应用视角,也展现了群体智能方法在机器学习中的灵活性和适应性。



那么这些改动具体是什么?



在调整和优化 DFO(分散飞行优化算法)时,为了改进其性能,我对原算法做了一系列改动。以下是对主要改动的总结说明(不包括用于绘图或神经网络表示的必要样板代码):


DFO 改动概述


  • 更新方法(共七种)。


  • 苍蝇群体的精英保留


  • 扰动阈值的衰减


  • 使用多线程加速适应度估计的计算


  • 引入“永恒之神”苍蝇(Eternal God Fly)机制



更新机制



原始更新方法


在上述代码中,有七种更新方法可用,加上其他修改,用户可以进行各种组合尝试。以下是主要更新机制的概述:


if self.mode == 'original':
    if r[i][x] < self.disturbance_threshold:
        p[x] = np.random.normal(dev, mean)
    else:
        leader_rate = np.random.uniform(0.0, 1.0)
        update = self.swarms_best[x] - best_neighbour[x]
        p[x] = best_neighbour[x] + leader_rate * update


在原始更新方法中,对苍蝇的位置进行了略微调整。具体来说,当重新初始化苍蝇位置时,不再使用传统的正态分布,而是基于网络初始权重的均值和标准差构造一个高斯分布。这种改动是基于经验的,结果显示性能有所提升。


混合更新模式


另一种更新方法被称为“混合模式”:


elif self.mode == 'hybrid':
    if r[i][x] < self.disturbance_threshold:
        p[x] = np.random.normal(dev, mean)
    else:
        leader_rate = np.random.uniform(0.0, 1.0)
        update = (best_neighbour[x] + self.swarms_best[x]) / 2.0 - p[x]
        p[x] = p[x] + leader_rate * update


这种模式的主要区别在于:苍蝇不会直接被分配到它的最佳邻居的位置,而是保留其自身位置,同时向最佳邻居与全局最佳之间的平均值移动。


实践中,这种方法并没有产生很好的结果。原因在于,最佳邻居和全局最佳的平均值未必是最优解。网络参数的可能配置很多,问题通常是多峰的(multimodal),而非单峰的(unimodal)。两个最佳权重的平均值可能根本不会带来好的适应度分数。


接下来会进一步讲解其他改动,例如“精英保留”和“神苍蝇”机制。


从混合模式到 n_fittest 模式


相比混合模式,n_fittest 模式进一步提升了更新方法:


elif self.mode == 'n_fittest':
    if r[i][x] < self.disturbance_threshold:
        p[x] = np.random.normal(dev, mean)
    else:
        leader_rate = np.random.uniform(0.0, 1.0)
        update = np.average(self.population[n_fittest]) - best_neighbour[x]
        p[x] = best_neighbour[x] + leader_rate * update


在此代码中,苍蝇会被分配到其最佳邻居的位置,然后朝着 “n” 个最优苍蝇的平均位置移动。在下方的图表中,n 的值被设置为 20。


data/78df2c1f-e442-415d-a382-fa7925af0c4b/33701a54-97ed-419a-912f-9e0193b8d2beimage.png


n_fittest 模式的观察结果


尽管这个方法运行时未能在限定时间内完成优化,但值得注意的是:


  • 种群的平均值和偏差在第一次迭代之后几乎没有发生显著变化。


  • 结果显示,一个迭代中的最优苍蝇在下一次迭代中未必仍然是最优的,即使它曾找到某一轮中奖励最高的神经网络参数。



为什么会发生这种情况?



这与 Cartpole 环境的随机初始角度有关:


  • 某些参数配置在特定初始角度下表现良好,但在其他角度下可能不适用。


  • 我们可以在奖励图表中观察到这一现象:当某只苍蝇似乎达到了最佳得分(-200)时,下一轮的得分可能会显著下降。



随机模式



代码中还加入了几个随机模式,比如 random_uniformrandom_gauss


elif self.mode == 'random_gauss':    
    p[x] = np.random.normal(dev, mean)

elif self.mode == 'random_uniform':
    p[x] = np.random.sample()


  • 随机高斯模式 (random_gauss):基于高斯分布随机分配值。


  • 随机均匀模式 (random_uniform):使用均匀分布随机分配值。


这些模式在较低维度的搜索空间中表现尚可,但在更大规模的网络权重搜索中效果较差。



精英主义(Elitism)



为了确保最优个体不会被更新,引入了 精英主义


for i, p in enumerate(self.population):             
    if elitism > 0 and i in n_fittest:
        pass



  • elitism 变量:整数值,表示有多少个最优个体会被保护,不会被更新。


  • 程序会将这些最优个体的索引存储在 n_fittest 中,以避免更新它们的位置。

精英主义的引入确保了群体中的“佼佼者”始终得以保留,这样可以减少优化过程中可能的退化现象,同时提高算法的整体性能。



两次实验对比:有精英主义与无精英主义


上述两次程序运行对比:


  • 精英主义设置为 20 的实验


结果发现:


  • 启用精英主义时,程序花费更多时间找到最佳奖励。原因:最优苍蝇被强制停留在局部最小值,而未能通过随机性进行进一步优化。


  • 精英主义为 0 的实验程序能够更快地将苍蝇更新到全局最小值。缺点:由于最优苍蝇未受到保护,每次迭代都可能丢失全局最小值的位置。


干扰阈值衰减


self.disturbance_threshold *= decay


另一种方法是让干扰阈值随迭代逐渐减小


  • 理论依据:当苍蝇逐渐接近全局最小值时,减少随机位置重置的频率,提升算法的收敛能力。


实际效果


data/78df2c1f-e442-415d-a382-fa7925af0c4b/b9052c8e-898b-4f8f-9cb3-5d90e3425fa8image.pngdata/78df2c1f-e442-415d-a382-fa7925af0c4b/d59961c6-6955-4dac-8fdf-b059a56d37d1image.png


多线程计算


当种群大小达到 1000,并且需要模拟多次 Cartpole 环境时,单线程运行效率很低。


通过以下代码将模拟过程并行化,显著提高了速度:


envs = [gym.make(self.env_name) for _ in range(multiprocessing.cpu_count())]

amount_per_thread = int(np.floor(self.population_size / multiprocessing.cpu_count()))
left_over = self.population_size - amount_per_thread * multiprocessing.cpu_count()

fitnesses = np.zeros(len(self.population))

def get_weights_reward(begin, size, env):
    for i in range(begin, begin + size):
        fitnesses[i] = -self.get_reward(self.population[i], 
                                        self.sess, 
                                        env,
                                        self.meta)

threads = []
idx = 0
for i in range(multiprocessing.cpu_count()):
    amt = (amount_per_thread + 1) if i < left_over else amount_per_thread
    thread = threading.Thread(target=get_weights_reward,
                              args=[idx, amt, envs[i]])
    threads.append(thread)
    idx += amt

for t in threads:
    t.start()
for t in threads:
    t.join()


  • 步骤:根据 CPU 核心数创建多个线程。为每个线程分配一部分种群,用于计算适应值。使用多线程同时计算所有苍蝇的奖励值。


  • 结果:通过将任务分摊到多个线程上,程序运行速度大幅提升。



永恒之神苍蝇(Eternal God Fly)



永恒之神苍蝇是指整个运行过程中表现最佳的苍蝇。


这一想法旨在保存当前运行中表现最好的神经网络参数,确保最佳个体不会丢失。


swarms_best_index = np.argmin(fitnesses)
self.swarms_best_score = np.amin(fitnesses)
self.swarms_best = self.population[swarms_best_index]

if self.swarms_best_score <= self.all_time_best_score:
    self.all_time_best_score = self.swarms_best_score
    self.all_time_best = self.swarms_best


  • 实现逻辑:每次迭代中找到种群的最优苍蝇,并与之前的“全时最佳苍蝇”对比。如果新的最优苍蝇的得分更低(或相等),更新全时最佳苍蝇。这里使用了 ≤ 操作符,原因是较新的苍蝇可能在更多环境中获得了经验,相较于某些早期的幸运个体更为可靠。


  • 效果:引入这一机制后,算法始终保留了当前运行的最佳解决方案以供测试和使用。


关于 DFO 在神经网络权重更新中的表现


在神经网络权重优化方面,当维度增大时,DFO 的性能显著下降。例如,当尝试优化一个每层有 256 个神经元的网络时,几乎无法在合理时间内完成。如果将 DFO 移植到 GPU 上运行,并给予其与反向传播(Backpropagation)或带经验回放的策略梯度(Policy Gradients with Experience Replay)相等的计算时间,或许能让结果更具可比性。不过,从附带的视频来看,通过足够的调整,DFO 最终成功生成了一个可以解决问题的工作网络!


No Free Lunch 讨论中,我们探讨了算法与其搜索空间之间的关系。评估算法在特定问题上的表现关键在于其适配搜索空间的能力。那么,DFO 与神经网络权重这一搜索空间的匹配度如何呢?


我认为 DFO 并不完全适合这个问题:


  • 权重更新频率高:权重位置的频繁更新以及权重之间的非线性关系,使得 DFO 很难稳定地朝向全局最小值优化。


  • 随机重置问题:随机重置苍蝇的位置是个关键问题。一个关键权重可能被重置为完全随机的值,这可能导致神经网络输出发生系统性恶化,产生连锁反应。


尽管如此,经过足够的调整,DFO 确实可以解决问题,并且仍有可能通过进一步改进来提升性能。



总结



最后,我想用 AI 领域的英雄 Stuart Russell 和 Peter Norvig 的一段精彩引言来结束本篇讨论:


The quest for ‘artificial flight’ succeeded when the Wright brothers and others stopped imitating birds and started using wind tunnels and learning about aerodynamics.”(“当莱特兄弟等人停止模仿鸟类,转而利用风洞研究空气动力学时,人类才实现了‘人工飞行’。


简而言之,从自然中汲取灵感以设计新算法是一个有价值的想法。这为面对设计新算法解决复杂问题时提供了重要的启发。然而,我们也必须记住,人类之所以能飞翔,是因为我们停止了制造带有羽毛的机器,而是开始设计适合飞行的科学方法。因此,我们需要在必要时加入一点“虚构”的想象力,同时辅以相关的数学或计算技术来取得优异的成果。


感谢阅读!



原文链接


评论
Copyright Created by DataER | 沪ICP备2024052789号-5 | 沪公网安备31010402336337号