Projeler · Proje 1
Otonom araç: pisti kendi kendine öğrenen sürücü
Beş mesafe sensörü, küçük bir sinir ağı ve nöroevrim
Senaryo. Bir robot yarışı için kapalı bir pist: yaklaşık 22 metreye 13 metrelik dalgalı bir halka (bir tur 57 metre), yol 1,3 metre genişliğinde. Her aracın önünde beş mesafe sensörü var (LiDAR’ın en basit hâli); yol kenarına olan uzaklığı ölçerler. Kimse araca nasıl direksiyon kıracağını göstermez; elimizde yalnızca bir ölçüt var: pistte ne kadar ilerledi.
Amaç. Bir aracın pisti yoldan çıkmadan iki tam tur dönmesi.
3B sahne yükleniyor…
Eğitim paneli
Eğitim çalıştırılıyor…
Model bu sayfada, tarayıcında sıfırdan eğitilir (sabit tohum: aynı ayarlarla her seferinde aynı sonuç). Eğitim her karede küçük parçalar hâlinde yapılır; sekme ya da sahne görünmezken durur.
Adımlar
- Sensörler: her karede beş ışın −60°, −30°, 0°, 30° ve 60° yönünde yol kenarına kadar uzatılır; uzaklık 5 metreye bölünür. Altıncı girdi aracın hızıdır.
- Ağ: altı sayı gizli katmandan geçer, iki sayı çıkar: direksiyon (−1 sol, +1 sağ) ve gaz (hız 1 ile 4 m/s arası).
- Nesil: 30 araç aynı anda başlar. Yoldan çıkan, geri giden ya da 3 saniye ilerleyemeyen araç elenir. Herkes elenince ya da 60 saniye dolunca nesil biter.
- Uygunluk: aracın orta çizgi boyunca ulaştığı en uzak nokta (metre). Sıralamada en iyi iki araç olduğu gibi kalır.
- Yeni nesil: geri kalan 28 araç, iyi araçlardan birinin kopyasıdır; her ağırlık %30 olasılıkla “mutasyon” kadar gauss gürültüsü alır. Kötü bozulmalar elenir, iyiler kalır.
Model
Her aracın beyni 6 → 6 → 2 nöronlu bir sinir ağı (sinir ağı dersindeki ağın aynısı, tanh eğrileriyle). Ağırlıklar gradyan inişiyle değil nöroevrimle öğrenilir: en iyi araçlar kopyalanır, kopyaların ağırlıklarına küçük gauss gürültüsü eklenir. Doğru cevap olmadığı için geri yayılım kullanılamaz; ödül yalnızca nesil sonunda gelir (Q-öğrenme dersindeki gibi).
Kullanılan dersler: Küçük bir sinir ağı · Aktivasyon fonksiyonları · Q-öğrenme: şarj istasyonunu bulan robot
Kendin dene
- Mutasyonu 0 yap ve eğit. Kopyalar asıllarının aynısı olur, evrim durur: rekor ilk nesilde ne ise orada kalır ve hiçbir araç tur atamaz.
- Popülasyonu 30’dan 10’a indir. Varsayılan tohumla ilk tam tur 6. nesil yerine 16. nesilde gelir; 6 araçla 80 nesilde bile gelmez. Az araç, her nesilde az deneme demektir.
- Gizli nöronu 6’dan 2’ye indir: ilk tam tur 16. nesle kalır. 12 yap: 4. nesilde gelir. Sonra tohumu değiştir; ilk 20 tohumun hepsinde 10 nesil içinde bir araç iki tur atar.
Python karşılığı
import numpy as npC = np.genfromtxt('pist-orta-cizgi.csv', delimiter=',', skip_header=1) # orta çizgi: 300 nokta (x, z), mn, YARI, H = len(C), 0.65, 0.1 # yol yarı genişliği, ızgara hücresi (m)xs = np.arange(C[:, 0].min() - 1, C[:, 0].max() + 1, H)zs = np.arange(C[:, 1].min() - 1, C[:, 1].max() + 1, H)IDX = np.full((len(zs), len(xs)), -1) # hücre başına en yakın orta çizgi noktası, yol dışı −1for i, z in enumerate(zs):d = (xs[:, None] - C[:, 0]) ** 2 + (z - C[:, 1]) ** 2j = d.argmin(1)IDX[i] = np.where(d[np.arange(len(xs)), j] < YARI ** 2, j, -1)def hucre(x, z): # konumların hücre değeri (yol mu, nerede)c, r = ((x - xs[0]) / H).astype(int), ((z - zs[0]) / H).astype(int)ok = (c >= 0) & (r >= 0) & (c < len(xs)) & (r < len(zs))out = np.full(x.shape, -1)out[ok] = IDX[r[ok], c[ok]]return outACILAR = np.radians([-60, -30, 0, 30, 60]) # beş mesafe sensörüdef isinlar(x, z, h): # bütün araçların ışınları birliktea = h[:, None] + ACILARd, acik = np.full(a.shape, 5.0), np.ones(a.shape, bool)for s in np.arange(0.25, 5.01, 0.25): # 25 cm adımlarla ilerleyol = hucre(x[:, None] + np.cos(a) * s, z[:, None] + np.sin(a) * s) >= 0d[acik & ~yol] = s - 0.125 # ilk yol dışı nokta: kenara uzaklıkacik &= yolreturn dN, rng = 30, np.random.default_rng(1) # 30 araçW1, b1 = rng.normal(0, 6 ** -.5, (N, 6, 6)), np.zeros((N, 6)) # her aracın ağı: 6 → 6 → 2W2, b2 = rng.normal(0, 6 ** -.5, (N, 6, 2)), np.zeros((N, 2))def sur(W1, b1, W2, b2, dt=0.05): # bir nesil: hepsi aynı anda sürerx, z = np.full(N, C[0, 0]), np.full(N, C[0, 1])h, v = np.full(N, np.arctan2(C[1, 1] - C[0, 1], C[1, 0] - C[0, 0])), np.ones(N)son, ilerleme, en_iyi, canli = np.zeros(N, int), np.zeros(N), np.zeros(N), np.ones(N, bool)for t in range(600): # en fazla 30 saniyeg = np.c_[isinlar(x, z, h) / 5, v / 4] # girdiler: 5 ışın, hızo = np.tanh(np.einsum('nj,njk->nk', np.tanh(np.einsum('ni,nij->nj', g, W1) + b1), W2) + b2) # direksiyon, gazv = np.where(canli, v + (2.5 + 1.5 * o[:, 1] - v) * 0.15, 0) # hız 1–4 m/sh += 2.5 * o[:, 0] * dtx, z = x + np.cos(h) * v * dt, z + np.sin(h) * v * dtk = hucre(x, z)canli &= k >= 0 # yoldan çıkan eleniradim = (k - son + n // 2) % n - n // 2 # orta çizgide kaç nokta ilerlediilerleme = np.where(canli, ilerleme + adim, ilerleme); son = np.where(canli, k, son)canli &= ilerleme > en_iyi - 10 # geri giden de eleniren_iyi = np.maximum(en_iyi, ilerleme)if not canli.any(): breakreturn en_iyi / n # uygunluk: tur cinsinden en uzak noktahistory = {'generation': [], 'best': [], 'mean': [], 'median': []} # eğitim geçmişi: nesil başına uygunluk (tur)for nesil in range(1, 13):puan = sur(W1, b1, W2, b2)sira = np.argsort(-puan)for k, v in zip(history, (nesil, puan.max(), puan.mean(), np.median(puan))): history[k].append(v if isinstance(v, int) else float(v))print(f"nesil {nesil:2d}: en iyi {puan.max():.2f} tur, ortalama {puan.mean():.2f}")if puan.max() >= 1: print("bir araç tam tur attı"); breakeb = np.r_[sira[:2], sira[(rng.random(N - 2) ** 2 * 12).astype(int)]] # en iyi iki aynen, kalanlar iyilerin kopyasıW1, b1, W2, b2 = [w[eb] + rng.normal(0, .3, w[eb].shape) * (rng.random(w[eb].shape) < .3) * (np.arange(N) >= 2).reshape(-1, *[1] * (w.ndim - 1)) for w in (W1, b1, W2, b2)] # mutasyon (ilk ikiye dokunma)for k in history: print(f'{k:<12}{history[k][-1]:>10.3f}') # son ölçümler tablosuimport csvwith open('egitim_gecmisi.csv', 'w', newline='') as f: # geçmişi CSV'ye yazcsv.writer(f).writerows([list(history), *zip(*history.values())]) # satır başına bir nesiltry:import matplotlib.pyplot as plt # varsa grafik çizfor k in ('best', 'mean', 'median'): plt.plot(history['generation'], history[k], label=k)plt.xlabel('generation'); plt.ylabel('laps'); plt.legend(); plt.show()except ImportError:print('matplotlib yok: grafik atlandı')
Veri seti
Tüm veri setleri →- Yarış pisti: orta çizgiVeri setini indir
- Sürücü sensör kayıtlarıalıştırmaVeri setini indir
Kodu tarayıcıda çalıştırPython · NumPy · matplotlib · Pyodide
Python ve NumPy bu sayfada, tarayıcında çalışır (Pyodide). Kodu değiştirip yeniden çalıştırabilirsin; dersin veri setleri çalışma klasöründe hazır. Kod matplotlib kullanırsa grafikler çıktının altında görünür, yazdığı dosyalar (ör. egitim_gecmisi.csv) indirilebilir.
Çıktı
Çıktı burada görünecek.