Lensa ML

Mixed Precision Training

Langkah 1 dari 6: Memori per Parameter

16 byte untuk setiap weight dengan Adam

Training dengan
Token per GPU per langkah2,048
Memori training model chat 7B dengan Adamweight fp162 B · 13.5 GBgradient fp162 B · 13.5 GBmaster weight fp324 B · 27.0 GBAdam m (fp32)4 B · 27.0 GBAdam v (fp32)4 B · 27.0 GBaktivasi, 2048 token9.1 GBSemua di satu GPU (garis putus-putus: 80 GB)0501001502006.74B parameter × 16 byte = 107.8 GB model statesaktivasi: sekitar 34 × d_model byte per token per layer
Byte per parameter
16
Model states
107.8 GB
Aktivasi
9.1 GB
Total
117.0 GB

Mixed precision tetap butuh 16 byte per parameter, karena salinan master fp32 dan kedua moment Adam tetap di fp32. Penghematannya ada di aktivasi: 9,1 GB di sini, dibanding 18,3 GB di fp32. Model states saja, 107,8 GB, sudah melebihi kapasitas satu GPU 80 GB.

Ganti antara fp32 dan mixed precision, lalu geser Token per GPU per langkah ke 8.192. Paper ZeRO menyebut 16 byte itu "model states" dan menuliskannya sebagai 2 + 2 + K byte per parameter, dengan K = 12 untuk Adam mixed precision. Estimasi aktivasi berasal dari Korthikanti et al. dan mengasumsikan skor attention tidak disimpan, seperti pada FlashAttention. Run sungguhan juga butuh buffer kerja dan kehilangan sebagian memori akibat fragmentasi. Activation checkpointing memangkas suku aktivasi dengan menghitung ulang sebagian forward pass saat backward.

Langkah 2 dari 6: Rentang Sempit fp16

Gradient kecil terbulatkan jadi nol

Ukuran gradient tipikal (pusat sebaran)1.0e-6
400 besaran gradient ilustratif di sumbu logdibulatkan ke 0subnormalfp16 normalinf1e-121e-101e-81e-61e-41e-211e21e41e61e8fp16: subnormal terkecil 6.0e-8, normal terkecil 6.1e-5, maks 65504
Terbulatkan ke 0
4.3%
Subnormal
91%
fp16 normal
4.8%
Gradient terbesar
1.6e-3

Sedikit nilai yang langsung hilang (4,3%), tetapi 91% masuk rentang subnormal di bawah 6,1e-5. Di sana fp16 menyimpan kurang dari 10 bit signifikan, dan nilai terkecil hanya menyimpan 1 atau 2 bit.

Geser Ukuran gradient tipikal dari 1e-9 ke 0,1 dan lihat warna batang berubah saat melewati tiap batas fp16. fp16 punya 5 bit eksponen dengan bias 15, jadi nilai normal berkisar dari 2^−14 sampai 65.504, dan nilai subnormal memanjang sampai 2^−24 dengan mengorbankan bit mantisa. Gradient aktivasi mengecil saat backpropagation mengalikannya melewati banyak layer, jadi bagian dalam network menerima nilai terkecil. 400 gradient di sini adalah sampel dengan seed, bukan hasil ukur dari model sungguhan.

Langkah 3 dari 6: Loss Scaling

Geser gradient ke dalam rentang, lalu kembalikan

Loss scale S2^0 = 1
Gradient ilustratif × S, tersimpan di fp16dibulatkan ke 0subnormalfp16 normalinf1e-121e-101e-81e-61e-41e-211e21e41e61e8backward pada S × loss, lalu bagi gradient dengan S di fp32Dynamic loss scaling, run ilustratif: log2 S per langkah1620241214160× = ada inf, langkah dilewati, S dipangkas separuh
Terbulatkan ke 0
7.2%
Overflow ke inf
0%
Run: S di langkah 1
2^16
Run: langkah dilewati
0

Pada S = 2^0, 7,2% gradient masih terbulatkan ke 0. Setiap penggandaan S menggeser seluruh histogram ke kanan sebesar faktor 2 tanpa mengubah bentuknya. Di run ini, langkah 1 pada 2^16 bersih; S berlipat dua setelah 5 langkah bersih berturut-turut.

Geser Loss scale S dari 2^0 ke 2^24, lalu tekan Putar untuk menjalankan scaler dinamis. Backpropagation linear terhadap loss, jadi mengalikan loss dengan S berarti mengalikan setiap gradient dengan S. Gradient dibagi S sebelum gradient clipping dan langkah optimizer, sehingga arti learning rate tidak berubah. GradScaler di PyTorch mulai dari 2^16, turun separuh saat ada inf atau NaN, dan berlipat dua setelah 2.000 langkah bersih. Run di sini menggandakan S setelah 5 langkah supaya grafiknya pendek, dan lonjakannya hanya rekaan.

Langkah 4 dari 6: Master Weight fp32

Update kecil hilang di fp16

Ukuran update (learning rate × gradient)1.00e-6
Weight w
Satu update ke w di fp16 (garis: tiap nilai fp16, berjarak 9,77e-4)ww + update (eksak)tersimpan di fp16Total perubahan setelah 1.000 update identikeksak1.00e-3master fp329.54e-4hanya weight fp160
Jarak fp16 di w
9.77e-4
Update ÷ jarak
1.0e-3
Total perubahan fp16
0
Perubahan master fp32
9.54e-4

Update ini 1,0e-3 dari jarak fp16 di w = 1, di bawah setengah langkah, jadi w + update dibulatkan kembali ke w. Semua 1.000 update hilang di fp16; salinan master fp32 menyimpan 9,54e-4 dari 1,00e-3.

Geser Ukuran update turun ke 1e-7 dengan w = 1, lalu coba w = 10. Di fp16, jarak antarnilai yang bersebelahan adalah 2^−10 kali pangkat dua dari weight, jadi update di bawah separuh jarak itu hilang saat pembulatan. Learning rate 1e-4 dikali gradient 1e-3 menghasilkan 1e-7, jauh di bawah batas 4,9e-4 di nilai 1,0. Salinan master fp32 punya 13 bit mantisa lebih banyak. m dan v milik Adam tetap di fp32 karena alasan yang sama: v menyimpan kuadrat gradient, yang paling dulu underflow di format 16-bit.

Langkah 5 dari 6: bf16

Rentang fp32 dengan bit mantisa lebih sedikit

Ukuran gradient tipikal (pusat sebaran)1.0e-8
Rentang: subnormal terkecil sampai nilai berhingga terbesargradientfp32bf16fp161e-401e-301e-201e-1011e101e201e301e40Presisi: setiap nilai tersimpan antara 1 dan 1,0625fp16bf16jarak di 1: fp16 2^-10 = 9.77e-4, bf16 2^-7 = 7.81e-3
fp16 terbulatkan ke 0
68%
bf16 terbulatkan ke 0
0%
Rerata error rel. fp16
74%
Rerata error rel. bf16
0.14%

Berpusat di 1,0e-8, fp16 kehilangan 68% gradient menjadi 0, sedangkan bf16 kehilangan 0%, karena bf16 memakai 8 bit eksponen yang sama dengan fp32. Tanpa loss scaling, rerata error fp16 di sini 74%, dibanding 0,14% pada bf16.

Geser Ukuran gradient tipikal dari 1e-12 ke 0,01 dan bandingkan keempat kartu. bf16 adalah 16 bit teratas dari angka fp32: 1 bit tanda, 8 bit eksponen, dan 7 bit mantisa. Google Brain merancangnya untuk TPU, dan NVIDIA menambahkannya di A100. Konversi dari fp32 hanya membuang bit mantisa bawah, jadi overflow dan underflow berperilaku seperti di fp32 dan loss scale tidak diperlukan. Training bf16 tetap menyimpan master weight fp32, karena jaraknya di 1,0 adalah 2^−7, delapan kali lebih kasar daripada fp16.

Langkah 6 dari 6: Kenapa Lebih Cepat

Tensor core, memori, dan fp8

Token per GPU per langkah4,096
Satu langkah training model chat 7B di GPU ilustratifWaktu: 6 × parameter × token ÷ (puncak × 40%)fp32 (tanpa tensor core)21 stensor core TF322.7 sbf16 mixed precision1.3 sMemori: 16 B/parameter untuk state + aktivasi (0 sampai 200 GB)fp32144 GBtf32144 GBbf16 mixed126 GB80 GB
Langkah fp32
21 s
Langkah bf16
1.3 s
Percepatan dibanding fp32
16×
Memori bf16
126.1 GB

Pada 4.096 token, langkah bf16 turun dari 21 s ke 1,3 s, peningkatan 16× pada utilisasi yang sama, dan aktivasi menyusut dari 36,5 GB ke 18,3 GB. GPU baru menambahkan tensor core fp8 dengan laju sekitar dua kali bf16.

Geser Token per GPU per langkah dan bandingkan ketiga batang waktu. Hitungan FLOP memakai patokan 6 FLOP per parameter per token: 2 untuk forward pass dan 4 untuk backward pass. Puncaknya adalah angka datasheet A100, 19,5 TFLOPS untuk fp32, 156 untuk TF32, dan 312 untuk bf16, dan run sungguhan hanya mencapai sebagian darinya. Autocast menjaga softmax, normalisasi, dan reduksi loss tetap di fp32. Training fp8 memakai E4M3 untuk weight dan aktivasi, serta E5M2 untuk gradient, dengan scale factor per tensor.

Apa itu mixed precision training?

Mixed precision training menjalankan sebagian besar hitungan neural network dalam format float 16-bit, fp16 atau bf16, sambil menyimpan beberapa nilai yang sensitif dalam fp32 yang 32-bit. Forward pass dan backward pass memakai weight dan aktivasi 16-bit, lalu optimizer memperbarui salinan master weight dalam fp32. Pada fp16, loss scale menjaga gradient kecil agar tidak terbulatkan menjadi nol.

Hampir semua model besar sekarang dilatih dengan cara ini. Perkalian matriks 16-bit berjalan di tensor core GPU dengan laju berkali-kali lipat fp32, dan aktivasi 16-bit memangkas separuh memori yang harus disimpan backward pass. Framework menyediakannya sebagai satu sakelar: autocast dan GradScaler di PyTorch, atau pengaturan bf16 di DeepSpeed dan Megatron-LM. Ide yang sama berlaku untuk training fp8 di GPU terbaru.

Ide utama

  • Mixed precision menjalankan hitungan matriks di fp16 atau bf16, sedangkan master weight dan state optimizer tetap di fp32.
  • Training dengan Adam butuh sekitar 16 byte per parameter dalam mixed precision, sama dengan fp32 biasa; penghematan memorinya datang dari aktivasi.
  • Rentang normal fp16 berakhir di 2^−14 pada sisi bawah dan 65.504 pada sisi atas, jadi gradient kecil terbulatkan ke nol kalau tidak dibantu.
  • Loss scaling mengalikan loss dengan pangkat dari 2 sebelum backward dan membagi gradient dengan angka itu sesudahnya.
  • Update yang lebih kecil dari separuh jarak fp16 hilang, karena itu optimizer memperbarui salinan weight dalam fp32.
  • bf16 mempertahankan rentang eksponen fp32 dengan bit mantisa lebih sedikit, jadi bisa dilatih tanpa loss scaling.

Ulasan singkat tentang topik ini

Pertanyaan umum

Sebaiknya training dengan fp16 atau bf16?

Pakai bf16 jika perangkat kerasnya mendukung, termasuk GPU NVIDIA sejak A100 dan TPU Google. Format ini tidak butuh loss scaling dan jarang overflow, jadi run lebih sederhana dan stabil. fp16 tetap jadi pilihan di GPU lama seperti V100 dan T4, yang tidak punya tensor core bf16.

Apakah bf16 lebih cepat daripada fp16?

Di GPU yang mendukung keduanya, seperti A100 dan H100, bf16 dan fp16 berjalan pada laju tensor core yang sama dan sama-sama memakai 2 byte per nilai, jadi perkalian matriks sama cepatnya. Run bf16 bisa sedikit lebih cepat secara keseluruhan karena melewati loss scaling dan tidak pernah kehilangan langkah akibat gradient yang overflow. Di GPU lama tanpa tensor core bf16, seperti V100 dan T4, bf16 jauh lebih lambat daripada fp16 atau sama sekali tidak didukung.

Untuk inference, pakai bf16 atau fp16?

Pakai format yang dipakai saat model dilatih, yang untuk sebagian besar LLM terbaru adalah bf16. fp16 punya 10 bit mantisa, sedangkan bf16 punya 7, jadi lebih presisi. Namun nilai terbesarnya 65.504, dan sebagian model yang dilatih dengan bf16 menghasilkan aktivasi di atas angka itu, lalu mengembalikan inf atau NaN saat dijalankan di fp16. Jika perangkat keras tidak mendukung bf16, fp16 biasanya bisa dipakai untuk model yang dilatih dengan format itu, dan quantization int8 atau 4-bit menghemat memori lebih banyak daripada keduanya.

Apakah mixed precision menurunkan akurasi model?

Dengan loss scaling dan master weight fp32, Micikevicius et al. menyamai akurasi fp32 pada model gambar, suara, terjemahan, dan bahasa. Sebagian besar model besar sesudahnya dilatih dengan mixed precision tanpa laporan penurunan. Masalah biasanya muncul sebagai lonjakan loss atau NaN, yang menandakan overflow atau operasi yang seharusnya tetap di fp32.

Apa penyebab loss NaN saat training fp16?

Aktivasi atau gradient di atas 65.504 menjadi inf, dan inf berubah menjadi NaN lewat operasi seperti inf − inf atau 0 × inf. Dynamic loss scaling menangkap overflow di gradient, tetapi tidak di forward pass. Perbaikan yang umum: menjaga softmax dan normalisasi tetap di fp32, menurunkan learning rate, atau beralih ke bf16.

Apa itu TF32?

TF32 adalah mode tensor core di GPU A100 dan yang lebih baru. Mode ini membaca input fp32, membulatkannya ke 10 bit mantisa dengan 8 bit eksponen fp32, lalu mengakumulasi dalam fp32. Kode tetap melihat tensor fp32 biasa, jadi training fp32 menjadi lebih cepat tanpa perubahan lain. Mode ini lebih lambat daripada bf16, karena setiap nilai tetap memakai 4 byte di memori dan laju puncaknya separuh.

Penjelasan terkait

Referensi

  1. Micikevicius et al. (2017), "Mixed Precision Training"
  2. Rajbhandari et al. (2019), "ZeRO: Memory Optimizations Toward Training Trillion Parameter Models"
  3. Kalamkar et al. (2019), "A Study of BFLOAT16 for Deep Learning Training"
  4. Korthikanti et al. (2022), "Reducing Activation Recomputation in Large Transformer Models"
  5. Micikevicius et al. (2022), "FP8 Formats for Deep Learning"

Terakhir diperbarui