1 poin oleh GN⁺ 2024-10-12 | 1 komentar | Bagikan ke WhatsApp
  • lm.rs adalah proyek untuk menjalankan inferensi model bahasa lokal di CPU dengan Rust, dan menargetkan implementasi kode minimal yang melakukan seluruh inferensi tanpa library ML
  • Terinspirasi dari llama2.c dan llm.c karya Karpathy; awalnya hanya mendukung Google Gemma 2, lalu diperluas hingga mendukung Llama 3.2 dan input gambar untuk PHI-3.5
  • Perubahan terbaru menghadirkan batch processing, sehingga kecepatan encoding gambar meningkat hingga sekitar 3x, dan Llama 3.2 1B berjalan pada 50 tok/s di mesin 16-core milik penulis
  • Model yang sudah disiapkan bisa diunduh dari Hugging Face, dan README merekomendasikan penggunaan Q8_0 serta menyebut kuantisasi Q4_0 masih dalam tahap perbaikan
  • Pengguna dapat langsung membangun dengan mengunduh model format LMRS dan tokenizer, atau mengonversi file model asli dari Hugging Face menggunakan export.py dan tokenizer.py untuk dijalankan

Tujuan lm.rs

  • lm.rs adalah implementasi inferensi model bahasa lokal berbasis CPU yang ditulis dengan Rust
  • Tujuannya adalah implementasi kode minimal yang menjalankan seluruh inferensi model bahasa di CPU tanpa library ML
  • Terinspirasi dari llama2.c dan llm.c karya Karpathy
  • README menyebut kode saat ini “tidak terlalu minimal”, dan beberapa bagian masih memiliki ruang untuk optimasi dan perbaikan
  • Proyek ini juga menjadi kesempatan bagi penulis untuk pertama kali mencoba Rust

Model yang didukung dan perluasan multimodal

  • Pada awalnya hanya mendukung model Google Gemma 2, tetapi kemudian ditambahkan dukungan untuk model Llama 3.2
  • Baru-baru ini, opsi penggunaan gambar ditambahkan melalui PHI-3.5
  • Dukungan yang saat ini ditekankan
    • Dukungan multimodal melalui model PHI-3.5-vision
    • Dukungan model teks saja PHI-3.5-mini
  • Sumber terkait

Performa dan model siap pakai

Alur konversi model

  • Jika mengunduh model kuantisasi dan tokenizer yang sudah disiapkan dari Hugging Face, Anda dapat melewati proses konversi
  • Untuk mengonversi langsung model yang dipublikasikan Google atau Meta di Hugging Face, dependensi Python tambahan perlu dipasang
pip install -r requirements.txt
  • File .safetensors dan config.json diunduh dari halaman model asli untuk digunakan
  • Untuk model multimodal seperti PHI3.5 Vision, file config CLIP juga diperlukan
  • export.py mengonversi bobot bfloat16 ke format LMRS
python export.py --files [ordered .safetensor files] --config [model config.json] --save-path [name and path to save] --type [model type (GEMMA/LLAMA/PHI)]
  • Untuk mengekspor versi kuantisasi, gunakan flag --quantize dan --quantize-type
  • Ukuran model kuantisasi int8 dapat berkurang dari sekitar 9.8G menjadi sekitar 2.5G tergantung ukuran grup
  • Model multimodal harus menyertakan argumen --vision-config
  • tokenizer.py mengonversi model tokenizer ke format tokenizer LMRS
python tokenizer.py --model-id [huggingface model_id] --tokenizer-type [type of the tokenizer (GEMMA/LLAMA/PHI)]

Build dan jalankan

  • Kode Rust dikompilasi dengan cargo, dan README secara eksplisit menyebut penggunaan flag target-cpu
RUSTFLAGS="-C target-cpu=native" cargo build --release --bin chat
  • Untuk mengaktifkan fitur multimodal, tambahkan argumen --features multimodal
  • Eksekusi dasar dilakukan dengan menentukan file bobot model
./target/release/chat --model [model weights file]
  • Argumen tambahan seperti tokenizer, temperature, top-p, show-metrics, dan lainnya juga dapat digunakan
  • Argumen yang tersedia dapat dilihat dengan --help
  • Pada model multimodal, tentukan path gambar dengan argumen --image
  • Saat menggunakan PHI3.5-vision, README merekomendasikan temperature 0

Menjalankan backend WebUI

  • Untuk menjalankan backend bagi WebUI, kompilasi dengan fitur backend
RUSTFLAGS="-C target-cpu=native" cargo build --release --features backend --bin backend
  • Untuk backend multimodal, aktifkan fitur backend-multimodal
  • Backend dijalankan dengan menentukan file bobot model
./target/release/backend --model [model weights file]
  • IP dan port dapat diubah dengan --ip dan --port
  • Flag tambahan seperti temperature juga dapat digunakan
  • Untuk kompatibilitas multimodal, gunakan flag --multimodal
  • Setelah dijalankan, Anda dapat terhubung melalui antarmuka web

Status TODO dan lisensi

  • Item yang sudah selesai
    • Penambahan metode sampling lain
    • Dari item pengujian model 9B dan 27B, pengujian 9B telah selesai, sementara 27B ditandai akan terlalu lambat
    • Paralelisasi loop multi-head attention
    • Penambahan metrik performa
    • Dukungan kuantisasi int8 dan int4
  • Item yang tersisa
    • Fitur untuk menyediakan system prompt
  • Lisensinya adalah MIT

1 komentar

 
GN⁺ 2024-10-12
Komentar Hacker News
  • Mencoba menjalankan llama3.2-1b-it-q80.lmrs berukuran 1,2GB di M2 64GB MacBook, dan terasa cukup cepat; menurut Activity Monitor, ia memakai 1000% CPU di 13 thread
    Meng-clone lm.rs ke /tmp, membangunnya dengan RUSTFLAGS="-C target-cpu=native" cargo build --release --bin chat, lalu mengambil tokenizer.bin dan llama3.2-1b-it-q80.lmrs dari Hugging Face, kemudian menjalankannya dengan ./target/release/chat --model llama3.2-1b-it-q80.lmrs

    • Bertanya apakah bisa dijalankan dengan ./target/release/chat --model llama3.2-1b-it-q80.lmrs --show-metrics untuk melihat berapa token per detik yang dihasilkan
    • Saat diberi prompt percakapan sederhana dalam bahasa Prancis, awalnya tampak merespons, tetapi segera runtuh menjadi output sampah tak masuk akal tanpa akhir
      Hanya sebagian yang ditinggalkan karena format, tetapi bentuknya adalah rangkaian panjang kata-kata acak yang terus berlanjut
    • Penasaran bagaimana seharusnya memahami seberapa pintar ini dibandingkan ChatGPT terbaru
  • Tulisannya sangat bagus, dan sebagian source code-nya tampaknya bisa dipakai saat menjelaskan bagaimana transformer benar-benar bekerja di kelas
    Dibanding diagram attention head, kodenya lebih konkret dan detail. Namun, jika library langsung menulis ke stdout, itu bisa merusak output aplikasi seperti editor teks yang menyediakan pemeriksaan gaya, jadi akan lebih baik jika menulis ke buffer string dari instance logging yang terhubung dengan objek lm.rs
    Juga terlihat ada bagian yang memakai unsafe untuk memaksa penyelarasan data di model reader; penasaran apakah ini bisa dilakukan tanpa unsafe

    • Daripada buffer string, akan lebih baik memanggil callback pengguna
      Dengan begitu, log bisa ditangani misalnya untuk ditampilkan di GUI
  • Sudah membuat cukup banyak alat Rust untuk berbagai tugas LLM seperti loading model
    Ada fitur untuk otomatis memilih model quantized terbesar sesuai memori yang tersedia, mengekstrak tokenizer dari gguf, atau memasukkan prompt. Ini tampaknya bisa menghilangkan sebagian dependensi Python
    Saat ini ditujukan untuk dukungan llama.cpp, tetapi ini juga cukup menarik. Penasaran apakah ada rencana dukungan grammar constraint
    https://github.com/ShelbyJenkins/llm_client

  • Ungkapan no dependency di judul kurang jelas
    Saat pertama melihatnya, sempat terpikir mungkin maksudnya no_std, tetapi ternyata bukan no_std dan tampaknya tetap ada beberapa dependensi. Mungkin maksudnya semua dependensinya adalah dependensi Rust

    • Membuat judul itu sulit. Yang ingin disampaikan adalah tidak ada dependensi deep learning seperti PyTorch, CUDA, ONNX, dan semua logikanya bersifat self-contained
      Jika dijelaskan secara transparan, ada 5 dependensi Rust dasar, dan di antaranya chrono serta clap semestinya diatur dengan feature flag untuk fungsi chat. Tiga sisanya adalah crate utilitas untuk sedikit memaksimalkan performa hardware: rayon untuk memudahkan paralelisasi, wide untuk membantu SIMD, dan memmap2 untuk memory mapping file model
    • Melihat README, tampaknya requirements.txt membutuhkan PyTorch dan berbagai dependensi Python, dan satu-satunya tempat di halaman yang menampilkan kata “dependency” juga ada di sana, jadi frasa di judul terasa cukup membingungkan
      Proyeknya sendiri tampaknya hanya memakai subjudul “Minimal LLM inference in Rust”. Dari riwayat Git, akun yang memposting artikel ini tampaknya kontributor tetapi bukan penulis utama, jadi akan membantu jika dijelaskan apa tepatnya arti zero dependencies
    • Mungkin awalnya judul seperti “tanpa dependensi hardware” atau “tanpa dependensi GPU” akan lebih masuk akal
      Sayangnya, HN sering menghapus kata dari judul tanpa alasan atau transparansi yang jelas
    • Jadi cargo milik Rust sekarang hampir jadi seperti npm ya
      Ada 16 dependensi, jadi saya tidak paham bagaimana ini bisa disebut tanpa dependensi
  • Dulu pernah membuat sesuatu yang mirip, tetapi performanya kurang memuaskan dibanding kode C/C++ yang berjalan di CPU
    Itu juga berarti saya dulu tidak benar-benar tahu cara membuat Rust menjadi cepat. Akan bagus kalau ada benchmark dari beberapa implementasi Rust
    Implementasi inferensi LLM tampaknya bisa menjadi “Hello, world!” baru bagi para programmer serius
    https://github.com/gip/yllama.rs

    • Saya juga dulu pernah membuat sesuatu dari pengalaman “Hello, world” yang serupa
      https://github.com/crabml/crabml
      Saya menggunakan langsung beberapa instruksi SIMD, dan performanya tampak bisa menyamai llama.cpp. Kuncinya tampaknya adalah penggunaan SIMD pada perkalian matriks quantized, dan saat membagi pekerjaan antar-thread memakai busy-wait loop alih-alih condition variable
      Namun, saya tidak sempat melanjutkan pekerjaan inferensi model quantized di GPU dengan Vulkan, jadi sudah lama tidak diperbarui
  • Menarik bahwa mereka sudah menggunakan Dioxus, dan saya penasaran apakah WASM juga bisa masuk ke roadmap
    Jika LLM ringan seperti RWKV bisa dijalankan di browser, browser dapat membuka kategori fungsi baru tanpa perlu memanggil API SaaS

    • Saya pernah sedikit mengutak-atik area ini
      https://github.com/maedoc/rwkv.js
      Saya memakai Rwkv.cpp yang dikompilasi dengan Emscripten, tetapi bagian tokenizer masih belum benar-benar terselesaikan. Meski begitu, 1.6B RWKV6 tampaknya sudah cukup layak dipakai khusus untuk browser offline
      Untuk chat umum kemampuannya masih kurang, tetapi untuk penggunaan seperti RAG bisa jadi sudah cukup memadai
    • Library itu sendiri tampaknya bisa dikompilasi ke WASM dengan perubahan yang sangat sedikit
      Dependensi wajib rayon dan wide langsung mendukung WASM, dan jika tipe Mmap di transformer.rs diubah menjadi &[u8], memmap2 juga bisa dihapus
      Namun RWKV memiliki arsitektur yang sepenuhnya berbeda sehingga seluruhnya harus diimplementasikan ulang, dan kemungkinannya masuk roadmap tampak sangat kecil
  • Saya penasaran apakah implementasi ini semuanya memang hanya untuk CPU
    Ia bertanya apakah kalau punya GPU yang bagus, memang sebaiknya mencari alternatif lain

    • Benar. Proyek ini berjalan di CPU sehingga tidak memanfaatkan GPU untuk komputasi
      Jika ingin mencoba framework Rust yang mendukung GPU, Candle https://github.com/huggingface/candle/tree/main layak dilihat
    • Semuanya diimplementasikan untuk CPU, dan setidaknya saat ini sama sekali belum ada akselerasi GPU
      Jika tujuannya benar-benar untuk dipakai menjalankan model, bahkan dengan CPU saja akan lebih baik memakai alternatif lain, yaitu llama.cpp. Proyek ini lebih dekat ke materi edukasi yang menunjukkan bagaimana bagian dalamnya bekerja ketika lapisan-lapisan rumit dalam ekosistem disingkirkan
      Dari sisi efek, LLM terlihat seperti sihir, tetapi dari sudut pandang kode sebenarnya cukup sederhana
    • Bergantung pada GPU, perbedaannya bisa 10~20 kali
      Di sisi Rust ada wrapper llama.cpp seperti llm_client milik saya, dan ada proyek berbasis Candle seperti mistral.rs dan Kalosm
      Proyek saya juga ingin menyediakan implementasi mistral.rs, tetapi masih belum sepenuhnya berpindah dari llama.cpp. Implementasi Rust murni punya kelebihan besar seperti mempercepat waktu instalasi. Saat ini crate saya masih harus di-clone dan di-build, jadi meskipun otomatisasi untuk macOS, Windows, dan Linux sudah ada, waktu build tetap bertambah sekitar 1 menit
    • Benar CPU, tetapi yang lebih penting adalah bandwidth memori
      Misalnya RTX 3090 memiliki bandwidth memori hampir 1TB/s. Untuk menyamainya, Anda perlu setidaknya 12 kanal DDR5 tingkat proof-of-concept tercepat di dunia
      Jika punya GPU diskret, memakai implementasi yang memanfaatkannya adalah dunia yang benar-benar berbeda. Alasan angka inferensi LLM di Apple Silicon tampak mengesankan juga karena arsitektur memori terpadu ber-bandwidth tinggi CPU-GPU, dan kalau tidak salah angkanya sekitar 400GB/s
    • Tergantung kasusnya. Model yang bagus berukuran besar dan kebutuhan memorinya juga tinggi
      Bahkan 4090 pun, dalam konteks LLM, memorinya tidak terlalu besar. GPU memang akan lebih cepat, tetapi kemungkinan tidak bisa memuat model yang besar
  • Saya penasaran nilai apa yang dimilikinya dibandingkan llama.cpp

    • Mungkin lebih mudah diintegrasikan dengan proyek Rust lain
    • Karena fiturnya lebih sedikit, codebase-nya lebih rapi
  • Keren, dan selamat atas library Rust pertamanya, tetapi untuk penggunaan lokal yang serius dukungan Metal/CUDA itu wajib

    • Jika memakai CUDA, itu bertentangan dengan tujuan proyek ini sehingga sejak awal memang kurang cocok
      Namun meski saya bukan penulis utamanya, sebagai kontributor saya sedang bereksperimen untuk mendapatkan sebagian akselerasi GPU dengan wgpu. Penulis utama ingin menjaga kompleksitas tetap terkendali, jadi saya tidak tahu sejauh mana ini benar-benar akan berkembang
  • Semangat komunitas Rust untuk menulis ulang hampir semuanya terasa menarik dan patut diapresiasi