画期的な囲碁アプリ「囲碁シル」リリース

以前から予告があった囲碁のアプリ「囲碁シル」がリリースされた。

これが想像以上に画期的であった。

囲碁シル

 

その前に「囲碁であそぼ!」というアプリが囲碁普及活動としてリリースされていた。

囲碁を楽しく覚えられる、新感覚学習ゲーム「囲碁であそぼ!」 | 囲碁学習・普及活動 | 囲碁の日本棋院

こちらは完全な初心者向けで9路盤の対局が出来るまで誘導してくれる。特徴的なのは大口の寄付により広告などを排除している点だろう。

囲碁未経験者にはお勧めするので是非スマホタブレットに入れておいて暇つぶしなどに利用していただきたい。

 

囲碁シルの方は広告はもちろん,有料課金アイテムもあるので少し毛色が違うようだ。

ゲームとしては大きく2つのバトルシステムで構成されている。

ひとつめはステップアップバトルと命名され対局が行われる。

当初はチョイスバトルと候補手3つから選ぶ三択システムで容易に対局感を味わえる。

相手側も弱いレベルからなので「囲碁であそぼ!」をクリアして8級程度の私でも最初は楽勝である。まぁそもそも三択のどこかを選ぼうとする気があるのでほとんどの局面で意見が一致している感じで打っている。

 

対局時の三択システムは将棋の方でも私は提案して実装している。もちろん次の一手問題が連続して出題されているようなものなので分からなくても適当に選ぶことで詰まることなく進行することが出来る。

また,対局後に検討モードがついているため何が悪かったのかの確認が行えるのは独学するのに非常に便利である。

 

三択で楽勝になれば次は「ベアバトル」と称して部分的にサポートAIが打ってくれるモードがあったり,最終的には全て自分で打つ「フルバトル」モードと移行することで自然に囲碁が打てるようになる教育的仕組みである。実によくできていると思う。

じっくり上級までやってみようと思っている。

 

で,本命が定石カードバトルである。

定石は囲碁の用語で将棋界は定跡と呼ばれる。という話はおいておいて,囲碁では定石の形が多く存在し覚えるだけでも相当大変である。

これはカードバトル化したのが画期的と言える。意味や状況が分からなくても手持ちのカードから選ぶだけで成立するのである。囲碁では白黒同数の配置で形が整理するのでこれは非常にうまい使い方である。

 

具体的には19路盤面を4分割し左奥,右手前を自分側(毎回白番な気がする)の定石カードを設置することで対局初期局面がスタートする。右奥,左手前には相手の定石カードが設置されておりそれを参考にすることで後手側が有利な印象である。

印象とゆるい表現にしているのは私の棋力不足で全く有効になっていないのが原因であり,本来はここが唯一かつ一番の棋力の見せ所である。

カードが4枚並ぶとそこから「自動対局」がはじまる。途中で中間評価が行われ優勢などと言われるが結局は終局しないと勝敗は決しない。

ということでカード2枚並べるだけで19路の囲碁をやった気になるという簡単設計に驚いている。

 

以下,中間評価のRound1の盤面である。

 

「踏ん張りどころ」とか言われているが見ているだけなのですることがない。まぁ簡易的にやってる感だけ体験できるのもハードルを下げるのに非常に有用なのは間違いないので普及の起爆剤としては面白そうだ。

実際オセロや囲碁将棋は見ているだけで慣れるしなんとなく急所を覚えていたりするので間違いない。

 

で,これAI開発者視点から見ると指定局面の自動対局なので親近感がある。

AI開発者的には見慣れた構図なので,この自動対局部分のAIちょっといじれないかなとか,このカードシステムをオセロや将棋など他のゲームにも応用できないかななどと考えていた。

 

カードを選ぶだけで何かをやった気になるというのは今のスマホゲームの緩さにもきっと合うのだろう。ヒットすることを期待しております。

 

TensorRT for RTX

TensorRT for RTXと言う技術がある。

TensorRTはNVIDIAの最適化技術であるが、ここでいうfor RTXの部分はどうやらPC向けと言う意味らしい。

既に使い込んでいるがそもそもはTensorRTはAI用のGPU向けで,一般消費者向けではなかったことを思い出すに至る。

pc.watch.impress.co.jp

 

6月リリース予定であったが相当な難産で遅れた。

上記記事には「DirectMLと比べて最大2倍のパフォーマンスが発揮できる」とあるが、役割もDirectMLに近い役割であるようだ。実際は一つ下のWindowsMLのレイヤーでTensorRTの技術を用いてカジュアルに最適化を図る。性能面での他社に対する差別化であり、更新頻度やバージョン互換・ファイルサイズが大きいなど一般向けでないTensorRTの普及版といったところだろう。

TensorRT for RTX Documentation — NVIDIA TensorRT for RTX Documentation

 

blogs.windows.com

WindowsMLの方が難産でその煽りをくった形と思われる。こちらのGAが遅れに遅れ9月である。

 

で、NVIDIA側の公式配布がこちら。バイナリとソースのそれぞれである。

TensorRT for RTX Download | NVIDIA Developer

https://github.com/NVIDIA/TensorRT-RTX

 

そして最も一般的な使われ方がonnxruntimeからの利用だが、今のところPyPiやNuGetでのバイナリ配布は行われていないらしい。

NVIDIA - TensorRT RTX | onnxruntime

 

ざっとWeb界隈を調べてみたところDirectMLに近い使用感でTensorRTに近いパフォーマンスが出ている模様。

自作WindowsアプリをTensorRTからTensorRT for RTXに移行してみた! #NVIDIA - Qiita

 

ファイルサイズも一般配布向けに抑えめである。

 

もちろん、AMDQualcommなどもWindowsML対応でパフォーマンスを出してくると思われるのでここから数か月楽しみな話題の一つでしょうか。

もちろんインテルも頑張って頂きたいところですね。そういえばArc Pro Bどうなった?

 

Windowsで自動タスク

UNIX系ならcronの話。

 

昔と違ってたのでメモしておく。

schtasks create | Microsoft Learn

 

コマンドラインからschtasksと打てば大体できるらしい。

GUIだと「コンピュータの管理」の「タスクスケジューラ」で管理できるがコマンドラインの方がオプションが細かい。

 

schtasks /create /tn "High" /tr "C:\work\go\high_process.bat" /sc minute /mo 5

今回のタスク、プロセス優先度を昇格させるバッチファイルを5分毎に実行させる。やりすぎ感あるがこれで一度やってみる。

 

それにしてもMSが自動翻訳に頼りだしてから誤訳を放置しているのはもう取り返しがつかないレベルなのね

---

 

Pythonプログラムの昇格は以下のようにインタプリタを昇格させたがこれで動いているみたい。問題は全インタプリタが昇格してしまうところだな。

PowerShell -Command "Get-Process -Name \"Python\" | ForEach-Object { $_.PriorityClass = \"High\" }"

 

---

11/9追記:

ミニPCに負荷をかけすぎたのか20日ほどで起動しなくなった

やはり長期運用設計のものでやるべきか

 

盆栽いじりの成果

先週盆栽いじりのようなものだと表現した。

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

 

言い訳のつもりは無いがコンピュータ関係は大半独学で,特定のカリキュラムで学んだことは皆無である。もちろん,大学の授業にFORTRANの入門があったりはしたがそれ以外で学ぶものの方が先行していたので特に記憶に残っていない。

元は旧友の影響だろう。書籍の紹介などがアドバイスとして有益だったことを記憶している。

 

前回Go言語のプログラムがあまり強くなっていない件,Pythonのプログラムが少し高速化しただけのはずなのに結構効果的だったなどの話をしたが,この違和感の原因らしきものがわかった。

これらを投入しているPCは2年ほど前に購入したミニPCである。

floodgate近況(2023年7月) - 48's diary

温故知新(3年ぶりNaN回目,gpsfish計測編) - 48's diary

当時の記録だとCPUがインテルの1235UでPコアが2つしかないが,4GHz動作し結構なパフォーマンスをみせている。

ノートPCに比べ厚みがある分冷却性能が高いようである。

 

この状況がいつのまにか変わっていたらしい。今考えるとWindows11のアップデートでゲーム性能が落ちる話題と関連していたのかもしれない。

 

今回の件は具体的には省電力処理の問題であった。

上記の計測をしていたころは見ての通りの性能であったが,いつのまにか改良を施しても思ったほどレート向上が無いなという印象であった。リアルタイムで対局しているのをタスクマネージャーの動きも見ていたところ,ベースクロックも上がらずEコアにしか負荷が入っていないことを確認した。探索速度的には4分の1とか5分の1といった感じである。PコアEコア比が2倍,クロック比で2倍程度だろうか。いつのまにかEコアでブーストもされずに漫然と対局していたのだ。

 

理由はプロセスの実行時間と負荷だろう。対局時間に比べて待機時間の方が長い上にこの間無負荷である。サーバプログラムでもよくあることだがこういうプロセスは省電力モードで動かされる。Windows11もバージョンアップにつれてかどうか知らないが徐々にそういった動作をするようになったのだろう。

 

ということでAMDのCPUの方でも同じようなプログラムを投入してみた。こちらにはEコアが無いので少なくともそこは大丈夫なはずだ。

 

go_test12と13が1235Uのプロセスで13cがAMDの8840HSである。

プログラム的には若干違うものであるが基本構造や評価関数は同一である。
ちょっと大げさに出てるかもしれないが4倍のノード差があればレート200くらいは妥当な範囲と思われる。

 

せっかくの省電力ミニPCだが使いにくいものになったもんだ。

 

 

ローカルLLMへの期待度

ふと適当なことを呟いておきます。

 

今のところ検索にもひっかからないので普及したら私が言い出したことになります。

もちろん,LLLMと表現している人もいます。

zenn.dev

 

で,何なのかということですがLLMの言語化の部分をUIとしてローカルにやろうという話です。

マイクロソフト社的に言うとCopilotとCopilot+の差でしょうか。最後の言語化部分をローカルのPCを使って行うのがCopilot+と区分するのだそうです。それで並のユーザに不快感がない速度が出るように40TOPS程度のNPUが必要だろうって話ですね。

 

理屈で言うと人間の言語よりAIの情報形式の方が秘匿性も高くネット上のスループットも出るはずなのでそれはリーズナブルな話です。

Webで圧縮転送している比ではなくなりますが,ネットを流れる情報の大半がこういったものになってくるのは時間の問題だろうという予測が立ちます。

 

じゃ,必要なのは何かというと共通のプロトコルでしょう。そのうちできるんでしょうか?

更にもう少し高機能なものを手元に置くとすれば手元からMCPサーバを叩きにいくことになるわけです。

様々な公式情報がMCPサーバの形で提供されるようになるのも時間の問題かもしれません。Webのクローラが失職してしまいますか。

変革の時期ですね。

 

ハードウェア的にはQualcomm Snapdragon X2が省電力で80TOPSとか言ってるので期待したいところです。

 

floodgate近況(2025秋)

前回が7月。

bleu48.hatenablog.com

 

N150を2機購入しほぼ常駐している。

Kristallweizenが前回3900付近が4000を超えている。

短期レートが100程度シフトするのは珍しくないのでそういう現象ととらえて相対位置に着目する。

この間、やねうら王の9.00がリリースされている。

GitHub - yaneurao/YaneuraOu: YaneuraOu is the World's Strongest Shogi engine(AI player) , WCSC29 1st winner , educational and USI compliant engine.

 

で、400戦ほどしたのが上の表で拍子抜けする話だが有意差は認めにくい。

有償版は強いとの宣伝文句なので購入した人は比較して欲しい。

近隣レートにノートPCが複数ある感じだがサーマルスロットリングなどで安定したレートを計測するのには向いていないと思われる。同じ省電力CPUでも冷却ファンに余裕のあるミニPCとかの方がよさそう。(もちろんミニPCとて熱設計が悪ければ同じなのだが)

 

さらに下位層である。

前回予告したGo言語実装のv0.13を放り込んでみたが、v0.12と大差ないというか若干劣っている感じである。元々置換表の機能はあったのでLMRやアスピレーションサーチなど他の技術と組み合わせた際の相性などで差が出てくるものと予測する。

 

sample4-8のβ1はPythonの探索に仮実装のTTを加えたモデル。

4-7より随分探索が速くなってレートの向上が見られた。落ち着いた値もそこそも素晴らしい。Go言語実装より一桁以上探索が遅いので並びかけるとしたら脅威である。

 

本格的な開発というよりは盆栽弄りに近いものである。

写経の方が適当か。

「プログラミング 写経」でググってみて下さい。

私にとってはGo言語やPythonの習作であり、アルゴリズム理解の確認作業でもある。

 

温故知新(続Transposition Table編)

前回のTransposition Table編に続きます。

 

bleu48.hatenablog.com

 

前回はTransposition Table実装をgpt-oss頼りに行ったという話で、当然ながら結構効果的なものでした。

ただ、Python実装なのでStockfishのような特殊なメモリ管理をしていないという話でしたが、この部分もgpt-ossに詳しく聞くことができました。

以下の回答が結構驚きです。

 

Stichfish準拠のTTとC++標準のunordered_mapのパフォーマンス比較として、ベンチマークプログラムとベンチマーク結果を出力してくれました。

以下、少し修正して動くようになったプログラムです。

#include <chrono>
#include <random>
#include <unordered_map>
#include <vector>
#include <cstring>
#include <immintrin.h>   // for _mm_clflush (optional)

using Key = uint64_t;

inline unsigned long long __builtin_clzll(unsigned long long x) { unsigned long r; _BitScanReverse64(&r, x); return 63 - r; }

// ---- TT の最小実装 -------------------------------------------------
constexpr size_t ClusterSize = 4;           // 4‑way
struct TTEntry {
    uint16_t move;
    int16_t  value;
    uint8_t  depth;
    uint8_t  genBound;   // 2bit bound + 6bit generation
    uint16_t key16;
};

struct TTCluster { TTEntry e[ClusterSize]; };

class SimpleTT {
    std::vector<TTCluster> table;
    size_t mask;            // (clusterCount-1)
    uint8_t generation = 0;

public:
    explicit SimpleTT(size_t mb) {
        size_t clusters = (mb * 1024 * 1024) / sizeof(TTCluster);
        // 2 のべき乗に丸める
        clusters = 1ULL << (63 - __builtin_clzll(clusters));
        table.resize(clusters);
        mask = clusters - 1;
    }

    // プローブだけ。ヒットしたらエントリへのポインタ、外れたら nullptr
    TTEntry* probe(Key k) {
        size_t idx = (k >> 16) & mask;
        uint16_t k16 = uint16_t(k >> 48);
        TTCluster& cl = table[idx];
        for (int i = 0; i < ClusterSize; ++i)
            if (cl.e[i].key16 == k16) return &cl.e[i];
        // 置換エントリを探す(最古・浅いもの)
        TTEntry* victim = &cl.e[0];
        for (int i = 1; i < ClusterSize; ++i) {
            TTEntry* e = &cl.e[i];
            bool older = (e->genBound & 0x3F) < (victim->genBound & 0x3F);
            bool shallower = (e->depth < victim->depth) &&
                             *1;
            if (older || shallower) victim = e;
        }
        // クリアして返す
        std::memset(victim, 0, sizeof(TTEntry));
        victim->key16 = k16;
        victim->genBound = generation;      // generation だけ設定
        return victim;
    }

    void incGen() { generation = (generation + 1) & 0x3F; }
};

// ---- ベンチマーク ---------------------------------------------------
int main() {
    const size_t N = 1'000'000;               // キー数
    const size_t ITER = 100'000'000;          // プローブ回数
    std::mt19937_64 rng(0xDEADBEEF);
    std::vector<Key> keys(N);
    for (auto &k : keys) k = rng();

    // 1. TT
    SimpleTT tt(64);                          // 64 MiB ≈ 1M エントリ
    for (Key k : keys) tt.probe(k);           // 予め全エントリを登録

    auto t0 = std::chrono::high_resolution_clock::now();
    uint64_t dummy = 0;
    for (size_t i = 0; i < ITER; ++i) {
        Key k = keys[i % N];
        TTEntry* e = tt.probe(k);
        dummy += e->key16;                    // 防止最適化
    }
    auto t1 = std::chrono::high_resolution_clock::now();
    double ttTime = std::chrono::duration<double>(t1 - t0).count();

    // 2. unordered_map
    std::unordered_map<Key, uint16_t> umap;
    umap.reserve(N * 2);
    for (Key k : keys) umap.emplace(k, 0);

    t0 = std::chrono::high_resolution_clock::now();
    for (size_t i = 0; i < ITER; ++i) {
        Key k = keys[i % N];
        dummy += umap[k];                     // 同様に dummy で最適化防止
    }
    t1 = std::chrono::high_resolution_clock::now();
    double umapTime = std::chrono::duration<double>(t1 - t0).count();

    printf("TT   : %.3f s (%.1f ns/op)\n", ttTime, ttTime * 1e9 / ITER);
    printf("unordered_map: %.3f s (%.1f ns/op)\n", umapTime,
           umapTime * 1e9 / ITER);
    printf("dummy=%llu\n", (unsigned long long)dummy);
    return 0;
}
 

 

LLMが吐くベンチマーク結果はもちろんいい加減なものですが、ベンチマークプログラムは少し修正しただけで意味のある動作をしており、3倍近い速度差が得られました。

それにしても他分野に比較して異常とも思えるほどStockfishには詳しいようです。

 

---

おまけ:

Go言語実装しているエンジン(俗称:地ビール)にも以前からTT実装してありましたが、独自実装から部分的にStockfish準拠にしたものに変更したものを作成しました。

全体のベンチマークにはあまり影響がないようですが、バージョン0.13としてそのうちFloodgateデビューすると思います。

 

 

 

 

*1:e->genBound & 0x3F) == (victim->genBound & 0x3F