· kaynak dev.to (home feed)
Temperature=0 LLM çağrıları neden hâlâ sapıyor: kayan nokta aritmetiği ve GPU batching
Bir dev.to yazısı, temperature=0 ve seed sabitlenmiş LLM çağrılarının CI'da neden hâlâ farklı yanıtlar döndürdüğünü açıklıyor: birleşmeli olmayan kayan nokta aritmetiği ve GPU batching, çalıştırmalar arasında logitleri kaydırıyor.

Bir dev.to yazısı, tanıdık bir tür flake'i ele alıyor: sabit bir prompt, sabitlenmiş bir model snapshot'ı, 0'a ayarlanmış temperature ve seed'li bir isteğe rağmen, LLM çıktı dizesini doğrulayan bir CI testi yaklaşık haftada bir kez başarısız oluyordu. Kod değişikliklerini eledikten sonra yazar, aynı isteği 500 kez çalıştırıp sonuçları karşılaştırdı. On iki yanıt farklıydı ve biri bir iade talebini 'fraud' yerine 'billing' olarak sınıflandırmıştı — bayt bayt aynı girdiden gelen gerçek bir davranışsal değişim.
Yazıya göre açıklama şu: temperature=0 baştan beri determinizm garantisi vermiyordu.
Greedy sampling deterministiktir; aritmetik değil
Temperature'ı 0'a ayarlamak sampler'ı argmax'a indirger: her zaman en yüksek puanlı token'ı al. Aynı logitler verildiğinde bu adım tamamen deterministiktir. Sorun, paylaşımlı bir inference sunucusundan asla aynı logitleri alamamanızdır.
Kayan nokta toplama işlemi birleşmeli değildir, dolayısıyla (a + b) + c ile a + (b + c) son bitlerinde farklılık gösterebilir. GPU'da reduction işlemleri — hidden boyutları boyunca toplama, softmax paydalayıcıları, normalizasyon katmanları — bloklara bölünür ve nasıl bölündüğü kernel'in aldığı tensor şekillerine bağlıdır. Farklı bir şekil, farklı bir reduction sırası, farklı bir yuvarlama ve hafifçe farklı logitler demektir.
Göremediğiniz batch
Devreye batch giriyor. Yazı, batch invariance kavramına değiniyor: tek bir isteğin, yanına hangi başka istekler batch'lenirse batch'lensin aynı çıktıyı üretmesi. Çoğu üretim inference kernel'i bu özelliğe sahip değil ve yazar bunu bir hata değil, performans kararı olarak çerçeveliyor. Saat 15:00'te 48'lik bir batch'e düşen istek, saat 04:00'te 3'lük bir batch'teki aynı istekten farklı bir tiling ve split-K stratejisi alır; böylece logitlerin son bit yuvarlaması farklılaşır.
Her bir çalıştırma, kendi batch'i verildiğinde deterministiktir — hiçbir şey rastgeleleştirilmez — ama batch'i ne kontrol edebilir ne de gözlemleyebilirsiniz. Yazı, gerçek endpoint'lerdeki diğer etkenleri de listeliyor: uzman atamasının rekabet eden token'lara bağlı olduğu kapasite limitli mixture-of-experts routing; hesaplama sınırını kaydıran prefix caching; doğrulama yolu sayısal olarak farklı olan speculative decoding; ve tek bir endpoint arkasındaki heterojen GPU filoları. Yazarın belirttiğine göre, büyük API'lerdeki seed parametresi, sampler'ın RNG'sini sabitlediği için değil aritmetiği sabitlediği için değil, best-effort olarak belgelenmiştir — seed yalnızca sampler'ın RNG'sini sabitler, aritmetiği değil.
Yakın beraberlikler küçük bir salınımı büyütür
Çoğu token konumu kıyası kolay değildir; en iyi iki aday arasındaki fark büyük olduğunda 1e-7'lik bir perturbasyon bunu tersine çeviremez. Ancak yakın beraberliklerde — 'however' ile 'but', belirsiz bir talepte 'fraud' ile 'billing' — fark sayısal gürültüden küçüktür ve argmax fiilen yazı-tura atar. Decoding otoregresif olduğundan, tersinen bir token, sonraki her token'ın girdisini değiştirir; böylece tek bitlik bir salınım bir paragrafın ikinci yarısını yeniden yazabilir. Yazıya göre flake'lerin tam da en zor, en belirsiz girdilerde kümelenmesinin nedeni de budur: yakın beraberlikler tam olarak orada yaşar.
Matematiği değil, testleri düzeltin
Hosted bir API'de bitwise tekrarlanabilirlik elden gelmez; bu yüzden yazı, doğrulamaları sağlamlaştırmayı öneriyor:
- Çıktıyı parse edin ve çevresindeki düzyazı yerine önemli olan alanlar üzerinde assert edin.
- Alias'ı değil tarihli model snapshot'ını sabitleyin, çünkü alias'lar sessizce değişir ve ayrı bir, sıklıkla yanlış teşhis edilen sapmaya yol açar.
- Çıktı uzayını daraltın: tek bir enum token'ı üreten bir sınıflandırıcı, etiketi bir paragrafa gömen bir sınıflandırıcıdan çok daha az yakın beraberlik konumuna sahiptir.
- Eval setini birden çok kez çalıştırarak flip oranını ölçün ve kararsız öğeleri pass/fail yerine düşük güvenli olarak değerlendirin.
- Önemli kararlar için K-of-N oylama kullanın; iade gibi bir konudaki anlaşmazlıkları tekrar denemek yerine bir insana yönlendirin.
- Yanıt parmak izini kaydedin ki 'backend değişti' ile 'yakın bir beraberliğe denk geldik' ayırt edilebilsin.
Yazara göre gerçek bitwise determinizm, yerelde çalıştırmayı gerektirir: batch size 1, sabit kütüphane ve sürücü sürümleri, deterministik kernel bayrakları ve tek bir GPU modeli — ve o durumda bile yalnızca o makineye karşı tekrarlanabilirdir. Batch-invariant kerneller serving stack'lerine ekleniyor ama throughput'a mal oluyorlar; dolayısıyla bir satıcı açıkça söylemedikçe bunlara sahip olmadığınızı varsayın.
Yazı ayrıca, bir ekibin devreye aldığını gördüğü cazip bir anti-pattern'e karşı da uyarıyor: model beklenen dizeyi üretene kadar yeniden çalıştıran bir retry döngüsü. Yazarın deyişiyle bu determinizm değil, fazladan adımlarla ve daha büyük bir faturayla rejection sampling'dir. Dürüst çerçeveleme şudur: bir LLM çağrısı saf bir fonksiyon değil, istatistiksel bir bağımlılıktır.
Neden önemli
Ekipler giderek LLM destekli davranışları CI'ya koyuyor ve içgüdü, bir model çağrısını aynı girdi için aynı çıktı döndüren sıradan bir fonksiyon gibi ele almak. Bu yazının gösterdiği gibi, bu varsayım — modelin 'yaratıcılığı' değil — kayan nokta aritmetiği ve GPU zamanlamasında köklenen nedenlerle başarısız oluyor ve başarısızlık, doğruluğun en çok önemli olduğu tam o belirsiz girdilerde haftalık flake'ler olarak ortaya çıkıyor. Gerçek nedeni anlamek, retry döngüleri veya temperature ayarları çevresindeki batıl inançlar gibi israflı çabaları önler ve kalıcı çözüme işaret eder: parse edilmiş yapı ve değişmezler üzerinde assert edin, determinizmi açıkça ölçün ve gerçekten belirsiz durumlar için insan yükseltme yolları kurun.
- #llm
- #machine-learning
- #ci-cd
- #testing
- #gpu