TensorFlow'un @tf.function Dekoratörünü Anlama

Giriş

Bir eğitim döngüsünün performansını artırmak, makine öğrenimi modellerini eğitirken saatlerce süren hesaplama süresinden tasarruf sağlayabilir. TensorFlow kodunun performansını artırmanın yollarından biri, tf.function() dekoratör – işlevlerinizin önemli ölçüde daha hızlı çalışmasını sağlayabilecek basit, tek satırlık bir değişiklik.

Bu kısa kılavuzda bunun nasıl yapılacağını açıklayacağız. tf.function() performansı artırın ve en iyi uygulamalardan bazılarına göz atın.

Python Dekoratörleri ve tf.function()

Python'da dekoratör, diğer işlevlerin davranışını değiştiren bir işlevdir. Örneğin, bir not defteri hücresinde aşağıdaki işlevi çağırdığınızı varsayalım:

import tensorflow as tf

x = tf.random.uniform(shape=[100, 100], minval=-1, maxval=1, dtype=tf.dtypes.float32)

def some_costly_computation(x):
    aux = tf.eye(100, dtype=tf.dtypes.float32)
    result = tf.zeros(100, dtype = tf.dtypes.float32)
    for i in range(1,100):
        aux = tf.matmul(x,aux)/i
        result = result + aux
    return result

%timeit some_costly_computation(x)
16.2 ms ± 103 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Ancak, maliyetli işlevi bir şeye aktarırsak tf.function():

quicker_computation = tf.function(some_costly_computation)
%timeit quicker_computation(x)

Alırız quicker_computation() – öncekinden çok daha hızlı performans gösteren yeni bir işlev:

4.99 ms ± 139 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

Yani, tf.function() değiştirir some_costly_computation() ve çıktıyı verir quicker_computation() işlev. Dekoratörler aynı zamanda işlevleri de değiştirirler, dolayısıyla tf.function() aynı zamanda bir dekoratör.

Dekoratör notasyonunu kullanmak, çağırmakla aynıdır tf.function(function):

@tf.function
def quick_computation(x):
  aux = tf.eye(100, dtype=tf.dtypes.float32)
  result = tf.zeros(100, dtype = tf.dtypes.float32)
  for i in range(1,100):
    aux = tf.matmul(x,aux)/i
    result = result + aux
  return result

%timeit quick_computation(x)
5.09 ms ± 283 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

Nasıl tf.function() İş?

Nasıl olur da bazı fonksiyonların 2-3 kat daha hızlı çalışmasını sağlayabiliriz?

TensorFlow kodu iki modda çalıştırılabilir: istekli mod ve grafik modu. İstekli mod, kod çalıştırmanın standart, etkileşimli yoludur: bir işlevi her çağırdığınızda yürütülür.

Ancak grafik modu biraz farklıdır. Grafik modunda, işlevi çalıştırmadan önce TensorFlow, işlevi yürütmek için gerekli işlemleri içeren bir veri yapısı olan bir hesaplama grafiği oluşturur. Hesaplama grafiği, TensorFlow'un hesaplamaları basitleştirmesine ve paralelleştirme fırsatlarını bulmasına olanak tanır. Grafik ayrıca işlevi üstteki Python kodundan yalıtarak birçok farklı cihazda verimli bir şekilde çalıştırılmasına olanak tanır.

İle süslenmiş bir fonksiyon @tf.function iki adımda gerçekleştirilir:

  1. İlk adımda TensorFlow, işlev için Python kodunu çalıştırır ve bir hesaplama grafiği derleyerek herhangi bir TensorFlow işleminin yürütülmesini geciktirir.
  2. Daha sonra hesaplama grafiği çalıştırılır.

Not: İlk adım şu şekilde bilinir: "izleme".

Yeni bir hesaplama grafiği oluşturmaya gerek yoksa ilk adım atlanacaktır. Bu, işlevin performansını artırır ancak aynı zamanda işlevin normal Python kodu (her yürütülebilir satırın yürütüldüğü) gibi yürütülmeyeceği anlamına da gelir. Örneğin önceki fonksiyonumuzu değiştirelim:

@tf.function
def quick_computation(x):
  print('Only prints the first time!')
  aux = tf.eye(100, dtype=tf.dtypes.float32)
  result = tf.zeros(100, dtype = tf.dtypes.float32)
  for i in range(1,100):
    aux = tf.matmul(x,aux)/i
    result = result + aux
  return result

quick_computation(x)
quick_computation(x)

Bunun sonucu:

Only prints the first time!

The print() izleme adımı sırasında yalnızca bir kez yürütülür; bu, normal Python kodunun çalıştırıldığı zamandır. İşleve yapılan sonraki çağrılar yalnızca hesaplama grafiğinden (TensorFlow işlemleri) TenforFlow işlemlerini yürütür.

Ancak, tf.print() yerine:

@tf.function
def quick_computation_with_print(x):
  tf.print("Prints every time!")
  aux = tf.eye(100, dtype=tf.dtypes.float32)
  result = tf.zeros(100, dtype = tf.dtypes.float32)
  for i in range(1,100):
    aux = tf.matmul(x,aux)/i
    result = result + aux
  return result

quick_computation_with_print(x)
quick_computation_with_print(x)

En iyi uygulamalar, endüstri tarafından kabul edilen standartlar ve dahil edilen hile sayfası ile Git'i öğrenmek için uygulamalı, pratik kılavuzumuza göz atın. Googling Git komutlarını durdurun ve aslında öğrenmek o!

Prints every time!
Prints every time!

TensorFlow şunları içerir: tf.print() hesaplama grafiğinde bu bir TensorFlow işlemi olduğu için normal bir Python işlevi değil.

Uyarı: ile süslenmiş bir işleve yapılan her çağrıda Python kodunun tümü yürütülmez. @tf.function. İzlemeden sonra yalnızca hesaplamalı grafikteki işlemler çalıştırılır, bu da kodumuza biraz dikkat edilmesi gerektiği anlamına gelir.

En İyi Uygulamalar @tf.function

TensorFlow İşlemleri ile Kod Yazma

Az önce gösterdiğimiz gibi kodun bazı kısımları hesaplama grafiği tarafından göz ardı edilir. Bu, az önce gördüğümüz gibi "normal" Python koduyla kodlama yaparken fonksiyonun davranışını tahmin etmeyi zorlaştırıyor. print(). Beklenmeyen davranışlardan kaçınmak için işlevinizi uygun olduğunda TensorFlow işlemleriyle kodlamak daha iyidir.

Örneğin, for ve while döngüler eşdeğer TensorFlow döngüsüne dönüştürülebilir veya dönüştürülmeyebilir. Bu nedenle mümkünse “for” döngünüzü vektörleştirilmiş bir işlem olarak yazmanız daha doğru olacaktır. Bu, kodunuzun performansını artıracak ve işlevinizin doğru şekilde izlenmesini sağlayacaktır.

Örnek olarak aşağıdakileri göz önünde bulundurun:

x = tf.random.uniform(shape=[100, 100], minval=-1, maxval=1, dtype=tf.dtypes.float32)

@tf.function
def function_with_for(x):
    summ = float(0)
    for row in x:
      summ = summ + tf.reduce_mean(row)
    return summ

@tf.function
def vectorized_function(x):
  result = tf.reduce_mean(x, axis=0)
  return tf.reduce_sum(result)


print(function_with_for(x))
print(vectorized_function(x))

%timeit function_with_for(x)
%timeit vectorized_function(x)
tf.Tensor(0.672811, shape=(), dtype=float32)
tf.Tensor(0.67281103, shape=(), dtype=float32)
1.58 ms ± 177 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
440 µs ± 8.34 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

TensorFlow işlemlerini içeren kod oldukça hızlıdır.

Global Değişkenlere Referanslardan Kaçının

Aşağıdaki kodu göz önünde bulundurun:

x = tf.Variable(2, dtype=tf.dtypes.float32)
y = 2

@tf.function
def power(x):
  return tf.pow(x,y)

print(power(x))

y = 3

print(power(x))
tf.Tensor(4.0, shape=(), dtype=float32)
tf.Tensor(4.0, shape=(), dtype=float32)

İlk kez dekore edilmiş fonksiyon power() çağrıldığında çıktı değeri beklenen 4'tü. Ancak ikinci seferde işlev, değerini göz ardı etti. y değişti. Bunun nedeni Python global değişkenlerinin değerinin izleme sonrasında işlev için dondurulmasıdır.

Daha iyi bir yol kullanmak olacaktır tf.Variable() tüm değişkenleriniz için ve her ikisini de işlevinize argüman olarak iletin.

x = tf.Variable(2, dtype=tf.dtypes.float32)
y = tf.Variable(2, dtype = tf.dtypes.float32)

@tf.function
def power(x,y):
  return tf.pow(x,y)

print(power(x,y))

y.assign(3)

print(power(x,y))
tf.Tensor(4.0, shape=(), dtype=float32)
tf.Tensor(8.0, shape=(), dtype=float32)

Hata ayıklama [e-posta korumalı]_s

Genel olarak, istekli modda işlevinizin hatalarını ayıklamak ve ardından bunları ile süslemek istersiniz. @tf.function Kodunuz düzgün bir şekilde çalıştıktan sonra, istekli moddaki hata mesajları daha bilgilendirici olduğundan.

Bazı yaygın sorunlar yazım hataları ve şekil hatalarıdır. Bir işlemde yer alan değişkenlerin türünde bir uyumsuzluk olduğunda tür hataları meydana gelir:

x = tf.Variable(1, dtype = tf.dtypes.float32)
y = tf.Variable(1, dtype = tf.dtypes.int32)

z = tf.add(x,y)
InvalidArgumentError: cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a int32 tensor [Op:AddV2]

Yazım hataları kolayca ortaya çıkar ve bir değişkenin farklı bir türe dönüştürülmesiyle kolayca düzeltilebilir:

y = tf.cast(y, tf.dtypes.float32)
z = tf.add(x, y) 
tf.print(z) 

Tensörleriniz operasyonunuzun gerektirdiği şekle sahip olmadığında şekil hataları meydana gelir:

x = tf.random.uniform(shape=[100, 100], minval=-1, maxval=1, dtype=tf.dtypes.float32)
y = tf.random.uniform(shape=[1, 100], minval=-1, maxval=1, dtype=tf.dtypes.float32)

z = tf.matmul(x,y)
InvalidArgumentError: Matrix size-incompatible: In[0]: [100,100], In[1]: [1,100] [Op:MatMul]

Her iki tür hatayı düzeltmek için kullanışlı bir araç, Jupyter Notebook'ta aşağıdakileri kullanarak otomatik olarak çağırabileceğiniz etkileşimli Python hata ayıklayıcıdır: %pdb. Bunu kullanarak işlevinizi kodlayabilir ve bazı yaygın kullanım durumlarında çalıştırabilirsiniz. Bir hata varsa etkileşimli bir bilgi istemi açılır. Bu istem, kodunuzdaki soyutlama katmanlarında yukarı ve aşağı gitmenize ve TensorFlow değişkenlerinizin değerlerini, türlerini ve şekillerini kontrol etmenize olanak tanır.

Sonuç

TensorFlow'un nasıl çalıştığını gördük tf.function() işlevinizi daha verimli hale getirir ve nasıl @tf.function dekoratör işlevi kendinize uygular.

Bu hızlandırma, makine öğrenimi modellerine yönelik özel eğitim adımları gibi birçok kez çağrılacak işlevlerde kullanışlıdır.

Zaman Damgası:

Den fazla Yığın kötüye kullanımı