3 điểm bởi GN⁺ 28 ngày trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Tối ưu phân bổ tensor giữa GPU·RAM·NVMe để chạy các mô hình ngôn ngữ lớn bằng một bộ lập lịch suy luận nhận biết tầng lưu trữ
  • Trên Mac mini 32GB, có thể chạy mô hình Mixtral 8x7B(31GB) ở tốc độ 2.2 tok/s và mô hình Llama 70B(40GB) ở tốc độ 0.3 tok/s
  • Phân tích mẫu truy cập và băng thông phần cứng để vận hành ổn định cả những mô hình vượt quá bộ nhớ vật lý, xử lý được cả các mô hình mà llama.cpp trước đây thất bại do OOM
  • Thông qua định tuyến chuyên gia của kiến trúc MoE, bộ nhớ đệm neuronprefetch, giảm I/O tới 75% và đạt tỷ lệ cache hit 99.5%
  • Tự động chọn các chế độ Full-resident, Expert-streaming, Dense FFN-streaming theo kích thước mô hình và phần cứng để duy trì hiệu năng tối ưu
  • Cung cấp HTTP API tương thích Ollama để tích hợp với OpenClaw và các công cụ khác, đồng thời dùng SSD chỉ ở chế độ đọc để hỗ trợ suy luận dựa trên NVMe mà không làm giảm tuổi thọ

Tổng quan

  • Hypura là một bộ lập lịch suy luận LLM nhận biết tầng lưu trữ trên môi trường Apple Silicon, thực hiện tối ưu phân bổ tensor giữa GPU·RAM·NVMe
  • Dựa trên mẫu truy cập, chi phí băng thông và hiệu năng phần cứng, nó phân bố tensor trên nhiều tầng để chạy ổn định các mô hình lớn vượt quá bộ nhớ vật lý
  • Trên Mac Mini 32GB, có thể chạy mô hình Mixtral 8x7B(31GB) ở tốc độ 2.2 tok/s và mô hình Llama 70B(40GB) ở tốc độ 0.3 tok/s
  • Trong cùng môi trường, llama.cpp không thể chạy do OOM (Out of Memory)

Bối cảnh vấn đề

  • Máy Mac cho người dùng phổ thông có bộ nhớ hợp nhất nhanh và lưu trữ NVMe, nhưng dung lượng bộ nhớ lại bị giới hạn
  • Ví dụ, M1 Max 32GB không thể nạp trực tiếp mô hình 40GB nên xảy ra swap quá mức và bị dừng do OOM
  • Hypura giải quyết vấn đề này bằng cách phân tích cấu trúc mô hình và thực hiện phân bổ tối ưu theo từng tầng

Phân bổ theo tầng dựa trên cấu trúc mô hình

  • Norms và Embeddings: nhỏ nhưng được truy cập ở mọi token nên được cố định trên GPU
  • Định tuyến chuyên gia MoE: tận dụng tính thưa, chỉ kích hoạt 2 chuyên gia trong số 8 cho mỗi token
    • Chặn router để xác định các chuyên gia đang hoạt động, sau đó chỉ nạp phần cần thiết từ NVMe
    • Giảm I/O 75%, đạt tỷ lệ bộ nhớ đệm neuron 99.5%
    • Dùng theo dõi đồng kích hoạt (co-activation tracking) để dự đoán chuyên gia sẽ hoạt động tiếp theo và thực hiện prefetch trước
  • Dense FFN Weights: chiếm khoảng 60% kích thước mô hình
    • Stream từ NVMe thông qua dynamic pool buffer
    • Độ sâu prefetch nhìn trước (prefetch lookahead depth) được tự động điều chỉnh theo lượng bộ nhớ khả dụng
  • Kết quả là ngay cả các mô hình từng bị crash với cách mmap truyền thống cũng có thể chạy được; còn các mô hình vừa với bộ nhớ thì chạy ở tốc độ Metal GPU mà không có overhead

Cách hoạt động

  • Hypura đọc tệp GGUF và profiling băng thông GPU·RAM·NVMe
  • Mỗi tensor được đặt vào một trong ba tầng sau
    • GPU(Metal): các tầng Attention, Norm, Embedding
    • RAM: các tầng tràn không thể nạp lên GPU
    • NVMe: các tầng còn lại, thực hiện I/O trực tiếp bằng F_NOCACHE + pread
  • Tự động chọn chế độ suy luận theo kích thước mô hình và phần cứng
    • Full-resident: nạp toàn bộ mô hình vào GPU+RAM, không có I/O NVMe
    • Expert-streaming: cho mô hình MoE, chỉ các tensor không phải chuyên gia cư trú trên GPU, tensor chuyên gia được stream từ NVMe
    • Dense FFN-streaming: cho các mô hình lớn không phải MoE, Attention+Norm ở GPU, FFN được stream từ NVMe
  • Kích thước pool buffer, độ sâu prefetch, ngân sách bộ nhớ được tự động tính theo hồ sơ phần cứng

Hiệu năng

  • Môi trường thử nghiệm: M1 Max, 32GB bộ nhớ hợp nhất, NVMe 5.1GB/s
  • Kết quả benchmark chính
    • Qwen 2.5 14B Q4_K_M (8.4GB): nạp hoàn toàn lên GPU, 21 tok/s
    • Mixtral 8x7B Q5_K_M (30.9GB): chế độ Expert-streaming, 2.2 tok/s, tỷ lệ cache hit 99.5%
    • Llama 3.3 70B Q4_K_M (39.6GB): chế độ Dense FFN-streaming, 0.3 tok/s, pool 24 slot, prefetch 7 tầng
  • Các mô hình vừa với bộ nhớ có overhead bằng 0, còn các mô hình vượt ngưỡng thì nhờ Hypura vẫn duy trì được khả năng chạy

Cài đặt và chạy

  • Cần Rust 1.75+CMake
  • Quy trình cài đặt
    git clone --recurse-submodules https://github.com/hypura/hypura.git  
    cd hypura  
    cargo build --release  
    
  • Ví dụ chạy
    hypura profile  
    hypura run ./model.gguf --prompt "Hello, world"  
    hypura run ./model.gguf --interactive  
    hypura bench ./model.gguf  
    hypura inspect ./model.gguf  
    
  • Với các mô hình chưa được kiểm chứng, khuyến nghị thử bằng --max-tokens 10

Máy chủ tương thích Ollama

  • Hypura cung cấp HTTP API tương thích Ollamahoàn toàn tương thích với các công cụ dựa trên Ollama như OpenClaw
    hypura serve ./model.gguf  
    
    Endpoint: http://127.0.0.1:8080  
    
    API: /api/generate, /api/chat, /api/tags  
    
  • Các endpoint chính
    Endpoint Chức năng
    GET / Kiểm tra trạng thái
    GET /api/tags Danh sách mô hình đã nạp
    GET /api/version Phiên bản máy chủ
    POST /api/show Metadata mô hình
    POST /api/generate Tạo văn bản
    POST /api/chat Tạo hội thoại
  • Để tích hợp OpenClaw, đặt Ollama base URL thành Hypura trong ~/.openclaw/openclaw.json
  • Tùy chọn máy chủ
    hypura serve  [OPTIONS]  
    --host    mặc định 127.0.0.1  
    --port    mặc định 8080  
    --context    mặc định 4096  
    

Kiến trúc

  • Cấu trúc Cargo workspace, gồm hai crate
    • hypura: binary và thư viện chính
    • hypura-sys: binding FFI cho llama.cpp (build bằng CMake)
  • Các mô-đun chính
    Mô-đun Vai trò
    scheduler/placement.rs Tối ưu phân bổ tensor giữa GPU/RAM/NVMe
    compute/inference.rs Engine suy luận và các hàm nạp/tạo cho máy chủ
    compute/nvme_backend.rs Stream NVMe, bộ nhớ đệm neuron, callback đánh giá
    server/routes.rs HTTP handler tương thích Ollama
    profiler/ Profiling phần cứng
    cli/bench.rs Công cụ benchmark
    model/tensor_role.rs Phân loại vai trò tensor

FAQ

  • Không có vấn đề về tuổi thọ SSD

    • Hypura chỉ đọc từ SSD, không ghi
    • NVMe I/O được thực hiện chỉ đọc bằng pread() + F_NOCACHE
    • SSD chỉ đóng vai trò lưu trữ nguội, còn tính toán được thực hiện trên RAM/GPU
    • Việc ghi chỉ ở mức rất nhỏ tính bằng KB như JSON kết quả benchmark, tệp thống kê, v.v.

Hướng dẫn an toàn

  • Nếu mô hình vượt quá giới hạn RAM (–4GB dung lượng dự phòng), bench --baseline sẽ bị chặn
  • Với các mô hình chưa được kiểm chứng, hãy thử bằng --max-tokens 10
  • Các mô hình thử nghiệm được lưu trong thư mục ./test-models/

Giấy phép

  • MIT License

Thông báo đạo đức

  • Mã trong kho lưu trữ không phải do tác giả tự viết hoàn toàn
  • Đây là sản phẩm của một thử nghiệm sinh mã theo chỉ dẫn bằng LLM
  • Là một dự án nhằm khám phá khả năng ứng dụng của suy luận dựa trên NVMe

1 bình luận

 
Ý kiến trên Hacker News
  • Muốn đề xuất với người duy trì dự án. Bảng so sánh hiện tại có các mô hình cũ như Qwen 2.5 14B, Mixtral 8x7B, Llama 3.3 70B
    Gần đây có nhiều báo cáo cho thấy các mô hình Qwen 3.5 MoE cho hiệu năng ấn tượng trên phần cứng Apple
    Có thể tham khảo bài viết của Simon Willison
    Nếu có thể thì cũng nên thêm mô hình Kimi K2.5 (1T tham số) vào bảng
    Tweet liên quan: seikixtc, danpacary

    • Cảm ơn đã chia sẻ. Nếu bạn muốn tự chạy benchmark bằng Hypura, tôi sẽ gộp kết quả vào thống kê. Nếu không thì tôi sẽ thêm vào danh sách việc cần làm của mình
    • Simon, hơi ngoài lề một chút nhưng trang của bạn đã bị down trong chốc lát
      Có hiện thông báo lỗi liên quan đến Heroku, nhưng giờ đã hoạt động bình thường trở lại
      Tôi vào để đọc bài này, và thấy bạn cũng đã viết bài về litellm rồi. Đọc rất hay
    • Hơi tiếc là ví dụ Kimi thiếu chỉ số tốc độ token
  • Trong công việc cục bộ, dù tốc độ dưới 1 token/giây thì nếu là tác vụ nền vẫn đủ dùng
    Sự khác biệt giữa “xong ngay” và “xong sau một đêm” vẫn là một bước nhảy hiệu năng có ý nghĩa

  • Trên thực tế, điều quan trọng là mẫu đọc có tuần tự (sequential) đến mức nào
    NVMe đạt 5–7GB/s khi đọc tuần tự, nhưng với đọc ngẫu nhiên thì tụt xuống khoảng 500MB/s
    Với mô hình 1T, nếu tính theo fp16 thì một lần forward pass phải stream 2TB, nên về lý thuyết sẽ mất hơn 300 giây cho mỗi token
    Không phù hợp cho tương tác, nhưng có tiềm năng cho suy luận theo lô (batch inference)

    • Trên M1 Max, đọc ngẫu nhiên 4K (QD=1) chỉ khoảng 65MB/s
    • Đồng ý. Cái này gần với POC (Proof of Concept) hơn là tính thực dụng
      Nhưng với các mô hình MoE nhỏ thì có thể tạo ra nhiều token mỗi giây nên thực sự dùng được
    • Điểm cốt lõi của mô hình MoE là kích hoạt thưa (sparse activation)
      Không phải đọc toàn bộ 2TB mà chỉ truy cập một phần các expert layer
      Mỗi layer có kích thước cỡ vài MiB nên hiệu quả truy cập NVMe cũng không quá tệ
  • Tôi từng thắc mắc “mô hình 1T tham số” xuất hiện từ đâu. Trong repo chỉ thấy các mô hình 70B trở xuống

    • Đó là cách nói về mặt khả năng. Nhưng tốc độ quá chậm nên ngoài các tác vụ dài hạn đặc thù thì không thực tế
      Các mô hình thực tế hơn là dòng MoE nhỏ nhưng có thể tạo nhiều token mỗi giây
    • Tiêu đề có cảm giác hơi cường điệu. Cuối cùng điều quan trọng vẫn là tốc độ, nhưng lại không có thông tin về phần đó
  • Ý chính của MoE là nhờ kích hoạt thưa nên không phải đọc toàn bộ 2TB
    Nhưng mẫu truy cập lại bị ngẫu nhiên hóa, khiến đây trở thành điều kiện tệ nhất cho NVMe
    Với các tác vụ mà độ trễ (latency) quan trọng như suy luận agent thì đây là điểm mấu chốt

  • Tình huống này khiến Intel Optane như đang trằn trọc dưới mồ

    • Memristor cũng từng có vẻ như sắp thương mại hóa cách đây 10 năm, nhưng giờ thì biến mất hoàn toàn
    • Tôi vẫn còn giữ 4 chiếc Optane mới. Nói đùa vậy thôi nhưng là thật
      Dù vậy trên thực tế nó không nhanh hơn NVMe. Với phần mềm hỗ trợ đọc/ghi song song, gần như không có khác biệt
    • Chuyện Intel làm ra thứ tốt rồi lại bỏ dở giữa chừng giờ cũng thành quen rồi
      Dù sao nếu ghép 4 cái bằng RAID 0 thì chắc có thể tận dụng hết băng thông PCIe 16x
    • nhắc đến pmem
  • Phần cứng Mac tiêu dùng có bộ nhớ hợp nhất và NVMe nhanh, nhưng dung lượng lại hạn chế
    Nếu tải mô hình 40GB trên M1 Max 32GB thì swap sẽ tăng vọt và cuối cùng rơi vào trạng thái panic
    macOS không có OOM killer kiểu Linux, mà chỉ đơn giản là hết chỗ cho swap

  • Việc có “càng nhiều bộ nhớ càng tốt” cũng quan trọng, nhưng băng thông (bandwidth) mới là biến số lớn hơn
    M4 Pro là 273GB/s, M4 Max là 546GB/s, M4 Ultra là 819GB/s
    Sau khi mô hình đã nằm trong bộ nhớ, băng thông sẽ quyết định tốc độ token
    Theo Hypura thì M4 Max là điểm cân bằng tốt nhất. Với 64GB có thể chạy thoải mái mô hình 70B (Q4), và tốc độ sinh token gấp đôi so với Pro

  • Dự án này về cơ bản hoạt động như một dạng bộ nhớ swap thông minh
    Điểm thú vị là nó điều tiết để không sử dụng NVMe quá mức
    Tuy vậy, nếu thực sự dồn tải nặng lên NVMe thì có thể lo ngại về giảm tuổi thọ

    • Cách nói “dồn tải lên NVMe” nghe hơi lạ
      SSD đúng là giảm tuổi thọ cell theo số lần ghi, nhưng việc controller bị hỏng vì tải đọc thì hầu như không xảy ra
      Nếu đúng là thế thì hệ thống đang có vấn đề khác
  • Sẽ hay nếu so sánh dự án này với các thử nghiệm trước đó, một thử nghiệm khác
    Bản này là dựa trên mmap nên từng có báo cáo là overhead lớn

    • Đoạn mã đó do LLM viết ra nên độ tin cậy thấp
    • Ngoài ra, bản triển khai lần này không dùng quantization quá mạnh nên ít suy giảm chất lượng hơn