シミュレーテッド アニーリング

目次

第1章 シミュレーテッド アニーリング法とは

確率的最適化法は、ランダム サーチ(random search)の現代版である。

ランダム サーチというのは、試行錯誤を多数回くりかえして、 その中でたまたま一番うまくいったものを最適と見なそうというやりかたである。 ランダム サーチは、どんな場面でも適用できる、汎用性を備えている。 そのかわり、より洗練された方法に比べて極端に能率が悪いことが多い。 確率的最適化法には、そこを効率化する工夫が入っている。

効率化の工夫は、 自然界でうまくいっているランダム サーチのまねから始まる。 たとえば生物の進化は突然変異と自然淘汰という試行錯誤によっている。 そのまねをする計算法は古くからいろいろある。 それらをまとめて遺伝的算法(genetic algorithms)とよんでいる。 また、規則的な結晶は分子のでたらめな運動による試行錯誤の結果としてできあがる。 そのまねが、シミュレーテッド アニーリング(simulated annealing)である。 和訳して疑似焼き戻し法と呼ばれることもある。 以降、単にアニーリングと呼ぶ。

アニーリングは、 大規模な組合せ最適化問題を解くために最も広く使われている確率的最適化法である。 ゲート アレーの配置問題、巡回セールスマン問題等への応用が注目されている。 アニーリングによって、今まで解けなかった広範囲な実用上の問題が、 解けるようになる可能性がある。 例えば、半導体製造工程における品種別の材料投入量の割付けや、 基板への部品挿入手順の計画などである。

ここで、まとめると。 まず第1に、アニーリングは CAD などで実用化され、 代表的な確率的最適化手法であること。 第2に、家電製品から、システム製品まで、 広範囲に応用が急速に拡大する可能性があること。 第3に、ニューラル ネットワーク, 学習機械など、 他の研究と関連が深いことがある。

(シミュレーテッド アニーリングやジェネティック アルゴリズムは、 確率を含まないシステムを確率的な方法で最適化しようとする。 確率的最適化法という言葉は、 このような方法を指す言葉として一般に通用しているわけではない。 たとえば、入力に対して出力が確率的なシステムを 最適化する方法を指して確率的最適化法とよぶことがある。 この 2 つは全く別ものなので、混乱しないように注意されたい。)

第2章 確率的最適化

確率的算法(probabilistic algorithm)とは、以下に述べるようなものである。 従来の決定論的な算法で正確な解を求めようとすると、 計算量の爆発が起きて、手におえないような問題を考える。 そのとき、正確な解を求めることをあきらめて、近似解で良いことにする。 しかも、ここで言う「近似」の意味を、 通常の「正確な解に近い」という意味ではなく、それよりも弱い、 「正確な解に近い確率が高い」という意味にとらえることにする。

このように要求を弱めると、正確な解に近い確率が十分高くなったなら、 計算を打ち切れることになる。 そのため、あくまでも正確な解を求めるよりは計算量が減って、 実用的な時間で何らかの答えが得られるようになることがある。 アニーリングは、確率的算法の一種である。

アニーリングは、一般的な最適化問題を扱う。 すなわち、次の形の問題である。

D := 領域
R := 実数全体
f  :   D→R
として、
f(x)→最小 

アニーリングは、厳密な最適解の求められないような複雑な問題 (典型的には、たとえば NP-困難とよばれるクラスに属する組合せ問題) について、確率的な意味での最適化を行なうために作られた計算法である。

通常のアニーリングでは領域 D が、 たとえば後出の巡回セールスマン問題なら 「n 個の都市をそれぞれ 1 度ずつ訪問する順番の全体」 といったように、離散的である。 しかし、連続領域に対応できるように改良することも研究されている。 これについては「連続系の場合」の項で説明する。 以降、特に断らない限り、離散の領域を考えるものとする。

従来の数理計画法に比べてアニーリングの優れている点は、 目的関数や制約条件が自由にとれることである。 例えば、代表的な数理計画法である線形計画法[今87]を考える。 これは製油所や化学工場の生産計画には極めて有用な道具である。 しかし、半導体の生産計画のような問題に対しては、領域が連続でない、 目的関数が一次式にならない、制約が一次不等式でないなどのため、 使えないことが多い。 アニーリングならば、そのような条件は、ほとんど問題にならないくらい弱い。

第3章 巡回セールスマン問題

離散系における最適化問題の例として、 巡回セールスマン問題を説明する。

セールスマンが巡回する n 個の都市がある。 セールスマンはある都市から巡回を始め、 全ての都市を回って出発した都市に帰って来る。 その際になるべく全行程の距離を短くするよう、 各々の都市を回る順番を決定したい。 この場合、全都市を巡回するルートの数は(n-1)! になり (2つの都市間で往復の距離が同じ場合はこの2分の1)n=10 のとき、 ルートの数は30万以上になるので、全数探索は問題外である。

巡回セールスマン問題を、最適化問題に定式化すると次の様になる。

要素 n 個の都市 i (i=1,2, ... , n)
各要素の状態 各々の都市の順番x
システムの状態ルート(順番) X (X=(x₁, ... ,xₙ))
評価関数 全行程の距離 f(X)

第4章 Move とは

Move とは、ある状態 Xc (カレント状態)を少しだけ変更して、 Xn(次の状態)得る操作のことである。 例えば、巡回セールスマン問題では、 ひとつのルートの内の2つの都市の順番だけを入れ換えるような操作が、 これにあたる。

Move は次の条件を満たさなければならない。

1番目の条件が成立しなければ、 評価できない状態が存在することになり、 確率的にも最適解が得られない。 2番目の条件が成立しない場合、 局所的な最適解が高い山に囲まれることになるので、 局所的な最適解から、大域的な最適解へ到達するのが難しくなる。 たとえば巡回セールスマン問題なら、 ある巡回経路が与えられたとき、 図4.1のように点 A と点 B の訪問順序を単に交換する(swap)よりも、 図4.2のように点 A と点 B の間の点の訪問順序を逆転してしまう (reverse)方が良いことが知られている。

A→B→C→D→E→F→G        A→B→C→D→E→F→G

A→→→→→→→F
       ←←←←            A→→→→→→→F
      C→D→E                  ←C←D←E←
    ←←←←                  B→→→→→→→G
   B→→→→→→→G

図4.1 BとFをSWPで入替える  図4.2 BとFをREVで入替える

第5章 温度とアルゴリズム

アニ-リングの基本的アルゴリズムは、 確率的繰り返しによって最適解を求める。 しかし、アニ-リングは、 いわゆる温度というコントロ-ル パラメタを系に与え、 温度を上手に下げることによって、 状態を評価関数の低い方へと移行し、 最終的には局所最適解に捕われることなく、 評価関数の大域最適な状態へ収束することを目指している。 具体的なアルゴリズムを図5.1に示す。

procedure アニーリング;
begin
  初期化(状態,温度,生成回数);
  repeat
    for 生成回数 do
    begin
      Move(次の状態 from 状態);
      if 評価関数(次の状態) < 評価関数(状態) then
        状態 := 次の状態
      else
                        評価関数(状態)-評価関数(次の状態)
        if 乱数(0,1]<exp---------------------------------then
                                    温度
          状態:=次の状態
    end
    設定(生成回数,温度);
  until 終了基準
end;
図5.1:アニーリング アルゴリズム

このように確率的に状態を変更すると、 元の状態の評価関数よりも必ずしも低くくない状態になる場合がある。 そのため、状態は局所的な最適から這い出して、 大域的な最適に向かうことができる。

外のループは、状態の温度を徐々に下げながら繰り返し行われる。 温度を急激に下げると、ローカル ミニマへ収束するので、 十分にゆっくり温度を下げなければならない。 一方、ゆっくり温度を下げるということは、 繰り返し計算に莫大な時間がかかるということになる。

第6章 アルゴリズムの効率化

アニーリングに話を限ると、所与の問題を解くための計算時間は、 温度の下げ方と Move の取り方に大きく依存する。

温度の下げ方については、改良の余地が大きく、 主に欧米で研究が急速に進行している。 現在の研究は、 「温度の下げ方は具体的な問題にはよらない」 という形になるように進められている。 これは、汎用の最適化法を求めるなら、当然の方向である。 具体的には、計算の進行中にさまざまな統計を取り、 その値によって温度を下げる時期を決めている。 そこで用いられているのは漸近理論であって、 標本が大きいときに成り立つ性質を利用する。 しかし一定の温度で実際に得られる標本は必ずしも大きくない。 したがって、適応推定や頑健推定をとりいれれば、 より鋭い下げ方が得られよう。

Move の取り方については、 「目的関数があまり動かないようにとるのが良い」ということ以外、 あまり知られていないらしい。 これは個々の問題に依存するためなのか、 あるいはノウ ハウに属することだからなのか、わからない。 いずれにしろ現段階では、いろいろ実験してみるよりしかたがない。

温度の下げ方と Move のとりかたと、 どちらを追求するのが効率が良いか。 温度の下げ方は汎用で理論的なので、 研究結果の情報は黙っていても注意さえしていれば数年の遅れで入って来る。 Move については、当分そうはならない。 しかも、Move が計算時間に及ぼす影響は、 温度の下げ方に勝るとも劣らない。 結局、一般理論よりも個別の問題に注目するなら、 Move のとり方に凝る方が、温度の下げ方に凝るよりも効率が良い。

第7章 アニーリングのパラメータ

以下に、アニーリングのパラメータの意味を示す。

Sample
ここで、指定した数だけランダムにシステムを生成し、評価をする。 ここを大きくすることの効果は以下のとおり。
  1. 空間全体をまんべんなく調べられる
  2. アニーリングの初期温度を適切に選べる
しかし、1000 以上指定しても、2.の効果は上がらなくなる。 また、1.の効果も、アニーリングと比較した場合、効果的とはいえなくなる。 例題のように、小さい問題では、 この Sample の段階で最適解が求まる場合がある。 アニーリングはあくまでも、 巨大な空間を対象にしたアルゴリズムなので、 この時点で最適値を得ようとは思わないこと。 デフォルトの 384 がちょうど良い。
Crit
ここの精度は、評価関数に比例した値で指定する。 例えば、100000と 100100 の違いが問題になり、 100000 と 100010 の違いが問題にならないならば、 10 を指定する。
OptiScore
あらかじめ、大域最適解の評価関数値がわかっている時は、 その値を指定する。最適化中、 この値と等しい大域最適解を得た時点でプログラムは終了する。
Gamma, Multi, MinLoop
これらのパラメータを変更する必要は、ほとんどない。 Gamma を小さくすれば、きめ細かく温度が下がるようになり、 最適解を得る確率は高くなる。 Multi を大きくすれば LoopSize が長くなり、 最適解を得る確率が高くなる。 Multi を小さくしすぎると、LoopSize が 50 以下になり、 次の温度や、終了条件を決める統計量を正しく推測できなくなる。 Multi のデフォルトは 10 である。デフォルトの場合、 巡回セールスマン問題なら、ほぼ確実に最適解に到達する。 例えば、都市数が 14 ならば、約 95 % の確率で到達する。 しかも、Pentium!!! 550MHz の場合、0.02 秒で到達する。 最適解にこだわらす、計算を速くしたければ、Multi を 4 にするとよい。 MinLoop は LoopSize の最小値を決める。
MaxCount
パラメータの設定によっては、 実用時間ないにアルゴリズムが収束しなくなる場合がある。 このような時でも、強制的に計算を終了し解析を行なうためには、 この MaxCount で終了させるのが便利である。 問題の質や、マシンの速さに合せて、適当な値を決める。 目安として、8086 マシンならば、10000 回くらい。 SPARC ならば、100000 回位がよい。
Smooth
アニーリングの終了は、分散の推定値できまる。 分散の平均をそのまま用いる場合(Smooth=1.0)、 推定値が確率的に不安定なので、 突然終了する危険がある。 これを避けるために、現在の推定値と、 過去の推定値とを Smooth の値に従って混ぜる。 デフォルトの 0.20 がちょうど良い。
EpsiList
評価関数を計算毎に経過報告する変数のリスト
InitList
当たりを付けるための統計量の経過報告する変数のリスト
MetList
アニーリング チェーンの収束状況の経過報告する変数のリスト

第8章 アニーリングの実行

関数 Anneal の引数として、「評価関数」と「Move」を指定する。 「Move」は、現在8通りの方法がある。指定方法は以下の通り。

  1. Anneal UserGoalFunc PartiMove Ivec Int
  2. Anneal UserGoalFunc WalkMove Ivec1 Ivec2 Ivec3
  3. Anneal UserGoalFunc PermuMove Cvec SWP
  4. Anneal UserGoalFunc PermuMove Cvec REV
  5. Anneal UserGoalFunc PermuMove Cvec1 SWP Cvec2 SWP
  6. Anneal UserGoalFunc PermuMove Cvec1 SWP Cvec2 REV
  7. Anneal UserGoalFunc PermuMove Cvec1 REV Cvec2 SWP
  8. Anneal UserGoalFunc PermuMove Cvec1 REV Cvec2 REV
UserGoalFunc
評価関数である。 あらかじめ定義されていないので、C言語で記述すること。 好きな名前で pdef.h に登録すること。 記述の最後で、求まった評価関数値を CurrScore に代入すること。
PartiMove
分割による Move。 anneal.h と anneal.c に定義されている。 複数の箱に玉をどのように入れるかを決めるような問題に応用する。 箱は Ivec で表される。 Ivec の各要素に、玉がどれだけはいっているかが表される。 Int は玉が全体でどれだけあるかを示す。
WalkMove
多次元ランダム ウォークによる Move。 anneal.h と anneal.c に定義されている。 引数にとる Ivec1,Ivec2,Ivec3 は同じサイズでなければならない。 これらは、定義されていないので、pdef.h に好きな名前で登録すること。 WalkMove は、Ivec の要素をからランダムに一つを選ぶ。 そして、Max と Min の範囲内で1だけ加減する。
PermuMove
並べ換えによるMove。 anneal.h と anneal.c に定義されている。 引数に1つか2つの Cvec 型 (全ての要素がコードであるようなベクトル。 ノードの名前を定義した Cdef 型も必要) がとれる。    これらは、定義されていないので、好きな名前で登録すること。 SWP と REV はそれぞれ、swap と reverse を表す。

第9章 巡回セールスマン問題の例題

最適化のプログラムを実際にどうやって作るかを説明する。例題として、巡回セー ルスマン問題の最適化をとりあげてある。手順は大きく分けて以下のようになる。

9.1 データ構造の決定

設計に最も時間がかかるのがこの部分である。 巡回セールスマン問題では、最低、都市の数を示す変数(N:int)、 都市名を登録する変数(Name:cdef)、 その位置を示す変数(X,Y:rvec)、 訪問順序を都市名で示す変数(Order:cvec)が必要になる。

必要ならば、いろいろなデータを追加できる。 例えば、訪問時間の制限を示す変数(OpenTime,CloseTime:rvec)や、 任意の2都市間の距離(DistMat:rmat)など、 目的に応じて追加するとよい。 このツールの入出力を受持っているポコムは、 工夫すれば、様々なモデルが表現できる。 ポコムの範囲内でモデルを記述すれば、 入出力のルーチンを一切作らずにすむ。 詳しくはポコムのマニュアル(pocom.html)を参照のこと。

#include "../anneal.h"
INT(N,      3,       "訪問する場所の数")
CDEF(Name,  6,N,     "訪問地の名前")
RVEC(X,   306,N,     "訪問地の位置を示すX座標")
RVEC(Y,   306,N,     "訪問地の位置を示すY座標")
CVEC(Order, 5,N,Name,"セールスマンが訪問する順番" )
PROC(Length,"セールスマンの移動距離をCurrScoreへ")

9.2 評価関数のプログラミング

データ構造がきまれば、 評価関数のプログラミングは比較的簡単である。 このアニーリング ツールは、 C言語で評価関数の作成しなければならないが、 ポインタを使わずにすむように設計されている。 読み込みとエラー チェックは、ポコムがほとんど行なうので、 評価関数のなかに、アルゴリズム以外の手続きをあまり書かずにすむ。

手続きの最初で、使用する変数が正しく読まれたかどうかを調べ、 エラーがあれば、return 文で強制終了する。

次に評価関数値を計算する。

最後に、評価関数値を CurrScore に代入する。

評価関数(Length)の名前は、 あらかじめ登録しておく必要がある。 名前を複数登録し、状況によりアルゴリズムを選べるようにすると便利である。 アルゴリズムの切替は、データファイルで行なう。


#include "pocom.h"

void Length(void)
{
    Int i,From,To;  real Sum=0.0,DifX,DifY;

    Check("Order X Y");
    From = Order[N-1];
    for (i=0; i<N; i++) {
        To   = Order[i];
        DifX = X[From]-X[To];
        DifY = Y[From]-Y[To];
        Sum += sqrt( DifX*DifX + DifY*DifY );
        From = To;
    }
    CurrScore = (real)Sum;
}

9.3 テスト データによるパラメータの調整

実際のデータ ファイルは以下のようになる。 タイトル、モデル、アニーリング パラメータ、アニーリング コマンドからなる。 このようなテスト データで、何回か実験を行ない、 アニーリング パラメータを調節し、チューン アップを行なうのもよい。

 ############################
 #  test.txt の内容        ##
 ############################

 Name  X      Y
 都市A 28.634  2.322
 都市B  2.184  7.898
 都市C 22.569 10.736
 都市D 20.729  1.310
 都市E 20.138 17.180
 都市F 18.494 15.311
 都市G 31.022  9.727
 都市H  2.029  7.070
 都市I  6.583  1.413
 都市J  0.960 10.699

 Sample Crit  Gamma Multi Smooth MaxCount DispBest
    384 0.01   0.10     4   0.25    10000        1

 Anneal Length PermuMove Order REV

こうして作成したデータ ファイルは

tsp test.txt

のように起動することで、読み込ませ、 最適化を行なうことができる。

参考文献

R.H. J.M. Otten and L.P. P.P. van Ginneken. The Annealing Algorithm. Kluer Academic Publishers, 1989.