Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Parallel-Simulated-Annealing

Tsuji Daishiro
October 28, 2019

 Parallel-Simulated-Annealing

We implemented temperature parallel simulated annealing in Golang and applied it to a traveling salesman problem.

Tsuji Daishiro

October 28, 2019
Tweet

More Decks by Tsuji Daishiro

Other Decks in Science

Transcript

  1. 局所探索法 ✓ 山登り法 ✓ ちょっと改善することを試行し続ける方法 • 適当な探索解 x に対して、x の近傍内に

    x よりもよい解 x′ があれば x′ を解とすることを反復する手法 • 評価値が悪化しない 評価値 状態 良 悪 7
  2. 局所探索法 ✓ 山登り法 ✓ ちょっと改善することを試行し続ける方法 • 適当な探索解 x に対して、x の近傍内に

    x よりもよい解 x′ があれば x′ を解とすることを反復する手法 • 評価値が悪化しない(局所解に収束) 評価値 状態 良 悪 大域的最適解 局所的最適解 局所的最適解に収束し、大域的最適解に到達できない 8
  3. SAの並行化のアプローチ ✓ いろいろな既存研究がある ✓ Parallel Independent Annealing(PIA) • 従来の逐次SAを並列化して最良の結果を解とする ✓

    Temperature Parallel Simulated Annealing(TPSA) • 温度で並列化してSAを実行する TPSAをGolangで実装して検証 15
  4. 巡回セールスマン問題の近傍 ✓ 2-opt • TSPで最も基本的な近傍 • ある巡回路上において、適当な2辺を交換する手法 1 2 3

    4 7 6 5 1 2 3 4 7 6 5 ※2辺を交換して評価値が改善する例 もとの巡回路: (1, 2, 6, 5, 4, 3, 7) 交換後の巡回路: (1, 2, 3, 4, 5, 6, 7) 19
  5. TPSAの実装 func (t *TPSA) Solve() error { iteration := 0

    for iteration < t.MaxIteration { wg := &sync.WaitGroup{} for i := 0; i < t.Thread; i++ { wg.Add(1) //各温度プロセスが並行してSAを実行 go func(i int) { defer wg.Done() t.sa(i) }(i) } wg.Wait() // 隣接プロセス間の解交換は逐次処理 t.exchangeSolutions(iteration) iteration++ } } ✓ SAを実施する各プロセスは goroutine で温度数分まで非同期処理として並行化 ✓ 解交換は sync.WaitGroup を用いて待ち合わせすることで同期処理 21 https://github.com/d-tsuji/tpsa
  6. 実験データ ✓ 実験データはTSPLIBを使用 • 同じアニーリング回数でSAとTPSAを比較するとTPSAで良好な結果を得た berlin52 krod100 ch130 23 パラメータ

    値 最低温度 0 最高温度 100 交換周期 32 温度数(ゴルーチン数) 16 総アニーリング回数 51,200 ※実験時の各種パラメータ
  7. 実験結果(評価値) ✓ 評価値の実験結果 • SAと比較してTPSAで良好な結果を得ていることが確認できた berlin52 (最適解7,542) krod100 (最適解21,294) ch130

    (最適解6,110) 24 平均値 最良値 最悪値 SA 7,840 7,544 8,238 TPSA 7,544 7,544 7,544 平均値 最良値 最悪値 SA 6,347 6,185 6,482 TPSA 6,171 6,129 6,253 平均値 最良値 最悪値 SA 22,197 21,662 22,795 TPSA 21,294 21,294 21,294
  8. 実験結果(実行時間) ✓ 実行時間のベンチマーク結果 • コア数に比例して実行時間がスケールされていることを確認できた 25 496 251 177 135

    137 123 119 98.6 0 100 200 300 400 500 600 1 2 3 4 5 6 7 8 実行時間(ns/op) 並列数 並列数ごとの実行時間(ns/op) ※実験環境 プロセッサ:Intel Core i7-8650U Processor 4コア/8スレッド メモリ:16GB ※サンプルデータ berlin52
  9. 【参考】実験時にハマったこと ✓ 実験当初、並列実行したときにスケールしなかった • なぜか並列数をあげると実行時間が増加する... 26 547 821 1158 1158

    1098 1118 1128 1147 0 200 400 600 800 1000 1200 1400 1 2 3 4 5 6 7 8 実行時間(ns/op) 並列数 並列数ごとの実行時間(ns/op) ※実験環境 プロセッサ:Intel Core i7-8650U Processor 4コア/8スレッド メモリ:16GB ※サンプルデータ berlin52
  10. 【参考】実験時にハマったこと ✓ 共有ロックを取得することを知らなかった... ✓ 並行処理する関数内で rand インスタンスを生成することで対応 28 /* *

    Top-level convenience functions */ var globalRand = New(&lockedSource{src: NewSource(1).(Source64)}) // ... // Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) // from the default Source. func Float64() float64 { return globalRand.Float64() } // ... type lockedSource struct { lk sync.Mutex src Source64 } ※go1.12のmath/rand/rand.goより抜粋