純Goの機械学習フレームワーク「tensai」でXOR学習とローカルLLMを試す

GoでローカルLLMを簡単に扱うことができるライブラリがSNSで話題になっているので使ってみます。

候補となるライブラリは以下の2つです。

本資料ではtensaiを使って簡単な動作確認をしてみます。

比較(mattn/tensai vs goccy/go-llama)

2つのライブラリを比較します。

比較項目mattn/tensaigoccy/go-llama
主な目的Go製の小規模な機械学習フレームワークGoからllama.cpp相当の推論機能を利用するライブラリ
実装行列演算、学習、推論などをGoで実装llama.cppをWebAssembly経由でGoへ変換
LLMの実行GGUFやsafetensors形式のモデルに対応GGUF形式のモデルに対応
特徴LLMの実行だけでなく、ニューラルネットワークの学習や内部構造も試せるストリーミング、LoRA、埋め込み、複数コンテキストなど推論機能が充実
サンプルXOR、MNIST、文字生成、TinyGPT、GPT-2などが用意されているGGUFモデルを読み込み、文章を生成する基本的なサンプルが用意されている
向いている用途Goで機械学習やLLMの仕組みを触ってみたい場合GoアプリケーションへローカルLLMを組み込みたい場合
今回選んだ理由Goで実装された学習・推論処理や複数のサンプルを確認でき、単なるLLM実行以上のことを試せるため推論機能は充実しているが、今回の「GoでAIを動かして遊ぶ」という目的にはやや実用寄り

上記より、今回はmattn/tensaiを利用することにしました。

補足:用語説明

用語の説明もしておきます。

用語簡単な説明
GGUFllama.cpp系のローカルLLMで使われるモデル形式。量子化済みのモデルを配布・実行しやすい。
safetensors主にHugging Faceで使われる、安全に読み込める機械学習モデルの重みファイル形式。
XOR2つの入力が異なるときだけ正解になる、ニューラルネットワークの最小的な学習例。
MNIST手書き数字を画像から判別する、機械学習の定番データセット。
文字生成学習した文章から、次に続く文字を1文字ずつ予測してテキストを作るサンプル。
TinyGPT小規模なGPT型モデルをゼロから学習し、文章生成を試すサンプル。
GPT-2OpenAIが公開した大規模言語モデル。学習済みモデルを読み込み、文章を生成するサンプル。

サンプルプログラム

雑に動作確認してみようと思います。

以下はサンプルプログラムのURLです。
https://github.com/taako-502/tensai-playground

私はメモリ 24GB、CPUはAppleシリコンM4を利用しています。

準備

Go 1.27がインストールされていれば問題ありません。

ローカルLLMを実行する

利用方法は簡単です。Makefileにllm-runコマンドを用意してるのでそれを利用してください。
量子化版を利用したい場合はllm-run-q8コマンドを代わりに利用してください。

make llm-run PROMPT="GoでCQRSを採用する条件を説明してください"

初回利用時はmodelのインストールから始まるので時間がかかることにご注意ください。

実行すると以下のようになります。

% make llm-run PROMPT="GoでCQRSを採用する条件を説明してください"
go tool tensai run  "GoでCQRSを採用する条件を説明してください"
loaded qwen2 (24 layers, hidden 896) as float32 in 1.878s
prompt: 43 tokens
prefill: 1.347s
CQRS(Command Query Responsibility Segregation)は、C#で使用するための概念です。これは、命令(Command)、応答(Query)とその間の関係を分離するための設計原則です。この設計原則は、命令が応答に影響を与える可能性があることを避けるために導入されています。

CQRSの基本的な条件は以下の通りです:

1. **命令(Command)**:
   - クエリ(Query)は、命令(Command)を実行するためのためのためのもので、命令は応答(Query)に影響を与える可能性があることを避けるために設計されています。

2. **応答(Query)**:
   - クエリ(Query)は、命令(Command)を実行するためのためのためのもので、命令は応答(Query)に影響を与える可能性があることを避けるために設計されています。

3. **命令(Command)**:
   - クエリ(Query)は、命令(Command)を実行するためのためのためのもので、命令は応答(Query)に影響を与える可能性があることを避ける
(256 tokens, 7.3 tok/s)
299 tokens total in 36.655s

何を言っているかわからないですね。私のPCで動作させるために弱いモデルで実行させているため、出力が弱くなります。

モデルを指定する場合

モデルを指定する場合は以下になります。

make llm-run-q8 \
  MODEL=./models/model.gguf \
  PROMPT="Goについて説明してください"

参考:modelの保存先

保存先はコンピュータのOSや設定次第なので参考情報に留めてほしいですが、私のコンピューターには以下のディレクトリにmodelは保存されます。

~/Library/Caches/tensai/Qwen2.5-0.5B-Instruct

modelはそれなりに重いファイルなので、ストレージの容量に不安がある人は利用が終わったら削除を推奨します。

対話モード

以下のコマンドを実行することで対話モードで実行できます。

make llm-chat

実行すると以下のようになります。

% make llm-chat
go tool tensai chat 
loaded qwen2 (24 layers, hidden 896) as float32 in 1.802s
chat mode: type a message, empty line or Ctrl-D to quit
> こんにちは
こんにちは!お元気ですか?何かお手伝いできることがありますか?
(16 tokens, 6.7 tok/s)
> バジルの育て方
バジル(バジル、バジル、バジル)は、日本の伝統的な野菜で、主に秋の野菜として知られています。以下にバジルの育て方について説明します:

1. 原材料の選び方:
- 一般的に、バジルは秋の野菜として採用されることが多いです。
- その際、秋の葉が落ちてから、その葉を剥き出します。

2. 視野の広さ:
- 視野の広さは、バジルの成長に影響します。バジルは、広い視野の下で成長します。
- そのため、バジルの植え付けは、広い場所に位置付けます。

3. 水分の管理:
- バジルは、水分を必要とします。水を適切に管理し、適度な水分を与えることが重要です。
- 水分の管理は、定期的な水やりと、適度な水分を与えることが求められます。

4. 適切な土壌:
- バジルは、砂
(256 tokens, 7.1 tok/s)

出力には制限を入れてるので、途中で止まります。

まとめ

簡単にローカルLLMを動作させることができました。

応用すればいろんなものを作れそうですね。
これからAIを学習したい人は、RAGなどをローカルで構築してみても面白そうです。