15 คะแนน โดย GN⁺ 2026-02-23 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เป็น เอนจิน inference สำหรับ LLM ที่พัฒนาด้วย C++/CUDA ซึ่งทำให้สามารถรัน โมเดล Llama 70B บน RTX 3090 (VRAM 24GB) ได้ผ่านการสตรีมหน่วยความจำ GPU และ direct I/O จาก NVMe
  • ใช้ โครงสร้างแคชแบบปรับตัว 3 ชั้น เพื่อแบ่งการใช้งานระหว่าง VRAM, RAM แบบ pinned และ NVMe/mmap โดยอัตโนมัติ และทำความเร็วได้ สูงสุด 83 เท่าเมื่อเทียบกับ mmap
  • แบ็กเอนด์ gpu-nvme-direct ส่งข้อมูลจาก NVMe ไปยัง GPU โดยตรงแบบข้าม CPU ทั้งหมด เพื่อใช้แบนด์วิดท์ PCIe ได้อย่างเต็มที่
  • ฟีเจอร์ Layer skip และ self-speculative decoding ช่วยลดการคำนวณที่ไม่จำเป็นและเพิ่มความเร็วการประมวลผลโดยไม่สูญเสียคุณภาพ
  • ช่วยให้สามารถรันโมเดลขนาดใหญ่มากได้อย่างมีประสิทธิภาพบนฮาร์ดแวร์สำหรับผู้บริโภค และชี้ให้เห็นถึงความเป็นไปได้ในการ ขยายการเข้าถึง inference ของ LLM ประสิทธิภาพสูง

ภาพรวมของ NTransformer

  • เป็น เอนจิน inference LLM แบบ C++/CUDA ประสิทธิภาพสูง ที่รัน โมเดล Llama 70B บน RTX 3090 (VRAM 24GB)
    • สตรีมเลเยอร์ของโมเดลผ่านหน่วยความจำ GPU และสามารถเลือกใช้ direct I/O จาก NVMe เพื่อข้าม CPU ทั้งหมดได้
  • ไม่มี dependency ภายนอกนอกเหนือจาก CUDA Toolkit, ไม่ต้องใช้ PyTorch หรือ cuBLAS
  • รองรับ ฟอร์แมตโมเดล GGUF และใช้รูปแบบ quantization ได้ทั้ง Q4_0, Q8_0, Q4_K_M, Q5_K, Q6_K, F16, F32

ประสิทธิภาพและโครงสร้างแคช

  • แคชแบบปรับตัว 3 ชั้น (3-Tier Adaptive Caching)
    • เลเยอร์ที่อยู่ใน VRAM (0 I/O)
    • RAM แบบ pinned (สำหรับส่ง H2D เท่านั้น)
    • fallback ไปยัง NVMe/mmap
  • บนระบบ RTX 3090 + RAM 48GB ทำความเร็วได้ สูงกว่า mmap 83 เท่า
  • แบนด์วิดท์ PCIe Gen3 x8 (ประมาณ 6.5 GB/s) เป็นคอขวดหลัก
  • quantization แบบ Q4_K_M สามารถบรรจุเลเยอร์ใน VRAM ได้มากกว่าอีก 10 เลเยอร์ (36 เทียบกับ 26) จึงลดปริมาณการส่งข้อมูลลง
  • Layer skip (อิงจาก cosine similarity) สามารถข้าม 20 เลเยอร์จากทั้งหมด 80 เลเยอร์ โดยสูญเสียคุณภาพน้อยมาก

ความสามารถหลัก

  • การสตรีมแบบ SLEP: ซ้อนการอ่านจาก NVMe, PCIe DMA และการประมวลผลบน GPU ด้วย double buffering
  • แบ็กเอนด์ gpu-nvme-direct: อ่านข้อมูลจาก NVMe เข้าสู่หน่วยความจำแบบ pinned ที่ GPU เข้าถึงได้โดยตรง
  • Self-speculative decoding: ใช้เลเยอร์ที่อยู่ใน VRAM เป็น draft model โดยไม่ต้องมีโมเดลเพิ่มเติม
  • การเลือกเส้นทางข้อมูลอัตโนมัติ: VRAM resident > pinned RAM H2D > mmap pinned > CPU memcpy
  • รองรับสถาปัตยกรรม Llama: รวมถึง RoPE, GQA, SwiGLU, RMSNorm และ KV cache

ความต้องการของระบบ

  • Linux (Ubuntu, kernel 6.17+), CUDA Toolkit 13.1, gcc/g++ 14, CMake 3.24+
  • GPU ที่มี Compute Capability 8.0+ (ทดสอบบน RTX 3090)
  • หากใช้ direct I/O จาก NVMe ต้องมี NVMe SSD บนสล็อต PCIe แยกต่างหาก และต้องใช้ไลบรารี gpu-nvme-direct

การสตรีมตรงจาก NVMe

  • หากโมเดลมีขนาดใหญ่เกิน VRAM จะใช้ เส้นทางตรง NVMe → GPU โดยตัด CPU ออกทั้งหมด
    • การไหลของข้อมูล: NVMe SSD → DMA → หน่วยความจำ staging แบบ pinned → PCIe H2D → บัฟเฟอร์ GPU → การคำนวณ
  • bind NVMe เข้ากับ VFIO เพื่อให้เข้าถึงได้โดยตรงจาก user space
  • แต่ละเลเยอร์ (ประมาณ 670MB สำหรับ 70B Q6_K) ถูกอ่านด้วยคำสั่ง NVMe 670 คำสั่งภายในเวลาราว 202ms
  • การอ่าน NVMe, H2D DMA และการคำนวณบน GPU ถูกประมวลผลแบบขนานใน pipeline แบบ double buffer

การตั้งค่าระบบและคำเตือนด้านความเสี่ยง

  • สคริปต์ตั้งค่าอัตโนมัติ (setup_system.sh) จะคอนฟิก GRUB, NVIDIA DKMS, CUDA headers, VFIO, การ bind NVMe ตามลำดับ
  • มีงานความเสี่ยงสูงรวมถึง การปิด IOMMU, การแพตช์ kernel module, การ bind NVMe เข้ากับ VFIO
  • หากตั้งค่าผิดอาจทำให้ บูตไม่ขึ้น, ข้อมูลใน NVMe สูญหาย, ระบบไม่เสถียร
  • ห้ามใช้ boot drive โดยเด็ดขาด, ต้องมีอุปกรณ์ NVMe แยกต่างหากสำหรับงานนี้
  • มีสคริปต์สำหรับสำรองและกู้คืนการเปลี่ยนแปลงทั้งหมด

สถาปัตยกรรมและโครงสร้างโค้ด

  • องค์ประกอบหลักในไดเรกทอรี src/
    • core/: เทนเซอร์, การจัดสรรหน่วยความจำ, การจัดการอุปกรณ์ GPU
    • cuda/: เคอร์เนล GEMV, RMSNorm, RoPE, SwiGLU, softmax
    • memory/: เอนจินสตรีมมิง SLEP ที่ทำงานบน NVMe และ mmap
    • model/: องค์ประกอบ Transformer, ตัวโหลด GGUF, attention, FFN, normalization
    • inference/: tokenizer, sampler, engine
  • scripts/: รวมสคริปต์ตั้งค่าระบบ, การ bind NVMe และสคริปต์กู้คืน

โรดแมปการพัฒนา

  • ระยะที่ 1: Llama 8B Q8_0, เคอร์เนล CUDA แบบคัสตอม, 48.9 tok/s (เสร็จสิ้น)
  • ระยะที่ 2: การสตรีมแบบ SLEP, รัน 70B บน GPU เดี่ยว, เร็วขึ้น 33 เท่า (เสร็จสิ้น)
  • ระยะที่ 3: รองรับ Q4_K_M/Q5_K, Layer skip, self-speculative decoding, F16 KV cache (เสร็จสิ้น)
  • ระยะที่ 4: แบ็กเอนด์ NVMe Direct, การอ่าน NVMe ที่ขับเคลื่อนโดย GPU 3.35 GB/s (เสร็จสิ้น)
  • ระยะที่ 5: ปรับแต่ง inference และเปิดเผย C API สาธารณะ (ตามแผน)

ไลเซนส์

  • ใช้ไลเซนส์ BSD-2-Clause

1 ความคิดเห็น

 
GN⁺ 2026-02-23
ความคิดเห็นบน Hacker News
  • คิดว่าวิธี ส่งข้อมูลจาก NVMe ไปยัง GPU โดยตรง โดยข้าม CPU นั้นฉลาดมาก
    เวลารันโมเดลขนาดใหญ่บนเครื่องโลคัล คอขวดมักจะเป็นลำดับชั้นหน่วยความจำเสมอ แต่นี่เหมือนกับการใช้ NVMe เป็น VRAM แบบขยายผ่าน DMA โดยตรง
    อยากรู้เหมือนกันว่าถ้าเทียบกับแนวทาง unified memory ของ Apple M series จะเป็นอย่างไร M4 Max สามารถโหลดโมเดล 70B เข้าเมโมรีได้ทั้งหมด แต่ throughput ต่ำกว่า 3090
    ถ้ามีเบนช์มาร์กที่เทียบประสิทธิภาพแบบเนทีฟของ 3090 ที่ใช้แนวทาง NVMe กับ M4 Max โดยอิง batch inference ก็น่าจะน่าสนใจมาก

    • ฉันมี M3 อยู่ เลยว่าจะลองทดสอบบน Metal ดู
  • ถ้าใช้ GPUdirect ก็สามารถทำ DMA transfer ไปยังอุปกรณ์สตอเรจได้โดยตรง
    เลยลองคิดดูว่าถ้า m.2 storage เป็น DRAM จริง ๆ จะเป็นอย่างไร ตอนที่ spill โมเดลจาก GPU จริง ๆ แล้วไม่ต้องการ persistence ดังนั้นอาจเก็บ system RAM ไว้ให้ CPU ใช้ได้

    • ถ้าใช้ RAM disk น่าจะดีกว่ามาก เสียดายที่ Intel Optane ไม่ได้กลายเป็นมาตรฐาน เทคโนโลยีนี้เหมาะกับ workflow แบบนี้มาก
    • ฉันก็คิดเหมือนกัน ก่อนหน้านี้เคยพูดที่ Dask Summit เกี่ยวกับ dask-cudf โดยเร่งการวิเคราะห์ล็อกด้วยโครงสร้าง parallel SSD array → GPUDirect Storage → PCIe → A100 GPU ตอนนี้คิดว่าคงน่าสนใจถ้านำโครงสร้างแบบนี้ไปใช้กับ LLM หรือโมเดล MoE
    • ที่จริงแล้ว m.2 storage ที่อิง DRAM มีอยู่แล้วในรูปแบบ CXL (Compute Express Link) แต่ปัญหาคือ RAM แพงเกินไป เลยใช้แบนด์วิดท์ 31GB/s ต่อคอนเน็กเตอร์ NVMe ได้ยาก
  • ความเร็ว 0.2 โทเคนต่อวินาทีนั้นช้าเกินไปสำหรับแชต แต่พอสำหรับ งานแบบแบตช์/อะซิงก์
    ฉันรัน pipeline สร้างคอนเทนต์อัตโนมัติที่มีการเรียก LLM หลายตัวพร้อมกัน โดยคอขวดคือการสร้างภาพอยู่แล้ว ดังนั้นทั้งงานก็ใช้เวลาราว 20 นาทีอยู่ดี
    ถ้ารันโมเดล 70B แบบโลคัลได้ ก็จะช่วยประหยัดค่า API token ได้มาก จึงเป็นการ ลดต้นทุน อย่างมีนัยสำคัญ

    • ถ้ามองเรื่องต้นทุน มันไม่ได้คุ้มขนาดนั้น ที่ 0.5 tok/s จะได้ 3600 โทเคนต่อชั่วโมง ในขณะที่ระบบ 3090 กินไฟ 200~300W ถ้าใช้ OpenRouter กับ llama 3.1 สำหรับจำนวนโทเคนเท่ากัน ยังถูกกว่าค่าไฟมาก ถึงอย่างนั้นก็ยังมีความหมายในแง่ การทำ inference แบบรักษาความเป็นส่วนตัว
    • ต้องคิด ค่าไฟ ตอนรัน 3090 ที่ 350W ต่อเนื่องเป็นเวลานานด้วย
  • 0.2 tok/s ถือว่าโอเคสำหรับการทดลอง แต่ไม่พอสำหรับการใช้งานแบบ interactive
    ในกรณีส่วนใหญ่ โมเดล 8B หรือ 13B ที่ quantize มาดีแล้วจะให้ สมดุลระหว่าง latency กับคุณภาพ ได้ดีกว่า

    • ฉันแค่อยากลองทดสอบความเป็นไปได้ เมื่อก่อนเคยทำได้ 3000 โทเคนต่อวินาทีบน PS2 ด้วย transformer แบบคลาสสิก เพราะใช้ สถาปัตยกรรมที่ส่งคำสั่งจากหน่วยความจำไปยัง GPU โดยตรง พีซีทั่วไปต้องผ่าน CPU เลยช้ากว่า ส่วน GPU ระดับโปรแก้ปัญหานี้ได้ แต่แพงเกินไป
    • ถึงอย่างนั้น ในบางสถานการณ์ คุณภาพของโมเดลขนาดใหญ่ ก็สำคัญกว่า
    • รันแบบ CPU+GPU ด้วยกันจะเร็วกว่า ฉันได้ประมาณ 1.5 tok/s บนชุด 7950X+3090
    • ฉันเพิ่งเข้าใจหลังจากดูตารางประสิทธิภาพว่ารายการด้านบนเป็นโมเดล 8B 5 วินาทีต่อโทเคนมันช้าเกินไป บนระบบ 5950X+128GB RAM ของฉัน ถ้าใช้ CPU กับ GPU 3060 ร่วมกันน่าจะยังเร็วกว่า และก็ไม่ค่อยเชื่อคำกล่าวที่ว่า 2 วินาทีต่อโทเคนบน 3090 เป็นขีดจำกัดด้านการคำนวณ
  • เป็นการทดลองที่น่าสนใจมาก ฉันเองก็น่าจะลองอะไรแบบนี้ก่อน
    อยากรู้ตัวเลข throughput จริงเมื่อเทียบกับแบนด์วิดท์เชิงทฤษฎีของ PCIe อยากรู้ว่ามันติดที่ latency หรือแบนด์วิดท์กันแน่

    • ในทางปฏิบัติมันเป็น คอขวดด้านแบนด์วิดท์ เมนบอร์ด B450 ของฉันรองรับแค่ PCIe3 x8 เลยจำกัด GPU ถ้าอัปเกรดเป็น X570 ความเร็วน่าจะเพิ่มได้ 2~3 เท่า
  • เป็นการแฮ็กที่เจ๋ง แต่ 0.5 tok/s สำหรับโมเดล 70B ก็ยังช้าเมื่อเทียบกับการที่การ์ดใบเดียวกันรันโมเดล 7B ได้ 30+ tok/s
    ตามงานวิจัยของ NVIDIA โมเดลต่ำกว่า 10B ก็จัดการงานเอเจนต์ได้ 40~70% แล้ว และช่องว่างด้านคุณภาพก็กำลังลดลงอย่างรวดเร็ว

  • ด้านนี้ยังน่าทดลองต่ออีกมาก
    ในระยะยาว สิ่งสำคัญน่าจะเป็นการทำ optimization ของโมเดล หรือก็คือ การค้นหาส่วนของโมเดลที่ตัดทิ้งได้โดยไม่กระทบประสิทธิภาพ เพราะท้ายที่สุดโมเดลก็เป็นโครงสร้างแบบ lossy compression อย่างหนึ่ง แนวทางนี้ยังช่วยเรื่อง การทำให้ AI เข้าถึงได้กว้างขึ้น ด้วย

    • อุปมาเรื่องการบีบอัดน่าสนใจดี fine-tuning ก็อาจมองคล้ายกันได้ เช่น ถ้าปรับจูนโมเดล 3B ให้เหมาะกับงานเฉพาะ ก็อาจไม่จำเป็นต้องใช้ความอเนกประสงค์ของโมเดล 70B
  • เป็นโปรเจกต์ที่เจ๋งมาก อยากรู้ว่าต้องมีพื้นฐานความรู้ด้าน ระบบ/ฮาร์ดแวร์ แบบไหนถึงจะคิดไอเดียแบบนี้ออกมาได้
    ฉันทำงานในสภาพแวดล้อมที่ฮาร์ดแวร์ถูก abstraction ไว้เยอะ เลยคิดแนวทางแบบนี้ได้ยาก ดูเหมือนต้องมีทั้งความคิดสร้างสรรค์และความเข้าใจระดับระบบจริง ๆ

    • นี่แหละคือการทดลองนั้น: โปรเจกต์ ps2-llm
      ตอนพยายามรัน LLM บน PS2 ก็เจอข้อจำกัด RAM 32MB และ VRAM 4MB เลยคิดวิธี สตรีมเลเยอร์ ขึ้นมา PS2 สามารถให้ VRAM จัดการที่อยู่ 32 บิตได้โดยตรง เลยเร็วมาก และเขาพยายามจำลองสิ่งนั้นบนพีซีด้วย
    • ฉันก็คิดคล้ายกัน คอนโซลยุคก่อน CPU ช้าเลยทำให้ DMA transfer เป็นหัวใจสำคัญ ประสบการณ์แบบนั้นน่าจะนำไปสู่ไอเดียนี้ และ smart memory card ของ PS2 ก็มีฟังก์ชัน DMA ที่ซับซ้อนพอสมควร
  • ฉันก็กำลังลองอะไรคล้าย ๆ กันอยู่ กำลังทดลองรัน โมเดล 1T โดยใช้ VRAM ไม่ถึงครึ่ง
    ดูเหมือนว่าจะปรับ routing layer ของ SGLang เพื่อทำ expert swap แบบอิง JIT prediction จาก Gen5 NVMe ไปยัง GPU memory ได้ โดยใช้ primitive ของ NVIDIA Dynamo และ NIXL
    ไม่แน่ใจว่ามีใครลองทำมาก่อนหรือยัง

    • ฉันก็อยากเห็นเหมือนกัน กำลังคิดจะซื้อ 3090 เพิ่มอีกใบและ อัปเกรดเมนบอร์ด เพื่อแก้คอขวด PCIe3 น่าจะรัน glm 4.7~5 แบบ q4_k_m ได้
  • เป็นโปรเจกต์ที่เจ๋งมาก อยากรู้รายละเอียดเพิ่มเกี่ยวกับ ขั้นตอนแพตช์ DKMS บน GPU ทั่วไป ฉันก็อยากลองทำดู

    • ฉันอัปเดตเอกสารแล้ว เพิ่มขั้นตอนแพตช์และ ข้อมูลความเสี่ยง เข้าไป
    • มีกรณีที่แก้ไดรเวอร์โอเพนซอร์สของ NVIDIA เพื่อปลดล็อกฟีเจอร์ระดับองค์กรอย่าง การสื่อสาร P2P ระหว่าง GPU หรือ การแบ่ง vGPU ได้เหมือนกัน
      ลิงก์ที่เกี่ยวข้อง: RTX4090 P2P Unlock, vGPU Unlock