genel bakış
Bu kılavuz, TensorFlow Profiler ve tf.data
ile aşina olduğunuzu varsayar. Kullanıcıların giriş boru hattı performans sorunlarını teşhis etmesine ve düzeltmesine yardımcı olmak için örneklerle adım adım talimatlar sağlamayı amaçlar.
Başlamak için, TensorFlow işinizin profilini toplayın. Bunun nasıl yapılacağına ilişkin talimatlar, CPU'lar/GPU'lar ve Cloud TPU'lar için mevcuttur.
Aşağıda ayrıntıları verilen analiz iş akışı, Profil Oluşturucu'daki iz görüntüleyici aracına odaklanır. Bu araç, TensorFlow programınız tarafından gerçekleştirilen operasyonların süresini gösteren bir zaman çizelgesi görüntüler ve hangi operasyonların yürütülmesinin en uzun sürdüğünü belirlemenizi sağlar. İz görüntüleyici hakkında daha fazla bilgi için TF Profiler kılavuzunun bu bölümüne bakın . Genel olarak, ana bilgisayar CPU zaman çizelgesinde tf.data
olayları görünecektir.
Analiz İş Akışı
Lütfen aşağıdaki iş akışını takip edin. Geliştirmemize yardımcı olacak geri bildiriminiz varsa, lütfen "comp:data" etiketiyle bir github sorunu oluşturun .
1. tf.data
hattınız yeterince hızlı veri üretiyor mu?
Giriş boru hattının TensorFlow programınız için darboğaz olup olmadığını belirleyerek başlayın.
Bunu yapmak için izleme görüntüleyicide IteratorGetNext::DoCompute
işlemlerini arayın. Genel olarak, bunları bir adımın başında görmeyi beklersiniz. Bu dilimler, giriş boru hattınızın istendiğinde bir grup öğeyi vermesi için geçen süreyi temsil eder. Bir tf.function içinde keras kullanıyorsanız veya veri kümeniz üzerinde yineleme tf.function
, bunlar tf_data_iterator_get_next
dizilerinde bulunmalıdır.
Bir dağıtım stratejisi kullanıyorsanız, IteratorGetNext::DoCompute
::DoCompute yerine (TF 2.3'ten itibaren) IteratorGetNextAsOptional::DoCompute
olaylarını görebileceğinizi unutmayın.
Aramalar hızlı bir şekilde geri dönerse (<= 50 us), bu, talep edildiğinde verilerinizin mevcut olduğu anlamına gelir. Giriş boru hattı sizin darboğazınız değildir; daha genel performans analizi ipuçları için Profil oluşturucu kılavuzuna bakın.
Aramalar yavaş dönerse, tf.data
tüketicinin isteklerine yetişemez. Bir sonraki bölüme devam edin.
2. Verileri önceden mi getiriyorsunuz?
Girdi işlem hattı performansı için en iyi uygulama, tf.data işlem hattınızın sonuna bir tf.data.Dataset.prefetch
dönüşümü tf.data
. Bu dönüşüm, girdi ardışık düzeninin ön işleme hesaplamasıyla model hesaplamanın sonraki adımıyla çakışır ve modelinizi eğitirken optimum girdi ardışık düzeni performansı için gereklidir. Verileri önceden getiriyorsanız, IteratorGetNext::DoCompute
aynı iş parçacığında bir Iterator::Prefetch
dilimi görmelisiniz.
Ardışık düzeninizin sonunda bir prefetch
yoksa, bir tane eklemelisiniz. tf.data
performans önerileri hakkında daha fazla bilgi için tf.data performans kılavuzuna bakın.
Halihazırda verileri önceden getiriyorsanız ve giriş ardışık düzeni sizin için hâlâ darboğazsa, performansı daha fazla analiz etmek için bir sonraki bölüme geçin.
3. Yüksek CPU kullanımına ulaşıyor musunuz?
tf.data
, mevcut kaynakları mümkün olan en iyi şekilde kullanmaya çalışarak yüksek verim elde eder. Genel olarak, modelinizi GPU veya TPU gibi bir hızlandırıcı üzerinde çalıştırırken bile tf.data
ardışık düzenleri CPU üzerinde çalıştırılır. Kullanımınızı sar ve htop gibi araçlarla veya GCP'de çalışıyorsanız bulut izleme konsolunda kontrol edebilirsiniz.
Kullanımınız düşükse bu, girdi boru hattınızın ana bilgisayar CPU'sundan tam olarak yararlanamayabileceğini gösterir. En iyi uygulamalar için tf.data performans kılavuzuna başvurmalısınız. En iyi uygulamaları uyguladıysanız ve kullanım ile verim düşük kalmaya devam ediyorsa, aşağıdaki Darboğaz analizine devam edin.
Kullanımınız kaynak sınırına yaklaşıyorsa performansı daha da artırmak için ya girdi hattınızın verimliliğini artırmanız (örneğin, gereksiz hesaplamadan kaçınma) ya da hesaplamayı boşaltmanız gerekir.
tf.data
gereksiz hesaplamalardan kaçınarak girdi işlem hattınızın verimliliğini artırabilirsiniz. Bunu yapmanın bir yolu, verileriniz belleğe sığarsa, hesaplama açısından yoğun bir çalışmanın ardından bir tf.data.Dataset.cache
dönüşümü eklemektir; bu, artan bellek kullanımı pahasına hesaplamayı azaltır. Ek olarak, tf.data
işlem içi paralelliğin devre dışı bırakılması verimliliği > %10 artırma potansiyeline sahiptir ve giriş boru hattınızda aşağıdaki seçeneği ayarlayarak yapılabilir:
dataset = ...
options = tf.data.Options()
options.experimental_threading.max_intra_op_parallelism = 1
dataset = dataset.with_options(options)
4. Darboğaz Analizi
Aşağıdaki bölüm, darboğazın nerede olduğunu ve olası hafifletme stratejilerini anlamak için iz görüntüleyicide tf.data
olaylarının nasıl okunacağını açıklamaktadır.
Profil tf.data
olaylarını anlama
Profil Oluşturucu'daki her tf.data
olayı, Iterator::<Dataset>
adına sahiptir; burada <Dataset>
, veri kümesi kaynağının veya dönüşümün adıdır. Her olayın ayrıca tf.data
olayına tıklayarak görebileceğiniz Iterator::<Dataset_1>::...::<Dataset_n>
uzun adı vardır. Uzun adda <Dataset_n>
, (kısa) addan <Dataset>
ile eşleşir ve uzun addaki diğer veri kümeleri aşağı akış dönüşümlerini temsil eder.
Örneğin, yukarıdaki ekran görüntüsü aşağıdaki koddan oluşturulmuştur:
dataset = tf.data.Dataset.range(10)
dataset = dataset.map(lambda x: x)
dataset = dataset.repeat(2)
dataset = dataset.batch(5)
Burada Iterator::Map
olayı, Iterator::BatchV2::FiniteRepeat::Map
uzun adına sahiptir. Veri kümelerinin adının python API'sinden biraz farklı olabileceğini (örneğin, Tekrar yerine FiniteRepeat) ancak ayrıştırmak için yeterince sezgisel olması gerektiğini unutmayın.
Eşzamanlı ve eşzamansız dönüşümler
Eşzamanlı tf.data
dönüşümleri için ( Batch
ve Map
gibi), aynı iş parçacığında yukarı akış dönüşümlerinden gelen olayları göreceksiniz. Yukarıdaki örnekte, kullanılan tüm dönüşümler senkronize olduğundan, tüm olaylar aynı iş parçacığında görünür.
Zaman uyumsuz dönüşümler için (örneğin Prefetch
, ParallelMap
, ParallelInterleave
ve MapAndBatch
) yukarı akış dönüşümlerinden gelen olaylar farklı bir iş parçacığında olacaktır. Bu gibi durumlarda, "uzun ad", bir olayın ardışık düzende hangi dönüşüme karşılık geldiğini belirlemenize yardımcı olabilir.
Örneğin, yukarıdaki ekran görüntüsü aşağıdaki koddan oluşturulmuştur:
dataset = tf.data.Dataset.range(10)
dataset = dataset.map(lambda x: x)
dataset = dataset.repeat(2)
dataset = dataset.batch(5)
dataset = dataset.prefetch(1)
Burada, Iterator::Prefetch
olayları tf_data_iterator_get_next
iş parçacığındadır. Prefetch
eşzamansız olduğundan, girdi olayları ( BatchV2
) farklı bir iş parçacığında olacaktır ve Iterator::Prefetch::BatchV2
uzun adı aranarak bulunabilir. Bu durumda, tf_data_iterator_resource
dizisinde bulunurlar. Uzun adından, BatchV2
Prefetch
yukarı akışı olduğunu anlayabilirsiniz. Ayrıca, parent_id
olayının BatchV2
değeri, Prefetch
olayının kimliği ile eşleşecektir.
Darboğazın belirlenmesi
Genel olarak, giriş boru hattınızdaki darboğazı belirlemek için, giriş boru hattını en dıştaki dönüşümden kaynağa kadar yürütün. İşlem hattınızdaki son dönüşümden başlayarak, yavaş bir dönüşüm bulana veya TFRecord
gibi bir kaynak veri kümesine ulaşana kadar yukarı akış dönüşümlerine yineleyin. Yukarıdaki örnekte, Prefetch
başlayacak, ardından BatchV2
, FiniteRepeat
, Map
ve son olarak Range
doğru ilerleyeceksiniz.
Genel olarak, yavaş bir dönüşüm, olayları uzun, ancak girdi olayları kısa olan bir dönüşüme karşılık gelir. Bazı örnekler aşağıdadır.
Çoğu ana bilgisayar giriş işlem hattındaki son (en dıştaki) dönüşümün Iterator::Model
olayı olduğunu unutmayın. Model dönüşümü, tf.data
çalışma zamanı tarafından otomatik olarak sunulur ve girdi ardışık düzeni performansının enstrümantasyonu ve otomatik olarak ayarlanması için kullanılır.
İşiniz bir dağıtım stratejisi kullanıyorsa iz görüntüleyici, cihaz giriş hattına karşılık gelen ek olaylar içerecektir. Cihaz boru hattının en dıştaki dönüşümü ( IteratorGetNextOp::DoCompute
veya IteratorGetNextAsOptionalOp::DoCompute
altında iç içe geçmiş), yukarı akış Iterator::Generator
olayı ile bir Iterator::Prefetch
olayı olacaktır. Iterator::Model
olaylarını arayarak karşılık gelen ana bilgisayar ardışık düzenini bulabilirsiniz.
örnek 1
Yukarıdaki ekran görüntüsü, aşağıdaki giriş boru hattından oluşturulur:
dataset = tf.data.TFRecordDataset(filename)
dataset = dataset.map(parse_record)
dataset = dataset.batch(32)
dataset = dataset.repeat()
Ekran görüntüsünde, (1) Iterator::Map
olaylarının uzun olduğunu, ancak (2) giriş olaylarının ( Iterator::FlatMap
) hızlı bir şekilde geri döndüğünü gözlemleyin. Bu, sıralı Harita dönüşümünün darboğaz olduğunu gösterir.
Ekran görüntüsünde, InstantiatedCapturedFunction::Run
olayının harita işlevini yürütmek için geçen süreye karşılık geldiğini unutmayın.
Örnek 2
Yukarıdaki ekran görüntüsü, aşağıdaki giriş boru hattından oluşturulur:
dataset = tf.data.TFRecordDataset(filename)
dataset = dataset.map(parse_record, num_parallel_calls=2)
dataset = dataset.batch(32)
dataset = dataset.repeat()
Bu örnek, yukarıdakine benzer, ancak Harita yerine ParallelMap'i kullanır. Burada (1) Iterator::ParallelMap
olaylarının uzun olduğunu ancak (2) Iterator::FlatMap
giriş olaylarının (ParallelMap eşzamansız olduğundan farklı bir iş parçacığında olan) kısa olduğunu fark ettik. Bu, ParallelMap dönüşümünün darboğaz olduğunu gösterir.
Darboğazın ele alınması
Kaynak veri kümeleri
Darboğaz olarak bir veri kümesi kaynağı belirlediyseniz (TFRecord dosyalarından okuma gibi), veri ayıklamayı paralel hale getirerek performansı artırabilirsiniz. Bunu yapmak için, verilerinizin birden çok dosya arasında paylaştırıldığından emin olun ve tf.data.Dataset.interleave
num_parallel_calls
parametresi tf.data.AUTOTUNE
olarak ayarlanmış şekilde kullanın. Determinizm programınız için önemli değilse, TF tf.data.Dataset.interleave
itibaren tf.data.Dataset.interleave'de deterministic=False
bayrağını ayarlayarak performansı daha da artırabilirsiniz. Örneğin, TFRecords'tan okuyorsanız aşağıdakileri yapabilirsiniz:
dataset = tf.data.Dataset.from_tensor_slices(filenames)
dataset = dataset.interleave(tf.data.TFRecordDataset,
num_parallel_calls=tf.data.AUTOTUNE,
deterministic=False)
Parçalanmış dosyaların, bir dosyayı açma yükünün amortismana tabi tutulması için makul ölçüde büyük olması gerektiğini unutmayın. Paralel veri çıkarma hakkında daha fazla ayrıntı için tf.data
performans kılavuzunun bu bölümüne bakın.
Dönüşüm veri kümeleri
Darboğaz olarak bir ara tf.data
dönüşümü belirlediyseniz, verileriniz belleğe sığıyorsa ve uygunsa, dönüşümü paralelleştirerek veya hesaplamayı önbelleğe alarak bu sorunu çözebilirsiniz. Map
gibi bazı dönüşümlerin paralel karşılıkları vardır; tf.data
performans kılavuzu, bunların nasıl paralelleştirileceğini gösterir . Filter
, Unbatch
ve Batch
gibi diğer dönüştürmeler doğası gereği sıralıdır; “dış paralellik” getirerek bunları paralelleştirebilirsiniz. Örneğin, giriş boru hattınızın başlangıçta aşağıdaki gibi göründüğünü varsayalım, darboğaz Batch
ile:
filenames = tf.data.Dataset.list_files(file_path, shuffle=is_training)
dataset = filenames_to_dataset(filenames)
dataset = dataset.batch(batch_size)
Parçalanmış girdiler üzerinde girdi hattının birden çok kopyasını çalıştırarak ve sonuçları birleştirerek "dış paralelliği" tanıtabilirsiniz:
filenames = tf.data.Dataset.list_files(file_path, shuffle=is_training)
def make_dataset(shard_index):
filenames = filenames.shard(NUM_SHARDS, shard_index)
dataset = filenames_to_dataset(filenames)
Return dataset.batch(batch_size)
indices = tf.data.Dataset.range(NUM_SHARDS)
dataset = indices.interleave(make_dataset,
num_parallel_calls=tf.data.AUTOTUNE)
dataset = dataset.prefetch(tf.data.AUTOTUNE)
Ek kaynaklar
- performans
tf.data
giriş ardışık düzenlerinin nasıl yazılacağına ilişkin tf.data performans kılavuzu - TensorFlow videosu içinde:
tf.data
en iyi uygulamaları - Profil oluşturucu kılavuzu
- colab ile profil oluşturma eğitimi