Upgrade to Pro — share decks privately, control downloads, hide ads and more …

オセロを速く解く話/solveothello

 オセロを速く解く話/solveothello

京大マイコンクラブの春合宿で、オセロを速く「解く」ことについて特化して話したスライドです。

prime number

March 15, 2019
Tweet

More Decks by prime number

Other Decks in Programming

Transcript

  1. 16 NegaMax 法 -1 倍して最大値を取る +8 -4 +6 -8 +20

    +4 +16 先手 後手 終局 -6 +8 -20 -4 -16
  2. 17 NegaMax 法 -1 倍して最大値を取る +4 +8 -4 +6 -8

    +20 +4 +16 先手 後手 終局 -8 +4
  3. 23 NegaAlpha 法 NegaMax 法と同様に手番が変わるたびに -1 倍する 子ノードの α 値は

    -beta 、 β 値は -alpha になる 子ノードの結果が beta 以上なら枝刈りできる 実装が簡単になる 計算量はほとんど同じ
  4. 31 ベンチマーク mini-max alpha-beta fastest-first 0.01 0.1 1 10 100

    1000 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
  5. 32 ベンチマーク mini-max alpha-beta fastest-first 0.01 0.1 1 10 100

    1000 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 1 〜 35 倍程度の高速化
  6. 33 ビットボード オセロの盤面は 8*8=64 マス 各マスは空き、黒、白のいずれか これを 64bit 整数 2

    つで持つ 自分の石のある位置、相手の石のある位置 64bit*2=128bit=16Byte で盤面を表現できる メモリ使用量の削減になる 手番の交代は 2 つの整数の入れ替えで表現できる
  7. 42 ビットボードでひっくり返る石の計算 反対側の石 -1 とマスクの AND を取る ひっくり返る石の位置がわかる 0 1

    0 0 0 0 0 0 1 1 1 1 1 0 0 0 マスク 反対側の石 0 0 1 1 1 1 1 1 0 0 1 1 1 0 0 0 反対側 -1 反転する石
  8. 45 ベンチマーク mini-max alpha-beta fastest-first bit-board 0.01 0.1 1 10

    100 1000 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
  9. 46 ベンチマーク mini-max alpha-beta fastest-first bit-board 0.01 0.1 1 10

    100 1000 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 5 倍程度の高速化
  10. 48 ベンチマーク mini-max alpha-beta fastest-first bit-board leaf-opti 0.01 0.1 1

    10 100 1000 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
  11. 49 ベンチマーク mini-max alpha-beta fastest-first bit-board leaf-opti 0.01 0.1 1

    10 100 1000 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 2 倍程度の高速化
  12. 50 SIMD/ ビット演算命令 SIMD(Single Instruction Multiple Data) 1 命令で複数データを処理すること SSE,

    AVX, NEON など ビット演算命令 特定のビット演算を高速化する命令 ひっくり返る石の計算、着手可能位置の計算に利用
  13. 51 ベンチマーク mini-max alpha-betafastest-first bit-board leaf-opti avx2-popcnt 0.01 0.1 1

    10 100 1000 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
  14. 52 ベンチマーク mini-max alpha-betafastest-first bit-board leaf-opti avx2-popcnt 0.01 0.1 1

    10 100 1000 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 2 倍程度の高速化
  15. 53 NegaScout 法 αβ 探索では Alpha 値以下のノードには興味がない 何も更新されないので 先頭以外の各子ノードについて、 alpha

    値を超えるかどうかだけ探索 solve(next, -alpha-1, -alpha) で実現できる 超えるなら改めて完全探索 solve(next, -beta, -alpha) する
  16. 54 ベンチマーク 0.01 0.1 1 10 100 1000 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
  17. 55 ベンチマーク 0.01 0.1 1 10 100 1000 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 1 〜 3 倍程度の高速化
  18. 57 ベンチマーク 0.01 0.1 1 10 100 1000 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
  19. 58 ベンチマーク 0.01 0.1 1 10 100 1000 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 1 〜 1.7 倍程度の高速化
  20. 71 ベンチマーク 0.01 0.1 1 10 100 1000 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
  21. 72 ベンチマーク 0.01 0.1 1 10 100 1000 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 1 〜 10 倍程度の高速化 (#39 は除く )
  22. 74 ベンチマーク 0.01 0.1 1 10 100 1000 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 52
  23. 75 ベンチマーク 0.01 0.1 1 10 100 1000 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 52 5% 程度の高速化
  24. 78 計算量の見積もり 大体 1 〜 5*10^7nodes/sec 出ている ゲーム木の大きさは 10^54 、局面数は

    10^28 程度 あくまで推定だか、大きくは外れていないと思われる αβ 探索は、理想的な場合はノード数が平方根ぐらい 置換表を使えば 10^14 ぐらい読めば良い…? 単純計算で 3*10^6sec=35 日程度
  25. 85 GPU の利用 並列計算なら CPU より並列計算に適したデバイスがある GPU (Graphic Processing Unit)

    画像処理を行うプロセッサ PC で画面に映像を出すのに使われる 並列計算に向いている GPGPU General Purpose computing on GPU GPU を汎用計算に使うこと
  26. 86 GPU の利用 実装してみた https://github.com/primenumber/GPUOthello2 αβ 法 + 葉から遠いところで速さ優先探索 +

    静的並べ替え 再帰をループで実装する必要があり、かなり移植に苦労
  27. 87 GPU での分岐 GPU は何スレッドかを 1 つに束ねて実行している 16, 32, 64

    スレッドなど 束ねられたスレッドは同一の命令を実行する 分岐があった場合 分岐の方向が全部同じ場合 分岐の方向の命令だけ実行する 分岐の方向が違う場合 両方のパスをマスク付きで実行する
  28. 88 GPU での分岐 分岐の方向が同じ場合 if (X) { A; B; }

    else { C; D; } X==true X==true X==true X==true A A A A B B B B
  29. 89 GPU での分岐 分岐の方向が違う場合 if (X) { A; B; }

    else { C; D; } X==true X==false X==false X==true A A A A B B B B C C C C D D D D
  30. 90 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる void f() { if (X) { f(); } else { A; } } X !X !X X !X X X X
  31. 91 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる void f() { if (X) { f(); } else { A; } } X !X !X X !X X X X f() f() f() f() f()
  32. 92 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる void f() { if (X) { f(); } else { A; } } X !X !X X !X X X X f() f() f() f() f() !X X !X X X
  33. 93 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる void f() { if (X) { f(); } else { A; } } X !X !X X !X X X X f() f() f() f() f() !X X !X X X f() f() f()
  34. 94 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる void f() { if (X) { f(); } else { A; } } X !X !X X !X X X X f() f() f() f() f() !X X !X X X f() f() f() X !X !X
  35. 95 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる void f() { if (X) { f(); } else { A; } } X !X !X X !X X X X f() f() f() f() f() !X X !X X X f() f() f() X !X !X f()
  36. 96 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる void f() { if (X) { f(); } else { A; } } X !X !X X !X X X X f() f() f() f() f() !X X !X X X f() f() f() X !X !X f() !X
  37. 97 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる void f() { if (X) { f(); } else { A; } } X !X !X X !X X X X f() f() f() f() f() !X X !X X X f() f() f() X !X !X f() !X A
  38. 98 GPU で再帰 + 分岐 GPU で再帰 + 各スレッドでバラバラに分岐すると、 1

    スレッド以外はほぼ常にマスクされている状態になる マスクされている間は計算していないのと同じ 演算能力の 1/16 や 1/32 しか使えない
  39. 99 GPU での実装 αβ 法を素直に実装すると、再帰 + 分岐になる 各スレッドがバラバラに分岐して CPU より遅くなる

    そこで、スタックをメモリ上に用意し、再帰をループに 再帰はスタックを用いてループで書けることが知られている ループを用いると一重の分岐コストだけで済む 約 5*10^9nodes/sec NegaScout 等が実装されていないので、 nodes/sec の比ほどは速くはならない
  40. 101 PEZY-SC/SC2 PEZY Computing 社の開発している MIMD プロセッサ 各スレッドが完全に独立して動作する 分岐によるペナルティがない! PEZY-SC/SC2

    の搭載されている菖蒲 (/SystemB) スパコ ンを使わせてもらえることになった 2017 年 12 月(ちょうど社長が逮捕された頃)
  41. 102 PEZY-SC/SC2 版ソルバー 実装してみた https://github.com/primenumber/PEZY-Othello 8*10^9 nodes/sec (on PEZY-SC2 1

    モジュール ) スタック領域が 1 スレッドあたり 2KB/2.5KB しかないため、かなり移植に苦労した
  42. 103 PEZY-SC/SC2 版ソルバー αβ 法 + 葉から遠いところで速さ優先探索 + 静的並べ替え +

    置換表 +NegaScout 評価関数の利用はまだうまく行っていない MIMD 動作のため、速さ優先探索の分岐ペナルティが なくなり、かなり葉の近くまで速さ優先探索出来るので nodes/sec の違い以上に速い
  43. 105 PEZY-SC/SC2 の問題点 スループットを出すにはかなりの並列度が必要 1 モジュールあたり数十万局面必要 1CPU に 4 〜

    8 モジュール繋がっているので全体では 数百万局面必要 1 局面を解くのにかかる時間(レイテンシ)は長い 700MHz, 4 スレッド交代のため
  44. 109 オセロソルバー on FPGA Othello ソルバーと FPGA は相性が良い FPGA にとって苦手な演算がいらない

    乗算器の数も余裕がある ビット演算などが得意 オセロ専用回路を作れる
  45. 110 オセロソルバー on FPGA 2018 年 5 月〜 https://github.com/primenumber/FPGAOthello 現在の仕様

    パイプラインプロセッサ、 9 ステージ 9cycle / node を 9 並列 @1 コア 100MHz 程度 数千 LUT&FF / 1 コア 愚直な αβ 法
  46. 111 FPGA 版の実装 FPGA では再帰をそのまま回路に落とし込むのは難しい スタックを Block RAM 上に作ってループで解く またか…

    パイプライン化するためには工夫が必要 すべての実行パスでサイクル数を揃える ステートマシンが単純なループになるようにする Block RAM へのアクセス回数を減らす 2 ポートしかないため
  47. 112 オセロソルバー on FPGA のアーキテクチャ 9 段パイプライン Fetch Decode1 Decode2

    Exec1 Exec2 Exec3 Exec4 Check Write Stack [154bit width * (16*9) depth] Dual Port BRAM
  48. 118 オセロソルバー on FPGA の性能 AWS F1 インスタンスに載っている、 Xilinx UltraScale+

    VU9P で考える 2,364K FF & 1,182K LUT だいたい 300 コアぐらいは載りそう? 3*10^10 nodes/sec 程度
  49. 119 オセロソルバー on FPGA の今後の展望 Fetch ステージでスタックへの書き込みをやめる 次の Write ステージで書き込めば原理上行ける

    Simple Dual Port RAM にできる アーキテクチャによっては BRAM の数を減らせる Fetch/Decode と Exec/Check/Write を分ける Fetch/Decode を高速に動かす Exec は半分くらい演算器が遊んでいるので有効活用したい 速さ優先探索等を行う・クロック周波数の向上
  50. 126 ベンチマーク @4 コア 8 スレッド 0.01 0.1 1 10

    100 1000 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 52
  51. 127 ベンチマーク @4 コア 8 スレッド 0.01 0.1 1 10

    100 1000 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 52 1 〜 3 倍程度の高速化 (#47 等は除く )
  52. 129 YBWC vs APHID コア数が少ない時: YBWC の方がよい コア数が多い時: APHID の方がよいはず…

    現状では CPU 版 : YBWC GPU/PEZY-SC2 版 : APHID の亜種 非同期にタスクを投げるのが難しいので亜種 FPGA 版 : APHID の予定
  53. 130 現状の進捗 6x6 オセロ 初手からの 32 手完全読み CPU 版(評価関数なし) :

    1 時間 34 分 GPU 版 : 43 分 PEZY-SC2 版 : 未実装( GPU 版と同程度?) FPGA 版 : 未実装( GPU 版よりかなり速いはず…) 目標性能が出れば 1 秒未満で解けるが…