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

Grafik ve fonksiyonlara giriş

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

Grafik ve tf.function

Bu kılavuz, TensorFlow ve Keras'ın yüzeyinin altına, TensorFlow'un nasıl çalıştığını görmek için gider. Bunun yerine hemen Keras'ı kullanmaya başlamak istiyorsanız, lütfen Keras rehber koleksiyonumuza bakın.

Bu kılavuzda, TensorFlow'un grafik almak için kodunuzda nasıl basit değişiklikler yapmanıza izin verdiğini, bunların nasıl saklandığını ve temsil edildiğini ve modellerinizi hızlandırmak ve dışa aktarmak için bunları nasıl kullanabileceğinizi göreceksiniz.

Bu kısa biçimli bir giriştir; bu kavramlara tam bir giriş için tf.function kılavuzuna bakın .

Grafikler nelerdir?

Önceki üç kılavuzda, TensorFlow'un hevesle çalıştığını gördünüz. Bu, TensorFlow işlemlerinin Python tarafından yürütüldüğü, işlem tarafından çalıştırıldığı ve sonuçların Python'a geri döndürüldüğü anlamına gelir. Eager TensorFlow, GPU'lardan yararlanır ve değişkenler, tensörler ve hatta GPU'lar ve TPU'lara işlemler yerleştirmenize olanak tanır. Hata ayıklamak da kolaydır.

Bazı kullanıcılar için Python'dan asla ayrılmanız gerekmeyebilir.

Ancak, Python'da TensorFlow op-by-op'nin çalıştırılması, başka türlü mevcut olan bir dizi ivmeyi engeller. Python'dan tensör hesaplamalarını çıkarabiliyorsanız, bunları bir grafiğe dönüştürebilirsiniz.

Grafikler, hesaplama birimlerini temsil eden bir dizi tf.Operation nesneleri içeren veri yapılarıdır; ve tf.Tensor nesneleri; bunlar, işlemler arasında akan veri birimlerini temsil eder. Bir tf.Graph bağlamında tanımlanırlar. Bu grafikler veri yapıları olduğundan, orijinal Python kodu olmadan kaydedilebilir, çalıştırılabilir ve geri yüklenebilir.

TensorBoard'da görselleştirildiğinde basit iki katmanlı bir grafik böyle görünür.

iki katmanlı bir tensorflow grafiği

Grafiklerin faydaları

Bir grafik ile çok fazla esnekliğe sahip olursunuz. TensorFlow grafiğinizi Python yorumlayıcısı olmayan ortamlarda (mobil uygulamalar, katıştırılmış cihazlar ve arka uç sunucuları gibi) kullanabilirsiniz. TensorFlow, kaydedilen modeller için Python'dan dışa aktardıklarında grafikleri biçim olarak kullanır.

Grafikler de kolayca optimize edilebilir ve derleyicinin aşağıdaki gibi dönüşümler yapmasına izin verir:

  • Hesaplamadaki sabit düğümleri katlayarak ("sabit katlama") tensörlerin değerini statik olarak çıkarın.
  • Bir hesaplamanın bağımsız olan alt bölümlerini ayırın ve bunları iş parçacıkları veya cihazlar arasında bölün.
  • Ortak alt ifadeleri ortadan kaldırarak aritmetik işlemleri basitleştirin.

Bunu ve diğer hızlandırmaları gerçekleştirmek için eksiksiz bir optimizasyon sistemi olan Grappler var .

Kısacası, grafikler son derece kullanışlıdır ve TensorFlow'unuzun hızlı çalışmasını , paralel çalışmasını ve birden fazla cihazda verimli çalışmasını sağlar.

Ancak, yine de kolaylık sağlamak için Python'da makine öğrenme modellerimizi (veya diğer hesaplamaları) tanımlamak ve ardından ihtiyacınız olduğunda grafikleri otomatik olarak oluşturmak istiyorsunuz.

İzleme grafikleri

TensorFlow'da grafik oluşturmanın yolu, doğrudan arama veya dekoratör olarak tf.function kullanmaktır.

 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 fonksiyonlar Python eşdeğerleriyle aynı şekilde çalışan Python callables'larıdır . Belirli bir sınıfları vardır ( python.eager.def_function.Function ), ancak sizin için iz bırakılmamış sürüm gibi davranırlar.

tf.function , çağırdığı Python işlevlerini özyinelemeli olarak izler.

 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 kullandıysanız, hiçbir zaman bir Placeholder veya tf.Sesssion tanımlamanız gerekmediğini fark tf.Sesssion .

Akış kontrolü ve yan etkiler

Akış kontrolü ve döngüler varsayılan olarak tf.autograph üzerinden tf.autograph öğesine dönüştürülür. Autograph, döngü yapılarını standartlaştırma, açma ve AST manipülasyonunu içeren bir yöntem kombinasyonu kullanır.

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

Python'un TensorFlow ops'ye nasıl dönüştürüldüğünü görmek için doğrudan İmza dönüşümünü çağırabilirsiniz. Bu çoğunlukla okunamıyor, ancak dönüşümü görebilirsiniz.

 # 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 cümlelerini, döngülerini, break , return , continue ve daha fazlasını otomatik olarak dönüştürür.

Çoğu zaman, İmza özel değerlendirmeler olmadan çalışacaktır. Bununla birlikte, bazı uyarılar vardır ve tf.fonksiyon kılavuzu , tam imza referansının yanı sıra burada yardımcı olabilir

Hızı görmek

Sadece tensor kullanma fonksiyonunu tf.function içine tf.function kodunuzu otomatik olarak hızlandırmaz. Tek bir makinede birkaç kez çağrılan küçük işlevler için, bir grafik veya grafik parçasını çağırmanın yükü çalışma zamanına hakim olabilir. Ayrıca, hesaplamaların çoğu zaten GPU-ağır kıvrımların yığınları gibi bir hızlandırıcıda gerçekleşiyorsa, grafik hızlanması büyük olmayacaktır.

Karmaşık hesaplamalar için, grafikler önemli bir hızlanma sağlayabilir. Bunun nedeni, grafiklerin Python-cihaz iletişimini azaltması ve bazı hızlandırmaların gerçekleştirilmesidir.

Bu kod, birkaç kez bazı küçük yoğun katmanlarda çalışır.

 # 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

Polimorfik fonksiyonlar

Bir Function izlediğinizde, polimorfik bir Function nesnesi oluşturursunuz. Bir polimorfik fonksiyon, bir API'nin arkasındaki birkaç somut fonksiyon grafiğini kapsayan bir Python'dur.

Bu kullanabilirsiniz Function her çeşit üzerinde dtypes ve şekiller. Yeni bir bağımsız değişken imzası ile her çağırışınızda, orijinal işlev yeni bağımsız değişkenlerle yeniden izlenir. Function sonra depolayan tf.Graph bir o iz tekabül concrete_function . İşlev zaten bu tür bir argümanla izlenmişse, önceden izlenen grafiğinizi alırsınız.

Kavramsal olarak, o zaman:

  • Bir tf.Graph , bir hesaplamayı tanımlayan ham, taşınabilir veri yapısıdır
  • Bir Function , ConcreteFunctions üzerinde bir önbellek, izleme, dağıtıcı
  • ConcreteFunction , grafiği Python'dan yürütmenizi sağlayan, grafik etrafında istekli uyumlu bir pakettir

Polimorfik fonksiyonların incelenmesi

Sen inceleyebilir a_function çağırarak sonucudur, tf.function Python fonksiyonu üzerinde my_function . Bu örnekte, a_function üç tür argümanla çağırmak, üç farklı somut işleve neden olur.

 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)

Bu örnekte, yığının çok yakınında görüyorsunuz. İzlemeyi özel olarak yönetmiyorsanız, normalde burada gösterildiği gibi doğrudan somut işlevleri çağırmanız gerekmez.

İstekli yürütmeye geri dönme

Kendinizi, özellikle tf.Graph veya with tf.Graph().as_default() olan uzun yığın izlerine bakarken bulabilirsiniz with tf.Graph().as_default() . Bu, muhtemelen bir grafik bağlamında çalıştığınız anlamına gelir. TensorFlow'daki temel işlevler, Keras model.fit() gibi grafik bağlamlarını kullanır.

İstekli yürütmede hata ayıklamak genellikle çok daha kolaydır. Yığın izleri nispeten kısa ve anlaşılması kolay olmalıdır.

Grafiğin hata ayıklamayı zorlaştırdığı durumlarda, hata ayıklamak için istekli yürütmeyi kullanmaya geri dönebilirsiniz.

İstekli bir şekilde çalıştığınızdan emin olmanın yolları:

run_eagerly=True kullanma

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

İlk olarak, modeli istekli olmadan derleyin. Modelin izlenmediğini unutmayın; Derlemesine rağmen, compile yalnızca kayıp işlevlerini, optimizasyonu ve diğer eğitim parametrelerini ayarlar.

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

Şimdi, fit çağırın ve işlevin izlendiğini (iki kez) görün ve sonra istekli etkisi bir daha asla çalışmaz.

 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>

Bununla birlikte, istekli bir tek dönem bile yönetirseniz, istekli yan etkiyi iki kez görebilirsiniz.

 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 kullanma

Ayrıca küresel olarak her şeyi hevesle çalışacak şekilde ayarlayabilirsiniz. Bunun yalnızca yeniden izlediğinizde işe yaradığını unutmayın; izlenen işlevler izlenir ve grafik olarak çalışır.

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

İzleme ve performans

Takip biraz masraflıdır. Küçük işlevlerin izlenmesi hızlı olmakla birlikte, büyük modellerin izlenmesi için duvar saati fark edilebilir. Bu yatırım genellikle hızlı bir şekilde performans artışı ile geri ödenir, ancak herhangi bir büyük model eğitiminin ilk birkaç çağının izleme nedeniyle daha yavaş olabileceğinin farkında olmak önemlidir.

Modeliniz ne kadar büyük olursa olsun, sık sık izlemekten kaçınmak istersiniz. Tf.fonksiyon kılavuzunun bu bölümü, giriş spesifikasyonlarının nasıl ayarlanacağını ve geri çekilmeyi önlemek için tensör argümanlarının nasıl kullanılacağını açıklar . Alışılmadık derecede düşük performans elde ettiğinizi fark ederseniz, yanlışlıkla geri çekip çekmediğinizi kontrol etmek iyidir.

İşlevin ne zaman izlendiğini görebilmeniz için yalnızca istekli bir yan etki (Python bağımsız değişkeni yazdırma gibi) ekleyebilirsiniz. Burada, yeni Python argümanları her zaman geri çekmeyi tetiklediğinden ekstra geri çekme görüyorsunuz.

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

Sonraki adımlar

Sen hem de daha derinlemesine tartışma okuyabilir tf.function API başvuru sayfası ve en rehber .