はじめに
「ローカルLLMを使いたいけど、GPUがない」
エンジニアなら誰もがぶつかる壁です。しかし 2026 年現在、1.5〜2B パラメータの小型モデルが CPU のみで実用的な速度 で動くようになりました。
本記事では、以下 5 モデル を GPU なし・CPU 環境で実機ベンチマーク した結果を公開します。
| モデル | パラメータ | 開発元 | ライセンス | 特徴 |
|---|---|---|---|---|
| Qwen3.5:0.8b | 0.8B | Alibaba | Apache 2.0 | 最新世代・thinking搭載 |
| Qwen3.5:2b | 2B | Alibaba | Apache 2.0 | 最新世代・マルチモーダル |
| Qwen2.5:1.5b | 1.5B | Alibaba | Apache 2.0 | 安定の前世代 |
| DeepSeek-R1-Distill:1.5b | 1.5B | DeepSeek | MIT | 推論特化(671Bの蒸留) |
| Gemma2:2b | 2B | Apache 2.0 | 官公庁案件向け |
結論から言うと、Qwen3.5 は速いが「考えすぎ」で暴走する。日本語タスクでは Qwen2.5 が依然として最強。そして DeepSeek-R1 には衝撃的な事実が判明しました。
検証環境
CPU: Intel Core i3-14100T(4コア / 8スレッド、35W TDP)
RAM: 7.4 GB
OS: Ubuntu 22.04(ネイティブ Linux)
ツール: Ollama v0.18.2
GPU: なし(CPU推論のみ)
省電力デスクトップ向け CPU です。ゲーミング PC でもワークステーションでもない、普通のマシンで検証しています。
ベンチマーク設計
テストプロンプト(7問)
以下の 7 問を各モデルに投げ、推論速度(tokens/sec) と 回答品質 を計測しました。
| カテゴリ | プロンプト |
|---|---|
| 日本語 QA① | 東京の人口は約何人ですか? |
| 日本語 QA② | WebRTC と WebSocket の主な違いを3点で教えてください |
| 日本語 QA③ | 機械学習とディープラーニングの違いを2文で説明してください |
| 英語 QA① | What is the capital of France? |
| 英語 QA② | What is the time complexity of quicksort? |
| コード生成 | top-3 largest values without sort() |
| 推論(論理) | バットとボール問題(認知バイアステスト) |
Ollama API(/api/generate)を使用し、stream: false で全トークン生成後のメトリクスを取得しています。
結果:推論速度
tokens/sec 比較
| プロンプト | Qwen3.5:0.8b | Qwen3.5:2b | Qwen2.5:1.5b | DeepSeek-R1:1.5b | Gemma2:2b |
|---|---|---|---|---|---|
| 日本語 QA① | ⏱️ | 0.0 | 4.3 | 4.0 | 3.9 |
| 日本語 QA② | ⏱️ | ⏱️ | 4.0 | 3.9 | 3.4 |
| 日本語 QA③ | 12.1 | ⏱️ | 4.0 | 3.9 | 3.5 |
| 英語 QA① | 14.9 | 9.0 | 8.2 | 4.0 | 4.0 |
| 英語 QA② | 12.9 | 8.7 | 4.1 | 4.0 | 3.5 |
| コード生成 | ⏱️ | ⏱️ | 4.0 | ⏱️ | 3.5 |
| 推論(論理) | ⏱️ | ⏱️ | 3.9 | 3.9 | 3.4 |
単位: tokens/sec(高い方が高速)。⏱️ = 300秒タイムアウト
Qwen3.5 は tok/s だけ見れば圧倒的です。0.8b で 14.9 tok/s、2b で 9.0 tok/s — Qwen2.5 の 2〜3 倍速い。
しかし ⏱️ の多さが物語るように、実際の応答は返ってこないことが多い。その理由は次のセクションで解説します。
Qwen3.5 の罠 — thinking モードの暴走
Qwen3.5 にはデフォルトで thinking(推論)モード が搭載されています。これは回答前に「思考過程」を大量にトークン生成する機能です。
Qwen2.5: 質問 → 回答(30トークン) → 8秒で完了
Qwen3.5: 質問 → 🤔思考…思考…(3,000+トークン)→ 回答 → 270秒 or タイムアウト
実例を見てみましょう。
「機械学習とDLの違いを2文で」 という簡単な質問に対して:
- Qwen2.5:1.5b → 52秒(通常の回答)
- Qwen3.5:0.8b → 270秒、3,240トークン生成(回答自体は2文なのに思考過程が膨大)
「What is the capital of France?」 に対して:
- Qwen2.5:1.5b → 3.5秒
- Qwen3.5:0.8b → 41秒、591トークン生成("Paris" と答えるために591トークン思考)
tok/s が速くても、生成トークン数が 10〜100 倍になるため、実質的なレスポンスは遅くなります。 CPU 環境で thinking モデルを使うのは現時点では非実用的です。
thinking は OFF にできるのか?
当然の疑問として「thinking を OFF にすれば解決では?」と思うでしょう。結論から言うと、Ollama では現時点で完全に OFF にできません。
実際に検証しました。同じ質問「What is the capital of France?」に対して:
| モデル | 回答 | 生成トークン数 | 時間 |
|---|---|---|---|
| Qwen2.5:1.5b | Paris | 2 | 9.0s |
| Qwen3.5:0.8b | Paris | 188 | 12.8s |
Qwen3.5 は「Paris」と答えるために 186 トークン分の思考過程を生成 しています。出力には "Paris" しか表示されませんが、内部では思考が走っており、その分の計算時間がかかります。
thinking を OFF にする方法として議論されているのは以下の 3 つです。
| 方法 | 対応状況 |
|---|---|
プロンプトに /no_think を付与 |
❌ Ollama では効果なしの報告多数 |
chat_template_kwargs: {enable_thinking: false} |
❌ Ollama 未サポート(llama.cpp では可能) |
| Ollama の Modelfile でテンプレート書き換え | △ 一部成功報告あるが公式手順なし |
参考: ollama/ollama#14617 — 2026年3月時点で未解決
現時点での結論: Ollama + CPU 環境では、thinking なしの Qwen2.5 を選ぶのが正解です。Qwen3.5 の thinking OFF 対応は Ollama 側のアップデート待ちの状態です。
レスポンス時間(実測)
| プロンプト | Qwen3.5:0.8b | Qwen3.5:2b | Qwen2.5:1.5b | DeepSeek-R1:1.5b | Gemma2:2b |
|---|---|---|---|---|---|
| 日本語 QA①(短答) | >300s ⏱️ | 0.0s※ | 8.2s | 54.5s | 8.6s |
| 日本語 QA②(技術) | >300s ⏱️ | >300s ⏱️ | 62.8s | 137.2s | 122.2s |
| 日本語 QA③(比較) | 270.6s | >300s ⏱️ | 52.3s | 153.1s | 25.2s |
| 英語 QA①(短答) | 40.9s | 16.6s | 3.5s | 76.0s | 4.9s |
| 英語 QA②(技術) | 187.1s | 82.6s | 13.4s | 100.6s | 18.0s |
| コード生成 | >300s ⏱️ | >300s ⏱️ | 34.1s | >300s ⏱️ | 23.3s |
| 推論(論理) | >300s ⏱️ | >300s ⏱️ | 88.0s | 145.7s | 64.0s |
※ Qwen3.5:2b の日本語QA①は 0 トークン(空回答)
レスポンス時間で見ると Qwen2.5:1.5b が最も安定しています。Qwen3.5 と DeepSeek-R1 は thinking/推論の特性上、CPU では実用的なレスポンス時間を確保できません。
結果:回答品質
日本語 QA — 衝撃の事実
Q1: 東京の人口は?
| モデル | 回答 | 評価 |
|---|---|---|
| Qwen3.5:0.8b | (タイムアウト) | ⏱️ |
| Qwen3.5:2b | (空回答) | ❌ |
| Qwen2.5:1.5b | 東京市の現在の人口は約1,600万人です。 | △ |
| DeepSeek-R1:1.5b | 东京的人口约为375万至400万左右。 | ❌ |
| Gemma2:2b | 約370万人です。 | ❌ |
東京都の実際の人口は約 1,400 万人です。Qwen2.5 の「1,600万人」もやや不正確ですが、他モデルと比べると 桁が合っているだけでも圧倒的にマシ です。
DeepSeek-R1 は日本語で質問しても中国語で回答します。 1.5B パラメータでは日本語の言語能力が確保できていないようです。さらに数値も大幅に不正確です。
Gemma2 は日本語で返しますが、370 万人という数値は東京都区部の人口(約 980 万人)とも合わない謎の回答です。
Qwen2.5 だけが自然な日本語で概ね妥当な数値を回答しました。
Q2: WebRTC vs WebSocket
| モデル | 言語 | 技術的正確さ | 評価 |
|---|---|---|---|
| Qwen3.5:0.8b | (タイムアウト) | — | ⏱️ |
| Qwen3.5:2b | (タイムアウト) | — | ⏱️ |
| Qwen2.5:1.5b | 日本語 | UDPの言及あり、概ね正確 | ⭕ |
| DeepSeek-R1:1.5b | 中国語 | 「WebRTCはHTTPベース」と誤記 | ❌ |
| Gemma2:2b | 日本語 | P2Pの説明が正確 | ⭕ |
DeepSeek-R1 は中国語で回答した上に、「WebRTC は HTTP プロトコルベース」という技術的に誤った説明をしています。
Qwen3.5 は 2 モデルとも日本語の技術質問でタイムアウトしており、CPU 環境での日本語技術 QA には使えない という結果です。
英語 QA
英語では全モデル安定しています。thinking モデルも英語短答は返せました。
| Q: Capital of France? | 回答 |
|---|---|
| Qwen3.5:0.8b | Paris |
| Qwen3.5:2b | Paris |
| Qwen2.5:1.5b | Paris |
| DeepSeek-R1:1.5b | Paris |
| Gemma2:2b | Paris 🇫🇷 |
Gemma2 がフランス国旗の絵文字付きで返すのは面白い特徴です。
コード生成
テスト: top-3 largest values without sort()
Qwen3.5:0.8b / 2b ⏱️
→ 両モデルとも 300 秒タイムアウト。thinking モードでコード生成前に思考が終わりませんでした。
Qwen2.5:1.5b ✅
def find_top_three(nums):
max1, max2, max3 = float('-inf'), float('-inf'), float('-inf')
for num in nums:
if num > max1:
max3 = max2
max2 = max1
max1 = num
elif num > max2:
max3 = max2
max2 = num
elif num > max3:
max3 = num
return [max1, max2, max3]
→ O(n) のシンプルで正しい実装。sort() を使っていない。
DeepSeek-R1:1.5b ⏱️
→ 300 秒タイムアウト。chain-of-thought で延々と「考え続けた」結果、コードにたどり着けませんでした。
Gemma2:2b ❌
def top_three(data):
sorted_data = sorted(data, reverse=True)
return sorted_data[:3]
→ sorted() を使ってしまっています。 「sort() を使わない」という制約を守れていません(Python の sorted() は内部的にソートを行う)。
推論タスク(バットとボール問題)
バットとボールの合計は $1.10。バットはボールより $1.00 高い。ボールの値段は?
正解は $0.05($0.10 は認知バイアスによる誤答)。
| モデル | 回答 | 正誤 |
|---|---|---|
| Qwen3.5:0.8b | (タイムアウト) | ⏱️ |
| Qwen3.5:2b | (タイムアウト) | ⏱️ |
| Qwen2.5:1.5b | 連立方程式で $0.05 を導出 | ✅ |
| DeepSeek-R1:1.5b | 変数定義して推論開始(途中切れだが方向は正しい) | △ |
| Gemma2:2b | 変数定義して推論(途中切れだが方向は正しい) | △ |
Qwen2.5 が最も簡潔に正解にたどり着いています。Qwen3.5 は推論タスクこそ得意なはずですが、CPU 環境では thinking の生成量が多すぎてタイムアウトしてしまいました。
総合評価
| 評価項目 | 🥇 1位 | 🥈 2位 | 🥉 3位 |
|---|---|---|---|
| tok/s(生の速度) | Qwen3.5:0.8b (15) | Qwen3.5:2b (9) | Qwen2.5 (8) |
| レスポンス時間 | Qwen2.5 | Gemma2 | Qwen3.5 |
| 日本語品質 | Qwen2.5 | Gemma2 | Qwen3.5 |
| 英語品質 | Qwen3.5 / Qwen2.5 | Gemma2 | DeepSeek-R1 |
| コード生成 | Qwen2.5 | Gemma2(※制約違反) | 他3モデル ⏱️ |
| 推論・論理 | Qwen2.5 | Gemma2 | DeepSeek-R1 |
| 安定性 | Qwen2.5 | Gemma2 | 他3モデル |
用途別おすすめ
| 用途 | おすすめ | 理由 |
|---|---|---|
| 日本語タスク全般 | Qwen2.5:1.5b | 日本語品質・安定性ともに最強 |
| 英語タスク | Qwen2.5:1.5b | 速度と安定性のバランス |
| 官公庁・防衛案件 | Gemma2:2b | Google 製。中国製モデルの説明コスト回避 |
| GPU 環境 | Qwen3.5:2b | thinking の恩恵を受けられる |
| 推論・数学 | Qwen2.5:1.5b | CPU ではタイムアウトしない安定感 |
| コード生成 | Qwen2.5:1.5b | 制約を守った正しいコードを生成 |
thinking / 推論モデルが CPU で遅い理由
DeepSeek-R1 と Qwen3.5 に共通する問題です。
両モデルとも thinking(推論)機能 を持ち、回答前に「思考過程」を大量にトークン生成します。
通常モデル(Qwen2.5): 質問 → 回答(30トークン)
推論モデル(Qwen3.5): 質問 → 🤔思考(3,000トークン)→ 回答
推論モデル(DeepSeek): 質問 → 🤔思考(500トークン)→ 回答
tok/s が同じでも、生成トークン数が 10〜100 倍 になるため、レスポンス時間は桁違いに長くなります。
GPU 環境(50+ tok/s)なら thinking の恩恵を受けつつ実用的な速度を維持できますが、CPU(4〜15 tok/s)では致命的です。CPU 環境では thinking なしの通常モデルを選ぶべき というのが、今回の検証から得られた最大の教訓です。
ローカル完結の真の価値
ベンチマーク数値を見ると、クラウドの大型モデルには遠く及びません。しかし、本質的な価値は別のところにあります。
GPT-4o Realtime API の料金: 約 $0.20/分
1日8時間 × 20営業日: $1,920/月(約29万円)
ローカル CPU モデル: $0/月(永続)
コストだけではありません。複数の市場調査で、音声 AI サービスに対するユーザーの最大の懸念は プライバシー であると報告されています。
医療・金融・法務・官公庁 では、データをクラウドに送ること自体がコンプライアンス違反になりえます。ローカル完結なら データが一切外部に出ません。
| 比較 | クラウド API | ローカル CPU |
|---|---|---|
| 速度 | 50-100+ tok/s | 3-8 tok/s |
| コスト | 従量課金 | ¥0 |
| プライバシー | データが外部に送信される | 完全ローカル |
| オフライン | 不可 | 可能 |
| レイテンシ | ネットワーク依存 | ゼロ |
リアルタイム会話に必要な速度は?
ベンチマーク結果を見て気になるのは、「結局リアルタイムで会話できるの?」という点です。
会話に必要な速度の基準
人間の日本語発話速度は約 5〜8 文字/秒(NHK アナウンサー基準)。LLM の 1 トークンは日本語で約 1〜2 文字に相当するため、TTS(音声合成)がスムーズに読み上げるには 最低 5 tok/s 程度 の生成速度が必要です。
さらに重要なのが First Token Latency(最初の 1 トークンが出るまでの時間)です。人間の会話で許容される応答遅延は 200〜500ms 程度。これを超えると「間」が不自然になります。
| レベル | 必要速度 | 体感 |
|---|---|---|
| 🟢 自然な会話 | 15〜30+ tok/s | 人間同士の会話に近い |
| 🟡 なんとか使える | 8〜15 tok/s | ストリーミング TTS 併用で可 |
| 🔴 厳しい | < 8 tok/s | 明らかに「考え中…」の間が生じる |
今回の計測結果と照合
| モデル | 実測速度 | 判定 |
|---|---|---|
| Qwen2.5:1.5b | 4.0〜8.2 tok/s | 🔴〜🟡 ギリギリ |
| DeepSeek-R1:1.5b | 3.9〜4.0 tok/s | 🔴 不可 |
| Gemma2:2b | 3.4〜4.0 tok/s | 🔴 不可 |
CPU only の Core i3 では、リアルタイム会話は厳しい というのが正直な結論です。
ストリーミング TTS で活路を開く
ただし、全トークン生成を待ってから音声合成する従来方式ではなく、ストリーミング TTS を使えば状況は変わります。
従来方式: 全トークン生成完了 → TTS → 再生(遅い)
ストリーミング: 数トークン生成 → 即TTS再生 → 並行して次のトークン生成
この方式なら 5〜8 tok/s でも体感的にはそこそこ会話らしくなります。ただし最初の発話開始までに 1〜2 秒の遅延は残ります。
GPU を使えばどうなるか
| ハードウェア | 推定速度 | 判定 |
|---|---|---|
| CPU (Core i3) | 3〜8 tok/s | 🔴 バッチ処理向け |
| GPU (RTX 3060) | 30〜50+ tok/s | 🟢 自然な会話可能 |
| GPU (RTX 4070) | 50〜80+ tok/s | 🟢 余裕あり |
| NPU 搭載エッジデバイス | 20〜40 tok/s | 🟡〜🟢 次世代の本命 |
CPU はバッチ処理・オフライン用途、リアルタイム会話は GPU または NPU という棲み分けが現実的です。
まとめ
CPU only 環境での小型LLM実機ベンチマーク結果:
- Qwen2.5:1.5b が総合優勝。日本語・英語・コード・推論すべてで最も安定。CPU 環境ならこれ一択
- Qwen3.5 は速いが「考えすぎ」で暴走する。tok/s は最速だが、thinking モードで 3,000+ トークン生成してタイムアウト続出。GPU 環境向き
- DeepSeek-R1:1.5b は日本語が使えない。日本語で聞いても中国語で返答する
- Gemma2:2b は日本語がまずまず。官公庁案件での採用しやすさが強み
- CPU 環境では thinking なしの通常モデルを選ぶべき。推論モデルの恩恵は GPU 環境でこそ発揮される
エッジ AI 音声エージェントの構築に向けた検証として、今後は QLoRA による特化ファインチューニングや、GPU 環境での比較検証も予定しています。
検証スクリプト
import json, time, requests
MODELS = ["qwen3.5:0.8b", "qwen3.5:2b", "qwen2.5:1.5b", "deepseek-r1:1.5b", "gemma2:2b"]
PROMPTS = {
"ja_tokyo": "東京の人口は約何人ですか?簡潔に答えてください。",
"ja_webrtc": "WebRTCとWebSocketの主な違いを3点で教えてください。",
"ja_ml": "機械学習とディープラーニングの違いを2文で説明してください。",
"en_capital": "What is the capital of France? Answer in one word.",
"en_sort": "What is the time complexity of quicksort? Answer briefly.",
"code": "Write a Python function that takes a list of numbers and returns the top-3 largest values without using sort().",
"logic": "A bat and a ball cost $1.10 in total. The bat costs $1.00 more than the ball. How much does the ball cost?",
}
def query(model, prompt, timeout=300):
try:
resp = requests.post("http://localhost:11434/api/generate",
json={"model": model, "prompt": prompt, "stream": False}, timeout=timeout)
d = resp.json()
ec = d.get("eval_count", 0)
ed = d.get("eval_duration", 1)
tps = ec / (ed / 1e9) if ed > 0 else 0
return {"response": d["response"], "tokens_per_sec": round(tps, 2),
"total_sec": round(d["total_duration"] / 1e9, 2)}
except requests.exceptions.Timeout:
return {"response": "TIMEOUT", "tokens_per_sec": 0, "total_sec": timeout}
for model in MODELS:
for key, prompt in PROMPTS.items():
r = query(model, prompt)
print(f"{model} | {key} | {r['tokens_per_sec']} tok/s | {r['total_sec']}s")
# 実行方法
ollama serve &
ollama pull qwen3.5:0.8b && ollama pull qwen3.5:2b && ollama pull qwen2.5:1.5b && ollama pull deepseek-r1:1.5b && ollama pull gemma2:2b
python3 benchmark.py