🧠

WSL×RTX3090でローカルLLMを動かす:vLLM + Qwen2.5-14B-AWQ構築記録

に公開

はじめに

最近は RTX 5090 も定価で市場に出回ってきて、だいぶ物欲を刺激されました。とはいえ、手元の RTX 3090(24GB) もまだ十分に戦えるはず。まずは 今ある戦力を使い倒す 方針で、WSL2(Ubuntu 24.04)上に vLLM + Qwen2.5‑14B‑Instruct‑AWQ を立て、OpenAI互換APIとして動かすところまでやってみた記録です。

気になったのは、CUDA 13.0 ドライバのまま vLLM を導入すると依存解決で PyTorch が自動的に CUDA 12.8 系(2.8.0+cu128)へ切り替わること。結論から言うと、この「自動ダウングレード」を受け入れても 安定稼働しました(実測は後述)。最終的には /v1/chat/completions で日本語応答まで通せています。


TL;DR

  • Windows 11 + WSL2 (Ubuntu 24.04) + RTX3090vLLM を立ち上げ、OpenAI互換API を即利用できる。
  • CUDA 13.0 ドライバのまま pip install vllm すると、依存解決で PyTorch 2.8.0 + cu128自動ダウングレードされるが、そのまま安定稼働(実測あり)。
  • Qwen2.5-14B-Instruct-AWQ/v1/chat/completions で日本語応答。curlOpenAI SDK のサンプル付き。

図で把握

💡 ポイント

  • CUDAドライバはWindows側。WSL はドライバを透過利用しつつ、ユーザー空間の CUDA ランタイムは cu128(12.8系)として落ち着く構成。
  • vLLM が OpenAI互換API を起動するため、外部アプリからそのまま叩ける

検証環境

項目 内容
ホスト Windows 11 Pro
仮想環境 WSL2 + Ubuntu 24.04 (noble)
GPU NVIDIA RTX 3090 (24GB VRAM)
ドライバ 581.29(CUDA 13.0 対応)
CUDA 13.0(Driver 由来)
Python 3.12.3
PyTorch 2.8.0 + cu128(自動ダウングレード)
vLLM 0.11.0
モデル Qwen/Qwen2.5-14B-Instruct-AWQ

まず動かす(クイックスタート)

3分でAPI応答まで。細かい背景は後半へ。

1) venv 準備

sudo apt update && sudo apt install -y python3-full python3-venv build-essential
cd /mnt/c/Users/xxxxx/work
mkdir vllm && cd vllm
python3 -m venv .venv
source .venv/bin/activate
pip install -U pip wheel

2) PyTorch(CUDA13対応版)を一旦導入

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu130

初期確認:

python - <<'PY'
import torch
print("PyTorch:", torch.__version__)
print("CUDA available:", torch.cuda.is_available())
if torch.cuda.is_available():
    print("Device:", torch.cuda.get_device_name(0))
PY
# => PyTorch: 2.9.0+cu130 / RTX3090 が見えればOK

3) vLLM を入れる(※ここで自動的に cu128 へ)

pip install vllm

⚙️ 依存解決により torch==2.8.0+cu128自動置換されます。以後は cu128 前提で進みます。

再確認(2.8.0+cu128 になっていれば想定どおり):

python - <<'PY'
import torch
print("PyTorch:", torch.__version__)
print("CUDA:", torch.version.cuda)
print("CUDA available:", torch.cuda.is_available())
if torch.cuda.is_available():
    print("Device:", torch.cuda.get_device_name(0))
PY

4) AWQ 対応

pip install autoawq

5) Hugging Face ログイン

pip install huggingface_hub
hf auth login   # 新コマンド。旧: huggingface-cli login(廃止予定)

6) モデル起動(vLLM API サーバ)

vllm serve Qwen/Qwen2.5-14B-Instruct-AWQ \
  --quantization awq \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.92 \
  --port 8000 --host 0.0.0.0

起動ログ例:

INFO ... Starting vLLM API server 0 on http://0.0.0.0:8000
Route: /v1/chat/completions
Route: /v1/models

7) 動作確認(curl)

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model":"Qwen/Qwen2.5-14B-Instruct-AWQ",
    "messages":[
      {"role":"system","content":"日本語で簡潔・正確に答えてください。"},
      {"role":"user","content":"自己紹介を一段落で。"}
    ],
    "temperature":0.3,
    "max_tokens":400
  }'

🎉 OpenAI互換API として JSON 応答が返れば成功。


背景と設計の肝

  • なぜ「CUDA13 ドライバ × cu128(12.8)ランタイム」で動くのか?
    NVIDIA ドライバは後方互換を持ち、ユーザー空間の CUDA ランタイムが 12.8 系でも、13.0 ドライバ上で正常に実行できます。vLLM は検証済みの PyTorch + CUDA 組み合わせへ依存を合わせ込み、動作安定性を優先します。

  • WSL での CUDA
    WSL 側は Windows の GPU ドライバを透過利用します。nvidia-smi は WSL 側でも確認でき、VRAM 使用量やプロセスを観測可能です。


API 呼び出しをもう一歩(ストリーミング & SDK)

Streaming(SSE)

curl -N http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model":"Qwen/Qwen2.5-14B-Instruct-AWQ",
    "messages":[{"role":"user","content":"要約してください。"}],
    "stream": true
  }'

OpenAI SDK(Python)

from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")

resp = client.chat.completions.create(
    model="Qwen/Qwen2.5-14B-Instruct-AWQ",
    messages=[
        {"role": "system", "content": "日本語で簡潔に。"},
        {"role": "user", "content": "このAPIの構成を一言で。"}
    ],
    temperature=0.3,
    max_tokens=300,
)
print(resp.choices[0].message.content)

🔒 セキュリティ--host 0.0.0.0LANへ公開します。個人環境ではFWで閉じるか、リバースプロキシ+Basic認証などで保護してください。


実測(ログからの概況)

指標
初期起動時間 約 90 秒
VRAM使用量 約 9.5 GiB
生成速度 約 4〜5 tokens/s
並列処理 約 7 リクエスト(8Kトークン換算)

ログ抜粋:

Available KV cache memory: 11.26 GiB
GPU KV cache size: 61,472 tokens
Maximum concurrency for 8,192 tokens per request: 7.50x

✅ 14B + AWQ 構成なら 3090 24GB実用レンジ
用途により --max-model-len--gpu-memory-utilizationトレードオフを調整。


トラブルと対処集(現場対応メモ)

fatal error: Python.h: No such file or directory

原因:Python 開発ヘッダ未導入
対処

sudo apt install -y python3-dev python3.12-dev build-essential zlib1g-dev libexpat1-dev
# 既存ビルドキャッシュのリセット
rm -rf ~/.cache/vllm/torch_compile_cache ~/.cache/torch/inductor ~/.cache/torch_extensions

⚠️ LoRA 読み込み失敗

ValueError: Loading lora personaA failed: No adapter found for /models/lora/personaA

原因adapter_config.json 不在(PEFT 形式でない)
回避:LoRA を使わないなら --enable-lora を外す。使うなら PEFT 形式に揃え、adapter_config.json を配置。


WSL 特有のTips

  • デフォルトで pin_memory=False になりわずかに遅くなる場合あり(体感差は小)。
  • FlashInfer 未導入時は PyTorch ネイティブへフォールバック。導入は上級者向け(ビルドや互換で詰まりがち)。
  • パスは /mnt/c/...Windowsディスク直下を使うと安定(権限・I/O 周りで無用なハマりを回避)。

まとめ(判断材料の要約)

ポイント 内容
✅ CUDA13ドライバでもOK vLLM導入で cu128 へ自動調整されるが 安定稼働
✅ OpenAI互換APIが即利用可能 /v1/chat/completions で疎通確認済み
⚙️ Pythonヘッダは必須 Inductor のビルド失敗を防止
🧩 LoRAはPEFT形式が安全 adapter_config.json を確認
🚀 RTX3090でも快適 14B + AWQ で 4〜5 tok/s 目安

付録:そのまま再現するワンライナー

sudo apt update && sudo apt install -y python3-full python3-venv build-essential
cd /mnt/c/Users/xxxxx/work && mkdir vllm && cd vllm
python3 -m venv .venv && source .venv/bin/activate
pip install -U pip wheel
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu130
pip install vllm autoawq huggingface_hub
sudo apt install -y python3-dev python3.12-dev build-essential zlib1g-dev libexpat1-dev
vllm serve Qwen/Qwen2.5-14B-Instruct-AWQ --quantization awq --max-model-len 8192 --gpu-memory-utilization 0.92 --port 8000 --host 0.0.0.0

おわりに

vLLM は ローカルGPUを即API化できる実戦的フレームワーク。
Windows + WSL2 + RTX3090 でも、CUDA13 ドライバ × cu128 ランタイムの“ねじれ”をそのまま受け入れて運用できました。

「まずは 動く」→「必要に応じて 最適化」の順で、手元の 3090 を価値ある生成系 APIへ育てていきましょう。

Discussion