Sıradaki

Mini yığınlara böl

Zorluk: Orta

veri işleme

Bu problemde veriyi mini yığınlara (mini-batch) bölen bir fonksiyon yazarsın. Büyük bir veri kümesinde (dataset) gradyanı her adımda tüm örneklerden hesaplamak yavaştır. Bunun yerine veriyi mini-batch denen küçük gruplara bölersin ve her adımda yalnızca bir grup kullanırsın.

Bu yönteme stokastik gradyan inişi (stochastic gradient descent, SGD) denir. Grupların rastgele seçilmiş örneklerden oluşması için örnekleri önce karıştırırsın.

minibatches(X, y, batch_size, seed=0) fonksiyonunu yaz. Girdiler şunlardır:

  • X: şekli (shape) (n, d) olan bir dizi (array). Her satır bir örnek (sample) içerir.
  • y: hedef değerleri (target) tutan, (n,) shape’inde bir vektör. y[i], X[i]’nin target’ıdır.
  • batch_size: her mini-batch’teki örnek sayısı.
  • seed: karıştırmanın tohumu (seed).

Fonksiyon şu adımlarla çalışır:

  1. rng = np.random.default_rng(seed) ile bir rastgele sayı üreteci kur.
  2. Örneklerin sırasını rng.permutation(n) ile belirle.
  3. Bu sırayı ardışık batch_size’lık parçalara böl.

NN örnek ve BB = batch_size ile mini-batch sayısı şudur:

⌈NB⌉\left\lceil \frac{N}{B} \right\rceil

NN, BB‘ye bölünmüyorsa son batch daha küçük olur. Onu atma. Her mini-batch, karıştırılmış sıradaki bir parçanın (X_batch, y_batch) çiftidir.

Bütün çiftleri bir tuple olarak döndür. Sonucu for X_batch, y_batch in minibatches(X, y, 4): ile gezebilirsin.

Örnekler

Girdi: X = [[0.0, 0.0], [1.0, 1.0], [2.0, 4.0], [3.0, 9.0], [4.0, 16.0], [5.0, 25.0], [6.0, 36.0], [7.0, 49.0], [8.0, 64.0], [9.0, 81.0]], y = [0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0], batch_size = 4, seed = 0
Çıktı: ((array([[ 4., 16.], [ 6., 36.], [ 2., 4.], [ 7., 49.]]), array([40., 60., 20., 70.])), (array([[ 3., 9.], [ 5., 25.], [ 9., 81.], [ 0., 0.]]), array([30., 50., 90., 0.])), (array([[ 8., 64.], [ 1., 1.]]), array([80., 10.])))

Girdi: X = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], y = [10.0, 20.0, 30.0], batch_size = 8, seed = 0
Çıktı: ((array([[5., 6.], [1., 2.], [3., 4.]]), array([30., 10., 20.])),)

Girdi: X = [[-3.0, 1.5], [-2.0, 0.5], [-1.0, -0.5], [0.0, 2.0], [1.0, -1.5], [2.0, 0.25], [3.0, -2.0]], y = [-1.5, 0.5, 2.0, -3.0, 4.0, 0.0, 1.0], batch_size = 2, seed = 42
Çıktı: ((array([[ 0. , 2. ], [-1. , -0.5]]), array([-3., 2.])), (array([[ 3. , -2. ], [ 1. , -1.5]]), array([1., 4.])), (array([[-2. , 0.5 ], [ 2. , 0.25]]), array([0.5, 0. ])), (array([[-3. , 1.5]]), array([-1.5])))

İpucu 1

Verinin kendisini değil, örnek numaralarını karıştır. rng.permutation(n), 0’dan n - 1’e kadar sayıların rastgele bir sırasını verir. Aynı numaralarla hem X’ten hem y’den eleman seçersen her örnek kendi target’ıyla birlikte kalır.

İpucu 2

range(0, n, batch_size) her batch’in başlangıç noktasını verir. Karıştırılmış numaralardan order[start:start + batch_size] ile bir parça al. X ile y’yi bu parçayla indeksle.

İpucu 3

Bir dilim (slice) array’in sonunu aşarsa NumPy hata vermez. Kalan elemanları verir. Bu yüzden aynı döngü hem tam batch’leri hem küçük son batch’i üretir.

Gereksinimler

  • X (n, d) ve y (n,) shape’inde array’lerdir. batch_size, 1 ya da daha büyük bir int’tir. seed bir int’tir.
  • (X_batch, y_batch) çiftlerinden oluşan bir tuple döndür, liste ya da generator değil. X_batch (b, d), y_batch (b,) shape’inde NumPy array’leridir. bb o batch’teki örnek sayısıdır.
  • Sırayı rng = np.random.default_rng(seed) ve rng.permutation(n) ile üret. np.random.seed ile ya da rng.choice gibi başka bir çağrıyla karıştırırsan sıra farklı çıkar.
  • Her örnek tam bir kez görünür.
  • X ile y’yi aynı sırayla karıştır: X_batch[j] ile y_batch[j] aynı örneğe ait olmalı.
  • n, batch_size’a bölünmüyorsa son batch daha küçüktür. Onu atma ve boş bir batch ekleme. batch_size >= n ise tek batch döndür.
  • Varsayılan seed 0’dır. Aynı seed her zaman aynı batch’leri verir.
  • X’i ve y’yi değiştirme. Karıştırmayı yerinde yapma, örneğin rng.shuffle(X) ile.

Mini-batch gradyanı, tam gradyanın ucuz ve gürültülü bir yaklaşık değeridir. İki gradyanı karşılaştır:

GradyanHesaplandığı örneklerDoğrulukMaliyet
Tam gradyanTüm örneklerDoğruPahalı
Mini-batch gradyanıKüçük bir grupOna yakın, gürültülüUcuz

Çok sayıda ucuz adım, az sayıda pahalı adımdan çoğu zaman daha hızlı ilerler. Gürültü rastgele örneklemeden geldiği için yönteme stokastik denir.

Karıştırmak önemlidir. Veri target’a ya da sınıfa göre sıralıysa, karıştırmadan alınan her batch tek yana eğilimli olur. Gradyan her adımda aynı yöne çeker.

Eğitimde bütün mini-batch’ler birer kez kullanılınca bir epoch (dataset’in tamamı üzerinden bir tur) biter. Her epoch’ta yeniden karıştırmak için seed + epoch gibi bir seed kullanabilirsin.

Sabit bir seed, aynı kodun aynı sonucu vermesini sağlar. Hata ararken buna ihtiyacın olur.

Bu problemde batch’leri bir tuple’da toplarsın. for döngüsünde kullanımı aynıdır. Büyük dataset’lerde batch’leri yield ile tek tek üretmek, hepsini aynı anda bellekte tutmaktan daha ucuzdur.

Daha fazlası için Ölçekleme, mini-batch ve kapalı form dersine bak.

Çözüm üç adımdır:

  1. Sırayı bir kez karıştır.
  2. batch_size’lık slice’larla ilerle.
  3. X ve y’yi aynı numaralarla seç.

Kodda bu adımlar şöyle görünür:

import numpy as npdef minibatches(    X: np.ndarray, y: np.ndarray, batch_size: int, seed: int = 0) -> tuple[tuple[np.ndarray, np.ndarray], ...]:    n = X.shape[0]    rng = np.random.default_rng(seed)    order = rng.permutation(n)    batches = []    for start in range(0, n, batch_size):        idx = order[start : start + batch_size]        batches.append((X[idx], y[idx]))    return tuple(batches)

Sık yapılan hata, X’i ve y’yi aynı rng ile ayrı ayrı karıştırmaktır. İkinci çağrı üretecin kaldığı yerden devam eder ve farklı bir sıra verir. Bu yüzden satırlar yanlış target’larla eşleşir.

Bir başka hata, döngüyü n - batch_size’da kesip son küçük batch’i atmaktır.

Bu problemde bir sorun mu var?

solution.py
import numpy as npdef minibatches(    X: np.ndarray, y: np.ndarray, batch_size: int, seed: int = 0) -> tuple[tuple[np.ndarray, np.ndarray], ...]:    """Örnekleri sabit tohumla karıştırıp (X_batch, y_batch) çiftlerinden oluşan bir tuple döndürür."""    rng = np.random.default_rng(seed)    # Kodunu buraya yaz.    return ()

İçindekiler

Geri bildirim

Tür