In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Egitim donguleri ile tf.distribute.Strategy

Note: Bu dökümanlar TensorFlow gönüllü kullanıcıları tarafından çevirilmiştir. Topluluk tarafından sağlananan çeviriler gönüllülerin ellerinden geldiğince güncellendiği için Resmi İngilizce dökümanlar ile bire bir aynı olmasını garantileyemeyiz. Eğer bu tercümeleri iyileştirmek için önerileriniz var ise lütfen tensorflow/docs havuzuna pull request gönderin. Gönüllü olarak çevirilere katkıda bulunmak için docs-tr@tensorflow.org listesi ile iletişime geçebilirsiniz.

Bu rehber egitim donguleri ile tf.distribute.Strategy'nin nasil kullanildigini gosteriyor. Basit bir CNN modelini Fashion MNIST veri seti ile egitecegiz. Bu veri seti icinde 28X28 boyutunda 60000 egitim resmini ve 28X28 boyutunda 10000 test resmini barindirir.

Burada bize esneklik ve daha cok kontrol kazandirmasi icin ozellestirilmis egitim donguleri kullanacagiz. Ustelik, bu ozel donguler modeli ve egitim dongulerindeki hatalari ayiklamamizi da kolaylastiracaktir.


In [ ]:
# TensorFlow'u yukleyelim
import tensorflow.compat.v1 as tf


# Yardimci kutuphaneler
import numpy as np
import os

print(tf.__version__)

Fashion MNIST veri setini indirelim


In [ ]:
fashion_mnist = tf.keras.datasets.fashion_mnist

(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

# Diziye yeni bir boyut ekleyelim-> new shape == (28, 28, 1)
# Bunu yapmamizin sebebi ise modelimizin ilk katmaninin katlamali olmasi
# ve 4D bir girdiye ihtiyac duyar (batch_size, height, width, channels).
# batch_size boyutunu daha sonra ekleyecegiz.
train_images = train_images[..., None]
test_images = test_images[..., None]

# Resimleri [0, 1] araligina indirgeyelim.
train_images = train_images / np.float32(255)
test_images = test_images / np.float32(255)

train_labels = train_labels.astype('int64')
test_labels = test_labels.astype('int64')

Degiskenleri ve grafigi dagitmak icin bir taktik olusturalim

tf.distribute.MirroredStrategy nasil calisir?

  • Butun degiskenler ve model grafigi birkac kere kopyalanir.
  • Girdi bu kopyalara esit olarak dagitilir.
  • Her kopya verilen girdiye gore bir kayip ve degisim tablosu hesaplar.
  • Butun degisim verileri toplanir ve kopyalardaki degerler bu toplama gore guncellenir.
  • Bu islemden sonra, ayni guncelleme degiskenlerin kopyalarina da uygulanir.

Note: Butun kodu tek bir kapsam icine koyabilirsiniz, fakat biz burada daha aciklayici olmasi icin kodu boluyoruz.


In [ ]:
# Eger kullanilacak cihazlar `tf.distribute.MirroredStrategy` yapicisinda belirtilmediyse
# otomatik olarak bulunacaktir.
strategy = tf.distribute.MirroredStrategy()

In [ ]:
print ('Number of devices: {}'.format(strategy.num_replicas_in_sync))

Girdi hattinin kurulmasi

Eger bir model birden fazla GPU'da egitiliyorsa, grup boyutu buna orantili olarak arttirilmalidir ki fazla bilgisayar gucunu verimli bir sekilde kullanabilelim. Ayrica, egitim hizi da orantili olarak ayarlanmaidir.


In [ ]:
BUFFER_SIZE = len(train_images)

BATCH_SIZE_PER_REPLICA = 64
BATCH_SIZE = BATCH_SIZE_PER_REPLICA * strategy.num_replicas_in_sync

EPOCHS = 10

strategy.make_dataset_iterator, veriyi kopyalara esit olarak dagitan bir iterator olusturur.

Note: Bu API yakin zamanda degisecektir.


In [ ]:
with strategy.scope():
  train_dataset = tf.data.Dataset.from_tensor_slices(
  (train_images, train_labels)).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
  train_iterator = strategy.make_dataset_iterator(train_dataset)

  test_dataset = tf.data.Dataset.from_tensor_slices(
      (test_images, test_labels)).batch(BATCH_SIZE)
  test_iterator = strategy.make_dataset_iterator(test_dataset)

Modelin olusturulmasi

tf.keras.Sequential ile modelimizi olusturalim. Model Subclassing API'yini da kullanarak bu islemi yapabiliriz.


In [ ]:
with strategy.scope():
  model = tf.keras.Sequential([
      tf.keras.layers.Conv2D(32, 3, activation='relu',
                             input_shape=(28, 28, 1)),
      tf.keras.layers.MaxPooling2D(),
      tf.keras.layers.Conv2D(64, 3, activation='relu'),
      tf.keras.layers.MaxPooling2D(),
      tf.keras.layers.Flatten(),
      tf.keras.layers.Dense(64, activation='relu'),
      tf.keras.layers.Dense(10, activation='softmax')
    ])
  optimizer = tf.train.GradientDescentOptimizer(0.001)

Kayip fonksiyonunu tanimlayalim

Normalde, eger 1 GPU/CPU'lu bir makine kullaniyorsak, kayip girdi grubundaki ornek sayisina bolunur.

Peki tf.distribute.Strategy ile kayip nasil hesaplanir?

Ornegin, 4 GPU'muz ve boyutu 64 olan girdimiz oldugunu varsayalim. Bu girdiler esit olarak 4 GPU (4 kopya) ustune bolunur, yani her kopyaya giden girdi grub boyutu 16 idir.

Her kopyadaki model icindeki girdinin ustunden gecerek kayip degerini hesaplar. Simdi, bu kayip degerini icindeki girdi sayisina (16) bolmek yerine, en bastaki evrensel girdi miktarina (64) boler.

Neden bu islem boyle yaplir?

Cunku degisim degerleri her kopyada hesaplandiktan sonra, butun kopyalardaki degerler butun degisim degerlerinin toplamina esitlenir.

Bunu TensorFlow'da nasil yapabiliriz?

Eger ozellestirilmis bir egitim dongusu yaziyorsaniz, her ornekteki kayiplari toplayip butun orneklerin toplamina bolmelisiniz:

GLOBAL_BATCH_SIZE:`scale_loss = tf.reduce_sum(loss) * (1. / GLOBAL_BATCH_SIZE)`
  • tf.reduce_mean metodunu kullanmanizi tavsiye etmiyoruz. Bu metod kayip degerini kopyalardaki ornek sayisina boler ki bu her adimda degisebilir.

  • Bu indirgeme ve olcekleme keras'ta otomatok olarak yapilir: model.fit ve model.compile ile

  • Eger tf.keras.losses siniflarini kullaniyorsaniz, kayip indirgemesinin ozellikle NONE ya da SUM olarak belirtilmesi gerekmektedir. AUTO ve SUM_OVER_BATCH_SIZE ise tf.distribute.Strategy ile birlikte kullanilamaz. Cunku kullanicilarin AUTO kullanmadan once yaptiklari indirgemenin o anki dagitim ornegindeki dogrulugundan emin olmalari gerekir. SUM_OVER_BATCH_SIZE kullanilamaz cunku su anki haliyle sadece kopyadaki ornek sayisina bolum yapip asil toplam ornek sayisina bolme islemini kullaniciya birakir, ki bu cok kolay gozden kacabilecek bir noktadir. Onun yerine kullanicinin indirgemeyi kendilerinin yapmalarini istiyoruz.

Egitim dongusu


In [ ]:
with strategy.scope():
  def train_step():
    def step_fn(inputs):
      images, labels = inputs
      logits = model(images)
      cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
          logits=logits, labels=labels)
      loss = tf.reduce_sum(cross_entropy) * (1.0 / BATCH_SIZE)
      train_op = optimizer.minimize(loss)
      with tf.control_dependencies([train_op]):
        return tf.identity(loss)

    per_replica_losses = strategy.experimental_run(
        step_fn, train_iterator)
    mean_loss = strategy.reduce(
        tf.distribute.ReduceOp.SUM, per_replica_losses, axis=None)
    return mean_loss

In [ ]:
with strategy.scope():
  iterator_init = train_iterator.initialize()
  var_init = tf.global_variables_initializer()
  loss = train_step()
  with tf.Session() as sess:
    sess.run([var_init])
    for epoch in range(EPOCHS):
      sess.run([iterator_init])
      for step in range(10000):
        if step % 1000 == 0:
          print('Epoch {} Step {} Loss {:.4f}'.format(epoch+1,
                                                      step,
                                                      sess.run(loss)))

Sirada ne var?

Simdi tf.distribute.Strategy API'yini kendi modellerinizde deneyin.