コンテンツにスキップ

サンプル

すべてのサンプルはリポジトリルートから go run で実行できます:

サンプル コマンド 見せるもの
helloworld go run ./_example/helloworld 最小のプログラム: グラフ上で 2 つの値を加算
dataset go run ./_example/dataset Dataset のワークフロー: shuffle, split, standardize, batches
xor go run ./_example/xor XOR の学習 (MSE + softmax の健全性チェック)
fizzbuzz go run ./_example/fizzbuzz 分類問題としての FizzBuzz
spiral go run ./_example/spiral 3 クラスのスパイラル分類
iris go run ./_example/iris Iris の分類
mnist go run ./_example/mnist MNIST 分類器 (-model dense, cnn, knn) と保存/読込
charrnn go run ./_example/charrnn 自動微分エンジン上の文字レベル LSTM テキスト生成
tinygpt GOEXPERIMENT=simd go run ./_example/tinygpt n 次元自動微分エンジンでゼロから学習する文字レベル transformer (-gpu でデバイス学習)
plasma go run ./_example/plasma ニューラルネットワークが描くターミナルプラズマ — 生きた SIMD ベンチマーク
dot go run ./_example/dot z = x + y グラフの Graphviz DOT エクスポート
tensor go run ./_example/tensor N 次元 Tensor ツアー: ブロードキャスト、バッチ MatMul、attention
wgpu go run -tags wgpu ./_example/wgpu WebGPU MatMul: アダプタ情報、CPU との照合、GPU vs CPU スイープ
gpt2 GOEXPERIMENT=simd go run ./_example/gpt2 公開 GPT-2 (124M) チェックポイントが純 Go でテキスト生成
flappy GOEXPERIMENT=simd go run ./_example/flappy Flappy Bird を、毎ステップ Engine.Score でモデルに聞いて遊ばせる。ランダムと 1 行のヒューリスティックと並べて、採点された 1 トークンにどの聞き方なら決められるかを測る。-screen で観戦

gpt2 サンプルは初回に GPT-2 チェックポイント (~550MB) をダウンロードします。instruction-tuned モデル (Qwen2.5-0.5B から 7B まで 9 ファミリー) は tensai コマンドを使ってください: LLM 推論を参照。

MNIST

MNIST サンプルは標準の IDX gzip ファイルがなければ _example/mnist/data にダウンロードします (MNIST_DIR で別のキャッシュディレクトリを指定可能。生の IDX と .gz の両方を受け付けます):

go run ./_example/mnist                                  # dense MLP
go run ./_example/mnist -model cnn                       # Conv2D/MaxPool2D/Dropout + AdamW
go run ./_example/mnist -model knn                       # 学習不要の k-NN ベースライン
go run ./_example/mnist -model cnn -export mnist.tflite  # TFLite へエクスポート

5000 サンプルのサブセットで、k-NN ベースラインは約 91%、MLP は約 92%、CNN は約 95% です。学習する 2 つのバリアントは最後にモデルを保存し、再読込後に再スコアします。-export は LiteRT インタプリタ上で同一スコアになる TFLite flatbuffer を書き出します — モデルフォーマット参照。

charrnn

埋め込みのパブリックドメインテキストで文字レベル LSTM を学習し、SaveParamsFile でパラメータを保存し、新しいモデルに復元して、再読込したパラメータからサンプルを生成します。

tinygpt

charrnn と同じ埋め込みテキストで、小さな文字レベル transformer (トークン埋め込みと位置埋め込み、4 ヘッドの因果 attention と GELU の feed-forward を持つ pre-norm ブロック 2 段、最終 norm と出力射影) を学習し、そこからサンプリングします。パラメータは約 106k、GOEXPERIMENT=simd で 1 分ほど学習すれば、コーパスの文をそのまま再現するようになります。モデル全体が n 次元自動微分エンジンで書かれています: 活性は (batch, sequence, model) のテンソル、ヘッド分割は Reshape と Transpose、各ステップのバッファは Tape が再利用します。フラグは -iters, -lr, -temp, -n, -seed、それに形を変える -model, -heads, -blocks, -batch, -seq。

-data を指定すると埋め込みの 1 ページの代わりにテキストファイルで学習し、-tokenizer を指定すると文字単位ではなく tokenizer.json (BPE) で分割します。語彙はコーパスに出てくるトークン ID だけなので、GPT-2 のトークナイザで 100KB のテキストを学習しても 50257 ではなく 2656 エントリで済みます。-save は形・語彙・トークナイザ・重みをまとめた 1 つの JSON チェックポイントを書き出し、-load はそれだけからモデルを組み立て直します。-prompt から生成するか、-data を付ければ追加で学習します (Adam のモーメントは初期化されます)。コンテキスト窓より短いプロンプトも使えます。attention は因果的なので、プロンプトより後ろの空きスロットは次のトークンに影響しません。

go run ./_example/tinygpt -data notes.txt -tokenizer _example/gpt2/data/tokenizer.json \
    -model 128 -seq 64 -save notes.json
go run ./_example/tinygpt -load notes.json -prompt "The tape" -n 60

-gpu (wgpu ビルド時) はブロック全体をデバイスで学習します。値も勾配も Adam の更新もデバイスに留まり、毎ステップ帰ってくるのは損失だけです。速くなるかは形次第で、既定のサイズではテンソルが小さすぎて GPU が埋まらず AVX2 カーネルが勝ち、モデルを広げるとクロスオーバーします。AMD 780M では既定サイズで 24ms/step に対し -gpu が 72ms/step、-model 256 -heads 8 -batch 16 -seq 64 では 282ms に対し 129ms でした。損失はどちらでも桁まで一致します。

flappy

Flappy Bird を何通りかで遊ばせます。ランダムに羽ばたくもの、1 行のヒューリスティック (隙間の中心より下なら羽ばたく)、そして毎ステップ聞かれる言語モデル。モデルには state を 文章にして渡し、答えは Engine.Score で読みます。学習は一切しません。変えるのは聞き方です。 素のプレイヤーは「今羽ばたくべきか」を yes/no で聞かれます。-hint は隙間に対する相対位置を state に足し、-compare は「鳥は隙間の中心より下にいるか」という比較だけを yes/no で聞きます。 -larger は同じ比較を「57 と 63、どちらが大きい?」と聞いて、その 2 つの数を選択肢にします。 答えはモデルが書く数であって、寄りがちな yes ではありません。語順を入れ替えて 2 回聞き、 平均します。-rows はそれを高さを 1 桁に丸めてやり、heur/rows が丸めで届く上限です。

結果そのものが要点です。Ryzen 7735HS、400 ステップで勝ち:

プレイヤー パイプ ステップ 1 手
ランダム 0.3 16 0
ヒューリスティック 20 (勝ち) 400 0
heur/rows 16 325 0
Qwen2.5-0.5B 0 12 265ms
Qwen2.5-0.5B, hint 0.3 19 291ms
Qwen2.5-0.5B, larger 14 284 382ms
Qwen2.5-0.5B, rows 16 325 191ms
Gemma-3-1B 0 11 681ms
Gemma-3-1B, larger 20 (勝ち) 400 693ms
Gemma-3-1B, rows 16 325 421ms
K2-Horizon-7B 0 9 4.7s
K2-Horizon-7B, hint 0 9 5.6s
K2-Horizon-7B, 比較のみ 0 11 2.8s

yes/no で聞く限り、ヒントの有無にかかわらずどのモデルも遊べません。比較の行が理由です。 「65 は 63 より下か」に 7B は yes 98%、「87 は 63 より下か」に yes 88% と答えます。採点された 1 トークンが運ぶのは質問の癖 (ここでは yes) であって、数値比較ではありません。数を選択肢に して「どちらが大きいか」と聞くと、1B がヒューリスティックと 1 手も違わずに遊びます。勝った ゲームで 390 回比較して誤りはゼロ、61 対 62 まで正しく答えます。仕事終わりにコーヒーより ビールを選ぶのと同じ仕組みは、数について yes/no には何も言えず、数そのものが答えなら すべてを言えます。物理はどちらでもコード側にあり、動いたのはモデルが答えられる質問です。

GOEXPERIMENT=simd go run ./_example/flappy -episodes 3 -hint -compare -larger -rows
GOEXPERIMENT=simd go run ./_example/flappy -model ~/.cache/tensai/gemma-3-1b-it-Q8_0.gguf -larger -nobase -screen
GOEXPERIMENT=simd go run ./_example/flappy -show        # 確率つきで全手を表示
GOEXPERIMENT=simd go run ./_example/flappy -nomodel     # ベースラインだけ

-screen はゲームをターミナルに描きながら進め (1 手 1 フレーム、表は最後のフレームの下)、 -nobase はベースラインを飛ばします。

plasma

デモシーン風のプラズマをターミナルにアニメーションします。プラズマ関数はランダムに重み付けされたネットワーク (CPPN) で、毎フレーム全ピクセルを 1 バッチとして評価します。ステータス行にフレームあたりのネットワーク時間が出ます: ポータブルで約 32 fps、GOEXPERIMENT=simd で約 100 fps。-seed を変えると違う模様になります。

wgpu

アダプタを表示し、GPU の結果を CPU カーネルと照合し、-sweep で行列サイズの階段を上りながら GPU が CPU を追い越す地点に印を付けます — GPU (WebGPU) 参照。