Mini yığınlara böl
Zorluk: Orta Çözüldü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:
rng = np.random.default_rng(seed)ile bir rastgele sayı üreteci kur.- Örneklerin sırasını
rng.permutation(n)ile belirle. - Bu sırayı ardışık
batch_size’lık parçalara böl.
örnek ve = batch_size ile mini-batch sayısı şudur:
, ‘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)vey(n,)shape’inde array’lerdir.batch_size,1ya da daha büyük birint’tir.seedbirint’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. o batch’teki örnek sayısıdır.- Sırayı
rng = np.random.default_rng(seed)verng.permutation(n)ile üret.np.random.seedile ya darng.choicegibi başka bir çağrıyla karıştırırsan sıra farklı çıkar. - Her örnek tam bir kez görünür.
Xiley’yi aynı sırayla karıştır:X_batch[j]iley_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 >= nise tek batch döndür.- Varsayılan
seed0’dır. Aynıseedher zaman aynı batch’leri verir. X’i vey’yi değiştirme. Karıştırmayı yerinde yapma, örneğinrng.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:
| Gradyan | Hesaplandığı örnekler | Doğruluk | Maliyet |
|---|---|---|---|
| Tam gradyan | Tüm örnekler | Doğru | Pahalı |
| Mini-batch gradyanı | Küçük bir grup | Ona 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:
- Sırayı bir kez karıştır.
batch_size’lık slice’larla ilerle.Xvey’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?