این صفحه به‌وسیله ‏Cloud Translation API‏ ترجمه شده است.
Switch to English

آشنایی با نمودارها و توابع

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

آشنایی با نمودارها و tf.function

این راهنما زیر سطح TensorFlow و Keras می رود تا ببیند چگونه TensorFlow کار می کند. اگر به جای آن می خواهید بلافاصله با Keras شروع به کار کنید ، لطفاً به مجموعه راهنمای ما از Keras مراجعه کنید .

در این راهنما هسته اصلی نحوه TensorFlow به شما امکان می دهد تغییرات ساده ای را در کد خود ایجاد کنید تا نمودارها ، نحوه ذخیره و نمایش آنها و نحوه استفاده از آنها را برای تسریع و صادرات مدل های خود انجام دهید.

این یک معرفی کوتاه است؛ برای معرفی کامل این مفاهیم ، به راهنمای tf.function .

نمودارها چیست؟

در سه راهنما قبلی ، شما TensorFlow را مشتاقانه مشاهده کرده اید. این بدان معنی است که عملیات TensorFlow توسط پایتون ، عملیاتی با عملیات انجام می شود و نتایج را به پایتون باز می گرداند. مشتاق TensorFlow از GPU استفاده می کند و به شما امکان می دهد متغیرها ، تنسورها و حتی عملیات را روی GPU و TPU قرار دهید. اشکال زدایی نیز آسان است.

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

با این حال ، اجرای TensorFlow به صورت عملی در Python مانع از تسریع تعداد زیادی شتاب در غیر این صورت می شود. اگر می توانید محاسبات تانسور را از Python استخراج کنید ، می توانید آنها را در یک نمودار قرار دهید .

نمودارها ساختار داده هایی هستند که شامل مجموعه ای از اشیاء tf.Operation که واحدهای محاسبه را نشان می دهند. و tf.Tensor اشیاء ، که نمایانگر واحدهای داده است که بین عملیات جریان دارند. آنها در یک زمینه tf.Graph تعریف شده اند. از آنجا که این نمودارها ساختار داده هستند ، می توانند بدون کد اصلی پایتون ذخیره ، اجرا و بازیابی شوند.

این همان چیزی است که وقتی در TensorBoard تجسم می شود ، یک نمودار ساده دو لایه به نظر می رسد.

نمودار کششی دو لایه

فواید نمودارها

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

نمودارها نیز به راحتی بهینه سازی می شوند و به کامپایلر این امکان را می دهند تا دگرگونی هایی مانند:

  • با خم کردن گره های ثابت در محاسبات خود ("تاشو ثابت") مقدار تنش ها را استاتیک استنباط کنید.
  • زیر بخش های یک محاسبه را که مستقل هستند جدا کنید و آنها را بین موضوعات یا دستگاه ها تقسیم کنید.
  • عملیات ریاضی را با از بین بردن زیرپوشش های رایج ساده کنید.

یک سیستم بهینه سازی کامل ، Grappler ، برای انجام این کار و سایر سرعت های سریع وجود دارد.

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

با این حال ، شما هنوز هم می خواهید برای راحتی ، مدل های یادگیری ماشین (یا محاسبات دیگر) خود را در پایتون تعریف کنید ، و سپس در صورت نیاز به طور خودکار نمودارها را بسازید.

ردیابی نمودارها

روش ایجاد نمودار در tf.function استفاده از tf.function ، یا به صورت تماس مستقیم یا به عنوان تزئین کننده است.

 import tensorflow as tf
import timeit
from datetime import datetime
 
 # Define a Python function
def function_to_get_faster(x, y, b):
  x = tf.matmul(x, y)
  x = x + b
  return x

# Create a `Function` object that contains a graph
a_function_that_uses_a_graph = tf.function(function_to_get_faster)

# Make some tensors
x1 = tf.constant([[1.0, 2.0]])
y1 = tf.constant([[2.0], [3.0]])
b1 = tf.constant(4.0)

# It just works!
a_function_that_uses_a_graph(x1, y1, b1).numpy()
 
array([[12.]], dtype=float32)

tf.function -ized توابع فراخوانیهایی پایتون که همان کار به عنوان معادل پایتون است. آنها کلاس خاصی دارند ( python.eager.def_function.Function ) ، اما برای شما آنها مانند نسخه غیر دنباله عمل می کنند.

tf.function هر عملکرد پایتون را که می خواند ، ردیابی می کند.

 def inner_function(x, y, b):
  x = tf.matmul(x, y)
  x = x + b
  return x

# Use the decorator
@tf.function
def outer_function(x):
  y = tf.constant([[2.0], [3.0]])
  b = tf.constant(4.0)

  return inner_function(x, y, b)

# Note that the callable will create a graph that
# includes inner_function() as well as outer_function()
outer_function(tf.constant([[1.0, 2.0]])).numpy()
 
array([[12.]], dtype=float32)

اگر شما TensorFlow نگارش 1.x استفاده کرده اند، متوجه خواهید شد که در هیچ زمان آیا شما نیاز به تعریف یک Placeholder و یا tf.Sesssion .

کنترل جریان و عوارض جانبی

کنترل جریان و حلقه ها به طور پیش فرض از طریق tf.autograph شوند. Autograph از ترکیبی از روشها استفاده می کند ، از جمله استاندارد سازی سازه های حلقه ، کنترل نشده و دستکاری AST .

 def my_function(x):
  if tf.reduce_sum(x) <= 1:
    return x * x
  else:
    return x-1

a_function = tf.function(my_function)

print("First branch, with graph:", a_function(tf.constant(1.0)).numpy())
print("Second branch, with graph:", a_function(tf.constant([5.0, 5.0])).numpy())
 
First branch, with graph: 1.0
Second branch, with graph: [4. 4.]

می توانید مستقیماً با تبدیل Autograph تماس بگیرید تا ببینید چگونه پایتون به گزینه TensorFlow تبدیل می شود. این ، بیشتر ، غیرقابل خواندن است ، اما می توانید تحول را ببینید.

 # Don't read the output too carefully.
print(tf.autograph.to_code(my_function))
 
def tf__my_function(x):
    with ag__.FunctionScope('my_function', '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 (retval_, do_return)

        def set_state(vars_):
            nonlocal retval_, do_return
            (retval_, do_return) = vars_

        def if_body():
            nonlocal retval_, do_return
            try:
                do_return = True
                retval_ = (ag__.ld(x) * ag__.ld(x))
            except:
                do_return = False
                raise

        def else_body():
            nonlocal retval_, do_return
            try:
                do_return = True
                retval_ = (ag__.ld(x) - 1)
            except:
                do_return = False
                raise
        ag__.if_stmt((ag__.converted_call(ag__.ld(tf).reduce_sum, (ag__.ld(x),), None, fscope) <= 1), if_body, else_body, get_state, set_state, ('retval_', 'do_return'), 2)
        return fscope.ret(retval_, do_return)


Autograph به طور خودکار بندهای if-then ، حلقه ها ، break ، return ، continue و موارد دیگر را تبدیل می کند.

بیشتر اوقات ، Autograph بدون ملاحظات خاص کار خواهد کرد. با این حال ، برخی از هشدارها وجود دارد ، و راهنمای tf.function می تواند در اینجا کمک کند ، و همچنین مرجع کامل خودکارنگاری

سرعت را می بینید

فقط tf.function یک تابع با استفاده از تنسور در عملکرد tf.function به طور خودکار سرعت کد شما را افزایش نمی دهد. برای عملکردهای کوچک که چند بار بر روی یک دستگاه واحد خوانده می شود ، سربار فراخوانی یک قطعه نمودار یا نمودار ممکن است در زمان اجرا مسلط شود. همچنین ، اگر بیشتر محاسبات قبلاً روی یک شتاب دهنده اتفاق افتاده باشد ، مانند پشته های کاناله های GPU-سنگین ، سرعت گراف زیاد نخواهد بود.

برای محاسبات پیچیده ، نمودارها می توانند باعث افزایش سرعت علامت گذاری شوند. این امر به این دلیل است که نمودارها ارتباطات پایتون به دستگاه را کاهش می دهند و برخی از سرعتی ها را انجام می دهند.

این کد چند بار روی چند لایه متراکم کوچک اجرا می شود.

 # Create an oveerride model to classify pictures
class SequentialModel(tf.keras.Model):
  def __init__(self, **kwargs):
    super(SequentialModel, self).__init__(**kwargs)
    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))
    self.dense_1 = tf.keras.layers.Dense(128, activation="relu")
    self.dropout = tf.keras.layers.Dropout(0.2)
    self.dense_2 = tf.keras.layers.Dense(10)

  def call(self, x):
    x = self.flatten(x)
    x = self.dense_1(x)
    x = self.dropout(x)
    x = self.dense_2(x)
    return x

input_data = tf.random.uniform([60, 28, 28])

eager_model = SequentialModel()
graph_model = tf.function(eager_model)

print("Eager time:", timeit.timeit(lambda: eager_model(input_data), number=10000))
print("Graph time:", timeit.timeit(lambda: graph_model(input_data), number=10000))

 
Eager time: 4.9249971129993355
Graph time: 2.026840765000088

توابع چند شکل

هنگامی که یک عملکرد را ردیابی می کنید ، یک شیء Function ایجاد می کنید چند شکل است . یک عملکرد چند شکل یک پایتون قابل تماس است که چندین نمودار عملکرد بتن را در پشت یک API محصور می کند.

شما می توانید این Function در انواع مختلف از dtypes و اشکال. هر بار که آن را با امضای آرگومان جدید فراخوانی کنید ، عملکرد اصلی با آرگومان های جدید دوباره ردیابی می شود. Function پس از ذخیره tf.Graph مربوط به آن اثری در یک concrete_function . اگر تابعی از قبل با آن نوع استدلال ردیابی شده است ، فقط نمودار پیش بینی شده خود را دریافت می کنید.

از نظر مفهومی ، پس از آن:

  • tf.Graph ساختار داده های قابل حمل و خام است که محاسبات را توصیف می کند
  • Function یک حافظه پنهان ، ردیابی ، توزیع کننده ConcreteFunctions است
  • ConcreteFunction یک بسته بندی سازگار با اشتیاق است که در اطراف یک نمودار قرار دارد و به شما امکان می دهد تا نمودار را از Python اجرا کنید.

بازرسی عملکردهای چند شکل

می توانید a_function بازرسی a_function ، که نتیجه فراخوانی tf.function در عملکرد Python my_function . در این مثال ، فراخوانی a_function با سه نوع آرگومان منجر به سه عملکرد متفاوت بتن می شود.

 print(a_function)

print("Calling a `Function`:")
print("Int:", a_function(tf.constant(2)))
print("Float:", a_function(tf.constant(2.0)))
print("Rank-1 tensor of floats", a_function(tf.constant([2.0, 2.0, 2.0])))
 
<tensorflow.python.eager.def_function.Function object at 0x7f466417bf60>
Calling a `Function`:
Int: tf.Tensor(1, shape=(), dtype=int32)
Float: tf.Tensor(1.0, shape=(), dtype=float32)
Rank-1 tensor of floats tf.Tensor([1. 1. 1.], shape=(3,), dtype=float32)

 # Get the concrete function that works on floats
print("Inspecting concrete functions")
print("Concrete function for float:")
print(a_function.get_concrete_function(tf.TensorSpec(shape=[], dtype=tf.float32)))
print("Concrete function for tensor of floats:")
print(a_function.get_concrete_function(tf.constant([2.0, 2.0, 2.0])))

 
Inspecting concrete functions
Concrete function for float:
ConcreteFunction my_function(x)
  Args:
    x: float32 Tensor, shape=()
  Returns:
    float32 Tensor, shape=()
Concrete function for tensor of floats:
ConcreteFunction my_function(x)
  Args:
    x: float32 Tensor, shape=(3,)
  Returns:
    float32 Tensor, shape=(3,)

 # Concrete functions are callable
# Note: You won't normally do this, but instead just call the containing `Function`
cf = a_function.get_concrete_function(tf.constant(2))
print("Directly calling a concrete function:", cf(tf.constant(2)))
 
Directly calling a concrete function: tf.Tensor(1, shape=(), dtype=int32)

در این مثال ، شما تقریباً در پشته مشاهده می کنید. مگر در مواردی که به طور خاص ردیابی را کنترل کرده باشید ، دیگر نیازی به تماس مستقیم با عملکردهای بتونی مانند تصویر زیر نیست.

بازگشت به اعدام مشتاق

شما ممکن است خود را در حال یافتن آثار پشته بلند ، به ویژه مواردی که به tf.Graph یا with tf.Graph().as_default() . این بدان معنی است که شما به احتمال زیاد در یک متن نمودار اجرا می کنید. توابع هسته در model.fit() از model.fit() استفاده می کند ، مانند مدل model.fit() . Keras model.fit() .

اغلب اشکال زدایی در اجرای اعدام مشتاقانه بسیار ساده تر است. آثار پشته باید نسبتاً کوتاه و درک آسانی باشد.

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

در اینجا روش هایی وجود دارد که می توانید با اشتیاق در حال اجرا باشید:

  • مدل ها و لایه ها را مستقیماً به عنوان تماس پذیر تماس بگیرید

  • هنگام استفاده از کامپایل / مناسب model.compile(run_eagerly=True) ، در زمان کامپایل استفاده از model.compile(run_eagerly=True)

  • حالت اجرای جهانی را از طریق tf.config.run_functions_eagerly(True) تنظیم کنید tf.config.run_functions_eagerly(True)

استفاده از run_eagerly=True

 # Define an identity layer with an eager side effect
class EagerLayer(tf.keras.layers.Layer):
  def __init__(self, **kwargs):
    super(EagerLayer, self).__init__(**kwargs)
    # Do some kind of initialization here

  def call(self, inputs):
    print("\nCurrently running eagerly", str(datetime.now()))
    return inputs
 
 # Create an override model to classify pictures, adding the custom layer
class SequentialModel(tf.keras.Model):
  def __init__(self):
    super(SequentialModel, self).__init__()
    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))
    self.dense_1 = tf.keras.layers.Dense(128, activation="relu")
    self.dropout = tf.keras.layers.Dropout(0.2)
    self.dense_2 = tf.keras.layers.Dense(10)
    self.eager = EagerLayer()

  def call(self, x):
    x = self.flatten(x)
    x = self.dense_1(x)
    x = self.dropout(x)
    x = self.dense_2(x)
    return self.eager(x)

# Create an instance of this model
model = SequentialModel()

# Generate some nonsense pictures and labels
input_data = tf.random.uniform([60, 28, 28])
labels = tf.random.uniform([60])

loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
 

ابتدا مدل را بدون اشتیاق کامپایل کنید. توجه داشته باشید که مدل ردیابی نشده است. علیرغم نام آن ، compile فقط توابع از دست دادن ، بهینه سازی و سایر پارامترهای آموزشی را تنظیم می کند.

 model.compile(run_eagerly=False, loss=loss_fn)
 

اکنون ، fit تماس بگیرید و ببینید که این عملکرد (دو بار) ردیابی شده است و دیگر هیچ وقت اثر مشتاق دوباره اجرا نمی شود.

 model.fit(input_data, labels, epochs=3)
 
Epoch 1/3

Currently running eagerly 2020-08-04 01:22:21.848492

Currently running eagerly 2020-08-04 01:22:21.955102
2/2 [==============================] - 0s 1ms/step - loss: 1.4056
Epoch 2/3
2/2 [==============================] - 0s 1ms/step - loss: 0.0037
Epoch 3/3
2/2 [==============================] - 0s 1ms/step - loss: 0.0019

<tensorflow.python.keras.callbacks.History at 0x7f45f03c5630>

اگر حتی یک دوره واحد را مشتاقانه اجرا کنید ، می توانید دو بار اثر جانبی مشتاق را مشاهده کنید.

 print("Running eagerly")
# When compiling the model, set it to run eagerly
model.compile(run_eagerly=True, loss=loss_fn)

model.fit(input_data, labels, epochs=1)

 
Running eagerly

Currently running eagerly 2020-08-04 01:22:22.152979
1/2 [==============>...............] - ETA: 0s - loss: 8.7806e-04
Currently running eagerly 2020-08-04 01:22:22.173295
2/2 [==============================] - 0s 5ms/step - loss: 4.6877e-04

<tensorflow.python.keras.callbacks.History at 0x7f45f0312940>

با استفاده از run_functions_eagerly

همچنین می توانید همه چیز را به صورت جهانی تنظیم کنید تا مشتاقانه اجرا شوند. توجه داشته باشید که این کار فقط در صورت ردیابی مجدد انجام می شود. توابع ردیابی مانند نمودار باقی می ماند و ردیابی می شود.

 # Now, globally set everything to run eagerly
tf.config.run_functions_eagerly(True)
print("Run all functions eagerly.")

# First, trace the model, triggering the side effect
polymorphic_function = tf.function(model)

# It was traced...
print(polymorphic_function.get_concrete_function(input_data))

# But when you run the function again, the side effect happens (both times).
result = polymorphic_function(input_data)
result = polymorphic_function(input_data)
 
Run all functions eagerly.

Currently running eagerly 2020-08-04 01:22:22.202726
ConcreteFunction function(self)
  Args:
    self: float32 Tensor, shape=(60, 28, 28)
  Returns:
    float32 Tensor, shape=(60, 10)

Currently running eagerly 2020-08-04 01:22:22.206521

Currently running eagerly 2020-08-04 01:22:22.207818

 # Don't forget to set it back when you are done
tf.config.experimental_run_functions_eagerly(False)

 
WARNING:tensorflow:From <ipython-input-17-782fe9ce7b18>:2: experimental_run_functions_eagerly (from tensorflow.python.eager.def_function) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.config.run_functions_eagerly` instead of the experimental version.

ردیابی و عملکرد

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

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

می توانید یک اثر جانبی مشتاقانه اضافه کنید (مانند چاپ یک آرگومان پایتون) ، بنابراین می توانید هنگام ردیابی عملکرد مشاهده کنید. در اینجا ، شما عقبگرد اضافی را مشاهده می کنید زیرا استدلال های جدید پایتون همیشه باعث عقب نشینی می شوند.

 # Use @tf.function decorator
@tf.function
def a_function_with_python_side_effect(x):
  print("Tracing!")  # This eager
  return x * x + tf.constant(2)

# This is traced the first time
print(a_function_with_python_side_effect(tf.constant(2)))
# The second time through, you won't see the side effect
print(a_function_with_python_side_effect(tf.constant(3)))

# This retraces each time the Python argument chances
# as a Python argument could be an epoch count or other
# hyperparameter
print(a_function_with_python_side_effect(2))
print(a_function_with_python_side_effect(3))

 
Tracing!
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(11, shape=(), dtype=int32)
Tracing!
tf.Tensor(6, shape=(), dtype=int32)
Tracing!
tf.Tensor(11, shape=(), dtype=int32)

مراحل بعدی

شما می توانید یک بحث عمیق تر را هم در صفحه مرجع API tf.function و هم در راهنمای بخوانید.