텐서 플로 기능의 이중 수명

텐서 플로 기능의 이중 수명

콘텐츠 개요

Tensorflow 2에서 열렬한 실행 기본적으로 켜집니다. 사용자 인터페이스는 직관적이고 유연합니다 (일회성 작업을 실행하는 것이 훨씬 쉽고 빠릅니다). 그러나 이는 성능과 배포 성을 희생시킬 수 있습니다.

당신은 사용할 수 있습니다 tf.function 프로그램에서 그래프를 만듭니다. 파이썬 코드에서 파이썬 독립적 인 데이터 흐름 그래프를 생성하는 변환 도구입니다. 이것은 성능 및 휴대용 모델을 만드는 데 도움이되며 사용해야합니다. SavedModel.

이 안내서는 방법을 개념화하는 데 도움이됩니다 tf.function 후드 아래에서 작동하므로 효과적으로 사용할 수 있습니다.

주요 테이크 아웃 및 권장 사항은 다음과 같습니다.

  • 열성적인 모드로 디버그 한 다음 장식하십시오 @tf.function.

  • 물체 돌연변이 또는 목록 추가와 같은 파이썬 부작용에 의존하지 마십시오.

  • tf.function Tensorflow OPS와 가장 잘 작동합니다. Numpy 및 Python 호출은 상수로 변환됩니다.

설정

import tensorflow as tf
2024-08-15 02:57:28.958444: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered
2024-08-15 02:57:28.979712: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered
2024-08-15 02:57:28.986177: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered

도우미 기능을 정의하여 발생할 수있는 오류의 종류를 보여줍니다.

import traceback
import contextlib

# Some helper code to demonstrate the kinds of errors you might encounter.
@contextlib.contextmanager
def assert_raises(error_class):
  try:
    yield
  except error_class as e:
    print('Caught expected exception \n  {}:'.format(error_class))
    traceback.print_exc(limit=2)
  except Exception as e:
    raise e
  else:
    raise Exception('Expected {} to be raised but no error was raised!'.format(
        error_class))

기초

용법

에이 tf.function 당신이 정의하는 것 (예 : 적용하여 @tf.function Decorator)는 핵심 텐서 플로 작동과 같습니다. 간절히 실행할 수 있습니다. 그라디언트를 계산할 수 있습니다. 등.

@tf.function  # The decorator converts `add` into a `PolymorphicFunction`.
def add(a, b):
  return a + b

add(tf.ones([2, 2]), tf.ones([2, 2]))  #  [[2., 2.], [2., 2.]]
tf.ones([2, 2]), tf.ones([2, 2]))  #  [[2., 2.], [2., 2.]]

WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1723690651.607368  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.611235  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.614398  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.618234  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.629890  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.633433  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.636337  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.639748  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.643233  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.646588  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.649526  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690651.652949  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.865955  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.868101  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.870112  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.872121  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.874165  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.876153  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.878068  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.879960  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.881883  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.883841  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.885768  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.887660  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.926250  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.928321  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.930298  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.932288  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.934241  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.936253  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.938172  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.940080  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.942041  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.944593  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.946947  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 
I0000 00:00:1723690652.949245  167534 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at 

v = tf.Variable(1.0)
with tf.GradientTape() as tape:
  result = add(v, 1.0)
tape.gradient(result, v)

당신은 사용할 수 있습니다 tf.function다른 내부 tf.function에스.

@tf.function
def dense_layer(x, w, b):
  return add(tf.matmul(x, w), b)

dense_layer(tf.ones([3, 2]), tf.ones([2, 2]), tf.ones([2]))

tf.functionS는 특히 작은 작전이있는 그래프의 경우 열망하는 코드보다 빠를 수 있습니다. 그러나 비싼 OP가 몇 개있는 그래프 (컨볼 루션과 같은)의 경우 많은 속도를 보이지 않을 수 있습니다.

import timeit
conv_layer = tf.keras.layers.Conv2D(100, 3)

@tf.function
def conv_fn(image):
  return conv_layer(image)

image = tf.zeros([1, 200, 200, 100])
# Warm up
conv_layer(image); conv_fn(image)
print("Eager conv:", timeit.timeit(lambda: conv_layer(image), number=10))
print("Function conv:", timeit.timeit(lambda: conv_fn(image), number=10))
print("Note how there's not much difference in performance for convolutions")
W0000 00:00:1723690654.228267  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.285525  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.290477  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.295072  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.299820  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.304580  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.322737  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.327483  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.332646  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.337747  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.343046  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.347480  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.361780  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.370325  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.381185  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1723690654.405763  167534 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
Eager conv: 0.011224052000216034
Function conv: 0.005400947000453016
Note how there's not much difference in performance for convolutions

트레이싱

이 섹션은 향후 변경 될 수있는 구현 세부 사항을 포함하여 TF. 기능이 후드 아래에서 작동하는 방식을 노출시킵니다. 그러나 추적이 발생하는 이유와시기를 이해하면 TF. 기능을 효과적으로 사용하는 것이 훨씬 쉽습니다!

“추적”이란 무엇입니까?

TF. 기능은 텐서 플로 그래프로 프로그램을 실행합니다. 그러나 TF.Graph는 열망하는 Tensorflow 프로그램에 쓸 모든 것을 나타내는 것은 아닙니다. 예를 들어, Python은 다형성을 지원하지만 tf.graph에는 입력이 지정된 데이터 유형과 차원을 갖도록 요구합니다. 또는 명령 줄 인수를 읽거나 오류를 높이거나보다 복잡한 파이썬 객체로 작업하는 것과 같은 측면 작업을 수행 할 수 있습니다. 이러한 것들 중 어느 것도 tf.graph에서 실행할 수 없습니다.

TF. 기능은 코드를 두 단계로 분리 하여이 차이를 연결합니다.

  1. “추적”이라고하는 첫 번째 단계에서 TF.Function은 새로운 tf.graph를 만듭니다. 파이썬 코드는 정상적으로 실행되지만 모든 텐서 플로우 작업 (예 : 두 텐서 추가)은 연기됩니다. TF.Graph에 의해 캡처되고 실행되지 않습니다.
  2. 두 번째 단계에서는 첫 번째 단계에서 연기 된 모든 것을 포함하는 TF.Graph가 실행됩니다. 이 단계는 추적 단계보다 훨씬 빠릅니다.

입력에 따라 TF. 기능이 호출 될 때 항상 첫 번째 단계를 실행하지는 않습니다. 그것이 어떻게 결정을 내리는지를 더 잘 이해하려면 아래의 “추적 규칙”을 참조하십시오. 첫 번째 단계를 건너 뛰고 두 번째 단계 만 실행하는 것은 Tensorflow의 고성능을 제공합니다.

TF.Function이 추적하기로 결정하면 추적 단계는 즉시 두 번째 단계가 이어 지므로 TF.Function을 호출하십시오. 둘 다 TF.Graph를 생성하고 실행합니다. 나중에 get_concrete_function으로 추적 단계 만 실행할 수있는 방법을 볼 수 있습니다.

다른 유형의 인수를 TF. 기능으로 전달하면 두 단계 모두 실행됩니다.

@tf.function
def double(a):
  print("Tracing with", a)
  return a + a

print(double(tf.constant(1)))
print()
print(double(tf.constant(1.1)))
print()
print(double(tf.constant("a")))
print()
Tracing with Tensor("a:0", shape=(), dtype=int32)
tf.Tensor(2, shape=(), dtype=int32)

Tracing with Tensor("a:0", shape=(), dtype=float32)
tf.Tensor(2.2, shape=(), dtype=float32)

Tracing with Tensor("a:0", shape=(), dtype=string)
tf.Tensor(b'aa', shape=(), dtype=string)

반복적으로 전화하면 a tf.function 동일한 인수 유형을 사용하면 Tensorflow는 생성 된 그래프가 동일하기 때문에 추적 단계를 건너 뛰고 이전에 추적 된 그래프를 재사용합니다.

# This doesn't print 'Tracing with ...'
print(double(tf.constant("b")))
tf.Tensor(b'bb', shape=(), dtype=string)

당신은 사용할 수 있습니다 pretty_printed_concrete_signatures() 사용 가능한 모든 트레이스를 보려면 :

print(double.pretty_printed_concrete_signatures())
Input Parameters:
  a (POSITIONAL_OR_KEYWORD): TensorSpec(shape=(), dtype=tf.int32, name=None)
Output Type:
  TensorSpec(shape=(), dtype=tf.int32, name=None)
Captures:
  None

Input Parameters:
  a (POSITIONAL_OR_KEYWORD): TensorSpec(shape=(), dtype=tf.float32, name=None)
Output Type:
  TensorSpec(shape=(), dtype=tf.float32, name=None)
Captures:
  None

지금까지, 당신은 그것을 보았습니다 tf.function Tensorflow의 그래프 추적 로직 위에 캐시 된 동적 디스패치 레이어를 만듭니다. 용어에 대해보다 구체적으로 :

  • 에이 tf.Graph 텐서 플로 계산의 원시적이고 언어에 비해 휴대 할 수있는 표현입니다.
  • 추적은 새로운 과정입니다 tf.GraphS는 파이썬 코드에서 생성됩니다.
  • 인스턴스 tf.Graph 추적 된 특정 입력 유형에 특화되어 있습니다. 다른 유형은 회복이 필요합니다.
  • 각각 추적 tf.Graph 해당합니다 ConcreteFunction.
  • 에이 tf.function 캐시를 관리합니다 ConcreteFunctions와 입력에 맞는 올바른 것을 선택하십시오.
  • tf.function 추적 될 파이썬 함수를 랩핑하여 tf.types.experimental.PolymorphicFunction 물체.

추적 규칙

호출되면 a tf.function 먼저 다음을 사용하여 각 입력 인수의 유형을 평가합니다. tf.types.experimental.TraceType 각 주장의. 이것은 a를 구성하는 데 사용됩니다 tf.types.experimental.FunctionType 원하는 서명을 설명합니다 ConcreteFunction. 우리는 이것을 비교합니다 FunctionTypeFunctionType기존의 s ConcreteFunction에스. 일치하는 경우 ConcreteFunction 발견되면 호출이 파견됩니다. 일치하지 않으면 새로운 ConcreteFunction 원하는대로 추적됩니다 FunctionType.

여러 경기가 발견되면 가장 구체적인 서명이 선택됩니다. 예를 들어 C ++ 또는 Java의 일반 기능 호출과 마찬가지로 서브 타입으로 일치합니다. 예를 들어, TensorShape([1, 2]) 하위 유형입니다 TensorShape([None, None]) 그리고 TF.Function에 대한 호출 TensorShape([1, 2]) The에 파견 될 수 있습니다 ConcreteFunction 제작 TensorShape([None, None]) 그러나 만약 a ConcreteFunction ~와 함께 TensorShape([1, None]) 또한 더 구체적이므로 우선 순위가 지정됩니다.

그만큼 TraceType 다음과 같이 입력 인수로부터 결정됩니다.

  • 을 위한 Tensor유형은 매개 변수로 매개 변수입니다 Tensor‘에스 dtype 그리고 shape; 순위 형태는 해지되지 않은 모양의 하위 유형입니다. 고정 치수는 알려지지 않은 치수의 하위 유형입니다

  • 을 위한 Variable유형은 비슷합니다 Tensor변수의 고유 리소스 ID가 포함되어 있으며 제어 의존성을 올바르게 와이어와 전선하는 데 필요합니다.

  • 파이썬 원시 값의 경우, 유형은 그 자체. 예를 들어, TraceType 가치의 3 ~이다 LiteralTraceType~ 아니다 int.

  • 파이썬 주문 컨테이너의 경우 list 그리고 tuple등. 유형은 요소의 유형에 의해 매개 변수화된다. 예를 들어, 유형 [1, 2] ~이다 ListTraceType, LiteralTraceType> 그리고 유형 [2, 1] ~이다 ListTraceType, LiteralTraceType> 다른 것은 다릅니다.

  • Python Mappings와 같은 dict유형은 또한 동일한 키의 매핑이지만 실제 값 대신 값 유형에 이르기까지합니다. 예를 들어, 유형 {1: 2, 3: 4}~이다 MappingTraceType>>, >>>. 그러나 주문한 컨테이너와 달리 {1: 2, 3: 4} 그리고 {3: 4, 1: 2} 동등한 유형이 있습니다.

  • 구현하는 파이썬 객체의 경우 __tf_tracing_type__ 방법, 유형은 그 메소드가 반환하는 모든 것입니다.

  • 다른 Python 객체의 경우 유형은 일반입니다. TraceType일치하는 선례는 다음과 같습니다.

    • 먼저 객체가 이전 트레이스에서 사용 된 것과 동일한 객체인지 확인합니다 (Python 사용 id() 또는 is). 객체가 변경된 경우에도 여전히 일치하므로 Python 객체를 사용하는 경우 tf.function 인수 사용하는 것이 가장 좋습니다 불변 하나.
    • 다음으로 객체가 이전 트레이스에 사용 된 객체와 동일인지 확인합니다 (Python 사용 ==).

    메모 이 절차는 객체에 대한 약점을 유지하므로 객체가 범위에 있거나 삭제되지 않는 한만 작동합니다.

메모: TraceType THE를 기반으로합니다 tf.function 입력 매개 변수를 통해 전역으로 변경됩니다 자유 변수 혼자서는 새로운 흔적을 만들지 않습니다. 보다 이 섹션 Python Global 및 Free 변수를 다룰 때 권장되는 관행.

회복 제어

회복, 당신의시기입니다 tf.function 둘 이상의 트레이스를 생성하여 텐서 플로가 각 입력 세트에 대해 올바른 그래프를 생성하도록합니다. 그러나 추적은 값 비싼 작업입니다! 당신의 경우 tf.function 모든 통화마다 새 그래프를 되돌리면 사용하지 않은 경우보다 코드가 더 느리게 실행된다는 것을 알 수 있습니다. tf.function.

추적 행동을 제어하려면 다음 기술을 사용할 수 있습니다.

고정을 통과하십시오 input_signature 에게 tf.function

이 힘 tf.function 하나만으로 제한합니다 tf.types.experimental.FunctionType 에 의해 열거 된 유형으로 구성됩니다 input_signature. 이것에 파견 할 수없는 전화 FunctionType 오류가 발생합니다.

@tf.function(input_signature=(tf.TensorSpec(shape=[None], dtype=tf.int32),))
def next_collatz(x):
  print("Tracing with", x)
  return tf.where(x % 2 == 0, x // 2, 3 * x + 1)

print(next_collatz(tf.constant([1, 2])))
# You specified a 1-D tensor in the input signature, so this should fail.
with assert_raises(TypeError):
  next_collatz(tf.constant([[1, 2], [3, 4]]))

# You specified an int32 dtype in the input signature, so this should fail.
with assert_raises(TypeError):
  next_collatz(tf.constant([1.0, 2.0]))

Tracing with Tensor("x:0", shape=(None,), dtype=int32)
tf.Tensor([4 1], shape=(2,), dtype=int32)
Caught expected exception 
  :
Caught expected exception 
  :
Traceback (most recent call last):
  File "/tmpfs/tmp/ipykernel_167534/3551158538.py", line 8, in assert_raises
    yield
  File "/tmpfs/tmp/ipykernel_167534/3657259638.py", line 9, in 
    next_collatz(tf.constant([[1, 2], [3, 4]]))
TypeError: Binding inputs to tf.function failed due to `Can not cast TensorSpec(shape=(2, 2), dtype=tf.int32, name=None) to TensorSpec(shape=(None,), dtype=tf.int32, name=None)`. Received args: (,) and kwargs: {} for signature: (x: TensorSpec(shape=(None,), dtype=tf.int32, name=None)).
Traceback (most recent call last):
  File "/tmpfs/tmp/ipykernel_167534/3551158538.py", line 8, in assert_raises
    yield
  File "/tmpfs/tmp/ipykernel_167534/3657259638.py", line 13, in 
    next_collatz(tf.constant([1.0, 2.0]))
TypeError: Binding inputs to tf.function failed due to `Can not cast TensorSpec(shape=(2,), dtype=tf.float32, name=None) to TensorSpec(shape=(None,), dtype=tf.int32, name=None)`. Received args: (,) and kwargs: {} for signature: (x: TensorSpec(shape=(None,), dtype=tf.int32, name=None)).

유연성을 위해 알려지지 않은 차원을 사용하십시오

텐서 플로우는 모양에 따라 텐서와 일치하기 때문에 None 와일드 카드로서의 치수가 허용됩니다 tf.function다양한 크기의 입력에 대한 추적을 재사용합니다. 길이가 다른 시퀀스 또는 각 배치에 대해 다른 크기의 이미지가있는 경우 다양하게 크기가 큰 입력이 발생할 수 있습니다.

@tf.function(input_signature=(tf.TensorSpec(shape=[None], dtype=tf.int32),))
def g(x):
  print('Tracing with', x)
  return x

# No retrace!
print(g(tf.constant([1, 2, 3])))
print(g(tf.constant([1, 2, 3, 4, 5])))
Tracing with Tensor("x:0", shape=(None,), dtype=int32)
tf.Tensor([1 2 3], shape=(3,), dtype=int32)
tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)

사용 reduce_retracing 자동 유연성을 위해

언제 reduce_retracing 활성화되고 tf.function 관찰중인 입력 유형의 슈퍼 타입을 자동으로 식별하고보다 일반화 된 그래프를 자동으로 추적하기로 선택합니다. 설정보다 덜 효율적입니다 input_signature 많은 유형을 지원해야 할 때 직접적이지만 유용합니다.

@tf.function(reduce_retracing=True)
def g(x):
  print('Tracing with', x)
  return x

# Traces once.
print(g(tf.constant([1, 2, 3])))

# Traces again, but more generalized this time.
print(g(tf.constant([1, 2, 3, 4, 5])))

# No more tracing!
print(g(tf.constant([1, 2, 3, 4, 5, 6, 7])))
print(g(tf.constant([1, 2, 3, 4, 5, 6, 7, 8, 9])))
Tracing with Tensor("x:0", shape=(3,), dtype=int32)
tf.Tensor([1 2 3], shape=(3,), dtype=int32)
Tracing with Tensor("x:0", shape=(None,), dtype=int32)
tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)
tf.Tensor([1 2 3 4 5 6 7], shape=(7,), dtype=int32)
tf.Tensor([1 2 3 4 5 6 7 8 9], shape=(9,), dtype=int32)

파이썬 리터럴 대신 텐서를 통과하십시오

종종 파이썬 인수는 과도한 파라미터 및 그래프 구성을 제어하는 ​​데 사용됩니다 (예 : num_layers=10 또는 training=True 또는 nonlinearity='relu'. 따라서 파이썬 인수가 변경되면 그래프를 되돌려 야하는 것이 합리적입니다.

그러나 파이썬 인수는 그래프 구성을 제어하는 ​​데 사용되지 않을 수 있습니다. 이 경우, 파이썬 값의 변화는 불필요한 회복을 유발할 수 있습니다. 예를 들어, 사인이 동적으로 풀리는이 교육 루프를 가져 가십시오. 다중 추적에도 불구하고 생성 된 그래프는 실제로 동일하므로 회복은 불필요합니다.

def train_one_step():
  pass

@tf.function
def train(num_steps):
  print("Tracing with num_steps = ", num_steps)
  tf.print("Executing with num_steps = ", num_steps)
  for _ in tf.range(num_steps):
    train_one_step()

print("Retracing occurs for different Python arguments.")
train(num_steps=10)
train(num_steps=20)

print()
print("Traces are reused for Tensor arguments.")
train(num_steps=tf.constant(10))
train(num_steps=tf.constant(20))
Retracing occurs for different Python arguments.
Tracing with num_steps =  10
Executing with num_steps =  10
Tracing with num_steps =  20
Executing with num_steps =  20

Traces are reused for Tensor arguments.
Tracing with num_steps =  Tensor("num_steps:0", shape=(), dtype=int32)
Executing with num_steps =  10
Executing with num_steps =  20

강제 회복이 필요하다면 새로운 것을 만드십시오 tf.function. 분리된 tf.function 물체는 흔적을 공유하지 않도록 보장됩니다.

def f():
  print('Tracing!')
  tf.print('Executing')

tf.function(f)()
tf.function(f)()
Tracing!
Executing
Tracing!
Executing

추적 프로토콜을 사용하십시오

가능한 경우 파이썬 유형을 tf.experimental.ExtensionType 대신에. 또한, TraceTypeExtensionType 입니다 tf.TypeSpec 그것과 관련이 있습니다. 따라서 필요한 경우 기본값을 간단히 대체 할 수 있습니다 tf.TypeSpec an을 통제합니다 ExtensionType‘에스 Tracing Protocol.

그렇지 않으면 언제에 대한 직접적인 제어를 위해 tf.function 특정 Python 유형과 관련하여 되돌아 보면 Tracing Protocol 직접.

@tf.function
def get_mixed_flavor(fruit_a, fruit_b):
  return fruit_a.flavor + fruit_b.flavor

class Fruit:
  flavor = tf.constant([0, 0])

class Apple(Fruit):
  flavor = tf.constant([1, 2])

class Mango(Fruit):
  flavor = tf.constant([3, 4])

# As described in the above rules, a generic TraceType for `Apple` and `Mango`
# is generated (and a corresponding ConcreteFunction is traced) but it fails to
# match the second function call since the first pair of Apple() and Mango()
# have gone out out of scope by then and deleted.
get_mixed_flavor(Apple(), Mango()) # Traces a new concrete function
get_mixed_flavor(Apple(), Mango()) # Traces a new concrete function again

# However, each subclass of the `Fruit` class has a fixed flavor, and you
# can reuse an existing traced concrete function if it was the same
# subclass. Avoiding such unnecessary tracing of concrete functions
# can have significant performance benefits.

class FruitTraceType(tf.types.experimental.TraceType):
  def __init__(self, fruit):
    self.fruit_type = type(fruit)
    self.fruit_value = fruit

  def is_subtype_of(self, other):
      # True if self subtypes `other` and `other`'s type matches FruitTraceType.
      return (type(other) is FruitTraceType and
              self.fruit_type is other.fruit_type)

  def most_specific_common_supertype(self, others):
      # `self` is the specific common supertype if all input types match it.
      return self if all(self == other for other in others) else None

  def placeholder_value(self, placeholder_context=None):
      # Use the fruit itself instead of the type for correct tracing.
      return self.fruit_value

  def __eq__(self, other):
    return type(other) is FruitTraceType and self.fruit_type == other.fruit_type

  def __hash__(self):
    return hash(self.fruit_type)

class FruitWithTraceType:

  def __tf_tracing_type__(self, context):
    return FruitTraceType(self)

class AppleWithTraceType(FruitWithTraceType):
  flavor = tf.constant([1, 2])

class MangoWithTraceType(FruitWithTraceType):
  flavor = tf.constant([3, 4])

# Now if you try calling it again:
get_mixed_flavor(AppleWithTraceType(), MangoWithTraceType()) # Traces a new concrete function
get_mixed_flavor(AppleWithTraceType(), MangoWithTraceType()) # Re-uses the traced concrete function

Obtaining concrete functions

Every time a function is traced, a new concrete function is created. You can directly obtain a concrete function, by using get_concrete_function.

print("Obtaining concrete trace")
double_strings = double.get_concrete_function(tf.constant("a"))
print("Executing traced function")
print(double_strings(tf.constant("a")))
print(double_strings(a=tf.constant("b")))
Obtaining concrete trace
Executing traced function
tf.Tensor(b'aa', shape=(), dtype=string)
tf.Tensor(b'bb', shape=(), dtype=string)
# You can also call get_concrete_function on an InputSpec
double_strings_from_inputspec = double.get_concrete_function(tf.TensorSpec(shape=[]dtype = tf.string)) print (double_strings_from_inputspec (tf.constant ( "c")))
tf.Tensor(b'cc', shape=(), dtype=string)

인쇄 a ConcreteFunction 입력 인수 (유형) 및 출력 유형의 요약을 표시합니다.

print(double_strings)
ConcreteFunction Input Parameters:
  a (POSITIONAL_OR_KEYWORD): TensorSpec(shape=(), dtype=tf.string, name=None)
Output Type:
  TensorSpec(shape=(), dtype=tf.string, name=None)
Captures:
  None

콘크리트 기능의 시그니처를 직접 검색 할 수도 있습니다.

print(double_strings.function_type)
(a: TensorSpec(shape=(), dtype=tf.string, name=None)) -> TensorSpec(shape=(), dtype=tf.string, name=None)

호환되지 않는 유형의 콘크리트 트레이스를 사용하면 오류가 발생합니다.

with assert_raises(tf.errors.InvalidArgumentError):
  double_strings(tf.constant(1))
Caught expected exception 
  :
Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/eager/polymorphic_function/function_type_utils.py", line 442, in bind_function_inputs
    bound_arguments = function_type.bind_with_defaults(
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/core/function/polymorphism/function_type.py", line 277, in bind_with_defaults
    with_default_args[arg_name] = constraint.cast(
TypeError: Can not cast TensorSpec(shape=(), dtype=tf.int32, name=None) to TensorSpec(shape=(), dtype=tf.string, name=None)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/eager/polymorphic_function/concrete_function.py", line 1179, in _call_impl
    return self._call_with_structured_signature(args, kwargs)
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/eager/polymorphic_function/concrete_function.py", line 1259, in _call_with_structured_signature
    function_type_utils.canonicalize_function_inputs(
TypeError: Binding inputs to tf.function failed due to `Can not cast TensorSpec(shape=(), dtype=tf.int32, name=None) to TensorSpec(shape=(), dtype=tf.string, name=None)`. Received args: (,) and kwargs: {} for signature: (a: TensorSpec(shape=(), dtype=tf.string, name=None)) -> TensorSpec(shape=(), dtype=tf.string, name=None).

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/tmpfs/tmp/ipykernel_167534/3551158538.py", line 8, in assert_raises
    yield
  File "/tmpfs/tmp/ipykernel_167534/3196284684.py", line 2, in 
    double_strings(tf.constant(1))
tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute __inference_double_189 as input #0(zero-based) was expected to be a string tensor but is a int32 tensor [Op:__inference_double_189]

Python 논쟁은 콘크리트 기능의 입력 시그니처에서 특별한 처리를 받음을 알 수 있습니다. Tensorflow 2.3 이전에, Python 인수는 콘크리트 기능의 시그니처에서 간단히 제거되었습니다. Tensorflow 2.3으로 시작하여 Python 인수는 서명에 남아 있지만 추적 중에 설정된 값을 취하도록 제한됩니다.

@tf.function
def pow(a, b):
  return a ** b

square = pow.get_concrete_function(a=tf.TensorSpec(None, tf.float32), b=2)
print(square)
ConcreteFunction Input Parameters:
  a (POSITIONAL_OR_KEYWORD): TensorSpec(shape=, dtype=tf.float32, name=None)
  b (POSITIONAL_OR_KEYWORD): Literal[2]
Output Type:
  TensorSpec(shape=, dtype=tf.float32, name=None)
Captures:
  None
assert square(tf.constant(10.0)) == 100

with assert_raises(TypeError):
  square(tf.constant(10.0), b=3)
Caught expected exception 
  :
Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/eager/polymorphic_function/function_type_utils.py", line 442, in bind_function_inputs
    bound_arguments = function_type.bind_with_defaults(
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/core/function/polymorphism/function_type.py", line 277, in bind_with_defaults
    with_default_args[arg_name] = constraint.cast(
ValueError: Can not cast 3 to Literal[2]

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/eager/polymorphic_function/concrete_function.py", line 1179, in _call_impl
    return self._call_with_structured_signature(args, kwargs)
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/eager/polymorphic_function/concrete_function.py", line 1259, in _call_with_structured_signature
    function_type_utils.canonicalize_function_inputs(
TypeError: Binding inputs to tf.function failed due to `Can not cast 3 to Literal[2]`. Received args: (,) and kwargs: {'b': 3} for signature: (a: TensorSpec(shape=, dtype=tf.float32, name=None), b: Literal[2]) -> TensorSpec(shape=, dtype=tf.float32, name=None).

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/eager/polymorphic_function/concrete_function.py", line 1182, in _call_impl
    return self._call_with_flat_signature(args, kwargs)
  File "/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/eager/polymorphic_function/concrete_function.py", line 1233, in _call_with_flat_signature
    raise TypeError(f"{self._flat_signature_summary()} got unexpected "
TypeError: pow(a) got unexpected keyword arguments: b.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/tmpfs/tmp/ipykernel_167534/3551158538.py", line 8, in assert_raises
    yield
  File "/tmpfs/tmp/ipykernel_167534/2310937119.py", line 4, in 
    square(tf.constant(10.0), b=3)
TypeError: Binding inputs to tf.function failed due to `Can not cast 3 to Literal[2]`. Received args: (,) and kwargs: {'b': 3} for signature: (a: TensorSpec(shape=, dtype=tf.float32, name=None), b: Literal[2]) -> TensorSpec(shape=, dtype=tf.float32, name=None).
Fallback to flat signature also failed due to: pow(a) got unexpected keyword arguments: b.

그래프 획득

실제를 검색하지만 tf.Graph 물체는 일반적으로해야 할 일이 아니며, 콘크리트 기능에서 쉽게 얻을 수 있습니다.

graph = double_strings.graph
for node in graph.as_graph_def().node:
  print(f'{node.input} -> {node.name}')
[] -> a
['a', 'a'] -> add
['add'] -> Identity

실제로, tf.Graphs는 직접 호출 할 수 없습니다. 우리는 실제로 사용합니다 tf.types.experimental.AtomicFunction 다음으로 설명 된 계산을 수행합니다 tf.Graph. 당신은 액세스 할 수 있습니다 AtomicFunction 추적을 설명합니다 tf.Graph 그리고 대신 직접 전화하십시오 ConcreteFunction:

atomic_fn = double_strings.inference_fn
atomic_fn(tf.constant("a"))

이는 고성능 시나리오를 위해 파이썬 오버 헤드가 낮은 이점이 있습니다. 그러나 전방 추론 (그라디언트 지원 없음)에만 사용해야하며 캡처 된 텐서 값 (있는 경우)을 명시 적으로 제공해야합니다.

디버깅

일반적으로 디버깅 코드는 열심 인 모드에서 내부보다 쉽습니다. tf.function. 코드가 tf.function. 디버깅 프로세스를 지원하려면 전화 할 수 있습니다 tf.config.run_functions_eagerly(True) 전 세계적으로 비활성화하고 다시 활성화 할 수 있습니다 tf.function.

내부에만 나타나는 문제를 추적 할 때 tf.function몇 가지 팁은 다음과 같습니다.

  • 평범한 오래된 파이썬 print 통화는 추적 중에만 실행되므로 기능이 추적 될 때 추적하는 데 도움이됩니다.
  • tf.print 전화는 매번 실행되며 실행 중에 중간 값을 추적하는 데 도움이 될 수 있습니다.
  • tf.debugging.enable_check_numerics NANS와 INF가 생성되는 위치를 쉽게 추적하는 방법입니다.
  • pdb (Python Debugger)는 추적 중에 무슨 일이 일어나고 있는지 이해하는 데 도움이됩니다. (경고: pdb당신을 사인 변환 소스 코드로 데려갑니다.)

원래 게시 Tensorflow 웹 사이트,,, 이 기사는 새 헤드 라인 아래에 표시되며 라이센스가 부여됩니다. CC x 4.0. 코드 샘플이 공유됩니다 Apache 2.0 라이센스.

출처 참조

Post Comment

당신은 놓쳤을 수도 있습니다