遗传算法如何在不知道搜索量的情况下优化神经网络的权重?

How can a genetic algorithm optimize a neural network's weights without knowing the search volume?

我已经实现了一个遗传算法训练的神经网络,其中包含一个变异算子,如下所示:

def mutation(chromosome, mutation_rate):
  for gene in chromosome:
    if random.uniform(0.00, 1.00) <= mutation_rate:
      gene = random.uniform(-1.00, 1.00)

并且染色体最初是随机初始化的:

def make_chromosome(chromosome_length):
  chromosome = []
  for _ in range(chromosome_length):
    chromosome.append(random.uniform(-1.00, 1.00))
  return chromosome

执行交叉时,后代染色体只能在区间 [-1, 1] 内拥有基因,因为父染色体也只能在该区间内拥有基因。当一个后代发生变异时,它同样会将其基因保持在该区间内。

这似乎对某些问题有效,但对其他问题无效。如果一个神经元的最佳权重在 [-1, 1] 内,那么遗传算法就可以工作,但是如果一个神经元的最佳权重在不同的区间内呢?

例如,如果我使用分类误差低于 5% 的终止条件训练了一个网络,我可以查看网络权重并看到 -1.491.982.01,等等。我的遗传算法永远无法产生这些基因,因为基因在 [-1, 1] 内初始化,交叉和变异也不能产生该范围之外的基因。

看来我需要更好地定义搜索 space,像这样:

# search space boundaries
S_MIN = -1.00
S_MAX = 1.00

# in mutation()
gene = random.uniform(S_MIN, S_MAX)

# in make_chromosome()
chromosome.append(random.uniform(S_MIN, S_MAX))

然后我可以根据问题设置搜索 space 边界。但是如何确定搜索space?此信息不是先验知识,而是通过网络训练找到的。但是,如果培训需要知道搜索 space,那么我将处于停滞状态。

我可以将搜索 space 设置为任意大(例如肯定比必要的大),但算法收敛速度很慢。我至少需要知道搜索的大致数字 space 才能使遗传算法有效。

通过反向传播,搜索 space 不是先验的,这无关紧要,但对于 GA 来说它确实如此。

这似乎是对神经网络强化学习核心挑战的重述。你有一个损失函数,它在数值上量化了解决方案 space 的当前局部可能采取的行动有多好,这样当采取行动时将使你 closer/further 远离全局最优(答案). {IE。梯度 w.r.t。损失函数}

在开始之前,您无法知道答案的确切位置,因此您有一个探索策略,您将其定义为算法的一部分。这推动了对可能解决方案的探索 space 以某些行动在接近损失函数定义的答案方面有多大改进为指导。

一开始的探索非常激进,大胆的尝试,以便快速探索解决方案space。然后,随着解决方案的区域 space 变得更有希望,探索变得不那么大胆,试图收敛于解决方案。

在您的情况下,探索策略会改变突变大小、突变率和染色体交叉。突变大小和速率将代表局部内的移动大小,交叉将代表解决方案中的维度转置 space。

因此,您将在解决方案 space 中拥有一个起始位置,而不是 max/min 并假设统一缩放和归一化的解决方案 space 具有最佳猜测是单位中的任何随机点space.

然后探索策略将 select 突变大小、速率和交叉以最初积极地广泛探索。后代的选择会更喜欢那些更接近答案并且探索策略不那么激进的。因此,后几代人往往更接近“答案”,探索策略也不那么激进,因此会趋于收敛。

本文对概念进行了更正式的回顾。

https://towardsdatascience.com/reinforcement-learning-demystified-exploration-vs-exploitation-in-multi-armed-bandit-setting-be950d2ee9f6

这是一个故事。曾经有一个演示文稿,可能是 this 篇论文,介绍了遗传算法如何配置室内飞行的输入、输出和架构。也就是说,它将愚蠢的传感器连接到那些漂浮的室内飞艇上,让它们探索房间,同时优化直线和水平飞行。

本例中的 "genes" 是:

  • 从对标准成像处理过滤器(垂直边缘检测、低对比度、线检测等)的响应列表中选择两个或三个输入值
  • 从每个引擎的标准电压曲线列表中选择两个输出连接(硬 ramp/slow ramp/immediate 到 0%、50%、100%、-50%、-100% 等.)
  • 在两级神经网络中选择节点之间的连接,每层只有五个节点。例如,"input 2 attaches to node 3 in layer 1"。只允许一部分(30%?)的连接。

因此,一个 DNA 由两个输入节点、五十个连接和两个输出节点组成。种群从一百个随机 DNA 选择开始,运行飞艇训练选定的神经网络,计算水平飞行时间,然后繁殖。就品种而言,我的意思是它杀死了得分最低的一半,并创造了获胜者的变异副本。成功了。

现在,关于你的问题。

你需要非常清楚什么可以是你的基因。一些不错的选择可能是:

  • 网络架构,如上文
  • 淘汰赛、学习率、重启、损失函数等的超参数。
  • 初始权重分布,实际上更多的参数,包括一些用于偶尔添加的野生权重。
  • Wild kicks 到一个或另一个参数,这意味着选择一个或两个轴以使用 wild 值或细粒度精度进行搜索。

还要记住突变和杂交育种是不同的。有时你应该允许野生突变。一种常见的策略是繁殖大约 70%(制作副本,交换一些基因)并变异大约 30%(复制幸存者并进行随机更改)。

就像快速建议一样,我猜你的描述中没有说什么。如果我完全不相信你在做什么,假装它是正确的;你是 很可能是解决您问题的人。

根据@a_guest 的评论,我发现使用突变运算符可获得最佳性能,该突变运算符扰乱正态分布附近的基因。我做了三个测试:

  • 干扰基因在 [-1.00, 1.00]
  • 内随机均匀
  • 在染色体中所有基因的平均值附近的正态分布内扰乱基因
  • 在正态分布范围内扰乱被突变基因周围的基因

我已将测试标记为#1、#2、#3。这是在使用 ReLU 激活函数的 4-3-3 网络中使用 Iris 数据集。每个测试一个 运行 并不重要,因为它可能是幸运的也可能是不幸的,因此该图使用的是来自 50 个 运行 样本的三十个最佳 运行 之间的平均值。

您可以看到 BP-NN 提供了一个很好的比较基线。

我的均匀随机变异算子几乎立即陷入局部最小值,因为没有对搜索的探索 space(因为基因永远不会在 [-1, 1] 之外,即我的天真方法我开始了这个问题与).

围绕染色体平均值的高斯算子运行良好,在第 32 轮达到 MSE <= 0.1(比较第 50 轮的反向传播)。突变基因周围的高斯算子也很有效,在第 26 轮达到相同的 MSE 阈值。

我认为围绕基因平均值进行突变比围绕突变基因进行突变更有意义,因为如果您认为一个基因会发生两次突变(两代一次),那么探索就会减少。单个基因发生突变不会对基因平均值产生太大影响,如果一个基因发生第二次突变,也不会增加太多探索。

如果你有一个基因平均值 0.00,一个基因是 0.00,在最末端突变为 2.00,基因平均值可能只发生了轻微的变化(例如.0.10)。下一次突变出现时,基因可能是 2.00,但平均值与 0.00 相差不远。也许第二个突变会将基因扰动到 2.05 的最末端。在特定基因周围使用高斯算子可能会看到它在末端变为 4.00

我认为具有 mu = mutating genesigma = decreasing as MSE decreases 的高斯变异算子是最好的方法。我试过 sigma = 0.7 + MSE 似乎效果很好,至少对于这个数据集是这样,因为最大 MSE 约为 0.7。当 MSE 接近 0 时,探索因子会缩小,这意味着早期会进行更多的探索,而稍后会进行更多的局部开发。这也意味着我不需要定义甚至不知道搜索量。