Trang này được dịch bởi Cloud Translation API.
Switch to English

Gỡ lỗi các vấn đề về số trong các chương trình TensorFlow bằng cách sử dụng chươ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 sâu xa của những sự kiện như vậy thường rất mơ hồ, đặc biệt là đối với các mô hình có kích thước và độ phức tạp không tầm thường. Để dễ dàng gỡ lỗi loại lỗi mô hình này, TensorBoard 2.3+ (cùng với TensorFlow 2.3+) cung cấp một bảng điều khiển chuyên dụng 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 khắc phục một lỗi thực sự liên quan đến NaN trong một mạng lưới 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 như kiểm tra hình dạng tenor 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 tương đối cao.

Quan sát lỗi

Mã nguồn của chương trình TF2 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 vào gói pip tenorflow (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 một nhận thức nhiều lớp (MLP) và huấn luyện nó để nhận ra hình ảnh MNIST . Ví dụ này sử dụng API TF2 cấp thấp để xác định cấu trúc lớp tùy chỉnh, hàm mất và vòng huấn luyện, vì khả năng lỗi NaN cao hơn khi chúng tôi sử dụng API linh hoạt hơn nhưng dễ bị lỗi hơn so với khi chúng tôi sử dụng dễ dàng hơn sử dụng nhưng các API cấp cao ít linh hoạt hơn một chút, chẳng hạn như tf.keras .

Chương trình in độ chính xác kiểm tra 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 kiểm tra bị kẹt ở mức gần cơ hội (~ 0,1) sau bước đầu tiên. Đây chắc chắn không phải là cách đào tạo mô hình dự kiến ​​sẽ hành xử: chúng tôi hy vọng độ chính xác sẽ dần dần tiếp cận 1.0 (100%) khi bước 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 có giáo dục là vấn đề này được gây ra bởi sự mất ổ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 về số? Để trả lời những câu hỏi này, hãy sử dụng chương trình lỗi với Debugger V2.

Sử dụng mã TensorFlow với Debugger V2

tf.debugging.experimental.enable_dump_debug_info() là điểm nhập API của Debugger V2. Nó ghi một chương trình TF2 với một dòng mã. Chẳng hạn, việc thêm dòng sau gần đầu chương trình sẽ khiến thông tin gỡ lỗi được ghi vào thư mục log (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.feft , việc thực hiện các biểu đồ, các giá trị tenxơ đượ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 tối nghĩa.

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

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

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

Chế độ ĐẦY ĐỦ FULL_HEALTH Phù hợp để gỡ lỗi các 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.

Các circular_buffer_size điều khiển lập luận bao nhiêu sự kiện tensor được lưu vào logdir. Nó mặc định là 1000, điều này chỉ khiến 1000 tenor cuối cùng trước khi kết thúc chương trình TF2 được ghi vào đĩa. Hành vi mặc định này làm giảm chi phí trình gỡ lỗi bằng cách hy sinh tính đầy đủ 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 bộ đệ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 truyền 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 với công cụ gỡ lỗi này được bật, hãy làm:

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

Bắt đầu GUI gỡ lỗi V2 trong TensorBoard

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

 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. Mặc định, plugin Plugin Debugger V2 nên được kích hoạt theo mặc định, hiển thị một trang giống như sau:

Trình gỡ lỗi V2 xem toàn màn hình

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

GUI Debugger V2 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ủa người phát hiện bởi chương trình gỡ lỗi được phát hiện trong dữ liệu gỡ lỗi từ chương trình TensorFlow được ghi công cụ. Mỗi cảnh báo chỉ ra một sự bất thường nhất định đảm bảo sự chú ý. Trong trường hợp của chúng tôi, phần này làm nổi bật các sự kiện 499 NaN / with 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 học được vì sự hiện diện của NaN và / hoặc vô số trong các giá trị tenxơ bên trong của nó. Chúng tôi sẽ đi sâu vào những cảnh báo này trong thời gian ngắn.
  • Dòng thời gian thực thi Python : Đây là nửa trên của phần trên cùng giữa. Nó trình bày toàn bộ lịch sử của việc thực hiện háo hức các ops và đồ thị. Mỗi hộp của timeline được đánh dấu bằng ký tự ban đầu của op hoặc tên đồ thị của (ví dụ, “T” cho “TensorSliceDataset” op, “m” cho “mô hình” 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à trung tâm trong nhiệm vụ gỡ lỗi của chúng tôi. Nó chứa một lịch sử của tất cả các tenxơ dtype nổi được tính bên trong các biểu đồ (nghĩa là được biên dịch bởi @tf-function s).
  • Cấu trúc đồ thị (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.

Đã định hướng bản thân đến việc tổ chức UI, chúng ta hãy thực hiện các bước sau để đi đến tận cùng lý do tại sao NaN xuất hiện. Đầu tiên, nhấp vào cảnh báo NaN / in trong phần Cảnh báo. Điều này sẽ tự động cuộn danh sách 600 tenxơ đồ thị trong phần Thực thi đồ thị và tập trung vào # 88, đây là một tenxơ có tên là Log Log: 0 ấn được tạo bởi một Log (logarit tự nhiên) op. Một màu đỏ hồng nổi bật làm nổi bật một yếu tố -∞ trong số 1000 yếu tố của tenxơ 2D float32. Đây là tenxơ đầ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: các tenxơ được tính toán trước khi nó không chứa NaN hoặc; nhiều (trên thực tế, hầu hết) các tenxơ được tính toán sau đó có 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ự mất ổn định số trong chương trình TF2 này.

Trình gỡ lỗi V2: Cảnh báo Nan / Infinity và danh sách thực thi đồ thị

Tại sao Log này lại nhổ ra -∞? Trả lời câu hỏi đó yêu cầu kiểm tra đầu vào cho op. Nhấp vào tên của tenxơ (Nhật ký: 0 Nhật) sẽ hiển thị trực quan đơn giản nhưng nhiều 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 biểu đồ. Lưu ý hướng từ trên xuống dưới của luồng thông tin. Bản thân op được thể hiện bằng chữ in đậm ở giữa. Ngay lập tức phía trên nó, chúng ta có thể thấy một Placeholder op cung cấp đầu vào một và duy nhất cho Log op. Trường hợp tenor được tạo bởi bản ghi này Placeholder trong danh sách Thực thi đồ thị? Bằng cách sử dụng màu nền màu vàng làm công cụ hỗ trợ trực quan, chúng ta có thể thấy rằng các logits:0 tenor là hai hàng phía trên các Log:0 , nghĩa là, trong hàng 85.

Trình gỡ lỗi V2: Chế độ xem cấu trúc đồ thị và truy tìm tenxơ đầu vào

Một cái nhìn cẩn thận hơn về sự cố số của các bản ghi nhật ký: 0 tenxơ hàng trong 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 một -∞: Trong số 1000 phần tử của các bản ghi nhật ký: 0, một phần tử có giá trị 0. -∞ là kết quả của việc tính toán logarit tự nhiên bằng 0! Nếu bằng cách nào đó chúng tôi có thể đảm bảo rằng Log op 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 cắt (ví dụ: bằng cách sử dụng tf.clip_by_value () ) trên thang đo giữ chỗ của trình giữ chỗ.

Chúng tôi đang tiến gần hơn để giải quyết lỗi, nhưng chưa hoàn thành. Để áp dụng sửa lỗi, chúng ta cần biết mã nguồn Python ở đâu và đầu vào Placeholder của nó bắt nguồn từ đâu. Trình gỡ lỗi V2 cung cấp hỗ trợ hạng nhất để truy tìm các biểu đồ ops và các sự kiện thực thi đối với nguồn của chúng. Khi chúng tôi nhấp vào tenor Log:0 trong Thực thi đồ thị, phần Stack Trace đã được điền với dấu vết ngăn xếp ban đầu của sáng tạo của Log op. Theo dõi ngăn xếp có phần 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à dumping_callback.py), mà chúng ta có thể bỏ qua một cách an toàn cho 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 (nghĩa là tệp Python chúng tôi thực sự đang cố gắng gỡ lỗi). Nhấp vào dòng Line 204 204 sẽ hiển thị chế độ xem dòng mã tương ứng trong phần Mã nguồn.

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

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

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

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

Nó sẽ giải quyết sự mất ổn định về số trong chương trình TF2 này và khiến MLP đào tạo thành công. Một cách tiếp cận khả thi khác để khắc phục sự mất ổn định về 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à biểu đồ của chương trình TF2, bao gồm cả tóm tắt bằng số giá trị tenxơ và liên kết giữa ops, tenor và mã nguồn gốc 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 bao gồm CPU và GPU. Đào tạo đa GPU với tf.distribution.MirroredStrargety cũng được hỗ trợ. Hỗ trợ cho TPU vẫn còn ở giai đoạn đầu và yêu cầ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 trên TPU. Nếu bạn gặp vấn đề khi sử dụng Debugger 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 Debugger V2

Trình gỡ lỗi V2 được triển khai ở cấp độ ngăn xếp phần mềm tương đối thấp 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 đối với các logdir 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à ở đâu trong mã TensorFlow, người ta nên chèn lệnh gọi tới enable_dump_debug_info() . Thông thường, API nên đượ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 khi các dòng nhập Python và trước khi bắt đầu xây dựng và thực hiện đồ thị. Điều này sẽ đảm bảo phạm vi bảo hiểm đầy đủ của tất cả các op và đồ thị cung cấp năng lượng cho mô hình của bạn và đào tạo của nó.

Các tenor_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 tenor và chi phí hiệu năng cho chương trình 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í hoạt động

API gỡ lỗi giới thiệu chi phí hoạt động cho chương trình TensorFlow được ghi công cụ. Chi phí hoạt động khác nhau tùy theo tensor_debug_mode , loại phần cứng và bản chất của chương trình TensorFlow được ghi công cụ. Như một điểm tham chiếu, trên GPU, các NO_TENSOR chế độ bổ sung thêm một chi phí 15% trong việc đào tạo một mô hình Transformer dưới kích thước hàng loạt 64. Các 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 TPU, chi phí hiện tại cao hơn.

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

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 nên sử dụng Debugger V2 và khi nào nên sử dụng tf.print() ? tf.print() thuận tiện trong trường hợp

  1. chúng tôi biết chính xác những gì tenors để in,
  2. chúng ta biết chính xác nơi mã nguồn để chèn các câu lệnh tf.print() ,
  3. số lượng tenor 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ị tenxơ, kiểm tra các giá trị tenxơ được tạo bởi mã nội bộ của TensorFlow và tìm kiếm nguồn gốc của sự mất ổn định số như chúng tôi đã trình bày ở trên), Debugger V2 cung cấp 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 tenxơ háo hức và đồ thị. Nó cũng cung cấp thông tin về cấu trúc biểu đồ và vị trí mã, vượt quá 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ỉ giám sát và NaN trong thời gian chạy TensorFlow và lỗi với vị trí mã nguồn 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í hoạt động thấp hơn so với enable_dump_debug_info() , nhưng không đủ khả năng theo dõi lịch sử thực hiện 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.