粒子群最適化(Particle Swarm Optimization, PSO)

粒子群最適化(Particle Swarm Optimization, PSO)

粒子群最適化(Particle Swarm Optimization, PSO)は、進化的アルゴリズムの一種で、群知能を利用して最適解を見つける手法です。

具体的な問題として、ここでは以下の二次関数の最小化問題を解いてみます:

$$
f(x, y) = (x - 3)^2 + (y - 2)^2
$$

この関数の最小値を探すことが目的です。

この関数はパラボロイドであり、最小値は点$ ( (3, 2) ) $で$ 0 $となります。


以下にPythonを使ったPSOの具体的なコード例を示します。

このコードでは、PyGMOライブラリを使ってPSOを実装します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import pygmo as pg
import numpy as np
import matplotlib.pyplot as plt

# 最適化したい関数の定義
def objective_function(x):
return (x[0] - 3)**2 + (x[1] - 2)**2

# 問題の定義
class MyProblem:
def fitness(self, x):
return [objective_function(x)]
def get_bounds(self):
return ([-10, -10], [10, 10])

# 問題のインスタンスを作成
prob = pg.problem(MyProblem())

# アルゴリズムの選択 (PSO)
algo = pg.algorithm(pg.pso(gen=100)) # 100世代

# アルゴリズムのインスタンスを作成
algo.set_verbosity(1)

# 集団 (swarm) の定義
pop = pg.population(prob, size=20)

# 最適化の実行
pop = algo.evolve(pop)

# 最適化結果の取得
best_solution = pop.champion_x
best_fitness = pop.champion_f

print(f"Best solution: {best_solution}")
print(f"Best fitness: {best_fitness}")

# グラフの描画
# 評価関数の値をカラーマップでプロット
x = np.linspace(-10, 10, 400)
y = np.linspace(-10, 10, 400)
X, Y = np.meshgrid(x, y)
Z = objective_function([X, Y])

plt.contourf(X, Y, Z, levels=50, cmap='viridis')
plt.colorbar()
plt.plot(best_solution[0], best_solution[1], 'ro') # 最適解を赤い点でプロット
plt.title("Particle Swarm Optimization Result")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

ソースコード解説

1. 必要なライブラリのインポート

1
2
3
import pygmo as pg
import numpy as np
import matplotlib.pyplot as plt

PyGMONumPyMatplotlibライブラリをインポートします。

2. 最適化したい関数の定義

1
2
def objective_function(x):
return (x[0] - 3)**2 + (x[1] - 2)**2

ここで、最小化したい二次関数を定義します。

3. 最適化問題の定義

1
2
3
4
5
class MyProblem:
def fitness(self, x):
return [objective_function(x)]
def get_bounds(self):
return ([-10, -10], [10, 10])

PyGMOが理解できる形式で問題を定義します。
この例では、解の範囲を$ -10 $から$ 10 $とします。

4. 問題インスタンスの作成

1
prob = pg.problem(MyProblem())

最適化問題のインスタンスを作成します。

5. アルゴリズムの選択

1
algo = pg.algorithm(pg.pso(gen=100))  # 100世代

PSOアルゴリズムを選択し、世代数を設定します。

6. アルゴリズムインスタンスの作成

1
algo.set_verbosity(1)

アルゴリズムの詳細な実行状況を表示するように設定します。

7. 集団の定義

1
pop = pg.population(prob, size=20)

解の集団(swarm)を定義します。
ここでは $20$ 個体で初期化します。

8. 最適化の実行

1
pop = algo.evolve(pop)

最適化を実行します。

9. 最適化結果の取得

1
2
3
4
5
best_solution = pop.champion_x
best_fitness = pop.champion_f

print(f"Best solution: {best_solution}")
print(f"Best fitness: {best_fitness}")

最適な解とその評価値を取得し、表示します。

10. グラフの描画

1
2
3
4
5
6
7
8
9
10
11
12
x = np.linspace(-10, 10, 400)
y = np.linspace(-10, 10, 400)
X, Y = np.meshgrid(x, y)
Z = objective_function([X, Y])

plt.contourf(X, Y, Z, levels=50, cmap='viridis')
plt.colorbar()
plt.plot(best_solution[0], best_solution[1], 'ro') # 最適解を赤い点でプロット
plt.title("Particle Swarm Optimization Result")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

評価関数のカラーマップをプロットし、最適解を赤い点で示します。

結果解説

[実行結果]

最適化結果の解釈

  • Best solution: [2.99999768, 2.00000504]

    • これはPSOアルゴリズムによって見つかった最適解です。
      関数$ ( f(x, y) = (x - 3)^2 + (y - 2)^2 ) $の最小値を見つけるために、PSOが探索した結果、最適解が$ ( x \approx 3 ) と ( y \approx 2 ) $に非常に近い値であることが示されています。
  • Best fitness: [3.07979981e-11]

    • これは最適解における関数の値(評価値)です。
      最小化したい関数の最小値は$ 0 $ですが、見つけた最適解での関数値は$ ( 3.07979981 \times 10^{-11} ) $となっています。
      これは非常に小さい値であり、関数の理論的な最小値に非常に近いことを示しています。

グラフの説明

グラフは評価関数の値をカラーマップとしてプロットしたものです。
以下のような特徴があります:

  • カラーマップ:

    • 色の濃淡で関数の値を表しています。

    濃い色の部分が関数の値が低い(小さい)領域を示し、薄い色の部分が関数の値が高い(大きい)領域を示します。

  • 等高線:

    • 関数の等高線をプロットしています。

    等高線は、同じ関数値を持つ点を結んだ線であり、最小値に向かって収束するように見えます。

  • 最適解のプロット:

    • 赤い点最適解を示しています。
      この点が$ ( (2.99999768, 2.00000504) ) $の位置にあります。
      これにより、最適化によって見つけた最適解がグラフ上のどこにあるかが視覚的にわかります。