Eğitim

Salı akşamı bir transformer eğitmek

Beş yıl önce aldığınız dizüstünü alın. Bir sekme açın. Üzerinde bir transformer eğitin — ince ayar değil: eğitim; rastgele başlatılmış ağırlıklardan çoğunlukla doğru heceleyen metne, makinenin kendi GPU'sunda ve koşunun büyük bölümünde Wi-Fi kapalıyken. Karakter düzeyinde bir model, altı katman, yaklaşık 4,8 milyon parametre. Bütün akşamı birlikte yürüyelim, hatalar da dahil; çünkü bir platformun karakteri hatalarda belli olur.

Adım adım örnek

Bu bir laboratuvar raporu değil, bir anlatımdır. Scellis henüz kullanıcılara açılmadı (bugün neredeyiz); dolayısıyla bu akşamı henüz kimse yaşamadı — yazarı da dahil. Aşağıdaki hesaplar birebir doğrudur: parametre sayıları, bellek bütçeleri, çapraz entropinin başlangıç değeri. Platformun davranışı da motorun yapmak üzere kurulduğu ve doğrulandığı davranıştır. Süre rakamları ise tasarımdan çıkarılmış tahminlerdir ve öyle yazılmıştır — ölçülmüş sayılar, ölçülecek bir sürüm olduğunda yayımlanacak.

Daha önce bir eğitim ortamı kurduysanız — sürücü ruleti, bağımlılık sabitleme, “bende çalışıyor” — bu yürüyüşün özü şu: bunların hiçbiri olmuyor. Bir sekme açıyorsunuz; motor, GPU ile tarayıcının zaten içinde taşıdığı WebGPU üzerinden konuşuyor. Kurulum bu kadar.

Katmanları çizmek#

Tuvaldeki bir model düğümüne çift tıklayınca Model View açılıyor: aynı modelin üç eşzamanlı izdüşümünü gösteren tam ekran bir editör — çizdiğiniz bir Graph, doldurduğunuz bir Form ve aynı yapının bildirimsel, Python havalı bir dili olan SML'de bir Code görünümü. Birini değiştirdiğinizde diğer ikisi anında izliyor. Graph'ta çizin — token gömme, öğrenilmiş konumlar, altı pre-norm blok, bağlı bir çıkış başlığı — genişlikleri de Form'da ayarlayın. Code görünümü altta kendini durmadan yeniden yazıyor; akşam dokuzda bu, tuhaf biçimde iyi bir yol arkadaşı.

sml
# Yığının Code görünümü (kısaltılmış)
model CharTransformer(context=256, vocab=96):
  d = 256; heads = 8; layers = 6

  x = token_embed(vocab, d)(tokens) + learned_pos(context, d)
  repeat layers:
    x = x + attention(norm(x), heads=heads, causal=true, dropout=0.1)
    x = x + mlp(norm(x), hidden=4 * d, activation="gelu", dropout=0.1)
  logits = head(norm(x), tied=token_embed)

Oradaki context=256 hayatta kalanın sayısı — ilk taslak 512 diyor. Birazdan geleceğiz.

Daha siz bırakmadan kablo kırmızıya dönüyor#

İlk gerçek hata bir klasik; o hâlde onu bilerek yapalım. MLP'nin gizli genişliği olan 1024'ü çıkış projeksiyonuna da yazın — blok artık [B, T, 256] bekleyen bir artık toplamaya [B, T, 1024] teslim etmeye kalkıyor. Bir betikte bu, yirmi dakika sonra ilk çalıştırmada gelen bir hata dökümüdür. Burada, fareyi daha bırakmadan kablo kırmızıya dönüyor. Model View'da doğrulama canlı; tanı iki portu ve iki şekli adıyla gösteriyor, onarımı da tek tıklık bir çözüm olarak sunuyor: projeksiyonu d_model'e geri al. Tıklıyorsunuz — biraz alınmış, çoğunlukla minnettar.

Bütün yüzeyin sessiz tezi bu: Burada model, editörün anladığı yapılandırılmış bir belgedir; ancak çalışma zamanında patlayan bir metin dosyası değil. Şekil hataları yazım anında yakalanır, çünkü şekiller sözleşmenin parçasıdır — forward geçişin içindeki bir sürpriz değil.

Peçete hesabı: 4,8 milyon parametre#

Transformer parametre sayısı bir peçeteye sığar. Her blok, attention (Q, K, V ve çıkış projeksiyonu için 4d²) ile MLP (d→4d ve geri dönüş için 8d²) taşır: katman başına on iki d². d = 256 ile bu, katman başına 786.432 parametre eder; altı katman 4.718.592 yapar. Token gömme 96 × 256 ≈ 25 bin ekler — çıkış başlığıyla bağlı olduğundan bir kez sayılır —, öğrenilmiş konumlar 256 × 256 = 65.536 daha, normlar ve bias'lar da birkaç bin. Toplam: aşağı yukarı 4,8 milyon.

f32'de bu, yaklaşık 19 MB ağırlık demek. Sorun hiçbir zaman ağırlıklar olmayacaktı. Sorun aktivasyonlar.

Plan hayır diyor#

Bağlam 512, batch 64 isteyin; çünkü derleyene kadar hırs bedava. Burada bir şey çalışmadan önce motor koşuyu planlıyor ve belleğini kalem kalem çıkarıyor — parametreler, gradyanlar, optimizer durumu, aktivasyonlar, çalışma belleği — sığmıyorsa da düpedüz reddediyor. Plan kırmızı dönüyor. Döküm açık sözlü: aktivasyonlar eziyor ve içlerinde, bağlamın karesiyle büyüyen attention tamponları. Batch 64 ve bağlam 512'de yalnızca attention matrisleri katman başına 64 × 8 × 512 × 512 float ediyor — yarım gigabayt, çarpı altı katman; henüz backward için hiçbir şey saklanmadan. Tepe: 6 GB'ın üzeri. Böyle bir makinedeki bütçe: dört civarı.

Ret, kendi çarelerini de yanında getiriyor: bağlamı kısalt, batch'i küçült, duyarlığı değiştir. Üçünü de alın. Bağlam 256 — insanı öldüren o kare; yarıya indirmek tam da o tamponları dörtte bire düşürüyor. Batch 32. Ve karışık duyarlık: aktivasyonlar ile matmul'lar f16, ana ağırlıklar f32; f16 gradyanları yoksa sıfıra ezileceği için kayıp ölçeklemesini durumlu bir GradScaler yürütüyor. Yeniden plan: yeşil, tepe 2 GB'ın hemen altı. Hâlâ kırmızı kalsaydı yedekte aktivasyonları yeniden hesaplama vardı — saklamak yerine yeniden hesapla. Akılda kalması gereken şu: bellek hiçbir an bir gizem değil. Tek bir bayt kıpırdamadan önce her büyük tamponun nereden geleceğini biliyorsunuz.

Loss düşerken izlemek#

Eğitim yapılandırması da Model View'da, betiklere dağılmak yerine mimarinin hemen yanında duruyor: 3e-4 ile AdamW, WarmupCosineLR, CrossEntropy, 1.0'da gradyan kırpma, 0.1 dropout, tohum 1337, determinizm kademesi prod — bu cihazda, beyan edilmiş bir tolerans içinde yeniden üretilebilir; dürüst varsayılan bu. debug aynı koşuyu bit düzeyinde sabitlerdi — hız pahasına.

Bir karakter modelinin ilk tahmini, sözlük üzerinde tekdüze dağılımdır: 96 karakterle çapraz entropi ln 96 ≈ 4,56 nat'tan başlar. Oradan sonra eğri ısınma boyunca hızla düşer ve örneklenen metin, böyle bir şeyi bir kez eğitmiş herkesin tanıyacağı evrelerden geçer: önce doğru karakter sıklıklarına sahip gürültü, sonra kelimemsi şekiller, en sonda ise neredeyse her şeyi doğru yazıp neredeyse hiçbir şey anlatmayan cümle parçaları. Bir yerde fark ediyorsunuz: Wi-Fi akşam yemeğinden beri kapalı. Kimsenin umurunda olmamış. Model, veri, derleyici, koşu — hepsi yerel öncelikli: ağın bu yakasında.

Şimdi dürüst kısım. Batch 32 ve bağlam 256 ile 12.000 adım kabaca 98 milyon token eder — bu, aritmetik. Bunun beş yaşındaki bir GPU'da kaç dakika tuttuğu ise bir tahmindir ve adını da böyle koymak gerekir: bir akşam; bir kahve molası değil. Ölçülmüş süreleri, ölçülecek bir sürüm olduğunda yayımlayacağız; öncesinde değil. Bugün kesin olarak söylenebilecek olan, maliyetin biçimi: eğitim, eager autograd bandında koşuyor — gradyan doğru, ama füzyonlu değil (çekirdek füzyonu bugün çıkarımın forward yoluna hizmet ediyor). Kimse eski bir dizüstündeki sekmenin kiralık bir veri merkezi GPU'sunu geçtiğini iddia etmiyor. İddia başka: kurulacak ortam yok, yükleme yok, işleyen bir sayaç yok — ve zaten sahip olduğunuz makine, siz çay demlerken işin tamamını yapıyor. Koşu paneli, dizüstü epoch ortasında uyuyakalmasın diye bir wake lock bile öneriyor.

Checkpoint, commit, atıf#

Sondaki checkpoint bir ağırlık dosyası değil, bir demet: ağırlıklar, optimizer durumu, RNG durumu, epoch, adım, metrikler — tek birim olarak içerik adresli. Kaldığı yerden devam edebilmek bu yapının doğal sonucu: sekme 9.000. adımda ölürse koşu “kesildi” olarak uzlaştırılır ve son checkpoint'ten tek eylemle sürer; RNG durumu da içinde olduğundan karıştırma ile dropout tam kaldıkları yerden devam eder.

Sonra koşuyu commit ediyorsunuz. Commit edilmiş bir sürüm içerik adreslidir — hash; iş akışını, modeli, veri kümesi sürümünü, eğitim yapılandırmasını, checkpoint'i ve motor sürümünü kapsar — ve anlık görüntü bağlantısı tam o baytları yeniden çözer: herkes için, girişsiz. Yeniden üretilebilirlik iddiasını özenle kurmakta yarar var; çünkü bu platformun şişirmeyi reddettiği iddia tam da bu: atıf verilen baytlar sonsuza dek aynıdır; aynı eğitimi başka donanımda yeniden koşan biri sonucu prod kademesinin beyan edilmiş toleransları içinde üretir — bit düzeyinde değil. Heterojen GPU'larda kayan noktalar bit düzeyinde eşleşmez ve platform bunu yuvarlamak yerine açıkça söyler.

Akşam buydu. Bir şekil hatası, bir kırmızı plan, bir yeşil ve düşen bir kayıp eğrisinin sonunda, deneyin resmi değil kendisi olan bir URL. Aynı yolu adım adım ve bu hataların daha azıyla yürümek isterseniz kılavuzun tarayıcıda eğitim bölümü orada. Salı olması da şart değil.

  • training
  • transformer
  • webgpu
  • model-view
  • mixed-precision

← Tüm yazılar