8GBのRaspberry Pi 5にGranite 4.1を載せたら、どこまで使えるのか試してみた!

以前のエントリで Graniteの進化や、Raspberry Pi 5で動くローカルLLMを整理してみたんですが、2026年4月29日にIBM Researchから Granite 4.1が発表されて、ほぼ同時期にOllama公式ライブラリにも登録されました。個人的には少し落ち着いたタイミングで調べることが多いのですが、今回の更新はもう試してもいいかなと思います。

www.ibm.com

今回は、Ollama経由でGranite 4.1の 3B8B をRaspberry Pi 5(8GB RAM)に載せて、Chat・日本語品質・JSON出力・Function Callingまで複数の観点で比較を行なっています。

「ChatGPTやClaudeを普段から触っていて、コードを書かせるのも慣れているけど、LLMの中身まではちょっと…」という方を想定しています。なので、Transformerのアーキテクチャや量子化の数式みたいな話には踏み込みません。代わりに、「Raspberry Pi 5のような小さい箱で動かすなら、どのモデルをどう使えばいいか」をざっくり押さえる方針でいこうと思います🤗

⚠️ この情報は 2026-05時点のものです。Granite 4.1はリリース直後(2026-04-29)なので、Ollama側のタグや量子化バリエーションは今後変わる可能性があります。

以前の関連記事

uepon.hatenadiary.com

uepon.hatenadiary.com


1. Granite 4.1で何が嬉しくなったのか😊

一番大きいのは「Ollamaで普通に動くようになった」こと

前バージョンの4.0は、新しい仕組みを取り入れた「攻めた構成」のモデルが目玉だったんですが、その新しさのせいでOllamaやllama.cpp側がまだ最適化しきれていない部分があり、「とりあえず動かしてみたい」だけのときには一手間かかる状態でした。Ollamaのページにも「最適化されていない環境では別バージョンを使ってください」という注釈があったくらいです。

以前の4.0を触っていない方にはピンと来ない話かもしれませんが、当時は 「動かすまでにちょっと工夫が必要なモデル」という位置づけだったんです🤔

今回リリースされた、4.1では構成を素直な作りに戻していて、その結果 Ollamaで pull して run するだけで普通に動く状態になりました。Raspberry Pi 5のような環境では、これだけで触り始めるハードルが大きく下がりますね😊

👉補足しておくと、4.0では Mamba-2 + Transformerのハイブリッドアーキテクチャが目玉だったんですが、4.1では Dense Decoder-only Transformerのアーキテクチャに戻っています。これ、地味に大きな方向転換なんですよね。「ハイブリッドの新しさ」より「ふつうに動く堅さ」を取ったのかもしれません。

4.0 → 4.1の変更点

バージョンアップによる変更点をざっくりまとめると、こんな感じです。

項目 Granite 4.0 Granite 4.1 かなり要約した意味合い
モデル構成 攻めた新方式と従来方式が混在 従来ある方式に一本化 Ollamaでそのまま動く
サイズ展開 350M〜H-Smallまで多系統 3B / 8B / 30B 選択肢が減って選びやすい
性能 H-Smallが代表 8Bが旧4.0のH-Small(32B)相当 小さくなって賢くなった
ツール呼び出し 強化 さらに改善 エージェント用途でも楽しめる

サイズ感とコンテキスト長

3B8Bのサイズ感ですが、Q4_K_M量子化(後述、Ollamaデフォルト相当の品質バランス型)でのダウンロードサイズは 3Bが約2.1GB、8Bが約5.3GB。Raspberry Pi 5 8GBなら8Bでもギリギリ載りますが、メモリの余裕は3Bのほうが圧倒的に上です。

コンテキスト長は仕様上128Kまで対応していますが、これはあくまで「対応可能」の上限で、Raspberry Pi 5で実際に大きく取ると一瞬でメモリが埋まってしまうようです。

⚠️ Raspberry Pi 5 8GBでは、コンテキスト長を大きくするとメモリが圧迫されてスワップしたり、最悪はメモリ不足でプロセスが強制終了されたりします(Linuxでいうところの OOM = Out Of Memoryですね)。実用上は2K〜4K程度で運用するのが安全です。設定方法は後半のModelfileセクションで書きます。

Graniteファミリーで揃えられるのも地味に強い

数字でひとつ補足すると、Granite 4.1の学習トークン数は約15T。同時に Granite Guardian 4.1(安全性チェック)、Speech 4.1(音声認識、WER 5.33%)、Vision 4.1(チャート・テーブル抽出)もリリースされているので、エッジで「LLM + 音声 + Vision」をGranite系で揃える、という選択肢が出てきました。組み込み的には、ライセンスや扱いの揃った家系で一式組めるのは結構ありがたいという人もいそうです。

2. 環境構築

今回使用するのは以下のような環境です。

ハードウェア

  • Raspberry Pi 5 8GB RAM
  • NVMe SSD(PCIe HAT経由)
  • 5V/5A電源
  • Raspberry Pi OS 64-bit

5V/5A電源とアクティブ冷却は、ローカルLLMを回すなら正直必須です。電力不足だとロード時点で落ち、CPUが熱で性能を絞られると、応答速度が目に見えて落ちます😅

Ollamaのインストールとモデルの取得

導入は以下のように行います。

# Ollamaのインストール(ARM64を自動検出、バージョンアップも行います)
$ curl -fsSL https://ollama.com/install.sh | sh

# Granite 4.1 3Bのダウンロード
$ ollama pull granite4.1:3b-q4_K_M

# Granite 4.1 8Bのダウンロード
$ ollama pull granite4.1:8b-q4_K_M

モデル名の末尾に付いている q4_K_M というのが量子化の指定です。Ollamaのタグページには Q2_K から Q8_0 までいろいろ並んでいますが、これは 「モデルをどれくらい圧縮するか」のレベルだと思えば問題ありません。 数字が小さいほど軽くて速いけど品質が落ち、大きいほど重いけど品質が上がる、というトレードオフになっています。もしモデル選びで迷ったら Q4_K_Mが品質と速度のバランスが取れています。

なお、Ollamaのタグ表記は小文字(q4_K_M)、量子化形式の名前としては大文字(Q4_K_M)で書かれることが多いようです。同じものですが、記事内では文脈に合わせて使い分けています。

量子化 Raspberry Pi 5 8GBでの評価 ひとこと
Q4_K_M 最有力(3B/8Bとも) 迷ったらこれ😊
Q5_K_M / Q6_K 3Bは動作可、8Bは微妙 品質寄りだがメモリ・速度に注意🤔
Q8_0 3Bなら可、8Bはかなり重い 品質は高いがRAMがきつい🥲

👉K_M(k-quants の medium variant)は内部のブロック単位で精度を変える派生量子化で、純粋な Q4_0よりも知覚品質が安定しやすいタイプです。Raspberry Pi 5のような CPU推論環境では、ロードサイズと品質のバランスがちょうどいいので「迷ったらQ4_K_M」という理由になります。

インストール直後からOllamaはsystemdサービスとして自動で起動します。systemctl status ollama で確認できます。

3. Modelfileでパラメータを固定する

この設定を行うことでRaspberry Pi 5の動作の安全装置となります。

Ollamaでモデルを動かすときは、普段は ollama run granite4.1:3b-q4_K_M と打つだけです。これでも十分動きます。

ただ、Raspberry Pi 5で本気で運用しようとすると、毎回同じ設定で起動したいという場面が出てきます。そんなときに使える設定がModelfileです。

Modelfileとは?

大まかにいうと、「このモデルを、このパラメータで使う」という設定をまとめておけるファイルとなります。DockerfileのAIモデル版、と思ってもらうと近いと思います。

最初は「ollama run のオプションでパラメータ渡せばよくない?」と思っていたんですが、Raspberry Pi 5で触り始めると、コンテキスト長を毎回オプションで指定するのを忘れて、メモリ不足で落ちる(OOM)みたいなしょうもない事故が起きます😅

そんなときに事前に作成したModelfileに固定パラメータを書いておくことで、毎回同じ設定で起動できます。

なぜModelfileが必要なのか?

Granite 4.1はコンテキスト長を最大128Kまで対応しています。ですが、コンテキスト長を大きくすると、それに比例して 裏側で確保される作業用のメモリが増えます。Raspberry Pi 5 8GBだと、これが一気にメモリを食い尽くしてしまうんですね。

ollama run でそのまま起動するとOllama側がコンテキスト長を自動で決めてくれますが、それがRaspberry Pi 5にとってちょうどいい値とは限りません。特に8Bモデルは、デフォルトのままだと モデルをロードしただけでメモリがほぼ埋まることもあります。

そのため、Modelfileを、「Raspberry Pi 5で安全に動かすためのストッパー」として使う位置づけで活用しています。これで、うっかり大きなコンテキスト長で起動してしまう事故を防げますし、毎回同じ設定で起動できるので、安定した運用がしやすくなります。

実際に作ってみる

3B用の Modelfile はこれだけ。日本語応答に寄せるために、システムプロンプトも埋め込んでいます。

Modelfile3B

FROM granite4.1:3b-q4_K_M
PARAMETER num_ctx 4096
PARAMETER temperature 0.2
SYSTEM あなたは日本語で応答するアシスタントです。簡潔に回答してください。

FROM で元のモデル、PARAMETER で固定したい設定を記述していきます。num_ctx がコンテキスト長、temperature は応答のランダムさを調整するパラメータです。Raspberry Pi 5で安定して動かすために、コンテキスト長は4096に絞っています。

# カスタムモデルとして登録
$ ollama create granite4.1-pi-3B -f Modelfile3B

# 実行
$ ollama run granite4.1-pi-3B

granite4.1-pi-3B という名前で登録され、以降はこの名前で呼ぶだけで毎回同じ設定で起動します。新しくモデルがダウンロードされるわけじゃなく、既存モデルに設定を被せた「ラッパー」みたいな感じです。

8Bモデルを使用する場合にはメモリサイズがギリギリなので、コンテキスト長をさらに絞って設定するのが安全です。

Modelfile8B

FROM granite4.1:8b-q4_K_M
PARAMETER num_ctx 2048
PARAMETER temperature 0.2
SYSTEM あなたは日本語で応答するアシスタントです。簡潔に回答してください。
# カスタムモデルとして登録
$ ollama create granite4.1-pi-8B -f Modelfile8B

# 実行
$ ollama run granite4.1-pi-8B

登録後はollama listコマンドで確認できます。

最初は「こんなもの必要か?」と思っていたんですが、Raspberry Pi 5みたいな制約のキツい環境だと実質必須だと感じました。

4. テスト1:Chat機能(基本的な対話と速度の感触)

まずはシンプルにChat機能から試してみます。

$ ollama run granite4.1-pi-3B --verbose
>>> Raspberry Piとは何か、3行で説明してください。

$ ollama run granite4.1-pi-8B --verbose
>>> Raspberry Piとは何か、3行で説明してください。

--verboseオプションをつけることで対話ごとに統計情報が出るので、そこから eval rate(tokens/s = 1秒あたり何文字くらい吐けるか、の指標)を確認できます。メモリ使用量は別ターミナルで ollama ps を実行します。

速度比較

Raspberry Pi 5で3BクラスのLLMを動かすと、おおむね 4〜5 tokens/sくらいが目安です(Qwen2.5-3B Q4_K_Mで 4.808 tok/s、Llama-3.2-3B Q4_K_Mで 4.674 tok/s という報告もあります)。8Bクラスになると 2 tok/s前後で、対話用途だとかなり 遅さを感じます

体感としては、3Bが「結構考えて喋ってくれる人」くらいの速度、8Bは「打ち込んだあとお茶を入れに行ける」くらい、と思っておくと心の準備ができます😅 クラウドサービスのLLMを使っていると、いろいろ言いたくなるかもしれません🙄

5. テスト2:日本語と英語の品質比較

Granite 4.1は12言語をサポートしていて、その中には日本語も含まれています。同じ意味の質問を日英で投げて比較してみました。

$ ollama run granite4.1:3b-q4_K_M
>>> 桜が日本文化において重要な理由を3つ挙げてください。

$ ollama run granite4.1:3b-q4_K_M
>>> List three reasons why cherry blossoms are important in Japanese culture.

Granite 4.1はいろんな言語をバランスよく学習したモデルですが、英語側にやや比重がある印象です。日本語特化モデル(TinySwallowなど)と比べると、日本語の自然さでは一歩譲る部分はありました。ただ、基本的な理解と生成は普通にこなしてくれそうです。

6. テスト3:JSON形式での構造化出力

エッジ/組み込みでLLMを使うとき、出力をプログラムで処理したい場面がよくあります。「LLMの返事を if 文で分岐させたい」「DBに突っ込みたい」みたいなケースですね。そういうとき、LLMにJSONで返してもらえると楽です。

Granite 4.1はもともとこういう構造化出力を意識した作りになっているらしいので、試してみます。

$ ollama run granite4.1-pi-3B --verbose
>>> 以下のテキストから情報を抽出し、JSON形式で出力してください。
... フォーマット: {"name": "...", "age": 数値, "occupation": "...", "city": "..."}
... 余計な説明は不要で、JSONのみを返してください。
... 
... テキスト: 田中太郎は45歳のエンジニアで、名古屋市に住んでいます。

{"name": "田中太郎", "age": 45, "occupation": "エンジニア", "city": "名古屋市"}

$ ollama run granite4.1-pi-8B --verbose
>>> 以下のテキストから情報を抽出し、JSON形式で出力してください。
... フォーマット: {"name": "...", "age": 数値, "occupation": "...", "city": "..."}
... 余計な説明は不要で、JSONのみを返してください。
... 
... テキスト: 田中太郎は45歳のエンジニアで、名古屋市に住んでいます。

{"name": "田中太郎", "age": 45, "occupation": "エンジニア", "city": "名古屋市"}

ポイントは、3Bと8Bで 「余計な説明文をつけずに、純粋なJSONだけを返してくれるか」です。「こちらが抽出したJSONです: ...」みたいな前置きを付けてくる小さいモデルあるあるをやらないかどうか、で実用性がかなり変わります。 3Bも8Bも、きちんとJSONだけを返してくれました。この点は両者とも合格ですね😊

7. テスト4:Function Calling(ツール呼び出し)

Granite 4.1の機能のひとつが Function Calling(ツール呼び出し)です。

これは何かというと、LLMに「どの関数を、どんな引数で呼べばいいか」を判断してもらう機能です。たとえば「名古屋の天気を教えて」と聞かれたら、「あ、これは get_weather 関数を city: "名古屋" で呼ぶべきだな」とLLMが判断してくれる、というやつ。

組み込み視点でこれが面白いのは、自然言語で家電操作やセンサ読み取りを扱える世界に直結するからなんですよね。「リビングの電気消して」をLLM経由でデバイス制御に落とせる、という夢のある話。

実は仕組みは以前からしっていたのですが、コードとして書いたことはありませんでした。今回、Function Callingを初めて使ってみたんですが、これがなかなか楽しかったです。仕組みの解説と、Raspberry Pi 5のシステム情報を取得するPythonデモは、別記事として続編にまとめる予定です。

👉 続編🤗「OllamaでFunction Callingを初めて使ってみた」

uepon.hatenadiary.com

今回は、curl での簡易テスト結果だけ載せておきます。

OllamaでFunction Callingを呼ぶ口は2種類あって、Ollamaネイティブの /api/chattools フィールドを使う方法と、OpenAI互換API(/v1/chat/completions)の tools パラメータを使う方法があります。今回はおなじみの形が分かりやすいかなと思って、OpenAI互換APIのほうを叩いてみます。

⚠️ Function Callingまわりの挙動は Ollama本体のバージョンによって変わることがあります。本記事の検証時の環境は Ollama (バージョンは検証時に追記)ollama --version で確認できます)。手元で試す際は、まず自分のOllamaのバージョンを確認してから読み進めてもらうのが安全です。

Function Callingのテスト内容("granite4.1:3b-q4_K_M")

$ curl -s http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "granite4.1:3b-q4_K_M",
    "messages": [
      {"role": "user", "content": "名古屋の今日の天気を教えて"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "指定都市の天気を取得する",
          "parameters": {
            "type": "object",
            "properties": {
              "city": {"type": "string", "description": "都市名"}
            },
            "required": ["city"]
          }
        }
      }
    ]
  }' | jq .

{
  "id": "chatcmpl-812",
  "object": "chat.completion",
  "created": 1778075585,
  "model": "granite4.1:3b-q4_K_M",
  "system_fingerprint": "fp_ollama",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "tool_calls": [
          {
            "id": "call_ofukh5ce",
            "index": 0,
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"化州\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 192,
    "completion_tokens": 25,
    "total_tokens": 217
  }
}

Function Callingのテスト内容("granite4.1:8b-q4_K_M")

$  curl -s http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "granite4.1:8b-q4_K_M",
    "messages": [
      {"role": "user", "content": "名古屋の今日の天気を教えて"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "指定都市の天気を取得する",
          "parameters": {
            "type": "object",
            "properties": {
              "city": {"type": "string", "description": "都市名"}
            },
            "required": ["city"]
          }
        }
      }
    ]
  }' | jq .

{
  "id": "chatcmpl-517",
  "object": "chat.completion",
  "created": 1778075908,
  "model": "granite4.1:8b-q4_K_M",
  "system_fingerprint": "fp_ollama",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "tool_calls": [
          {
            "id": "call_u66feme4",
            "index": 0,
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"名台の\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 192,
    "completion_tokens": 29,
    "total_tokens": 221
  }
}

LLMが get_weather 関数を選び、引数に "city": "名古屋" を正しく抜き出せれば成功です。3Bと8Bの両方で成否を確認してみました。関数名は正しく呼び出せていますが、日本の地名はやっぱり駄目でしたね🥲

# granite4.1:3b-q4_K_Mの場合はなぜか「化州」となってしまっています。
"arguments": "{\"city\":\"化州\"}"
---
# granite4.1:8b-q4_K_Mの場合はなぜか「名台の」となってしまっています。
"arguments": "{\"city\":\"名台の\"}"

英語ならもう少しマシな結果が出るのかもしれませんが、日本語の地名を引数として抜き取るのは、3Bも8Bも苦手そうだということはわかりました。Function Calling自体は両方ともきちんと呼び出せているので、ツール呼び出しの機能は3Bでも8Bでも基本的には動くといえそうです。

8. 3B vs 8B比較まとめ

Raspberry Pi 5(8GB RAM)で自分なりに使い分けるなら、こんな感じでしょうか。

  • 3B Q4_K_M … 応答もそれなりに返ってくるし、Function Callingも基本は動く
  • 8B Q4_K_M … 比較的賢いけどかなり遅い。バッチ処理向き
  • 30B … Raspberry Pi 5ではほぼ無理(Q4_K_Mで約17GB)。クラウド側に任せるのが現実的です

品質を上げたいときの自然な順番は、3B Q4_K_M → 3B Q8_0 → 8B Q4_K_Mです。まずは3B Q4_K_Mで要件を満たせるかを試して、足りなければ上に登る、という流れでしょうか。

しかし、日本語の使用に関しては、3Bも8Bも同じくらいの印象でしょうか。日本語の自然さを求めるなら、3B Q4_K_Mで十分という印象です。

9. 他のローカルLLMとの速度比較

Raspberry Pi 5で動く3Bクラスの代表選手たちと並べてみます。

モデル 量子化 Raspberry Pi 5推論速度 日本語 ライセンス
Granite 4.1 3B Q4_K_M Apache 2.0
Qwen2.5 3B Q4_K_M 4.808 tok/s Apache 2.0
Llama-3.2 3B Q4_K_M 4.674 tok/s Community License
TinySwallow 1.5B Q5_K_M 8-10 tok/s Apache 2.0
LFM2.5-1.2B-JP Q4_K_M 10-15 tok/s Apache 2.0
Gemma3 1B Q8_0 11-12 tok/s Gemma License

Granite 4.1 3Bのポジションは、QwenやLlamaの3Bモデルと同じ程度でしょうか。速度が速いわけじゃないので、Graniteを選ぶ理由は速度以外のところでの必要性でしょうか。

おわりに

今回はRaspberry Pi 5でGranite 4.1をOllama経由で動かして、3B8Bを複数の観点で比較してみました。

結論としては、Raspberry Pi 5でGraniteを常用するなら3B Q4_K_Mが本命です。8Bは賢いんですが、Raspberry Pi 5 8GBだとかなり窮屈な印象です。

何より大きいのは、4.0では「動かすまでに一手間」だったのが、4.1では pull して run するだけで普通に動くようになったこと。仕組みのことを気にせず、「LLMを組み込んだ何かを作る」のほうに時間を使えるようになるのは、地味だけど大事なポイントだと思います。

個人的には、初めて触ったModelfileFunction Callingもいい経験になりました。特にFunction Callingは、仕組みの解説とPythonデモを別記事として続編にまとめる予定なので、公開できたらこちらにもリンクを追記します。

参考リンク

www.ibm.com

www.ibm.com

research.ibm.com

huggingface.co

ollama.com

Ollama Modelfileドキュメント