遗传算法 Python 3.11 实战:5步实现函数优化,对比梯度下降收敛速度
·
遗传算法Python 3.11实战:5步实现函数优化与梯度下降对比
1. 遗传算法核心原理与Python实现框架
遗传算法(Genetic Algorithm, GA)是一种模拟自然选择机制的优化算法,它通过模拟生物进化过程中的选择、交叉和变异等操作来寻找最优解。与传统的梯度下降法不同,GA不依赖于目标函数的梯度信息,特别适合处理非连续、非凸、多峰等复杂优化问题。
在Python 3.11中实现遗传算法,我们需要构建以下核心组件:
import numpy as np
import matplotlib.pyplot as plt
from typing import List, Callable, Tuple
class Individual:
def __init__(self, gene: np.ndarray):
self.gene = gene # 染色体编码
self.fitness = 0.0 # 适应度值
class GeneticAlgorithm:
def __init__(self,
population_size: int,
gene_length: int,
fitness_func: Callable,
crossover_rate: float = 0.8,
mutation_rate: float = 0.01):
self.population_size = population_size
self.gene_length = gene_length
self.fitness_func = fitness_func
self.crossover_rate = crossover_rate
self.mutation_rate = mutation_rate
关键参数说明 :
| 参数 | 类型 | 说明 | 典型值 |
|---|---|---|---|
| population_size | int | 种群规模 | 50-200 |
| gene_length | int | 基因长度 | 根据问题维度 |
| fitness_func | Callable | 适应度函数 | 自定义 |
| crossover_rate | float | 交叉概率 | 0.7-0.9 |
| mutation_rate | float | 变异概率 | 0.001-0.1 |
2. 完整遗传算法实现步骤
2.1 初始化种群
def initialize_population(self) -> List[Individual]:
"""初始化种群"""
population = []
for _ in range(self.population_size):
gene = np.random.uniform(-5.12, 5.12, self.gene_length) # 以Rastrigin函数为例
individual = Individual(gene)
population.append(individual)
return population
2.2 适应度评估
Rastrigin函数是常用的测试函数,具有多个局部极小点:
def rastrigin(x: np.ndarray) -> float:
"""Rastrigin函数"""
A = 10
return A * len(x) + np.sum(x**2 - A * np.cos(2 * np.pi * x))
def evaluate_fitness(self, population: List[Individual]):
"""评估种群适应度"""
for individual in population:
individual.fitness = 1 / (1 + rastrigin(individual.gene)) # 转换为最大化问题
2.3 选择操作(轮盘赌选择)
def selection(self, population: List[Individual]) -> List[Individual]:
"""轮盘赌选择"""
fitness_sum = sum(ind.fitness for ind in population)
probabilities = [ind.fitness / fitness_sum for ind in population]
selected = np.random.choice(population, size=len(population), p=probabilities)
return selected.tolist()
2.4 交叉操作(模拟二进制交叉)
def crossover(self, parent1: Individual, parent2: Individual) -> Tuple[Individual, Individual]:
"""模拟二进制交叉(SBX)"""
if np.random.rand() > self.crossover_rate:
return parent1, parent2
child1_gene = np.zeros_like(parent1.gene)
child2_gene = np.zeros_like(parent2.gene)
for i in range(self.gene_length):
if np.random.rand() < 0.5:
if abs(parent1.gene[i] - parent2.gene[i]) > 1e-10:
if parent1.gene[i] < parent2.gene[i]:
x1, x2 = parent1.gene[i], parent2.gene[i]
else:
x1, x2 = parent2.gene[i], parent1.gene[i]
beta = 1.0 + (2.0 * (x1 - (-5.12)) / (x2 - x1))
alpha = 2.0 - beta**(-5)
u = np.random.rand()
if u <= 1.0/alpha:
beta_q = (u * alpha)**(1.0/5)
else:
beta_q = (1.0/(2.0 - u * alpha))**(1.0/5)
child1_gene[i] = 0.5*((x1 + x2) - beta_q*abs(x2 - x1))
beta = 1.0 + (2.0 * (5.12 - x2) / (x2 - x1))
alpha = 2.0 - beta**(-5)
u = np.random.rand()
if u <= 1.0/alpha:
beta_q = (u * alpha)**(1.0/5)
else:
beta_q = (1.0/(2.0 - u * alpha))**(1.0/5)
child2_gene[i] = 0.5*((x1 + x2) + beta_q*abs(x2 - x1))
else:
child1_gene[i] = parent1.gene[i]
child2_gene[i] = parent2.gene[i]
else:
child1_gene[i] = parent1.gene[i]
child2_gene[i] = parent2.gene[i]
return Individual(child1_gene), Individual(child2_gene)
2.5 变异操作(多项式变异)
def mutation(self, individual: Individual) -> Individual:
"""多项式变异"""
mutated_gene = individual.gene.copy()
for i in range(self.gene_length):
if np.random.rand() < self.mutation_rate:
u = np.random.rand()
delta_q = (2*u)**(1/21) - 1 if u < 0.5 else 1 - (2*(1-u))**(1/21)
mutated_gene[i] += delta_q * (5.12 - (-5.12))
mutated_gene[i] = np.clip(mutated_gene[i], -5.12, 5.12)
return Individual(mutated_gene)
3. 完整算法流程与可视化实现
def run(self, max_generations: int = 100):
"""运行遗传算法"""
population = self.initialize_population()
self.evaluate_fitness(population)
best_fitness = []
avg_fitness = []
for gen in range(max_generations):
# 选择
selected = self.selection(population)
# 交叉
new_population = []
for i in range(0, len(selected), 2):
if i+1 < len(selected):
child1, child2 = self.crossover(selected[i], selected[i+1])
new_population.extend([child1, child2])
else:
new_population.append(selected[i])
# 变异
population = [self.mutation(ind) for ind in new_population]
self.evaluate_fitness(population)
# 记录统计信息
current_fitness = [ind.fitness for ind in population]
best_fitness.append(max(current_fitness))
avg_fitness.append(np.mean(current_fitness))
if gen % 10 == 0:
print(f"Generation {gen}: Best Fitness = {best_fitness[-1]:.4f}")
# 可视化收敛曲线
plt.figure(figsize=(10, 6))
plt.plot(best_fitness, label='Best Fitness')
plt.plot(avg_fitness, label='Average Fitness')
plt.xlabel('Generation')
plt.ylabel('Fitness')
plt.title('Genetic Algorithm Convergence')
plt.legend()
plt.grid()
plt.show()
best_individual = max(population, key=lambda x: x.fitness)
return best_individual
4. 与梯度下降法的对比实验
为了全面比较遗传算法和梯度下降法的性能,我们设计以下实验:
def gradient_descent(func: Callable,
grad_func: Callable,
initial_point: np.ndarray,
learning_rate: float = 0.01,
max_iter: int = 1000,
tol: float = 1e-6) -> Tuple[np.ndarray, List[float]]:
"""梯度下降法实现"""
x = initial_point.copy()
history = [func(x)]
for _ in range(max_iter):
grad = grad_func(x)
x_new = x - learning_rate * grad
if np.linalg.norm(x_new - x) < tol:
break
x = x_new
history.append(func(x))
return x, history
# Rastrigin函数的梯度
def rastrigin_grad(x: np.ndarray) -> np.ndarray:
A = 10
return 2 * x + 2 * np.pi * A * np.sin(2 * np.pi * x)
# 对比实验
def compare_methods():
# 遗传算法
ga = GeneticAlgorithm(population_size=50,
gene_length=2,
fitness_func=lambda x: 1/(1+rastrigin(x)))
best_ga = ga.run(max_generations=100)
# 梯度下降法
initial_point = np.random.uniform(-5.12, 5.12, 2)
best_gd, gd_history = gradient_descent(rastrigin, rastrigin_grad, initial_point)
# 可视化对比
plt.figure(figsize=(10, 6))
plt.plot([1/(1+f) for f in gd_history], label='Gradient Descent')
plt.plot(ga.best_fitness, label='Genetic Algorithm')
plt.xlabel('Iteration/Generation')
plt.ylabel('Fitness (1/(1+f(x)))')
plt.title('Comparison of GA and Gradient Descent')
plt.legend()
plt.grid()
plt.show()
print(f"GA Best Solution: {best_ga.gene}, Fitness: {best_ga.fitness:.6f}")
print(f"GD Best Solution: {best_gd}, Function Value: {rastrigin(best_gd):.6f}")
性能对比关键指标 :
| 指标 | 遗传算法 | 梯度下降法 |
|---|---|---|
| 全局搜索能力 | 强(多起点并行) | 弱(单起点) |
| 局部精修能力 | 较弱 | 强 |
| 函数要求 | 无需梯度 | 需要可微 |
| 计算开销 | 较高(群体计算) | 较低 |
| 参数敏感性 | 中等 | 高(依赖学习率) |
| 早熟收敛风险 | 存在 | 局部极小风险 |
5. 实战技巧与参数调优
5.1 遗传算法参数优化指南
交叉概率与变异概率的平衡 :
- 高交叉概率(>0.9)+ 低变异概率(<0.01):适合简单问题,快速收敛但易陷入局部最优
- 中等交叉概率(0.7-0.8)+ 中等变异概率(0.01-0.05):平衡探索与开发
- 低交叉概率(<0.6)+ 高变异概率(>0.1):增强多样性但收敛慢
提示:实际应用中建议采用自适应参数策略,随着进化代数动态调整交叉和变异概率
5.2 精英保留策略实现
def elitism(self, population: List[Individual], new_population: List[Individual],
elite_size: int = 2) -> List[Individual]:
"""精英保留策略"""
combined = population + new_population
combined.sort(key=lambda x: x.fitness, reverse=True)
return combined[:len(new_population)]
5.3 并行化加速技巧
利用Python的multiprocessing模块实现种群评估的并行化:
from multiprocessing import Pool
def parallel_evaluate(self, population: List[Individual]):
"""并行评估适应度"""
with Pool() as p:
fitness_values = p.map(self.fitness_func, [ind.gene for ind in population])
for ind, fit in zip(population, fitness_values):
ind.fitness = fit
5.4 针对高维问题的改进策略
当处理高维优化问题时(维度>50),传统遗传算法效率会显著下降。可以采用以下改进措施:
- 分块进化 :将高维向量分成若干块,分别进化后再组合
- 协同进化 :不同种群进化不同维度,定期交换信息
- 局部搜索混合 :在遗传算法后期加入局部搜索步骤
def hybrid_optimization(self, max_generations: int, local_search_start: int = 0.8):
"""混合遗传算法与局部搜索"""
# ...遗传算法主循环...
if gen > max_generations * local_search_start:
# 对优秀个体进行局部搜索
for ind in sorted(population, key=lambda x: x.fitness, reverse=True)[:5]:
optimized, _ = gradient_descent(rastrigin, rastrigin_grad, ind.gene)
ind.gene = optimized
ind.fitness = 1 / (1 + rastrigin(optimized))
遗传算法与梯度下降法的结合可以发挥各自优势,在全局探索和局部开发之间取得良好平衡。这种混合策略在实际工程优化问题中往往能取得比单一算法更好的效果。
更多推荐
所有评论(0)