امروز برای رویداد محلی TensorFlow خود در همه جا پاسخ دهید!
This page was translated by the Cloud Translation API.
Switch to English

عملکرد بهتر با عملکرد tf

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub دانلود دفترچه یادداشت

در TensorFlow 2 ، اجرای مشتاق به طور پیش فرض روشن می شود. رابط کاربری بصری و انعطاف پذیر است (اجرای عملیات یکبار مصرف بسیار راحت تر و سریعتر است) ، اما این می تواند به قیمت عملکرد و قابلیت استفاده باشد.

برای تهیه نمودار از برنامه های خود می توانید از tf.function استفاده کنید. این یک ابزار تحول است که نمودارهای گردش داده داده مستقل از پایتون را از کد پایتون شما ایجاد می کند. این به شما در ایجاد مدل های قابل اجرا و قابل حمل کمک می کند و استفاده از SavedModel .

این راهنما به شما کمک می کند تا نحوه عملکرد tf.function در زیر کاپوت را مفهوم سازی کنید تا بتوانید به طور م effectivelyثر از آن استفاده کنید.

اقدامات اصلی و توصیه های اصلی عبارتند از:

  • در حالت اشتیاق اشکال زدایی کنید ، سپس با @tf.function تزئین کنید.
  • به عوارض جانبی پایتون مانند جهش جسم یا ضمیمه لیست اعتماد نکنید.
  • tf.function با tf.function به بهترین وجه کار می کند. تماس های NumPy و Python به ثابت تبدیل می شوند.

برپایی

import tensorflow as tf

برای نشان دادن انواع خطاهایی که ممکن است با آنها روبرو شوید ، یک تابع کمکی را تعریف کنید:

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

اصول

استفاده

Function که تعریف می کنید (به عنوان مثال با استفاده از دکوراتور @tf.function ) دقیقاً مانند یک عملیات اصلی TensorFlow است: می توانید با اشتیاق آن را اجرا کنید. می توانید شیب ها را محاسبه کنید. و غیره

@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 در داخل سایر 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.Tensor: shape=(3, 2), dtype=float32, numpy=
array([[3., 3.],
       [3., 3.],
       [3., 3.]], dtype=float32)>

Function s می تواند سریعتر از کد مشتاق باشد ، به خصوص برای نمودارهایی که دارای بسیاری از عملیات کوچک هستند. اما برای نمودارهایی با چند اپلیکیشن گران قیمت (مانند پیچ ​​های پیچشی) ، ممکن است سرعت زیادی نبینید.

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

ردیابی

این بخش نحوه Function زیر کاپوت را نشان می دهد ، از جمله جزئیات اجرای آن که ممکن است در آینده تغییر کند . با این حال ، هنگامی که دلیل و زمان tf.function استفاده از tf.function موثر بسیار آسان تر است!

"ردیابی" چیست؟

یک Function برنامه شما را در نمودار TensorFlow اجرا می کند. با این حال ، tf.Graph نمی تواند تمام مواردی را که می خواهید در یک برنامه مشتاق tf.Graph ، نشان دهد. به عنوان مثال ، پایتون از چند tf.Graph پشتیبانی می کند ، اما tf.Graph نیاز دارد که ورودی های آن نوع و بعد داده مشخصی داشته باشد. یا ممکن است کارهای جانبی مانند خواندن استدلال های خط فرمان ، بالا بردن خطا یا کار با یک جسم پیچیده Python را انجام دهید. هیچ یک از این موارد نمی توانند به صورت tf.Graph اجرا tf.Graph .

Function با جدا کردن کد در دو مرحله ، این شکاف را از بین می برد:

1) در مرحله اول ، که به آن " tracing " گفته می شود ، Function یک tf.Graph جدید ایجاد می کند. کد پایتون به طور معمول اجرا می شود ، اما تمام عملیات TensorFlow (مانند افزودن دو تنور) به تعویق افتاده است : آنها توسط tf.Graph گرفته می tf.Graph و اجرا نمی شوند.

2) در مرحله دوم ، یک tf.Graph که شامل همه مواردی است که در مرحله اول به تعویق افتاده است ، اجرا می شود. این مرحله بسیار سریعتر از مرحله ردیابی است.

بسته به ورودی های خود ، Function همیشه هنگام فراخوانی اولین مرحله را اجرا نمی کند. برای درک بهتر نحوه تعیین آن ، به "قوانین ردیابی" در زیر مراجعه کنید. رد شدن از مرحله اول و تنها اجرای مرحله دوم ، همان چیزی است که عملکرد بالای TensorFlow را در اختیار شما قرار می دهد.

هنگامی که Function تصمیم به ردیابی می گیرد ، مرحله ردیابی بلافاصله مرحله دوم را دنبال می کند ، بنابراین فراخوانی Function هم tf.Graph ایجاد و هم اجرا می کند. بعداً خواهید دید که چگونه می توانید تنها مرحله ردیابی را با get_concrete_function .

وقتی آرگومان های مختلف را به یک Function ، هر دو مرحله اجرا می شوند:

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


توجه داشته باشید که اگر شما مرتباً یک 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())
double(a)
  Args:
    a: float32 Tensor, shape=()
  Returns:
    float32 Tensor, shape=()

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

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

تاکنون مشاهده کرده اید که tf.function یک لایه اعزام پویا ، پنهان شده و منطق ردیابی نمودار tf.function ایجاد می کند. برای اینکه در مورد اصطلاحات دقیق تر باشیم:

  • tf.Graph خام ، زبان-اگنوستیک و قابل حمل محاسبه TensorFlow است.
  • یک ConcreteFunction یک tf.Graph پیچد.
  • یک Function حافظه نهان ConcreteFunction مدیریت می کند و ورودی مناسب را برای ورودی شما انتخاب می کند.
  • tf.function تابع Python را می پیچد ، و یک شی Function tf.function .
  • Tracing یک tf.Graph ایجاد می کند و آن را در ConcreteFunction پیچیده می کند ، همچنین به عنوان ردیابی شناخته می شود .

قوانین ردیابی

یک Function تعیین می کند که آیا از ConcreteFunction ردیابی شده با محاسبه یک کلید حافظه نهان از کمان ها و کوارگ های ورودی استفاده مجدد شود. کلید حافظه پنهان ، کلیدی است که با توجه به قوانین زیر (که ممکن است تغییر کند) ConcreteFunction بر اساس آرگهای ورودی و کوارگ های فراخوانی Function می کند:

  • کلید تولید شده برای استدلال tf.Tensor شکل و نوع آن است.
  • با شروع TensorFlow 2.3 ، کلیدی که برای یک tf.Variable استدلال tf.Variable id() آن است id() .
  • کلیدی که برای یک اولیه پایتون تولید می شود مقدار آن است. کلیدی که برای s ، namedtuple dict ، list s ، tuple s ، namedtuple s و attr شود ، تاپل مسطح است. (در نتیجه این پهن شدن ، فراخوانی عملکرد بتنی با ساختار تودرتو متفاوت از عملکردی که در حین ردیابی استفاده شده منجر به ایجاد TypeError خواهد شد).
  • برای همه انواع دیگر پایتون ، کلیدها بر اساس object id() تا روش ها به طور مستقل برای هر نمونه از یک کلاس ردیابی شوند.

کنترل بازیابی

جستجوی مجدد ، که زمانی است که Function شما بیش از یک ردی ایجاد می کند ، به شما اطمینان می دهد که TensorFlow نمودارهای صحیحی را برای هر مجموعه ورودی تولید می کند. با این حال ردیابی عملیاتی پرهزینه است! اگر Function شما نمودار جدیدی را برای هر تماس tf.function کند ، متوجه می شوید که کد شما کندتر از آنچه از tf.function استفاده tf.function .

برای کنترل رفتار ردیابی ، می توانید از تکنیک های زیر استفاده کنید:

  • input_signature در tf.function برای محدود کردن ردیابی مشخص کنید.
@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-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-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-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-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))

  • برای ایجاد انعطاف پذیری در استفاده مجدد از tf.TensorSpec ابعاد [None] را در tf.TensorSpec مشخص کنید.

    از آنجا که TensorFlow بر اساس شکل آنها با تانسورها مطابقت دارد ، استفاده از یک بعد None به عنوان یک کلمه وحشی به Function s امکان استفاده مجدد از ردیابی ها را برای ورودی با اندازه متغیر می دهد. اگر توالی هایی با طول متفاوت یا تصاویر با اندازه های مختلف برای هر دسته داشته باشید ، ورودی به اندازه متغیر می تواند رخ دهد (برای مثال به آموزشهای Transformer و Deep Dream مراجعه کنید).

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

  • استدلال های Python را برای کاهش بازگرداندن به تنورها ارائه دهید.

    غالباً ، از آرگومان های پایتون برای کنترل num_layers=10 پارامترها و ساختارهای نمودار استفاده می شود - به عنوان مثال ، num_layers=10 یا training=True یا nonlinearity='relu' . بنابراین اگر آرگومان پایتون تغییر کند ، منطقی است که مجبور شوید نمودار را دوباره تهیه کنید.

    با این حال ، ممکن است که از آرگومان پایتون برای کنترل ساخت نمودار استفاده نشده باشد. در این موارد ، تغییر در مقدار پایتون می تواند باعث بازگرداندن بدون نیاز شود. به عنوان مثال ، این حلقه آموزش را در نظر بگیرید ، که AutoGraph به صورت پویا آن را باز می کند. با وجود ردپاهای متعدد ، نمودار ایجاد شده در واقع یکسان است ، بنابراین بازگرداندن آن غیر ضروری است.

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

اگر نیاز به بازگرداندن مجدد دارید ، یک Function جدید ایجاد کنید. اشیاction Function جداگانه تضمین می کنند که ردیابی نمی کنند.

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

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

دستیابی به توابع بتن

هر بار که یک تابع ردیابی می شود ، یک تابع بتن جدید ایجاد می شود. با استفاده از get_concrete_function می توانید مستقیماً یک عملکرد بتن بدست 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")))
Tracing with Tensor("a:0", shape=(), dtype=string)
tf.Tensor(b'cc', shape=(), dtype=string)

چاپ ConcreteFunction خلاصه ای از آرگومان های ورودی آن (با انواع) و نوع خروجی آن را نمایش می دهد.

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

همچنین می توانید امضای یک عملکرد بتن را مستقیماً بازیابی کنید.

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

استفاده از ردیابی بتونی با انواع ناسازگار خطایی ایجاد می کند

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]

ممکن است متوجه شوید که استدلالهای پایتون در امضای ورودی یک تابع بتن رفتار ویژه ای دارند. قبل از TensorFlow 2.3 ، استدلال های پایتون به سادگی از امضای عملکرد بتن حذف شدند. با شروع TensorFlow 2.3 ، آرگومان های پایتون در امضا باقی می مانند ، اما محدود به گرفتن مقدار تعیین شده در هنگام ردیابی هستند.

@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 1683, in _call_impl
    cancellation_manager)
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 1728, 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

به دست آوردن نمودارها

هر عملکرد بتن یک بسته بندی قابل تماس با یک tf.Graph . اگرچه بازیابی شی واقعی 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.function . قبل از تزئین با tf.function باید اطمینان حاصل کنید که کد شما در حالت مشتاق بدون خطا اجرا می شود. برای کمک به روند اشکال زدایی ، می توانید با tf.config.run_functions_eagerly(True) تماس بگیرید تا tf.config.run_functions_eagerly(True) در سطح جهانی غیرفعال و دوباره فعال tf.function .

هنگام ردیابی مسائلی که فقط در tf.function نظر می tf.function ، در اینجا چند نکته وجود دارد:

  • تماس های print قدیمی پایتون فقط هنگام ردیابی اجرا می شوند ، به شما کمک می کند وقتی عملکرد شما ردیابی می شود ردیابی کنید.
  • تماس های tf.print هر بار اجرا می شوند و می توانند به شما کمک کنند مقادیر متوسط ​​را در حین اجرا ردیابی کنید.
  • tf.debugging.enable_check_numerics راهی آسان برای ردیابی محل ایجاد NaN و Inf است.
  • pdb می تواند به شما کمک کند بفهمید که در هنگام ردیابی چه خبر است. (Caveat: PDB شما را در کد منبع تبدیل شده توسط AutoGraph رها می کند.)

تحولات خودکار نمودار

AutoGraph کتابخانه ای است که به طور پیش فرض در tf.function و زیرمجموعه ای از کد مشتاق Python را به گزینه های سازگار با نمودار tf.function تبدیل می کند. این شامل جریان کنترل مانند if ، for ، while .

گزینه های tf.cond مانند tf.cond و tf.while_loop به کار خود ادامه می دهند ، اما نوشتن و فهم جریان کنترل اغلب هنگام نوشتن در پایتون راحت تر است.

# 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.418865323 0.911027312 0.382812262 0.722406387 0.160078526]
[0.39597407 0.721625 0.365147263 0.618397713 0.158725053]
[0.376498967 0.617914855 0.34973979 0.550011516 0.157405376]
[0.359663159 0.549674571 0.336144745 0.500528812 0.156118125]
[0.344917297 0.500276268 0.324031234 0.462533 0.154862]
[0.331860244 0.462334394 0.313147396 0.43214643 0.15363577]
[0.320191294 0.431984901 0.303297669 0.407113552 0.152438238]
[0.309679836 0.406978786 0.294327527 0.386019081 0.151268333]
[0.300145775 0.385904342 0.286112964 0.36792323 0.150125]
[0.29144603 0.367824018 0.278553277 0.352173865 0.149007246]
[0.283465207 0.352086931 0.271565557 0.338302 0.147914127]
[0.276109159 0.338225 0.265080959 0.325960636 0.146844745]
[0.269300193 0.325891823 0.259041727 0.31488657 0.145798281]
[0.262973547 0.314824551 0.253399 0.304876 0.144773886]
[0.257074684 0.304819793 0.248111084 0.29576847 0.143770814]
[0.25155738 0.29571715 0.243142202 0.287435412 0.142788336]
[0.246382073 0.287388295 0.238461465 0.279772669 0.14182575]
[0.241514727 0.279729217 0.234042 0.272694677 0.140882403]
[0.23692593 0.272654444 0.229860321 0.266130418 0.139957651]
[0.232590035 0.266093045 0.225895762 0.260020494 0.139050901]
[0.228484616 0.259985656 0.222130179 0.254314691 0.13816157]
[0.224589869 0.254282087 0.218547404 0.248970196 0.137289107]
[0.220888361 0.248939633 0.215133116 0.243950352 0.13643299]
[0.217364609 0.243921608 0.211874455 0.23922351 0.135592714]
[0.214004785 0.239196405 0.208759964 0.234762147 0.134767786]
[0.210796505 0.234736577 0.20577924 0.230542287 0.133957744]
[0.207728744 0.230518073 0.202923 0.226542845 0.133162171]

<tf.Tensor: shape=(5,), dtype=float32, numpy=
array([0.20479149, 0.22651988, 0.20018281, 0.22274524, 0.13238062],
      dtype=float32)>

اگر کنجکاو هستید می توانید کد تولید شده خودنویس را بررسی کنید.

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)


مشروط

AutoGraph برخی از دستورات if <condition> را به تماس های معادل tf.cond می کند. اگر <condition> یک Tensor باشد این تعویض انجام می <condition> . در غیر این صورت ، دستور if به صورت شرطی پایتون اجرا می شود.

شرط Python در حین ردیابی اجرا می شود ، بنابراین دقیقاً یک شاخه از شرط به نمودار اضافه می شود. بدون وجود AutoGraph ، در صورت وجود جریان کنترل وابسته به داده ، این نمودار پیگیری شده قادر به گرفتن شاخه جایگزین نخواهد بود.

tf.cond ردیابی می کند و هر دو شاخه شرطی را به نمودار اضافه می کند ، یک شاخه را در زمان اجرا به صورت پویا انتخاب می کند. ردیابی می تواند عوارض جانبی ناخواسته ای داشته باشد. برای اطلاعات بیشتر به جلوه های ردیابی خودکار نمودار مراجعه کنید.

@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 برخی از دستورات for و while را به گزینه های معادل حلقه TensorFlow تبدیل می کند ، مانند tf.while_loop . اگر تبدیل نشود ، حلقه for یا while به عنوان حلقه Python اجرا می شود.

این جایگزینی در شرایط زیر انجام می شود:

  • for x in y : اگر y یک Tensor است ، به tf.while_loop تبدیل کنید. در حالت خاص که y یکtf.data.Dataset ، ترکیبی ازtf.data.Dataset هایtf.data.Dataset ایجاد می شود.
  • while <condition> : اگر <condition> Tensor است ، به tf.while_loop تبدیل کنید.

یک حلقه پایتون در حین ردیابی اجرا می شود و گزینه های اضافی به tf.Graph اضافه می کند. tf.Graph برای هر تکرار حلقه.

یک حلقه TensorFlow بدن حلقه را ردیابی می کند و به صورت پویا تعداد تکرارها را برای اجرا در زمان اجرا انتخاب می کند. بدنه حلقه فقط یک بار در tf.Graph تولید شده tf.Graph .

را ببینید اسناد مرجع برای محدودیت های بیشتر در دستخط-تبدیل for و while اظهارات.

حلقه زدن روی داده های پایتون

یک دام مشترک این است که داده های Python / Numpy را در یک tf.function . tf.function . این حلقه در طول فرایند ردیابی اجرا می شود و یک کپی از مدل خود را به tf.Graph کند. tf.Graph برای هر تکرار حلقه.

اگر می خواهید کل حلقه آموزش را در tf.function ، مطمئن ترین راه برای انجام این کار بسته بندی داده های خود به صورتtf.data.Dataset تا AutoGraph به صورت پویا حلقه آموزش را باز کند.

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 در یک مجموعه داده ، مراقب tf.data.Dataset.from_generator در مقابل tf.data.Dataset.from_tensors . مورد اول داده ها را در پایتون نگه داشته و از طریق tf.py_function که می تواند پیامدهای عملکردی داشته باشد ، واکشی می کند ، در حالی که دومی نسخه ای از داده را به عنوان یک گره tf.constant() بزرگ در نمودار قرار می دهد که می تواند پیامدهای حافظه داشته باشد.

خواندن داده ها از طریق TFRecordDataset / CsvDataset / و غیره م effectiveثرترین روش برای مصرف داده است ، زیرا در این صورت TensorFlow خودش می تواند بارگیری و پیش بارگیری همزمان داده ها را بدون نیاز به پایتون مدیریت کند. برای کسب اطلاعات بیشتر ، به راهنمای tf.data مراجعه کنید .

مقادیر جمع شده در یک حلقه

یک الگوی معمول جمع آوری مقادیر میانی از یک حلقه است. به طور معمول ، این کار با الحاق به لیست پایتون یا اضافه کردن ورودی به فرهنگ لغت پایتون انجام می شود. با این حال ، از آنجا که اینها عوارض جانبی پایتون هستند ، در یک حلقه باز نشده پویا مطابق انتظار عمل نخواهند کرد. برای جمع آوری نتایج حاصل از یک حلقه باز نشده به صورت پویا ، از tf.TensorArray استفاده کنید.

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.04024231, 0.8750231 , 0.7828673 , 0.95796347],
        [0.6933379 , 1.4302992 , 1.0286844 , 1.2873636 ],
        [1.0946463 , 2.3919935 , 1.383383  , 1.6184174 ]],

       [[0.35952663, 0.8509462 , 0.04545867, 0.40333533],
        [0.43437874, 1.1436893 , 0.31203532, 0.4216336 ],
        [0.46808207, 1.8400187 , 0.3120687 , 1.1190954 ]]], dtype=float32)>

محدودیت ها

Function TensorFlow با طراحی محدودیت هایی دارد که هنگام تبدیل یک تابع پایتون به یک Function باید از آنها مطلع باشید.

اجرای عوارض جانبی پایتون

عوارض جانبی مانند چاپ ، ضمیمه کردن لیست ها و جهش جهانی ، می توانند در یک Function غیرمنتظره رفتار کنند ، گاهی اوقات دو بار اجرا می شوند یا نه همه. آنها فقط در اولین باری که شما یک Function با مجموعه ای از ورودی فراخوانی می کنید اتفاق می افتد. پس از آن ، tf.Graph ردیابی شده بدون اجرای کد پایتون دوباره اجرا می شود.

قانون کلی این است که در منطق خود به اتکای به عوارض جانبی پایتون خودداری کنید و فقط از آنها برای اشکال زدایی از ردیابی های خود استفاده کنید. در غیر این صورت ، API های tf.data مانند tf.data ، tf.print ، tf.summary ، tf.Variable.assign و tf.TensorArray بهترین راه برای اطمینان از اجرای کد شما توسط زمان اجرا TensorFlow با هر تماس هستند.

@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

اگر می خواهید در هر فراخوانی یک Function کد پایتون را اجرا کنید ، tf.py_function یک دریچه خروج است. اشکال tf.py_function این است که قابل حمل نیست یا عملکرد خاصی ندارد ، با SavedModel ذخیره نمی شود و در تنظیمات توزیع شده (چند GPU ، TPU) به خوبی کار نمی کند. همچنین ، از آنجا که tf.py_function باید به نمودار وصل شود ، تمام ورودی ها / خروجی ها را به تنسورها منتقل می کند.

تغییر متغیرهای جهانی و رایگان پایتون

تغییر متغیرهای جهانی و رایگان پایتون به عنوان یک عارضه جانبی پایتون محسوب می شود ، بنابراین فقط در هنگام ردیابی اتفاق می افتد.

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

باید از جهش دادن ظروف مانند لیست ها ، حکم ها ، اشیا objects دیگری که خارج از Function زندگی می کنند ، خودداری کنید. در عوض ، از آرگومان ها و اشیا T TF استفاده کنید. به عنوان مثال ، بخش "تجمع مقادیر در یک حلقه" دارای یک مثال از نحوه اجرای عملیات مانند لیست است.

اگر در حالت tf.Variable باشد ، می توانید حالت را ضبط و دستکاری کنید. به این ترتیب است که وزن مدل های Keras با تماس های مکرر با همان ConcreteFunction .

استفاده از تکرارکننده ها و مولدهای پایتون

بسیاری از ویژگی های پایتون ، مانند مولد ها و تکرارکننده ها ، برای پیگیری وضعیت ، به زمان اجرای پایتون متکی هستند. به طور کلی ، اگرچه این سازه ها همانطور که انتظار می رود در حالت اشتیاق کار می کنند ، آنها نمونه هایی از عوارض جانبی پایتون هستند و بنابراین فقط در هنگام ردیابی اتفاق می افتند.

@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

دقیقاً مانند این که tf.TensorArray یک tf.TensorArray تخصصی دارد. tf.TensorArray برای سازه های لیست ، یک tf.data.Iterator تخصصی دارد. تکرار سازه های تکرار. برای نمای کلی به بخش تغییرات خودکار نمودار مراجعه کنید. همچنین ، tf.data API می تواند به اجرای الگوهای ژنراتور کمک کند:

@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

حذف tf. بین تماسهای Function متغیر است

خطای دیگری که ممکن است با آن روبرو شوید متغیر جمع آوری زباله است. ConcreteFunction فقط WeakRef ها را در متغیرهایی که بسته می شوند حفظ می کند ، بنابراین باید به هر متغیری اشاره داشته باشید.

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: 2 root error(s) found.
  (0) Failed precondition:  Error while reading resource variable _AnonymousVar3 from Container: localhost. This could mean that the variable was uninitialized. Not found: Resource localhost/_AnonymousVar3/N10tensorflow3VarE does not exist.
     [[node ReadVariableOp (defined at <ipython-input-1-9a93d2e07632>:4) ]]
  (1) Failed precondition:  Error while reading resource variable _AnonymousVar3 from Container: localhost. This could mean that the variable was uninitialized. Not found: Resource localhost/_AnonymousVar3/N10tensorflow3VarE does not exist.
     [[node ReadVariableOp (defined at <ipython-input-1-9a93d2e07632>:4) ]]
     [[ReadVariableOp/_2]]
0 successful operations.
0 derived errors ignored. [Op:__inference_f_782]

Function call stack:
f -> f


مشکلات شناخته شده

اگر Function شما به درستی ارزیابی نمی شود ، ممکن است خطا توسط این موارد شناخته شده که در آینده برطرف می شود ، توضیح داده شود.

بسته به متغیرهای جهانی و رایگان پایتون

Function هنگامی که با مقدار جدیدی از آرگومان Python فراخوانی می شود ، یک ConcreteFunction جدید ایجاد می کند. با این حال ، این کار را برای بسته شدن پایتون ، جهانی یا غیر محلی آن Function . اگر مقدار آنها در بین فراخوانی های Function ، Function همچنان از مقادیری که هنگام ردیابی داشته اند استفاده خواهد کرد. این متفاوت از نحوه عملکرد منظم پایتون است.

به همین دلیل ، ما یک سبک برنامه نویسی کاربردی را پیشنهاد می دهیم که به جای بسته کردن نام های خارجی ، از آرگومان ها استفاده می کند.

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

به شرطی که مقادیر آنها را به روز نکنید ، می توانید نامهای خارجی را ببندید.

به اشیا Py پایتون بستگی دارد

توصیه برای انتقال اشیا tf.function پایتون به عنوان آرگومان در tf.function دارای چندین مسئله شناخته شده است که انتظار می رود در آینده برطرف شوند. به طور کلی ، اگر از یک ساختار اولیه سازگار با Python یا tf.nest به عنوان آرگومان استفاده کنید یا از نمونه دیگری از یک شی به یک Function عبور کنید ، می توانید به ردیابی سازگار اعتماد کنید. با این حال ، هنگامی که از همان شی عبور می کنید و فقط ویژگی های آن را تغییر می دهید ، Function ردیابی جدید ایجاد نمی کند.

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)

استفاده از همان Function برای ارزیابی نمونه به روز شده مدل اشکالی نخواهد داشت زیرا مدل به روز شده دارای همان حافظه نهان همان مدل اصلی است.

به همین دلیل ، توصیه می کنیم Function خود را بنویسید تا از این امر به ویژگی های شی mut قابل تغییر یا ایجاد اشیا new جدید اجتناب کنید.

اگر این امکان وجود ندارد ، یک راه حل این است که هر بار که شی your خود را تغییر می دهید تا عملکرد را مجدداً تغییر دهید ، Function جدیدی ایجاد کنید:

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)

از آنجا که بازگردانی می تواند گران باشد ، می توانید از tf.Variable به عنوان ویژگی های شی استفاده کنید که می تواند برای یک اثر مشابه بدون نیاز به استفاده مجدد ، جهش یابد (اما بدون تغییر ، دقیق!).

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.Variables

Function فقط از ایجاد متغیرها یکبار ، هنگامی که برای اولین بار فراخوانی می شوند ، و سپس دوباره استفاده می کند. شما نمی توانید tf.Variables در ردیابی های جدید ایجاد کنید. در حال حاضر ایجاد متغیرهای جدید در تماس های بعدی مجاز نیست ، اما در آینده خواهد بود.

مثال:

@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.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:731 invalid_creator_scope
        "tf.function-decorated function tried to create "

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


می توانید متغیرهایی را در داخل یک Function ایجاد کنید به شرطی که این متغیرها فقط در اولین باری که تابع اجرا می شود ایجاد شوند.

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)

استفاده با چندین بهینه ساز Keras

ممکن است با ValueError: tf.function-decorated function tried to create variables on non-first call. روبرو شوید ValueError: tf.function-decorated function tried to create variables on non-first call. هنگام استفاده از بیش از یک بهینه ساز Keras با عملکرد tf.function . این خطا به این دلیل رخ می دهد که بهینه tf.Variables وقتی برای اولین بار از شیب استفاده می کنند tf.Variables ایجاد می کنند.

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.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:604 apply_gradients  **
        self._create_all_weights(var_list)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:781 _create_all_weights
        _ = self.iterations
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:788 __getattribute__
        return super(OptimizerV2, self).__getattribute__(name)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:926 iterations
        aggregation=tf_variables.VariableAggregation.ONLY_FIRST_REPLICA)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:1132 add_weight
        aggregation=aggregation)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/base.py:810 _add_variable_with_custom_getter
        **kwargs_for_getter)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer_utils.py:142 make_variable
        shape=variable_shape if variable_shape else None)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:260 __call__
        return cls._variable_v1_call(*args, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:221 _variable_v1_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:731 invalid_creator_scope
        "tf.function-decorated function tried to create "

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


در صورت نیاز به تغییر بهینه ساز در حین آموزش ، ایجاد یک Function جدید برای هر بهینه ساز با تماس مستقیم با ConcreteFunction .

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.

با استفاده از چندین مدل Keras

همچنین ممکن است با ValueError: tf.function-decorated function tried to create variables on non-first call. روبرو شوید ValueError: tf.function-decorated function tried to create variables on non-first call. هنگام انتقال نمونه های مختلف مدل به همان Function .

این خطا به این دلیل رخ می دهد که مدل های Keras (که شکل ورودی آنها مشخص نیست ) و لایه های Keras هنگام tf.Variables s ایجاد می کنند. ممکن است شما در تلاش باشید که آن متغیرها را در داخل یک Function ، که قبلاً فراخوانی شده است ، مقداردهی اولیه کنید. برای جلوگیری از این خطا ، سعی کنید با model.build(input_shape) فراخوانی کنید تا قبل از آموزش مدل ، تمام وزن ها مقدار دهی شود.

خواندن بیشتر

برای کسب اطلاعات در مورد نحوه صادرات و بارگذاری یک Function ، به راهنمای SavedModel مراجعه کنید . برای کسب اطلاعات بیشتر در مورد بهینه سازی نمودار که پس از ردیابی انجام می شود ، به راهنمای Grappler مراجعه کنید. برای یادگیری نحوه بهینه سازی خط لوله داده و نمایه سازی مدل خود ، به راهنمای Profiler مراجعه کنید.