Evolutionary Algorithms
进化算法通过选择、交叉和变异演化候选解群体。涵盖主要类型、代码和实际用途。
进化算法 (EA) 是一类优化算法,其模拟自然选择过程。算法会维护一组候选解,使用适应度函数为每个候选解打分,让表现最好的候选解通过重组和随机变异产生后代,并重复许多代,使整个种群逐渐趋向更优解。EA 只需评估候选解,无需计算梯度,因此适用于梯度下降无法处理的问题:离散选择、不可微或含噪的目标,以及充满局部最优解的崎岖空间。因此,EA 是超参数调优、神经架构搜索、工程设计和调度中的常用工具。
进化算法的工作原理#
每种 EA 都由相同的组成部分构成:
- 表示方式:每个候选解都编码为一个基因组,例如比特串、实数向量或程序树。
- 初始化:第一代通常是随机生成的,有时也会加入已知的优质解作为种子。
- 适应度评估:适应度函数会根据待优化的目标为每个候选解打分。
- 选择:适应度更高的候选解更有可能成为父代。例如,锦标赛选择会从几个随机候选解中选出较优者,而精英保留则会将最优解原样复制到下一代。
- 变异:交叉会组合两个父代的部分内容,变异则会进行小幅随机改动,让种群持续探索。
在机器学习 (ML)中,适应度函数通常是验证指标,例如准确率或平均精度均值 (mAP),因此评估一个候选解就意味着训练并测试模型,这远远是最耗时的步骤。循环会持续进行,直到预算耗尽或适应度不再提升:
选择压力和变异强度决定了利用与探索之间的平衡。强选择搭配小幅变异能快速收敛,但可能陷入局部最优;弱选择搭配大幅变异则能广泛探索,但会浪费评估次数。
进化算法的主要类型#
- 遗传算法 (GA):将候选解编码为字符串(通常是比特串),并大量依赖交叉操作。John Holland 在其 1975 年出版的《自然系统与人工系统中的适应》一书中对遗传算法进行了系统阐述。
- 进化策略 (ES):通过高斯变异优化实数向量,并在运行过程中调整步长。CMA-ES 会学习变异分布的完整协方差,是解决连续黑盒问题的最强通用方法之一。
- 遗传编程:对表示为树结构的程序或数学表达式进行进化,可用于符号回归和自动程序设计。
- 神经进化:对神经网络的权重,有时也包括网络结构进行进化。OpenAI 在 2017 年展示,使用一千多个并行工作进程运行的进化策略,可以在 10 分钟内训练一个 3D 人形机器人行走,为强化学习提供了一种可扩展的替代方案。
代码中的遗传算法#
背包问题要求在不超过重量限制的情况下,选择要装入的物品以最大化总价值。这是一个没有梯度的离散问题。这个 NumPy 遗传算法通过锦标赛选择、均匀交叉、位翻转变异和精英保留,对 50 个比特串基因组进行进化,每个位对应一个物品,然后将结果与全部 1,048,576 种可能的选择进行比较:
import itertools
import numpy as np
rng = np.random.default_rng(0)
# Knapsack problem: pick from 20 items to maximize total value within a weight limit of 200
values, weights, limit = rng.integers(10, 100, 20), rng.integers(5, 50, 20), 200
def fitness(pop):
"""Return each selection's total value, or 0 if it exceeds the weight limit."""
return np.where(pop @ weights <= limit, pop @ values, 0)
population = rng.random((50, 20)) < 0.2 # 50 random genomes, one bit per item
for generation in range(100):
scores = fitness(population)
# Tournament selection: each parent is the better of two random genomes
pairs = rng.integers(50, size=(50, 2))
parents = population[np.where(scores[pairs[:, 0]] > scores[pairs[:, 1]], pairs[:, 0], pairs[:, 1])]
# Uniform crossover with the next parent, then flip each bit with probability 0.05
children = np.where(rng.random((50, 20)) < 0.5, parents, np.roll(parents, 1, axis=0))
children ^= rng.random((50, 20)) < 0.05
children[0] = population[scores.argmax()] # elitism: keep the best genome
population = children
all_selections = np.array(list(itertools.product([0, 1], repeat=20)))
print(f"GA best: {fitness(population).max()}, true optimum: {fitness(all_selections).max()}")它会输出 GA best: 811, true optimum: 811。该算法只进行了 5,000 次适应度评估,就找到了最佳装箱方案,约为暴力搜索必须检查的百万种选择的 0.5%。
进化超参数#
学习率、损失权重和增强强度等训练设置会以无法通过公式预测的方式相互影响,而评估每个候选设置都需要完整训练一次,因此很适合采用进化搜索。Ultralytics YOLO 中的 tune() 方法会将这种方式用于 YOLO26模型:每次迭代都会根据适应度加权,从目前最好的九组配置中选出一个父代;然后以与搜索范围相匹配的高斯步长,对默认搜索空间中的 26 个超参数进行变异,其中约一半会受到变异;接着训练模型并记录其适应度,目标检测任务的适应度指标为 mAP50-95。得到 30 个结果后,一些变异还会参考表现最好的 20% 配置的协方差,这种做法借鉴了 CMA-ES。超参数调优指南列出了完整的搜索空间:
from ultralytics import YOLO
# 加载预训练的 YOLO26 nano 模型
model = YOLO("yolo26n.pt")
# 进化超参数:迭代 30 次,每次训练一组经过变异的配置,训练 10 个 epoch
model.tune(data="coco8.yaml", epochs=10, iterations=30, plots=False)调优器会将每组配置及其适应度写入 tune_results.ndjson,并将最佳配置保存到 best_hyperparameters.yaml,供完整训练任务使用。
其他应用#
- 神经架构搜索:Google 的 AmoebaNet 源自正则化进化,这是一种锦标赛选择 EA,会淘汰最早出现的模型,而不是表现最差的模型。2018 年,该方法在 ImageNet 上达到了 83.9% 的 top-1 准确率。
- 工程设计:NASA 的 Space Technology 5 任务于 2006 年搭载了一款通过计算机进化设计的 X 波段天线。它不规则的弯线形状与传统设计天线的性能相当。
- 算法发现:Google DeepMind 于 2025 年 5 月公布的 AlphaEvolve 将提出代码变更的 Gemini 模型、自动评估器和程序进化数据库结合起来。该系统进化出的一种调度启发式算法,平均可为 Google 数据中心回收其全球计算资源的 0.7%。
进化算法与相关方法的区别#
- 梯度下降:沿着可微损失的梯度前进,对于训练拥有数百万参数的网络权重而言效率高得多。EA 适用于参数较少、评估成本高或没有梯度的问题。
- 群体智能:粒子群优化等方法会让一组持续存在的智能体在搜索空间中移动,每个智能体根据自身和邻居的最佳结果调整位置,不进行代际替换、交叉或变异。
- 贝叶斯优化:为目标函数拟合概率模型,并在该模型预测最有可能提升的地方选择下一次试验。在小型、平滑的搜索空间中,它比 EA 所需的评估次数更少,但扩展到大量参数和并行工作进程时表现较差。










