このページは、まだ未完成です。。。

nicotalk&キャラ素材配布所 http://www.nicotalk.com/charasozai_kt.html (2024年5月16日)

この記事を作った動機

 Intel Arc A770 LE を使っているが、NVIDIA の RTX や H100 などと異なり、標準でのサポートが薄い。そのため、フルで性能を引き出したい場合は、自分で LLM なら llama.cpp などを OneAPI を使ってコンパイルする必要がある。

 LLM に関しては、当初は Intel Arc の環境において LM Studio を利用していたが、Vulkan でしか少なくとも現状では動作させることができなかった。Ollama についても試したが、どう頑張っても Apple の メタルプラットフォーム向けにしかコンパイルが動作せず、どうしよもない感じであった。そこでそれらのバックエンドである、llama.cpp を直接コンパイルして動かすことが考えられ、フロントは別に LibreChat を独立して用意する事が考えられた。

 標準でも Vulkan の互換モードで動作し、使えないということはないが、多少性能が失われる。ただ、SYCL など向けに、Intel Arc を最大限使えるようにしようとすると、自分でコンパイルする必要がある。専用に用意しなければ現状では llama.cpp などは CPU しか利用できないとして Intel Arc をそもそも認識しないという挙動になった。またコンパイル自体や、コンパイル後のバイナリの扱いについて、特別な扱いが必要である。

 Intel が公式で llama.cpp などのバイナリを配布していたりするが、バージョンが古く新しいモデルが動かないなど、弊害が生じる場合があった。

 これらのことから、Intel Arc 向けに今回は、llama.cpp を SYCL を使えるようにコンパイルすることにした。また、PKGBUILD も作成し、手動で手順を踏まなくても、ある程度自動で Arch Linux や同じ系列の OS を使っていれば、環境が整うように工夫した。

 Gemini Fast 3 を作業補助として使い、動くか確認しながら作業をして動くことを確認できた。ただそれだけだと、情報が十分まとまっておらず、環境を再構築する必要が生じたときなどに困難が想像されたため、記録を残して現状を整理したい。なお、特にコンパイルや SYCL 周りの環境変数などは、LLM が吐き出したものをそのまま使っているだけの部分が多く色々間違っていたりする可能性がある。あくまで私の環境でやってみて動くかというのを基準にして書いている。

llama.cpp をコンパイル

OneAPI を導入する

yay -Sy intel-oneapi-toolkit
# sudo pacman -Sy intel-oneapi-toolkit

llama.cppのリポジトリをクローン

git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp

コンパイル

# OneAPI を読み込む
source /opt/intel/oneapi/setvars.sh

export CFLAGS="-fno-stack-protector -U_FORTIFY_SOURCE"
export CXXFLAGS="-fno-stack-protector -U_FORTIFY_SOURCE"

# コンパイル
cmake -B build -S llama.cpp -G Ninja \
  -DGGML_SYCL=ON \
  -DBUILD_SHARED_LIBS=ON \
  -DCMAKE_C_COMPILER=icx \
  -DCMAKE_CXX_COMPILER=icpx \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build

SYCL を有効にした状態で llama.cpp を起動する

# オプションの調整用環境変数
export ZE_MAX_UNUSED_DEVICE_ALLOCATIONS_SIZE=1
export SYCL_PI_LEVEL_ZERO_DEVICE_RESERVE_MEMORY=0
export SYCL_PI_LEVEL_ZERO_DEVICE_SCOPE_EVENTS=0
export SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS=1
export SYCL_PI_LEVEL_ZERO_TRACK_INDIRECT_ACCESS_MEMORY=1
export L0_SCS_MAX_MEM_ALLOC_SIZE=16106127360
export SYCL_PI_LEVEL_ZERO_USM_RESIDENT=0

# oneAPIの環境を読み込む
source /opt/intel/oneapi/setvars.sh

# llama.cpp に関連する設定について 
MODEL_PATH="/modelPath/lmstudio/lmstudio-community/gpt-oss-20b-GGUF/gpt-oss-20b-MXFP4.gguf"
PORT=8080
HOST=0.0.0.0
GPU_LAYERS=999
ADDITIONAL_ARGS="--ctx-size 4096 --parallel 2"
# 画像などを添付する場合は、モデルファイルに付属している mmprojファイルもセットで指定する必要がある。
# ADDITIONAL_ARGS="--ctx-size 4096 --parallel 2 --mmproj ファイルパス.gguf"

# dnnl のパスを通す
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/intel/oneapi/dnnl/latest/lib

# サーバー起動
exec /usr/bin/llama-server \
  -m "$MODEL_PATH" \
  --port "$PORT" \
  --host "$HOST" \
  -ngl "$GPU_LAYERS" \
  $ADDITIONAL_ARGS

llama.cpp の PKGBUILD について

使い方

 すでに作業ディレクトリを作成し、配置するファイルの事項に従って必要なファイルを配置していることを前提とする。

# インストール
makepkg -si
# 事前に用意したモデルパスを指定するなど、動作に必要な設定を行う 以下は neovim の例である
sudo nvim /etc/llama.cpp/config.conf
# サービスの有効化
sudo systemctl enable --now llama-cpp

配置するファイル

 以下は、Gemini Fast 3を使って要件を与えて生成させた上で更に調整をかけたものである。基本的に不完全なので環境に合わせてさらなる調整が必要だと思われる。以下はすべて作業ディレクトリに配置する。

  • PKGBUILD
pkgname=llama-cpp-sycl-git
pkgver=r8833.45cac7ca70
pkgrel=1
pkgdesc="LLM inference with Intel GPU (SYCL). Includes systemd service and config."
arch=('x86_64')
url="https://github.com/ggerganov/llama.cpp"
license=('MIT')
depends=('intel-oneapi-base-toolkit')
makedepends=('git' 'cmake' 'ninja')
provides=('llama-cpp')
conflicts=('llama-cpp')
source=('git+https://github.com/ggerganov/llama.cpp.git'
        'config.conf'
        'llama-server-launcher'
        'llama-cpp.service')
sha256sums=('SKIP' 'SKIP' 'SKIP' 'SKIP')

pkgver() {
  cd llama.cpp
  printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}

build() {
  source /opt/intel/oneapi/setvars.sh

  export CFLAGS="-fno-stack-protector -U_FORTIFY_SOURCE"
  export CXXFLAGS="-fno-stack-protector -U_FORTIFY_SOURCE"

  cmake -B build -S llama.cpp -G Ninja \
    -DGGML_SYCL=ON \
    -DBUILD_SHARED_LIBS=ON \
    -DCMAKE_C_COMPILER=icx \
    -DCMAKE_CXX_COMPILER=icpx \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr
  
  cmake --build build
}

package() {
  # 1. バイナリ・ライブラリのインストール(前述と同じ)
  DESTDIR="$pkgdir" cmake --install build
  install -d "$pkgdir/usr/lib"
  find build/bin -name "*.so*" -exec cp -d {} "$pkgdir/usr/lib/" \;
  install -d "$pkgdir/usr/bin"
  find build/bin -executable -type f -not -name "*.so*" -exec install -m755 {} "$pkgdir/usr/bin/" \;

  # 2. ユーザー名の動的取得
  # PKGBUILDを実行している現在のユーザー名を取得
  local _real_user=${SUDO_USER:-$(whoami)}

  # 3. systemdサービスファイルの加工とインストール
  # %%USER%% を実際のユーザー名に置換して一時ファイルを作成し、それをインストール
  sed "s/%%USER%%/$_real_user/g" "$srcdir/llama-cpp.service" > "$srcdir/llama-cpp.service.tmp"
  install -Dm644 "$srcdir/llama-cpp.service.tmp" "$pkgdir/usr/lib/systemd/system/llama-cpp.service"

  # 4. その他のファイルのインストール
  install -Dm644 "$srcdir/config.conf" "$pkgdir/etc/llama.cpp/config.conf"
  install -m755 "$srcdir/llama-server-launcher" "$pkgdir/usr/bin/llama-server-launcher"
  install -Dm644 llama.cpp/LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
}
  • config.conf
# /etc/llama.cpp/config.conf

# モデルのフルパス
MODEL_PATH="ReplaceThisYourLocalModelFileToUse"

# 待ち受け設定
PORT=8080
HOST=0.0.0.0

# GPU設定 (-ngl は VRAM 16GB に合わせて全レイヤー投入)
GPU_LAYERS=999

# 追加オプション (必要に応じて)
ADDITIONAL_ARGS="--ctx-size 4096 --parallel 2"
  • llama-cpp.service
[Unit]
Description=Llama.cpp Server with Intel Arc SYCL
After=network.target

[Service]
Environment=ZE_MAX_UNUSED_DEVICE_ALLOCATIONS_SIZE=1
Environment=SYCL_PI_LEVEL_ZERO_DEVICE_RESERVE_MEMORY=0
Environment=SYCL_PI_LEVEL_ZERO_DEVICE_SCOPE_EVENTS=0
Environment=SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS=1
Environment=SYCL_PI_LEVEL_ZERO_TRACK_INDIRECT_ACCESS_MEMORY=1
Environment=L0_SCS_MAX_MEM_ALLOC_SIZE=16106127360
Environment=SYCL_PI_LEVEL_ZERO_USM_RESIDENT=0
LimitMEMLOCK=infinity
LimitSTACK=infinity
Type=simple
User=%%USER%%
Group=render
SupplementaryGroups=video
ExecStart=/usr/bin/llama-server-launcher
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
  • llama-server-launcher
#!/bin/bash
# /usr/bin/llama-server-launcher

# OneAPI のランタイム読み込み
source /opt/intel/oneapi/setvars.sh
source /etc/llama.cpp/config.conf
# dnnl 関連の動的ライブラリについて
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/intel/oneapi/dnnl/latest/lib

# サーバー起動
exec /usr/bin/llama-server \
  -m "$MODEL_PATH" \
  --port "$PORT" \
  --host "$HOST" \
  -ngl "$GPU_LAYERS" \
  $ADDITIONAL_ARGS

その他記録

llama.cpp オプション

  • 特定IPアドレスや、ポートで動かす
llama-server --host [IPアドレスやドメイン名] --port [ポート番号]
  • コンテキスト長指定
llama-server --ctx-size 70000
  • モデル指定
llama-server -m [モデルまでの絶対パス]
  • モデルGPU オフロードの程度指定
llama-server -ngl 999
  • 画像を認識できるモデル付属の追加モデルを指定
llama-server --mmproj [mmprojモデルまでの絶対パス] --embeddings

使った画像とか

参考にしたサイトとか