- 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
- Kabar terbaru: batch processing telah diimplementasikan sehingga kecepatan encoding gambar meningkat hingga sekitar 3x
- Llama 3.2 1B berjalan pada 50 tok/s di mesin 16-core milik penulis
- Model dan tokenizer yang sudah disiapkan bisa diunduh dari Hugging Face
- Pengukuran kecepatan dilakukan pada AMD Epyc 16-core
- README merekomendasikan penggunaan Q8_0, dan menyebut kuantisasi Q4_0 masih dalam tahap perbaikan
-
Tabel model siap pakai
- Gemma 2 2B IT Q4_0: 1.39G, 20 tok/s
- Gemma 2 2B IT Q8_0: 2.66GB, 24 tok/s
- Gemma 2 9B IT Q4_0: 4.91GB, 7 tok/s
- Gemma 2 9B IT Q8_0: 9.53GB, 8 tok/s
- Llama 3.2 1B IT: 4.94GB, 21 tok/s
- Llama 3.2 1B IT Q8_0: 1.27GB, 50 tok/s
- Llama 3.2 3B IT Q4_0: 1.71GB, 17 tok/s
- Llama 3.2 3B IT Q8_0: 3.31GB, 19 tok/s
- PHI 3.5 IT Vision Q8_0: 4.28GB, 17 tok/s
- PHI 3.5 IT Mini Q8_0: 3.94GB, 18 tok/s
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
Komentar Hacker News
Mencoba menjalankan
llama3.2-1b-it-q80.lmrsberukuran 1,2GB di M2 64GB MacBook, dan terasa cukup cepat; menurut Activity Monitor, ia memakai 1000% CPU di 13 threadMeng-clone
lm.rske/tmp, membangunnya denganRUSTFLAGS="-C target-cpu=native" cargo build --release --bin chat, lalu mengambiltokenizer.bindanllama3.2-1b-it-q80.lmrsdari Hugging Face, kemudian menjalankannya dengan./target/release/chat --model llama3.2-1b-it-q80.lmrs./target/release/chat --model llama3.2-1b-it-q80.lmrs --show-metricsuntuk melihat berapa token per detik yang dihasilkanHanya sebagian yang ditinggalkan karena format, tetapi bentuknya adalah rangkaian panjang kata-kata acak yang terus berlanjut
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 objeklm.rsJuga terlihat ada bagian yang memakai
unsafeuntuk memaksa penyelarasan data di model reader; penasaran apakah ini bisa dilakukan tanpaunsafeDengan 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 PythonSaat ini ditujukan untuk dukungan
llama.cpp, tetapi ini juga cukup menarik. Penasaran apakah ada rencana dukungan grammar constrainthttps://github.com/ShelbyJenkins/llm_client
Ungkapan no dependency di judul kurang jelas
Saat pertama melihatnya, sempat terpikir mungkin maksudnya
no_std, tetapi ternyata bukanno_stddan tampaknya tetap ada beberapa dependensi. Mungkin maksudnya semua dependensinya adalah dependensi RustJika dijelaskan secara transparan, ada 5 dependensi Rust dasar, dan di antaranya
chronosertaclapsemestinya diatur dengan feature flag untuk fungsi chat. Tiga sisanya adalah crate utilitas untuk sedikit memaksimalkan performa hardware:rayonuntuk memudahkan paralelisasi,wideuntuk membantu SIMD, danmemmap2untuk memory mapping file modelrequirements.txtmembutuhkan 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 membingungkanProyeknya 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
Sayangnya, HN sering menghapus kata dari judul tanpa alasan atau transparansi yang jelas
cargomilik Rust sekarang hampir jadi sepertinpmyaAda 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
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 variableNamun, 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
https://github.com/maedoc/rwkv.js
Saya memakai
Rwkv.cppyang dikompilasi dengan Emscripten, tetapi bagian tokenizer masih belum benar-benar terselesaikan. Meski begitu, 1.6B RWKV6 tampaknya sudah cukup layak dipakai khusus untuk browser offlineUntuk chat umum kemampuannya masih kurang, tetapi untuk penggunaan seperti RAG bisa jadi sudah cukup memadai
Dependensi wajib
rayondanwidelangsung mendukung WASM, dan jika tipeMmapditransformer.rsdiubah menjadi&[u8],memmap2juga bisa dihapusNamun 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
Jika ingin mencoba framework Rust yang mendukung GPU, Candle https://github.com/huggingface/candle/tree/main layak dilihat
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 disingkirkanDari sisi efek, LLM terlihat seperti sihir, tetapi dari sudut pandang kode sebenarnya cukup sederhana
Di sisi Rust ada wrapper
llama.cppsepertillm_clientmilik saya, dan ada proyek berbasis Candle sepertimistral.rsdan KalosmProyek saya juga ingin menyediakan implementasi
mistral.rs, tetapi masih belum sepenuhnya berpindah darillama.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 menitMisalnya 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
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.cppKeren, dan selamat atas library Rust pertamanya, tetapi untuk penggunaan lokal yang serius dukungan Metal/CUDA itu wajib
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 berkembangSemangat komunitas Rust untuk menulis ulang hampir semuanya terasa menarik dan patut diapresiasi