背景
先日、GoogleからGemma 3 270m-itがリリースされました。
このモデルはわずか270Mパラメータで指示追従が可能な小型モデルです。
メモリ使用量は4-bit量子化でわずか250MB弱なので、ラズパイZero 2Wに乗るのでは?と思い、試してみました。
推論にはllama.cppを用いましたが、実機上でビルドするとラズパイが落ちるため、クロスコンパイルを行いました。
環境
Raspberry Pi Zero 2W: Debian 12(aarch64)
クロスコンパイル環境: Debian 13(x86-64) + aarch64-linux-gnu-gcc-12, aarch64-linux-gnu-g++-12
クロスコンパイル環境にはaarch64用のgcc, g++をインストールしておきます。
クロスコンパイル
sysrootの取得
ビルド時にラズパイ側のライブラリを使ってもらえるようにラズパイ側のsysrootを取得します。
適当なディレクトリ(ここではrpi-sysrootとします)を作り、その中にラズパイ側の/lib/
, /usr/lib/
, /usr/include/
をコピーします。私はrsyncを使いました。
rsync -avz pi@raspberrypi.local:/lib/ ./rpi-sysroot/lib/
rsync -avz pi@raspberrypi.local:/usr/lib/ ./rpi-sysroot/usr/lib/
rsync -avz pi@raspberrypi.local:/usr/include/ ./rpi-sysroot/usr/include
CMAKEツールチェインファイルの構成
コマンドラインにビルドオプションを長々と書いてしまうと調整時に問題が出るかもしれないので、CMAKEツールチェインファイル機能を使って各種オプションを一括で設定します。自環境で使ったものをそのまま書いただけなので、自身の環境に合わせて調整してください。/path/to/rpi-sysroot/は先ほど取得したsysrootへのパスに置き換えてください。
# ターゲット環境の設定
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
# クロスコンパイラを指定
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc-12)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++-12)
# ラズパイ側から取得した sysroot へのパスを指定
set(CMAKE_SYSROOT /path/to/rpi-sysroot)
# sysroot を使った include / lib パスの自動設定を有効化
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so")
# C++/Cコンパイラのオプション設定
# ラズパイsysroot内のC++ライブラリを明示的に使うように強制し、リンカーにもsysrootの位置を渡しておく。また、コンパイラのmarchオプションをCortex-A53にしておく。
set(CMAKE_CXX_FLAGS "-mcpu=cortex-a53 --sysroot=${CMAKE_SYSROOT} -I${CMAKE_SYSROOT}/usr/include/c++/12 ${CMAKE_CXX_FLAGS} -isystem /path/to/rpi-sysroot/usr/include/c++/12 -isystem /path/to/rpi-sysroot/usr/include/aarch64-linux-gnu/c++/12")
set(CMAKE_EXE_LINKER_FLAGS "--sysroot=${CMAKE_SYSROOT} ${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_C_FLAGS "-mcpu=cortex-a53")
# ホストのライブラリを拾わないように制限
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# ARMのF16命令付きでコンパイルしようとするとエラーになるので無効化
set(GGML_NO_ARM_F16 ON)
# 静的ビルドにする
set(CMAKE_SHARED_LIBS OFF)
ビルド
cmakeで構成、ビルドします。
cmake -B ./build -S . -DCMAKE_TOOLCHAIN_FILE=rpi-aarch64.cmake
ビルドに成功したらllama.cppのディレクトリをラズパイにコピーします。pi@raspberrypiのところはご自身のラズパイのアドレスに置き換えてください。
scp -r ./llama.cpp pi@raspberrypi:/home/pi/
バージョンを確認してみましょう。
pi@raspberrypi:~/llama.cpp $ ./build/bin/llama-server --version
version: 6178 (5e6229a8)
built with gcc-12 (Debian 12.4.0-5) 12.4.0 for aarch64-linux-gnu
表示されれば成功です。
実行
Gemmaのモデルをダウンロードします。今回はunslothの4-bit Quantのggufを利用しました。
curl -O -L https://huggingface.co/unsloth/gemma-3-270m-it-GGUF/resolve/main/gemma-3-270m-it-IQ4_NL.gguf
ダウンロードし終えたら実行します。今回はllama.cppのhttpサーバー+簡易WebUI機能を使ってテストします。
./build/bin/llama-server -m gemma-3-270m-it-IQ4_NL.gguf --host 0.0.0.0
Webブラウザで[ラズパイのアドレス]:8080にアクセスすると、WebUIが開きます。これでお喋りできます。
いろいろ試してみる
他の言語モデルと同様、英語のほうが得意ですが、日本語も全くできないわけではないようです。他の小型モデルでは英語だと受け答えができても、日本語では完全に破綻しているということは珍しくありません。そういった意味でGemma 3 270m-itは驚異的です。
そしてメモリに収まっていれば、毎秒6~7トークンが出力されています。ラズパイ Zero 2Wのスペックを鑑みると、この速度も驚異的です。
ただし、メモリに余裕がなくなってデータがSwapされると急に低速になることがあるので、安定したパフォーマンスを実現したいならメモリ使用量の少ないRaspberry Pi OS以外の組み込みLinuxディストロ(Yocto, Buildrootなど)の利用を検討しても良いでしょう。