TensorFlow.org'da görüntüleyin | Google Colab'da çalıştırın | GitHub'da görüntüle | Not defterini indir |
Kaputun altında, TensorFlow 2, TF1.x'ten temelde farklı bir programlama paradigmasını takip eder.
Bu kılavuz, davranışlar ve API'ler açısından TF1.x ve TF2 arasındaki temel farklılıkları ve bunların geçiş yolculuğunuzla nasıl ilişkili olduğunu açıklamaktadır.
Büyük değişikliklerin üst düzey özeti
Temel olarak, TF1.x ve TF2, yürütme (TF2'de istekli), değişkenler, kontrol akışı, tensör şekilleri ve tensör eşitlik karşılaştırmaları etrafında farklı bir çalışma zamanı davranışı seti kullanır. TF2 uyumlu olması için kodunuzun TF2 davranışlarının tamamıyla uyumlu olması gerekir. Taşıma sırasında, tf.compat.v1.enable_*
veya tf.compat.v1.disable_*
API'leri aracılığıyla bu davranışların çoğunu tek tek etkinleştirebilir veya devre dışı bırakabilirsiniz. Tek istisna, istekli yürütmeyi etkinleştirmenin/devre dışı bırakmanın bir yan etkisi olan koleksiyonların kaldırılmasıdır.
Yüksek düzeyde, TensorFlow 2:
- Gereksiz API'leri kaldırır.
- API'leri daha tutarlı hale getirir - örneğin, Birleşik RNN'ler ve Birleşik Optimize Ediciler .
- İşlevleri oturumlara tercih eder ve grafikler ve derleme için otomatik kontrol bağımlılıkları sağlayan
tf.function
ile birlikte Eager yürütmenin varsayılan olarak etkinleştirildiği Python çalışma zamanı ile daha iyi bütünleşir. - Genel grafik koleksiyonlarını kullanımdan kaldırır.
-
ReferenceVariables
üzerindeResourceVariables
kullanarak Değişken eşzamanlılık semantiğini değiştirir. - Fonksiyon tabanlı ve türevlenebilir kontrol akışını destekler (Kontrol Akışı v2).
- TensorShape API'sini
tf.compat.v1.Dimension
nesneleri yerineint
s tutacak şekilde basitleştirir. - Tensör eşitliği mekaniğini günceller. TF1.x'te tensörler ve değişkenler üzerindeki
==
operatörü, nesne referans eşitliğini kontrol eder. TF2'de değer eşitliğini kontrol eder. Ek olarak, tensörler/değişkenler artık hash edilebilir değildir, ancak setlerde veyadict
anahtarları olarak kullanmanız gerekiyorsavar.ref()
aracılığıyla bunlara hashable nesne referansları alabilirsiniz.
Aşağıdaki bölümler, TF1.x ve TF2 arasındaki farklar hakkında biraz daha bağlam sağlar. TF2'nin arkasındaki tasarım süreci hakkında daha fazla bilgi edinmek için RFC'leri ve tasarım belgelerini okuyun.
API temizleme
Birçok API, TF2'de ya gitti ya da taşındı . Önemli değişikliklerden bazıları, şimdi açık kaynaklı absl-py lehine tf.app
, tf.flags
ve tf.logging
öğelerinin kaldırılmasını, tf.contrib içinde yaşayan projelerin yeniden barındırılmasını ve ana tf.*
ad alanını şu şekilde temizlemeyi tf.contrib
: daha az kullanılan işlevleri tf.math
gibi alt paketlere taşımak. Bazı API'ler TF2 eşdeğerleriyle değiştirildi - tf.summary
, tf.keras.metrics
ve tf.keras.optimizers
.
tf.compat.v1
: Eski ve Uyumluluk API Uç Noktaları
tf.compat
ve tf.compat.v1
ad alanlarının altındaki semboller, TF2 API'leri olarak kabul edilmez. Bu ad alanları, TF 1.x'ten eski API uç noktalarının yanı sıra uyumluluk sembollerinin bir karışımını ortaya çıkarır. Bunlar, TF1.x'ten TF2'ye geçişe yardımcı olmayı amaçlamaktadır. Ancak, bu compat.v1
API'lerinin hiçbiri deyimsel TF2 API'leri olmadığından, bunları yepyeni TF2 kodu yazmak için kullanmayın.
Bireysel tf.compat.v1
sembolleri TF2 uyumlu olabilir, çünkü TF2 davranışları etkinken bile çalışmaya devam ederler ( tf.compat.v1.losses.mean_squared_error
gibi), diğerleri ise TF2 ile uyumsuzdur ( tf.compat.v1.metrics.accuracy
). Çoğu compat.v1
sembolü (tümü olmasa da), belgelerinde TF2 davranışlarıyla uyumluluk derecelerini ve bunların TF2 API'lerine nasıl taşınacağını açıklayan özel geçiş bilgileri içerir.
TF2 yükseltme komut dosyası , birçok compat.v1
API sembolünü, takma ad olmaları veya aynı bağımsız değişkenlere sahip olmaları ancak farklı bir sıralamaya sahip olmaları durumunda eşdeğer TF2 API'leriyle eşleyebilir. TF1.x API'lerini otomatik olarak yeniden adlandırmak için yükseltme komut dosyasını da kullanabilirsiniz.
Yanlış arkadaş API'leri
TF2 tf
ad alanında ( compat.v1
altında değil) bulunan bir dizi "sahte arkadaş" sembolü bulunur, bunlar aslında TF2 davranışlarının altında yatan ve/veya TF2 davranışlarının tamamıyla tam olarak uyumlu değildir. Bu nedenle, bu API'lerin potansiyel olarak sessiz yollarla TF2 koduyla hatalı davranması muhtemeldir.
-
tf.estimator.*
: Tahminciler, başlık altında grafikler ve oturumlar oluşturur ve kullanır. Bu nedenle, bunlar TF2 uyumlu olarak kabul edilmemelidir. Kodunuz tahmin edicileri çalıştırıyorsa, TF2 davranışlarını kullanmıyor. -
keras.Model.model_to_estimator(...)
: Bu, başlık altında yukarıda belirtildiği gibi TF2 uyumlu olmayan bir Tahminci oluşturur. -
tf.Graph().as_default()
: Bu, TF1.x grafik davranışlarını girer ve standart TF2 uyumlutf.function
davranışlarını izlemez. Bunun gibi grafiklere giren kodlar genellikle onları Oturumlar aracılığıyla çalıştırır ve TF2 uyumlu olarak kabul edilmemelidir. -
tf.feature_column.*
Özellik sütunu API'leri genellikle TF1 stilitf.compat.v1.get_variable
değişken oluşturmaya dayanır ve oluşturulan değişkenlere genel koleksiyonlar aracılığıyla erişileceğini varsayar. TF2, koleksiyonları desteklemediğinden, API'ler, TF2 davranışları etkinken çalıştırıldığında düzgün çalışmayabilir.
Diğer API değişiklikleri
TF2,
tf.colocate_with
kullanımını gereksiz kılan cihaz yerleştirme algoritmalarında önemli iyileştirmeler sunar. Kaldırılması performansın düşmesine neden oluyorsa lütfen bir hata bildirin .tf.v1.ConfigProto'nun tüm kullanımlarını
tf.v1.ConfigProto
eşdeğer işlevlerletf.config
.
hevesli yürütme
TF1.x, tf.*
API çağrıları yaparak soyut bir sözdizimi ağacını (grafik) manuel olarak birleştirmenizi ve ardından bir dizi çıktı tensörü ve giriş tensörünü bir session.run
çağrısına geçirerek soyut sözdizimi ağacını manuel olarak derlemenizi gerektiriyordu. TF2 hevesle çalışır (normalde Python'un yaptığı gibi) ve grafikleri ve oturumları uygulama ayrıntıları gibi hissettirir.
İstekli yürütmenin dikkate değer bir yan ürünü, tüm kod satırları sırayla yürütüldüğü için tf.control_dependencies
artık gerekli olmamasıdır (bir tf.function
içinde, yan etkileri olan kod, yazılan sırayla yürütülür).
Artık küresel yok
TF1.x, büyük ölçüde örtük global ad alanlarına ve koleksiyonlara güveniyordu. tf.Variable
, varsayılan grafikte bir koleksiyona konur ve ona işaret eden Python değişkeninin izini kaybetseniz bile orada kalır. Daha sonra bu tf.Variable
kurtarabilirsiniz, ancak yalnızca oluşturulduğu adı biliyorsanız. Değişkenin yaratılmasının kontrolü sizde değilse bunu yapmak zordu. Sonuç olarak, değişkenlerinizi yeniden bulmanıza ve çerçevelerin kullanıcı tarafından oluşturulan değişkenleri bulmasına yardımcı olmak için her türlü mekanizma çoğaldı. Bunlardan bazıları şunlardır: değişken kapsamlar, genel koleksiyonlar, tf.get_global_step
ve tf.global_variables_initializer
gibi yardımcı yöntemler, optimize ediciler, tüm eğitilebilir değişkenler üzerinde gradyanları dolaylı olarak hesaplar, vb. TF2, tüm bu mekanizmaları ( Değişkenler 2.0 RFC ) varsayılan mekanizma lehine ortadan kaldırır - değişkenlerinizi takip edersiniz. Bir tf.Variable
izini kaybederseniz, çöp toplanır.
Değişkenleri izleme gereksinimi bazı ekstra işler yaratır, ancak modelleme şimleri ve tf.Module
s ve tf.keras.layers.Layer
s'deki örtük nesne yönelimli değişken koleksiyonları gibi davranışlar gibi araçlarla yük en aza indirilir.
Oturumlar değil, işlevler
Bir session.run
çağrısı neredeyse bir işlev çağrısı gibidir: girişleri ve çağrılacak işlevi belirlersiniz ve bir dizi çıktıyı geri alırsınız. TF2'de, TensorFlow'un onu tek bir grafik olarak çalıştırması için JIT derlemesi için işaretlemek üzere tf.function
kullanarak bir Python işlevini dekore edebilirsiniz ( Functions 2.0 RFC ). Bu mekanizma, TF2'nin grafik modunun tüm avantajlarını elde etmesini sağlar:
- Performans: İşlev optimize edilebilir (düğüm budama, çekirdek birleştirme vb.)
- Taşınabilirlik: İşlev dışa aktarılabilir/yeniden içe aktarılabilir ( SavedModel 2.0 RFC ), modüler TensorFlow işlevlerini yeniden kullanmanıza ve paylaşmanıza olanak tanır.
# TF1.x
outputs = session.run(f(placeholder), feed_dict={placeholder: input})
# TF2
outputs = f(input)
Python ve TensorFlow kodunu serbestçe serpiştirme gücüyle Python'un etkileyiciliğinden yararlanabilirsiniz. Ancak taşınabilir TensorFlow, mobil, C++ ve JavaScript gibi bir Python yorumlayıcısı olmayan bağlamlarda yürütülür. tf.function
eklerken kodunuzu yeniden yazmaktan kaçınmaya yardımcı olmak için, Python yapılarının bir alt kümesini TensorFlow eşdeğerlerine dönüştürmek için AutoGraph kullanın:
-
for
/while
->tf.while_loop
(break
vecontinue
etme desteklenir) -
if
->tf.cond
-
for _ in dataset
->dataset.reduce
AutoGraph, sekans modelleri, pekiştirmeli öğrenme, özel eğitim döngüleri ve daha fazlası gibi birçok karmaşık ML programının performanslı ve özlü bir şekilde uygulanmasını mümkün kılan, kontrol akışının rastgele iç içe yerleştirilmesini destekler.
TF 2.x Davranış Değişikliklerine Uyum Sağlamak
TF2'ye geçişiniz, ancak TF2 davranışlarının tamamına geçiş yaptığınızda tamamlanır. Davranışların tamamı, tf.compat.v1.enable_v2_behaviors
ve tf.compat.v1.disable_v2_behaviors
aracılığıyla etkinleştirilebilir veya devre dışı bırakılabilir. Aşağıdaki bölümlerde her bir önemli davranış değişikliği ayrıntılı olarak tartışılmaktadır.
tf.function
s kullanma
Geçiş sırasında programlarınızdaki en büyük değişikliklerin, grafiklerden ve oturumlardan istekli yürütmeye ve tf.function
olan temel programlama modeli paradigma kaymasından kaynaklanması muhtemeldir. İstekli yürütme ve tf.function
ile uyumlu olmayan API'lerden bunlarla uyumlu API'lere geçiş hakkında daha fazla bilgi edinmek için TF2 geçiş kılavuzlarına bakın.
Aşağıda, herhangi bir API'ye bağlı olmayan ve tf.Graph
s ve tf.compat.v1.Session
s'den tf.function
s ile istekli yürütmeye geçerken sorunlara neden olabilecek bazı yaygın program kalıpları verilmiştir.
Model 1: Python nesne manipülasyonu ve yalnızca bir kez yapılması amaçlanan değişken oluşturma, birden çok kez çalıştırılır
Grafiklere ve oturumlara dayanan TF1.x programlarında, genellikle programınızdaki tüm Python mantığının yalnızca bir kez çalışması beklenir. Ancak, istekli yürütme ve tf.function
ile Python mantığınızın en az bir kez, ancak muhtemelen daha fazla kez (ya birden çok kez hevesle, ya da farklı tf.function
izlerinde birden çok kez) çalıştırılmasını beklemek adil olur. Bazen, tf.function
aynı girdi üzerinde iki kez izlenerek beklenmeyen davranışlara neden olur (bkz. Örnek 1 ve 2). Daha fazla ayrıntı için tf.function
kılavuzuna bakın.
Örnek 1: Değişken oluşturma
Fonksiyonun çağrıldığında bir değişken oluşturduğu aşağıdaki örneği düşünün:
def f():
v = tf.Variable(1.0)
return v
with tf.Graph().as_default():
with tf.compat.v1.Session() as sess:
res = f()
sess.run(tf.compat.v1.global_variables_initializer())
sess.run(res)
Ancak, değişken oluşturmayı içeren yukarıdaki işlevin tf.function
ile saf olarak kaydırılmasına izin verilmez. tf.function
yalnızca ilk çağrıda tek değişken oluşturmayı destekler. Bunu uygulamak için, tf.function ilk çağrıda değişken oluşturma algıladığında, tekrar izlemeyi dener ve ikinci izlemede değişken oluşturma varsa bir hata verir.
@tf.function
def f():
print("trace") # This will print twice because the python body is run twice
v = tf.Variable(1.0)
return v
try:
f()
except ValueError as e:
print(e)
Geçici bir çözüm, değişkeni ilk çağrıda oluşturulduktan sonra önbelleğe almak ve yeniden kullanmaktır.
class Model(tf.Module):
def __init__(self):
self.v = None
@tf.function
def __call__(self):
print("trace") # This will print twice because the python body is run twice
if self.v is None:
self.v = tf.Variable(0)
return self.v
m = Model()
m()
Örnek 2: tf.function
retracing nedeniyle kapsam dışı Tensörler
Örnek 1'de gösterildiği gibi, tf.function
ilk çağrıda Değişken oluşturma algıladığında yeniden izlenecektir. Bu, fazladan kafa karışıklığına neden olabilir, çünkü iki izleme iki grafik oluşturacaktır. Geri izlemeden gelen ikinci grafik, ilk izleme sırasında oluşturulan grafikten bir Tensöre erişmeye çalıştığında, Tensorflow, Tensörün kapsam dışında olduğundan şikayet eden bir hata verir. Senaryoyu göstermek için aşağıdaki kod, ilk tf.function
çağrısında bir veri kümesi oluşturur. Bu beklendiği gibi çalışır.
class Model(tf.Module):
def __init__(self):
self.dataset = None
@tf.function
def __call__(self):
print("trace") # This will print once: only traced once
if self.dataset is None:
self.dataset = tf.data.Dataset.from_tensors([1, 2, 3])
it = iter(self.dataset)
return next(it)
m = Model()
m()
Ancak, ilk tf.function
çağrısında da bir değişken oluşturmaya çalışırsak, kod, veri kümesinin kapsam dışında olduğundan şikayet eden bir hata verecektir. Bunun nedeni, veri kümesinin birinci grafikte olması ve ikinci grafiğin de ona erişmeye çalışmasıdır.
class Model(tf.Module):
def __init__(self):
self.v = None
self.dataset = None
@tf.function
def __call__(self):
print("trace") # This will print twice because the python body is run twice
if self.v is None:
self.v = tf.Variable(0)
if self.dataset is None:
self.dataset = tf.data.Dataset.from_tensors([1, 2, 3])
it = iter(self.dataset)
return [self.v, next(it)]
m = Model()
try:
m()
except TypeError as e:
print(e) # <tf.Tensor ...> is out of scope and cannot be used here.
En basit çözüm, hem değişken oluşturmanın hem de veri kümesi oluşturmanın tf.funciton
çağrısının dışında olmasını sağlamaktır. Örneğin:
class Model(tf.Module):
def __init__(self):
self.v = None
self.dataset = None
def initialize(self):
if self.dataset is None:
self.dataset = tf.data.Dataset.from_tensors([1, 2, 3])
if self.v is None:
self.v = tf.Variable(0)
@tf.function
def __call__(self):
it = iter(self.dataset)
return [self.v, next(it)]
m = Model()
m.initialize()
m()
Bununla birlikte, bazen tf.function
içinde değişkenler yaratmaktan kaçınılamaz (bazı TF keras optimizerlerindeki slot değişkenleri gibi). Yine de, veri kümesi oluşturmayı tf.function
çağrısının dışına kolayca taşıyabiliriz. Buna güvenebilmemizin nedeni, tf.function
veri kümesini örtük bir girdi olarak alması ve her iki grafiğin de buna düzgün şekilde erişebilmesidir.
class Model(tf.Module):
def __init__(self):
self.v = None
self.dataset = None
def initialize(self):
if self.dataset is None:
self.dataset = tf.data.Dataset.from_tensors([1, 2, 3])
@tf.function
def __call__(self):
if self.v is None:
self.v = tf.Variable(0)
it = iter(self.dataset)
return [self.v, next(it)]
m = Model()
m.initialize()
m()
Örnek 3: Dikt kullanımı nedeniyle beklenmeyen Tensorflow nesnesi yeniden oluşturma
tf.function
, bir listeye ekleme veya bir sözlüğe kontrol etme/ekleme gibi python yan etkileri için çok zayıf bir desteğe sahiptir. Daha fazla ayrıntı "tf.function ile daha iyi performans" bölümündedir . Aşağıdaki örnekte kod, veri kümelerini ve yineleyicileri önbelleğe almak için sözlükleri kullanır. Aynı anahtar için, modele yapılan her çağrı, veri kümesinin aynı yineleyicisini döndürür.
class Model(tf.Module):
def __init__(self):
self.datasets = {}
self.iterators = {}
def __call__(self, key):
if key not in self.datasets:
self.datasets[key] = tf.compat.v1.data.Dataset.from_tensor_slices([1, 2, 3])
self.iterators[key] = self.datasets[key].make_initializable_iterator()
return self.iterators[key]
with tf.Graph().as_default():
with tf.compat.v1.Session() as sess:
m = Model()
it = m('a')
sess.run(it.initializer)
for _ in range(3):
print(sess.run(it.get_next())) # prints 1, 2, 3
Ancak, yukarıdaki kalıp tf.function
içinde beklendiği gibi çalışmayacaktır. İzleme sırasında tf.function
, sözlüklere eklemenin python yan etkisini yok sayar. Bunun yerine, yalnızca yeni bir veri kümesinin ve yineleyicinin oluşturulmasını hatırlar. Sonuç olarak, modele yapılan her çağrı her zaman yeni bir yineleyici döndürür. Sayısal sonuçlar veya performans yeterince önemli olmadıkça bu sorunu fark etmek zordur. Bu nedenle, kullanıcıların tf.function
saf bir şekilde python koduna sarmadan önce kodu dikkatlice düşünmelerini öneririz.
class Model(tf.Module):
def __init__(self):
self.datasets = {}
self.iterators = {}
@tf.function
def __call__(self, key):
if key not in self.datasets:
self.datasets[key] = tf.data.Dataset.from_tensor_slices([1, 2, 3])
self.iterators[key] = iter(self.datasets[key])
return self.iterators[key]
m = Model()
for _ in range(3):
print(next(m('a'))) # prints 1, 1, 1
Beklenen davranışı elde etmek için veri kümesini ve yineleyici oluşturmayı grafiğin dışına çıkarmak için tf.init_scope
kullanabiliriz:
class Model(tf.Module):
def __init__(self):
self.datasets = {}
self.iterators = {}
@tf.function
def __call__(self, key):
if key not in self.datasets:
# Lifts ops out of function-building graphs
with tf.init_scope():
self.datasets[key] = tf.data.Dataset.from_tensor_slices([1, 2, 3])
self.iterators[key] = iter(self.datasets[key])
return self.iterators[key]
m = Model()
for _ in range(3):
print(next(m('a'))) # prints 1, 2, 3
Genel kural, mantığınızdaki Python yan etkilerine güvenmekten kaçınmak ve bunları yalnızca izlemelerinizde hata ayıklamak için kullanmaktır.
Örnek 4: Genel bir Python listesini işlemek
Aşağıdaki TF1.x kodu, yalnızca geçerli eğitim adımı tarafından oluşturulan kayıpların listesini korumak için kullandığı genel bir kayıp listesi kullanır. Kayıpları listeye ekleyen Python mantığının, oturumun kaç eğitim adımı için çalıştırıldığına bakılmaksızın yalnızca bir kez çağrılacağını unutmayın.
all_losses = []
class Model():
def __call__(...):
...
all_losses.append(regularization_loss)
all_losses.append(label_loss_a)
all_losses.append(label_loss_b)
...
g = tf.Graph()
with g.as_default():
...
# initialize all objects
model = Model()
optimizer = ...
...
# train step
model(...)
total_loss = tf.reduce_sum(all_losses)
optimizer.minimize(total_loss)
...
...
sess = tf.compat.v1.Session(graph=g)
sess.run(...)
Bununla birlikte, bu Python mantığı, istekli yürütme ile saf bir şekilde TF2 ile eşlenirse, küresel kayıp listesi, her eğitim adımında kendisine eklenen yeni değerlere sahip olacaktır. Bu, daha önce listenin yalnızca mevcut eğitim adımındaki kayıpları içermesini bekleyen eğitim adımı kodunun, şimdi o ana kadar çalıştırılan tüm eğitim adımlarındaki kayıpların listesini gördüğü anlamına gelir. Bu, istenmeyen bir davranış değişikliğidir ve listenin her adımın başında temizlenmesi veya eğitim adımına yerel hale getirilmesi gerekir.
all_losses = []
class Model():
def __call__(...):
...
all_losses.append(regularization_loss)
all_losses.append(label_loss_a)
all_losses.append(label_loss_b)
...
# initialize all objects
model = Model()
optimizer = ...
def train_step(...)
...
model(...)
total_loss = tf.reduce_sum(all_losses) # global list is never cleared,
# Accidentally accumulates sum loss across all training steps
optimizer.minimize(total_loss)
...
Model 2: TF1.x'teki her adımda yeniden hesaplanması amaçlanan bir sembolik tensör, istekli duruma geçerken yanlışlıkla ilk değerle önbelleğe alınır.
Bu model genellikle kodunuzun tf.functions dışında hevesle yürütülürken sessizce hatalı davranmasına neden olur, ancak ilk değer önbelleğe alma bir tf.function
içinde gerçekleşirse bir InaccessibleTensorError
oluşturur. Ancak, yukarıdaki Model 1'den kaçınmak için, genellikle yanlışlıkla kodunuzu, bu ilk değer önbelleğe alma, bir hata oluşturabilecek herhangi bir tf.function
dışında gerçekleşecek şekilde yapılandıracağınızı unutmayın. Bu nedenle, programınızın bu kalıba duyarlı olabileceğini biliyorsanız, ekstra özen gösterin.
Bu kalıbın genel çözümü, değeri yanlışlıkla önbelleğe almak yerine her seferinde yeniden hesaplandığından emin olmak için kodu yeniden yapılandırmak veya gerekirse Python çağrılabilirlerini kullanmaktır.
Örnek 1: Öğrenme hızı/hiperparametre/vb. küresel adıma bağlı programlar
Aşağıdaki kod parçacığında beklenti, oturum her çalıştırıldığında en son global_step
değerinin okunacağı ve yeni bir öğrenme oranının hesaplanacağı yönündedir.
g = tf.Graph()
with g.as_default():
...
global_step = tf.Variable(0)
learning_rate = 1.0 / global_step
opt = tf.compat.v1.train.GradientDescentOptimizer(learning_rate)
...
global_step.assign_add(1)
...
sess = tf.compat.v1.Session(graph=g)
sess.run(...)
Ancak, istekli olmaya geçiş yapmaya çalışırken, amaçlanan programı takip etmek yerine, öğrenme oranının yalnızca bir kez hesaplanıp sonra yeniden kullanılmasıyla sonuçlanmamaya dikkat edin:
global_step = tf.Variable(0)
learning_rate = 1.0 / global_step # Wrong! Only computed once!
opt = tf.keras.optimizers.SGD(learning_rate)
def train_step(...):
...
opt.apply_gradients(...)
global_step.assign_add(1)
...
Bu özel örnek yaygın bir model olduğundan ve optimize ediciler her eğitim adımından ziyade yalnızca bir kez başlatılmalıdır, TF2 optimize edicileri öğrenme hızı ve diğer hiperparametreler için argümanlar olarak tf.keras.optimizers.schedules.LearningRateSchedule
programlarını veya Python çağrılabilirlerini destekler.
Örnek 2: Nesne öznitelikleri olarak atanan ve ardından işaretçi aracılığıyla yeniden kullanılan sembolik rasgele sayı başlatmaları, istekliye geçerken yanlışlıkla önbelleğe alınır
Aşağıdaki NoiseAdder
modülünü göz önünde bulundurun:
class NoiseAdder(tf.Module):
def __init__(shape, mean):
self.noise_distribution = tf.random.normal(shape=shape, mean=mean)
self.trainable_scale = tf.Variable(1.0, trainable=True)
def add_noise(input):
return (self.noise_distribution + input) * self.trainable_scale
TF1.x'te aşağıdaki gibi kullanmak, oturum her çalıştırıldığında yeni bir rastgele gürültü tensörü hesaplayacaktır:
g = tf.Graph()
with g.as_default():
...
# initialize all variable-containing objects
noise_adder = NoiseAdder(shape, mean)
...
# computation pass
x_with_noise = noise_adder.add_noise(x)
...
...
sess = tf.compat.v1.Session(graph=g)
sess.run(...)
Ancak, noise_adder
başlangıçta başlatılması, noise_distribution
yalnızca bir kez hesaplanmasına ve tüm eğitim adımları için donmasına neden olacaktır:
...
# initialize all variable-containing objects
noise_adder = NoiseAdder(shape, mean) # Freezes `self.noise_distribution`!
...
# computation pass
x_with_noise = noise_adder.add_noise(x)
...
Bunu düzeltmek için, her seferinde aynı tensör nesnesine başvurmak yerine, her yeni bir rastgele tensör gerektiğinde tf.random.normal
öğesini çağırmak için NoiseAdder
refactor.
class NoiseAdder(tf.Module):
def __init__(shape, mean):
self.noise_distribution = lambda: tf.random.normal(shape=shape, mean=mean)
self.trainable_scale = tf.Variable(1.0, trainable=True)
def add_noise(input):
return (self.noise_distribution() + input) * self.trainable_scale
Model 3: TF1.x kodu doğrudan dayanır ve tensörleri ada göre arar
TF1.x kod testlerinin bir grafikte hangi tensörlerin veya işlemlerin bulunduğunu kontrol etmeye dayanması yaygındır. Bazı ender durumlarda, modelleme kodu da bu aramaları ada göre kullanır.
tf.function
dışında hevesle yürütülürken tensör adları oluşturulmaz, bu nedenle tf.Tensor.name öğesinin tüm kullanımları bir tf.Tensor.name
içinde tf.function
. Gerçek oluşturulan adların, aynı tf.function
içinde bile TF1.x ve TF2 arasında büyük olasılıkla farklılık gösterebileceğini ve API garantilerinin, oluşturulan adların TF sürümlerinde kararlılığını sağlamadığını unutmayın.
Model 4: TF1.x oturumu, oluşturulan grafiğin yalnızca bir kısmını seçerek çalıştırır
TF1.x'te, bir grafik oluşturabilir ve ardından grafikteki her işlemin çalıştırılmasını gerektirmeyen bir dizi girdi ve çıktı seçerek bunun yalnızca bir alt kümesini seçerek bir oturumla çalıştırmayı seçebilirsiniz.
Örneğin, tek bir grafiğin içinde hem bir oluşturucu hem de bir ayırıcı olabilir ve yalnızca ayırıcıyı eğitmek veya yalnızca oluşturucuyu eğitmek arasında geçiş yapmak için ayrı tf.compat.v1.Session.run
çağrıları kullanabilirsiniz.
TF2'de, tf.function
otomatik kontrol bağımlılıkları ve istekli yürütme nedeniyle, tf.function
izlerinin seçici budaması yoktur. Tüm değişken güncellemelerini içeren tam bir grafik, örneğin yalnızca ayırıcının veya üretecin çıktısı tf.function
.
Bu nedenle, ya programın farklı bölümlerini içeren birden çok tf.function
s kullanmanız ya da yalnızca gerçekten çalıştırmak istediğiniz şeyleri yürütmek için tf.function
için koşullu bir argüman kullanmanız gerekir.
Koleksiyon Kaldırma
İstekli yürütme etkinleştirildiğinde, grafik koleksiyonuyla ilgili compat.v1
API'leri ( tf.compat.v1.trainable_variables
gibi başlık altındaki koleksiyonlara okuyan veya bunlara yazanlar dahil) artık kullanılamaz. Bazıları ValueError
s'yi yükseltebilirken, diğerleri sessizce boş listeler döndürebilir.
TF1.x'teki koleksiyonların en standart kullanımı, başlatıcıları, genel adımı, ağırlıkları, düzenlileştirme kayıplarını, model çıktı kayıplarını ve BatchNormalization
katmanlarından çalıştırılması gereken değişken güncellemelerini korumaktır.
Bu standart kullanımların her birini işlemek için:
- Başlatıcılar - Yoksay. İstekli yürütme etkinken manuel değişken başlatma gerekli değildir.
- Genel adım - Taşıma talimatları için
tf.compat.v1.train.get_or_create_global_step
belgelerine bakın. - Ağırlıklar - Model eşleme kılavuzundaki yönergeleri izleyerek modellerinizi
tf.Module
s/tf.keras.layers.Layer
s/tf.keras.Model
s ile eşleştirin ve ardındantf.module.trainable_variables
. - Düzenlileştirme kayıpları - Model haritalama kılavuzundaki yönergeleri izleyerek modellerinizi
tf.Module
s/tf.keras.layers.Layer
s/tf.keras.Model
s ile eşleştirin ve ardındantf.keras.losses
kullanın. Alternatif olarak, düzenlileştirme kayıplarınızı manuel olarak da takip edebilirsiniz. - Model çıktı kayıpları -
tf.keras.Model
kayıp yönetimi mekanizmalarını kullanın veya koleksiyon kullanmadan kayıplarınızı ayrı olarak izleyin. - Ağırlık güncellemeleri - Bu koleksiyonu yoksay. İstekli yürütme ve
tf.function
(imza ve otomatik kontrol bağımlılıklarıyla birlikte), tüm değişken güncellemelerin otomatik olarak çalıştırılacağı anlamına gelir. Bu nedenle, tüm ağırlık güncellemelerini en sonunda açıkça çalıştırmanız gerekmeyecek, ancak bunun, ağırlık güncellemelerinin, kontrol bağımlılıklarını nasıl kullandığınıza bağlı olarak, TF1.x kodunuzda olduğundan farklı bir zamanda gerçekleşebileceği anlamına geldiğini unutmayın. - Özetler - Taşıma özeti API kılavuzuna bakın.
Daha karmaşık koleksiyon kullanımı (özel koleksiyonlar kullanmak gibi), kendi global mağazalarınızı sürdürmek veya global mağazalara hiç güvenmemek için kodunuzu yeniden düzenlemenizi gerektirebilir.
ReferenceVariables
yerine ResourceVariables
ResourceVariables
, ReferenceVariables
daha güçlü okuma-yazma tutarlılığı garantilerine sahiptir. Bu, değişkenlerinizi kullanırken önceki bir yazmanın sonucunu gözlemleyip gözlemlemeyeceğiniz konusunda anlambilim hakkında daha öngörülebilir, daha kolay akıl yürütmeye yol açar. Bu değişikliğin, mevcut kodun hata vermesine veya sessizce kırılmasına neden olması pek olası değildir.
Ancak, bu daha güçlü tutarlılık garantilerinin belirli programınızın bellek kullanımını artırması pek olası olmasa da mümkündür. Durumun böyle olduğunu düşünüyorsanız lütfen bir sorun bildirin. Ek olarak, değişken okumalarına karşılık gelen bir grafikte operatör adlarıyla tam dize karşılaştırmalarına dayanan birim testleriniz varsa, kaynak değişkenlerini etkinleştirmenin bu operatörlerin adını biraz değiştirebileceğini unutmayın.
Bu davranış değişikliğinin kodunuz üzerindeki etkisini izole etmek için, istekli yürütme devre dışı bırakılırsa, bu davranış değişikliğini genel olarak devre dışı bırakmak veya etkinleştirmek için tf.compat.v1.disable_resource_variables()
ve tf.compat.v1.enable_resource_variables()
kullanabilirsiniz. İstekli yürütme etkinleştirilirse, ResourceVariables
her zaman kullanılacaktır.
Kontrol akışı v2
TF1.x'te, tf.cond
ve tf.while_loop
gibi kontrol akışı operasyonları Switch
, Merge
vb. gibi satır içi düşük seviyeli operasyonlar. TF2, her dal ve destek için ayrı tf.function
izlemeleriyle uygulanan gelişmiş fonksiyonel kontrol akışı operasyonları sağlar. üst düzey farklılaşma
Bu davranış değişikliğinin kodunuz üzerindeki etkisini izole etmek için, istekli yürütme devre dışı bırakılırsa, bu davranış değişikliğini genel olarak devre dışı bırakmak veya etkinleştirmek için tf.compat.v1.disable_control_flow_v2()
ve tf.compat.v1.enable_control_flow_v2()
kullanabilirsiniz. Ancak, kontrol akışı v2'yi yalnızca istekli yürütme de devre dışı bırakılmışsa devre dışı bırakabilirsiniz. Etkinleştirilirse, kontrol akışı v2 her zaman kullanılacaktır.
Bu davranış değişikliği, bir düz grafik yerine birkaç iç içe işlev izi içereceğinden, kontrol akışını kullanan oluşturulan TF programlarının yapısını önemli ölçüde değiştirebilir. Bu nedenle, üretilen izlerin tam semantiğine yüksek oranda bağımlı olan herhangi bir kod, bazı değişiklikler gerektirebilir. Bu içerir:
- Operatör ve tensör adlarına dayanan kod
- Bir TensorFlow kontrol akışı dalında o dalın dışından oluşturulan tensörlere atıfta bulunan kod. Bunun bir
InaccessibleTensorError
üretmesi muhtemeldir
Bu davranış değişikliğinin performans açısından nötrden pozitife doğru olması amaçlanmıştır, ancak v2 kontrol akışının sizin için TF1.x kontrol akışından daha kötü performans gösterdiği bir sorunla karşılaşırsanız, lütfen çoğaltma adımlarıyla ilgili bir sorun bildirin.
TensorShape API davranış değişiklikleri
TensorShape
sınıfı, tf.compat.v1.Dimension
nesneleri yerine int
s'yi tutacak şekilde basitleştirildi. Yani int
almak için .value
çağırmaya gerek yoktur.
Bireysel tf.compat.v1.Dimension
nesnelerine tf.TensorShape.dims
erişilebilir.
Bu davranış değişikliğinin kodunuz üzerindeki etkisini izole etmek için, bu davranış değişikliğini genel olarak devre dışı bırakmak veya etkinleştirmek için tf.compat.v1.disable_v2_tensorshape()
ve tf.compat.v1.enable_v2_tensorshape()
kullanabilirsiniz.
Aşağıdakiler, TF1.x ve TF2 arasındaki farkları göstermektedir.
import tensorflow as tf
# Create a shape and choose an index
i = 0
shape = tf.TensorShape([16, None, 256])
shape
-yer tutucu21 l10n-yerTensorShape([16, None, 256])
TF1.x'te buna sahip olsaydınız:
value = shape[i].value
Ardından bunu TF2'de yapın:
value = shape[i]
value
tutucu24 l10n-yer16
TF1.x'te buna sahip olsaydınız:
for dim in shape:
value = dim.value
print(value)
Ardından, bunu TF2'de yapın:
for value in shape:
print(value)
tutucu27 l10n-yer16 None 256
Bunu TF1.x'te aldıysanız (veya başka bir boyut yöntemi kullandıysanız):
dim = shape[i]
dim.assert_is_compatible_with(other_dim)
Ardından bunu TF2'de yapın:
other_dim = 16
Dimension = tf.compat.v1.Dimension
if shape.rank is None:
dim = Dimension(None)
else:
dim = shape.dims[i]
dim.is_compatible_with(other_dim) # or any other dimension method
True-yer tutucu31 l10n-yer
shape = tf.TensorShape(None)
if shape:
dim = shape.dims[i]
dim.is_compatible_with(other_dim) # or any other dimension method
Bir tf.TensorShape
boole değeri, sıralama biliniyorsa True
, değilse False
olur.
print(bool(tf.TensorShape([]))) # Scalar
print(bool(tf.TensorShape([0]))) # 0-length vector
print(bool(tf.TensorShape([1]))) # 1-length vector
print(bool(tf.TensorShape([None]))) # Unknown-length vector
print(bool(tf.TensorShape([1, 10, 100]))) # 3D tensor
print(bool(tf.TensorShape([None, None, None]))) # 3D tensor with no known dimensions
print()
print(bool(tf.TensorShape(None))) # A tensor with unknown rank.
tutucu33 l10n-yerTrue True True True True True False
TensorShape değişikliklerinden kaynaklanan olası hatalar
TensorShape davranış değişikliklerinin kodunuzu sessizce bozması pek olası değildir. Ancak, şekille ilgili kodun AttributeError
s'yi int
s olarak yükseltmeye başladığını görebilirsiniz ve None
s, tf.compat.v1.Dimension
s ile aynı özelliklere sahip değildir. Aşağıda bu AttributeError
'lara ilişkin bazı örnekler verilmiştir:
try:
# Create a shape and choose an index
shape = tf.TensorShape([16, None, 256])
value = shape[0].value
except AttributeError as e:
# 'int' object has no attribute 'value'
print(e)
'int' object has no attribute 'value'yer tutucu36 l10n-yer
try:
# Create a shape and choose an index
shape = tf.TensorShape([16, None, 256])
dim = shape[1]
other_dim = shape[2]
dim.assert_is_compatible_with(other_dim)
except AttributeError as e:
# 'NoneType' object has no attribute 'assert_is_compatible_with'
print(e)
'NoneType' object has no attribute 'assert_is_compatible_with'
Değere Göre Tensör Eşitliği
Değişkenler ve tensörler üzerindeki ikili ==
ve !=
operatörleri, TF1.x'teki gibi nesne referansıyla karşılaştırmak yerine TF2'deki değere göre karşılaştırılacak şekilde değiştirildi. Ek olarak, tensörler ve değişkenler artık doğrudan hash edilemez veya setlerde veya dict anahtarlarında kullanılamaz, çünkü onları değere göre hash etmek mümkün olmayabilir. Bunun yerine, tensör veya değişkene kolay erişilebilir bir başvuru elde etmek için kullanabileceğiniz bir .ref()
yöntemini gösterirler.
Bu davranış değişikliğinin etkisini izole etmek için, bu davranış değişikliğini genel olarak devre dışı bırakmak veya etkinleştirmek için tf.compat.v1.disable_tensor_equality()
ve tf.compat.v1.enable_tensor_equality()
kullanabilirsiniz.
Örneğin, TF1.x'te, ==
operatörünü kullandığınızda aynı değere sahip iki değişken false döndürür:
tf.compat.v1.disable_tensor_equality()
x = tf.Variable(0.0)
y = tf.Variable(0.0)
x == y
tutucu39 l10n-yerFalse
TF2'de tensör eşitlik kontrolleri etkinken, x == y
True
değerini döndürür.
tf.compat.v1.enable_tensor_equality()
x = tf.Variable(0.0)
y = tf.Variable(0.0)
x == y
tutucu41 l10n-yer<tf.Tensor: shape=(), dtype=bool, numpy=True>
Bu nedenle, TF2'de, nesne referansına göre karşılaştırmanız gerekiyorsa, is
ve is not
not'u kullandığınızdan emin olun.
tf.compat.v1.enable_tensor_equality()
x = tf.Variable(0.0)
y = tf.Variable(0.0)
x is y
tutucu43 l10n-yerFalse
Karma tensörler ve değişkenler
TF1.x davranışlarıyla, set
ve dict
tuşları gibi karma gerektiren veri yapılarına doğrudan değişkenler ve tensörler ekleyebiliyordunuz.
tf.compat.v1.disable_tensor_equality()
x = tf.Variable(0.0)
set([x, tf.constant(2.0)])
tutucu45 l10n-yer{<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>, <tf.Tensor: shape=(), dtype=float32, numpy=2.0>}
Bununla birlikte, tensör eşitliği etkinleştirilmiş TF2'de, ==
ve !=
operatör anlambiliminin değer eşitlik kontrollerine dönüşmesi nedeniyle tensörler ve değişkenler hash edilemez hale getirilir.
tf.compat.v1.enable_tensor_equality()
x = tf.Variable(0.0)
try:
set([x, tf.constant(2.0)])
except TypeError as e:
# TypeError: Variable is unhashable. Instead, use tensor.ref() as the key.
print(e)
tutucu47 l10n-yerVariable is unhashable. Instead, use tensor.ref() as the key.
Bu nedenle, TF2'de anahtar veya set
içeriği olarak tensör veya değişken nesneler kullanmanız gerekiyorsa, anahtar olarak kullanılabilecek bir hashable referansı almak için tensor.ref()
kullanabilirsiniz:
tf.compat.v1.enable_tensor_equality()
x = tf.Variable(0.0)
tensor_set = set([x.ref(), tf.constant(2.0).ref()])
assert x.ref() in tensor_set
tensor_set
tutucu49 l10n-yer{<Reference wrapping <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>>, <Reference wrapping <tf.Tensor: shape=(), dtype=float32, numpy=2.0>>}
Gerekirse, referanstan tensörü veya değişkeni reference.deref()
kullanarak da alabilirsiniz:
referenced_var = x.ref().deref()
assert referenced_var is x
referenced_var
tutucu51 l10n-yer<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>
Kaynaklar ve daha fazla okuma
- TF1.x'ten TF2'ye geçiş hakkında daha fazla bilgi için TF2'ye Geçiş bölümünü ziyaret edin.
- TF1.x modellerinizi doğrudan TF2'de çalışacak şekilde eşleştirme hakkında daha fazla bilgi edinmek için model eşleştirme kılavuzunu okuyun.