TensorBoard Debugger V2'yi Kullanarak TensorFlow Programlarındaki Sayısal Sorunlarda Hata Ayıklama

Bazen bir TensorFlow programı sırasında NaN'leri içeren yıkıcı olaylar meydana gelebilir ve model eğitim süreçlerini sekteye uğratabilir. Bu tür olayların temel nedeni, özellikle önemsiz olmayan boyut ve karmaşıklıktaki modeller için genellikle belirsizdir. Bu tür model hatalarının hatalarını ayıklamayı kolaylaştırmak için TensorBoard 2.3+ (TensorFlow 2.3+ ile birlikte), Debugger V2 adı verilen özel bir kontrol paneli sağlar. Burada, TensorFlow'da yazılmış bir sinir ağında NaN'leri içeren gerçek bir hata üzerinde çalışarak bu aracın nasıl kullanılacağını gösteriyoruz.

Bu öğreticide gösterilen teknikler, karmaşık programlarda çalışma zamanı tensör şekillerinin incelenmesi gibi diğer hata ayıklama etkinliklerine uygulanabilir. Bu eğitimde, nispeten yüksek görülme sıklıkları nedeniyle NaN'lere odaklanılmaktadır.

Hatayı gözlemlemek

Hata ayıklayacağımız TF2 programının kaynak kodu GitHub'da mevcuttur . Örnek program ayrıca tensorflow pip paketinde (sürüm 2.3+) paketlenmiştir ve şu şekilde çağrılabilir:

python -m tensorflow.python.debug.examples.v2.debug_mnist_v2

Bu TF2 programı çok katmanlı bir algı (MLP) oluşturur ve onu MNIST görüntülerini tanıyacak şekilde eğitir. Bu örnek, özel katman yapılarını, kayıp fonksiyonunu ve eğitim döngüsünü tanımlamak için kasıtlı olarak TF2'nin düşük seviyeli API'sini kullanır; çünkü bu daha esnek ancak hataya daha yatkın API'yi kullandığımızda NaN hatalarının olasılığı daha kolay olanı kullandığımıza göre daha yüksektir. tf.keras gibi kullanımı kolay ancak biraz daha az esnek üst düzey API'ler.

Program, her eğitim adımından sonra bir test doğruluğu yazdırır. Konsolda, ilk adımdan sonra test doğruluğunun neredeyse şans seviyesinde (~0,1) sıkıştığını görebiliriz. Model eğitiminin kesinlikle bu şekilde davranması beklenmiyor: adım arttıkça doğruluğun kademeli olarak 1,0'a (%100) yaklaşmasını bekliyoruz.

Accuracy at step 0: 0.216
Accuracy at step 1: 0.098
Accuracy at step 2: 0.098
Accuracy at step 3: 0.098
...

Bilgili bir tahmin, bu sorunun NaN veya sonsuzluk gibi sayısal bir istikrarsızlıktan kaynaklandığı yönündedir. Ancak durumun gerçekten böyle olduğunu nasıl doğrularız ve sayısal istikrarsızlığın oluşmasından sorumlu olan TensorFlow işlemini (op) nasıl buluruz? Bu soruları cevaplamak için buggy programını Debugger V2 ile donatalım.

Hata Ayıklayıcı V2 ile TensorFlow kodunu izleme

tf.debugging.experimental.enable_dump_debug_info() Debugger V2'nin API giriş noktasıdır. Tek bir kod satırıyla bir TF2 programını çalıştırır. Örneğin aşağıdaki satırı programın başına yakın bir yere eklemek, hata ayıklama bilgilerinin /tmp/tfdbg2_logdir adresindeki log dizinine (logdir) yazılmasına neden olacaktır. Hata ayıklama bilgileri TensorFlow çalışma zamanının çeşitli yönlerini kapsar. TF2'de istekli yürütmenin tam geçmişini, @tf.function tarafından gerçekleştirilen grafik oluşturmayı, grafiklerin yürütülmesini, yürütme olayları tarafından oluşturulan tensör değerlerini ve bu olayların kod konumunu (Python yığın izleri) içerir. . Hata ayıklama bilgilerinin zenginliği, kullanıcıların belirsiz hataları daraltmasına olanak tanır.

tf.debugging.experimental.enable_dump_debug_info(
    "/tmp/tfdbg2_logdir",
    tensor_debug_mode="FULL_HEALTH",
    circular_buffer_size=-1)

tensor_debug_mode bağımsız değişkeni, Hata Ayıklayıcı V2'nin her istekli veya grafik içi tensörden hangi bilgileri çıkardığını kontrol eder. "FULL_HEALTH", her kayan tip tensör hakkında aşağıdaki bilgileri yakalayan bir moddur (örneğin, yaygın olarak görülen float32 ve daha az yaygın olan bfloat16 dtype):

  • DTipi
  • Rütbe
  • Toplam öğe sayısı
  • Kayan tipteki elemanların şu kategorilere ayrılması: negatif sonlu ( - ), sıfır ( 0 ), pozitif sonlu ( + ), negatif sonsuz ( -∞ ), pozitif sonsuzluk ( +∞ ) ve NaN .

“FULL_HEALTH” modu, NaN ve sonsuzlukla ilgili hataların ayıklanması için uygundur. Desteklenen diğer tensor_debug_mode için aşağıya bakın.

circular_buffer_size argümanı logdir'e kaç tane tensör olayının kaydedildiğini kontrol eder. Varsayılan olarak 1000'dir; bu, yalnızca aletli TF2 programının bitiminden önceki son 1000 tensörün diske kaydedilmesine neden olur. Bu varsayılan davranış, hata ayıklama verilerinin bütünlüğünden ödün vererek hata ayıklayıcının yükünü azaltır. Bu durumda olduğu gibi tamlık tercih edilirse, argümanı negatif bir değere (örneğin, burada -1) ayarlayarak dairesel arabelleği devre dışı bırakabiliriz.

debug_mnist_v2 örneği, komut satırı işaretlerini kendisine ileterek enable_dump_debug_info() öğesini çağırır. Sorunlu TF2 programımızı bu hata ayıklama araçları etkinken yeniden çalıştırmak için şunları yapın:

python -m tensorflow.python.debug.examples.v2.debug_mnist_v2 \
    --dump_dir /tmp/tfdbg2_logdir --dump_tensor_debug_mode FULL_HEALTH

TensorBoard'da Hata Ayıklayıcı V2 GUI'sini Başlatma

Programı hata ayıklayıcı araçlarıyla çalıştırmak, /tmp/tfdbg2_logdir konumunda bir logdir oluşturur. TensorBoard'u başlatabilir ve logdir'e şu şekilde yönlendirebiliriz:

tensorboard --logdir /tmp/tfdbg2_logdir

Web tarayıcısında, http://localhost:6006 adresindeki TensorBoard sayfasına gidin. “Debugger V2” eklentisi varsayılan olarak etkin olmayacaktır, bu nedenle sağ üstteki “Etkin olmayan eklentiler” menüsünden seçin. Seçildikten sonra aşağıdaki gibi görünmelidir:

Hata ayıklayıcı V2 tam görünüm ekran görüntüsü

NaN'lerin temel nedenini bulmak için Hata Ayıklayıcı V2 GUI'yi kullanma

TensorBoard'daki Debugger V2 GUI altı bölüm halinde düzenlenmiştir:

  • Uyarılar : Bu sol üst bölüm, aletli TensorFlow programından gelen hata ayıklama verilerinde hata ayıklayıcı tarafından tespit edilen "uyarı" olaylarının bir listesini içerir. Her uyarı, dikkat edilmesi gereken belirli bir anormalliği belirtir. Bizim durumumuzda bu bölüm, belirgin pembe-kırmızı renkle 499 NaN/∞ olayını vurgulamaktadır. Bu, modelin dahili tensör değerlerinde NaN'lerin ve/veya sonsuzlukların varlığı nedeniyle öğrenmede başarısız olduğu yönündeki şüphemizi doğrulamaktadır. Bu uyarılara birazdan değineceğiz.
  • Python Yürütme Zaman Çizelgesi : Bu, üst orta bölümün üst yarısıdır. Operasyonların ve grafiklerin istekli bir şekilde yürütülmesinin tam geçmişini sunar. Zaman çizelgesinin her kutusu, op veya grafiğin adının ilk harfiyle işaretlenir (örneğin, "TensorSliceDataset" op için "T", "model" tf.function için "m"). Gezinme düğmelerini ve zaman çizelgesinin üzerindeki kaydırma çubuğunu kullanarak bu zaman çizelgesinde gezinebiliriz.
  • Grafik Yürütme : GUI'nin sağ üst köşesinde yer alan bu bölüm, hata ayıklama görevimizin merkezinde yer alacaktır. Grafiklerin içinde hesaplanan (yani @tf-function s tarafından derlenen) tüm kayan tip tensörlerin geçmişini içerir.
  • Grafik Yapısı (üst-orta bölümün alt yarısı), Kaynak Kodu (sol alt bölüm) ve Yığın İzleme (sağ alt bölüm) başlangıçta boştur. GUI ile etkileşime girdiğimizde içerikleri doldurulacaktır. Bu üç bölüm aynı zamanda hata ayıklama görevimizde de önemli roller oynayacaktır.

Kendimizi kullanıcı arayüzünün organizasyonuna yönlendirdikten sonra, NaN'lerin neden ortaya çıktığının temeline inmek için aşağıdaki adımları atalım. Öncelikle Uyarılar bölümündeki NaN/∞ uyarısına tıklayın. Bu, Grafik Yürütme bölümündeki 600 grafik tensörünün listesini otomatik olarak kaydırır ve bir Log (doğal logaritma) işlemi tarafından oluşturulan Log:0 adlı bir tensör olan #88'e odaklanır. Göze çarpan pembe-kırmızı renk, 2D float32 tensörünün 1000 öğesi arasında -∞ öğesini vurguluyor. Bu, TF2 programının çalışma zamanı geçmişinde herhangi bir NaN veya sonsuzluk içeren ilk tensördür: ondan önce hesaplanan tensörler NaN veya ∞ içermez; sonradan hesaplanan tensörlerin çoğu (aslında çoğu) NaN'ler içerir. Bunu Graph Execution listesini yukarı ve aşağı kaydırarak doğrulayabiliriz. Bu gözlem, Log op'un bu TF2 programındaki sayısal istikrarsızlığın kaynağı olduğuna dair güçlü bir ipucu sağlar.

Hata Ayıklayıcı V2: Nan / Infinity uyarıları ve grafik yürütme listesi

Bu Log işlemi neden bir -∞ ortaya çıkarıyor? Bu soruyu yanıtlamak operasyona yapılan girdilerin incelenmesini gerektirir. Tensörün adına tıklamak ( Log:0 ), Grafik Yapısı bölümündeki TensorFlow grafiğinde Log operasyonunun çevresinin basit ama bilgilendirici bir görselleştirmesini getirir. Bilgi akışının yukarıdan aşağıya doğru yönüne dikkat edin. Operasyonun kendisi ortada kalın harflerle gösterilmiştir. Hemen üstünde, Log op'a tek girişi sağlayan Yer Tutucu op'u görebiliriz. Bu probs Yer Tutucusu tarafından oluşturulan tensör, Grafik Yürütme listesinde nerede? Sarı arka plan rengini görsel yardım olarak kullanarak probs:0 tensörünün Log:0 tensörünün üç sıra üzerinde, yani 85. satırda olduğunu görebiliriz.

Hata Ayıklayıcı V2: Grafik yapısı görünümü ve giriş tensörünün izlenmesi

85. satırdaki probs:0 tensörünün sayısal dökümüne daha dikkatli bir bakış Log:0 tüketicisinin neden bir -∞ ürettiğini ortaya çıkarır: probs:0 1000 öğesi arasında bir öğenin değeri 0'dır. -∞, 0'ın doğal logaritmasının hesaplanmasının bir sonucu! Log operasyonunun yalnızca pozitif girdilere maruz kalmasını bir şekilde sağlayabilirsek, NaN/∞'un oluşmasını engelleyebileceğiz. Bu, Yer Tutucu probs tensörüne kırpma uygulanarak (örneğin tf.clip_by_value() kullanılarak) gerçekleştirilebilir.

Hatayı çözmeye yaklaşıyoruz ancak henüz tam olarak bitmiş değil. Düzeltmeyi uygulamak için Python kaynak kodunda Log op ve Yer Tutucu girişinin nereden kaynaklandığını bilmemiz gerekiyor. Hata Ayıklayıcı V2, grafik operasyonlarını ve yürütme olaylarını kaynaklarına kadar izlemek için birinci sınıf destek sağlar. Grafik Yürütmelerinde Log:0 tensörünü tıklattığımızda Yığın İzleme bölümü, Log işleminin oluşturulmasının orijinal yığın izlemesiyle dolduruldu. Yığın izlemesi biraz büyüktür çünkü TensorFlow'un dahili kodundan (örneğin, gen_math_ops.py ve dumping_callback.py) çoğu hata ayıklama görevi için güvenle göz ardı edebileceğimiz birçok kare içerir. İlgi çerçevesi debug_mnist_v2.py dosyasının 216. satırıdır (yani aslında hata ayıklamaya çalıştığımız Python dosyası). “Satır 216”ya tıklamak, Kaynak Kodu bölümünde karşılık gelen kod satırının bir görünümünü getirir.

Hata Ayıklayıcı V2: Kaynak kodu ve yığın izleme

Bu nihayet bizi probs girişinden sorunlu Log op'u yaratan kaynak koduna getiriyor. Bu, @tf.function ile süslenmiş ve dolayısıyla bir TensorFlow grafiğine dönüştürülmüş özel kategorik çapraz entropi kaybı fonksiyonumuzdur. Yer tutucu op probs kayıp fonksiyonuna ilişkin ilk giriş argümanına karşılık gelir. Log op, tf.math.log() API çağrısıyla oluşturulur.

Bu hatanın değer kırpıcı düzeltmesi şöyle görünecektir:

  diff = -(labels *
           tf.math.log(tf.clip_by_value(probs), 1e-6, 1.))

Bu TF2 programındaki sayısal istikrarsızlığı çözecek ve MLP'nin başarılı bir şekilde eğitilmesine neden olacaktır. Sayısal istikrarsızlığı düzeltmeye yönelik başka bir olası yaklaşım da tf.keras.losses.CategoricalCrossentropy kullanmaktır.

Bu, bir TF2 model hatasını gözlemlemekten, sayısal özetler de dahil olmak üzere enstrümanlı TF2 programının istekli ve grafik yürütme geçmişine tam görünürlük sağlayan Debugger V2 aracının yardımıyla hatayı düzelten bir kod değişikliği bulmaya kadar olan yolculuğumuzu tamamlıyor tensör değerleri ve ops, tensörler ve bunların orijinal kaynak kodları arasındaki ilişki.

Debugger V2'nin donanım uyumluluğu

Debugger V2, CPU ve GPU dahil genel eğitim donanımlarını destekler. tf.distributed.MirroredStrategy ile çoklu GPU eğitimi de desteklenmektedir. TPU desteği henüz başlangıç ​​aşamasındadır ve çağrı yapılmasını gerektirir

tf.config.set_soft_device_placement(True)

enable_dump_debug_info() işlevini çağırmadan önce. TPU'larda da başka sınırlamalar olabilir. Hata Ayıklayıcı V2'yi kullanırken sorunlarla karşılaşırsanız lütfen GitHub sorunlar sayfamızdaki hataları bildirin.

Hata Ayıklayıcı V2'nin API uyumluluğu

Hata ayıklayıcı V2, TensorFlow'un yazılım yığınının nispeten düşük bir seviyesinde uygulanır ve dolayısıyla tf.keras , tf.data ve TensorFlow'un daha düşük seviyelerinin üzerine inşa edilen diğer API'lerle uyumludur. Hata Ayıklayıcı V2, TF1 programları tarafından oluşturulan hata ayıklama günlük dizinleri için Eager Execution Timeline'ın boş olmasına rağmen, TF1 ile geriye dönük olarak uyumludur.

API kullanım ipuçları

Bu hata ayıklama API'si hakkında sık sorulan bir soru, TensorFlow kodunda enable_dump_debug_info() çağrısının nereye eklenmesi gerektiğidir. Genellikle API'nin TF2 programınızda mümkün olduğu kadar erken çağrılması gerekir; tercihen Python içe aktarma satırlarından sonra ve grafik oluşturma ve yürütme başlamadan önce. Bu, modelinize ve eğitimine güç veren tüm operasyonların ve grafiklerin tam olarak kapsanmasını sağlayacaktır.

Şu anda desteklenen tensor_debug_modes şunlardır: NO_TENSOR , CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTH ve SHAPE . Her tensörden çıkarılan bilgi miktarına ve hata ayıklanan programın performans yüküne göre değişirler. Lütfen enable_dump_debug_info() belgelerinin argümanlar bölümüne bakın.

Performans ek yükü

Hata ayıklama API'si, aletli TensorFlow programına performans ek yükü getirir. Ek yük, tensor_debug_mode , donanım türüne ve aletli TensorFlow programının niteliğine göre değişir. Referans noktası olarak, bir GPU'da NO_TENSOR modu, toplu iş boyutu 64'ün altındaki bir Transformer modelinin eğitimi sırasında %15'lik bir ek yük ekler. Diğer tensor_debug_modes için ek yük yüzdesi daha yüksektir: CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTH ve SHAPE için yaklaşık %50 modlar. CPU'larda ek yük biraz daha düşüktür. TPU'larda ek yük şu anda daha yüksek.

Diğer TensorFlow hata ayıklama API'leriyle ilişkisi

TensorFlow'un hata ayıklama için başka araçlar ve API'ler sunduğunu unutmayın. Bu tür API'lere, API belgeleri sayfasındaki tf.debugging.* ad alanı altında göz atabilirsiniz. Bu API'ler arasında en sık kullanılanı tf.print() tır. Ne zaman Debugger V2 kullanılmalı ve bunun yerine ne zaman tf.print() kullanılmalı? tf.print() aşağıdaki durumlarda uygundur

  1. tam olarak hangi tensörlerin yazdırılacağını biliyoruz,
  2. Bu tf.print() ifadelerini kaynak kodunda tam olarak nereye ekleyeceğimizi biliyoruz,
  3. bu tür tensörlerin sayısı çok fazla değil.

Diğer durumlarda (örneğin, birçok tensör değerinin incelenmesi, TensorFlow'un dahili kodu tarafından oluşturulan tensör değerlerinin incelenmesi ve yukarıda gösterdiğimiz gibi sayısal istikrarsızlığın kökeninin aranması), Hata Ayıklayıcı V2, hata ayıklamanın daha hızlı bir yolunu sağlar. Ayrıca Debugger V2 istekli ve grafik tensörlerin incelenmesine yönelik birleşik bir yaklaşım sağlar. Ayrıca tf.print() yeteneğinin ötesinde olan grafik yapısı ve kod konumları hakkında bilgi sağlar.

∞ ve NaN ile ilgili sorunları ayıklamak için kullanılabilecek başka bir API ise tf.debugging.enable_check_numerics() dir. enable_dump_debug_info() farklı olarak, enable_check_numerics() hata ayıklama bilgilerini diske kaydetmez. Bunun yerine, TensorFlow çalışma zamanı sırasında yalnızca ∞ ve NaN'yi izler ve herhangi bir operasyon bu kadar kötü sayısal değerler ürettiğinde kaynak kodu konumuyla ilgili hatalar verir. enable_dump_debug_info() ile karşılaştırıldığında daha düşük bir performans yüküne sahiptir, ancak programın yürütme geçmişinin tam izini sağlayamaz ve Debugger V2 gibi bir grafik kullanıcı arayüzü ile birlikte gelmez.