텐서 플로 기능의 이중 수명
콘텐츠 개요
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.function
S는 특히 작은 작전이있는 그래프의 경우 열망하는 코드보다 빠를 수 있습니다. 그러나 비싼 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. 기능은 코드를 두 단계로 분리 하여이 차이를 연결합니다.
- “추적”이라고하는 첫 번째 단계에서 TF.Function은 새로운 tf.graph를 만듭니다. 파이썬 코드는 정상적으로 실행되지만 모든 텐서 플로우 작업 (예 : 두 텐서 추가)은 연기됩니다. TF.Graph에 의해 캡처되고 실행되지 않습니다.
- 두 번째 단계에서는 첫 번째 단계에서 연기 된 모든 것을 포함하는 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.Graph
S는 파이썬 코드에서 생성됩니다. - 인스턴스
tf.Graph
추적 된 특정 입력 유형에 특화되어 있습니다. 다른 유형은 회복이 필요합니다. - 각각 추적
tf.Graph
해당합니다ConcreteFunction
. - 에이
tf.function
캐시를 관리합니다ConcreteFunction
s와 입력에 맞는 올바른 것을 선택하십시오. tf.function
추적 될 파이썬 함수를 랩핑하여tf.types.experimental.PolymorphicFunction
물체.
추적 규칙
호출되면 a tf.function
먼저 다음을 사용하여 각 입력 인수의 유형을 평가합니다. tf.types.experimental.TraceType
각 주장의. 이것은 a를 구성하는 데 사용됩니다 tf.types.experimental.FunctionType
원하는 서명을 설명합니다 ConcreteFunction
. 우리는 이것을 비교합니다 FunctionType
에 FunctionType
기존의 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 사용
==
).
메모 이 절차는 객체에 대한 약점을 유지하므로 객체가 범위에 있거나 삭제되지 않는 한만 작동합니다.
- 먼저 객체가 이전 트레이스에서 사용 된 것과 동일한 객체인지 확인합니다 (Python 사용
메모: TraceType
THE를 기반으로합니다 tf.function
입력 매개 변수를 통해 전역으로 변경됩니다
회복 제어
회복, 당신의시기입니다 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
대신에. 또한, TraceType
의 ExtensionType
입니다 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.Graph
s는 직접 호출 할 수 없습니다. 우리는 실제로 사용합니다 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
당신을 사인 변환 소스 코드로 데려갑니다.)
원래 게시
Post Comment