CUDA13環境下でGPU使用版のllama.cppを導入しC++ライブラリを使う
POSTED BY
2025-12-03
2025-12-03

当方の環境は以下の通りである。
Debian GNU/Linux 12 (bookworm) Linux 6.1.0-41-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.158-1 (2025-11-09) x86_64 GNU/Linux NVIDIA-SMI 580.105.08 Driver Version: 580.105.08 CUDA Version: 13.0 VGA compatible controller: NVIDIA Corporation AD106 [GeForce RTX 4060 Ti] (rev a1) Python 3.11.2
GPU版のllama.cppコマンドおよびライブラリは、以下のようにして導入する。
git clone https://github.com/ggerganov/llama.cpp cd llama.cpp cmake -B build -DLLAMA_CURL=OFF -DGGML_CUDA=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release cmake --build build --config Release -j
このようにすると、build/bin以下に、llama-cli, llama-server, libllama.so, libggml.so, libggml-base.so, libggml-cuda.soが出来上がる。なおincludeはinclude, ggml/include内にある。
単体テストコマンド
llama.cpp/build/bin/llama-cli -m Qwen3VL-8B-Instruct-Q8_0.gguf -p "###INPUT:以降の文章から出発時間と思われる表現と、到着時間と思われる表現を抜き出しYYYYMMDDHHMM形式で推測しJSONで出力せよ。また、出発地と思われる表現と、目的地と思われる表現を抜き出してJSONで出力せよ。JSON以外は出力しないこと。なお本日は20251203である。###INPUT:「いやー、明日午後に新宿を出て、神奈川へ向かいます。あさって着けばいいかな。」"
ggml_cuda_init: found 1 CUDA devices:
Device 0: NVIDIA GeForce RTX 4060 Ti, compute capability 8.9, VMM: yes
print_info: n_layer = 36
load_tensors: offloading 36 repeating layers to GPU
load_tensors: offloading output layer to GPU
load_tensors: offloaded 37/37 layers to GPU
load_tensors: CPU_Mapped model buffer size = 630.59 MiB
load_tensors: CUDA0 model buffer size = 7669.77 MiB
.......................................................................................
llama_context: constructing llama_context
llama_context: n_seq_max = 1
llama_context: n_ctx = 4096
llama_context: n_ctx_seq = 4096
llama_context: n_batch = 2048
llama_context: n_ubatch = 512
llama_context: causal_attn = 1
llama_context: flash_attn = auto
llama_context: kv_unified = false
llama_context: freq_base = 5000000.0
llama_context: freq_scale = 1
llama_context: CUDA_Host output buffer size = 0.58 MiB
llama_kv_cache: CUDA0 KV buffer size = 576.00 MiB
llama_kv_cache: size = 576.00 MiB ( 4096 cells, 36 layers, 1/1 seqs), K (f16): 288.00 MiB, V (f16): 288.00 MiB
llama_context: Flash Attention was auto, set to enabled
llama_context: CUDA0 compute buffer size = 304.75 MiB
llama_context: CUDA_Host compute buffer size = 16.02 MiB
assistant
{
"出発時間": "202512041300",
"到着時間": "202512050000",
"出発地": "新宿",
"目的地": "神奈川"
}
GPUもちゃんと使っているし、解析もバッチリできている。
C/C++言語ライブラリ
次は、一緒にビルドされたシェアードライブラリとインクルードファイルを使って、C言語に組み込み、コードから呼んでみる。以下のようなコードを書く。
| C/C++ | llama_cpp_sample.cpp | GitHub Source |
#include "llama.h"
#include <iostream>
#include <vector>
#include <string>
int main(int argc, char **argv) {
if (argc < 3) {
std::cerr << "usage: " << argv[0] << " model.gguf \"prompt text\"\n";
return 1;
}
std::string model_path = argv[1];
std::string prompt = argv[2];
// 生成最大長
int n_predict = 512;
// **各パラメータ**
int n_ctx = 4096; // 総コンテキスト長
int n_batch = 2048; // 1回のdecodeで処理できるトークン数
int n_ubatch = 512; // 内部マイクロバッチ(VRAM節約)
int n_layer = 36; // GPUに載せる層数(-1 = すべての層)
// GPUでoffloadする層数
llama_model_params mparams = llama_model_default_params();
mparams.n_gpu_layers = n_layer;
// **モデルロード**
llama_backend_init();
ggml_backend_load_all();
llama_model *model = llama_model_load_from_file(model_path.c_str(), mparams);
if (!model) {
std::cerr << "ERROR: failed to load model\n";
return 1;
}
const llama_vocab *vocab = llama_model_get_vocab(model);
// **コンテキスト作成**
llama_context_params cparams = llama_context_default_params();
cparams.n_ctx = n_ctx;
cparams.n_batch = n_batch;
cparams.n_ubatch = n_ubatch;
llama_context *ctx = llama_init_from_model(model, cparams);
if (!ctx) {
std::cerr << "ERROR: failed to init context\n";
llama_model_free(model);
return 1;
}
// プロンプトをトークン化
int32_t tcount = llama_tokenize(vocab, prompt.c_str(), prompt.size(),
nullptr, 0, false, true);
if (tcount < 0) tcount = -tcount;
std::vector<llama_token> prompt_tokens(tcount);
llama_tokenize(vocab, prompt.c_str(), prompt.size(),
prompt_tokens.data(), prompt_tokens.size(),
false, true);
// **プロンプトを評価**
llama_batch batch = llama_batch_get_one(prompt_tokens.data(), prompt_tokens.size());
if (llama_decode(ctx, batch) != 0) {
std::cerr << "ERROR: prompt eval failed\n";
llama_free(ctx);
llama_model_free(model);
return 1;
}
std::string result;
int n_generated = 0;
while (n_generated < n_predict) {
const float *logits = llama_get_logits(ctx);
int32_t n_vocab = llama_vocab_n_tokens(vocab);
// greedy
int best = 0;
float best_log = logits[0];
for (int i = 1; i < n_vocab; ++i) {
if (logits[i] > best_log) {
best_log = logits[i];
best = i;
}
}
// EOS判定
if (llama_vocab_is_eog(vocab, best))
break;
// トークン → 文字列
char buf[256];
int32_t cc = llama_token_to_piece(vocab, best, buf, sizeof(buf), 0, true);
if (cc > 0) result.append(buf, cc);
// 次のステップ:1トークンだけ評価
batch = llama_batch_get_one(&best, 1);
if (llama_decode(ctx, batch) != 0)
break;
++n_generated;
}
// **まとめてドン!出力**
std::cout << result << std::endl;
llama_free(ctx);
llama_model_free(model);
llama_backend_free();
return 0;
}
ビルド
g++ -std=c++17 -O3 llama_cpp_sample.cpp -I llama.cpp/include -I llama.cpp/ggml/include -L llama.cpp/build/bin -lllama -ldl -pthread -lggml -lggml-base -lggml-cuda
実行
env LD_LIBRARY_PATH=llama.cpp/build/bin ./a.out Qwen3VL-8B-Instruct-Q8_0.gguf "###INPUT:以降の文章から出発時間と思われる表現と、到着時間と思われる表現を抜き出しYYYYMMDDHHMM形式で推測しJSONで出力せよ。また、出発地と思われる表現と、目的地と思われる表現を抜き出してJSONで出力せよ。JSON以外は出力しないこと。なお本日は20251203である。###INPUT:「いやー、明日午後に新宿を出て、神奈川へ向かいます。あさって着けばいいかな。」"
ggml_cuda_init: found 1 CUDA devices:
Device 0: NVIDIA GeForce RTX 4060 Ti, compute capability 8.9, VMM: yes
llama_model_load_from_file_impl: using device CUDA0 (NVIDIA GeForce RTX 4060 Ti) (0000:65:00.0) - 14550 MiB free
llama_model_loader: loaded meta data with 30 key-value pairs and 399 tensors from Qwen3VL-8B-Instruct-Q8_0.gguf (version GGUF V3 (latest))
print_info: n_layer = 36
load_tensors: offloading 36 repeating layers to GPU
load_tensors: offloaded 36/37 layers to GPU
load_tensors: CPU_Mapped model buffer size = 8300.36 MiB
load_tensors: CUDA0 model buffer size = 7039.16 MiB
.......................................................................................
llama_context: constructing llama_context
llama_context: n_seq_max = 1
llama_context: n_ctx = 4096
llama_context: n_ctx_seq = 4096
llama_context: n_batch = 2048
llama_context: n_ubatch = 512
llama_context: causal_attn = 1
llama_context: flash_attn = auto
llama_context: kv_unified = false
llama_context: freq_base = 5000000.0
llama_context: freq_scale = 1
set_abort_callback: call
llama_context: CUDA0 compute buffer size = 935.34 MiB
llama_context: CUDA_Host compute buffer size = 16.02 MiB
llama_context: graph nodes = 1267
llama_context: graph splits = 4 (with bs=512), 3 (with bs=1)
###OUTPUT:{"departure_time": "202512041300", "arrival_time": "202512050000", "departure_place": "新宿", "arrival_place": "神奈川"}
いい感じ。しっかりGPUも使っているっぽい。
システム常駐サーバー
最初にモデルをロードして初期化した後はシステムに常駐し、外部からのプロンプトを受け付け、結果をソケット経由で返すものが望ましい。llama-serverがまさにそれ。
llama.cpp/build/bin/llama-server --model Qwen3VL-8B-Instruct-Q8_0.gguf --port 8668 --host 0.0.0.0 --n-gpu-layers -1 ggml_cuda_init: found 1 CUDA devices: Device 0: NVIDIA GeForce RTX 4060 Ti, compute capability 8.9, VMM: yes init: using 19 threads for HTTP server start: binding port with default address family main: loading model srv load_model: loading model 'Qwen3VL-8B-Instruct-Q8_0.gguf' llama_model_load_from_file_impl: using device CUDA0 (NVIDIA GeForce RTX 4060 Ti) (0000:65:00.0) - 14550 MiB free llama_model_loader: loaded meta data with 30 key-value pairs and 399 tensors from Qwen3VL-8B-Instruct-Q8_0.gguf (version GGUF V3 (latest)) print_info: n_layer = 36 llama_context: n_ctx = 4096 llama_context: n_ctx_seq = 4096 llama_context: n_batch = 2048 llama_context: n_ubatch = 512 main: model loaded main: server is listening on http://0.0.0.0:8668 main: starting the main loop... srv update_slots: all slots are idle
立ち上がったらnvidia-smiすれば、GPUを占有しているのがわかるはず。テストは以下のように打つ。
curl http://localhost:8668/completion \
-H "Content-Type: application/json" \
-d '{
"prompt": "###INPUT:以降の文章から出発時間と思われる表現と、到着時間と思われる表現を抜き出しYYYYMMDDHHMM形式で推測しJSONで出力せよ。また、出発地と思われる表現と、目的地と思われる表現を抜き出してJSONで出力せよ。JSON以外は出力しないこと。なお本日は20251203である。###INPUT:「いやー、明日午後に新宿を出て、神奈川へ向かいます。あさって着けばいいかな。」",
"n_predict": 128,
"temperature": 0.2
}'
出力
{"index":0,"content":"###OUTPUT:{\"departure_time\": \"202512041300\", \"arrival_time\": \"202512050000\", \"departure_place\": \"新宿\", \"arrival_place\": \"神奈川\"}"
なかなかやるなあ。llama-cpp-pythonと違い、本家本体のllama.cppソースビルドであれば、最新のQwenモデルも問題なく使える。
Android
iPhone/iPad
Flutter
MacOS
Windows
Debian
Ubuntu
CentOS
FreeBSD
RaspberryPI
HTML/CSS
C/C++
PHP
Java
JavaScript
Node.js
Swift
Python
MatLab
Amazon/AWS
CORESERVER
Google
仮想通貨
LINE
OpenAI/ChatGPT
IBM Watson
Microsoft Azure
Xcode
VMware
MySQL
PostgreSQL
Redis
Groonga
Git/GitHub
Apache
nginx
Postfix
SendGrid
Hackintosh
Hardware
Fate/Grand Order
ウマ娘
将棋
ドラレコ
※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
※本記事内容の無断転載を禁じます。
【WEBMASTER/管理人】
自営業プログラマーです。お仕事ください!ご連絡は以下アドレスまでお願いします★
【キーワード検索】
【最近の記事】【全部の記事】
CUDA13環境下でGPU使用版のllama.cppを導入しC++ライブラリを使うCUDA13環境下でGPU使用版のllama-cpp-pythonを導入する
CUDA13環境下でGPU使用版のPyTorchを導入する
LetsEncrypt/certbotの証明書自動更新がエラーになる場合
Wav2Lipのオープンソース版を改造して外部から呼べるAPI化する
Wav2Lipのオープンソース版で静止画の口元のみを動かして喋らせる
【iOS】アプリアイコン・ロゴ画像の作成・設定方法
オープンソースリップシンクエンジンSadTalkerをAPI化してアプリから呼ぶ【2】
オープンソースリップシンクエンジンSadTalkerをAPI化してアプリから呼ぶ【1】
【Xcode】iPhone is not available because it is unpairedの対処法
【人気の記事】【全部の記事】
【Windows10】リモートデスクトップ間のコピー&ペーストができなくなった場合の対処法進研ゼミチャレンジタッチをAndroid端末化する
CUDA13環境下でGPU使用版のPyTorchを導入する
Windows11+WSL2でUbuntuを使う【2】ブリッジ接続+固定IPの設定
【Apache】サーバーに同時接続可能なクライアント数を調整する
【C/C++】小数点以下の切り捨て・切り上げ・四捨五入
Googleスプレッドシートを編集したら自動で更新日時を入れる
LinuxからWindowsの共有フォルダをマウントする
Windows11のコマンドプロンプトでテキストをコピーする
size_tとssize_tを使い分けてSegmentation Faultを予防する
【カテゴリーリンク】
Android
iPhone/iPad
Flutter
MacOS
Windows
Debian
Ubuntu
CentOS
FreeBSD
RaspberryPI
HTML/CSS
C/C++
PHP
Java
JavaScript
Node.js
Swift
Python
MatLab
Amazon/AWS
CORESERVER
Google
仮想通貨
LINE
OpenAI/ChatGPT
IBM Watson
Microsoft Azure
Xcode
VMware
MySQL
PostgreSQL
Redis
Groonga
Git/GitHub
Apache
nginx
Postfix
SendGrid
Hackintosh
Hardware
Fate/Grand Order
ウマ娘
将棋
ドラレコ