続Go 1.26のSIMD実装

前回に続く

bleu48.hatenablog.com

 

前回SaturateToInt8がAVX512依存してしまう話をしていた。

世間的にもAVX2対応が基準だろうと某AIが言うのでそのように対応していたが、そもそもGo言語のライブラリでしれっとAVXバージョン混在状態になっている理由は何故かと考えると、サーバサイドはインテルもAMDもAVX512対応しているからであることに気づく。

Go言語の主戦場は多コアサーバなのでこれでよかったのだ。

 

今回問題となったSaturateToInt8もよくない。

これは各要素を8ビット幅に収める命令だがSIMD命令を使わないと個々の変数を8ビットに収めてSIMDレジスタに格納する手間となる。これはGo言語では相当遅い。

なお、func (Int16x8) SaturateToInt8は128ビット、func (Int16x16) SaturateToInt8は256ビットであるにも関わらずAVX512の命令なのだ。

では、開き直って512ビットのfunc (Int16x32) SaturateToInt8を使えばどうだという話になる。で、AVX512依存を覚悟して他の命令群も512ビット化するとどうなったかというと結構高速化した。全体で2割程度、局所的にはもっと出ていることになる。

 

更に言うとAVX512はZen4とZen5で速度向上が大きい。Zen5でAVX512は効く。

本件メインの演算はDotProductPairsSaturatedであるが、これもAVX2の256ビット命令とAVX512の512ビット命令がある。この命令の実行速度がZen4とZen5の大きな差である。

 

ということで、Zen5においてAVX2実装とAVX512実装で倍くらいの速度差が実現した。

 

 

更新しながら様々なバージョンをFloodgateに投入して迷惑をかけている感があるが、恐らく一番強いのがgo_test13na3でレート2700を超えている。2800というとgpsfishの基準レートなのでもう少しといったところだろうか。ちなみにこれだけZen5である。

念願のYSS1000Kとの直接対局は少ないが超えたかどうかの判定は楽しみである。

 

技術的な話を少ししておくと現状前向き枝狩りが軽いLMRのみである。Stockfish由来の様々な枝狩りを使うのが今風なので、伸びしろを残しているというかコーディングが面倒で放置しているというかメインループが長くなるのが嫌とかそんなところである。まぁ習作なのでコピペプログラミングみたいなことをしても仕方ないってのもある。

気が向いたらStockfishに寄せるかもしれないし、別の伸びしろを見つけるかもしれない。

 

---

インテルがサーバだけAVX512対応している件、邪推してみた。

Zen5が出ている現状AVX512はAMDの方が速い。インテルが対応しても勝てる見込みがない。が、まだ普及していないので非対応とすれば世間的にはAVX2バイナリが流通することになって差が縮まるということだろう。

サーバ側は前バージョンで対応したものを下げることができなかったのでそのまま残していると考える。まぁ、クライアント側はEコアが非搭載なのでしかたないという体になっている。

まぁSIMDが活躍する分野はどの程度あるか分からないが動画音声のエンコードデコード、ファイル圧縮展開、暗号化復号化などは大きく寄与するだろう。そっかサーバには不可欠だな。

 

Go 1.26のSIMD実装

2月なのでGo言語のバージョンアップがあった。

Go 1.26 Release Notes - The Go Programming Language

 

Go言語はいつからか年2回、2月と8月にバージョンアップがある。

最初Go言語を触った頃は違った気がしている。

最近はセキュリティ系のアップデートが多いが、機能的なものが更新されると実際に弄ってチェックするようにしている。

Go 1.23のrange over func - 48's diary

 

で、1.26で結構大きいのが速度向上である。

cgoのオーバーヘッドが減っているなど具体的な記述もあるが、手持ちのソースをビルドして実行するだけでざっと見で1割程度速くなっているようである。皆すぐに移行すべき。

 

加えて個人的にはsimd/archsimdパッケージの実験的導入である。

古くはインテルのSSE、AVXなどのSIMD演算を導入された。AVX512まで記述がある。

詳しくは以下のリンクを見ると良い。

https://pkg.go.dev/simd/archsimd

個々の関数にAVXだのAVX2だのAVX512だの書かれている点がミソである。後述する。

 

うちではGo言語の習作として将棋エンジンの地ビールシリーズがある。

1ファイルマッチというのを提案して体験会で優勝してしまったこともあるが、Floodgateレートでは2300~2500くらいと思われる。結構変動がある。

1ファイルマッチ体験会反省会 - 48's diary

floodgate近況(2025秋) - 48's diary

 

Go言語でSIMD演算が使えないため世間で流行っているNNUEが有効利用できないでいた。具体的にはシーケンシャルに計算することで3駒系のモデルの2~3割程度の速度しかでないのである。元々単純なループ部分などもC++と比べて遅い言語であるので、これはさすがに負けることになる。

 

今回は習作のアップデート機会ということで地ビールSIMD実装のNNUE評価関数を実装してみた。一日半要した。

あまり考えず普通のコードでNNUE実装していたものをSIMD実装してみたところ、意外にすんなりエラーもなくコンパイルが通るようになった。が、実行時にパニックを起こした。AVX512であった。

AVX512が使えるのはAMDのZen4以降とインテルの11世代のみである。(家庭用ね)

12世代環境で作業していたため取り急ぎZen4環境に移行し作業を進めた。

いくつかのトラブルがあったが、なんとCopilotが結構役に立った。Google系の言語の最新機能であるにもかかわらずGoogleのAIよりもMSのCopilotの方が有用だったのが驚きである。具体的には添え字などのミスタイプ、オーバーフローの可能性などであった。特にオーバーフローはSIMD演算ではエラーにならないため計算結果が異なるということになる。SIMD演算ではオーバーフロー処理のみが異なる別命令もあるので注意である。また、8ビット演算前の丸めのタイミングなどでも若干挙動が変わることを確認した。

そうこうして動くようになった後、なんとかしてAVX512命令を除去することにした。SaturateToInt8などである。

結局要所のVPMADDUBSW(simd/archsimdパッケージではDotProductPairsSaturated)さえ使えればそこそこ速いだろうくらいの実装である。

少し遅くなったがなんとかAVX2の範囲で動くソースとなった。

 

まぁ、理想的にはVNNI命令まで使いたいところだがこれはライブラリ対応次第といったところだろう。コーデックやニューラルネットワークの実装が捗るような使い勝手のよいものになっていただきたいと思う。

それとうっかりAVX512依存してしまうのは何とかしていただきたい。サーバサイドだと問題ないのだろうか?

 

ということで、最新の地ビールをfloodgateに放り込んでおく。

 

1fileの戯れ

重量級のライブラリやフレームワークに振り回されることもありますが,個人的には1fileで簡単なプログラムを作るのが学習効率が良いと思っています。

過去にも色々提案してます。

1file match(仮)の参考資料4(ネガアルファ法) - 48's diary

温故知新(2年ぶり,Transposition Table編) - 48's diary

 

で,この年末年始は体調を崩してしまったので本格的な開発ではなくゆるゆるリハビリ気分で小さなプログラムを弄っていました。

240行くらいですが,コメント行も多いので実質200行満たないでしょう。

sampleシリーズの3-6c群です。

 

上ふたつはレート3500に達しました。ええ,gikou2_1cしっかり越えました。個人的新記録です。

c3はPCスペックが低く桁違いに探索速度が遅くなっていますが,レート3000ありますね。

 

いずれにしても周辺の同レート帯で逆転負けの多いことは確認できました。また,比較的幅広いレートで一方的でない勝敗を記録しており格上にも偶に勝てることがあるので実に面白いです。

 

AlphaEvolveの話

半年くらい遅れているが自分用のメモとしてAlphaEvolveの話題をいれておく。

 

AlphaEvolve: A Gemini-powered coding agent for designing advanced algorithms - Google DeepMind

 

どういうものか端的に言うと昨今流行のLLMをUIつまりヒューマンインタフェースとして使って問題解決のツールとしようとするものだ。

といっても対応する問題解決というのはコンピュータが扱えるもので主にコードを書くことでえられるものである。

 

例で挙げられているのがシュトラッセンアルゴリズムの改良である。

シュトラッセンのアルゴリズム - Wikipedia

簡単に言うと2x2の行列積に必要な乗算の数を8から7へ減らしたという話だ。

シュトラッセンアルゴリズムには歴史的にヒントとなるものがあって,多倍長乗算のカラツバ法が先にある。

カラツバ法 - Wikipedia

 

AlphaEvolveは4x4の行列積においてシュトラッセンアルゴリズムを2回適用する乗算49回よりも1回すくない48回の手順を発見したとある。もちろん単純に計算すると8x8の64回であるから随分と減らされている。

 

実はこれは新発見ではない。

2022年に4x4の行列積の乗算数を47回にしているのは同DeepMind社のAlphaTensorである。

Discovering novel algorithms with AlphaTensor - Google DeepMind

つまり,この手法のUIを挿げ替えたのが本件である。

もちろんLLMを入力にしているために様々な問題への対応が柔軟に行えることは間違いない。が,ベストスコアは専用機であるのが面白いところだろう。

 

部分的にではあるが人間の最適化能力を上回ることがあるようなので,そのうちこういった最適化問題の一番のコンペティターとして出てくることになるのであろう。

もちろん一番の活躍の場はAI高速化である。

 

第6回電竜戦本戦

第6回電竜戦本戦の最中にうちのエントリーの三番絞りの紹介を書きました。

 

bleu48.hatenablog.com

 

まぁ、計測対局などほぼ出来ていないままでしたが予選を通るかどうかの辺りまで戦えていたので素晴らしいなと思うところです。

AobaNNUEがトラブルで不要な負けをしながらも決勝入りしていましたので手法的なポテンシャルは十分あることを示していただきました。予選ギリギリということで今年はAobaNNUEがバレルハウス賞となりました。(唯一予選日に決定する賞です)

 

結果は以下のリンク先にあります。

文部科学大臣杯第6回世界将棋AI電竜戦本戦

 

優勝は氷彗でした。

HEROZは今までもずっとそうですが使っているリソースが桁違いです。

しばらく多くの参加者の比較的分かりやすい目標になるのではないでしょうか。

技術的にはstockfish由来が多いのですが1層目の要素数を増やしているようです。2019年にうちも相当様々なモデルをテストしていたのですが当時とCPUのL1キャッシュが量も質も変わってしまい、最適点が随分大きいところになっていそうな感じです。

事実AobaNNUEの山下さんも大きな1層目で予想したよりずっと高いパフォーマンスが出ている点をコメントされていました。

 

個人的には二番絞りが決勝入りしましたが、予選は若干対局相手によって運不運があるようで実際の実力が発揮されないことも多いですね。仕方ないとされていますが、何かアイデアはないかと日ごろから考える課題の一つです。

 

今年の話題としては鯤鱶(多くの方がクンシャンと呼んでました)が決勝入りしたことでしょうか。昨年も参加頂いていたのですが中国企業の兆芯がリリースしているCPUであるKX-6580Uを国産CPUと呼ばれているので中国からのエントリーと思われます。兆芯で決勝入りは世界初ですね。決勝ではマシンパワー差だと思われる敗戦が多く10位となっていました。

 

他には独創賞の元気もりもりニンニクパワーが詰将棋をターゲットに開発を進めて面白い試みとなっているほか、LLMを利用するチームが急増しているのが今回の傾向です。

今後も色々と発展の気配をみせつつ2025年のまとめとしておきます。

 

ーーー

おまけ:

チェス界でnnue-pytorchよりも強力なライブラリが出たとの噂です。

GitHub - jw1912/bullet: Specialised ML Library

比較的汎用設計になっており、CPU推論をするような低ビット小サイズのニューラルネットワークを効率的にGPUで学習させるためのライブラリのようです。

nnue-pytorchは仕方ない部分があるのですが恐らくバス部分がボトルネックになっておりハイスペックでも低スペックでもあまり計算速度が変わりません。bulletはそういう部分をかなり解消しているものと思われます。学習器と言うよりデータローダや転送部分の技術です。

で、問題はこれrustで開発されており、私個人はrustからは逃げていたのでほぼ触っていません。少しやらないといけないかなぁという気分になっていますので年末年始の課題としておきましょうか。

1層目の拡大と共にNNUEが新しいステージに行きそうな感じです。

近いうちにチェス・将棋以外にも展開しそうです。

 

三番絞り

電竜戦も6シーズン目です。

文部科学大臣杯第6回世界将棋AI電竜戦本戦

電竜戦 - 棋譜中継

 

運営サイドとして今年も色々と模索していますが、プレイヤーとしても今年の新しいものは「三番絞り」です。

といってもとってつけたようなもので、AobaNNUEが強いことが判明してから同じ手法を試そうと手元の二番絞りをベースに行ってみたものです。

思いのほか時間がかかっており、複数パラメータ同時に仕掛けたのですが一番最初に学習が終わったもので丁度今予選を戦っています。

もう一つ終わっているのですがどちらが良いかとの判別が難しいというのが現状です。明日入れ替えるかもしれません。

 

行った手順は山下さんのBBSに書かれたものとほぼ同じです

http://www.yss-aya.com/bbs/patio.cgi?read=195&ukey=1

 

野田さん公開のHaoでdepth9のデータが元です 

 

静止探索局面に書き換えを行った後、二番絞りの静止局面評価を50%:50%で平均化したものが教師データとなります。

簡単に書きますが80億局面ほどあり、ハイエンドPCを2台用いても評価値の差し替えだけで1週間以上要します。

 

たとえば80億秒が253年です。Threadripper128並列で0.1秒で一局面を処理できたとしても2か月以上かかるのですが、野田さんが公開されたものがこれくらいのデータ量ということです。うちのLAN回線ではダウンロードに10時間近くかかりました。

 

さらに山下さんの報告では学習に2週間ほど要したそうですが、うちでは残り時間を考えて簡略化して数日で終えています。恐らく、収束管理が甘いためかAobaNNUEより弱い印象です。

電竜戦本戦後に再度時間をかけて確認したいと思っています。

 

80億局面も必要なのかどうかに関しては正直そこまでの比較実験を行っていないので分かりませんが、二番絞りでの経験では2億では全然足りないのでせめて4,5億欲しい。可能なら10億局面と考えて強化学習を進めていました。そのため1ステップに要する時間が最終局面で1年を超えました。さすがに手持ちのGPUでは手に負えません。

 

あまりこういう物量勝負をしたくないのですが・・・

 

CSAで提案したこと2025

CSAは最近のうちの文脈だとコンピュータ将棋協会の略である。

http://www2.computer-shogi.org/

 

昔の話をすると2019年の世界選手権の運営で先後の差が大きく,あまり公平と言えない点を主張した。過去の例もあって当然のように流されることになった。他にも時間管理の話もした気がするが私本人が詳細を覚えていない。

 

2020年に電竜戦を立ち上げるに辺り先後差の是正はひとつの課題となっており,現在さまざまな試みの経過で引き分け時先手0.4勝後手0.6勝とやや差をつける運用となっている。選手権でも同様にしようかとアンケートがあったが私はせっかくなので効果がはっきりするまで違うルールで運用頂きたいと思っている。

 

他にも色々とあるが,今年7月に提案しているのは2点である。正確には二度目かもしれない。

1.24点法の導入

2.時間管理の精細化(少なくとも1秒単位から0.1秒単位へ)

 

1は27点法と24点法の差異が分かる人には分かりやすいと思う。

プロ棋士は24点法でそれ以外はアマチュアとコンピュータは27点法で行われている。

理由は引き分けの対応に困る点である。アマチュアとコンピュータの大会には運営時間が無いため引き分けが発生すると困る。持将棋は避けたいのである。

比べてプロは持将棋で決着がつくのは時間がかかる上に恐らく視聴者が喜ばないと考えられているため差し直しが現行のルールだ。

もちろん日本将棋連盟や新聞各社にKristallweizenが利用される際にはこの点は丁寧に説明しており,対応が必要であればリクエスト下さいとお伝えしている。

伊藤叡王誕生の際にはコメントを求められたのでどこかの記事になっていることだろう。

 

で,本提案のざっくりした意味は先手勝率の是正方法として後手が最初から持将棋を狙った場合に持ち込むことが可能であるかどうかというところだ。もちろん戦型によっては可能性が高いと言う噂も既に出ている現状である。が,実際どうか真剣にやってみないかという提案である。

 

2つ目は時間管理の単位である。現在1秒が最小単位である。

フィッシャークロックルールの1手5秒加算や2秒加算で1秒が単位は少し大きいのではないかと言うのが私の提案である。

粗い話はえいださんが行っている。

コンピュータ将棋の対局で秒単位からミリ秒単位化に対応すると勝敗にどこまで影響するか?|都賀町えいだ@コンピュータ将棋開発VTuberバ美肉おじさん

この議論は制御側が時計を持っていない場合成立する。

実際の実装は探索時に指し手が決まっても,例えば2.4秒であったとしたら2.8秒か2.9秒くらいまで使って指すような仕組みになっており実質0.5秒程度内部で無駄に使っていることになる。稀に有効なることがあるので100%の話ではないが

2.4秒で指して浮いた0.5秒分くらいを持ち時間に残して欲しいと言うのが私の意見だ。

 

2018年にマルチポンダーシステムを組んで0秒指しを披露した。ネタとしてウケればいいと思っていたのだが勝敗ばかりが話題になった。選手権ルールだと1秒未満は0秒になる。1秒を超えると上記理由で2秒になるのだ。

そう,本題は相手のポンダーが全く機能しない状態を作り出すことにあったのだが,ネタとしてこの辺を考えたことが無い人には説明しても伝わらなかったようだ。

で,こうなると1手2秒程度であっても100手付近になって数分の差になる。意図的に作り出した状況だが人間の将棋に準えて強弱の話で雑にまとめられている。

こういった部分も精度よく時間評価して欲しいと考えている。