一般的に使用される最適化アルゴリズム (シミュレーテッド アニーリング、遺伝的アルゴリズム、粒子群アルゴリズム) と Python でのそれらの実装

目次

シミュレーテッド アニーリング アルゴリズム

ステップ

Python 実装

遺伝的アルゴリズム

ステップ

Python 実装

粒子群アルゴリズム

粒子群最適化アルゴリズム

ステップ

Python 実装

推奨読書



シミュレーテッド アニーリング アルゴリズム

Simulated Annealing アルゴリズム (Simulated Annealing) は、複雑な非凸最適化問題を解決するために通常使用されるグローバル最適化アルゴリズムです。基本的な考え方は、局所最適解に陥らないように、ある程度の確率で劣った解を受け入れ、グローバルな範囲で最適解を探すことです。

ステップ

シミュレーテッド アニーリング アルゴリズムの手順は次のとおりです。

各冷却サイクルでは、温度が低下するにつれて劣悪な解を受け入れる確率が徐々に減少し、それによって全体的な最適解に徐々に収束します。ただし、シミュレーテッド アニーリング アルゴリズムの効果と結果は、初期温度、アニーリング速度、終了条件などのパラメーターの設定に大きく依存します。

Python 実装

  以下では、Python を使用してシミュレーテッド アニーリング アルゴリズムを実装する方法を示す例として、1 変数関数のグローバル最小値を解きます 。

最初に目的関数を定義します。

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

関数がどのように見えるかを見てみましょう。

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

シミュレーテッド アニーリング アルゴリズムの定義

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

初期パラメータを設定して解く:

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))

結果は次のとおりです。x_best = -0.2906, f_best = -0.9086

結果はまだ比較的理想的です。

遺伝的アルゴリズム

遺伝的アルゴリズムは、生物学的進化に着想を得た最適化アルゴリズムであり、生物学的進化のプロセスをシミュレートし、自然淘汰と遺伝的操作を通じて問題の解決策を徐々に最適化します。遺伝的アルゴリズムは、一般的に使用される最適化アルゴリズムであり、解決が容易ではない多くの実際的な問題に適しています。優れたグローバル検索能力、強力な適応性、堅牢性を備えていますが、収束速度が遅いなどの欠点もあり、ローカル最適解に陥る可能性があります。

ステップ

遺伝的アルゴリズムの基本的な手順は次のとおりです。

  • 初期母集団: 問題の特性と要件に応じて、一定数の解が初期母集団としてランダムに生成されます。

  • 適合度の評価: 問題の評価関数に従って、各解の適合度がその後の選択と遺伝的操作のために評価されます。

  • 選択操作: 適合度の大きさに応じて、一定数の個体を次世代集団の親として選択します。

  • 遺伝子操作:交叉や突然変異などの操作により、次世代集団の子孫が生成されます。

  • 停止条件が満たされるまでステップ 2 ~ 4 を繰り返します (特定の数の代数に到達する、最適解を見つけるなど)。

以下は、遺伝的アルゴリズムの適用プロセスを紹介する簡単な例です。

関数 として 、区間 [0,15] でこの関数の最大の整数値が必要です。まず、母集団を初期化する必要があります。各個体の遺伝子長が 4 であると仮定すると (つまり、個体は 2 を意味する 0010 などの 4 つの 2 進数で表されます)、1101、0110、0011、0001 などの 4 つの 2 進数をランダムに生成できます。など、初期母集団として。これらの個人によると、10進数に変換することで、対応する関数値を取得できます。例えば、1101に対応する10進数は13で、個体1101の適応度である関数に代入すると、f(13)=242が得られます。

次に、選択を行います。一般的に使用される選択操作には、ルーレット選択、競合選択などがあります。ここでは、ルーレット選択を使用し、個体を適応度に従ってルーレットに割り当て、一定数の個体をランダムに親として選択します。

次に、遺伝子操作(交叉、突然変異など)が行われます。ここでは、一点交叉とビット突然変異を使用します。1101 と 0011 の個体が交差のためにランダムに選択されたと仮定すると、交差ポイントは 2 番目であり、交差後に子孫 1111 と 0001 が得られます。次に、子孫をビット突然変異させます。つまり、ビットをランダムに選択して反転させます。たとえば、1111 の 3 番目のビットが変異され、変異後に子孫 1011 が取得されます。

最後に、親と子のフィットネスを比較して、フィットネスが評価されます。子 1111 と子 1011 の適応度がそれぞれ f(15)=260 と f(11)=142 であるとします。親世代と比較して、子孫の適応度が高い個体が次世代集団のメンバーとして選択されます。

停止条件が満たされるまで、上記の手順を繰り返します。

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)

ここでは、最小値を見つけたいため、フィットネス関数のfitnessを関数値とは異なるものに設定していることに注意してください。このアルゴリズムでは、フィットネス関数が大きいほど良いため、わずかな調整を行いました。

粒子群アルゴリズム

粒子群最適化アルゴリズム

粒子群最適化 (PSO) は、一般的に使用される最適化アルゴリズムであり、鳥の捕食行動の研究に端を発する進化的な計算手法です。このアルゴリズムは、鳥の捕食行動における情報交換と協力をシミュレートすることにより、最適な解決策を探します。具体的には、アルゴリズムは、解空間に一定数の「粒子」をランダムに生成します。各粒子は解を表し、各粒子の位置と速度を継続的に調整して最適解に向かって移動させ、徐々に最適解に近づけます。解決。

ステップ

  • (1) 初期化プロセスに従って、粒子群のランダムな位置と速度を最初に設定します。

  • (2) 各粒子の適応度を計算します。

  • (3) 各粒子について、その適合値をそれが経験した最良の位置の適合値と比較し  、より優れていれば、それを現在の最良の位置とする。 

  • (4) 各粒子について、そのフィットネス値をグローバルに経験されたベスト ポジションのフィットネス値と比較し   、より優れている場合は、それを現在のグローバル ベスト ポジションとする。

  • (5) 2 つの反復式に従って、粒子の速度と位置を進化させます。

  • (6) 終了条件に達していない場合、それは通常、十分な適応度値であるか、事前に設定された最大代数 (Gmax) に達している場合は、ステップ (2) に戻り、それ以外の場合はステップ (7) を実行します。

  • (7) gbest を出力します。

Python 実装

または、[-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()

evaluate_fitness 上記のコードでは、実際には関数値であるフィットネス値を計算する関数が最初に定義されています 。次に、PSO クラスを定義して、粒子群最適化アルゴリズムを実装します。初期化中に、特定の数の粒子がランダムに生成され、それらの適合値が計算されます。次に、各反復で、各粒子の速度と位置が個別に更新され、各粒子の最適位置とグローバル最適位置が更新されます。最後に、最終的なグローバル最適位置を出力します。

最適解は -0.290836630206147 です。

推奨読書

遺伝的アルゴリズム (GA) の基本原理 (qq.com)

シミュレーテッド アニーリング アルゴリズム (SA) の基本原理 (qq.com)

粒子群最適化 (PSO) の基本原則 (qq.com)

さて、以上が3つの重要な最適化アルゴリズムの紹介です。

おすすめ

転載: blog.csdn.net/weixin_64338372/article/details/130024634