三种优化算法

        本文将总结遗传算法、粒子群算法、模拟退火三种优化算法的核心思路,并使用python完整实现。实际上,越来越多的优秀算法已经被封装为一个易用的接口。很多时候,一行代码就能实现我们的需求。但了解这些算法的基本逻辑,能够使用最基本的代码实现它。无论对于提升我们的编程能力还是解决问题的能力,都会大有裨益。甚至,改变我们思考问题的方式。

1、遗传算法

        遗传算法,顾名思义,就是借鉴了生物通过遗传变异来逐渐适应环境的这一过程的算法。例如,我们的优化任务中,①就可以使用一个变量表示一个个体,而一组这样的变量就可以表示一个群体。②上一代两个个体的基因组合形成新的个体,就可以用两个变量通过某个操作产生新的变量。③个体按照一定比例发生基因突变,可以按照一定概率修改这些新产生的变量。④越适应环境的个体会越可能被选择,根据适应度函数选择新产生的变量。最终这个群体会越来越适应环境,解也越来越接近最优解。

import random


# 假设目标函数:f(x) = (x-3)^2 + 5,求目标函数最小值
# 设计适应度函数如下。因为我们是求目标最小值,所以目标值越小,适应度越大;也可以在选择操作那里处理
def fitness_function(x):
    return 1/((x-3) ** 2 + 5)


# 初始化种群
def initialize_population(pop_sz, chromosome_len):
    return [[random.randint(0, 1) for _ in range(chromosome_len)] for _ in range(pop_sz)]


# 解码染色体为实数
def decode_chromosome(chromosome):
    return int("".join(map(str, chromosome)), 2) / (2 ** len(chromosome) - 1) * 10 - 5


# 选择操作
def selection(population, fitness_values, inverse=False):
    assert min(fitness_values) > 0
    if inverse:
        fitness_values = [1 / (f + 1e-10) for f in fitness_values]
    total_fitness = sum(fitness_values)
    probabilities = [f / total_fitness for f in fitness_values]
    # 适应度越高的被选择的可能性也越高
    selected = random.choices(population, weights=probabilities, k=len(population))
    return selected


# 交叉操作
def crossover(parent1, parent2):
    point = random.randint(1, len(parent1) - 1)
    # 2个父代产生2个子代,这样可以保证种群数量不变(并不是不可以变化)
    # 这里的基因组合方式也可以修改
    child1 = parent1[:point] + parent2[point:]
    child2 = parent2[:point] + parent1[point:]
    return child1, child2


# 变异操作(随机翻转基因片段的值)
def mutation(chromosome, rate):
    for i in range(len(chromosome)):
        if random.random() < rate:
            chromosome[i] = 1 - chromosome[i]
    return chromosome


# 遗传算法主函数
def genetic_algorithm(pop_sz, chromosome_len, max_gens, rate):
    # 初始化种群
    population = initialize_population(pop_sz, chromosome_len)

    for generation in range(max_gens):
        # 计算适应度
        fitness_values = [fitness_function(decode_chromosome(chromosome)) for chromosome in population]

        # 找到当前最优解(根据实际问题,最大还是最小化)
        best_fitness = max(fitness_values)
        best_chromosome = population[fitness_values.index(best_fitness)]
        best_x = decode_chromosome(best_chromosome)
        if generation % 10 == 0:
            print(f"Generation {generation}: Best Fitness = {best_fitness}, Best x = {best_x}")

        # 选择
        selected_population = selection(population, fitness_values)

        # 交叉
        new_population = []
        for i in range(0, pop_size, 2):
            parent1 = selected_population[i]
            parent2 = selected_population[i + 1]
            child1, child2 = crossover(parent1, parent2)
            new_population.extend([child1, child2])

        # 变异
        population = [mutation(chromosome, rate) for chromosome in new_population]

    return best_x, best_fitness


if __name__ == '__main__':
    # 参数设置
    pop_size = 40  # 种群大小
    chromosome_length = 10  # 染色体长度(长度越长,表达能力越长)
    max_generations = 200  # 最大迭代次数(类似于模型训练次数)
    mutation_rate = 0.01  # 变异概率(类似学习率,一定程度,值越大,越快速接近最优值)

    # 运行遗传算法
    x, y = genetic_algorithm(pop_size, chromosome_length, max_generations, mutation_rate)
    print(f"Final Result: Best x = {x}, Best Fitness = {y}")

2、粒子群算法

        粒子群算法就是模拟一群粒子,他们各自行动(探索),但分享信息。每一个粒子每次行动都可以是随机的,完成一次行动后,通过环境的反馈(适应度函数),粒子可以知道这一步是离目标更远还是更近了(更新该粒子的最优解)。通过分享信息,他们共同更新全局最优解。这样,这一群粒子可以高效地找到最优解,也能避免个别粒子陷入局部最优解。

import random


# 假设目标函数:f(x) = (x+2)^2 + 3,求函数最小值对应的解x
def fitness_function(x):
    return 1/(x+2) ** 2


# 粒子类
class Particle:
    def __init__(self, bounds):
        self.position = random.uniform(bounds[0], bounds[1])  # 随机初始化位置
        self.velocity = random.uniform(-1, 1)  # 随机初始化速度
        self.best_position = self.position  # 个体最优解
        self.best_fitness = fitness_function(self.position)  # 个体最优适应度

    def update_velocity(self, global_best_pos, w, c1, c2):
        # 更新速度
        r1 = random.random()
        r2 = random.random()
        # 在完成最终寻优前,需要综合考虑个体最优和全局最优
        particle = c1 * r1 * (self.best_position - self.position)
        social = c2 * r2 * (global_best_pos - self.position)
        self.velocity = w * self.velocity + particle + social

    def update_position(self, bounds):
        # 更新位置
        self.position += self.velocity
        # 确保位置在边界内
        if self.position < bounds[0]:
            self.position = bounds[0]
        elif self.position > bounds[1]:
            self.position = bounds[1]


# PSO 主函数
def particle_swarm_optimization(num_particles, bounds, max_iterations, w, c1, c2):
    # 初始化粒子群
    particles = [Particle(bounds) for _ in range(num_particles)]
    global_best_position = particles[0].position  # 全局最优解
    global_best_fitness = fitness_function(global_best_position)  # 全局最优适应度

    for iteration in range(max_iterations):
        for particle in particles:
            # 计算适应度
            fitness = fitness_function(particle.position)

            # 更新个体最优解
            if fitness > particle.best_fitness:
                particle.best_fitness = fitness
                particle.best_position = particle.position

            # 更新全局最优解
            if fitness > global_best_fitness:
                global_best_fitness = fitness
                global_best_position = particle.position

        # 更新速度和位置
        for particle in particles:
            particle.update_velocity(global_best_position, w, c1, c2)
            particle.update_position(bounds)

        # 输出当前迭代结果
        print(f"Iteration {iteration}: Best Fitness = {global_best_fitness}, Best Position = {global_best_position}")

    return global_best_position, global_best_fitness


if __name__ == '__main__':
    # 参数设置
    num_particles = 20  # 粒子数量
    bounds = [-5, 5]  # 搜索空间边界
    max_iterations = 100  # 最大迭代次数
    w = 0.5  # 惯性权重(有一定的惯性可以避免振荡)
    c1 = 1.5  # 个体学习因子,控制粒子向个体最优解移动的强度(可能陷入局部最优)
    c2 = 1.5  # 社会学习因子,控制粒子向全局最优解移动的强度

    x, y = particle_swarm_optimization(num_particles, bounds, max_iterations, w, c1, c2)
    print(f"Final Result: Best Position = {x}, Best Fitness = {y}")

3、模拟退火算法

        模拟物理退火过程,物体在高温时,分子活动相对剧烈。即状态改变的可能性和幅度都很大。随着温度降低,分子活动减弱,分子状态改变的可能性和幅度也减小。最终达到平衡态,就相当于算法得到的最优解。

import random
import math


# 假设目标函数:f(x) = (x+1)^2,求函数最小值对应的x
# 这里注意区别,没有取倒数。因为核心函数里更新时,取的是更小的值。
def energy_function(x):
    return (x+1) ** 2


# 邻域搜索:在当前状态附近生成新状态
def neighbor(x, step_size):
    return x + random.uniform(-step_size, step_size)


# 模拟退火算法主函数
def simulated_annealing(initial_state, initial_temp, cooling_rate, min_temp, step_size, max_iterations):
    current_state = initial_state
    current_energy = energy_function(current_state)
    best_state = current_state
    best_energy = current_energy
    temp = initial_temp

    for iteration in range(max_iterations):
        # 生成新状态
        new_state = neighbor(current_state, step_size)
        new_energy = energy_function(new_state)

        # 计算能量差
        energy_delta = new_energy - current_energy

        # 决定是否接受新状态,这里的随机是为了避免陷入局部最优
        # ①能量变化越大,说明离稳态还很远,随机更新可能性越大;②温度逐渐降低,随机更新的可能越来越低。
        # 相当于一开始变化大一点,后面越来越稳定->模拟退火的核心理念
        if energy_delta < 0 or random.random() < math.exp(-energy_delta / temp):
            current_state = new_state
            current_energy = new_energy

        # 更新最优解
        if current_energy < best_energy:
            best_state = current_state
            best_energy = current_energy

        # 降低温度(指数级冷却,也可以均匀冷却——每次下降相同的温度)
        temp *= cooling_rate

        # 输出当前迭代结果
        print(f"Iteration {iteration}: Best State = {best_state}, Best Energy = {best_energy}, Temperature = {temp}")

        # 终止条件:温度低于最低温度
        if temp < min_temp:
            break

    return best_state, best_energy


if __name__ == '__main__':
    # 参数设置
    initial_state = random.uniform(-5, 5)  # 初始状态
    initial_temp = 1000  # 初始温度
    cooling_rate = 0.95  # 冷却速率(值越小,冷却速度越快,但可能冷却不充分。即没有达到最佳效果,没有找到全局最优解)
    min_temp = 1  # 最低温度
    step_size = 0.1  # 邻域搜索步长
    max_iterations = 1000  # 最大迭代次数

    x, y = simulated_annealing(initial_state, initial_temp, cooling_rate, min_temp, step_size, max_iterations)
    print(f"Final Result: Best State = {x}, Best Energy = {y}")

 4、优化算法的作用

        不知道有没有朋友发现一个问题,上述算法或案例中。完全可以使用穷举法,写一个循环去遍历,也可以找到最优值。这些优化算法看起来似乎很鸡肋?并非如此!以排序算法为例,你每拿到一个数,都与已排序数列的每一个数去比较然后确定位置。这种方法能完成排序吗?当然可以!但缺点就是耗时太多。

利用Python实现几种常见排序算法_python 序列 比较 排序-CSDN博客

        回到优化问题里,如果约束条件有n个,每个条件的取值有m个,那么完成全部遍历则需要遍历m^n种可能。

        此外,穷举法在多目标优化时,也无法权衡不同优化目标。也不能适应动态优化场景。比如离散问题的解空间随时间变化,每变化一次,穷举法都需要重新全部计算一次。

你可能感兴趣的:(算法,算法,python,开发语言)