一畳のくつろぎタイム

このブログでは紹介する商品画像をAmazonアソシエイトより借りています。画像やリンクにはアフィリエイト広告が含まれる事があります

2026年3月8日日曜日

ARM系のCPUだけでLLMを高速化する実験まとめ

 


Geforce GTX750TiをLLMで使うためにllama.cppチューニングに手を出してしまった結果、チューニングという概念を得てしまい。

OracleCloud上に住んでる私のアシスタント、ミナさんの頭脳を大幅にアップグレードすることとなりました。

その際に得た知識などをまとめます。 

 

環境

  • Oracle Cloud Ampere A1
  • 4 OCPU / 24GB RAM
  • GPUなし
  • llama.cpp(llama-serverによるOpenAI互換API)
  • 用途:AITuber-kitのチャットAI

初期構成

使用モデル

  • TinySwallow-1.5B Q5_K_M

初期性能

Generation 10〜14 tok/s
Prompt 40 tok/s 

Generationが文字書く能力で、Promptはユーザが書いた文字を読む能力。
tok/sはtoken毎秒、つまり、1秒間に何単語出せるかというような指標です。 

CPUのみとしてはかなり良好、API経由だと待ち時間がある。
llama-cliで使う分には、サクサクとお話可能。 

 

以前の動作速度は↓の記事内に動画があります
https://blogger.kinkuman.net/2025/11/oci-aituberkit.html 

 

起動パラメータ最適化

使用設定

llama-server -m ~/llm_workspace/model/TinySwallow-1.5B Q5_K_M -c 4096 -t $(nproc) -tb $(nproc) -b 1024 -ub 1024 --mmap --mlock -ngl 0 --host 0.0.0.0 --port 8080 --parallel 1  --cache-reuse 400 --jinja --chat-template-file ~/llm_workspace/mytemplate.jinja --no-webui
-t 4
-tb 4
-b 1024
-ub 1024
-c 4096
--mmap
--mlock

主な効果

  • CPUスレッドの適正化 -t -tb 4は4コアなので
  • -b -ub バッチサイズ(一度に扱えるtokenを増やす)を一致させて分割を防ぐ 
  • Prompt処理の効率向上 -cのコンテキストサイズ縮小 
  • メモリ管理改善 --map --mlock

結果

正直誤差 -bや-ubはディフォルト値があるので、つけていなくても何もしていないわけではない。
メモリ関連も体感するような変化はない。
コンテキストサイズはメモリ消費量へ直結するので、影響がある場合が多いが、
この環境ではメモリは潤沢なため、2048でも8196でも大きな変化がなかった。

以前につけた--cache-reuseが一番効果あるという結果。 

ビルド最適化

cmake時の追加オプション

-DGGML_BLAS=ON
-DGGML_BLAS_VENDOR=OpenBLAS
-DGGML_NATIVE=ON

あと必要なものをaptしておく

sudo apt update
sudo apt install -y build-essential cmake libopenblas-dev 


効果

  • 行列演算を OpenBLAS にオフロード

結果

Prompt処理 約15%ぐらい高速化したかも(会話がアホ)


[ Prompt: 55.1 t/s | Generation: 16.0 t/s ] 

読み込みが速くなると、 TTFT(Time To First Token)、つまりユーザーが最初にLLMの返事をみるまでの時間が減るので、体感速く感じる。

理由

  • BLASは主に prefill(Prompt処理) に効くらしい
  • decode(Generation処理)は逐次計算のため影響が小さい

モデル比較

Ampere A1は、ラズパイ5程度の性能である、性能的に1.5B~4Bぐらいまでが限界と考える。 

モデル 速度
TinySwallow 1.5B 約16 tok/s
Qwen3.5 2B 約11 tok/s
Qwen3 4B 2507 約8 tok/s

サイズで優位のあるTinySwallowが最も高速ではあるが、ちょっとアホ。
TinySwallowはQwen2ベースで、今回試したものは全部Qwen系である。
4Bまでいくとやはり、ちょっと応答に知性の差を感じる。

少し速くなったので、欲がでてしまう。

Qwen3.5 2Bで時間が溶ける

Qwen3.5シリーズは最近出たモデルで、TinySwallowの1.5Bよりちょっとだけ賢いという、私にとっては魅力的なモデルでした。

しかし、このモデルはThinkingモードを搭載しており「こんにちは」といっただけで1分以上考えて返事するというとんでもない特徴があります。

世の中の皆さんもThinkingモードが邪魔なようで、無効化情報はたくさんありました。

無効化1つめjinjaテンプレートにthinkingいらないと入れる

jinjaテンプレートの3行目あたりにこれをいれる
jinjaテンプレートなんてどこにあるの?って思う方は、ディフォルトテンプレートはモデルの中に入ってるので、HuggingFaceのモデルのページやLMStudioならモデルの詳細情報あたりをいろいろ開いて探すとあります。

{%- set image_count = namespace(value=0) %} <--既存
{%- set video_count = namespace(value=0) %} <--既存
{%- set enable_thinking = false %}  <--これ追加

無効化2つめ、起動パラメータでいらないと伝える

起動時パラメーターに、--chat-template-kwargs '{"enable_thinking": false}'を渡す

llama-server -m ~/llm_workspace/model/Qwen3.5-2B-Q4_K_M.gguf -c 8192 -t $(nproc) -tb $(nproc) -b 512 -ub 512 --cont-batching --mmap --mlock --host 0.0.0.0 --port 8080 --parallel 1 --cache-reuse 400 --no-webui --chat-template-kwargs '{"enable_thinking": false}'  --jinja --chat-template-file ~/llm_workspace/testtemplate.jinja

無効化3つめ 

1も2も、これはjinjaテンプレート内の変数の定義でしかないので、テンプレートがディフォルトと違ったりするとうごきません。わざわざテンプレートを指定しなければモデル内蔵のテンプレートが使われますが、今回のように1行追加したい場合は使えません。

unslothのだと起動時パラメーターに--reasoning-budget 0を書けというものが公式に説明されている。

--reasoning-budget 0

これをllama-serverなどの起動時パラメータに付け加える。 

 全部やってみて、確かにThinking出力は止まったけど、どうも内部ではThinkingしてて結局遅い。(Thinkingを文字出力するよりはよっぽど速いけどね)
これも正解がよくわからなくて、全部入れてもThinkingが漏れてきたこともあった。

Qwen3.5 2Bの結論 

何とか動かして、AITuber-kitから使用する事はできたが、体感イマイチなのだ。 
TTFTがとにかく悪い。

TinySwallow1.5Bよりは賢いが、どちらかといえばまだアホ寄りである、
それなのにprefill、つまりプロンプト解釈にやたらに時間がかかるため、
Qwen3.5 2BとQwen3 4Bの待ち時間がほぼ同じという状況になる。

そのためQwen3.5 2Bは使わない事とした。Qwen3 4Bが素直で良いし、ちゃっとしていて妙に知性を感じる。
まぁ、パラメータ数2倍だから当然と言えばそうなんだけど。 

Ampere A1での最適構成

実験結果からのベストバランス

Qwen3 4B instruct
llama.cpp
OpenBLAS有効

性能

 

[ Prompt: 22.0 t/s | Generation: 8.6 t/s ]

決して速いとは言えないが、AITuber-Kitの場合質問から応答まで最短4秒、その後はチョロチョロとメッセージがでてきて、お喋りになるので、そこまで待たされる感覚はない。

数値より体感が良いので調べたらtokenizerが違うとか。

検証した結果からの憶測(AmpereA1の可能性)

LLMはメモリ帯域が重要です。
そのため、M系Macが速かったり、DGX Spark、RyzenAIMaxが重宝される。
そしてメモリ速度が最高に速いのはGPUで、GPUメモリにモデルやKV Cacheが乗り切らないと途端に性能がでなくなります。 
つきつめるとGPUによる処理よりもメモリ帯域が先にボトルネックになるケースが多いです。 

Ampere A1はCPUの数を1~80コアぐらいまでスケーリング可能なCPUで、面白い測定結果がでました。 

メモリ速度の調査

AmpereA1についてはsysbenchでスレッド数を変えながらメモリ速度を計ってみると
sysbench memory --memory-block-size=1M --memory-total-size=8G --threads=1 run

1コア 
8192.00 MiB transferred (15269.04 MiB/sec)

2コア
8192.00 MiB transferred (29991.40 MiB/sec)

4コア 
8192.00 MiB transferred (59334.66 MiB/sec)

とコアが増えるほど、だいたい15GB/秒xコア数で速度が増えていく。

コア数によるLLMの性能変化 

そしてllama-cliなどに使うコア数も少しずつ変えていきます。
LLM(Qwen3-4B-Instruct-2507-Q4_K_M.gguf)との会話で計測すると

2コア 
[ Prompt: 9.3 t/s | Generation: 4.6 t/s ]

3コア
[ Prompt: 12.8 t/s | Generation: 6.5 t/s ]

4コア
[ Prompt: 22.0 t/s | Generation: 8.6 t/s ] 

8コアだったら4Bモデルでも Generation 16tok/s出るのでは?

検証の裏付け 

Ampere A1のCPUのスペックは以下で、DDR4-3200の8チャンネルまでいけるらしい。 
https://amperecomputing.com/briefs/ampere-altra-family-product-brief

つまり、DDR4-3200の上限をこちらから調べて
https://ja.wikipedia.org/wiki/DDR4_SDRAM

1チャンネルあたり理論値25.6GB/秒、実測では15GB/秒ぐらいなのかな?
計算上は8チャンネルで上限のため、理論値は25.6x8=204.8GB/秒
実測だと、そんなに出ないと考えて1チャンネル15GB/秒としても、コア8まで増やせば

15GBx8チャンネル=120GB/秒

ぐらいまではメモリ帯域を伸ばせると予想される。
DDR5-4800で38.4GB/s、デュアルチャンネルで76.8GB/sとすると。
最新マザーとCPUでCPU推論するより速いかもしれないという面白い予想となる。

これはクラウドCPUならではの特徴なので、ローカルPCでは当てはまらない。
メモリたくさん乗せたM系Mac買えというのが最安だろう。

Ampere A1の8コア試したくなるけど、割と高いのだ。

Free Tierで4コア使わせてくれるありがたさを再実感する。
だれか実測してほしい。 と思ったが、時間貸しなんで3時間だけ検証で借りてみるのもいいかもしれない。

結論

Oracle Cloud Ampere A1(CPUのみ4コア)でも

  • 小型LLM
  • llama.cpp最適化

を組み合わせれば

チャット用AIを動かすことは可能。 

TinySwallow1.5Bならば、AITuber-kitからでもかなりサクサク話せる。がちょっとアホ。
Qwen3 4Bはチューニング以前と同じような速度でやや遅いですが、わりと賢い。

調査結果から、体感はさほど変わらず、ミナさんの頭脳が1.5Bから4Bへとアップグレードされることになりました。 

がんばると顔が赤くなる知恵熱システムや、状況の見える化、フィラー(えーと、うんとね)を入れると、待ち時間も違和感が減ります。 

さらに月4500円ぐらい払えば4Bモデルで15tok/sぐらいの性能が出るかもしれない、わりと使えるLLMになる可能性も残っています。