Peristiwa bencana yang melibatkan NaN terkadang dapat terjadi selama program TensorFlow, melumpuhkan proses pelatihan model. Akar penyebab peristiwa semacam itu seringkali tidak jelas, terutama untuk model dengan ukuran dan kompleksitas yang tidak sepele. Untuk mempermudah men-debug jenis bug model ini, TensorBoard 2.3+ (bersama dengan TensorFlow 2.3+) menyediakan dasbor khusus yang disebut Debugger V2. Di sini kami mendemonstrasikan cara menggunakan alat ini dengan bekerja melalui bug nyata yang melibatkan NaN dalam jaringan saraf yang ditulis dalam TensorFlow.
Teknik yang diilustrasikan dalam tutorial ini berlaku untuk jenis aktivitas debug lainnya seperti memeriksa bentuk tensor runtime dalam program yang kompleks. Tutorial ini berfokus pada NaN karena frekuensi kemunculannya yang relatif tinggi.
Mengamati bug
Kode sumber program TF2 yang akan kami debug tersedia di GitHub . Contoh program juga dikemas ke dalam paket pip tensorflow (versi 2.3+) dan dapat dipanggil oleh:
python -m tensorflow.python.debug.examples.v2.debug_mnist_v2
Program TF2 ini menciptakan persepsi multi-layer (MLP) dan melatihnya untuk mengenali gambar MNIST . Contoh ini dengan sengaja menggunakan API tingkat rendah dari TF2 untuk mendefinisikan konstruksi lapisan kustom, fungsi kerugian, dan loop pelatihan, karena kemungkinan bug NaN lebih tinggi saat kami menggunakan API yang lebih fleksibel tetapi lebih rawan kesalahan ini daripada saat kami menggunakan yang lebih mudah -untuk digunakan tetapi API tingkat tinggi yang sedikit kurang fleksibel seperti tf.keras .
Program mencetak akurasi tes setelah setiap langkah pelatihan. Kita dapat melihat di konsol bahwa akurasi pengujian macet pada tingkat yang hampir mendekati (~0,1) setelah langkah pertama. Ini tentu bukan bagaimana model pelatihan diharapkan berperilaku: kami mengharapkan akurasi secara bertahap mendekati 1,0 (100%) seiring dengan peningkatan langkah.
Accuracy at step 0: 0.216
Accuracy at step 1: 0.098
Accuracy at step 2: 0.098
Accuracy at step 3: 0.098
...
Dugaan terdidik adalah bahwa masalah ini disebabkan oleh ketidakstabilan numerik, seperti NaN atau tak terhingga. Namun, bagaimana kami mengonfirmasi bahwa hal ini benar-benar terjadi dan bagaimana kami menemukan operasi TensorFlow (op) yang bertanggung jawab untuk menghasilkan ketidakstabilan numerik? Untuk menjawab pertanyaan ini, mari lengkapi program buggy dengan Debugger V2.
Menginstrumentasikan kode TensorFlow dengan Debugger V2
tf.debugging.experimental.enable_dump_debug_info() adalah titik masuk API Debugger V2. Ini instrumen program TF2 dengan satu baris kode. Misalnya, menambahkan baris berikut di dekat awal program akan menyebabkan informasi debug ditulis ke direktori log (logdir) di /tmp/tfdbg2_logdir. Informasi debug mencakup berbagai aspek runtime TensorFlow. Di TF2, ini mencakup riwayat lengkap eksekusi bersemangat, pembuatan grafik yang dilakukan oleh @tf.function , eksekusi grafik, nilai tensor yang dihasilkan oleh peristiwa eksekusi, serta lokasi kode (pelacakan tumpukan Python) dari peristiwa tersebut . Kekayaan informasi debug memungkinkan pengguna untuk mempersempit bug yang tidak jelas.
tf.debugging.experimental.enable_dump_debug_info(
"/tmp/tfdbg2_logdir",
tensor_debug_mode="FULL_HEALTH",
circular_buffer_size=-1)
Argumen tensor_debug_mode mengontrol informasi apa yang diekstrak Debugger V2 dari setiap tensor yang bersemangat atau dalam grafik. “FULL_HEALTH” adalah mode yang menangkap informasi berikut tentang setiap tensor tipe-mengambang (mis., float32 yang umum dilihat dan bfloat16 dtype yang kurang umum):
- Tipe D
- Pangkat
- Jumlah total elemen
- Perincian elemen tipe-mengambang ke dalam kategori berikut: hingga negatif (
-), nol (0), hingga positif (+), tak terhingga negatif (-∞), tak hingga positif (+∞), danNaN.
Mode “FULL_HEALTH” cocok untuk men-debug bug yang melibatkan NaN dan infinity. Lihat di bawah untuk tensor_debug_mode lain yang didukung.
Argumen circular_buffer_size mengontrol berapa banyak peristiwa tensor yang disimpan ke logdir. Standarnya adalah 1000, yang menyebabkan hanya 1000 tensor terakhir sebelum akhir program TF2 yang diinstrumentasikan untuk disimpan ke disk. Perilaku default ini mengurangi overhead debugger dengan mengorbankan kelengkapan data debug. Jika kelengkapan lebih disukai, seperti dalam kasus ini, kita dapat menonaktifkan buffer melingkar dengan menyetel argumen ke nilai negatif (misalnya, -1 di sini).
Contoh debug_mnist_v2 memanggil enable_dump_debug_info() dengan meneruskan flag baris perintah ke sana. Untuk menjalankan kembali program TF2 bermasalah kami dengan instrumentasi debugging ini diaktifkan, lakukan:
python -m tensorflow.python.debug.examples.v2.debug_mnist_v2 \
--dump_dir /tmp/tfdbg2_logdir --dump_tensor_debug_mode FULL_HEALTH
Memulai Debugger V2 GUI di TensorBoard
Menjalankan program dengan instrumentasi debugger membuat logdir di /tmp/tfdbg2_logdir. Kita dapat memulai TensorBoard dan mengarahkannya ke logdir dengan:
tensorboard --logdir /tmp/tfdbg2_logdir
Di browser web, navigasikan ke halaman TensorBoard di http://localhost:6006. Plugin "Debugger V2" tidak akan aktif secara default, jadi pilih dari menu "Plugin tidak aktif" di kanan atas. Setelah dipilih, itu akan terlihat seperti berikut:

Menggunakan Debugger V2 GUI untuk menemukan akar penyebab NaNs
GUI Debugger V2 di TensorBoard diatur menjadi enam bagian:
- Peringatan : Bagian kiri atas ini berisi daftar peristiwa "peringatan" yang terdeteksi oleh debugger dalam data debug dari program TensorFlow yang diinstrumentasi. Setiap peringatan menunjukkan anomali tertentu yang memerlukan perhatian. Dalam kasus kami, bagian ini menyoroti 499 peristiwa NaN/∞ dengan warna merah muda-merah yang menonjol. Ini menegaskan kecurigaan kami bahwa model gagal belajar karena adanya NaN dan/atau tak terhingga dalam nilai tensor internalnya. Kami akan mempelajari lansiran ini segera.
- Garis Waktu Eksekusi Python : Ini adalah bagian atas dari bagian tengah atas. Ini menyajikan sejarah lengkap dari eksekusi ops dan grafik yang bersemangat. Setiap kotak garis waktu ditandai dengan huruf awal dari op atau nama grafik (misalnya, "T" untuk operasi "TensorSliceDataset", "m" untuk "model"
tf.function). Kita dapat menavigasi timeline ini dengan menggunakan tombol navigasi dan scrollbar di atas timeline. - Eksekusi Grafik : Terletak di sudut kanan atas GUI, bagian ini akan menjadi pusat tugas debugging kami. Ini berisi riwayat semua tensor tipe-mengambang yang dihitung di dalam grafik (yaitu, dikompilasi oleh
@tf-functions). - Struktur Grafik (setengah bawah bagian tengah-atas), Kode Sumber (bagian kiri bawah), dan Stack Trace (bagian kanan bawah) awalnya kosong. Isinya akan terisi saat kita berinteraksi dengan GUI. Ketiga bagian ini juga akan memainkan peran penting dalam tugas debugging kami.
Setelah mengorientasikan diri kita pada organisasi UI, mari kita ambil langkah-langkah berikut untuk memahami mengapa NaN muncul. Pertama, klik peringatan NaN/∞ di bagian Peringatan. Ini secara otomatis menggulir daftar 600 tensor grafik di bagian Graph Execution dan berfokus pada #88, yang merupakan tensor bernama Log:0 yang dihasilkan oleh operasi Log (logaritma natural). Warna merah jambu-merah yang menonjol menyoroti elemen -∞ di antara 1000 elemen tensor float32 2D. Ini adalah tensor pertama dalam riwayat runtime program TF2 yang berisi NaN atau infinity: tensor yang dihitung sebelum tidak berisi NaN atau ; banyak (pada kenyataannya, sebagian besar) tensor yang dihitung setelahnya mengandung NaN. Kami dapat mengkonfirmasi ini dengan menggulir ke atas dan ke bawah daftar Graph Execution. Pengamatan ini memberikan petunjuk kuat bahwa Log op adalah sumber ketidakstabilan numerik dalam program TF2 ini.

Mengapa Log op ini mengeluarkan -∞? Menjawab pertanyaan itu membutuhkan pemeriksaan input ke op. Mengeklik nama tensor ( Log:0 ) akan menampilkan visualisasi sederhana namun informatif dari sekitar Operasi Log dalam grafik TensorFlow-nya di bagian Struktur Grafik. Perhatikan arah arus informasi dari atas ke bawah. Op itu sendiri ditampilkan dalam huruf tebal di tengah. Tepat di atasnya, kita dapat melihat operasi Placeholder memberikan satu-satunya masukan ke operasi Log . Di mana tensor yang dihasilkan oleh Placeholder probs ini dalam daftar Graph Execution? Dengan menggunakan warna latar belakang kuning sebagai bantuan visual, kita dapat melihat bahwa tensor probs:0 berada tiga baris di atas tensor Log:0 , yaitu pada baris 85.

Pengamatan yang lebih cermat pada perincian numerik dari probs:0 tensor di baris 85 mengungkapkan mengapa konsumennya Log:0 menghasilkan a -∞: Di antara 1000 elemen probs:0 , satu elemen memiliki nilai 0. -∞ adalah hasil dari menghitung logaritma natural dari 0! Jika kita dapat memastikan bahwa operasi Log hanya terekspos pada input positif, kita akan dapat mencegah terjadinya NaN/∞. Ini dapat dicapai dengan menerapkan kliping (misalnya, dengan menggunakan tf.clip_by_value() ) pada tensor masalah probs .
Kami semakin dekat untuk memecahkan bug, tetapi belum selesai. Untuk menerapkan perbaikan, kita perlu tahu dari mana dalam kode sumber Python operasi Log dan input Placeholder-nya berasal. Debugger V2 menyediakan dukungan kelas satu untuk melacak operasi grafik dan peristiwa eksekusi ke sumbernya. Saat kita mengklik tensor Log:0 di Graph Executions, bagian Stack Trace diisi dengan stack trace asli dari pembuatan Log op. Jejak tumpukan agak besar karena mencakup banyak bingkai dari kode internal TensorFlow (misalnya, gen_math_ops.py dan dumping_callback.py), yang dapat kita abaikan dengan aman untuk sebagian besar tugas debug. Bingkai yang menarik adalah Baris 216 dari debug_mnist_v2.py (yaitu, file Python yang sebenarnya kami coba debug). Mengklik "Baris 216" menampilkan tampilan baris kode yang sesuai di bagian Kode Sumber.

Ini akhirnya membawa kita ke kode sumber yang membuat operasi Log yang bermasalah dari input probs -nya. Ini adalah fungsi kerugian lintas-entropi kategoris kustom kami yang didekorasi dengan @tf.function dan karenanya diubah menjadi grafik TensorFlow. Masalah op probs sesuai dengan argumen input pertama ke fungsi loss. Operasi Log dibuat dengan panggilan API tf.math.log().
Perbaikan nilai-kliping untuk bug ini akan terlihat seperti:
diff = -(labels *
tf.math.log(tf.clip_by_value(probs), 1e-6, 1.))
Ini akan mengatasi ketidakstabilan numerik dalam program TF2 ini dan menyebabkan MLP berhasil berlatih. Pendekatan lain yang mungkin untuk memperbaiki ketidakstabilan numerik adalah dengan menggunakan tf.keras.losses.CategoricalCrossentropy .
Ini mengakhiri perjalanan kami dari mengamati bug model TF2 hingga menghasilkan perubahan kode yang memperbaiki bug, dibantu oleh alat Debugger V2, yang memberikan visibilitas penuh ke dalam riwayat eksekusi bersemangat dan grafik dari program TF2 yang diinstrumentasi, termasuk ringkasan numerik nilai tensor dan asosiasi antara ops, tensor dan kode sumber aslinya.
Kompatibilitas perangkat keras Debugger V2
Debugger V2 mendukung perangkat keras pelatihan utama termasuk CPU dan GPU. Pelatihan multi-GPU dengan tf.distributed.MirroredStrategy juga didukung. Dukungan untuk TPU masih dalam tahap awal dan membutuhkan panggilan
tf.config.set_soft_device_placement(True)
sebelum memanggil enable_dump_debug_info() . Ini mungkin memiliki batasan lain pada TPU juga. Jika Anda mengalami masalah saat menggunakan Debugger V2, laporkan bug di halaman masalah GitHub kami.
Kompatibilitas API Debugger V2
Debugger V2 diimplementasikan pada tingkat yang relatif rendah dari tumpukan perangkat lunak TensorFlow, dan karenanya kompatibel dengan tf.keras , tf.data , dan API lain yang dibangun di atas tingkat yang lebih rendah dari TensorFlow. Debugger V2 juga kompatibel dengan TF1, meskipun Eager Execution Timeline akan kosong untuk logdir debug yang dihasilkan oleh program TF1.
Kiat penggunaan API
Pertanyaan yang sering diajukan tentang API debugging ini adalah di mana dalam kode TensorFlow seseorang harus memasukkan panggilan ke enable_dump_debug_info() . Biasanya, API harus dipanggil sedini mungkin dalam program TF2 Anda, sebaiknya setelah baris impor Python dan sebelum pembuatan dan eksekusi grafik dimulai. Ini akan memastikan cakupan penuh dari semua operasi dan grafik yang mendukung model Anda dan pelatihannya.
Tensor_debug_mode yang saat ini didukung adalah: NO_TENSOR , CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTH , dan SHAPE . Mereka bervariasi dalam jumlah informasi yang diekstraksi dari setiap tensor dan overhead kinerja ke program yang di-debug. Silakan merujuk ke bagian args dari enable_dump_debug_info() .
Overhead kinerja
API debugging memperkenalkan overhead kinerja ke program TensorFlow yang diinstrumentasi. Overhead bervariasi menurut tensor_debug_mode , jenis perangkat keras, dan sifat program TensorFlow yang diinstrumentasi. Sebagai titik referensi, pada GPU, mode NO_TENSOR menambahkan 15% overhead selama pelatihan model Transformer di bawah ukuran batch 64. Persen overhead untuk tensor_debug_mode lainnya lebih tinggi: sekitar 50% untuk CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTH dan SHAPE mode. Pada CPU, overhead sedikit lebih rendah. Pada TPU, overhead saat ini lebih tinggi.
Kaitannya dengan API debugging TensorFlow lainnya
Perhatikan bahwa TensorFlow menawarkan alat dan API lain untuk debugging. Anda dapat menelusuri API semacam itu di bawah ruang nama tf.debugging.* di halaman dokumen API. Di antara API ini yang paling sering digunakan adalah tf.print() . Kapan seseorang harus menggunakan Debugger V2 dan kapan tf.print() harus digunakan? tf.print() nyaman jika
- kami tahu persis tensor mana yang akan dicetak,
- kita tahu di mana tepatnya dalam kode sumber untuk menyisipkan pernyataan
tf.print()itu, - jumlah tensor tersebut tidak terlalu besar.
Untuk kasus lain (misalnya, memeriksa banyak nilai tensor, memeriksa nilai tensor yang dihasilkan oleh kode internal TensorFlow, dan mencari asal ketidakstabilan numerik seperti yang kami tunjukkan di atas), Debugger V2 menyediakan cara debug yang lebih cepat. Selain itu, Debugger V2 menyediakan pendekatan terpadu untuk memeriksa tensor yang bersemangat dan grafik. Ini juga memberikan informasi tentang struktur grafik dan lokasi kode, yang berada di luar kemampuan tf.print() .
API lain yang dapat digunakan untuk men-debug masalah yang melibatkan dan NaN adalah tf.debugging.enable_check_numerics() . Tidak seperti enable_dump_debug_info() , enable_check_numerics() tidak menyimpan informasi debug pada disk. Sebaliknya, itu hanya memantau dan NaN selama runtime TensorFlow dan kesalahan dengan lokasi kode asal segera setelah operasi apa pun menghasilkan nilai numerik yang buruk. Ini memiliki overhead kinerja yang lebih rendah dibandingkan dengan enable_dump_debug_info() , tetapi tidak memberikan jejak penuh dari riwayat eksekusi program dan tidak datang dengan antarmuka pengguna grafis seperti Debugger V2.
Peristiwa bencana yang melibatkan NaN terkadang dapat terjadi selama program TensorFlow, melumpuhkan proses pelatihan model. Akar penyebab peristiwa semacam itu seringkali tidak jelas, terutama untuk model dengan ukuran dan kompleksitas yang tidak sepele. Untuk mempermudah men-debug jenis bug model ini, TensorBoard 2.3+ (bersama dengan TensorFlow 2.3+) menyediakan dasbor khusus yang disebut Debugger V2. Di sini kami mendemonstrasikan cara menggunakan alat ini dengan bekerja melalui bug nyata yang melibatkan NaN dalam jaringan saraf yang ditulis dalam TensorFlow.
Teknik yang diilustrasikan dalam tutorial ini berlaku untuk jenis aktivitas debug lainnya seperti memeriksa bentuk tensor runtime dalam program yang kompleks. Tutorial ini berfokus pada NaN karena frekuensi kemunculannya yang relatif tinggi.
Mengamati bug
Kode sumber program TF2 yang akan kami debug tersedia di GitHub . Contoh program juga dikemas ke dalam paket pip tensorflow (versi 2.3+) dan dapat dipanggil oleh:
python -m tensorflow.python.debug.examples.v2.debug_mnist_v2
Program TF2 ini menciptakan persepsi multi-layer (MLP) dan melatihnya untuk mengenali gambar MNIST . Contoh ini dengan sengaja menggunakan API tingkat rendah dari TF2 untuk mendefinisikan konstruksi lapisan kustom, fungsi kerugian, dan loop pelatihan, karena kemungkinan bug NaN lebih tinggi saat kami menggunakan API yang lebih fleksibel tetapi lebih rawan kesalahan ini daripada saat kami menggunakan yang lebih mudah -untuk digunakan tetapi API tingkat tinggi yang sedikit kurang fleksibel seperti tf.keras .
Program mencetak akurasi tes setelah setiap langkah pelatihan. Kita dapat melihat di konsol bahwa akurasi pengujian macet pada tingkat yang hampir mendekati (~0,1) setelah langkah pertama. Ini tentu bukan bagaimana model pelatihan diharapkan berperilaku: kami mengharapkan akurasi secara bertahap mendekati 1,0 (100%) seiring dengan peningkatan langkah.
Accuracy at step 0: 0.216
Accuracy at step 1: 0.098
Accuracy at step 2: 0.098
Accuracy at step 3: 0.098
...
Dugaan terdidik adalah bahwa masalah ini disebabkan oleh ketidakstabilan numerik, seperti NaN atau tak terhingga. Namun, bagaimana kami mengonfirmasi bahwa hal ini benar-benar terjadi dan bagaimana kami menemukan operasi TensorFlow (op) yang bertanggung jawab untuk menghasilkan ketidakstabilan numerik? Untuk menjawab pertanyaan ini, mari lengkapi program buggy dengan Debugger V2.
Menginstrumentasikan kode TensorFlow dengan Debugger V2
tf.debugging.experimental.enable_dump_debug_info() adalah titik masuk API Debugger V2. Ini instrumen program TF2 dengan satu baris kode. Misalnya, menambahkan baris berikut di dekat awal program akan menyebabkan informasi debug ditulis ke direktori log (logdir) di /tmp/tfdbg2_logdir. Informasi debug mencakup berbagai aspek runtime TensorFlow. Di TF2, ini mencakup riwayat lengkap eksekusi bersemangat, pembuatan grafik yang dilakukan oleh @tf.function , eksekusi grafik, nilai tensor yang dihasilkan oleh peristiwa eksekusi, serta lokasi kode (pelacakan tumpukan Python) dari peristiwa tersebut . Kekayaan informasi debug memungkinkan pengguna untuk mempersempit bug yang tidak jelas.
tf.debugging.experimental.enable_dump_debug_info(
"/tmp/tfdbg2_logdir",
tensor_debug_mode="FULL_HEALTH",
circular_buffer_size=-1)
Argumen tensor_debug_mode mengontrol informasi apa yang diekstrak Debugger V2 dari setiap tensor yang bersemangat atau dalam grafik. “FULL_HEALTH” adalah mode yang menangkap informasi berikut tentang setiap tensor tipe-mengambang (mis., float32 yang umum dilihat dan bfloat16 dtype yang kurang umum):
- Tipe D
- Pangkat
- Jumlah total elemen
- Perincian elemen tipe-mengambang ke dalam kategori berikut: hingga negatif (
-), nol (0), hingga positif (+), tak terhingga negatif (-∞), tak hingga positif (+∞), danNaN.
Mode “FULL_HEALTH” cocok untuk men-debug bug yang melibatkan NaN dan infinity. Lihat di bawah untuk tensor_debug_mode lain yang didukung.
Argumen circular_buffer_size mengontrol berapa banyak peristiwa tensor yang disimpan ke logdir. Standarnya adalah 1000, yang menyebabkan hanya 1000 tensor terakhir sebelum akhir program TF2 yang diinstrumentasikan untuk disimpan ke disk. Perilaku default ini mengurangi overhead debugger dengan mengorbankan kelengkapan data debug. Jika kelengkapan lebih disukai, seperti dalam kasus ini, kita dapat menonaktifkan buffer melingkar dengan menyetel argumen ke nilai negatif (misalnya, -1 di sini).
Contoh debug_mnist_v2 memanggil enable_dump_debug_info() dengan meneruskan flag baris perintah ke sana. Untuk menjalankan kembali program TF2 bermasalah kami dengan instrumentasi debugging ini diaktifkan, lakukan:
python -m tensorflow.python.debug.examples.v2.debug_mnist_v2 \
--dump_dir /tmp/tfdbg2_logdir --dump_tensor_debug_mode FULL_HEALTH
Memulai Debugger V2 GUI di TensorBoard
Menjalankan program dengan instrumentasi debugger membuat logdir di /tmp/tfdbg2_logdir. Kita dapat memulai TensorBoard dan mengarahkannya ke logdir dengan:
tensorboard --logdir /tmp/tfdbg2_logdir
Di browser web, navigasikan ke halaman TensorBoard di http://localhost:6006. Plugin "Debugger V2" tidak akan aktif secara default, jadi pilih dari menu "Plugin tidak aktif" di kanan atas. Setelah dipilih, itu akan terlihat seperti berikut:

Menggunakan Debugger V2 GUI untuk menemukan akar penyebab NaNs
GUI Debugger V2 di TensorBoard diatur menjadi enam bagian:
- Peringatan : Bagian kiri atas ini berisi daftar peristiwa "peringatan" yang terdeteksi oleh debugger dalam data debug dari program TensorFlow yang diinstrumentasi. Setiap peringatan menunjukkan anomali tertentu yang memerlukan perhatian. Dalam kasus kami, bagian ini menyoroti 499 peristiwa NaN/∞ dengan warna merah muda-merah yang menonjol. Ini menegaskan kecurigaan kami bahwa model gagal belajar karena adanya NaN dan/atau tak terhingga dalam nilai tensor internalnya. Kami akan mempelajari lansiran ini segera.
- Garis Waktu Eksekusi Python : Ini adalah bagian atas dari bagian tengah atas. Ini menyajikan sejarah lengkap dari eksekusi ops dan grafik yang bersemangat. Setiap kotak garis waktu ditandai dengan huruf awal dari op atau nama grafik (misalnya, "T" untuk operasi "TensorSliceDataset", "m" untuk "model"
tf.function). Kita dapat menavigasi timeline ini dengan menggunakan tombol navigasi dan scrollbar di atas timeline. - Eksekusi Grafik : Terletak di sudut kanan atas GUI, bagian ini akan menjadi pusat tugas debugging kami. Ini berisi riwayat semua tensor tipe-mengambang yang dihitung di dalam grafik (yaitu, dikompilasi oleh
@tf-functions). - Struktur Grafik (setengah bawah bagian tengah-atas), Kode Sumber (bagian kiri bawah), dan Stack Trace (bagian kanan bawah) awalnya kosong. Isinya akan terisi saat kita berinteraksi dengan GUI. Ketiga bagian ini juga akan memainkan peran penting dalam tugas debugging kami.
Setelah mengorientasikan diri kita pada organisasi UI, mari kita ambil langkah-langkah berikut untuk memahami mengapa NaN muncul. Pertama, klik peringatan NaN/∞ di bagian Peringatan. Ini secara otomatis menggulir daftar 600 tensor grafik di bagian Graph Execution dan berfokus pada #88, yang merupakan tensor bernama Log:0 yang dihasilkan oleh operasi Log (logaritma natural). Warna merah jambu-merah yang menonjol menyoroti elemen -∞ di antara 1000 elemen tensor float32 2D. Ini adalah tensor pertama dalam riwayat runtime program TF2 yang berisi NaN atau infinity: tensor yang dihitung sebelum tidak berisi NaN atau ; banyak (pada kenyataannya, sebagian besar) tensor yang dihitung setelahnya mengandung NaN. Kami dapat mengkonfirmasi ini dengan menggulir ke atas dan ke bawah daftar Graph Execution. Pengamatan ini memberikan petunjuk kuat bahwa Log op adalah sumber ketidakstabilan numerik dalam program TF2 ini.

Mengapa Log op ini mengeluarkan -∞? Menjawab pertanyaan itu membutuhkan pemeriksaan input ke op. Mengeklik nama tensor ( Log:0 ) akan menampilkan visualisasi sederhana namun informatif dari sekitar Operasi Log dalam grafik TensorFlow-nya di bagian Struktur Grafik. Perhatikan arah arus informasi dari atas ke bawah. Op itu sendiri ditampilkan dalam huruf tebal di tengah. Tepat di atasnya, kita dapat melihat operasi Placeholder memberikan satu-satunya masukan ke operasi Log . Di mana tensor yang dihasilkan oleh Placeholder probs ini dalam daftar Graph Execution? Dengan menggunakan warna latar belakang kuning sebagai bantuan visual, kita dapat melihat bahwa tensor probs:0 berada tiga baris di atas tensor Log:0 , yaitu pada baris 85.

Pengamatan yang lebih cermat pada perincian numerik dari probs:0 tensor di baris 85 mengungkapkan mengapa konsumennya Log:0 menghasilkan a -∞: Di antara 1000 elemen probs:0 , satu elemen memiliki nilai 0. -∞ adalah hasil dari menghitung logaritma natural dari 0! Jika kita dapat memastikan bahwa operasi Log hanya terekspos pada input positif, kita akan dapat mencegah terjadinya NaN/∞. Ini dapat dicapai dengan menerapkan kliping (misalnya, dengan menggunakan tf.clip_by_value() ) pada tensor masalah probs .
Kami semakin dekat untuk memecahkan bug, tetapi belum selesai. Untuk menerapkan perbaikan, kita perlu tahu dari mana dalam kode sumber Python operasi Log dan input Placeholder-nya berasal. Debugger V2 menyediakan dukungan kelas satu untuk melacak operasi grafik dan peristiwa eksekusi ke sumbernya. Saat kita mengklik tensor Log:0 di Graph Executions, bagian Stack Trace diisi dengan stack trace asli dari pembuatan Log op. Jejak tumpukan agak besar karena mencakup banyak bingkai dari kode internal TensorFlow (misalnya, gen_math_ops.py dan dumping_callback.py), yang dapat kita abaikan dengan aman untuk sebagian besar tugas debug. Bingkai yang menarik adalah Baris 216 dari debug_mnist_v2.py (yaitu, file Python yang sebenarnya kami coba debug). Mengklik "Baris 216" menampilkan tampilan baris kode yang sesuai di bagian Kode Sumber.

Ini akhirnya membawa kita ke kode sumber yang membuat operasi Log yang bermasalah dari input probs -nya. Ini adalah fungsi kerugian lintas-entropi kategoris kustom kami yang didekorasi dengan @tf.function dan karenanya diubah menjadi grafik TensorFlow. Masalah op probs sesuai dengan argumen input pertama ke fungsi loss. Operasi Log dibuat dengan panggilan API tf.math.log().
Perbaikan nilai-kliping untuk bug ini akan terlihat seperti:
diff = -(labels *
tf.math.log(tf.clip_by_value(probs), 1e-6, 1.))
Ini akan mengatasi ketidakstabilan numerik dalam program TF2 ini dan menyebabkan MLP berhasil berlatih. Pendekatan lain yang mungkin untuk memperbaiki ketidakstabilan numerik adalah dengan menggunakan tf.keras.losses.CategoricalCrossentropy .
Ini mengakhiri perjalanan kami dari mengamati bug model TF2 hingga menghasilkan perubahan kode yang memperbaiki bug, dibantu oleh alat Debugger V2, yang memberikan visibilitas penuh ke dalam riwayat eksekusi bersemangat dan grafik dari program TF2 yang diinstrumentasi, termasuk ringkasan numerik nilai tensor dan asosiasi antara ops, tensor dan kode sumber aslinya.
Kompatibilitas perangkat keras Debugger V2
Debugger V2 mendukung perangkat keras pelatihan utama termasuk CPU dan GPU. Pelatihan multi-GPU dengan tf.distributed.MirroredStrategy juga didukung. Dukungan untuk TPU masih dalam tahap awal dan membutuhkan panggilan
tf.config.set_soft_device_placement(True)
sebelum memanggil enable_dump_debug_info() . Ini mungkin memiliki batasan lain pada TPU juga. Jika Anda mengalami masalah saat menggunakan Debugger V2, laporkan bug di halaman masalah GitHub kami.
Kompatibilitas API Debugger V2
Debugger V2 diimplementasikan pada tingkat yang relatif rendah dari tumpukan perangkat lunak TensorFlow, dan karenanya kompatibel dengan tf.keras , tf.data , dan API lain yang dibangun di atas tingkat yang lebih rendah dari TensorFlow. Debugger V2 juga kompatibel dengan TF1, meskipun Eager Execution Timeline akan kosong untuk logdir debug yang dihasilkan oleh program TF1.
Kiat penggunaan API
Pertanyaan yang sering diajukan tentang API debugging ini adalah di mana dalam kode TensorFlow seseorang harus memasukkan panggilan ke enable_dump_debug_info() . Biasanya, API harus dipanggil sedini mungkin dalam program TF2 Anda, sebaiknya setelah baris impor Python dan sebelum pembuatan dan eksekusi grafik dimulai. Ini akan memastikan cakupan penuh dari semua operasi dan grafik yang mendukung model Anda dan pelatihannya.
Tensor_debug_mode yang saat ini didukung adalah: NO_TENSOR , CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTH , dan SHAPE . Mereka bervariasi dalam jumlah informasi yang diekstraksi dari setiap tensor dan overhead kinerja ke program yang di-debug. Silakan merujuk ke bagian args dari enable_dump_debug_info() .
Overhead kinerja
API debugging memperkenalkan overhead kinerja ke program TensorFlow yang diinstrumentasi. Overhead bervariasi menurut tensor_debug_mode , jenis perangkat keras, dan sifat program TensorFlow yang diinstrumentasi. Sebagai titik referensi, pada GPU, mode NO_TENSOR menambahkan 15% overhead selama pelatihan model Transformer di bawah ukuran batch 64. Persen overhead untuk tensor_debug_mode lainnya lebih tinggi: sekitar 50% untuk CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTH dan SHAPE mode. Pada CPU, overhead sedikit lebih rendah. Pada TPU, overhead saat ini lebih tinggi.
Kaitannya dengan API debugging TensorFlow lainnya
Perhatikan bahwa TensorFlow menawarkan alat dan API lain untuk debugging. Anda dapat menelusuri API semacam itu di bawah ruang nama tf.debugging.* di halaman dokumen API. Di antara API ini yang paling sering digunakan adalah tf.print() . Kapan seseorang harus menggunakan Debugger V2 dan kapan tf.print() harus digunakan? tf.print() nyaman jika
- kami tahu persis tensor mana yang akan dicetak,
- kita tahu di mana tepatnya dalam kode sumber untuk menyisipkan pernyataan
tf.print()itu, - jumlah tensor tersebut tidak terlalu besar.
Untuk kasus lain (misalnya, memeriksa banyak nilai tensor, memeriksa nilai tensor yang dihasilkan oleh kode internal TensorFlow, dan mencari asal ketidakstabilan numerik seperti yang kami tunjukkan di atas), Debugger V2 menyediakan cara debug yang lebih cepat. Selain itu, Debugger V2 menyediakan pendekatan terpadu untuk memeriksa tensor yang bersemangat dan grafik. Ini juga memberikan informasi tentang struktur grafik dan lokasi kode, yang berada di luar kemampuan tf.print() .
API lain yang dapat digunakan untuk men-debug masalah yang melibatkan dan NaN adalah tf.debugging.enable_check_numerics() . Tidak seperti enable_dump_debug_info() , enable_check_numerics() tidak menyimpan informasi debug pada disk. Sebaliknya, itu hanya memantau dan NaN selama runtime TensorFlow dan kesalahan dengan lokasi kode asal segera setelah operasi apa pun menghasilkan nilai numerik yang buruk. Ini memiliki overhead kinerja yang lebih rendah dibandingkan dengan enable_dump_debug_info() , tetapi tidak memberikan jejak penuh dari riwayat eksekusi program dan tidak datang dengan antarmuka pengguna grafis seperti Debugger V2.