이 페이지는 Cloud Translation API를 통해 번역되었습니다.
Switch to English

TensorBoard Debugger V2를 사용하여 TensorFlow 프로그램의 숫자 문제 디버깅

NaN 과 관련된 치명적인 이벤트는 때때로 TensorFlow 프로그램 중에 발생하여 모델 교육 프로세스를 방해 할 수 있습니다. 이러한 사건의 근본 원인은 특히 모호하지 않은 크기와 복잡한 모델의 경우 모호합니다. 이러한 유형의 모델 버그를 쉽게 디버깅 할 수 있도록 TensorBoard 2.3+ (TensorFlow 2.3+와 함께)는 Debugger V2라는 특수 대시 보드를 제공합니다. 여기서는 TensorFlow로 작성된 신경망에서 NaN과 관련된 실제 버그를 통해이 도구를 사용하는 방법을 보여줍니다.

이 튜토리얼에 설명 된 기술은 복잡한 프로그램에서 런타임 텐서 모양 검사와 같은 다른 유형의 디버깅 활동에 적용 할 수 있습니다. 이 튜토리얼에서는 발생 빈도가 상대적으로 높기 때문에 NaN에 중점을 둡니다.

버그 관찰

우리가 디버깅 할 TF2 프로그램의 소스 코드는 GitHub에서 구할 수 있습니다 . 예제 프로그램은 또한 tensorflow pip 패키지 (버전 2.3+)로 패키지되며 다음을 통해 호출 할 수 있습니다.

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

이 TF2 프로그램은 MLP (Multi-Layer Perception)를 생성하고 MNIST 이미지를 인식하도록 훈련시킵니다. 이 예제는 TF2의 저수준 API를 의도적으로 사용하여 사용자 정의 계층 구조, 손실 함수 및 교육 루프를 정의합니다. NaN 버그가 더 유연하지만 오류가 발생하기 쉬운 API를 사용할 때 더 쉽습니다. tf.keras 와 같이 사용하기 쉽지만 약간 덜 유연한 고급 API입니다.

이 프로그램은 각 교육 단계 후에 테스트 정확도를 인쇄합니다. 콘솔에서 첫 번째 단계 후에 테스트 정확도가 거의 확률 수준 (~ 0.1)에 고정되어 있음을 알 수 있습니다. 이것은 모델 훈련이 예상되는 방식이 아닙니다. 단계가 증가함에 따라 정확도가 점차 1.0 (100 %)에 도달 할 것으로 예상합니다.

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

교육적인 추측에 따르면이 문제는 NaN 또는 무한대와 같은 수치 적 불안정성으로 인해 발생합니다. 그러나 이것이 실제로 사실임을 확인하는 방법과 수치 적 불안정성을 생성하는 TensorFlow 작업 (op)을 어떻게 찾을 수 있습니까? 이러한 질문에 답하기 위해 Debugger V2로 버기 프로그램을 인스트루먼트하자.

디버거 V2를 사용한 TensorFlow 코드 계측

tf.debugging.experimental.enable_dump_debug_info() 는 디버거 V2의 API 진입 점입니다. 한 줄의 코드로 TF2 프로그램을 계측합니다. 예를 들어, 프로그램 시작 부분에 다음 행을 추가하면 디버그 정보가 / tmp / tfdbg2_logdir의 로그 디렉토리 (logdir)에 기록됩니다. 디버그 정보는 TensorFlow 런타임의 다양한 측면을 다룹니다. TF2에는 열성적인 실행, @ tf.function으로 수행되는 그래프 작성, 그래프 실행, 실행 이벤트로 생성 된 텐서 값 및 해당 이벤트의 코드 위치 (Python 스택 추적)에 대한 전체 히스토리가 포함됩니다. . 풍부한 디버그 정보를 통해 사용자는 모호한 버그를 좁힐 수 있습니다.

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

tensor_debug_mode 인수는 디버거 V2가 각 열망 또는 그래프 내 텐서에서 추출하는 정보를 제어합니다. "FULL_HEALTH"는 각 부동 유형 텐서 (예 : 일반적으로 보이는 float32 및 덜 일반적인 bfloat16 dtype)에 대한 다음 정보를 캡처하는 모드입니다.

  • D 타입
  • 계급
  • 총 요소 수
  • 부동 유형 요소를 음의 유한 ( - ), 0 ( 0 ), 양의 유한 ( + ), 음의 무한대 ( -∞ ), 양의 무한대 ( +∞ ) 및 NaN 합니다.

"FULL_HEALTH"모드는 NaN 및 무한대와 관련된 버그를 디버깅하는 데 적합합니다. 지원되는 다른 tensor_debug_mode 대해서는 아래를 참조하십시오.

circular_buffer_size 인수는 logdir에 저장되는 텐서 이벤트 수를 제어합니다. 기본값은 1000으로, 인스트루먼트 된 TF2 프로그램이 종료되기 전에 마지막 1000 개의 텐서 만 디스크에 저장됩니다. 이 기본 동작은 디버그 데이터 완성도를 희생하여 디버거 오버 헤드를 줄입니다. 이 경우와 같이 완전성이 선호되는 경우 인수를 음수 값 (예 : -1)으로 설정하여 순환 버퍼를 비활성화 할 수 있습니다.

debug_mnist_v2 예제는 명령 행 플래그를 전달하여 enable_dump_debug_info() 를 호출합니다. 이 디버깅 계측을 사용하여 문제가있는 TF2 프로그램을 다시 실행하려면 다음을 수행하십시오.

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

TensorBoard에서 디버거 V2 GUI 시작

디버거 계측으로 프로그램을 실행하면 / tmp / tfdbg2_logdir에 logdir이 생성됩니다. TensorBoard를 시작하고 다음과 같이 logdir을 가리킬 수 있습니다.

 tensorboard --logdir /tmp/tfdbg2_logdir
 

웹 브라우저에서 http : // localhost : 6006의 TensorBoard 페이지로 이동하십시오. “Debugger V2”플러그인은 기본적으로 활성화되어 다음과 같은 페이지를 표시합니다.

디버거 V2 전체 화면보기

Nager의 근본 원인을 찾기 위해 Debugger V2 GUI 사용

TensorBoard의 Debugger V2 GUI는 6 개의 섹션으로 구성되어 있습니다.

  • 경고 :이 왼쪽 상단 섹션에는 계측 된 TensorFlow 프로그램의 디버그 데이터에서 디버거가 감지 한 "경고"이벤트 목록이 포함되어 있습니다. 각 경고는주의가 필요한 특정 이상을 나타냅니다. 이 경우이 섹션에서는 두드러진 분홍색-빨간색의 499 NaN / ∞ 이벤트를 강조합니다. 이는 내부 텐서 값에 NaN 및 / 또는 무한대의 존재로 인해 모델이 학습에 실패한 것으로 의심됩니다. 우리는 이러한 경고를 곧 알아볼 것입니다.
  • Python Execution Timeline : 상단 중간 부분의 상단입니다. 그것은 op와 그래프의 열망 한 실행의 전체 역사를 제시합니다. 타임 라인의 각 상자는 op 또는 그래프 이름의 초기 문자로 표시됩니다 (예 : "TensorSliceDataset"op의 경우 "T", "model" tf.function 의 경우 "m"). 탐색 버튼과 타임 라인 위의 스크롤 막대를 사용하여이 타임 라인을 탐색 할 수 있습니다.
  • 그래프 실행 : GUI의 오른쪽 상단에 위치한이 섹션은 디버깅 작업의 중심입니다. 여기에는 그래프 내에서 계산 된 모든 부동 dtype 텐서의 기록이 포함됩니다 (예 : @tf-function 컴파일).
  • 그래프 구조 (맨 위 중간 섹션의 아래쪽 절반), 소스 코드 (왼쪽 아래 섹션) 및 스택 추적 (오른쪽 아래 섹션)은 처음에 비어 있습니다. GUI와 상호 작용할 때 내용이 채워집니다. 이 세 섹션은 또한 디버깅 작업에서 중요한 역할을합니다.

UI 구성에 중점을두고 다음 단계를 수행하여 NaN이 나타나는 이유를 알아 봅니다. 먼저 경고 섹션에서 NaN / ∞ 경고를 클릭하십시오. 그러면 그래프 실행 섹션에서 600 개의 그래프 텐서 목록이 자동으로 스크롤되고 # 88 ( Log (자연 로그) op에 의해 생성 된 "Log : 0"텐서)에 초점이 맞춰집니다. 두드러진 분홍색-빨간색은 2D float32 텐서의 1000 개 요소 중 -∞ 요소를 강조 표시합니다. 이것은 NaN 또는 무한대를 포함하는 TF2 프로그램 런타임 히스토리의 첫 번째 텐서입니다. 텐서는 NaN 또는 ∞를 포함하지 않기 전에 계산됩니다. 나중에 계산 된 많은 (실제로 대부분의) 텐서는 NaN을 포함합니다. 그래프 실행 목록을 위아래로 스크롤하여 확인할 수 있습니다. 이 관찰은 Log op가이 TF2 프로그램의 수치 적 불안정성의 원천이라는 강력한 힌트를 제공합니다.

디버거 V2 : Nan / Infinity 경고 및 그래프 실행 목록

Log 가 왜 -∞를 내뿜습니까? 이 질문에 대답하려면 op에 대한 입력을 검사해야합니다. 텐서 이름 ( "Log : 0")을 클릭하면 그래프 구조 섹션의 TensorFlow 그래프에서 Log op 주변을 간단하지만 유익하게 시각화 할 수 있습니다. 정보 흐름의 상단에서 하단 방향에 유의하십시오. op 자체는 중간에 굵게 표시되어 있습니다. 바로 위에 자리 표시 자 op가 Log op에 대한 유일한 입력을 제공함을 알 수 있습니다. 이 로그에 의해 생성 된 텐서는 그래프 실행 목록에서 어디에 위치합니까? 노란색 배경색을 시각 보조 도구로 사용하면 logits:0 텐서가 Log:0 텐서 위의 두 행, 즉 85 행에 있음을 알 수 있습니다.

디버거 V2 : 그래프 구조보기 및 입력 텐서 추적

85 행의 "logits : 0"텐서의 수치 분석을보다 면밀히 살펴보면 소비자 Log:0 이 -∞을 생성하는 이유를 알 수 있습니다. "logits : 0"의 1000 개 요소 중 한 요소의 값은 0입니다. -∞는 0의 자연 로그를 계산 한 결과입니다! Log op가 양의 입력에만 노출되도록 보장 할 수 있다면 NaN / ∞이 발생하는 것을 막을 수 있습니다. 플레이스 홀더 로짓 텐서에 클리핑 (예 : tf.clip_by_value () 사용 )을 적용하면됩니다.

버그 해결에 가까워지고 있지만 아직 완료되지 않았습니다. 수정 사항을 적용하려면 Python 소스 코드에서 Log op 및 플레이스 홀더 입력이 시작된 위치를 알아야합니다. 디버거 V2는 그래프 ops 및 실행 이벤트를 소스로 추적하는 일류 지원을 제공합니다. Graph Executions에서 Log:0 텐서를 클릭하면 스택 추적 섹션이 Log op 생성의 원래 스택 추적으로 채워졌습니다. 스택 추적은 TensorFlow의 내부 코드 (예 : gen_math_ops.py 및 dumping_callback.py)의 많은 프레임을 포함하므로 다소 크므로 대부분의 디버깅 작업에서 무시해도됩니다. 관심있는 프레임은 debug_mnist_v2.py의 216 행입니다 (즉, 실제로 디버깅하려는 Python 파일). “Line 204”를 클릭하면 소스 코드 섹션에 해당 코드 줄이 표시됩니다.

디버거 V2 : 소스 코드 및 스택 추적

이는 결국 logits 입력에서 문제가있는 Log op를 생성 한 소스 코드로 연결됩니다. 이것은 @tf.function 장식 된 맞춤형 범주 형 엔트로피 손실 함수이므로 TensorFlow 그래프로 변환됩니다. 자리 표시 자 op "logits"는 손실 함수에 대한 첫 번째 입력 인수에 해당합니다. Log op는 tf.math.log () API 호출로 작성됩니다.

이 버그에 대한 가치 자르기 수정은 다음과 같습니다.

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

이 TF2 프로그램의 수치 적 불안정성을 해결하고 MLP를 성공적으로 훈련시킵니다. 수치 적 불안정성을 수정하는 또 다른 방법은 tf.keras.losses.CategoricalCrossentropy 를 사용하는 tf.keras.losses.CategoricalCrossentropy 입니다.

이것으로 TF2 모델 버그 관찰부터 디버거 V2 툴의 도움으로 버그를 수정하는 코드 변경에 이르기까지의 여정을 마치고 수치 요약을 포함하여 인스트루먼트 된 TF2 프로그램의 열망 및 그래프 실행 히스토리에 대한 완전한 가시성을 제공합니다. 텐서 값과 op, 텐서 및 원래 소스 코드 간의 연관성.

디버거 V2의 하드웨어 호환성

디버거 V2는 CPU 및 GPU를 포함한 주류 ​​교육 하드웨어를 지원합니다. tf.distributed.MirroredStrategy를 사용한 다중 GPU 교육도 지원됩니다. TPU 지원은 아직 초기 단계이며 전화가 필요합니다

 tf.config.set_soft_device_placement(True)
 

enable_dump_debug_info() 를 호출하기 전에 TPU에도 다른 제한이있을 수 있습니다. Debugger V2 사용에 문제가 발생하면 GitHub 문제 페이지 에서 버그를보고 하십시오 .

디버거 V2의 API 호환성

디버거 V2는 비교적 낮은 수준의 TensorFlow 소프트웨어 스택에서 구현되므로 tf.keras , tf.data 및 TensorFlow의 낮은 수준 위에 구축 된 기타 API와 호환됩니다. 디버거 V2는 TF1과 역 호환되지만 Eager 실행 타임 라인은 TF1 프로그램에서 생성 된 디버그 로그 디렉토리에 대해 비어 있습니다.

API 사용법 팁

이 디버깅 API에 대해 자주 묻는 질문은 TensorFlow 코드에서 enable_dump_debug_info() 대한 호출을 삽입해야하는 위치입니다. 일반적으로 API는 TF2 프로그램에서 가능한 한 빨리 호출해야합니다. 바람직하게는 Python 가져 오기 라인 이후와 그래프 작성 및 실행이 시작되기 전에 가능합니다. 이를 통해 모델과 교육을 강화하는 모든 op 및 그래프를 완벽하게 커버 할 수 있습니다.

현재 지원되는 tensor_debug_mode는 NO_TENSOR , CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTHSHAPE 입니다. 각 텐서에서 추출 된 정보의 양과 디버깅 된 프로그램에 대한 성능 오버 헤드가 다릅니다. enable_dump_debug_info() 문서]의 args 섹션 을 참조하십시오.

성능 오버 헤드

디버깅 API는 계측 된 TensorFlow 프로그램에 성능 오버 헤드를 발생시킵니다. 오버 헤드는 tensor_debug_mode , 하드웨어 유형 및 인스트루먼트 된 TensorFlow 프로그램의 특성에 따라 다릅니다. 참고로 GPU에서 NO_TENSOR 모드는 배치 크기 64에서 Transformer 모델을 훈련하는 동안 15 %의 오버 헤드를 추가합니다. 다른 tensor_debug_mode의 오버 헤드 백분율이 더 높습니다. CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTHSHAPE 경우 약 50 % 모드. CPU에서 오버 헤드는 약간 낮습니다. TPU에서 오버 헤드는 현재 더 높습니다.

다른 TensorFlow 디버깅 API와의 관계

TensorFlow는 디버깅을위한 다른 도구와 API를 제공합니다. API 문서 페이지의 tf.debugging.* 네임 스페이스 에서 이러한 API를 찾아 볼 수 있습니다. 이러한 API 중에서 가장 자주 사용되는 것은 tf.print() 입니다. 언제 디버거 V2를 사용해야하고 언제 tf.print() 대신 사용해야합니까? tf.print() 는 편리한 경우에 편리합니다

  1. 인쇄 할 텐서를 정확히 알고
  2. 우리는 소스 코드에서 정확히 tf.print() 문을 삽입 할 위치를 알고 있습니다.
  3. 그러한 텐서의 수는 너무 크지 않습니다.

다른 경우 (예 : 많은 텐서 값 검사, TensorFlow의 내부 코드에 의해 생성 된 텐서 값 검사 및 위에서 보여준 수치 불안정의 원점 검색) Debugger V2는 더 빠른 디버깅 방법을 제공합니다. 또한 Debugger V2는 열망 및 그래프 텐서를 검사하는 통합 된 접근 방식을 제공합니다. 또한 tf.print() 의 기능을 넘어서는 그래프 구조 및 코드 위치에 대한 정보를 제공합니다.

∞ 및 NaN과 관련된 문제를 디버깅하는 데 사용할 수있는 또 다른 API는 tf.debugging.enable_check_numerics() 입니다. enable_dump_debug_info() 와 달리 enable_check_numerics() 는 디스크에 디버그 정보를 저장하지 않습니다. 대신 TensorFlow 런타임 동안 ∞ 및 NaN을 모니터링하고 op가 잘못된 숫자 값을 생성하는 즉시 원점 코드 위치에서 오류가 발생합니다. enable_dump_debug_info() 비해 성능 오버 헤드가 낮지 만 프로그램의 실행 기록을 추적 할 수 없으며 Debugger V2와 같은 그래픽 사용자 인터페이스가 제공되지 않습니다.