モデルのロードと推論
English | 简体中文 | 日本語 | Deutsch | Русский
ruLLM は、モデルの読み込み、トークン化、キャッシュされた自己回帰生成、およびリクエストのスケジューリングを提供します。 Cargo パッケージは ruLLM です。 Rust インポート名は rullm です。
ローカルモデルの準備
モデル ファイルを 1 つのディレクトリに保存します。
| ファイル | 目的 |
|---|---|
config.json |
モデルのアーキテクチャとパラメータ |
model.safetensors |
単一ファイルの重み |
model.safetensors.index.json およびリストされたすべてのシャード |
単一のウェイト ファイルではなく、分割されたウェイト |
tokenizer.json |
テキストのトークン化とデコード |
tokenizer_config.json |
ChatML Qwen2/Qwen2.5 パイプラインに必要なテンプレート |
generation_config.json |
EOS 設定を提供するオプションの Qwen2/Qwen2.5 生成構成 |
preprocessor_config.json |
Qwen3.5 画像前処理構成、画像入力に必要 |
ローダーはローカル ディレクトリを受け入れ、モデルをダウンロードしません。アーキテクチャに応じたローダーを選択します。
| モデル/入力 | ローダー |
|---|---|
| 量子化されていないラマ テキスト | load_huggingface_llama_pipeline::<B> |
| 量子化されていない Qwen2/Qwen2.5 テキスト | load_huggingface_qwen2_pipeline::<B> |
| AWQ GEMM INT4 Qwen2/Qwen2.5 | load_huggingface_awq_qwen2_pipeline::<R> |
| 量子化されていない Qwen3.5 テキスト | load_huggingface_qwen35_text::<B> |
| Qwen3.5 ビジョン エンコーダ | load_huggingface_qwen35_vision::<B> |
| Qwen3.5 の画像とテキスト | load_huggingface_qwen35_multimodal::<B> |
B はテンソル バックエンドです。 R はデバイスのランタイムです。 Qwen3.5 テキスト ローダーは、レイヤーごとの layer_types を持つ qwen3_5_text 構成を使用し、量子化構成を拒否します。 AWQ ファイルを浮動小数点ローダーに渡さないでください。
テキスト生成サンプルの実行
環境のセットアップ 後、ソース ルートからこれらのコマンドを実行します。相対パスは 2 つのローカル モデル ディレクトリを指します。
$env:RUDA_CUDA_COMPILER = 'nvrtc'
cargo run --locked -p ruda-llm --features nvidia --example qwen2_generate -- ./models/qwen2 "Hello" 32 1
Qwen3.5 の例では、RUDA_CUDA_COMPILER が設定されていない場合、デフォルトで Ruda IR → PTX になります。実行を最適化するには、--release を使用します。サポートされていない直接 PTX 操作は、NVRTC にフォールバックするのではなく、エラーを返します。 PTX のバージョンは、ターゲット GPU およびドライバーと一致する必要があります。 PTX バックエンドリファレンス を参照してください。
Remove-Item Env:RUDA_CUDA_COMPILER -ErrorAction SilentlyContinue
$env:RUDA_PTX_VERSION = '8.0'
cargo run --release --locked -p ruda-llm --features nvidia-ptx --example qwen35_generate -- ./models/qwen35 "Hello" 8 1
CUDA C++ / NVRTC パスは、明示的に選択すると引き続き使用できます。
$env:RUDA_CUDA_COMPILER = 'nvrtc'
cargo run --release --locked -p ruda-llm --features nvidia-ptx --example qwen35_generate -- ./models/qwen35 "Hello" 8 1
引数は、モデル ディレクトリ、生のテキスト プロンプト、新しいトークンの最大数、および実行回数です。最後の 2 つのデフォルトは、Qwen2 の場合は 32 と 1、Qwen3.5 の場合は 8 と 1 です。実行カウントは正の値である必要があります。例では、ロードおよび生成のために JSON 行を出力します。生成ラインには、text、generated_token_ids、および stopped_on_eos が含まれます。
これらの例は、チャット テンプレートを追加せずに、プロンプトを直接エンコードします。会話型モデルの場合は、以下のように render_chat を使用してプロンプトを準備します。
アプリケーションでチャット応答を生成する
RUDA ソース ディレクトリと並んでアプリケーション ディレクトリの場合は、これらの依存関係を使用します。
[dependencies]
rullm = { package = "ruLLM", path = "../RUDA/ruLLM", features = ["nvidia"] }
ruda-tensor-device = { path = "../RUDA/ruda-tensor-device", default-features = false, features = ["std", "cuda"] }
ruda-driver-cuda = { path = "../RUDA/ruda-driver-cuda", default-features = false, features = ["std"] }
half = "=2.7.1"
この完全な src/main.rs は、モデル ディレクトリとユーザー メッセージをコマンドライン引数として受け入れます。後の関数の例では、B エイリアス、インポート、依存関係を再利用します。
use half::bf16;
use ruda_tensor_device::cuda::{Cuda, CudaDevice};
use rullm::{
GreedyGenerationConfig, Qwen2ChatMessage, Qwen2ChatRole,
load_huggingface_qwen2_pipeline,
};
use std::{error::Error, io};
type B = Cuda<bf16, i32>;
fn main() -> Result<(), Box<dyn Error>> {
let mut args = std::env::args().skip(1);
let directory = args.next().ok_or_else(|| io::Error::other("model directory required"))?;
let prompt = args.next().ok_or_else(|| io::Error::other("prompt required"))?;
let device = CudaDevice::default();
let pipeline = load_huggingface_qwen2_pipeline::<B>(&directory, &device)?;
let messages = [Qwen2ChatMessage::new(Qwen2ChatRole::User, prompt)];
let prompt = pipeline.render_chat(&messages, true)?;
let output = pipeline.generate_text(
&prompt,
GreedyGenerationConfig {
max_new_tokens: 32,
eos_token_ids: pipeline.loaded.default_eos_token_ids.clone(),
},
false,
true,
&device,
)?;
println!("{}", output.generated_text);
Ok(())
}
render_chat は、プレーンテキストの Qwen2/Qwen2.5 ChatML メッセージを処理します。 true を渡すと、アシスタント生成プレフィックスが追加されます。役割には、System および Assistant も含まれます。会話の順序に従ってメッセージを入力します。この API はツール呼び出しメッセージを受け入れません。
generate_text に対する 2 つのブール引数は、add_special_tokens と skip_special_tokens です。 ChatML のレンダリング後に特別なトークンを再度追加しないでください。デコードするとそれらをスキップできます。 generated_text には新しい応答のみが含まれますが、text にはプロンプトと応答の両方が含まれます。
温度、top-k、および top-p のサンプリング
レンダリングされたプロンプトを generate_text_sampled に渡します。
use rullm::{
GeneratedText, HuggingFaceLoadError, HuggingFaceQwen2Pipeline,
SamplingConfig, SamplingGenerationConfig,
};
fn sample_text(
pipeline: &HuggingFaceQwen2Pipeline<B>,
prompt: &str,
device: &CudaDevice,
) -> Result<GeneratedText, HuggingFaceLoadError> {
pipeline.generate_text_sampled(
prompt,
SamplingGenerationConfig {
max_new_tokens: 32,
eos_token_ids: pipeline.loaded.default_eos_token_ids.clone(),
sampling: SamplingConfig {
temperature: 0.8,
top_k: 40,
top_p: 0.9,
seed: Some(42),
},
},
false,
true,
device,
)
}
| パラメータ | 値と効果 |
|---|---|
temperature |
有限かつ正。 scales が最初にログオンします |
top_k |
高スコアのトークンを次に保持します。 0 はフィルタリングを無効にし、境界のタイは保持されます。 |
top_p |
最後に累積確率によってフィルタリングします。範囲 (0, 1]、1 でフィルタリングが無効になります |
seed |
ローカル サンプリング シードを要求します。 None はシステム エントロピーを使用します |
max_new_tokens |
プロンプトを除き、新しいトークンを制限します |
eos_token_ids |
リストされたトークンを生成した後に停止します |
温度をゼロに設定するのではなく、最大ロジット デコードに generate_text を使用します。固定シードは、モデルまたはバックエンド間の数値の一貫性ではなく、サンプリングのランダム シーケンスを固定します。
AWQ 重みの読み込み
AWQ ローダーは、汎用パラメーターとして Cuda<bf16, i32> ではなく CudaRuntime を受け取ります。
use ruda_driver_cuda::CudaRuntime;
use rullm::{HuggingFaceAwqQwen2Pipeline, load_huggingface_awq_qwen2_pipeline};
fn load_awq(
directory: &str,
device: &CudaDevice,
) -> Result<HuggingFaceAwqQwen2Pipeline<CudaRuntime>, HuggingFaceLoadError> {
load_huggingface_awq_qwen2_pipeline::<CudaRuntime>(directory, device)
}
返されたパイプラインは、render_chat、encode、decode、generate_text、および generate_text_sampled も提供します。 AWQ 構成には、quant_method = "awq"、bits = 4、version = "gemm"、および zero_point = true が必要です。 group_size は正または -1 でなければなりません。線形投影では、F16 アクティベーションを使用します。梱包重量レイアウトについては、ruBLAS INT4 を参照してください。
Qwen3.5画像入力
generate_image_files_greedy は、1 つのプロンプトのトークン ID、プロンプト順の JPEG/PNG パス、画像プロセッサー、および生成オプションを受け取ります。
use rullm::{
Qwen35ImageProcessor, TokenGenerationOutput,
load_huggingface_qwen35_multimodal,
};
fn generate_from_images(
directory: &str,
prompt_ids: &[i32],
paths: &[&str],
device: &CudaDevice,
) -> Result<TokenGenerationOutput, Box<dyn Error>> {
let model = load_huggingface_qwen35_multimodal::<B>(directory, device)?;
let processor = Qwen35ImageProcessor::from_huggingface(directory)?;
let output = model.generate_image_files_greedy(
prompt_ids,
paths,
&processor,
&GreedyGenerationConfig {
max_new_tokens: 32,
eos_token_ids: vec![model.text.config.eos_token_id],
},
)?;
Ok(output)
}
prompt_ids をモデルの tokenizer.json でエンコードします。モデルのプロンプト テンプレートに従い、config.json から image_token_id を使用して画像ごとに 1 つのプレースホルダー トークンを保持します。画像パスはプレースホルダーの数と順序と一致する必要があります。このエントリ ポイントは、プレースホルダーを内部で展開します。事前に展開しないでください。静止画像を処理し、ビデオ トークンを拒否します。
既存の RGB8 データの場合は、Qwen35RgbImage { pixels, height, width } を generate_rgb_greedy とともに使用します。ピクセルは行パディングなしでインターリーブされた RGB バイトです。個別の前処理の場合、preprocess_files および preprocess_rgb は、FP32 patches、2 次元の shape、およびイメージごとの grids を返します。
複数のリクエストを処理する場合は、リクエスト ループの外側でモデルとプロセッサをロードします。返された generated_token_ids を同じトークナイザーでデコードします。
キャッシュと連続バッチ処理
単一リクエスト生成関数は、その世代のキャッシュを作成および維持します。 Qwen3.5 を手動で駆動するには、model.new_cache() を呼び出し、プロンプト テンソルを forward_cached_last(tokens, &mut cache) に渡し、その後、新しいトークンのみを渡します。キャッシュされたプレフィックス全体を再送信しないでください。
独自のバッチ エグゼキューターを統合するには、ContinuousBatchScheduler を使用します。
ContinuousBatchScheduler::new(config, kv_config)で作成します。ContinuousBatchConfigはmax_active_sequencesとmax_batch_tokensを設定します。PagedKvCacheConfigは、block_size、num_pages、およびmax_sequence_lengthを設定します。すべてがポジティブでなければなりません。submit(prompt_token_ids, generation)を使用してリクエストを送信し、返されたそれぞれのRequestIdを保持します。ScheduledBatchを取得するには、schedule()を呼び出します。kindはプレフィル/デコードを区別します。sequencesは、各行のトークン、開始位置、コンテキストの長さ、およびブロック テーブルを提供します。- モデルを行順に実行し、対応する KV ページを書き込み、各行の次のトークンを選択します。成功したら、行ごとに 1 つの結果トークンを指定して
complete_batch(batch.id, &generated_token_ids)を呼び出します。失敗した場合は、fail_batch(batch.id)を呼び出して、そのバッチのページ予約をキャンセルします。 pop_finished()を使用して、完了したリクエストと生成されたトークンを取得し、スケジューリングを続行します。
スケジューラはリクエストとページ割り当てメタデータを管理します。呼び出し元のエグゼキュータは、デバイス KV ストレージとモデルの実行を所有しています。 token_matrix()、context_lengths()、および flattened_block_table() を使用してバッチ入力を構築します。 schedule() を再度呼び出す前に、未処理のバッチを完了するかキャンセルしてください。
API 参照: ruLLM エクスポート、生成オプション、スケジューラー。
Qwen3.5 の融合ページ化アテンション
Qwen35BatchCache は new_batch_cache による作成時にアテンション経路を選択します。キャッシュ作成前に RUDA_PAGED_ATTENTION=fused を設定すると、Qwen3.5 の連続バッチ処理で ruDNN の融合ページ化アテンションを使用します。未設定または legacy は既存の経路を維持し、それ以外の値は拒否されます。変数の変更で既存のキャッシュは切り替わりません。また、すべての生成エントリポイントに対するグローバルな切り替えではありません。
融合経路は各フルアテンション層に物理 KV arena を保持し、スケジューラーのページテーブルを使ってプリフィルとデコードを行います。履歴 KV をパディング付きテンソルに集約しません。arena の次元は num_pages、block_size、KV ヘッド数、ヘッド次元に従うため、その容量の GPU メモリを確保してください。入力は ruDNN の連続 F32/F16/BF16 契約に従います。共有プレフィックスへの書き込みにはスケジューラー側のコピーオンライトが必要です。デバイスへの追加が失敗した後は、以前の位置から続行せず、キャッシュを再構築してください。
再利用可能なアテンションと MoE コンポーネント
rullm::gpu_inference は TensorOps、gqa_scores、gqa_value_product、mla_absorb_query、mla_scores、mla_value_product を提供します。呼び出し側のデバイステンソル演算を組み合わせ、キャッシュされた GQA ヘッドの複製や履歴 MLA 潜在値の展開を避けます。マスク、softmax、位置エンコーディング、モデル固有のスケーリングは呼び出し側が提供します。
rullm::device_inference は ruDNN の HostPlan、DevicePlan、PagedAttentionError、SwiGluExperts、RoutingOptions、GroupRoutingOptions、route_sigmoid_grouped、GroupedStrategy を再エクスポートします。これらは計算部品であり、完全な MLA/MoE モデルローダーではありません。アダプターは射影、ルーティング設定、キャッシュ所有権を提供する必要があります。