Bu sayfa, Cloud Translation API ile çevrilmiştir.
Switch to English

Tf.function ile daha iyi performans

TensorFlow.org üzerinde görüntüle Google Colab'da yayınla Kaynağı GitHub'da görüntüle Not defterini indir

TensorFlow 2'de istekli yürütme varsayılan olarak açıktır. Kullanıcı arayüzü sezgisel ve esnektir (bir defalık işlemlerin yürütülmesi çok daha kolay ve hızlıdır), ancak bu performans ve konuşlandırılabilirlik pahasına olabilir.

Programlarınızdan grafik yapmak için tf.function kullanabilirsiniz. Python kodunuzdan Python'dan bağımsız veri akışı grafikleri oluşturan bir dönüşüm aracıdır. Bu, performans ve taşınabilir modeller oluşturmanıza yardımcı olacaktır ve SavedModel kullanmanız SavedModel .

Bu kılavuz, etkin bir şekilde kullanabilmeniz için tf.function başlık altında nasıl çalıştığını kavramsallaştırmanıza yardımcı olacaktır.

Ana çıkarımlar ve öneriler:

  • İstekli modda hata ayıklayın, sonra @tf.function ile @tf.function .
  • Nesne mutasyonu veya liste ekleri gibi Python yan etkilerine güvenmeyin.
  • tf.function en iyi TensorFlow ops ile çalışır; NumPy ve Python çağrıları sabitlere dönüştürülür.

Kurmak

 import tensorflow as tf
 

Karşılaşabileceğiniz hata türlerini göstermek için bir yardımcı işlev tanımlayın:

 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))
 

temeller

kullanım

Tanımladığınız bir Function tıpkı bir çekirdek TensorFlow işlemi gibidir: İstekli bir şekilde çalıştırabilirsiniz; degradeleri hesaplayabilirsiniz; ve bunun gibi.

 @tf.function
def add(a, b):
  return a + b

add(tf.ones([2, 2]), tf.ones([2, 2]))  #  [[2., 2.], [2., 2.]]
 
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[2., 2.],
       [2., 2.]], dtype=float32)>
 v = tf.Variable(1.0)
with tf.GradientTape() as tape:
  result = add(v, 1.0)
tape.gradient(result, v)
 
<tf.Tensor: shape=(), dtype=float32, numpy=1.0>

Function s'yi diğer Function s içinde kullanabilirsiniz.

 @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.Tensor: shape=(3, 2), dtype=float32, numpy=
array([[3., 3.],
       [3., 3.],
       [3., 3.]], dtype=float32)>

Function s, özellikle birçok küçük op'lu grafikler için istekli koddan daha hızlı olabilir. Ancak, birkaç pahalı ops (kıvrımlar gibi) olan grafikler için, çok fazla hız göremeyebilirsiniz.

 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")

 
Eager conv: 0.0023194860004878137
Function conv: 0.0036776439992536325
Note how there's not much difference in performance for convolutions

İzleme

Python'un dinamik yazımı, çeşitli argüman türlerine sahip işlevleri çağırabileceğiniz ve Python'un her senaryoda farklı bir şey yapabileceği anlamına gelir.

Yine de, bir TensorFlow Grafiği oluşturmak için statik dtypes ve şekil boyutları gereklidir. tf.function işlevi bir Python işlevini sararak bir Function nesnesi oluşturarak bu boşluğu doldurur. Verilen girişlere bağlı olarak, Function verilen girişler için uygun grafiği seçerek Python işlevini gerektiği gibi geri çeker. tf.function neden ve ne zaman gerçekleştiğini anladıktan sonra, tf.function etkili bir şekilde kullanmak çok daha kolay!

Bu polimorfik davranışı çalışırken görmek için farklı türde argümanlara sahip bir Function çağırabilirsiniz.

 @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)


Aynı argüman türüne sahip bir Function tekrar tekrar çağırırsanız, oluşturulan grafik aynı olacağından TensorFlow öğesinin önceden izlenen bir grafiği yeniden kullanacağını unutmayın.

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

(Aşağıdaki değişiklik TensorFlow'da her gece ve TensorFlow 2.3'te mevcut olacaktır.)

Mevcut tüm izleri görmek için pretty_printed_concrete_signatures() kullanabilirsiniz:

 print(double.pretty_printed_concrete_signatures())
 
double(a)
  Args:
    a: string Tensor, shape=()
  Returns:
    string Tensor, shape=()

double(a)
  Args:
    a: int32 Tensor, shape=()
  Returns:
    int32 Tensor, shape=()

double(a)
  Args:
    a: float32 Tensor, shape=()
  Returns:
    float32 Tensor, shape=()

Şimdiye kadar, tf.function öğesinin TensorFlow'un grafik izleme mantığı üzerinde önbelleğe alınmış, dinamik bir gönderim katmanı oluşturduğunu gördünüz. Terminoloji hakkında daha spesifik olmak gerekirse:

  • tf.Graph , hesaplamanızın ham, dile agnostik, portatif sunumudur.
  • ConcreteFunction , tf.Graph etrafında hevesle çalışan bir tf.Graph .
  • Bir Function ConcreteFunction ın önbelleğini yönetir ve girdileriniz için doğru olanı seçer.
  • tf.function , bir Python işlevini sararak bir Function nesnesini döndürür.

Somut işlevlerin elde edilmesi

Bir işlev her izlendiğinde yeni bir somut işlev oluşturulur. get_concrete_function işlevini kullanarak doğrudan somut bir işlev elde edebilirsiniz.

 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")))
 
Tracing with Tensor("a:0", shape=(), dtype=string)
tf.Tensor(b'cc', shape=(), dtype=string)

(Aşağıdaki değişiklik TensorFlow'da her gece ve TensorFlow 2.3'te mevcut olacaktır.)

ConcreteFunction yazdırıldığında, girdi bağımsız değişkenlerinin (türleriyle birlikte) ve çıktı türünün bir özeti görüntülenir.

 print(double_strings)
 
ConcreteFunction double(a)
  Args:
    a: string Tensor, shape=()
  Returns:
    string Tensor, shape=()

Ayrıca somut bir işlevin imzasını doğrudan alabilirsiniz.

 print(double_strings.structured_input_signature)
print(double_strings.structured_outputs)
 
((TensorSpec(shape=(), dtype=tf.string, name='a'),), {})
Tensor("Identity:0", shape=(), dtype=string)

Uyumsuz türlerle somut bir iz kullanmak hata verir

 with assert_raises(tf.errors.InvalidArgumentError):
  double_strings(tf.constant(1))
 
Caught expected exception 
  <class 'tensorflow.python.framework.errors_impl.InvalidArgumentError'>:

Traceback (most recent call last):
  File "<ipython-input-3-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-15-e4e2860a4364>", line 2, in <module>
    double_strings(tf.constant(1))
tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute __inference_double_168 as input #0(zero-based) was expected to be a string tensor but is a int32 tensor [Op:__inference_double_168]

Python argümanlarına somut bir işlevin giriş imzasında özel bir işlem verildiğini fark edebilirsiniz. TensorFlow 2.3'ten önce, Python argümanları basitçe somut işlevin imzasından çıkarıldı. TensorFlow 2.3 ile başlayarak, Python argümanları imzada kalır, ancak izleme sırasında ayarlanan değeri almakla sınırlıdır.

 @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 pow(a, b=2)
  Args:
    a: float32 Tensor, shape=<unknown>
  Returns:
    float32 Tensor, shape=<unknown>

 assert square(tf.constant(10.0)) == 100

with assert_raises(TypeError):
  square(tf.constant(10.0), b=3)
 
Caught expected exception 
  <class 'TypeError'>:

Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 1669, in _call_impl
    cancellation_manager)
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 1714, in _call_with_flat_signature
    self._flat_signature_summary(), ", ".join(sorted(kwargs))))
TypeError: pow(a) got unexpected keyword arguments: b.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<ipython-input-3-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-17-d163f3d206cb>", line 4, in <module>
    square(tf.constant(10.0), b=3)
TypeError: ConcreteFunction pow(a, b) was constructed with int value 2 in b, but was called with int value 3

Grafikleri elde etme

Her somut işlev, bir tf.Graph etrafında çağrılabilir bir tf.Graph . Gerçek tf.Graph nesnesini almak normalde yapmanız gereken bir şey olmasa da, herhangi bir somut işlevden kolayca elde edebilirsiniz.

 graph = double_strings.graph
for node in graph.as_graph_def().node:
  print(f'{node.input} -> {node.name}')

 
[] -> a
['a', 'a'] -> add
['add'] -> Identity

Hata ayıklama

Genel olarak, hata ayıklama kodu istekli modda tf.function içine göre daha tf.function . tf.function ile tf.function etmeden önce kodunuzun istekli modda hatasız çalıştığından emin tf.function . Hata ayıklama işlemine yardımcı olmak için, tf.config.run_functions_eagerly(True) işlevini küresel olarak devre dışı bırakmak ve yeniden etkinleştirmek için tf.config.run_functions_eagerly(True) tf.function .

Yalnızca tf.function içinde görünen sorunları tf.function , bazı ipuçları:

  • Düz eski Python print çağrıları yalnızca izleme sırasında yürütülür ve işleviniz (yeniden) izlendiğinde izlemenize yardımcı olur.
  • tf.print çağrıları her seferinde yürütülür ve yürütme sırasında ara değerleri izlemenize yardımcı olabilir.
  • tf.debugging.enable_check_numerics , tf.debugging.enable_check_numerics oluşturulduğu yeri izlemenin kolay bir yoludur.
  • pdb , izleme sırasında neler olduğunu anlamanıza yardımcı olabilir. (Uyarı: PDB sizi AutoGraph tarafından dönüştürülmüş kaynak koduna bırakacaktır.)

İzleme semantiği

Önbellek anahtarı kuralları

Bir Function , bir girişin argümanlarından ve kwarg'larından bir önbellek anahtarı hesaplayarak izlenen bir somut işlevin yeniden kullanılıp kullanılmayacağını belirler.

  • Bir tf.Tensor argümanı için oluşturulan anahtar şekli ve dtype'dir.
  • TensorFlow 2.3 başlayarak, için oluşturulan anahtar tf.Variable bağımsız değişken olarak bir id() .
  • Bir Python ilkel için üretilen anahtar değeridir. İç içe için oluşturulan anahtar dict s, list ler, tuple ler, namedtuple ler ve attr s düzleştirilmiş başlık olur. (Bu düzleştirmenin bir sonucu olarak, izleme sırasında kullanılandan farklı bir yuvalama yapısına sahip somut bir işlev çağırmak TypeError ile sonuçlanacaktır).
  • Diğer tüm Python türleri için, anahtarlar nesne id() yöntemini temel alır, böylece yöntemler bir sınıfın her örneği için bağımsız olarak izlenir.

Geri çekmeyi kontrol etme

Geri çekme, TensorFlow'un her bir giriş seti için doğru grafikler oluşturmasını sağlar. Ancak, izleme pahalı bir işlemdir! Function her arama için yeni bir grafik alırsa, kodunuzun tf.function kullanmadığınızdan daha yavaş tf.function .

İzleme davranışını denetlemek için aşağıdaki teknikleri kullanabilirsiniz:

  • input_signature sınırlamak için input_signature tf.function değerini belirtin.
 @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])))
# We specified a 1-D tensor in the input signature, so this should fail.
with assert_raises(ValueError):
  next_collatz(tf.constant([[1, 2], [3, 4]]))

# We specified an int32 dtype in the input signature, so this should fail.
with assert_raises(ValueError):
  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 
  <class 'ValueError'>:
Caught expected exception 
  <class 'ValueError'>:

Traceback (most recent call last):
  File "<ipython-input-3-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-19-20f544b8adbf>", line 9, in <module>
    next_collatz(tf.constant([[1, 2], [3, 4]]))
ValueError: Python inputs incompatible with input_signature:
  inputs: (
    tf.Tensor(
[[1 2]
 [3 4]], shape=(2, 2), dtype=int32))
  input_signature: (
    TensorSpec(shape=(None,), dtype=tf.int32, name=None))
Traceback (most recent call last):
  File "<ipython-input-3-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-19-20f544b8adbf>", line 13, in <module>
    next_collatz(tf.constant([1.0, 2.0]))
ValueError: Python inputs incompatible with input_signature:
  inputs: (
    tf.Tensor([1. 2.], shape=(2,), dtype=float32))
  input_signature: (
    TensorSpec(shape=(None,), dtype=tf.int32, name=None))

  • İz yeniden kullanımında esneklik sağlamak için tf.TensorSpec içinde [Hiçbiri] boyutu belirtin.

    TensorFlow, tensörleri şekillerini temel alarak eşleştirdiğinden, joker karakter olarak None boyutu kullanıldığında Function s'nin izleri değişken boyutlu giriş için yeniden kullanmasına izin verir. Her grup için farklı uzunlukta diziler veya farklı boyutlarda görüntüler varsa değişken boyutlu girişler oluşabilir (Örneğin, bkz. Transformer ve Deep Dream eğiticileri).

 @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)

  • Geri çekmeyi azaltmak için Python argümanlarını Tensörlere yayınlayın.

    Genellikle, Python argümanları hiperparametreleri ve grafik yapılarını kontrol etmek için kullanılır - örneğin, num_layers=10 veya training=True veya nonlinearity='relu' . Python argümanı değişirse, grafiği yeniden izlemeniz gerekir.

    Ancak, grafik yapısını kontrol etmek için bir Python argümanı kullanılmıyor olabilir. Bu durumlarda, Python değerindeki bir değişiklik gereksiz yere geri çekilmeyi tetikleyebilir. Örneğin, AutoGraph'ın dinamik olarak açılacağı bu eğitim döngüsünü ele alalım. Çoklu izlere rağmen, oluşturulan grafik aslında aynıdır, bu nedenle geri çekme gereksizdir.

 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

Geri çekilmeyi zorlamanız gerekiyorsa, yeni bir Function . Ayrı Function nesnelerinin izleri paylaşmaması garanti edilir.

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

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

Python yan etkileri

Yazdırma, listelere ekleme ve globalleri değiştirme gibi Python yan etkileri, yalnızca bir dizi girdi içeren bir Function ilk kez çağırdığınızda gerçekleşir. Daha sonra, izlenen tf.Graph , Python kodu yürütülmeden yeniden yürütülür.

Genel kural, izlerinizi ayıklamak için yalnızca Python yan etkilerini kullanmaktır. Aksi takdirde, tf.Variable.assign, tf.print ve tf.summary gibi tf.Variable.assign tf.print , kodunuzun her çağrıda TensorFlow çalışma zamanı tarafından izlenmesini ve yürütülmesini sağlamanın en iyi yoludur.

 @tf.function
def f(x):
  print("Traced with", x)
  tf.print("Executed with", x)

f(1)
f(1)
f(2)

 
Traced with 1
Executed with 1
Executed with 1
Traced with 2
Executed with 2

Jeneratörler ve yineleyiciler gibi birçok Python özelliği, durumu takip etmek için Python çalışma zamanına güvenir. Genel olarak, bu yapılar istekli modda beklendiği gibi çalışırken, bir Function içinde beklenmedik birçok şey olabilir.

Bir örnek vermek gerekirse, yineleyici durumunu ilerletmek bir Python yan etkisidir ve bu nedenle yalnızca izleme sırasında gerçekleşir.

 external_var = tf.Variable(0)
@tf.function
def buggy_consume_next(iterator):
  external_var.assign_add(next(iterator))
  tf.print("Value of external_var:", external_var)

iterator = iter([0, 1, 2, 3])
buggy_consume_next(iterator)
# This reuses the first value from the iterator, rather than consuming the next value.
buggy_consume_next(iterator)
buggy_consume_next(iterator)

 
Value of external_var: 0
Value of external_var: 0
Value of external_var: 0

Bazı yineleme yapıları AutoGraph aracılığıyla desteklenir. Genel bir bakış için Otomatik Grafik Dönüşümleri bölümüne bakın.

Bir Function her çağrılması sırasında Python kodunu çalıştırmak isterseniz, tf.py_function bir çıkış tf.py_function . tf.py_function dezavantajı, taşınabilir veya özellikle performans göstermemesi veya dağıtılmış (çoklu GPU, TPU) kurulumlarda iyi çalışmamasıdır. Ayrıca, tf.py_function grafiğe bağlanması gerektiğinden, tüm girişleri / çıkışları tensörlere verir.

tf.gather , tf.stack ve tf.TensorArray gibi tf.gather , yerel TensorFlow'da ortak döngü kalıpları uygulamanıza yardımcı olabilir.

 external_list = []

def side_effect(x):
  print('Python side effect')
  external_list.append(x)

@tf.function
def f(x):
  tf.py_function(side_effect, inp=[x], Tout=[])

f(1)
f(1)
f(1)
# The list append happens all three times!
assert len(external_list) == 3
# The list contains tf.constant(1), not 1, because py_function casts everything to tensors.
assert external_list[0].numpy() == 1

 
Python side effect
Python side effect
Python side effect

Değişkenler

Bir işlevde yeni bir tf.Variable oluştururken bir hatayla karşılaşabilirsiniz. Bu hata, yinelenen çağrılarda davranış farklılığına karşı koruma sağlar: İstekli modda, bir işlev her çağrıda yeni bir değişken oluşturur, ancak bir Function iz yeniden kullanımı nedeniyle yeni bir değişken oluşturulamayabilir.

 @tf.function
def f(x):
  v = tf.Variable(1.0)
  v.assign_add(x)
  return v

with assert_raises(ValueError):
  f(1.0)
 
Caught expected exception 
  <class 'ValueError'>:

Traceback (most recent call last):
  File "<ipython-input-3-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-26-73e410646579>", line 8, in <module>
    f(1.0)
ValueError: in user code:

    <ipython-input-26-73e410646579>:3 f  *
        v = tf.Variable(1.0)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:262 __call__  **
        return cls._variable_v2_call(*args, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:256 _variable_v2_call
        shape=shape)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:67 getter
        return captured_getter(captured_previous, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/def_function.py:702 invalid_creator_scope
        "tf.function-decorated function tried to create "

    ValueError: tf.function-decorated function tried to create variables on non-first call.


Bu değişkenler yalnızca işlev ilk kez yürütüldüğünde oluşturulduğu sürece bir Function içinde değişkenler oluşturabilirsiniz.

 class Count(tf.Module):
  def __init__(self):
    self.count = None
  
  @tf.function
  def __call__(self):
    if self.count is None:
      self.count = tf.Variable(0)
    return self.count.assign_add(1)

c = Count()
print(c())
print(c())
 
tf.Tensor(1, shape=(), dtype=int32)
tf.Tensor(2, shape=(), dtype=int32)

Karşılaşabileceğiniz başka bir hata, çöp toplanan bir değişkendir. Normal Python işlevlerinden farklı olarak, somut işlevler WeakRef'leri yalnızca kapattıkları değişkenlere korur, bu nedenle herhangi bir değişkene referans tutmanız gerekir.

 external_var = tf.Variable(3)
@tf.function
def f(x):
  return x * external_var

traced_f = f.get_concrete_function(4)
print("Calling concrete function...")
print(traced_f(4))

del external_var
print()
print("Calling concrete function after garbage collecting its closed Variable...")
with assert_raises(tf.errors.FailedPreconditionError):
  traced_f(4)
 
Calling concrete function...
tf.Tensor(12, shape=(), dtype=int32)

Calling concrete function after garbage collecting its closed Variable...
Caught expected exception 
  <class 'tensorflow.python.framework.errors_impl.FailedPreconditionError'>:

Traceback (most recent call last):
  File "<ipython-input-3-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-28-304a18524b57>", line 14, in <module>
    traced_f(4)
tensorflow.python.framework.errors_impl.FailedPreconditionError: 2 root error(s) found.
  (0) Failed precondition:  Error while reading resource variable _AnonymousVar4 from Container: localhost. This could mean that the variable was uninitialized. Not found: Resource localhost/_AnonymousVar4/N10tensorflow3VarE does not exist.
     [[node ReadVariableOp (defined at <ipython-input-28-304a18524b57>:4) ]]
     [[ReadVariableOp/_2]]
  (1) Failed precondition:  Error while reading resource variable _AnonymousVar4 from Container: localhost. This could mean that the variable was uninitialized. Not found: Resource localhost/_AnonymousVar4/N10tensorflow3VarE does not exist.
     [[node ReadVariableOp (defined at <ipython-input-28-304a18524b57>:4) ]]
0 successful operations.
0 derived errors ignored. [Op:__inference_f_514]

Function call stack:
f -> f


Otomatik Grafik Dönüşümleri

Autograph varsayılan olarak bulunan bir kütüphane tf.function ve grafik uyumlu TensorFlow ops içine Python istekli kod bir alt kümesini dönüştürür. Bu gibi kontrol akışını içeren if , for , while .

Tf.cond ve tf.while_loop gibi tf.cond tf.while_loop çalışmaya devam eder, ancak Python'da yazıldığında kontrol akışının yazılması ve anlaşılması genellikle daha kolaydır.

 # Simple loop

@tf.function
def f(x):
  while tf.reduce_sum(x) > 1:
    tf.print(x)
    x = tf.tanh(x)
  return x

f(tf.random.uniform([5]))
 
[0.448926926 0.896036148 0.703306437 0.446930766 0.20440042]
[0.421016544 0.714362323 0.6064623 0.419372857 0.201600626]
[0.397786468 0.613405049 0.541632056 0.396401972 0.198913112]
[0.378053397 0.546519518 0.494222373 0.376866162 0.196330562]
[0.361015767 0.497907132 0.457561225 0.359982818 0.1938463]
[0.346108437 0.460469633 0.428094476 0.3451989 0.191454232]
[0.332919776 0.43046692 0.403727621 0.332110822 0.189148799]
[0.321141869 0.405711472 0.383133948 0.320416152 0.18692489]
[0.310539037 0.384825289 0.365426034 0.309883147 0.184777796]
[0.300927401 0.366890609 0.349984437 0.300330788 0.182703182]
[0.292161077 0.351268977 0.336361736 0.291615278 0.180697069]
[0.284122646 0.337500453 0.324225426 0.283620834 0.178755745]
[0.276716352 0.325244069 0.313322544 0.276252925 0.176875815]
[0.269863278 0.314240903 0.303456694 0.269433528 0.175054088]
[0.263497591 0.304290265 0.294472754 0.263097644 0.17328763]
[0.257564 0.295233846 0.2862463 0.257190555 0.171573699]
[0.25201565 0.286944896 0.278676242 0.25166589 0.169909731]
[0.246812463 0.279320478 0.271679461 0.246483982 0.168293342]
[0.24192 0.272276044 0.265186876 0.241610721 0.166722313]
[0.237308443 0.265741408 0.259140551 0.237016559 0.165194541]
[0.23295185 0.25965777 0.253491491 0.232675791 0.163708091]
[0.228827521 0.253975391 0.248197898 0.228565902 0.162261128]
[0.224915475 0.248651937 0.243223906 0.224667087 0.160851941]
[0.221198082 0.243651047 0.238538548 0.220961839 0.159478888]
[0.217659682 0.238941342 0.23411487 0.217434615 0.158140466]
[0.214286327 0.23449555 0.229929343 0.214071587 0.156835243]
[0.211065561 0.230289876 0.225961298 0.210860386 0.155561864]
[0.207986191 0.226303399 0.222192511 0.207789883 0.154319063]
[0.20503816 0.222517684 0.2186068 0.204850093 0.153105617]

<tf.Tensor: shape=(5,), dtype=float32, numpy=
array([0.20221236, 0.2189164 , 0.21518978, 0.20203198, 0.15192041],
      dtype=float32)>

Merak ediyorsanız, imza oluşturduğu kodu inceleyebilirsiniz.

 print(tf.autograph.to_code(f.python_function))
 
def tf__f(x):
    with ag__.FunctionScope('f', 'fscope', ag__.ConversionOptions(recursive=True, user_requested=True, optional_features=(), internal_convert_user_code=True)) as fscope:
        do_return = False
        retval_ = ag__.UndefinedReturnValue()

        def get_state():
            return (x,)

        def set_state(vars_):
            nonlocal x
            (x,) = vars_

        def loop_body():
            nonlocal x
            ag__.converted_call(ag__.ld(tf).print, (ag__.ld(x),), None, fscope)
            x = ag__.converted_call(ag__.ld(tf).tanh, (ag__.ld(x),), None, fscope)

        def loop_test():
            return (ag__.converted_call(ag__.ld(tf).reduce_sum, (ag__.ld(x),), None, fscope) > 1)
        ag__.while_stmt(loop_test, loop_body, get_state, set_state, ('x',), {})
        try:
            do_return = True
            retval_ = ag__.ld(x)
        except:
            do_return = False
            raise
        return fscope.ret(retval_, do_return)


Şartlılar

AutoGraph, if <condition> bazı if <condition> ifadelerini eşdeğer tf.cond çağrılarına dönüştürür. Bu ikame, <condition> bir Tensör ise yapılır. Aksi takdirde, if ifadesi bir Python koşullu olarak yürütülür.

İzleme sırasında bir Python koşulu yürütülür, bu nedenle koşulun tam olarak bir dalı grafiğe eklenir. AutoGraph olmasaydı, veriye bağlı kontrol akışı varsa bu izlenen grafik alternatif dalı alamazdı.

tf.cond , koşulun her iki dalını da izler ve tf.cond ekleyerek yürütme zamanında dinamik olarak bir dal tf.cond . İzlemenin istenmeyen yan etkileri olabilir; daha fazla bilgi için bkz. AutoGraph izleme efektleri .

 @tf.function
def fizzbuzz(n):
  for i in tf.range(1, n + 1):
    print('Tracing for loop')
    if i % 15 == 0:
      print('Tracing fizzbuzz branch')
      tf.print('fizzbuzz')
    elif i % 3 == 0:
      print('Tracing fizz branch')
      tf.print('fizz')
    elif i % 5 == 0:
      print('Tracing buzz branch')
      tf.print('buzz')
    else:
      print('Tracing default branch')
      tf.print(i)

fizzbuzz(tf.constant(5))
fizzbuzz(tf.constant(20))
 
Tracing for loop
Tracing fizzbuzz branch
Tracing fizz branch
Tracing buzz branch
Tracing default branch
1
2
fizz
4
buzz
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz

AutoGraph dönüştürülmüş if ifadeleriyle ilgili ek kısıtlamalar için başvuru belgelerine bakın.

döngüler

AutoGraph for ve while ifadelerini tf.while_loop gibi eşdeğer TensorFlow döngü tf.while_loop . Dönüştürülmezse, for veya while döngüsü bir Python döngüsü olarak yürütülür.

Bu değişiklik aşağıdaki durumlarda yapılır:

İzleme sırasında bir Python döngüsü tf.Graph ve döngünün her yinelemesi için tf.Graph ek ops tf.Graph .

Bir TensorFlow döngüsü, döngü gövdesini izler ve yürütme zamanında kaç yineleme çalıştırılacağını dinamik olarak seçer. Döngü gövdesi oluşturulan tf.Graph yalnızca bir kez görünür.

AutoGraph for dönüştürülen ve while ifadeleriyle ilgili ek kısıtlamalar için başvuru belgelerine bakın.

Python verileri üzerinde döngü

Yaygın bir tuzak, bir tf.function içinde Python / Numpy verileri üzerinde döngü tf.function . Bu döngü, izleme işlemi sırasında yürütülür ve döngünün her yinelemesi için modelinizin bir kopyasını tf.Graph .

Tüm egzersiz döngüsünü tf.function içine sarmak istiyorsanız, bunu yapmanın en güvenli yolu verilerinizi tf.data.Dataset olarak tf.data.Dataset böylece AutoGraph egzersiz döngüsünü dinamik olarak açar.

 def measure_graph_size(f, *args):
  g = f.get_concrete_function(*args).graph
  print("{}({}) contains {} nodes in its graph".format(
      f.__name__, ', '.join(map(str, args)), len(g.as_graph_def().node)))

@tf.function
def train(dataset):
  loss = tf.constant(0)
  for x, y in dataset:
    loss += tf.abs(y - x) # Some dummy computation.
  return loss

small_data = [(1, 1)] * 3
big_data = [(1, 1)] * 10
measure_graph_size(train, small_data)
measure_graph_size(train, big_data)

measure_graph_size(train, tf.data.Dataset.from_generator(
    lambda: small_data, (tf.int32, tf.int32)))
measure_graph_size(train, tf.data.Dataset.from_generator(
    lambda: big_data, (tf.int32, tf.int32)))
 
train([(1, 1), (1, 1), (1, 1)]) contains 11 nodes in its graph
train([(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1)]) contains 32 nodes in its graph
train(<FlatMapDataset shapes: (<unknown>, <unknown>), types: (tf.int32, tf.int32)>) contains 8 nodes in its graph
train(<FlatMapDataset shapes: (<unknown>, <unknown>), types: (tf.int32, tf.int32)>) contains 8 nodes in its graph

Python / Numpy verilerini bir Veri Kümesine tf.data.Dataset.from_generator , tf.data.Dataset.from_generator karşı tf.data.Dataset.from_tensors karşı dikkatli tf.data.Dataset.from_tensors . Birincisi verileri Python'da saklayacak ve performansla ilgili sonuçları olabilecek tf.py_function ile tf.py_function , ikincisi verilerin bir kopyasını grafikte bellek sonuçları olabilecek büyük bir tf.constant() düğümü olarak tf.constant() .

TFRecordDataset / CsvDataset / etc ile dosyalardan veri okuma. veri tüketmenin en etkili yoludur, çünkü TensorFlow'un kendisi Python'u dahil etmek zorunda kalmadan verilerin eşzamansız yüklenmesini ve önceden getirilmesini yönetebilir. Daha fazla bilgi için tf.data kılavuzuna bakın .

Bir döngüde değer biriktirme

Ortak bir örüntü, bir döngüden ara değerler biriktirmektir. Normalde bu, bir Python listesine eklenerek veya bir Python sözlüğüne girişler ekleyerek gerçekleştirilir. Bununla birlikte, bunlar Python yan etkileri olduğundan, dinamik olarak açılmamış bir döngüde beklendiği gibi çalışmazlar. Dinamik olarak açılmamış bir döngüden sonuç tf.TensorArray için tf.TensorArray kullanın.

 batch_size = 2
seq_len = 3
feature_size = 4

def rnn_step(inp, state):
  return inp + state

@tf.function
def dynamic_rnn(rnn_step, input_data, initial_state):
  # [batch, time, features] -> [time, batch, features]
  input_data = tf.transpose(input_data, [1, 0, 2])
  max_seq_len = input_data.shape[0]

  states = tf.TensorArray(tf.float32, size=max_seq_len)
  state = initial_state
  for i in tf.range(max_seq_len):
    state = rnn_step(input_data[i], state)
    states = states.write(i, state)
  return tf.transpose(states.stack(), [1, 0, 2])
  
dynamic_rnn(rnn_step,
            tf.random.uniform([batch_size, seq_len, feature_size]),
            tf.zeros([batch_size, feature_size]))
 
<tf.Tensor: shape=(2, 3, 4), dtype=float32, numpy=
array([[[0.2486304 , 0.0612042 , 0.69624186, 0.28587592],
        [1.2193475 , 0.2389338 , 1.5216837 , 0.38649392],
        [1.7640524 , 1.1970762 , 2.3265643 , 0.81419575]],

       [[0.36599267, 0.41830885, 0.73540664, 0.63987565],
        [0.48354673, 1.1808103 , 1.7210082 , 0.8333106 ],
        [0.7138835 , 1.2030114 , 1.8544207 , 1.1647347 ]]], dtype=float32)>

daha fazla okuma

Bir Function nasıl dışa aktarılacağı ve yükleneceği hakkında bilgi için, bkz. SavedModel kılavuzu . İzlemeden sonra gerçekleştirilen grafik optimizasyonları hakkında daha fazla bilgi için Grappler kılavuzuna bakın . Veri hattınızı nasıl optimize edeceğinizi ve modelinizi nasıl profil oluşturacağınızı öğrenmek için Profiler kılavuzuna bakın .