tf.function ile daha iyi performans

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyin Not defterini indir

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

Programlarınızdan grafikler oluşturmak için tf.function işlevini kullanabilirsiniz. Python kodunuzdan Python'dan bağımsız veri akışı grafikleri oluşturan bir dönüştürme aracıdır. Bu, performanslı ve taşınabilir modeller oluşturmanıza yardımcı olur ve SavedModel kullanmanız SavedModel .

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

Başlıca çıkarımlar ve öneriler şunlardır:

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

Kurulum

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

Temel bilgiler

kullanım

Tanımladığınız bir Function (örneğin @tf.function dekoratörünü uygulayarak) tıpkı bir çekirdek TensorFlow işlemi gibidir: Onu hevesle çalıştırabilirsiniz; gradyanları hesaplayabilirsiniz; ve benzeri.

@tf.function  # The decorator converts `add` into a `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 öğesini 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 çok sayıda küçük işlem içeren grafikler için istekli koddan daha hızlı olabilir. Ancak birkaç pahalı işlemi olan (kıvrımlar gibi) grafikler için çok fazla hızlanma görmeyebilirsiniz.

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.23302616399996623
Function conv: 0.21780993200013654
Note how there's not much difference in performance for convolutions

İzleme

Bu bölüm , gelecekte değişebilecek uygulama ayrıntıları da dahil olmak üzere, Function başlık altında nasıl çalıştığını ortaya koymaktadır . Ancak, izlemenin neden ve ne zaman gerçekleştiğini anladıktan sonra, tf.function etkili bir şekilde kullanmak çok daha kolay!

"İzlemek" nedir?

Bir Function , programınızı bir TensorFlow Graph'ta çalıştırır . Ancak, bir tf.Graph , hevesli bir TensorFlow programında yazacağınız her şeyi temsil edemez. Örneğin, Python polimorfizmi destekler, ancak tf.Graph , girdilerinin belirli bir veri tipine ve boyutuna sahip olmasını gerektirir. Veya komut satırı argümanlarını okumak, bir hatayı yükseltmek veya daha karmaşık bir Python nesnesi ile çalışmak gibi yan görevleri gerçekleştirebilirsiniz; bunların hiçbiri bir tf.Graph içinde çalıştırılamaz.

Function , kodunuzu iki aşamada ayırarak bu boşluğu doldurur:

1) " Tracing " olarak adlandırılan ilk aşamada, Function yeni bir tf.Graph oluşturur. Python kodu normal çalışır, ancak tüm TensorFlow işlemleri (iki Tensör eklemek gibi) ertelenir : bunlar tf.Graph tarafından tf.Graph ve çalıştırılmaz.

2) İkinci aşamada, ilk aşamada ertelenen her şeyi içeren bir tf.Graph çalıştırılır. Bu aşama, izleme aşamasından çok daha hızlıdır.

Girişlerine bağlı olarak, Function çağrıldığında her zaman ilk aşamayı çalıştırmaz. Bu belirlemeyi nasıl yaptığını daha iyi anlamak için aşağıdaki "İzleme kuralları"na bakın. İlk aşamayı atlamak ve yalnızca ikinci aşamayı yürütmek, size TensorFlow'un yüksek performansını verir.

Function izlemeye karar verdiğinde, izleme aşamasını hemen ikinci aşama izler, bu nedenle Function çağırmak tf.Graph hem oluşturur hem de çalıştırır. Daha sonra get_concrete_function ile sadece izleme aşamasını nasıl çalıştırabileceğinizi get_concrete_function .

Bir Function içine farklı türdeki argümanları Function , her iki aşama da çalıştırılır:

@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 tipine sahip bir Function tekrar tekrar çağırırsanız, oluşturulan grafik aynı olacağından TensorFlow'un izleme aşamasını atlayacağını ve ö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)

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

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

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

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

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

  • Bir tf.Graph , bir TensorFlow hesaplamasının ham, dilden bağımsız, taşınabilir temsilidir.
  • Bir ConcreteFunction bir tf.Graph sarar.
  • Bir Function , ConcreteFunction s önbelleğini yönetir ve girdileriniz için doğru olanı seçer.
  • tf.function Bir Python işlevini sarar ve bir Function nesnesi döndürür.
  • İzleme , bir tf.Graph oluşturur ve onu iz olarak da bilinen bir ConcreteFunction 'a sarar .

izleme kuralları

Bir Function , bir takip yeniden belirler ConcreteFunction bir girişin args ve kwargs bir önbellek anahtarı hesaplanmasıyla. Bir önbellek anahtar kilit önem taşıdığı tanımlar bir ConcreteFunction girdi args ve kwargs dayalı Function çağrısı, aşağıdaki kurallar (değişebilir olan) göre:

  • Bir tf.Tensor için oluşturulan anahtar, şekli ve tipidir.
  • Bir tf.Variable için oluşturulan anahtar, benzersiz bir değişken tf.Variable .
  • Bir Python ilkel öğesi ( int , float , str ) için oluşturulan anahtar, değeridir.
  • Yuvalanmış dict s, list s, tuple s, namedtuple s ve attr s için oluşturulan anahtar, yaprak anahtarların düzleştirilmişnest.flatten (bkz.nest.flatten ). (Bu düzleştirmenin bir sonucu olarak, izleme sırasında kullanılandan farklı bir yuvalama yapısına sahip somut bir işlevi çağırmak TypeError ile sonuçlanacaktır).
  • Diğer tüm Python türleri için anahtar, nesneye özeldir. Bu şekilde bir işlev veya yöntem, çağrıldığı her örnek için bağımsız olarak izlenir.

Geri izlemeyi kontrol etme

Function birden fazla iz oluşturduğu geri izleme, TensorFlow'un her giriş kümesi için doğru grafikler oluşturmasını sağlamaya yardımcı olur. Ancak, izleme pahalı bir işlemdir! Function her çağrı için yeni bir grafiğin izini sürerse, kodunuzun tf.function kullanmadığınıza göre daha yavaş yürütüldüğünü tf.function .

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

  • input_signature sınırlamak için input_signature içinde tf.function 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])))
# You 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]]))

# You 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-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-14ebce7b7ee8>", 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-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-14ebce7b7ee8>", 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))
  • İzleme yeniden kullanımında esnekliğe izin vermek için tf.TensorSpec bir [Yok] boyutu belirtin.

    TensorFlow, tensörleri şekillerine göre eşleştirdiğinden, joker karakter olarak None boyutunun kullanılması, Function s öğesinin değişken boyutlu girdiler için izleri yeniden kullanmasına olanak tanır. Farklı uzunluktaki dizileriniz veya her grup için farklı boyutlardaki resimleriniz varsa, değişken boyutlu girdiler oluşabilir (örneğin Transformer ve Deep Dream eğitimlerine bakın).

@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 izlemeyi azaltmak için Python bağımsız değişkenlerini Tensörlere aktarın.

    Genellikle, Python bağımsız değişkenleri hiperparametreleri ve grafik yapılarını kontrol etmek için kullanılır - örneğin, num_layers=10 veya training=True veya nonlinearity='relu' . Bu nedenle, Python argümanı değişirse, grafiği tekrar izlemeniz mantıklı olur.

    Ancak, grafik yapısını kontrol etmek için bir Python argümanının kullanılmaması mümkündür. Bu durumlarda, Python değerindeki bir değişiklik gereksiz yere yeniden izlemeyi tetikleyebilir. Örneğin, Otomatik Grafik'in dinamik olarak açacağı bu eğitim döngüsünü ele alalım. Birden çok izlemeye rağmen, oluşturulan grafik aslında aynıdır, bu nedenle yeniden izleme 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 izlemeyi zorlamanız gerekirse, yeni bir Function . Separate Function nesnelerinin izlemeleri paylaşmamaları garanti edilir.

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

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

Somut fonksiyonların elde edilmesi

Her fonksiyon izlendiğinde, yeni bir somut fonksiyon yaratılır. get_concrete_function 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)

Bir ConcreteFunction yazdırmak, girdi bağımsız değişkenlerinin (türlerle birlikte) ve çıktı türünün bir özetini görüntüler.

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-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-e4e2860a4364>", line 2, in <module>
    double_strings(tf.constant(1))
tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute __inference_double_162 as input #0(zero-based) was expected to be a string tensor but is a int32 tensor [Op:__inference_double_162]

Somut bir işlevin giriş imzasında Python argümanlarına özel muamele verildiğini fark edebilirsiniz. TensorFlow 2.3'ten önce, Python argümanları somut fonksiyonun imzasından basitçe kaldırıldı. TensorFlow 2.3 ile başlayarak, Python bağımsız değişkenleri imzada kalır, ancak izleme sırasında ayarlanan değeri almakla sınırlandırılı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.7/site-packages/tensorflow/python/eager/function.py", line 1725, in _call_impl
    cancellation_manager)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/eager/function.py", line 1770, 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-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-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

Grafiklerin elde edilmesi

Her somut işlev, bir tf.Graph çevresinde çağrılabilir bir sarmalayıcıdır. 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, hevesli modda kodun hata ayıklaması tf.function içindekinden daha tf.function . tf.function ile tf.function önce kodunuzun istekli modda tf.function . Hata ayıklama sürecine yardımcı olmak için, tf.config.run_functions_eagerly(True) işlevini genel 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ı takip tf.function , işte 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 nerede oluşturulduğunu izlemenin kolay bir yoludur.
  • pdb ( Python hata ayıklayıcısı ), izleme sırasında neler olduğunu anlamanıza yardımcı olabilir. (Uyarı: pdb sizi AutoGraph ile dönüştürülmüş kaynak koduna bırakacaktır.)

Otomatik Grafik dönüşümleri

AutoGraph, tf.function öğesinde varsayılan olarak tf.function olan ve Python istekli kodunun bir alt kümesini grafik uyumlu TensorFlow işlemlerine dönüştüren bir kitaplıktır. Bu, if , for , while gibi kontrol akışını içerir.

Gibi TensorFlow ops tf.cond ve tf.while_loop çalışmalarına devam eder, ancak kontrol akış yazma ve Python ile yazılmış zaman takip etmek çoğu zaman daha kolaydır.

# A 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.710546374 0.327660799 0.393230557 0.545059443 0.666661739]
[0.611019373 0.316417336 0.374141902 0.496808201 0.582779706]
[0.54484427 0.306263864 0.357609242 0.45960331 0.52468282]
[0.496646136 0.297034383 0.343106419 0.429760844 0.481306106]
[0.459475428 0.288596332 0.330247819 0.405121386 0.44728902]
[0.429656595 0.280842364 0.318743408 0.384322464 0.419668049]
[0.405034214 0.273684502 0.308370233 0.366455346 0.396650732]
[0.384248167 0.267049909 0.298953682 0.350887358 0.377079546]
[0.366391063 0.260877609 0.290354759 0.337162226 0.360168517]
[0.350830942 0.255116194 0.282461286 0.324941576 0.345362455]
[0.337112248 0.2497219 0.275181532 0.313968241 0.332256317]
[0.324896872 0.244657204 0.268439621 0.304042816 0.320546716]
[0.313927948 0.239889801 0.262172282 0.295007944 0.310001194]
[0.304006279 0.235391632 0.256326199 0.286737591 0.300438195]
[0.294974595 0.231138244 0.250856102 0.279129326 0.291713566]
[0.286706954 0.227108166 0.245723218 0.272099048 0.283711195]
[0.279101074 0.223282441 0.240894228 0.265576899 0.276336372]
[0.272072881 0.219644368 0.23634018 0.259504348 0.269510925]
[0.26555258 0.216179058 0.232035935 0.253831863 0.263169676]
[0.259481668 0.212873235 0.227959365 0.24851726 0.257257849]
[0.253810644 0.209715009 0.224091038 0.243524343 0.251728892]
[0.248497337 0.206693679 0.220413819 0.238821834 0.246543139]
[0.243505597 0.20379965 0.216912434 0.2343826 0.241666421]
[0.238804176 0.20102416 0.213573262 0.230182901 0.237069115]
[0.234365895 0.198359385 0.210384145 0.226201892 0.232725471]
[0.230167076 0.195798069 0.207334161 0.222421184 0.228612974]
[0.226186857 0.19333373 0.204413429 0.218824506 0.224711776]
[0.222406894 0.190960392 0.201613098 0.215397388 0.221004337]
[0.218810901 0.188672557 0.198925063 0.212126866 0.217475086]
[0.215384394 0.186465234 0.196342021 0.209001362 0.214110211]
[0.212114424 0.184333771 0.193857312 0.206010461 0.210897282]
<tf.Tensor: shape=(5,), dtype=float32, numpy=
array([0.20898944, 0.18227392, 0.19146483, 0.2031447 , 0.20782518],
      dtype=float32)>

Merak ediyorsanız, imzanın 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, bazı if <condition> ifadelerini eşdeğer tf.cond çağrılarına dönüştürür. Bu değiştirme, eğer <condition> bir Tensör ise yapılır. Aksi takdirde, if ifadesi 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şullunun tam olarak bir dalı grafiğe eklenir. AutoGraph olmadan, veriye bağlı kontrol akışı varsa, bu izlenen grafik alternatif dalı alamaz.

tf.cond , yürütme zamanında dinamik olarak bir dal seçerek koşulun her iki dalını da izler ve tf.cond ekler. İzlemenin istenmeyen yan etkileri olabilir; Daha fazla bilgi için AutoGraph izleme efektlerine göz atın .

@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 ile dönüştürülmüş if ifadeleriyle ilgili ek kısıtlamalar için başvuru belgelerine bakın.

döngüler

AutoGraph, bazı for ve while ifadelerini, tf.while_loop gibi eşdeğer TensorFlow döngü işlemlerine 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 ikame 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 işlemler tf.Graph .

Bir TensorFlow döngüsü, döngünün gövdesini izler ve yürütme zamanında kaç yinelemenin ç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 ile dönüştürülmüş for ve while ifadelerine ilişkin ek kısıtlamalar için başvuru belgelerine bakın.

Python verileri üzerinde döngü

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

Tüm eğitim döngüsünü tf.function içine sarmak istiyorsanız, bunu yapmanın en güvenli yolu, AutoGraph'ın eğitim döngüsünü dinamik olarak açması için verilerinizi birtf.data.Dataset olaraktf.data.Dataset .

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 10 nodes in its graph
train(<FlatMapDataset shapes: (<unknown>, <unknown>), types: (tf.int32, tf.int32)>) contains 10 nodes in its graph

Python/NumPy verilerini bir Veri Kümesine tf.data.Dataset.from_generator , tf.data.Dataset.from_generator ile tf.data.Dataset.from_tensors dikkatli tf.data.Dataset.from_tensors . İlki, verileri Python'da tutacak ve performans etkileri olabilecek tf.py_function aracılığıyla tf.py_function , ikincisi ise verilerin bir kopyasını grafikte bellek etkileri olabilecek büyük bir tf.constant() düğümü olarak tf.constant() .

Dosyalardan TFRecordDataset , CsvDataset vb. aracılığıyla veri okumak, veri tüketmenin en etkili yoludur, çünkü o zaman TensorFlow, Python'u dahil etmek zorunda kalmadan verilerin eşzamansız yüklenmesini ve önceden getirilmesini yönetebilir. Daha fazla bilgi edinmek için tf.data : TensorFlow giriş işlem hatları oluşturma kılavuzuna bakın.

Bir döngüde değerlerin toplanması

Yaygın bir kalıp, bir döngüden ara değerleri toplamaktır. Normalde bu, bir Python listesine ekleyerek veya bir Python sözlüğüne girdiler ekleyerek gerçekleştirilir. Ancak bunlar Python yan etkileri olduğundan dinamik olarak açılmamış bir döngüde beklendiği gibi çalışmayacaktır. Dinamik olarak açılmamış bir döngüden sonuçları 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.60458577, 0.3308612 , 0.7878152 , 0.3223114 ],
        [0.9110272 , 1.0819752 , 1.7657743 , 1.2409766 ],
        [1.7235098 , 1.5416101 , 2.2929285 , 1.9181627 ]],

       [[0.89487076, 0.22811687, 0.342862  , 0.5752872 ],
        [1.0133923 , 0.28650808, 0.9558767 , 1.0829899 ],
        [1.9280962 , 1.1437279 , 0.9857702 , 1.4834155 ]]], dtype=float32)>

sınırlamalar

TensorFlow Function , bir Python işlevini Function dönüştürürken bilmeniz gereken tasarım gereği birkaç sınırlamaya sahiptir.

Python yan etkilerini yürütme

Yazdırma, listelere ekleme ve globalleri değiştirme gibi yan etkiler bir Function içinde beklenmedik şekilde davranabilir, bazen iki kez yürütülür veya tümü yürütülmez. Yalnızca bir dizi girdiye sahip bir Function ilk kez çağırdığınızda gerçekleşirler. Daha sonra izlenen tf.Graph , Python kodu çalıştırılmadan yeniden çalıştırılır.

Genel kural, mantığınızdaki Python yan etkilerine güvenmekten kaçınmak ve bunları yalnızca izlerinizde hata ayıklamak için kullanmaktır. Aksi takdirde, gibi TensorFlow API'leri tf.data , tf.print , tf.summary , tf.Variable.assign ve tf.TensorArray her çağrı ile TensorFlow çalışma zamanı tarafından yürütülecek kodunuzu 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

Bir Function tf.py_function her çağrılması sırasında Python kodunu yürütmek isterseniz, tf.py_function bir çıkış tf.py_function . tf.py_function öğesinin dezavantajı, taşınabilir olmaması veya özellikle performanslı olmaması, SavedModel ile kaydedilememesi ve dağıtılmış (çoklu GPU, TPU) kurulumlarda iyi çalışmamasıdır. Ayrıca, tf.py_function bağlı olması gerektiğinden, tüm girdileri/çıktıları tensörlere gönderir.

Python global ve serbest değişkenlerini değiştirme

Python genel ve serbest değişkenlerini değiştirmek, Python yan etkisi olarak sayılır, bu nedenle yalnızca izleme sırasında olur.

external_list = []

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

side_effect(1)
side_effect(1)
side_effect(1)
# The list append only happened once!
assert len(external_list) == 1
Python side effect

Function dışında yaşayan listeler, dikteler ve diğer nesneler gibi kapsayıcıları değiştirmekten kaçınmalısınız. Bunun yerine argümanları ve TF nesnelerini kullanın. Örneğin, "Bir döngüde değerlerin toplanması" bölümünde, liste benzeri işlemlerin nasıl uygulanabileceğine dair bir örnek vardır.

Bazı durumlarda, bir tf.Variable ise durumu yakalayabilir ve değiştirebilirsiniz. Keras modellerinin ağırlıkları, aynı ConcreteFunction tekrarlanan çağrılarla bu şekilde güncellenir.

Python yineleyicilerini ve oluşturucularını kullanma

Oluşturucular ve yineleyiciler gibi birçok Python özelliği, durumu izlemek için Python çalışma zamanına güvenir. Genel olarak, bu yapılar istekli modda beklendiği gibi çalışsa da, bunlar Python yan etkilerinin örnekleridir ve bu nedenle yalnızca izleme sırasında gerçekleşir.

@tf.function
def buggy_consume_next(iterator):
  tf.print("Value:", next(iterator))

iterator = iter([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: 1
Value: 1
Value: 1

Tıpkı tf.TensorArray liste yapıları için özel bir tf.TensorArray'e sahip olması gibi, yineleme yapıları için özel bir tf.data.Iterator sahiptir. Genel bir bakış için AutoGraph dönüşümleri bölümüne bakın. Ayrıca, tf.data API, oluşturucu kalıplarının uygulanmasına yardımcı olabilir:

@tf.function
def good_consume_next(iterator):
  # This is ok, iterator is a tf.data.Iterator
  tf.print("Value:", next(iterator))

ds = tf.data.Dataset.from_tensor_slices([1, 2, 3])
iterator = iter(ds)
good_consume_next(iterator)
good_consume_next(iterator)
good_consume_next(iterator)
Value: 1
Value: 2
Value: 3

Function çağrıları arasında tf.Variables silme

Karşılaşabileceğiniz başka bir hata, çöpten toplanan bir değişkendir. ConcreteFunction s, yalnızca kapattıkları değişkenlere WeakRefs tutar, bu nedenle herhangi bir değişkene bir başvuru 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))

# The original variable object gets garbage collected, since there are no more
# references to it.
external_var = tf.Variable(4)
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-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-9a93d2e07632>", line 16, in <module>
    traced_f(4)
tensorflow.python.framework.errors_impl.FailedPreconditionError:  Could not find variable _AnonymousVar3. This could mean that the variable has been deleted. In TF1, it can also mean the variable is uninitialized. Debug info: container=localhost, status=Not found: Resource localhost/_AnonymousVar3/N10tensorflow3VarE does not exist.
     [[node ReadVariableOp (defined at <ipython-input-1-9a93d2e07632>:4) ]] [Op:__inference_f_782]

Function call stack:
f

Bilinen Sorunlar

Function doğru bir şekilde değerlendirmiyorsa, hata gelecekte düzeltilmesi planlanan bu bilinen sorunlarla açıklanabilir.

Python global ve serbest değişkenlerine bağlı olarak

Function , Python bağımsız değişkeninin yeni bir değeriyle çağrıldığında yeni bir ConcreteFunction Function oluşturur. Ancak, Python kapanışı, globaller veya bu Function öğesinin yerel olmayanları için bunu yapmaz. Onların değeri çağrıları arasında değişirse Function , Function hala takip edildiğinde oldukları değerleri kullanır. Bu, normal Python işlevlerinin çalışma biçiminden farklıdır.

Bu nedenle, dış adları kapatmak yerine argümanları kullanan işlevsel bir programlama stili öneriyoruz.

@tf.function
def buggy_add():
  return 1 + foo

@tf.function
def recommended_add(foo):
  return 1 + foo

foo = 1
print("Buggy:", buggy_add())
print("Correct:", recommended_add(foo))
Buggy: tf.Tensor(2, shape=(), dtype=int32)
Correct: tf.Tensor(2, shape=(), dtype=int32)
print("Updating the value of `foo` to 100!")
foo = 100
print("Buggy:", buggy_add())  # Did not change!
print("Correct:", recommended_add(foo))
Updating the value of `foo` to 100!
Buggy: tf.Tensor(2, shape=(), dtype=int32)
Correct: tf.Tensor(101, shape=(), dtype=int32)

Değerlerini güncellemediğiniz sürece dış isimleri kapatabilirsiniz.

Python nesnelerine bağlı olarak

Python nesnelerini argüman olarak tf.function , gelecekte düzeltilmesi beklenen bir dizi bilinen tf.function sahiptir. Genel olarak, argüman olarak Python ilkel veya tf.nest uyumlu bir yapı kullanıyorsanız veya bir nesnenin farklı bir örneğini bir Function içine tf.nest tutarlı izlemeye güvenebilirsiniz. Ancak Function aynı nesneyi geçmek ve sadece özelliklerini değiştiğinde yeni bir iz oluşturmaz.

class SimpleModel(tf.Module):
  def __init__(self):
    # These values are *not* tf.Variables.
    self.bias = 0.
    self.weight = 2.

@tf.function
def evaluate(model, x):
  return model.weight * x + model.bias

simple_model = SimpleModel()
x = tf.constant(10.)
print(evaluate(simple_model, x))
tf.Tensor(20.0, shape=(), dtype=float32)
print("Adding bias!")
simple_model.bias += 5.0
print(evaluate(simple_model, x))  # Didn't change :(
Adding bias!
tf.Tensor(20.0, shape=(), dtype=float32)

Güncellenen model orijinal modelle aynı önbellek anahtarına sahip olduğundan, modelin güncellenmiş örneğini değerlendirmek için aynı Function kullanmak hatalı olacaktır.

Bu nedenle değişken nesne özniteliklerine bağlı kalmamak için Function yazmanızı veya yeni nesneler oluşturmanızı öneririz.

Bu mümkün değilse, bir geçici çözüm, nesnenizi yeniden izlemeye zorlamak için her değiştirdiğinizde yeni Function s yapmaktır:

def evaluate(model, x):
  return model.weight * x + model.bias

new_model = SimpleModel()
evaluate_no_bias = tf.function(evaluate).get_concrete_function(new_model, x)
# Don't pass in `new_model`, `Function` already captured its state during tracing.
print(evaluate_no_bias(x))
tf.Tensor(20.0, shape=(), dtype=float32)
print("Adding bias!")
new_model.bias += 5.0
# Create new Function and ConcreteFunction since you modified new_model.
evaluate_with_bias = tf.function(evaluate).get_concrete_function(new_model, x)
print(evaluate_with_bias(x)) # Don't pass in `new_model`.
Adding bias!
tf.Tensor(25.0, shape=(), dtype=float32)

Geri tf.Variable pahalı olabileceğinden , tf.Variable s'yi nesne öznitelikleri olarak kullanabilirsiniz; bu öznitelikler mutasyona tf.Variable (ancak değiştirilemez, dikkatli olun!), benzer bir etki için bir geri izlemeye gerek yoktur.

class BetterModel:

  def __init__(self):
    self.bias = tf.Variable(0.)
    self.weight = tf.Variable(2.)

@tf.function
def evaluate(model, x):
  return model.weight * x + model.bias

better_model = BetterModel()
print(evaluate(better_model, x))
tf.Tensor(20.0, shape=(), dtype=float32)
print("Adding bias!")
better_model.bias.assign_add(5.0)  # Note: instead of better_model.bias += 5
print(evaluate(better_model, x))  # This works!
Adding bias!
tf.Tensor(25.0, shape=(), dtype=float32)

tf.Değişkenleri Oluşturma

Function , ilk çağrıldığında yalnızca bir kez değişken oluşturmayı ve ardından bunları yeniden kullanmayı destekler. Yeni izlemelerde tf.Variables oluşturamazsınız. Sonraki çağrılarda yeni değişkenler oluşturmaya şu anda izin verilmemektedir, ancak gelecekte izin verilecektir.

Misal:

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

with assert_raises(ValueError):
  f(1.0)
Caught expected exception 
  <class 'ValueError'>:
Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-8a0913e250e0>", line 7, in <module>
    f(1.0)
ValueError: in user code:

    <ipython-input-1-8a0913e250e0>:3 f  *
        v = tf.Variable(1.0)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/variables.py:262 __call__  **
        return cls._variable_v2_call(*args, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/variables.py:256 _variable_v2_call
        shape=shape)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/variables.py:67 getter
        return captured_getter(captured_previous, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py:769 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 çalıştırıldığında 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)

Birden çok Keras optimize edici ile kullanma

ValueError: tf.function-decorated function tried to create variables on non-first call. karşılaşabilirsiniz ValueError: tf.function-decorated function tried to create variables on non-first call. tf.function ile birden fazla tf.function iyileştirici tf.function . Bu hata, optimize tf.Variables degradeleri ilk kez uyguladıklarında dahili olarak tf.Variables oluşturmaları nedeniyle oluşur.

opt1 = tf.keras.optimizers.Adam(learning_rate = 1e-2)
opt2 = tf.keras.optimizers.Adam(learning_rate = 1e-3)

@tf.function
def train_step(w, x, y, optimizer):
   with tf.GradientTape() as tape:
       L = tf.reduce_sum(tf.square(w*x - y))
   gradients = tape.gradient(L, [w])
   optimizer.apply_gradients(zip(gradients, [w]))

w = tf.Variable(2.)
x = tf.constant([-1.])
y = tf.constant([2.])

train_step(w, x, y, opt1)
print("Calling `train_step` with different optimizer...")
with assert_raises(ValueError):
  train_step(w, x, y, opt2)
Calling `train_step` with different optimizer...
Caught expected exception 
  <class 'ValueError'>:
Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-d3d3937dbf1a>", line 18, in <module>
    train_step(w, x, y, opt2)
ValueError: in user code:

    <ipython-input-1-d3d3937dbf1a>:9 train_step  *
        optimizer.apply_gradients(zip(gradients, [w]))
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:636 apply_gradients  **
        self._create_all_weights(var_list)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:821 _create_all_weights
        _ = self.iterations
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:828 __getattribute__
        return super(OptimizerV2, self).__getattribute__(name)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:988 iterations
        aggregation=tf_variables.VariableAggregation.ONLY_FIRST_REPLICA)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:1194 add_weight
        aggregation=aggregation)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/training/tracking/base.py:815 _add_variable_with_custom_getter
        **kwargs_for_getter)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer_utils.py:139 make_variable
        shape=variable_shape if variable_shape else None)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/variables.py:260 __call__
        return cls._variable_v1_call(*args, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/variables.py:221 _variable_v1_call
        shape=shape)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/variables.py:67 getter
        return captured_getter(captured_previous, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py:769 invalid_creator_scope
        "tf.function-decorated function tried to create "

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

Eğer eğitim sırasında optimize edici değiştirmeniz gerekirse, bir çözüm yeni yaratmaktır Function çağırarak, her optimize edici için ConcreteFunction doğrudan.

opt1 = tf.keras.optimizers.Adam(learning_rate = 1e-2)
opt2 = tf.keras.optimizers.Adam(learning_rate = 1e-3)

# Not a tf.function.
def train_step(w, x, y, optimizer):
   with tf.GradientTape() as tape:
       L = tf.reduce_sum(tf.square(w*x - y))
   gradients = tape.gradient(L, [w])
   optimizer.apply_gradients(zip(gradients, [w]))

w = tf.Variable(2.)
x = tf.constant([-1.])
y = tf.constant([2.])

# Make a new Function and ConcreteFunction for each optimizer.
train_step_1 = tf.function(train_step).get_concrete_function(w, x, y, opt1)
train_step_2 = tf.function(train_step).get_concrete_function(w, x, y, opt2)
for i in range(10):
  if i % 2 == 0:
    train_step_1(w, x, y) # `opt1` is not used as a parameter. 
  else:
    train_step_2(w, x, y) # `opt2` is not used as a parameter.

Birden çok Keras modeliyle kullanma

Ayrıca ValueError: tf.function-decorated function tried to create variables on non-first call. farklı model örneklerini aynı Function geçirirken.

Bu hata, Keras modellerinin ( giriş şekilleri tanımlı olmayan ) ve tf.Variables katmanlarının ilk çağrıldıklarında tf.Variables s oluşturması tf.Variables oluşur. Bu değişkenleri zaten çağrılmış bir Function içinde başlatmaya çalışıyor olabilirsiniz. Bu hatayı önlemek için, modeli model.build(input_shape) önce tüm ağırlıkları başlatmak için model.build(input_shape) çağırmayı deneyin.

daha fazla okuma

Bir Function nasıl dışa aktarılacağını ve yükleneceğini öğrenmek için SavedModel kılavuzuna bakın . İzlemeden sonra gerçekleştirilen grafik optimizasyonları hakkında daha fazla bilgi edinmek için Grappler kılavuzuna bakın . Veri hattınızı nasıl optimize edeceğinizi ve modelinizin profilini nasıl çıkaracağınızı öğrenmek için Profiler kılavuzuna bakın .