Jika anda pernah melihat LLM menjana respons yang panjang dan tertanya-tanya mengapa ia seolah-olah merangkak selepas kilasan prom awal, anda sedang memerhatikan kesesakan perkakasan (hardware bottleneck) secara masa nyata. Kebanyakan pembangun menyalahkan kod Python mereka, rangka kerja (framework), atau saiz model yang terlalu besar. Mereka melakukan profil pada fungsi, menukar pengoptimum (optimizers), dan mengurangkan milisaat daripada prapemprosesan. Tiada satu pun daripada itu yang menyelesaikan masalah sebenar. Had kelajuan bukan pada perisian anda. Ia adalah pada silikon.
Setiap tugasan inferens model bahasa besar bergantung pada dua ciri fizikal GPU yang berada di pelayan anda: betapa cepat ia boleh memproses nombor, dan betapa cepat ia boleh menggerakkan nombor tersebut ke posisi untuk diproses.
Matematik Itu Murah. Menggerakkan Data Tidak
Pemasaran GPU gemar bercakap tentang pengkomputeran (compute). Trilion operasi titik apung (floating-point operations) sesaat. Angka-angkanya sangat menakjubkan. Tetapi pengkomputeran hanyalah separuh daripada ceritanya. Separuh lagi adalah lebar jalur memori (memory bandwidth), iaitu kadar data bergerak dari memori lebar jalur tinggi ke teras pengkomputeran di mana aritmetik sebenar berlaku.
Sebuah LLM tidak boleh berjalan lebih laju daripada pautan yang paling lemah antara keduanya. Bayangkan sebuah dapur komersial dengan dua puluh cef pakar. Ketuhar sudah panas, pisau sudah tajam, dan setiap tukang masak sudah bersedia. Tetapi penghantaran bahan mentah tiba dengan basikal, satu bakul pada satu masa. Dapur tersebut tergendala. Menambah lebih ramai cef tidak akan menyelesaikannya. Membeli ketuhar yang lebih laju juga tidak akan menyelesaikannya. Kesesakannya adalah pada jalan raya.
Dalam GPU pusat data moden, unit aritmetik sangat berkuasa sehingga ia sering menyelesaikan pengiraan dan kemudian duduk tanpa melakukan apa-apa (idle), membazir kitaran (cycles) sementara menunggu pemberat (weights) dan pengaktifan (activations) mengalir melalui memori. Ketidakseimbangan ini bukanlah pepijat (bug) dalam kod anda. Ia adalah realiti fizikal tentang bagaimana cip dibina. Lebar jalur memori tidak dapat menandingi kuasa pengkomputeran mentah, dan LLM sangat terkesan dengan ketidakseimbangan ini kerana proses forward pass mereka memerlukan setiap parameter disentuh bagi setiap token output.
Mengapa Prom Seolah-olah Laju dan Penjanaan Seolah-olah Perlahan
Inferens LLM terbahagi kepada dua fasa yang berbeza, dan ia memberi tekanan kepada perkakasan dengan cara yang sangat berbeza.
Prefill berlaku apabila prom anda mula-mula sampai ke model. Semua token tiba bersama-sama. GPU boleh memprosesnya secara selari menggunakan pendaraban matriks-matriks yang besar. Beribu-ribu unit aritmetik beroperasi serentak, dan beban kerja kekal padat. Fasa ini adalah terikat pengkomputeran (compute-bound). Lonjakan kelajuan tiba-tiba yang anda lihat pada permulaan? Itulah GPU melakukan tepat apa yang ia dibina untuk lakukan.
Decode adalah di mana keadaan menjadi sukar. Apabila model menjana token seterusnya, ia melakukannya satu demi satu token. Peringkat ini bergantung pada operasi matriks-vektor, yang hanya menggunakan sebahagian kecil daripada kapasiti selari GPU. Lebih teruk lagi, setiap token baharu memaksa GPU memuat semula keseluruhan pemberat model daripada memori. Unit aritmetik mahukan kerja. Sebaliknya, ia menunggu. Decode adalah terikat memori (memory-bound). GPU secara berkesan bertindak sebagai pengawal trafik yang mahal, menghantar parameter ke sana ke mari merentasi bas memori sementara enjin matematik berehat. Inilah sebabnya mengapa respons seratus patah perkataan boleh mengambil masa sepuluh saat walaupun analisis prom awal terasa sekelip mata.
KV cache menjadikan perkara ini lebih menarik. Semasa decode, model menyimpan tensor kunci (key) dan nilai (value) untuk setiap token sebelumnya supaya ia tidak perlu mengira semula perhatian (attention) dari awal. Cache tersebut berkembang mengikut panjang urutan (sequence length). Ia juga berada di dalam memori. Jadi sekarang GPU bukan sekadar memuat semula pemberat; ia membaca dan menulis cache yang sentiasa berkembang pada setiap forward pass. Teras pengkomputeran hampir tidak bekerja keras, manakala bas memori bekerja keras untuk kedua-duanya.
Menangani Dinding Memori (Memory Wall)
Jurutera telah membangunkan pelbagai teknik untuk mengurangkan jumlah data yang perlu digerakkan, atau sekurang-kurangnya untuk berkongsi kos penggerakannya.
Batching adalah yang paling mudah. Jika permintaan seorang pengguna memaksa pemuatan pemberat penuh daripada memori, maka memproses lapan atau enam belas permintaan sekaligus membolehkan GPU membahagikan beban tersebut kepada kesemuanya. Pemberat dibaca sekali dan digunakan semula untuk setiap urutan dalam batch tersebut. Dalam pengeluaran (production), sistem penjadualan yang canggih mengumpulkan permintaan secara dinamik, kadangkala dipanggil continuous atau in-flight batching, supaya GPU jarang berhenti. Ia adalah perbezaan antara sebuah bas dan enam belas kereta berasingan di laluan yang sama.
Kuantisasi menangani masalah jalur lebar secara langsung. Pemberat model biasanya disimpan dalam format titik apung enam belas-bit. Dengan memampatkannya kepada integer lapan-bit atau malah empat-bit, anda secara literal mengurangkan jumlah data yang bergerak merentasi bas sebanyak separuh atau lebih. Model tersebut masih memerlukan kejituan yang mencukupi untuk menghasilkan output yang koheren, tetapi kaedah kuantisasi pasca-latihan moden boleh mengecilkan jejak memori model secara drastik tanpa merosakkan kualiti. Kurang data yang sedang dihantar bermakna kurang masa yang dihabiskan menunggu di pengawal memori.
FlashAttention menyusun semula mekanisme perhatian untuk mengekalkan keputusan perantara di dalam memori dalam-cip GPU yang pantas. Perhatian standard perlu menulis matriks perhatian yang besar ke memori luaran yang perlahan dan kemudian membacanya semula. FlashAttention memecahkan pengiraan kepada jubin (tiles) lebih kecil yang muat dalam SRAM, melaksanakan langkah softmax dan penskalaan secara dalam-cip, dan hanya menulis output akhir kembali ke memori jalur lebar tinggi. Ia menukar sedikit pengiraan tambahan untuk mengurangkan kitaran balik ke memori utama, yang hampir sentiasa merupakan pertaruhan yang menguntungkan.
PagedAttention menyelesaikan jenis pembaziran memori yang berbeza. Semasa proses dekod, cache KV berkembang secara tidak menentu. Sistem tradisional memperuntukkan cebisan memori yang tetap dan bersambung untuk setiap urutan, meninggalkan ruang kosong yang besar apabila sesetengah urutan tamat lebih awal dan yang lain berkembang. PagedAttention meminjam konsep memori maya daripada sistem operasi. Ia menyimpan entri cache KV dalam blok bersaiz tetap yang boleh diperuntukkan secara tidak bersambung dan dipetakan melalui jadual tidak langsung. Ini menghalang memori daripada terbiar di dalam penimbal yang telah dikhaskan tetapi separa kosong, dan membolehkan saiz kelompok (batch size) yang lebih besar, yang seterusnya meningkatkan hasil (throughput) keseluruhan dengan memastikan bas memori sibuk dengan kerja yang berguna dan bukannya beban fragmentasi.
Ubah Persoalannya
Apabila kependaman melonjak, terlalu banyak pasukan bertanya sama ada mereka patut bertukar kepada model yang lebih kecil atau menulis semula pelayan inferens mereka. Persoalan tersebut penting, tetapi ia adalah sekunder. Persoalan pertama sepatutnya adalah mengenai perkakasan itu sendiri. Adakah GPU anda benar-benar sibuk melakukan pengiraan, atau adakah ia kekurangan data?
Lihat metrik penggunaan anda. Profilkan ketepuan jalur lebar memori bersama-sama dengan pengisian komputasi GPU. Jika anda melihat pertikaian memori yang tinggi dan keamatan aritmetik yang rendah semasa dekod, anda tidak mempunyai masalah seni bina model. Anda mempunyai masalah fizik. Penyelesaiannya tidak akan datang daripada kod Python yang lebih bersih. Ia akan datang daripada pemprosesan berkelompok (batching) yang lebih agresif, menguantisasi pemberat anda untuk melepasi saluran dengan lebih pantas, menyusun semula perhatian untuk kekal dalam-cip, dan mengurus cache KV supaya anda boleh memuatkan kelompok yang lebih besar tanpa kehabisan ruang.
Sebaik sahaja anda melihat inferens melalui lensa ini, pengoptimuman menjadi sesuatu yang mekanikal. Anda berhenti mengejar mitos tentang kecerdasan model yang melambatkan segalanya dan mula membuat keputusan kejuruteraan yang berasaskan apa yang sebenarnya boleh diberikan oleh perkakasan. Itulah anjakan yang membezakan sistem pengeluaran yang boleh diskalakan daripada sistem yang sekadar berfungsi.
