Tabla de contenido
algoritmo de recocido simulado
algoritmo de enjambre de partículas
Algoritmo de optimización de enjambre de partículas
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.