![]() | ![]() | ![]() | ![]() |
Genel Bakış
Bu kılavuz, TensorFlow'un nasıl çalıştığını görmek için TensorFlow ve Keras yüzeyinin altına iner. Bunun yerine Keras'ı hemen kullanmaya başlamak istiyorsanız, lütfen Keras kılavuzları koleksiyonumuza bakın.
Bu kılavuzda, TensorFlow'un grafik almak için kodunuzda basit değişiklikler yapmanıza nasıl izin verdiğini, bunların nasıl saklanıp 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 .
Grafik nedir?
Ö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 başına işlem yapıldığı ve sonuçları Python'a geri döndürdüğü anlamına gelir. Eager TensorFlow, GPU'lardan yararlanarak değişkenleri, tensörleri ve hatta işlemleri GPU'lara ve TPU'lara yerleştirmenize olanak tanır. Hata ayıklamak da kolaydır.
Bazı kullanıcılar için Python'a asla ihtiyaç duymayabilir veya Python'dan ayrılmak istemeyebilirsiniz.
Bununla birlikte, Python'da TensorFlow op-by-op çalıştırmak, aksi takdirde mevcut olan bir dizi hızlandırmayı engeller. Python'dan tensör hesaplamalarını çıkarabilirseniz, bunları bir grafiğe dönüştürebilirsiniz.
Grafikler, hesaplama birimlerini temsil eden bir dizi tf.Operation
nesnesi içeren veri yapılarıdır; ve işlemler arasında akan veri birimlerini temsil eden tf.Tensor
nesneleri. 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.
Bu, TensorBoard'da görselleştirildiğinde basit bir iki katmanlı grafiğin nasıl göründüğüdür.
Grafiklerin faydaları
Bir grafikle, büyük bir esnekliğe sahipsiniz. TensorFlow grafiğinizi, mobil uygulamalar, gömülü aygıtlar ve arka uç sunucuları gibi Python yorumlayıcısı olmayan ortamlarda kullanabilirsiniz. TensorFlow, grafikleri Python'dan dışa aktardığında kaydedilen modeller için format olarak kullanır.
Grafikler de kolayca optimize edilerek derleyicinin aşağıdaki gibi dönüşümler yapmasına olanak tanır:
- Hesaplamanızda sabit düğümleri katlayarak ("sabit bölme") 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 aygıtlar arasında ayırın.
- Yaygın alt ifadeleri ortadan kaldırarak aritmetik işlemleri basitleştirin.
Bunu ve diğer hızlandırmaları gerçekleştirmek için tam bir optimizasyon sistemi, Grappler var .
Kısacası, grafikler son derece kullanışlıdır ve TensorFlow'unuzun hızlı çalışmasına , paralel çalışmasına ve birden çok cihazda verimli şekilde çalışmasına izin verir .
Bununla birlikte, yine de kolaylık sağlamak için makine öğrenimi modellerimizi (veya diğer hesaplamaları) Python'da tanımlamak ve daha sonra ihtiyacınız olduğunda otomatik olarak grafikler oluşturmak istiyorsunuz.
Grafikleri izleme
Eğer TensorFlow bir grafik oluşturmak yolu kullanmaktır tf.function
doğrudan çağrı olarak veya bir dekoratör olarak ister.
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 işlevler, Python eşdeğerleriyle aynı şekilde çalışan Python çağrılabilirleridir . Belirli bir sınıfları vardır ( python.eager.def_function.Function
), ancak sizin için izlenmeyen sürüm olarak hareket ederler.
tf.function
, çağırdığı herhangi bir Python işlevini ö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
. tf.Sesssion
tanımlamanıza gerek olmadığını fark tf.Sesssion
.
Akış kontrolü ve yan etkiler
Akış denetimi ve döngüleri, varsayılan olarak tf.autograph aracılığıyla tf.autograph
dönüştürülür. İmza, döngü yapılarını standartlaştırma, rulo açma ve AST manipülasyonu dahil olmak üzere 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 işlemlerine nasıl dönüştürüldüğünü görmek için doğrudan Autograph dönüşümünü çağırabilirsiniz. Bu, çoğunlukla okunamaz, 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 (do_return, retval_) def set_state(vars_): nonlocal do_return, retval_ (do_return, retval_) = vars_ def if_body(): nonlocal do_return, retval_ try: do_return = True retval_ = (ag__.ld(x) * ag__.ld(x)) except: do_return = False raise def else_body(): nonlocal do_return, retval_ 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, ('do_return', 'retval_'), 2) return fscope.ret(retval_, do_return)
İmza, if-then
cümlelerini, döngüleri, break
, return
, continue
ve daha fazlasını otomatik olarak dönüştürür.
Çoğu zaman, Autograph özel bir husus 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 tensör kullanan bir işlevi 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 ek yükü çalışma süresine hakim olabilir. Ayrıca, hesaplamaların çoğu GPU ağırlıklı evrişim yığınları gibi bir hızlandırıcıda zaten yapılıyorsa, grafik hızlandırma büyük olmayacaktır.
Karmaşık hesaplamalar için, grafikler önemli bir hızlanma sağlayabilir. Bunun nedeni, grafiklerin Python'dan cihaza iletişimi azaltması ve bazı hızlandırmalar gerçekleştirmesidir.
Hızlanma, aşağıdaki örnekte olduğu gibi, birçok küçük katmanı çalıştırırken en belirgindir:
# 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))
# Add a lot of small layers
num_layers = 100
self.my_layers = [tf.keras.layers.Dense(64, activation="relu")
for n in range(num_layers)]
self.dropout = tf.keras.layers.Dropout(0.2)
self.dense_2 = tf.keras.layers.Dense(10)
def call(self, x):
x = self.flatten(x)
for layer in self.my_layers:
x = layer(x)
x = self.dropout(x)
x = self.dense_2(x)
return x
input_data = tf.random.uniform([20, 28, 28])
eager_model = SequentialModel()
# Don't count the time for the initial build.
eager_model(input_data)
print("Eager time:", timeit.timeit(lambda: eager_model(input_data), number=100))
Eager time: 2.185799148000001
# Wrap the call method in a `tf.function`
graph_model = SequentialModel()
graph_model.call = tf.function(graph_model.call)
# Don't count the time for the initial build and trace.
graph_model(input_data)
print("Graph time:", timeit.timeit(lambda: graph_model(input_data), number=100))
Graph time: 0.30396231500003523
Polimorfik fonksiyonlar
Bir işlevi izlediğinizde , polimorfik olan bir Function
nesnesi oluşturursunuz. Polimorfik bir işlev, bir API'nin arkasında birkaç somut işlev grafiğini kapsülleyen bir Python çağrılabilir özelliktir.
Bu Function
tüm farklı dtypes
ve şekillerde kullanabilirsiniz. Onu yeni bir bağımsız değişken imzasıyla her çağırdığı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 elde edersiniz.
O halde kavramsal olarak:
- Bir
tf.Graph
, bir hesaplamayı tanımlayan ham, taşınabilir veri yapısıdır. - Bir
Function
, ConcreteFunctions üzerinden önbelleğe alma, izleme, dağıtıcıdır -
ConcreteFunction
, grafiği Python'dan çalıştırmanıza izin veren, bir grafiğin etrafındaki hevesle uyumlu bir sarmalayıcıdır.
Polimorfik fonksiyonları inceleme
Sen inceleyebilir a_function
çağırarak sonucudur, tf.function
Python fonksiyonu üzerinde my_function
. Bu örnekte, a_function
üç tür bağımsız değişkenle çağırmak, üç farklı somut işlevle sonuçlanır.
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 0x7f90cc28e4a8> 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 oldukça ilerisini görüyorsunuz. İzlemeyi özel olarak yönetmediğiniz sürece, normalde burada gösterildiği gibi somut işlevleri doğrudan çağırmanız gerekmez.
Hevesli uygulamaya geri dönüyoruz
Kendinizi uzun yığın izlerine bakarken bulabilirsiniz, özellikle tf.Graph
veya 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'ın 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.
İşte hevesle koştuğunuzdan emin olmanın yolları:
Modelleri ve katmanları doğrudan çağrılabilir olarak çağırın
model.compile(run_eagerly=True)
compile / fit kullanırken, derleme zamanındamodel.compile(run_eagerly=True)
kullanınmodel.compile(run_eagerly=True)
tf.config.run_functions_eagerly(True)
aracılığıyla genel yürütme modunu ayarlayın
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; ismine 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 fonksiyonun izlendiğini (iki kez) ve ardından istekli etkinin bir daha asla çalışmadığını görün.
model.fit(input_data, labels, epochs=3)
Epoch 1/3 Currently running eagerly 2021-01-13 02:25:36.809205 Currently running eagerly 2021-01-13 02:25:36.941800 2/2 [==============================] - 0s 3ms/step - loss: 2.0352 Epoch 2/3 2/2 [==============================] - 0s 3ms/step - loss: 0.0045 Epoch 3/3 2/2 [==============================] - 0s 2ms/step - loss: 0.0026 <tensorflow.python.keras.callbacks.History at 0x7f90102f2550>
Ancak tek bir dönemi bile hevesle çalıştırırsanız, 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 2021-01-13 02:25:37.173159 1/2 [==============>...............] - ETA: 0s - loss: 0.0023 Currently running eagerly 2021-01-13 02:25:37.195392 2/2 [==============================] - 0s 13ms/step - loss: 0.0016 <tensorflow.python.keras.callbacks.History at 0x7f90101981d0>
run_functions_eagerly
kullanma
Ayrıca global olarak her şeyi hevesle çalışacak şekilde ayarlayabilirsiniz. Bu, polimorfik işlevin izlenen işlevlerini atlayan ve orijinal işlevi doğrudan çağıran bir anahtardır. Bunu hata ayıklamak için kullanabilirsiniz.
# Now, globally set everything to run eagerly
tf.config.run_functions_eagerly(True)
print("Run all functions eagerly.")
# Create a polymorphic function
polymorphic_function = tf.function(model)
print("Tracing")
# This does, in fact, trace the function
print(polymorphic_function.get_concrete_function(input_data))
print("\nCalling twice eagerly")
# When you run the function again, you will see the side effect
# twice, as the function is running eagerly.
result = polymorphic_function(input_data)
result = polymorphic_function(input_data)
Run all functions eagerly. Tracing Currently running eagerly 2021-01-13 02:25:37.594444 ConcreteFunction function(self) Args: self: float32 Tensor, shape=(60, 28, 28) Returns: float32 Tensor, shape=(60, 10) Calling twice eagerly Currently running eagerly 2021-01-13 02:25:37.600183 Currently running eagerly 2021-01-13 02:25:37.602196
# Don't forget to set it back when you are done
tf.config.experimental_run_functions_eagerly(False)
WARNING:tensorflow:From <ipython-input-1-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
İzleme bazı ek yüklere mal olur. Küçük işlevlerin izini sürmek hızlı olsa da, büyük modellerin izini sürmek fark edilebilir bir duvar saati süresi alabilir. Bu yatırım genellikle performans artışı ile hızlı bir şekilde geri ödenir, ancak herhangi bir büyük model eğitiminin ilk birkaç döneminin izleme nedeniyle daha yavaş olabileceğinin farkında olmak önemlidir.
Modeliniz ne kadar büyük olursa olsun, sık sık takip etmekten kaçınmak istersiniz. Tf.function kılavuzunun bu bölümünde, giriş özelliklerinin nasıl ayarlanacağı ve yeniden izlemeyi önlemek için tensör argümanlarının nasıl kullanılacağı anlatılmaktadır. Alışılmadık derecede düşük performans aldığınızı fark ederseniz, yanlışlıkla geri dönüp takip etmediğinizi kontrol etmek iyidir.
Yalnızca hevesli bir yan etki (Python bağımsız değişkeninin yazdırılması gibi) ekleyebilirsiniz, böylece işlevin ne zaman izlendiğini görebilirsiniz. Burada, fazladan yeniden izleme görüyorsunuz çünkü yeni Python argümanları her zaman yeniden izlemeyi tetikler.
# 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 changes,
# 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 .