Gỡ lỗi vấn đề số trong chương trình TensorFlow sử dụng trình gỡ lỗi TensorBoard V2, gỡ lỗi vấn đề số trong chương trình TensorFlow sử dụng trình gỡ lỗi TensorBoard V2

Các sự kiện thảm khốc liên quan đến NaN đôi khi có thể xảy ra trong chương trình TensorFlow, làm tê liệt các quy trình đào tạo mô hình. Nguyên nhân gốc rễ của những sự kiện như vậy thường không rõ ràng, đặc biệt là đối với các mô hình có kích thước và độ phức tạp không nhỏ. Để giúp gỡ lỗi loại lỗi mô hình này dễ dàng hơn, TensorBoard 2.3+ (cùng với TensorFlow 2.3+) cung cấp một bảng điều khiển chuyên biệt có tên là Debugger V2. Sau đây, chúng tôi trình bày cách sử dụng công cụ này bằng cách xử lý một lỗi thực sự liên quan đến NaN trong mạng thần kinh được viết bằng TensorFlow.

Các kỹ thuật được minh họa trong hướng dẫn này có thể áp dụng cho các loại hoạt động gỡ lỗi khác, chẳng hạn như kiểm tra các hình dạng tensor thời gian chạy trong các chương trình phức tạp. Hướng dẫn này tập trung vào NaN do tần suất xuất hiện của chúng tương đối cao.

Quan sát lỗi

Mã nguồn của chương trình TF2 mà chúng tôi sẽ gỡ lỗi có sẵn trên GitHub . Chương trình ví dụ cũng được đóng gói thành gói tensorflow pip (phiên bản 2.3+) và có thể được gọi bằng cách:

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

Chương trình TF2 này tạo ra nhận thức nhiều lớp (MLP) và đào tạo nó để nhận dạng hình ảnh MNIST . Ví dụ này có mục đích sử dụng API cấp thấp của TF2 để xác định cấu trúc lớp tùy chỉnh, hàm mất mát và vòng lặp đào tạo, bởi vì khả năng lỗi NaN cao hơn khi chúng ta sử dụng API này linh hoạt hơn nhưng dễ xảy ra lỗi hơn so với khi chúng ta sử dụng -để sử dụng nhưng API cấp cao hơi kém linh hoạt như tf.keras .

Chương trình in một bài kiểm tra độ chính xác sau mỗi bước đào tạo. Chúng ta có thể thấy trong bảng điều khiển rằng độ chính xác của bài kiểm tra bị mắc kẹt ở mức gần như cơ hội (~ 0,1) sau bước đầu tiên. Đây chắc chắn không phải là cách hoạt động của đào tạo mô hình được mong đợi: chúng tôi mong đợi độ chính xác dần dần đạt đến 1,0 (100%) khi bước này tăng lên.

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

Một phỏng đoán thông minh là vấn đề này gây ra bởi sự không ổn định về số, chẳng hạn như NaN hoặc vô cùng. Tuy nhiên, làm thế nào để chúng tôi xác nhận đây thực sự là trường hợp và làm thế nào để chúng tôi tìm thấy hoạt động TensorFlow (op) chịu trách nhiệm tạo ra sự không ổn định số? Để trả lời những câu hỏi này, hãy thiết bị chương trình lỗi với Debugger V2.

Tạo công cụ mã TensorFlow với Debugger V2

tf.debugging.experimental.enable_dump_debug_info() là điểm nhập API của Debugger V2. Nó tạo ra một chương trình TF2 với một dòng mã duy nhất. Ví dụ: thêm dòng sau vào gần đầu chương trình sẽ khiến thông tin gỡ lỗi được ghi vào thư mục nhật ký (logdir) tại / tmp / tfdbg2_logdir. Thông tin gỡ lỗi bao gồm các khía cạnh khác nhau của thời gian chạy TensorFlow. Trong TF2, nó bao gồm toàn bộ lịch sử thực thi háo hức, xây dựng biểu đồ được thực hiện bởi @ tf . function, việc thực thi đồ thị, giá trị tensor được tạo bởi các sự kiện thực thi, cũng như vị trí mã (dấu vết ngăn xếp Python) của các sự kiện đó . Sự phong phú của thông tin gỡ lỗi cho phép người dùng thu hẹp các lỗi khó hiểu.

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

Đối số tensor_debug_mode kiểm soát thông tin nào mà Trình gỡ lỗi V2 trích xuất từ ​​mỗi tensor háo hức hoặc trong đồ thị. “FULL_HEALTH” là một chế độ thu thập thông tin sau về mỗi tensor kiểu thả nổi (ví dụ: float32 thường thấy và dtype bfloat16 ít phổ biến hơn):

  • DType
  • Cấp
  • Tổng số phần tử
  • Phân tích các phần tử kiểu động thành các loại sau: âm hữu hạn ( - ), không ( 0 ), dương hữu hạn ( + ), vô cực âm ( -∞ ), vô cực dương ( +∞ ) và NaN .

Chế độ “FULL_HEALTH” phù hợp để gỡ lỗi liên quan đến NaN và vô cực. Xem bên dưới để biết các tensor_debug_mode được hỗ trợ khác.

Đối số circular_buffer_size kiểm soát số lượng sự kiện tensor được lưu vào logdir. Nó mặc định là 1000, điều này chỉ khiến 1000 tensors cuối cùng trước khi kết thúc chương trình TF2 có thiết bị được lưu vào đĩa. Hành vi mặc định này làm giảm chi phí của trình gỡ lỗi bằng cách hy sinh tính hoàn chỉnh của dữ liệu gỡ lỗi. Nếu tính đầy đủ được ưu tiên, như trong trường hợp này, chúng ta có thể vô hiệu hóa vùng đệm tròn bằng cách đặt đối số thành giá trị âm (ví dụ: -1 ở đây).

Ví dụ debug_mnist_v2 gọi enable_dump_debug_info() bằng cách chuyển các cờ dòng lệnh cho nó. Để chạy lại chương trình TF2 có vấn đề của chúng tôi khi bật thiết bị gỡ lỗi này, hãy thực hiện:

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

Khởi động GUI V2 Debugger trong TensorBoard

Chạy chương trình với thiết bị gỡ lỗi sẽ tạo logdir tại / tmp / tfdbg2_logdir. Chúng ta có thể khởi động TensorBoard và trỏ nó vào logdir với:

tensorboard --logdir /tmp/tfdbg2_logdir

Trong trình duyệt web, điều hướng đến trang của TensorBoard tại http: // localhost: 6006. Plugin “Debugger V2” sẽ không hoạt động theo mặc định, vì vậy hãy chọn plugin từ menu “Plugin không hoạt động” ở trên cùng bên phải. Sau khi được chọn, nó sẽ giống như sau:

Ảnh chụp màn hình toàn cảnh Debugger V2

Sử dụng GUI trình gỡ lỗi V2 để tìm nguyên nhân gốc rễ của NaNs

GUI V2 Debugger trong TensorBoard được tổ chức thành sáu phần:

  • Cảnh báo : Phần trên cùng bên trái này chứa danh sách các sự kiện “cảnh báo” được trình gỡ lỗi phát hiện trong dữ liệu gỡ lỗi từ chương trình TensorFlow có công cụ. Mỗi cảnh báo chỉ ra một điểm bất thường nhất định cần được chú ý. Trong trường hợp của chúng tôi, phần này đánh dấu các sự kiện 499 NaN / ∞ với màu đỏ hồng nổi bật. Điều này xác nhận sự nghi ngờ của chúng tôi rằng mô hình không thể học được do sự hiện diện của NaN và / hoặc số vô hạn trong các giá trị tensor bên trong của nó. Chúng tôi sẽ sớm đi sâu vào các cảnh báo này.
  • Dòng thời gian thực thi Python : Đây là nửa trên của phần trên-giữa. Nó trình bày toàn bộ lịch sử của việc thực hiện các hoạt động và đồ thị một cách háo hức. Mỗi ô của dòng thời gian được đánh dấu bằng chữ cái đầu của tên op hoặc tên của đồ thị (ví dụ: “T” cho op “TensorSliceDataset”, “m” cho chức năng “model” tf.function ). Chúng ta có thể điều hướng dòng thời gian này bằng cách sử dụng các nút điều hướng và thanh cuộn phía trên dòng thời gian.
  • Thực thi Đồ thị : Nằm ở góc trên bên phải của GUI, phần này sẽ là trọng tâm của nhiệm vụ gỡ lỗi của chúng tôi. Nó chứa lịch sử của tất cả các tenxơ kiểu nổi được tính toán bên trong đồ thị (tức là, được biên dịch bởi @tf-function s).
  • Cấu trúc biểu đồ (nửa dưới của phần trên cùng giữa), Mã nguồn (phần dưới cùng bên trái) và Dấu vết ngăn xếp (phần dưới cùng bên phải) ban đầu trống. Nội dung của chúng sẽ được điền khi chúng ta tương tác với GUI. Ba phần này cũng sẽ đóng vai trò quan trọng trong nhiệm vụ gỡ lỗi của chúng tôi.

Sau khi định hướng bản thân về tổ chức của giao diện người dùng, hãy thực hiện các bước sau để tìm hiểu sâu hơn về lý do tại sao NaN xuất hiện. Đầu tiên, nhấp vào cảnh báo NaN / ∞ trong phần Cảnh báo. Thao tác này sẽ tự động cuộn danh sách 600 tensor đồ thị trong phần Thực thi Đồ thị và tập trung vào # 88, là tensor có tên là Log:0 được tạo bởi Log (logarit tự nhiên). Màu đỏ hồng nổi bật làm nổi bật một phần tử -∞ trong số 1000 phần tử của tensor 2D float32. Đây là tensor đầu tiên trong lịch sử thời gian chạy của chương trình TF2 có chứa bất kỳ NaN hoặc vô cực nào: tensor được tính trước khi nó không chứa NaN hoặc ∞; nhiều (thực tế là hầu hết) các tensor được tính toán sau đó chứa NaN. Chúng tôi có thể xác nhận điều này bằng cách cuộn lên và xuống danh sách Thực thi Đồ thị. Quan sát này cung cấp một gợi ý mạnh mẽ rằng Log op là nguồn gốc của sự không ổn định số trong chương trình TF2 này.

Debugger V2: Cảnh báo Nan / Infinity và danh sách thực thi đồ thị

Tại sao op Log này lại xuất hiện một -∞? Trả lời câu hỏi đó yêu cầu kiểm tra đầu vào của op. Nhấp vào tên của tensor ( Log:0 ) mang đến một hình dung đơn giản nhưng đầy đủ thông tin về vùng lân cận của Log op trong biểu đồ TensorFlow của nó trong phần Cấu trúc đồ thị. Lưu ý hướng từ trên xuống dưới của luồng thông tin. Bản thân op được in đậm ở giữa. Ngay phía trên nó, chúng ta có thể thấy op Placeholder cung cấp đầu vào một và duy nhất cho op Log . Teor được tạo ra bởi trình giữ chỗ probs này ở đâu trong danh sách Thực thi Đồ thị? Bằng cách sử dụng màu nền vàng làm trợ giúp trực quan, chúng ta có thể thấy rằng các probs:0 nằm ba hàng trên tensor Log:0 , nghĩa là ở hàng 85.

Debugger V2: Chế độ xem cấu trúc đồ thị và truy tìm đến tensor đầu vào

Xem xét cẩn thận hơn về phân tích số của các probs:0 tensor ở hàng 85 cho thấy lý do tại sao người tiêu dùng của nó Log:0 tạo ra a -∞: Trong số 1000 phần tử của probs:0 , một phần tử có giá trị bằng 0. Giá trị -∞ là kết quả của việc tính toán lôgarit tự nhiên của 0! Nếu bằng cách nào đó chúng tôi có thể đảm bảo rằng op Log chỉ được tiếp xúc với các đầu vào tích cực, chúng tôi sẽ có thể ngăn NaN / ∞ xảy ra. Điều này có thể đạt được bằng cách áp dụng clipping (ví dụ: bằng cách sử dụng tf.clip_by_value() ) trên tensor thăm probs của Placeholder.

Chúng tôi đang tiến gần hơn đến việc giải quyết lỗi, nhưng vẫn chưa hoàn thành. Để áp dụng bản sửa lỗi, chúng ta cần biết nơi bắt nguồn từ mã nguồn Log và đầu vào Trình giữ chỗ của nó. Trình gỡ lỗi V2 cung cấp hỗ trợ hạng nhất để theo dõi các hoạt động biểu đồ và các sự kiện thực thi tới nguồn của chúng. Khi chúng tôi nhấp vào tensor Log:0 trong Graph Executions, phần Stack Trace được điền với dấu vết ngăn xếp ban đầu của việc tạo Log op. Dấu vết ngăn xếp hơi lớn vì nó bao gồm nhiều khung từ mã nội bộ của TensorFlow (ví dụ: gen_math_ops.py và dump_callback.py), chúng tôi có thể bỏ qua một cách an toàn đối với hầu hết các tác vụ gỡ lỗi. Khung quan tâm là Dòng 216 của debug_mnist_v2.py (tức là tệp Python mà chúng tôi thực sự đang cố gắng gỡ lỗi). Nhấp vào “Dòng 216” sẽ hiển thị dòng mã tương ứng trong phần Mã nguồn.

Trình gỡ lỗi V2: Mã nguồn và dấu vết ngăn xếp

Điều này cuối cùng đưa chúng ta đến mã nguồn đã tạo op Log có vấn đề từ đầu vào probs của nó. Đây là hàm mất entropy chéo phân loại tùy chỉnh của chúng tôi được trang trí bằng hàm @tf.function và do đó được chuyển đổi thành biểu đồ TensorFlow. Các thăm dò op của probs giữ chỗ tương ứng với đối số đầu vào đầu tiên của hàm mất mát. Op Log được tạo bằng lệnh gọi API tf.math.log ().

Bản sửa lỗi cắt bớt giá trị cho lỗi này sẽ giống như sau:

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

Nó sẽ giải quyết sự không ổn định về số lượng trong chương trình TF2 này và khiến MLP huấn luyện thành công. Một cách tiếp cận khả thi khác để khắc phục sự không ổn định số là sử dụng tf.keras.losses.CategoricalCrossentropy .

Điều này kết thúc hành trình của chúng tôi từ việc quan sát lỗi mô hình TF2 đến việc thay đổi mã để sửa lỗi, được hỗ trợ bởi công cụ Debugger V2, cung cấp khả năng hiển thị đầy đủ về lịch sử thực thi háo hức và đồ thị của chương trình TF2 được thiết kế, bao gồm các tóm tắt số giá trị tensor và sự liên kết giữa ops, tensor và mã nguồn ban đầu của chúng.

Khả năng tương thích phần cứng của Debugger V2

Debugger V2 hỗ trợ phần cứng đào tạo chính thống bao gồm CPU và GPU. Đào tạo đa GPU với tf.distributed.MirroredStrategy cũng được hỗ trợ. Sự hỗ trợ cho TPU vẫn đang trong giai đoạn đầu và cần phải kêu gọi

tf.config.set_soft_device_placement(True)

trước khi gọi enable_dump_debug_info() . Nó cũng có thể có những hạn chế khác đối với TPU. Nếu bạn gặp sự cố khi sử dụng Trình gỡ lỗi V2, vui lòng báo cáo lỗi trên trang sự cố GitHub của chúng tôi.

Khả năng tương thích API của Trình gỡ lỗi V2

Debugger V2 được triển khai ở mức tương đối thấp trong ngăn xếp phần mềm của TensorFlow và do đó tương thích với tf.keras , tf.data và các API khác được xây dựng trên các cấp thấp hơn của TensorFlow. Trình gỡ lỗi V2 cũng tương thích ngược với TF1, mặc dù Dòng thời gian thực thi Eager sẽ trống cho các trình tự gỡ lỗi được tạo bởi các chương trình TF1.

Mẹo sử dụng API

Một câu hỏi thường gặp về API gỡ lỗi này là nơi nào trong mã TensorFlow người ta sẽ chèn lệnh gọi tới enable_dump_debug_info() . Thông thường, API phải được gọi càng sớm càng tốt trong chương trình TF2 của bạn, tốt nhất là sau các dòng nhập Python và trước khi bắt đầu xây dựng và thực thi đồ thị. Điều này sẽ đảm bảo bao quát đầy đủ tất cả các hoạt động và biểu đồ cung cấp năng lượng cho mô hình của bạn và việc đào tạo nó.

Các tensor_debug_modes hiện được hỗ trợ là: NO_TENSOR , CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTHSHAPE . Chúng khác nhau về lượng thông tin được trích xuất từ ​​mỗi tensor và chi phí hiệu suất cho chương trình được gỡ lỗi. Vui lòng tham khảo phần args trong tài liệu của enable_dump_debug_info() .

Chi phí hiệu suất

API gỡ lỗi giới thiệu chi phí hiệu suất cho chương trình TensorFlow được thiết kế. Chi phí thay đổi theo tensor_debug_mode , loại phần cứng và bản chất của chương trình TensorFlow có công cụ. Như một điểm tham chiếu, trên GPU, chế độ NO_TENSOR thêm 15% chi phí trong quá trình đào tạo mô hình Biến áp theo kích thước lô 64. Chi phí phần trăm cho các tensor_debug_modes khác cao hơn: khoảng 50% cho CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTHSHAPE các chế độ. Trên CPU, chi phí thấp hơn một chút. Trên các TPU, chi phí hiện đang cao hơn.

Liên quan đến các API gỡ lỗi TensorFlow khác

Lưu ý rằng TensorFlow cung cấp các công cụ và API khác để gỡ lỗi. Bạn có thể duyệt các API như vậy trong không gian tên tf.debugging.* Tại trang tài liệu API. Trong số các API này được sử dụng thường xuyên nhất là tf.print() . Khi nào thì nên sử dụng Debugger V2 và khi nào thì nên sử dụng tf.print() ? tf.print() rất tiện lợi trong trường hợp

  1. chúng tôi biết chính xác bộ căng nào để in,
  2. chúng tôi biết chính xác vị trí trong mã nguồn để chèn các câu lệnh tf.print() đó,
  3. số lượng các tenxơ như vậy không quá lớn.

Đối với các trường hợp khác (ví dụ: kiểm tra nhiều giá trị tensor, kiểm tra các giá trị tensor được tạo bởi mã nội bộ của TensorFlow và tìm kiếm nguồn gốc của sự không ổn định số như chúng tôi đã trình bày ở trên), Debugger V2 cung cấp một cách gỡ lỗi nhanh hơn. Ngoài ra, Debugger V2 cung cấp một cách tiếp cận thống nhất để kiểm tra các yếu tố gây háo hức và vẽ đồ thị. Nó cũng cung cấp thông tin về cấu trúc đồ thị và vị trí mã, những thông tin này nằm ngoài khả năng của tf.print() .

Một API khác có thể được sử dụng để gỡ lỗi các vấn đề liên quan đến ∞ và NaN là tf.debugging.enable_check_numerics() . Không giống như enable_dump_debug_info() , enable_check_numerics() không lưu thông tin gỡ lỗi trên đĩa. Thay vào đó, nó chỉ theo dõi ∞ và NaN trong thời gian chạy TensorFlow và phát hiện lỗi với vị trí mã gốc ngay khi bất kỳ op nào tạo ra các giá trị số xấu như vậy. Nó có chi phí hiệu suất thấp hơn so với enable_dump_debug_info() , nhưng không có dấu vết đầy đủ về lịch sử thực thi của chương trình và không đi kèm với giao diện người dùng đồ họa như Debugger V2.

,

Các sự kiện thảm khốc liên quan đến NaN đôi khi có thể xảy ra trong chương trình TensorFlow, làm tê liệt các quy trình đào tạo mô hình. Nguyên nhân gốc rễ của những sự kiện như vậy thường không rõ ràng, đặc biệt là đối với các mô hình có kích thước và độ phức tạp không nhỏ. Để giúp gỡ lỗi loại lỗi mô hình này dễ dàng hơn, TensorBoard 2.3+ (cùng với TensorFlow 2.3+) cung cấp một bảng điều khiển chuyên biệt có tên là Debugger V2. Ở đây, chúng tôi trình bày cách sử dụng công cụ này bằng cách xử lý một lỗi thực sự liên quan đến NaN trong mạng thần kinh được viết bằng TensorFlow.

Các kỹ thuật được minh họa trong hướng dẫn này có thể áp dụng cho các loại hoạt động gỡ lỗi khác, chẳng hạn như kiểm tra các hình dạng tensor thời gian chạy trong các chương trình phức tạp. Hướng dẫn này tập trung vào NaN do tần suất xuất hiện của chúng tương đối cao.

Quan sát lỗi

Mã nguồn của chương trình TF2 mà chúng tôi sẽ gỡ lỗi có sẵn trên GitHub . Chương trình ví dụ cũng được đóng gói thành gói tensorflow pip (phiên bản 2.3+) và có thể được gọi bằng cách:

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

Chương trình TF2 này tạo ra nhận thức nhiều lớp (MLP) và đào tạo nó để nhận dạng hình ảnh MNIST . Ví dụ này có mục đích sử dụng API cấp thấp của TF2 để xác định cấu trúc lớp tùy chỉnh, hàm mất mát và vòng lặp đào tạo, bởi vì khả năng lỗi NaN cao hơn khi chúng ta sử dụng API này linh hoạt hơn nhưng dễ xảy ra lỗi hơn so với khi chúng ta sử dụng -để sử dụng nhưng API cấp cao hơi kém linh hoạt như tf.keras .

Chương trình in một bài kiểm tra độ chính xác sau mỗi bước đào tạo. Chúng ta có thể thấy trong bảng điều khiển rằng độ chính xác của bài kiểm tra bị mắc kẹt ở mức gần như cơ hội (~ 0,1) sau bước đầu tiên. Đây chắc chắn không phải là cách hoạt động của đào tạo mô hình được mong đợi: chúng tôi mong đợi độ chính xác dần dần đạt đến 1,0 (100%) khi bước này tăng lên.

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

Một phỏng đoán thông minh là vấn đề này gây ra bởi sự không ổn định về số, chẳng hạn như NaN hoặc vô cùng. Tuy nhiên, làm thế nào để chúng tôi xác nhận đây thực sự là trường hợp và làm thế nào để chúng tôi tìm thấy hoạt động TensorFlow (op) chịu trách nhiệm tạo ra sự không ổn định số? Để trả lời những câu hỏi này, hãy thiết bị chương trình lỗi với Debugger V2.

Tạo công cụ mã TensorFlow với Debugger V2

tf.debugging.experimental.enable_dump_debug_info() là điểm nhập API của Debugger V2. Nó tạo ra một chương trình TF2 với một dòng mã duy nhất. Ví dụ: thêm dòng sau vào gần đầu chương trình sẽ khiến thông tin gỡ lỗi được ghi vào thư mục nhật ký (logdir) tại / tmp / tfdbg2_logdir. Thông tin gỡ lỗi bao gồm các khía cạnh khác nhau của thời gian chạy TensorFlow. Trong TF2, nó bao gồm toàn bộ lịch sử thực thi háo hức, xây dựng biểu đồ được thực hiện bởi @ tf . function, việc thực thi đồ thị, giá trị tensor được tạo bởi các sự kiện thực thi, cũng như vị trí mã (dấu vết ngăn xếp Python) của các sự kiện đó . Sự phong phú của thông tin gỡ lỗi cho phép người dùng thu hẹp các lỗi khó hiểu.

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

Đối số tensor_debug_mode kiểm soát thông tin nào mà Trình gỡ lỗi V2 trích xuất từ ​​mỗi tensor háo hức hoặc trong đồ thị. “FULL_HEALTH” là một chế độ thu thập thông tin sau về mỗi tensor kiểu thả nổi (ví dụ: float32 thường thấy và dtype bfloat16 ít phổ biến hơn):

  • DType
  • Cấp
  • Tổng số phần tử
  • Phân tích các phần tử kiểu động thành các loại sau: âm hữu hạn ( - ), không ( 0 ), dương hữu hạn ( + ), vô cực âm ( -∞ ), vô cực dương ( +∞ ) và NaN .

Chế độ “FULL_HEALTH” phù hợp để gỡ lỗi liên quan đến NaN và vô cực. Xem bên dưới để biết các tensor_debug_mode được hỗ trợ khác.

Đối số circular_buffer_size kiểm soát số lượng sự kiện tensor được lưu vào logdir. Nó mặc định là 1000, điều này chỉ khiến 1000 tensors cuối cùng trước khi kết thúc chương trình TF2 có thiết bị được lưu vào đĩa. Hành vi mặc định này làm giảm chi phí của trình gỡ lỗi bằng cách hy sinh tính hoàn chỉnh của dữ liệu gỡ lỗi. Nếu tính đầy đủ được ưu tiên, như trong trường hợp này, chúng ta có thể vô hiệu hóa vùng đệm tròn bằng cách đặt đối số thành giá trị âm (ví dụ: -1 ở đây).

Ví dụ debug_mnist_v2 gọi enable_dump_debug_info() bằng cách chuyển các cờ dòng lệnh cho nó. Để chạy lại chương trình TF2 có vấn đề của chúng tôi khi bật thiết bị gỡ lỗi này, hãy thực hiện:

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

Khởi động GUI V2 Debugger trong TensorBoard

Chạy chương trình với thiết bị gỡ lỗi sẽ tạo logdir tại / tmp / tfdbg2_logdir. Chúng ta có thể khởi động TensorBoard và trỏ nó vào logdir với:

tensorboard --logdir /tmp/tfdbg2_logdir

Trong trình duyệt web, điều hướng đến trang của TensorBoard tại http: // localhost: 6006. Plugin “Debugger V2” sẽ không hoạt động theo mặc định, vì vậy hãy chọn plugin từ menu “Plugin không hoạt động” ở trên cùng bên phải. Sau khi được chọn, nó sẽ giống như sau:

Ảnh chụp màn hình toàn cảnh Debugger V2

Sử dụng GUI trình gỡ lỗi V2 để tìm nguyên nhân gốc rễ của NaNs

GUI V2 Debugger trong TensorBoard được tổ chức thành sáu phần:

  • Cảnh báo : Phần trên cùng bên trái này chứa danh sách các sự kiện “cảnh báo” được trình gỡ lỗi phát hiện trong dữ liệu gỡ lỗi từ chương trình TensorFlow có công cụ. Mỗi cảnh báo chỉ ra một điểm bất thường nhất định cần được chú ý. Trong trường hợp của chúng tôi, phần này đánh dấu các sự kiện 499 NaN / ∞ với màu đỏ hồng nổi bật. Điều này xác nhận sự nghi ngờ của chúng tôi rằng mô hình không thể học được do sự hiện diện của NaN và / hoặc số vô hạn trong các giá trị tensor bên trong của nó. Chúng tôi sẽ sớm đi sâu vào các cảnh báo này.
  • Dòng thời gian thực thi Python : Đây là nửa trên của phần trên-giữa. Nó trình bày toàn bộ lịch sử của việc thực hiện các hoạt động và đồ thị một cách háo hức. Mỗi ô của dòng thời gian được đánh dấu bằng chữ cái đầu của tên op hoặc tên của đồ thị (ví dụ: “T” cho op “TensorSliceDataset”, “m” cho chức năng “model” tf.function ). Chúng ta có thể điều hướng dòng thời gian này bằng cách sử dụng các nút điều hướng và thanh cuộn phía trên dòng thời gian.
  • Thực thi Đồ thị : Nằm ở góc trên bên phải của GUI, phần này sẽ là trọng tâm của nhiệm vụ gỡ lỗi của chúng tôi. Nó chứa lịch sử của tất cả các tenxơ kiểu nổi được tính toán bên trong đồ thị (tức là, được biên dịch bởi @tf-function s).
  • Cấu trúc biểu đồ (nửa dưới của phần trên cùng giữa), Mã nguồn (phần dưới cùng bên trái) và Dấu vết ngăn xếp (phần dưới cùng bên phải) ban đầu trống. Nội dung của chúng sẽ được điền khi chúng ta tương tác với GUI. Ba phần này cũng sẽ đóng vai trò quan trọng trong nhiệm vụ gỡ lỗi của chúng tôi.

Sau khi định hướng bản thân về tổ chức của giao diện người dùng, hãy thực hiện các bước sau để tìm hiểu sâu hơn về lý do tại sao NaN xuất hiện. Đầu tiên, nhấp vào cảnh báo NaN / ∞ trong phần Cảnh báo. Thao tác này sẽ tự động cuộn danh sách 600 tensor đồ thị trong phần Thực thi Đồ thị và tập trung vào # 88, là tensor có tên là Log:0 được tạo bởi Log (logarit tự nhiên). Màu đỏ hồng nổi bật làm nổi bật một phần tử -∞ trong số 1000 phần tử của tensor 2D float32. Đây là tensor đầu tiên trong lịch sử thời gian chạy của chương trình TF2 có chứa bất kỳ NaN hoặc vô cực nào: tensor được tính trước khi nó không chứa NaN hoặc ∞; nhiều (thực tế là hầu hết) các tensor được tính toán sau đó chứa NaN. Chúng tôi có thể xác nhận điều này bằng cách cuộn lên và xuống danh sách Thực thi Đồ thị. Quan sát này cung cấp một gợi ý mạnh mẽ rằng Log op là nguồn gốc của sự không ổn định số trong chương trình TF2 này.

Debugger V2: Cảnh báo Nan / Infinity và danh sách thực thi đồ thị

Tại sao op Log này lại xuất hiện một -∞? Trả lời câu hỏi đó yêu cầu kiểm tra đầu vào của op. Nhấp vào tên của tensor ( Log:0 ) mang đến một hình dung đơn giản nhưng đầy đủ thông tin về vùng lân cận của Log op trong biểu đồ TensorFlow của nó trong phần Cấu trúc đồ thị. Lưu ý hướng từ trên xuống dưới của luồng thông tin. Bản thân op được in đậm ở giữa. Ngay phía trên nó, chúng ta có thể thấy op Placeholder cung cấp đầu vào một và duy nhất cho op Log . Teor được tạo ra bởi trình giữ chỗ probs này ở đâu trong danh sách Thực thi Đồ thị? Bằng cách sử dụng màu nền vàng làm trợ giúp trực quan, chúng ta có thể thấy rằng các probs:0 nằm ba hàng trên tensor Log:0 , nghĩa là ở hàng 85.

Debugger V2: Chế độ xem cấu trúc đồ thị và truy tìm đến tensor đầu vào

Xem xét cẩn thận hơn về phân tích số của các probs:0 tensor ở hàng 85 cho thấy lý do tại sao người tiêu dùng của nó Log:0 tạo ra a -∞: Trong số 1000 phần tử của probs:0 , một phần tử có giá trị bằng 0. Giá trị -∞ là kết quả của việc tính toán lôgarit tự nhiên của 0! Nếu bằng cách nào đó chúng tôi có thể đảm bảo rằng op Log chỉ được tiếp xúc với các đầu vào tích cực, chúng tôi sẽ có thể ngăn NaN / ∞ xảy ra. Điều này có thể đạt được bằng cách áp dụng clipping (ví dụ: bằng cách sử dụng tf.clip_by_value() ) trên tensor thăm probs của Placeholder.

Chúng tôi đang tiến gần hơn đến việc giải quyết lỗi, nhưng vẫn chưa hoàn thành. Để áp dụng bản sửa lỗi, chúng ta cần biết nơi bắt nguồn từ mã nguồn Log và đầu vào Trình giữ chỗ của nó. Trình gỡ lỗi V2 cung cấp hỗ trợ hạng nhất để theo dõi các hoạt động biểu đồ và các sự kiện thực thi tới nguồn của chúng. Khi chúng tôi nhấp vào tensor Log:0 trong Graph Executions, phần Stack Trace được điền với dấu vết ngăn xếp ban đầu của việc tạo Log op. Dấu vết ngăn xếp hơi lớn vì nó bao gồm nhiều khung từ mã nội bộ của TensorFlow (ví dụ: gen_math_ops.py và dump_callback.py), chúng tôi có thể bỏ qua một cách an toàn đối với hầu hết các tác vụ gỡ lỗi. Khung quan tâm là Dòng 216 của debug_mnist_v2.py (tức là tệp Python mà chúng tôi thực sự đang cố gắng gỡ lỗi). Nhấp vào “Dòng 216” sẽ hiển thị dòng mã tương ứng trong phần Mã nguồn.

Trình gỡ lỗi V2: Mã nguồn và dấu vết ngăn xếp

Điều này cuối cùng đưa chúng ta đến mã nguồn đã tạo op Log có vấn đề từ đầu vào probs của nó. Đây là hàm mất entropy chéo phân loại tùy chỉnh của chúng tôi được trang trí bằng hàm @tf.function và do đó được chuyển đổi thành biểu đồ TensorFlow. Các thăm dò op của probs giữ chỗ tương ứng với đối số đầu vào đầu tiên của hàm mất mát. Op Log được tạo bằng lệnh gọi API tf.math.log ().

Bản sửa lỗi cắt bớt giá trị cho lỗi này sẽ giống như sau:

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

Nó sẽ giải quyết sự không ổn định về số lượng trong chương trình TF2 này và khiến MLP huấn luyện thành công. Một cách tiếp cận khả thi khác để khắc phục sự không ổn định số là sử dụng tf.keras.losses.CategoricalCrossentropy .

Điều này kết thúc hành trình của chúng tôi từ việc quan sát lỗi mô hình TF2 đến việc thay đổi mã để sửa lỗi, được hỗ trợ bởi công cụ Debugger V2, cung cấp khả năng hiển thị đầy đủ về lịch sử thực thi háo hức và đồ thị của chương trình TF2 được thiết kế, bao gồm các tóm tắt số giá trị tensor và sự liên kết giữa ops, tensor và mã nguồn ban đầu của chúng.

Khả năng tương thích phần cứng của Debugger V2

Debugger V2 hỗ trợ phần cứng đào tạo chính thống bao gồm CPU và GPU. Đào tạo đa GPU với tf.distributed.MirroredStrategy cũng được hỗ trợ. Sự hỗ trợ cho TPU vẫn đang trong giai đoạn đầu và cần phải kêu gọi

tf.config.set_soft_device_placement(True)

trước khi gọi enable_dump_debug_info() . Nó cũng có thể có những hạn chế khác đối với TPU. Nếu bạn gặp sự cố khi sử dụng Trình gỡ lỗi V2, vui lòng báo cáo lỗi trên trang sự cố GitHub của chúng tôi.

Khả năng tương thích API của Trình gỡ lỗi V2

Debugger V2 được triển khai ở mức tương đối thấp trong ngăn xếp phần mềm của TensorFlow và do đó tương thích với tf.keras , tf.data và các API khác được xây dựng trên các cấp thấp hơn của TensorFlow. Trình gỡ lỗi V2 cũng tương thích ngược với TF1, mặc dù Dòng thời gian thực thi Eager sẽ trống cho các trình tự gỡ lỗi được tạo bởi các chương trình TF1.

Mẹo sử dụng API

Một câu hỏi thường gặp về API gỡ lỗi này là nơi nào trong mã TensorFlow người ta sẽ chèn lệnh gọi tới enable_dump_debug_info() . Thông thường, API phải được gọi càng sớm càng tốt trong chương trình TF2 của bạn, tốt nhất là sau các dòng nhập Python và trước khi bắt đầu xây dựng và thực thi đồ thị. Điều này sẽ đảm bảo bao quát đầy đủ tất cả các hoạt động và biểu đồ cung cấp năng lượng cho mô hình của bạn và việc đào tạo nó.

Các tensor_debug_modes hiện được hỗ trợ là: NO_TENSOR , CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTHSHAPE . Chúng khác nhau về lượng thông tin được trích xuất từ ​​mỗi tensor và chi phí hiệu suất cho chương trình được gỡ lỗi. Vui lòng tham khảo phần args trong tài liệu của enable_dump_debug_info() .

Chi phí hiệu suất

API gỡ lỗi giới thiệu chi phí hiệu suất cho chương trình TensorFlow được thiết kế. Chi phí thay đổi theo tensor_debug_mode , loại phần cứng và bản chất của chương trình TensorFlow có công cụ. Như một điểm tham chiếu, trên GPU, chế độ NO_TENSOR thêm 15% chi phí trong quá trình đào tạo mô hình Biến áp theo kích thước lô 64. Chi phí phần trăm cho các tensor_debug_modes khác cao hơn: khoảng 50% cho CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTHSHAPE các chế độ. Trên CPU, chi phí thấp hơn một chút. Trên các TPU, chi phí hiện đang cao hơn.

Liên quan đến các API gỡ lỗi TensorFlow khác

Lưu ý rằng TensorFlow cung cấp các công cụ và API khác để gỡ lỗi. Bạn có thể duyệt các API như vậy trong không gian tên tf.debugging.* Tại trang tài liệu API. Trong số các API này được sử dụng thường xuyên nhất là tf.print() . Khi nào thì nên sử dụng Debugger V2 và khi nào thì nên sử dụng tf.print() ? tf.print() rất tiện lợi trong trường hợp

  1. chúng tôi biết chính xác bộ căng nào để in,
  2. chúng tôi biết chính xác vị trí trong mã nguồn để chèn các câu lệnh tf.print() đó,
  3. số lượng các tenxơ như vậy không quá lớn.

Đối với các trường hợp khác (ví dụ: kiểm tra nhiều giá trị tensor, kiểm tra các giá trị tensor được tạo bởi mã nội bộ của TensorFlow và tìm kiếm nguồn gốc của sự không ổn định số như chúng tôi đã trình bày ở trên), Debugger V2 cung cấp một cách gỡ lỗi nhanh hơn. Ngoài ra, Debugger V2 cung cấp một cách tiếp cận thống nhất để kiểm tra các yếu tố gây háo hức và vẽ đồ thị. Nó cũng cung cấp thông tin về cấu trúc đồ thị và vị trí mã, những thông tin này nằm ngoài khả năng của tf.print() .

Một API khác có thể được sử dụng để gỡ lỗi các vấn đề liên quan đến ∞ và NaN là tf.debugging.enable_check_numerics() . Không giống như enable_dump_debug_info() , enable_check_numerics() không lưu thông tin gỡ lỗi trên đĩa. Thay vào đó, nó chỉ theo dõi ∞ và NaN trong thời gian chạy TensorFlow và phát hiện lỗi với vị trí mã gốc ngay khi bất kỳ op nào tạo ra các giá trị số xấu như vậy. Nó có chi phí hiệu suất thấp hơn so với enable_dump_debug_info() , nhưng không có dấu vết đầy đủ về lịch sử thực thi của chương trình và không đi kèm với giao diện người dùng đồ họa như Debugger V2.