Algoritmos de optimización de uso común (recocido simulado, algoritmo genético, algoritmo de enjambre de partículas) y su implementación en Python

Tabla de contenido

algoritmo de recocido simulado

paso

implementación de Python

algoritmo genético

paso

implementación de Python

algoritmo de enjambre de partículas

Algoritmo de optimización de enjambre de partículas

paso

implementación de Python

Lectura recomendada



algoritmo de recocido simulado

El algoritmo de recocido simulado (Simulated Annealing) es un algoritmo de optimización global, generalmente utilizado para resolver problemas complejos de optimización no convexa. La idea básica es aceptar soluciones inferiores con cierta probabilidad, para evitar caer en la solución óptima local, para buscar la solución óptima en el ámbito global.

paso

Los pasos del algoritmo de recocido simulado son los siguientes:

En cada ciclo de enfriamiento, la probabilidad de aceptar una solución inferior disminuye gradualmente a medida que desciende la temperatura, convergiendo así gradualmente a la solución óptima global. Sin embargo, los efectos y resultados del algoritmo de recocido simulado dependen en gran medida de la configuración de parámetros como la temperatura inicial, la velocidad de recocido y las condiciones de terminación.

implementación de Python

A continuación, se muestra cómo resolver el mínimo global de una función de una variable    como ejemplo para demostrar cómo usar Python para implementar el algoritmo de recocido simulado.

Primero define la función objetivo:

import math
import random
def func(x):
    return x ** 2 + math.sin(5 * x)

Solo eche un vistazo a cómo se ve la función:

import matplotlib.pyplot as plt
import numpy as np
xarray = np.linspace(-5,5,10000)
plt.plot(xarray,[func(x) for x in xarray])

Definir el algoritmo de recocido simulado

def simulated_annealing(func, x0, T0, r, iter_max, tol):
    '''
    func 是目标函数
    x0 是初始解
    T0 是初始温度
    r 是退火速率
    iter_max 是最大迭代次数
    tol 是温度下限
    '''
    
    x_best = x0
    f_best = func(x0)
    T = T0
    iter = 0
    while T > tol and iter < iter_max: # 判断是否达到停止条件
        x_new = x_best + random.uniform(-1, 1) * T # 生成新解
        f_new = func(x_new) # 计算目标函数值(适应度值)
        delta_f = f_new - f_best # 能量差
        if delta_f < 0 or random.uniform(0, 1) < math.exp(-delta_f / T): # 决定是否接受
            x_best, f_best = x_new, f_new
        T *= r # 降温 
        iter += 1 # 增加迭代次数
    return x_best, f_best

Establezca los parámetros iniciales y resuelva:

x0 = 2
T0 = 100
r = 0.95
iter_max = 10000
tol = 0.0001
x_best, f_best = simulated_annealing(func, x0, T0, r, iter_max, tol)
print("x_best = {:.4f}, f_best = {:.4f}".format(x_best, f_best))

El resultado es:x_best = -0.2906, f_best = -0.9086

El resultado sigue siendo relativamente ideal.

algoritmo genético

El algoritmo genético es un algoritmo de optimización inspirado en la evolución biológica, que simula el proceso de evolución biológica y optimiza gradualmente la solución del problema a través de la selección natural y la operación genética. El algoritmo genético es un algoritmo de optimización de uso común, que es adecuado para muchos problemas prácticos que no son fáciles de resolver. Tiene una buena capacidad de búsqueda global, gran adaptabilidad y robustez, pero también tiene algunas desventajas, como una velocidad de convergencia lenta, y puede caer en una solución óptima local.

paso

Los pasos básicos de un algoritmo genético incluyen:

  • Población inicial: De acuerdo a las características y requerimientos del problema, se genera aleatoriamente un cierto número de soluciones como población inicial.

  • Evaluación de la aptitud: De acuerdo con la función de evaluación del problema, se evalúa la aptitud de cada solución para su posterior selección y operaciones genéticas.

  • Operación de selección: de acuerdo con el tamaño de la aptitud, seleccione un cierto número de individuos como padres de la población de la próxima generación.

  • Operación genética: a través de operaciones como el cruce y la mutación, se generan los descendientes de la población de la próxima generación.

  • Repita los pasos 2 a 4 hasta que se cumpla la condición de parada (como llegar a un cierto número de álgebras, encontrar la solución óptima, etc.).

El siguiente es un ejemplo simple para introducir el proceso de aplicación del algoritmo genético.

Como función  , requerimos el valor entero más grande de esta función en el intervalo [0,15]. Primero, necesitamos inicializar la población. Suponiendo que la longitud del gen de cada individuo es 4 (es decir, un individuo está representado por 4 números binarios, como 0010, que significa 2), entonces se pueden generar aleatoriamente 4 números binarios, como 1101, 0110, 0011, 0001 , etc., como población inicial . Según estos individuos, podemos obtener los valores de función correspondientes al convertir a números decimales. Por ejemplo, el número decimal correspondiente a 1101 es 13, y f(13)=242 se obtiene sustituyendo en la función, que es la aptitud del individuo 1101.

A continuación, haga una selección. Las operaciones de selección comúnmente utilizadas incluyen selección de ruleta, selección competitiva, etc. Aquí usamos la selección de ruleta, asignamos individuos a la ruleta de acuerdo con su estado físico y luego seleccionamos aleatoriamente un cierto número de individuos como padres.

Luego, se realizan manipulaciones genéticas (cruzamiento, mutación, etc.). Aquí usamos cruce de un punto y mutación de bits. Suponiendo que los individuos 1101 y 0011 se seleccionan al azar para el cruce, el punto de cruce es el segundo lugar y los descendientes 1111 y 0001 se obtienen después del cruce. Luego, mutamos un poco la descendencia, es decir, elegimos un poco al azar y lo invertimos. Por ejemplo, se muta el tercer bit de 1111 y se obtiene el descendiente 1011 después de la mutación.

Finalmente, se evalúa la aptitud, comparando la aptitud del progenitor y la descendencia. Suponga que la aptitud de la descendencia 1111 y la descendencia 1011 son f(15)=260 y f(11)=142 respectivamente. En comparación con la generación de padres, los individuos con mayor aptitud en la descendencia serán seleccionados como miembros de la población de la próxima generación.

Repita los pasos anteriores hasta que se cumpla la condición de parada.

implementación de Python

import math

def func(x):
    return x**2 + math.sin(5*x)

def fitness(x):
    return 30-(x**2 + math.sin(5*x))
import random

POPULATION_SIZE = 50
GENE_LENGTH = 16

def generate_population(population_size, gene_length):
    population = []
    for i in range(population_size):
        individual = [random.randint(0, 1) for j in range(gene_length)]
        population.append(individual)
    return population

population = generate_population(POPULATION_SIZE, GENE_LENGTH)
def crossover(parent1, parent2):
    crossover_point = random.randint(0, GENE_LENGTH - 1)
    child1 = parent1[:crossover_point] + parent2[crossover_point:]
    child2 = parent2[:crossover_point] + parent1[crossover_point:]
    return child1, child2

def mutation(individual, mutation_probability):
    for i in range(GENE_LENGTH):
        if random.random() < mutation_probability:
            individual[i] = 1 - individual[i]
    return individual

def select_parents(population):
    total_fitness = sum([fitness(decode(individual)) for individual in population])
    parent1 = None
    parent2 = None
    while parent1 == parent2:
        parent1 = select_individual(population, total_fitness)
        parent2 = select_individual(population, total_fitness)
    return parent1, parent2

def select_individual(population, total_fitness):
    r = random.uniform(0, total_fitness)
    fitness_sum = 0
    for individual in population:
        fitness_sum += fitness(decode(individual))
        if fitness_sum > r:
            return individual
    return population[-1]
def decode(individual):
    x = sum([gene*2**i for i, gene in enumerate(individual)])
    return -5 + 10 * x / (2**GENE_LENGTH - 1)

GENERATIONS = 100
CROSSOVER_PROBABILITY = 0.8
MUTATION_PROBABILITY = 0.05

def genetic_algorithm():
    population = generate_population(POPULATION_SIZE, GENE_LENGTH)
    for i in range(GENERATIONS):
        new_population = []
        for j in range(int(POPULATION_SIZE/2)):
            parent1, parent2 = select_parents(population)
            if random.random() < CROSSOVER_PROBABILITY:
                child1, child2 = crossover(parent1, parent2)
            else:
                child1, child2 = parent1, parent2
            child1 = mutation(child1, MUTATION_PROBABILITY)
            child2 = mutation(child2, MUTATION_PROBABILITY)
            new_population.append(child1)
            new_population.append(child2)
        population = new_population
    best_individual = max(population, key=lambda individual: fitness(decode(individual)))
    best_fitness = fitness(decode(best_individual))
    best_x = decode(best_individual)
    best_func = func(best_x)
    return best_x, best_fitness,best_func

best_x, best_fitness,best_func = genetic_algorithm()

print("x = ", best_x)
print("最大适应度为", best_fitness)
print("函数值为",best_func)

Tenga en cuenta que configuré la función de aptitud aptitud diferente del valor de la función aquí, porque queremos encontrar el valor mínimo, y la función de aptitud es cuanto más grande, mejor en este algoritmo, así que hice un ligero ajuste.

algoritmo de enjambre de partículas

Algoritmo de optimización de enjambre de partículas

La optimización de enjambre de partículas (PSO) es un algoritmo de optimización de uso común. Es una técnica de computación evolutiva, que se originó a partir del estudio del comportamiento de depredación de aves. El algoritmo busca la solución óptima simulando el intercambio de información y la cooperación en el comportamiento de depredación de aves. Específicamente, el algoritmo genera aleatoriamente un cierto número de "partículas" en el espacio de la solución, cada partícula representa una solución, y luego ajusta continuamente la posición y la velocidad de cada partícula para que se muevan hacia la solución óptima, acercándose así gradualmente a la solución óptima. solución.

paso

  • (1) Establecer inicialmente la posición aleatoria y la velocidad del enjambre de partículas de acuerdo con el proceso de inicialización;

  • (2) Calcular el valor de aptitud de cada partícula;

  • (3) Para cada partícula, compare su valor de aptitud con el valor de aptitud de la mejor posición que haya experimentado   y, si es mejor, tómela como la mejor posición actual; 

  • (4) Para cada partícula, compare su valor de aptitud con el valor de aptitud de la mejor posición experimentada globalmente    , y si es mejor, tómela como la mejor posición global actual;

  • (5) Evolucionar la velocidad y la posición de la partícula según dos fórmulas iterativas;

  • (6) Si no se alcanza la condición final, generalmente es un valor de fitness suficientemente bueno o alcanza un álgebra máxima preestablecida (Gmax), regrese al paso (2); de lo contrario, ejecute el paso (7)

  • (7) salida gmejor.

implementación de Python

O encuentre el valor mínimo de la función en [-5,5]

import numpy as np

def evaluate_fitness(x):
    return x ** 2 + np.sin(5*x)

class PSO:
    def __init__(self, n_particles, n_iterations, w, c1, c2, bounds):
        self.n_particles = n_particles
        self.n_iterations = n_iterations
        self.w = w
        self.c1 = c1
        self.c2 = c2
        self.bounds = bounds

        self.particles_x = np.random.uniform(bounds[0], bounds[1], size=(n_particles,))
        self.particles_v = np.zeros_like(self.particles_x)
        self.particles_fitness = evaluate_fitness(self.particles_x)
        self.particles_best_x = self.particles_x.copy()
        self.particles_best_fitness = self.particles_fitness.copy()

        self.global_best_x = self.particles_x[self.particles_fitness.argmin()]

    def update_particle_velocity(self):
        r1 = np.random.uniform(size=self.n_particles)
        r2 = np.random.uniform(size=self.n_particles)

        self.particles_v = self.w * self.particles_v + \
            self.c1 * r1 * (self.particles_best_x - self.particles_x) + \
            self.c2 * r2 * (self.global_best_x - self.particles_x)

        self.particles_v = np.clip(self.particles_v, -1, 1)

    def update_particle_position(self):
        self.particles_x = self.particles_x + self.particles_v

        self.particles_x = np.clip(self.particles_x, self.bounds[0], self.bounds[1])

        self.particles_fitness = evaluate_fitness(self.particles_x)

        better_mask = self.particles_fitness < self.particles_best_fitness
        self.particles_best_x[better_mask] = self.particles_x[better_mask]
        self.particles_best_fitness[better_mask] = self.particles_fitness[better_mask]

        best_particle = self.particles_fitness.argmin()
        if self.particles_fitness[best_particle] < evaluate_fitness(self.global_best_x):
            self.global_best_x = self.particles_x[best_particle]

    def run(self):
        for i in range(self.n_iterations):
            self.update_particle_velocity()
            self.update_particle_position()

            #print("Iteration:", i, "Global Best:", self.global_best_x)

        return self.global_best_x

pso = PSO(n_particles=20, n_iterations=50, w=0.7, c1=1.4, c2=1.4, bounds=(-5, 5))
global_best_x = pso.run()

En el código anterior, primero se define una función  evaluate_fitness para calcular el valor de aptitud, que en realidad es el valor de la función. Luego, se define una clase PSO para implementar el algoritmo de optimización de enjambre de partículas. Durante la inicialización, se genera aleatoriamente un cierto número de partículas y se calculan sus valores de aptitud. Luego, en cada iteración, la velocidad y la posición de cada partícula se actualizan por separado, y la posición óptima de cada partícula y la posición óptima global se actualizan. Finalmente, generamos la posición óptima global final.

La solución óptima es: -0.290836630206147.

Lectura recomendada

Principios básicos del algoritmo genético (GA) (qq.com)

Principios básicos del algoritmo de recocido simulado (SA) (qq.com)

Principios básicos de optimización de enjambre de partículas (PSO) (qq.com)

Bueno, lo anterior es la introducción de tres importantes algoritmos de optimización.

Supongo que te gusta

Origin blog.csdn.net/weixin_64338372/article/details/130024634
Recomendado
Clasificación