บทความทั้งหมด

ลองเล่น vLLM บน ASUS Pro ET900N G3 (NVIDIA® GB300 Grace Blackwell)

DGX Station™ เป็นเครื่องที่ใช้ NVIDIA® GB300 Grace Blackwell Superchip (20 PFLOPS) โดยมี Coherent Memory ถึง 748 GB, CPU 72 Cores, DRAM และ วันนี้ผมจะมาลองเล่น vLLM บนเจ้าเครื่องตัวนี้กันเพื่อทดสอบประสิทธิภาพของ AI Inference

มี Video
-
ขนาดตัวอักษร
ลองเล่น vLLM บน ASUS Pro ET900N G3 (NVIDIA® GB300 Grace Blackwell)
สารบัญ

สวัสดีครับเหล่าสาวกชานม

ก่อนอื่นเลยผมจบ AI Engineer ก็จริงแต่ผมยังเป็นมือใหม่ของ LLM Inference มากๆ โพสต์นี้ผมจะไม่ลงลึกใด ๆ ทั้งสิ้นเพราะผมเองก็มือใหม่ (ไม่ต้องพูดถึง LLM Gateway หรือ LM Cache เลย) ฮา! ส่วนที่มาของโพสต์ผมแค่ตื่นเต้นที่ได้ลองแงะเล่นเจ้านี้เฉย ๆ 😅

ด้วยโอกาสอันดีนี้จึงมีโอกาสได้ลองเจ้า ASUS Pro ET900N G3 (NVIDIA® GB300 Grace Blackwell) แน่นอนว่ามันค่อนข้าง Crazy! เลยหล่ะครับกับ Specs ที่ได้มา


รายละเอียด

  • GPU: NVIDIA® GB300 Grace Blackwell 20 PFLOPS
  • VRAM: ~ 252 GB
  • CPU: ARM Neoverse-V2 72 Cores 1 Thread per Core up to 3.366 GHz
  • System RAM: ~ 496 GB
  • Coherent Pool: ~ 748 GB of Coherent Memory
  • Storage: M.2 2280 NVMe PCIe 5.0 SSD, total 8TB
image

ที่เห็นใช้ไป ~220 GB นั้นคือการ Run Container ของ Qwen3.8-Flash-Next-NVFP4, TyphoonOCR, BGE-M3 ที่พยายามใช้ VRAM เพื่อจองพื้นที่สำหรับ Weight Model และ KV-Cache (รวมถึง MIG)


ลงมือทำกัน

โดยในส่วนนี้จำเป็นต้องเตรียมของไม่กี่อย่าง เพื่อที่เราจำเริ่มต้นทดสอบ Run Dock Container โดยทำการโหลด Docker Image ที่เป็น Weight Model ของ QWEN มาจาก Hugging Face ที่สำคัญมันเป็น Model Open Source ครับ หมายความว่ามันฟรี !!

สิ่งที่ต้องมีก็คือ

  • ASUS Expert Center Pro ET900N G3
  • Docker
  • Hugging Face Account (HF_KEY ยืนยันตัวตนเพื่อให้โหลดไวขึ้น)

วิธีดำเนินการ

  1. ตรวจสอบ Docker
    ตรวจสอบว่าในเครื่อง Host หรือ ASUS Expert Center Pro ET900N G3 ได้ลง Docker ไว้ในเครื่องรึยัง
$ docker --version 
# ควรจะได้ผลลัพธ์หน้าตาประมาณนี้ Docker version 29.1.3, build 29.1.3-0ubuntu3~24.04.1
  1. เลือก Model และตั้งค่าเบื้องต้น
    เข้าไปยังเว็บ https://recipes.vllm.ai/Qwen/Qwen3.8-Flash-Next แล้วเลือการตั้งค่าที่เหมาะสมกับเครื่องเราให้ได้มากที่สุด โดยเบื้องต้นผมจะกำหนดดังนี้ครับ
image
# 2.1 ขั้นตอนนี้เป็นการ Run Docker Container ที่ทำการโหลด Weight Model มาจาก Hungging Face ซึ่งใช้เวลานานพอสมควร

$ docker run -d --name vllm-qwen-flash-nvfp4 \
  --gpus all \
  --privileged --ipc=host -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  vllm/vllm-openai:nightly Inferact/Qwen3.8-Flash-Next-NVFP4 \
  --no-enable-flashinfer-autotune \
  --max-num-seqs 32 \
  --gpu-memory-utilization 0.95 \
  --max-num-batched-tokens 8192 \
  --enable-prefix-caching \
  --distributed-executor-backend mp \
  -cc.mode none \
  -cc.cudagraph_mode full_decode_only \
  --tensor-parallel-size 1 \
  --enable-auto-tool-choice \
  --tool-call-parser qwen3_coder \
  --reasoning-parser qwen3
# 2.2 ดู Logs 30 บรรทัดล่าสุด

$ docker logs -f --tail 30 vllm-qwen-nvfp4
image
  1. ตรวจสอบว่าตอนนี้ vLLM ที่รัน QWEN ทำงานรึยัง
    สามารถดูได้จาก Log ดังรูปว่าตอนนี้เซิฟเวอร์ทำงานที่ http://0.0.0.0:8000 แล้วแสดงว่าเซิฟเวอร์ vLLM ของเราพร้อมให้ชำแหละแล้วนั้นเอง หรือทำการทดลองยิงด้วย CURL เข้าไปได้ (บนเครื่อง Host)
image
# 3.1 CURL สำหรับทดสอบ

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Inferact/Qwen3.8-Flash-Next-NVFP4",
    "messages": [{"role": "user", "content": "Hello"}],
    "max_tokens": 32
  }'
image

ได้ผลลัพธ์กลับมาว่า "Hello! How can I help you today?" และ LLM ตอบกลับมาได้ตามความคาดหวังก็ใจฟูละครับ

  1. ทดสอบ Bench Load Balance (ตัวอย่าง)
    ในเมื่อเราสามารถ Host LLM ได้แล้วสิ่งที่เราต้องดูก็คือ มันสามารถนำไปใช้งานได้จริงใช้ไหมกับ Work-Load ที่จะเจอในสถานการณ์จริง เพราะคงเกิดคำถามกับผู้ใช้งานว่า มันตอบดีไหม ตอบได้เร็วไหม และสามารถใช้งานได้พร้อมกันกี่ Requests แน่นอนว่า vLLM เขาคิดเรื่องนี้มาให้แล้วแต่เราก็ได้แค่ดูคร่าว ๆ นะครับ
    • Generate Token/Sec
    • Generate Token/Req
    • KV Cache Usage (ยังไม่พูดถึงในโพสต์นี้นะครับ) (^^) ปาดเหงื่อ ~
# ทดสอบ Inference โดยใช้ข้อมูลสุ่ม โดยกำหนดให้ Input/Output ไม่เกิน Context Window ที่กำหนดไว้ซึ่งกำหนดไว้ 20 งานให้ยิงทดสอบทีละงาน (ชุดตัวแปรนี้เหมาะสำหรับตรวจสอบว่าต่อ 1 คนใช้งานได้ดีแค่ไหน)

$ docker exec -it vllm-qwen-nvfp4 vllm bench serve \
  --model Inferact/Qwen3.8-Flash-Next-NVFP4 \
  --host 127.0.0.1 \
  --port 8000 \
  --dataset-name random \
  --random-input-len 1024 \
  --random-output-len 512 \
  --num-prompts 20 \
  --max-concurrency 1

ผลลัพธ์จากการ Benchmark แบบเล็ก ๆ

Screenshot from 2026 09 26 13 24 35
============ Serving Benchmark Result ============
Successful requests:                     20        
Failed requests:                         0         
Maximum request concurrency:             1         
Benchmark duration (s):                  56.94     
Total input tokens:                      20480     
Total generated tokens:                  10240     
Request throughput (req/s):              0.35      
Output token throughput (tok/s):         179.85    
Peak output token throughput (tok/s):    190.00    
Peak concurrent requests:                2.00      
Total token throughput (tok/s):          539.54    
---------------Time to First Token----------------
Mean TTFT (ms):                          146.74    
Median TTFT (ms):                        146.85    
P99 TTFT (ms):                           154.53    
-----Time per Output Token (excl. 1st token)------
Mean TPOT (ms):                          5.28      
Median TPOT (ms):                        5.28      
P99 TPOT (ms):                           5.30      
---------------Inter-token Latency----------------
Mean ITL (ms):                           5.28      
Median ITL (ms):                         5.28      
P99 ITL (ms):                            5.36      
==================================================

สิ่งนี้บอกอะไรเราบ้าง แบบคร่าว ๆ

  • ความเร็วของ OUTPUT ของระบบอยู่ที่ ~179.85 tokens/s
  • เวลาในการ PREFILL 1 TOKEN (เวลารอตั้งแต่ส่ง Request จนตัวอักษรแรกปรากฏ) อยู่ที่ 146.74 ms
  • การพิมพ์สม่ำเสมอ ไม่มีกระตุก (P99 ITL 5.28 ms): ค่าความล่าช้าระหว่างคำ เช่น " Hello! -> How -> can " ถ้าผมเข้าใจไม่ผิดนะ

ทดสอบการใช้งานบน DESKTOP APP

image
AI DESKTOP APP

คำศัพท์ที่ควรรู้จาก Command

ตาราง: ตัวแปรที่ใช้รัน vLLM

ตัวแปรชื่อภาษาไทยประเภทข้อมูลความหมาย
-dรันเบื้องหลังFlagสั่งให้ Container ทำงานแบบ Background ไม่ล็อกหน้าจอ Terminal
--nameชื่อคอนเทนเนอร์Stringกำหนดชื่ออ้างอิงให้ Container (vllm-qwen-nvfp4)
--gpusจัดสรรการ์ดจอStringอนุญาตให้ Container เข้าถึงการ์ดจอทั้งหมดในเครื่อง
--privilegedสิทธิ์ระดับสูงFlagให้สิทธิ์เข้าถึงฮาร์ดแวร์โดยตรงเพื่อความเสถียรของไดรเวอร์
--ipc=hostแชร์หน่วยความจำ IPCStringแชร์ Inter-Process Communication กับโฮสต์ ป้องกันแรมแชร์เต็ม
-pแมปพอร์ตStringเปิดพอร์ต 8000 จาก Container ออกสู่เครื่องหลักเพื่อยิง API
-e VLLM_USE_V1=0ปิดเอนจิน V1Environmentบังคับถอยไปใช้ vLLM V0 ที่เสถียรกว่า ป้องกัน Error โมเดลใหม่
-vเมานต์โฟลเดอร์Stringเชื่อมโฟลเดอร์เก็บโมเดล เพื่อไม่ต้องดาวน์โหลดน้ำหนักใหม่ซ้ำ
vllm/vllm-openai:...อิมเมจ DockerImage tagระบุ Docker Image ของ vLLM ที่จะนำมาใช้งาน
Inferact/Qwen...ชื่อโมเดลModel IDกำหนดโฟลเดอร์หรือ Hugging Face ID ของโมเดลที่จะโหลด
--tensor-parallel-sizeขนานโมเดลข้ามการ์ดIntegerจำนวนการ์ดจอที่จะแบ่งชิ้นส่วนโมเดลไปรัน (1 ใบ = 1)
--gpu-memory-utilizationสัดส่วนจอง VRAMFloatจอง VRAM ล่วงหน้า 85% สำหรับ Model Weight และ KV Cache
--max-num-seqsจำนวนคำขอพร้อมกันสูงสุดIntegerจำกัดการประมวลผลคำขอพร้อมกันสูงสุดใน 1 Batch ไว้ที่ 64 คิว
--enforce-eagerบังคับโหมดรันตรงFlagสั่งรันคำนวณทีละคำสั่ง ปิด CUDA Graph เลี่ยงการแครชบนชิปใหม่
--no-enable-flashinfer-autotuneปิดจูนเคอร์เนลอัตโนมัติFlagข้ามขั้นตอนวัดความเร็ว FlashInfer ตอนบูต ช่วยให้เซิร์ฟเวอร์เปิดเร็ว
--enable-auto-tool-choiceเปิดเลือกระบบ Function CallFlagอนุญาตให้โมเดลตัดสินใจเรียกใช้ Tool/Function ให้อัตโนมัติ
--tool-call-parserตัวแปลงคำสั่ง ToolStringกำหนด Parser เฉพาะทางสำหรับจัดฟอร์แมต Tool Call ของ Qwen

ตาราง: ตัวแปรที่ใช้ทดสอบ vLLM

ตัวแปรชื่อภาษาไทยประเภทข้อมูลความหมาย
exec -itเข้าไปรันในคอนเทนเนอร์Flagสั่งให้คำสั่งทำงานภายใน Container ที่กำลังรันอยู่แบบโต้ตอบ
vllm bench serveคำสั่งเริ่มเบนช์มาร์กSubcommandเรียกโมดูลยิงทดสอบโหลด HTTP API ของ vLLM
--modelชื่อโมเดลที่ทดสอบStringระบุชื่อโมเดลใน Payload ให้ตรงกับตัวที่เซิร์ฟเวอร์เปิดรันไว้
--hostไอพีเซิร์ฟเวอร์Stringกำหนดปลายทางที่จะยิงคำขอทดสอบไป (127.0.0.1)
--portพอร์ตเซิร์ฟเวอร์Integerกำหนดพอร์ตเป้าหมายที่เซิร์ฟเวอร์เปิดให้บริการ (8000)
--dataset-nameรูปแบบชุดข้อมูลStringใช้โหมดสุ่มสร้างข้อความขึ้นมาเอง (random) ไม่โหลดไฟล์จริง
--random-input-lenความยาวข้อความขาเข้าIntegerกำหนดขนาด Prompt ทดสอบที่ 1,024 โทเค็นต่อคำขอ
--random-output-lenความยาวข้อความขาออกIntegerบังคับให้โมเดลตอบกลับขนาดยาว 512 โทเค็นต่อคำขอ
--num-promptsจำนวนคำขอรวมทั้งหมดIntegerส่งคำขอไปทดสอบจนครบตามจำนวน 20 ครั้งแล้วตัดผลสรุป
--max-concurrencyจำนวนคำขอพร้อมกันIntegerกำหนดให้ยิงทีละ 1 คำขอพร้อมกัน (วัด Single-stream Latency)

แหล่งอ้างอิง