3 poin oleh GN⁺ 3 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • GGUF adalah format berkas model bahasa yang digunakan oleh llama.cpp, yang menaruh metadata yang dibutuhkan untuk menjalankan model dalam satu berkas agar distribusi dan pemuatan model lebih sederhana
  • Template chat adalah skrip Jinja2 yang menangani format percakapan, pemanggilan alat, dan pengodean pesan multimedia, tetapi perilakunya bisa berbeda antar implementasi
  • GGUF dapat menyimpan token khusus seperti token akhir serta pengaturan sampler yang direkomendasikan, dan belakangan juga bisa menyatakan urutan rantai sampler
  • Format pemanggilan alat masih berbeda untuk tiap model, sehingga mesin inferensi masih perlu hardcoding per mesin, dan pembuatan parser berbasis grammar masih menjadi kandidat perbaikan standar
  • think_token, bundling model proyeksi, dan flag fitur masih kurang, sehingga pemisahan segmen pemikiran, konfigurasi multimodal, dan deteksi fitur yang didukung masih sulit

Apa yang disimpan GGUF

  • GGUF adalah format berkas yang digunakan llama.cpp untuk model bahasa
  • Keunggulan utama GGUF adalah memasukkan berbagai komponen yang diperlukan untuk menjalankan model ke dalam satu berkas
    • Repositori safetensors yang umum di Hugging Face memiliki berkas JSON yang diperlukan tersebar di beberapa tempat
    • Model Ollama yang umum berbentuk OCI yang mencakup layer JSON, template Go, dan sebagainya
  • GGUF memasukkan informasi tambahan semacam ini ke dalam satu berkas agar model lebih mudah ditangani

Template chat

  • Model bahasa percakapan dilatih dengan urutan token dalam format tertentu, dan format ini tampak seperti struktur percakapan
  • Contoh format Gemma4 adalah sebagai berikut
<|turn>user
Hi there!<turn|>
<|turn>model
Hi there, how can I help you today?<turn|>
  • Contoh template format LFM2 adalah sebagai berikut
<s>
<|im_start|>user Hi there!<|im_end|>
<|im_start|>assistant Hi there, how can I help you today?<|im_end|>
  • Template nyata jauh lebih kompleks karena juga mencakup blok penalaran, deskripsi alat, pemanggilan dan respons alat, sampai pengodean pesan multimedia seperti gambar, audio, dan video
  • Penanganan ini dilakukan oleh template chat, yaitu skrip yang ditulis dalam bahasa template Jinja2
  • Sebuah model dapat memiliki beberapa template chat
    • Bisa ada template yang mendukung pemanggilan alat dan template lain yang tidak mendukungnya
    • Kebanyakan model menyediakan satu template chat besar, lalu hanya menangani logika terkait pemanggilan alat saat alat ditentukan
    • Pada beberapa model, template chat khusus alat perlu dicari secara terpisah
  • Jinja2 lebih dekat ke bahasa pemrograman karena memiliki loop, kondisional, assignment, list, dictionary, dan sebagainya
    • Aplikasi LLM percakapan harus menyertakan interpreter untuk menjalankan program seperti skrip Jinja sekitar 250 baris yang disediakan Gemma setiap kali pesan baru ditambahkan
  • Cara penanganan Jinja juga berbeda antar implementasi
    • Hugging Face transformers memakai pustaka jinja2 Python yang sudah ada
    • llama-server dan llama-cli milik llama.cpp memakai implementasi Jinja buatan sendiri
    • llama_chat_apply_template yang diekspos ke API libllama adalah pendekatan lama yang langsung hardcode beberapa format chat ke C++
    • NobodyWho memakai minijinja, implementasi ulang dalam Rust oleh pembuat asli Jinja
    • Ini berbeda dengan minja, pustaka Jinja minimal yang pernah dipakai llama.cpp
  • Ada perbedaan performa yang cukup besar di antara implementasi Jinja
    • Dalam aplikasi LLM lokal, pemrosesan template chat bukan bottleneck performa, jadi ini bukan isu besar

Token khusus

  • Model bahasa bisa terus mengeluarkan token berikutnya untuk urutan token masukan, jadi dibutuhkan cara untuk menghentikan generasi
  • Solusi umum adalah memakai token akhir, dan ketika model mengeluarkan token ini, mesin inferensi menghentikan generasi
  • Token akhir adalah salah satu contoh token khusus
    • Token khusus umumnya memiliki makna yang melampaui karakter yang ditokenisasi biasa
    • Biasanya token ini tidak seharusnya ditampilkan ke pengguna, tetapi sering punya representasi teks sehingga tetap bisa ditampilkan
  • Beberapa contoh token khusus Gemma4 adalah sebagai berikut
    • 1 / <eos>: akhir urutan, dikeluarkan model untuk menghentikan generasi
    • 2 / <bos>: awal urutan, ditambahkan di depan input
    • 46 / <|tool_call>: menandai awal pemanggilan alat
    • 47 / <tool_call|>: menandai akhir pemanggilan alat
    • 105 / <|turn>: menandai awal giliran percakapan
    • 106 / <turn|>: menandai akhir giliran percakapan

Pengaturan dan urutan sampler

  • Model bahasa menghasilkan distribusi probabilitas token berikutnya, dan proses memilih token dari distribusi ini disebut sampling
  • Cara paling sederhana adalah memilih secara acak dari distribusi berbobot
  • Dalam praktiknya, hasil yang lebih baik bisa didapat jika transformasi diterapkan ke distribusi probabilitas sebelum memilih token tertentu
  • Saat lab merilis model baru, mereka sering menyertakan pengaturan sampler yang direkomendasikan
  • Pengguna juga sering menyalin-tempel nilai dari berkas Markdown dan sejenisnya untuk mendapatkan respons yang lebih baik
  • Untuk mengurangi penyalinan manual oleh pengguna, NobodyWho mengunggah model terkurasi ke halaman Hugging Face dan membundel pengaturan sampler yang direkomendasikan dalam formatnya sendiri
    • Ini bekerja, tetapi model hanya menjadi benar-benar berguna jika dikonversi lebih dulu oleh pihak NobodyWho
  • Dengan fitur yang baru ditambahkan ke format GGUF, rantai sampler kini bisa dinyatakan langsung di dalam berkas model
    • Karena itu, format milik NobodyWho sendiri menjadi tidak diperlukan lagi, dan memang itulah hasil yang diinginkan
  • Di webapp llm-sampling, kita bisa cepat melihat peran tahap sampler yang berbeda-beda
  • Dengan drag-and-drop tahap individual, terlihat bahwa urutan tahap sampling dapat membuat perbedaan besar pada distribusi akhir
  • Banyak format pengaturan sampler, termasuk berkas JSON di image Ollama atau generation_config.json milik Hugging Face, tidak punya cara untuk menyatakan urutan tahap sampling
  • Standar GGUF dapat menentukan urutan sampling dengan field general.sampling.sequence
  • Meski begitu, banyak model GGUF masih menghilangkan field ini dan bergantung pada urutan implisit berupa perilaku default llama.cpp

Hal-hal yang masih belum ada

  • Mesin inferensi yang baik berusaha menyediakan antarmuka terpadu untuk beragam model bahasa
  • Dengan mem-parsing dan memanfaatkan informasi tambahan dalam metadata GGUF, banyak jalur kode spesifik model bisa dikurangi
  • Format pemanggilan alat

    • Hampir semua mesin inferensi punya jalur hardcode untuk mem-parsing format pemanggilan alat yang berbeda-beda
    • Contoh format pemanggilan alat pada Qwen3 adalah sebagai berikut
<tool_call>{"name": "get_weather", "arguments": {"location": "Copenhagen"}}</tool_call>
  • Contoh format pemanggilan alat pada Qwen3.5 adalah sebagai berikut
<tool_call>
<function=get_weather>
<parameter=city>
Copenhagen
</parameter>
</function>
</tool_call>
  • Contoh format pemanggilan alat pada Gemma4 adalah sebagai berikut
<|tool_call>call:get_weather{city:<|"|>Copenhagen<|"|>}<tool_call|>
  • Setiap kali model baru muncul, berbagai mesin inferensi harus masing-masing mengimplementasikan parsernya
  • Jika grammar bisa disertakan di berkas model, lalu parser bisa diturunkan dari grammar tersebut, itu akan menjadi tambahan yang sangat baik untuk standar GGUF
  • NobodyWho juga menambahkan langkah ekstra untuk menghasilkan constraint grammar yang sesuai dengan alat tertentu yang diberikan
    • Dengan ini, keamanan tipe pada pemanggilan alat bisa dijamin
    • Ini khususnya berguna karena model kecil, terutama yang berukuran 1B atau kurang, bisa keliru mengirim float di tempat yang membutuhkan integer
  • Bahkan jika ada grammar yang bisa membuat parser pemanggilan alat umum, NobodyWho tetap perlu mengimplementasikan fungsi yang menghasilkan grammar per alat konkret yang diberikan
  • Format meta-grammar yang bisa membuat grammar spesifik alat lalu menurunkan parser darinya tetap menjadi persoalan menarik
  • Token think

    • Ini adalah bagian yang paling mudah ditambahkan di antara item yang masih kurang
    • Repositori upstream Hugging Face sudah mulai menyertakan field think_token
    • think_token sangat berguna untuk memisahkan segmen pemikiran dari output yang dihasilkan
      • Segmen pemikiran umumnya perlu dihapus atau dirender berbeda dari output utama
    • Hasil konversi GGUF downstream biasanya tidak menyertakan field ini
    • Akibatnya, mesin inferensi berbasis GGUF tidak bisa memisahkan aliran pemikiran dari output utama tanpa menulis kode terpisah untuk keluarga model tertentu
    • Masalah ini bisa diselesaikan dengan menambahkan think_token ke pipeline konversi GGUF standar
  • Model proyeksi

    • Interaksi LLM multimodal yang memungkinkan LLM melihat gambar dan audio secara native, bukan sebagai teks, memerlukan model tambahan untuk menangani input non-teks
    • Model tambahan ini disebut model proyeksi
    • Praktik saat ini adalah mengirim dua berkas GGUF
      • Satu GGUF untuk model bahasa utama
      • Satu model yang lebih kecil untuk pemrosesan gambar dan audio
    • Cara ini merusak kenyamanan satu berkas yang dimiliki GGUF
    • Akan menjadi peningkatan besar jika satu berkas GGUF bisa membundel bobot dan konfigurasi model proyeksi di dalam berkas utama
    • Model proyeksi sering berukuran sekitar 1GB
      • Ini cukup besar sehingga orang ingin menghindari overhead itu saat tidak digunakan
    • Menyediakan dua varian, yaitu GGUF dengan bobot proyeksi dan GGUF tanpa bobot proyeksi, adalah pendekatan yang masuk akal
    • Dengan begitu, kita bisa kembali ke kondisi hanya perlu mengelola satu URL untuk diunduh dan satu berkas untuk dicache di disk
  • Daftar fitur yang didukung

    • Fitur yang didukung berbeda-beda antar model, dan sulit mendeteksi kemampuan aktual hanya dari berkas GGUF
    • Beberapa model mendukung input gambar dan sebagian tidak
      • Penanganan terbaik saat ini adalah menganggap dukungan gambar ada jika model proyeksi diberikan
    • Beberapa model mendukung pemanggilan alat native dan sebagian tidak
      • Penanganan terbaik saat ini adalah memeriksa dengan pencocokan substring apakah template chat memiliki bagian yang mencoba merender daftar schema JSON alat
      • Ini jelas hanya solusi sementara
    • Beberapa model mengeluarkan blok pemikiran dan sebagian tidak
      • Karena tag pemikiran biasanya tidak ada di metadata GGUF, tidak ada cara yang jelas untuk memastikan apakah model diharapkan mengeluarkan blok pemikiran
    • Jika komunitas GGUF menambahkan flag fitur ke berkas model, pustaka inferensi yang tidak bergantung pada model tertentu bisa memberikan pesan error dan peringatan yang lebih konsisten
      • Misalnya, bisa memberi panduan yang lebih tepat saat seseorang mencoba pemanggilan alat pada model yang tidak mendukung pemanggilan alat native

Kesimpulan

  • GGUF menyimpan informasi tambahan yang dibutuhkan untuk menjalankan model dengan benar dalam satu berkas, sehingga tidak perlu menambah banyak jalur kode spesifik model
  • GGUF adalah format yang terbuka dan dapat diperluas, serta memiliki komunitas yang kuat
  • Dengan memperkuat standar bersama, aplikasi bisa lebih mudah mengganti model sambil tetap mempertahankan pengalaman pengembang yang baik
  • Metadata GGUF sudah sangat berguna, tetapi masih ada ruang perbaikan seperti grammar pemanggilan alat, think_token, bundling model proyeksi, dan flag fitur

1 komentar

 
GN⁺ 3 jam lalu
Komentar Hacker News
  • Agak disayangkan model proyeksi dipisah menjadi file terpisah, dan saya juga lebih ingin itu masuk ke dalam satu file
    Saya tidak tahu persis kenapa jadi begitu, tetapi ini cukup menyimpang dari filosofi satu file yang ada dalam benak saat GGUF dirancang
    Saya berharap ada yang memimpin upaya menggabungkan keduanya, meski kali ini rasanya saya agak terlalu keluar dari arus utama :-)

    • Melihat dukungan MTP sedang dikembangkan sekarang, tampaknya dalam diskusi itu sempat ada ide untuk memisahkan model MTP dari GGUF utama seperti Mmproj, tetapi ditolak
      Saya suka keputusan itu. Jadi menurut saya tidak berlebihan untuk menganggap masih ada kemungkinan terbuka agar file Mmproj juga dimasukkan ke dalam GGUF
      Satu-satunya masalah yang terpikir adalah format apa yang akan dipakai. Ada pilihan seperti BF16, F16, dan lain-lain
  • GGML dan GGUF sangat penting bagi ekosistem open source machine learning/AI
    Proyek seperti llama.cpp, whisper.cpp, dan stable-diffusion.cpp umumnya langsung berjalan dengan baik di berbagai platform dan backend perangkat keras

    • llama.cpp memang berasal dari kubu Meta, dan saya benar-benar tidak suka Meta, tetapi saya akui dibanding yang lain ini yang paling mudah
      Tinggal kompilasi, masukkan model, lalu jalankan. Setelah itu Anda bahkan mendapatkan web UI dan API
  • > <|turn>user Hi there!<|turn>model Hi there, how can I help you today
    Ya ampun, mereka berhasil membuat format yang bahkan lebih sulit dibaca daripada XML

    • Ini bukan format yang dibuat untuk dibaca manusia. Kenyataannya, kita juga hampir tidak pernah perlu melihatnya langsung
      Format ini dirancang agar tidak tertukar dengan isi sebenarnya, dan isi itu bisa berupa teks acak apa pun dari internet
      Untuk itu, harus dipakai format yang tidak digunakan di tempat lain
    • Betul. Dari sisi efisiensi penggunaan memori, format ini tampaknya bukan yang optimal
  • Menurut saya, hal terbesar yang masih belum ada saat ini adalah cara mendefinisikan arsitektur model tanpa meng-hardcode-nya ke build saat ini
    Tidak harus memiliki kesetaraan performa 1:1 dengan model yang didukung penuh
    Apakah pada hari rilis sudah ada dukungan yang benar dan tervalidasi vendor atau tidak sangat menentukan apakah sebuah model terasa hebat atau justru terasa buruk. Rilis Gemma dan Qwen baru-baru ini adalah contohnya
    Saya tidak tahu solusinya, tetapi mungkin bisa dengan menulis DSL yang mendeskripsikan graph model lalu memasukkannya ke GGUF
    Alternatif lain adalah membaca modul PyTorch dari rilis model resmi lalu entah bagaimana mengonversinya menjadi operasi GGML

    • Dalam spesifikasi GGUF, sengaja disisakan ruang untuk memasukkan graph komputasi, dan saya berharap ada yang melanjutkannya
      Saya ingin memasukkannya ke versi pertama, tetapi saat itu prioritasnya adalah merilis spesifikasi minimum yang fungsional dan benar-benar diimplementasikan
      Saya masih ingin melihatnya, tetapi sekarang dibutuhkan pendorong yang sangat paham kondisi GGML IR saat ini
    • Sepertinya graph komputasi bisa di-embed di dalam file bobot seperti ONNX
      Lalu file itu mengekspos antarmuka umum yang menerima parameter umum, sementara parameter kustom tambahan bisa dijadikan ekstensi seperti Wayland
      Dengan begitu, bukan hanya keluarga transformer seperti LLaMa, tetapi juga keluarga recurrent neural network seperti RWKV, model multimodal, dan lainnya bisa didukung
      Saya tidak tahu implementasi nyatanya, tetapi terdengar seperti ide yang keren. Hanya saja, kalau graph komputasinya tertanam di file model, saya khawatir perbaikan arsitektur atau optimisasi yang tidak perlu mengubah bobot jadi tidak bisa diterapkan ke file lama tanpa konversi
  • > Hal yang sangat rapi dari GGUF adalah semuanya ada dalam satu file. Dibandingkan repositori safetensors biasa di Hugging Face, file JSON yang dibutuhkan tersebar di mana-mana [...]
    Menariknya, bagi saya model AI “selalu” berupa satu file. Itu karena di sisi pembuatan gambar lokal, itulah standarnya
    File safetensors juga bisa memuat bermacam-macam hal di dalamnya, jadi sebenarnya GGUF tidak mutlak diperlukan untuk ini
    Hanya saja, text encoder pada model modern sendiri sudah berupa language model berukuran beberapa gigabita, jadi tidak ada yang menaruh salinan duplikatnya di setiap checkpoint

    • Distribusi satu file memang merupakan tujuan desain yang saya tetapkan secara sengaja
      Kebanyakan model gambar dulu memang satu file, atau bahkan sekarang pun masih begitu, tetapi safetensors untuk LLM setidaknya saat itu tidak seperti itu, dan saya ingin memaksakannya di tingkat struktur
      Saya juga tidak ingin runner seperti llama.cpp harus membutuhkan pembaca JSON, sementara pendekatan ST akan menuntut itu
      Masalah yang lebih besar, kalau saya ingat benar, adalah saat itu ST tidak bisa mendukung format kuantisasi baru GGML, dan memiliki format file sendiri memungkinkan fleksibilitas yang sulit didapat lewat ST
    • Pernyataan bahwa “di pembuatan gambar lokal model AI selalu satu file” juga tidak masuk akal bahkan di ranah itu
      Untuk benar-benar menjalankan arsitektur dengan bobotnya, yang dipakai bukan hanya satu file bobot tunggal, tetapi juga berbagai encoder dan decoder lain
      Alat yang Anda pakai mungkin menyembunyikan itu, tetapi di bawah permukaan semuanya tetap ada
  • Soal llama_chat_apply_template yang agak aneh itu, yang terekspos di API libllama dan langsung meng-hardcode beberapa format chat ke dalam C++, sebagai orang yang sedang mengutak-atik aplikasi inferensi desktop berbasis FLTK[0], saya berharap ini memakai parser template Jinja2 yang benar-benar digunakan llama.cpp
    Atau setidaknya ada fungsi C lain yang melakukan hal itu. Untuk parsing yang benar, tampaknya kita perlu bisa mengirim berbagai data, misalnya agar template tahu apakah pemanggilan tool tersedia
    Saat ini saya memakai fungsi sementara ini, tetapi pada akhirnya sepertinya saya akan memakai interpreter Jinja2 secara langsung atau menyalin kode dari llama.cpp
    Meski begitu, pendekatan all-in-one GGUF memang sangat praktis. Saya setuju bahwa model proyeksi yang berupa file terpisah terasa janggal
    Saat pertama kali mengunduh model dengan dukungan vision, saya hanya mengambil GGUF yang tampak cocok, lalu llama.cpp tidak bisa memproses model itu, dan baru lama kemudian saya sadar ternyata perlu file tambahan
    Pikiran saya waktu itu benar-benar, “Bukannya GGUF itu format yang memuat semuanya?” :-P
    [0] https://i.imgur.com/GiTBE1j.png

  • Saya selalu memakai format safetensors + file metadata yang mirip dengan repositori Hugging Face
    Ini sama sekali bukan ketidaknyamanan besar, tetapi GGUF tampaknya bagus karena memiliki format yang lebih rapat dan dukungan yang baik

  • Dengan melihat hal-hal yang masih belum ada di GGUF, saya justru jadi lebih memahami GGUF
    Format pemanggilan tool terasa sangat alami, dan tampaknya bisa menjadi penanda transisi dari LLM ke agent

  • Baru-baru ini saya mengunduh 7B Mistral dari TheBloke untuk dicoba, dan saya punya 4070

    • Saya suka Mistral, tetapi model itu bukan yang terbaik
      Sebaiknya coba Gemma 4 e4b. Ukurannya mirip dengan Mistral 7B dan akan berjalan baik di 4070
      Nama “E4B” sendiri agak sedikit menyesatkan
    • 7B Mistral sudah cukup lama
      Di 4070 12GB, Anda bisa menjalankan Qwen 3.5 9B q4km atau Qwen 3.6 35B. Yang terakhir jauh lebih cerdas tetapi juga jauh lebih lambat karena offloading memori
      Coba keduanya di LM Studio; kemampuannya benar-benar mengesankan
    • Saya juga memastikan ini berjalan sangat cepat dan baik bahkan di 2070
      Saya suka TheBloke, jadi saya masih berharap dia membuat model lagi