Holografik Bellek, Uyuyan Modeller ve Gradyansız Öğrenme: Ev Bilgisayarında Yedi Deney

Holografik Bellek, Uyuyan Modeller ve Gradyansız Öğrenme: Ev Bilgisayarında Yedi Deney

33 dakika okuma

Özet. Bu yazıda, evimdeki bilgisayarda tek bir günde tasarlayıp koştuğum yedi yapay zeka deneyini bir araştırma raporu düzeninde anlatıyorum. Deneyler, bugünkü yapay zekanın el kitabına yazılmamış üç soruyu kurcalıyor: bilgi bir donanıma değil de bir geometriye yazılabilir mi, bir model uyuyarak unutmayı yenebilir mi, ve öğrenme gradyanın geri akışı olmadan mümkün mü? Sonuçların bir kısmı beklediğimden güçlü çıktı: 40 KB'lık tek bir vektöre yüzlerce bilgi üst üste yazılıp tek tek geri okunabiliyor, geceleri rüya gören bir sinir ağı klasik ikizinin beş günde tamamen unuttuğu bilgiyi yüzde 98 ile koruyor, ve hiç geri geçiş yapmayan bir ağ Türkçe cümleleri backprop'lu rakibine yakın doğrulukla sınıflandırıyor. Bir kısmı ise duvara çarptı ve bu rapor o duvarları da saklamadan veriyor: iki bağımsız deney, birbirinden habersiz biçimde aynı darboğazı işaret etti. Üretilen deneyimin (rüyanın) gerçeğin dağılımına sadakati, bu deney ailesinde tekrar eden baskın başarısızlık modu oldu. Tüm deneyler GPU'suz, sıradan bir dizüstünde, dakikalar içinde koşuyor.

1. Giriş

Yapay zeka çağının garip bir çelişkisi var. Bir yanda insanlık tarihinin en güçlü öğrenen sistemleri, öbür yanda bu sistemlere ancak dev veri merkezleri üzerinden dokunabilen insanlar. Modeller büyüdükçe donanım isteği büyüyor, donanım isteği büyüdükçe araştırma birkaç şirketin çatısı altında toplanıyor. Peki bu zorunlu mu?

Kafamın içinde dönen soru şuydu: ya mimariyi yanlış kurduysak? Termodinamikten ya da matematiğin gerçekliğinden bahsetmiyorum; mühendislik tercihlerinden bahsediyorum. Kanıt ortada duruyor çünkü: kafatasımızın içindeki organ, bir ampulün harcadığı enerjiyle bu cümleyi anlıyor. Beyinde ayrı bir bellek ve ayrı bir işlemci yok, her şey aynı dokuda. Beyin gradyanları geriye doğru taşımıyor, çünkü bunu yapacak simetrik kablolara sahip değil. Demek ki bugün "zorunlu" saydığımız şeylerin en azından bir kısmı zorunlu değil; sadece eldeki donanıma en iyi uyan yol.

Sara Hooker bu duruma "donanım piyangosu" diyor: bir araştırma fikri en iyi fikir olduğu için değil, mevcut donanıma uyduğu için kazanır. Sinir ağları da 30 yıl bu piyangoyu kaybettikten sonra GPU'larla kazandı. Bugün ise tersine dönmüş durumda: GPU'ya uymayan fikirler daha denenmeden eleniyor.

Bu yazıdaki deneylerin amacı iddialı bir keşif değil. Amaç, paradigmanın kenarında duran ve yeterince kurcalanmayan fikirlerin ev donanımıyla, sıfırdan yazılmış kodla test edilebileceğini göstermek. Yani bir sonuç raporu olduğu kadar bir davet: bu işi denemek için kimseden izin almanız gerekmiyor.

2. Yöntem

Tüm deneyler MacBook Pro üzerinde, yalnızca CPU kullanılarak koşuldu. Kod tabanı Python ve NumPy'den ibaret; PyTorch, TensorFlow veya herhangi bir hazır yapay zeka çatısı kullanılmadı. Geri yayılım (backpropagation) dahil her algoritma sıfırdan, elle yazıldı. Böylece hiçbir sonuç bir kütüphanenin kara kutusuna borçlu değil.

Yedi deney, yedi bağımsız betik halinde. Her deney sabit rastgele tohumla tekrarlanabilir; test kümeleri küçük olduğu için koşudan koşuya birkaç puanlık oynama normaldir. Raporlama ilkem şu: başarısız denemeler ve yanlış çıkan ilk tasarımlar da rapora girer, çünkü bu deneylerin en öğretici sonuçları tam oralardan çıktı.

3. Deneyler

3.1 Kutunun içi dışından büyük

İlk deney bir ısınma turu: n boyutlu bir uzaya kaç tane "neredeyse dik" yön sığar? Her boyutta 2000 rastgele yön atıp aralarındaki açıları ölçtüm (eşik: kosinüs 0.20).

Boyut Sığan yön Rastgele iki yönün tipik açısı
3 3 60,0°
10 8 75,0°
100 106 85,4°
1.000 2.000 (denenen adayların tamamı) 88,6°
10.000 2.000 (denenen adayların tamamı) 89,5°

Üç boyutta birbirine dik ancak üç yön durabiliyor. On bin boyutta ise attığım her yön diğerlerine kendiliğinden dik geliyor. Tavan konusunda dürüst olayım: tek bir çiftin çakışma olasılığından türetilen kaba hesap 10 üzeri 86 gibi bir sayı verir, ama N yönün tüm çiftlerinin aynı anda uyumlu olması istendiğinde (birthday düzeltmesi) bu tahmin 10 üzeri 43 mertebesine iner; kesin paketleme problemi bundan da inceliklidir. Sağlam olan sonuç sayının kendisi değil, büyüme biçimi: sığan yön sayısı boyutla üstel artıyor ve her makul hesapta astronomik kalıyor. Dışarıdan 10.000 sayılık mütevazı bir kutu, içeriden pratikte tükenmeyen bir yön deposu. Bu geometri, modern dil modellerinin birkaç bin sayılık embedding vektörlerinin neden bu kadar ifade gücü taşıyabildiğine dair sezginin bir parçası; transformer temsilleri elbette bundan ibaret değil, bağlama göre dönüşen ve katmanlar boyunca yeniden hesaplanan çok daha zengin yapılar.

3.2 Üst üste yazılan bellek

İkinci deney bu geometriyi belleğe çeviriyor. Tek bir 10.000 boyutlu vektör (yaklaşık 40 KB) alıp içine anahtar-değer çiftlerini kelimenin tam anlamıyla üst üste yazdım; yöntem literatürde hyperdimensional computing olarak geçiyor. Sonra her bilgiyi tek tek geri çıkarmayı denedim.

Yazılan çift Geri okuma başarısı
200 %100,0
300 %99,3
500 %87,2
800 %63,1
2.000 %17,4

Üç yüz bilgi çifti, birbirinin üstüne yazıldığı halde neredeyse kusursuz geri okunuyor. Daha önemlisi bozulmanın karakteri: sistem hiçbir noktada "bellek doldu" demiyor. Klasik bir disk gibi duvara çarpmıyor, bir hologram gibi yavaşça flulaşıyor.

Bir muhasebe notu: 40 KB, üst üste yazılan durum vektörünün boyutu. Geri çağırmada kullanılan anahtar vektörleri ve aday değer sözlüğü, megabaytlar mertebesinde sabit altyapı olarak ayrıca duruyor. Yani doğru iddia "belleğin tamamı 40 KB" değil, "öğrenilen dinamik bellek durumu 40 KB". Bu ayrım yazının geri kalanındaki tüm boyut rakamları için de geçerli.

3.3 Hologram testi

Hologramı ikiye keserseniz yarım görüntü kalmaz; tamamının flu bir hali kalır, çünkü bilgi belirli bir yere değil her yere birden yazılmıştır. Üçüncü deney bu özelliği ölçüyor: 60 bilgi yazılmış vektörün bileşenlerini parça parça sıfırladım.

Silinen Hatırlanan
%50 %100,0
%75 %100,0
%90 %95,0
%95 %68,3
%99 %18,3

Belleğin yüzde 75'i yok edildiğinde kayıp sıfır. Yüzde 90'ı silinmişken "Türkiye'nin başkenti?" sorusuna hala "Ankara" diyor. Klasik bir diskte sektörlerin yarısını silmek dosyaların yarısını götürür; burada hiçbir bilgi belirli bir hücrede yaşamadığı için bütün, flulaşarak hayatta kalıyor. Dağıtık temsil, beynin hasara dayanıklılığı için önerilen mekanizmalardan biri; buradaki düzenek o fikrin basit bir gösterimi, kanıtı değil.

3.4 Gradyansız ilk model: dil tanıma

Dördüncü deney, bu belleği öğrenen bir modele çeviriyor. Altı dilde (Türkçe, İngilizce, Almanca, Fransızca, İspanyolca, İtalyanca) kısa metinlerin harf üçlüsü istatistiklerini, dil başına tek bir vektöre süperpozisyonla yazdım. Eğitim, verinin üzerinden tek bir geçiş: gradyan yok, epoch yok, GPU yok.

Sonuç: eğitim 0,04 saniye sürdü, modelin tamamı 234 KB, ve model eğitimde hiç görmediği 24 test cümlesinin 24'ünü de doğru dille eşleştirdi. İçinde tek bir sinir ağı katmanı olmayan, saniyenin yüzde dördünde eğitilmiş, çalışan bir model.

3.5 Uyuyan model: unutmanın tedavisi

Beşinci deney serinin kalbi. Hedef, sinir ağlarının 30 yıllık kronik hastalığı olan catastrophic forgetting: bir ağa önce A'yı sonra B'yi öğretirseniz, B'yi öğrenirken A'yı siler. Nörobilimin bu soruna dair güzel bir teorisi var (complementary learning systems): beyinde hipokampus anında yazar, korteks yavaş öğrenir, ve uykuda hipokampus gün içinde yazdıklarını kortekse tekrar oynatır. Rüyanın işlevlerinden birinin bu olduğu düşünülüyor.

Deney düzeni: 5 günlük bir veri akışı, her gün 10 yeni konu, her akşam o güne kadarki tüm konulardan sınav. Üç öğrenci yarışıyor:

  • A (klasik): elle yazılmış, backprop'lu sinir ağı. Sadece günün verisini görüyor.
  • B (holografik): deney 2'nin tek vektörlük belleği. Eğitim yok, anında yazma.
  • C (hibrit): A ile birebir aynı ağ ve birebir aynı gündüz eğitimi. Tek fark: geceleri, 156 KB'lık holografik hipokampusundan ürettiği rüyalarla eski konuları tekrar ediyor.
Öğrenci 1. gün bilgisinin 5. gündeki hali 50 konunun genel ortalaması
A (klasik) %0,0 %20,0
B (holografik) %100,0 %100,0
C (hibrit, uykulu) %98,2 %98,4

A, her yeni günle eskiyi ezdi; beş günün sonunda yalnızca son günü biliyor. C ise A ile aynı ağ olmasına rağmen neredeyse hiçbir şey unutmadı. Aradaki tek değişken uyku. Ham veri 191 MB tutuyordu ve kimse onu saklamadı; 156 KB'lik öğrenilen bellek durumu, unutmayı bu düzenekte büyük ölçüde önledi. (Muhasebe yine dürüst: 156 KB dinamik durum vektörüdür; rüya üretiminde kullanılan sabit projeksiyon matrisi ve sınıf anahtarları, öğrenilmeyen mimari altyapı olarak megabaytlar mertebesindedir.)

Bir ayrıntı, deneyin en sevdiğim anı: ilk tasarımda rüyaları kodlama uzayında rastgele gürültüyle üretmiştim ve sistem çöktü. Rüyalar ancak "yeniden yaşanan deneyim" gibi (anıyı girdi uzayına geri çözüp, gerçekçi gürültüyle yeniden yaşayıp yeniden kodlayarak) üretildiğinde çalıştı. Rüyanın rastgele statik değil de üretilmiş deneyim olması, görünüşe göre bir zorunluluk.

3.6 Gerçek veri sınavı ve ilk duvar

Altıncı deneyde aynı mimariyi oyuncak veriden çıkarıp gerçek el yazısı rakamlara (MNIST) taşıdım. Tablo kısmen aynı kaldı: klasik ağ yine çöktü (%19), uykulu hibrit erken günleri yine korudu. Ama genel toplamda hibrit %49'da, holografik bellek %63'te kaldı; tüm veriyi aynı anda gören "hileli" referans ağ ise %91 aldı.

Aradaki boşluğun sebebini deney kendisi gösterdi: terminalde, 391 KB'lık durum vektörünün içinden geri çözülen bir "3" rüyası duruyor (geri çözümde kullanılan sabit projeksiyon matrisi ise yaklaşık 157 MB; rüya 391 KB'den doğuyor ama mekanizmanın tamamı o kadar küçük değil). Rüya tanınabilir, ama flu. Ve o fluluk, 4 ile 9'u, 3 ile 5'i ayıran ince detayları taşımıyor. Bu düzenekte baskın darboğaz unutma değil, rüya sadakati çıktı: durum vektörünün kapasitesi ile anı sadakati arasında sert bir takas var ve literatürdeki generative replay araştırmaları da tam bu duvarda uğraşıyor. Ev bilgisayarında bir günde, alanın gerçek açık problemlerinden birine varmış olduk.

3.7 Backprop'suz öğrenme: dört perde

Yedinci deney en temel varsayıma saldırıyor: "öğrenme = geri yayılım" denklemine. Geoffrey Hinton'ın 2022'de önerdiği Forward-Forward algoritmasında ağ boyunca geri geçiş yok; her katman, gerçek veride "iyilik" puanını yükseltip sahte veride düşürerek kendi başına öğreniyor. Bir terim notu: başlıktaki "gradyansız" ifadesiyle ağ boyunca geriye taşınan gradyanın yokluğunu kastediyorum; FF katmanı kendi yerel hedefinin türevini kullanmaya devam ediyor, yani teknik olarak kesin terim "gradyansız" değil "backprop'suz". Bunu Türkçe cümlelerle test ettim: altı konuda (spor, ekonomi, sağlık, teknoloji, yemek, doğa) konu sınıflandırma.

Perde 1, yarış: Aynı mimaride backprop test doğruluğu %94,4, Forward-Forward %88,9. FF kaybetti ama az farkla, ve geri geçiş olmadan. (Test kümesi 36 cümle; her cümle yaklaşık 2,8 puana denk geliyor, yani aradaki fark iki cümle. Bu sayılara istatistiksel anlam yüklemiyorum; gözlem "aynı ligde oynuyorlar" seviyesinde.)

Perde 2, sabotaj: Katmanların arasına türevi olmayan bir işlem (kara kutu) koydum. Backprop %91,7'den %16,7'ye düştü; ölçümü de net, ilk katmana ulaşan gradyan tam olarak sıfır. Forward-Forward %88,9'dan %77,8'e geriledi, yani kara kutuyu neredeyse umursamadı. Burada gösterilen şey, standart zincir kuralının türevi bilinmeyen işlemden geçememesi; literatürde straight-through estimator gibi yaklaşık çözümler var ve bu deneyde bilinçli olarak kapsam dışı bırakıldı. Yine de yerel öğrenmenin bu senaryoda hiçbir yamaya ihtiyaç duymaması, kusurlu ve analog donanımda öğrenme açısından önemli bir işaret.

Perde 3, kopukluk: FF katmanları sırayla, birbirinden habersiz eğitildi; ikinci katman başladığında birincisi çoktan emekliye ayrılmıştı ve ona tek bir bayt geri dönmedi. Eğitimin senkron, tek parça bir canavar olması gerekmiyor; katmanlar ilkece ayrı makinelere dağıtılabilir.

Perde 4, dürüst başarısızlık: Deney 5'in rüya belleğini FF'e bağlamayı denedim: ağ gerçek cümleyi hiç görmeden, sadece holografik rüyalarla öğrensin istedim. Sonuç: rüya sınavında %97,2, gerçek testte %13,9. İşin çarpıcı yanı, sinyalin bellekte mevcut olması; öğrenmesiz bir "en yakın rüya yönü" sınıflandırıcısı aynı gerçek testte %86,1 alıyor. Yani FF öğrenebileceği doğru özelliği bulamıyor; pozitifle negatifi ayıran en kolay özelliği seçiyor ve o özellik rüya üretiminin bir yan izi olunca öğrendiği şey gerçeğe taşınmıyor. Üç farklı rüya üretim yöntemi denedim, üçünde de aynı duvar.

4. Bulgular

Yedi deneyin toplamından üç ders çıkarıyorum.

Bilgi, kaba değil geometriye sığıyor. Yüksek boyutlu uzaylar kelimenin matematiksel anlamıyla içi dışından büyük, ve bu genişlik gerçek bir bellek olarak kullanılabiliyor: kademeli dolan, hasara dayanıklı, tek geçişte yazılan bir bellek. Yapay zekayı küçük donanıma sığdırma savaşının matematiksel özü bu gözlem.

Unutma bu düzeneklerde çözülebilir çıktı; baskın darboğaz rüya sadakati oldu. Uyku mekanizması sentetik veride unutmayı büyük ölçüde önledi. Gerçek veride ise sınır, üretilen deneyimin gerçeğin dağılımına ne kadar benzediği çıktı ve bu darboğaz iki bağımsız deneyde, iki farklı kılıkta tekrarladı. Dikkatli olayım: üç deneyin aynı mekanizmayı kesin teşhis ettiğini söylemek için dağılım mesafesi ölçümleri, ablation ve kontrollü müdahaleler gerekir. Şimdilik savunabildiğim ifade şu: bu deney ailesinin tekrar eden baskın başarısızlık modu, üretilen verinin gerçeğe sadakatsizliği.

Yerel öğrenme çalışıyor, ama öğrenici tembel. Forward-Forward, geri yayılımın veri merkezi zorunluluklarını (senkron katmanlar, kusursuz türevlenebilirlik) gerçekten kırıyor. Fakat kendi zaafı var: pozitifle negatifi ayıran en ucuz kestirmeyi seçiyor. Negatif verinin tasarımı, öğretilmek istenen kavramın kendisi kadar önemli.

5. Açık problemler

Bu raporda çözülmemiş iki problem açık şekilde kayda geçti. Birincisi rüya sadakati: eğitimsiz, tek vektörlük bir bellekten, ince ayrımları koruyacak kadar sadık deneyimler nasıl üretilir? İkincisi transfer: Forward-Forward'a, üretilmiş veriyle öğrendiğini gerçek veriye taşıması nasıl öğretilir? İkisi de ev donanımında kurcalanabilir durumda ve ikisinin de üstünde çalışmaya devam edeceğim.

6. Sonuç

Bu deneylerin hiçbiri dünyayı değiştirmiyor; bunu en baştan söylemiştim. Katkı iddiamı da net koyayım: burada yeni bir algoritma icat edilmedi. Hyperdimensional computing yerleşik bir alan, complementary learning systems onlarca yıllık bir teori, Forward-Forward Hinton'ın önerisi. Bu yazının yaptığı şey, ayrı literatürlerde yaşayan bu fikirleri aynı soruya doğru art arda çarpıştırmak ve birleşim noktalarında ortaya çıkan başarısızlık kiplerini kayda geçirmek. Değiştirdiği şey ise daha kişisel: yapay zeka araştırmasının veri merkezi olan kurumların tekelinde olmadığını kendi gözümle görmüş oldum. Yedi deneyin tamamı sıfırdan yazılmış, kütüphanesiz kodla, GPU'suz bir dizüstünde, dakikalar içinde koşuyor. Paradigmanın kenarındaki sorular (bellek başka türlü kurulabilir mi, öğrenme gradyansız olur mu, model uyuyabilir mi) laboratuvar değil, merak istiyor.

Yedi deneyin tam kaynak kodu yazının sonundaki ekte. Kopyalayıp kendi makinenizde koşturabilir, sabitleri değiştirip kendi sorularınızı sorabilirsiniz. Sorularınız olursa iletişim sayfasından yazabilirsiniz.

Kaynakça

  • Hinton, G. (2022). The Forward-Forward Algorithm: Some Preliminary Investigations.
  • Hooker, S. (2020). The Hardware Lottery.
  • Kanerva, P. (2009). Hyperdimensional Computing: An Introduction to Computing in Distributed Representation with High-Dimensional Random Vectors.
  • Plate, T. (1995). Holographic Reduced Representations.
  • McClelland, J. L., McNaughton, B. L., O'Reilly, R. C. (1995). Why There Are Complementary Learning Systems in the Hippocampus and Neocortex.
  • Ramsauer, H. ve ark. (2020). Hopfield Networks is All You Need.
  • Christodoulou, M., Rovelli, C. (2015). How Big is a Black Hole?

Ek: Deney Kodları

Aşağıda yedi deneyin tam kaynak kodu var. Gereksinimler: Python 3 ve NumPy (pip install numpy). Her dosya bağımsız çalışır: python3 dosya_adi.py. Deney 4 ve 7 komut satırından kendi cümlenizle canlı test edilebilir (örnek: python3 4_dil_tanima.py "bir cümle"). Deney 6, MNIST veri dosyalarını veri/ klasöründe arar; dört dosyayı storage.googleapis.com/cvdf-datasets/mnist/ adresinden indirebilirsiniz.

1_tardis.py

Yüksek boyutlu uzaya kaç "neredeyse dik" yön sığıyor?

Python82 satır
# -*- coding: utf-8 -*-
# DENEY 1: TARDIS ETKISI
# Soru: n boyutlu bir uzaya kaç tane "neredeyse dik" yön sığar?
# 3 boyutta cevap acınası, 10.000 boyutta cevap astronomik.
# "Dışarıdan küçük kutu, içeriden devasa hacim" işte budur.

import numpy as np
import math

EPS = 0.2          # |cos| < 0.2 ise iki yönü "neredeyse dik" sayıyoruz (aralarında 78.5 - 101.5 derece)
ADAY = 2000        # her boyutta bu kadar rastgele yön deniyoruz
rng = np.random.default_rng(42)

def insanca(x):
    # 10 üzeri gösterimli okunur sayı
    if x == float("inf"):
        return "sonsuz"
    if x < 1e6:
        return f"{x:,.0f}".replace(",", ".")
    ust = int(math.floor(math.log10(x)))
    return f"~10^{ust}"

print()
print("=" * 74)
print("  DENEY 1: TARDIS ETKISI")
print("  Kural: iki yön 'neredeyse dik' sayılır, eğer |cos| < %.2f ise" % EPS)
print("  Her boyutta %d rastgele yön atıyoruz, birbirine dik kalanları sayıyoruz" % ADAY)
print("=" * 74)
print()
print(f"{'Boyut':>8} | {'Sığan yön':>12} | {'Tipik açı':>12} | {'Çift bazlı kaba tahmin':>22}")
print("-" * 74)

for d in [3, 10, 100, 1000, 10000]:
    X = rng.standard_normal((ADAY, d)).astype(np.float32)
    X /= np.linalg.norm(X, axis=1, keepdims=True)

    G = np.abs(X @ X.T)          # tüm çiftlerin |cos| matrisi
    np.fill_diagonal(G, 0.0)

    # Açgözlü seçim: sırayla gez, öncekilerle çakışmayanı tut
    secilen = []
    for i in range(ADAY):
        if all(G[i, j] < EPS for j in secilen):
            secilen.append(i)
    sigan = len(secilen)

    # Rastgele iki yön arasındaki tipik açı
    ortalama_cos = float(G[np.triu_indices(ADAY, 1)].mean())
    tipik_aci = math.degrees(math.acos(ortalama_cos))

    # Kaba tahmin: TEK bir çiftin çakışma olasılığı p ~ 2*exp(-d*eps^2/2),
    # tavan ~ 1/p. Dikkat: N vektörün TÜM çiftlerinin uyumu istendiğinde
    # (birthday düzeltmesi) ölçek ~1/sqrt(p) tarafına kayar; kesin paketleme
    # problemi daha da inceliklidir. Sağlam sonuç sayı değil, üstel büyüme.
    # (formül ancak yüksek boyutta anlamlı, düşük boyutta göstermiyoruz)
    if d >= 1000:
        p = 2.0 * math.exp(-d * EPS * EPS / 2.0)
        tavan_txt = insanca(1.0 / p) if p > 0 else "sonsuz"
    else:
        tavan_txt = "-"

    etiket = f"{sigan}"
    if sigan == ADAY:
        etiket = f"{ADAY} (TAMAMI!)"

    print(f"{d:>8} | {etiket:>12} | {tipik_aci:>10.1f}° | {tavan_txt:>22}")

print("-" * 74)
print()
print("Okuma rehberi:")
print("  * 3 boyutta ancak 3-4 yön birbirine dik durabiliyor. Kutu, göründüğü kadar.")
print("  * Boyut arttıkça rastgele iki yön kendiliğinden 90 dereceye yaklaşıyor.")
print("  * 10.000 boyutta denediğimiz 2000 yönün TAMAMI birbirine neredeyse dik.")
print("    Çift bazlı kaba hesap ~10^86 verir; tüm çiftlerin aynı anda uyumu")
print("    istendiğinde (birthday düzeltmesi) tahmin ~10^43 mertebesine iner.")
print("    Sağlam sonuç sayı değil, büyüme biçimi: kapasite boyutla ÜSTEL artar")
print("    ve her makul hesapta astronomik kalır. Dışarıdan 10.000 sayılık bir")
print("    kutu, içeriden pratikte tükenmeyen bir yön deposu. TARDIS budur.")
print()
print("  Yapay zekanın sırrı da bu: birkaç bin sayılık embedding vektörü,")
print("  milyonlarca kavramı bu 'neredeyse dik' yönlere yazarak taşıyor.")
print()

2_superpozisyon.py

Tek vektöre üst üste yazılan anahtar-değer belleği ve kapasite eğrisi.

Python100 satır
# -*- coding: utf-8 -*-
# DENEY 2: SUPERPOZISYON (üst üste yazma)
# Tek bir 10.000 sayılık vektöre yüzlerce bilgi çiftini UST USTE yazıyoruz.
# Vektör hiç büyümüyor. Sonra her bilgiyi tek tek geri çıkarmayı deniyoruz.
# Senin "disk dolunca üstüne yaz, sonra kurtar" sezginin matematiksel hali.
#
# Yöntem (hyperdimensional computing):
#   yaz:    bellek += anahtar * değer      (eleman eleman çarpım = bağlama)
#   oku:    tahmin = bellek * anahtar      (aynı çarpım bağı çözer)
#   bul:    sözlükteki hangi değere en çok benziyor?

import numpy as np

D = 10_000            # bellek vektörünün boyutu (asla değişmiyor)
SOZLUK = 1000         # olası değer sayısı (aday cevap havuzu)
rng = np.random.default_rng(7)

def rasgele_vektor(n):
    # bileşenleri -1/+1 olan rastgele vektörler
    return rng.integers(0, 2, size=(n, D)).astype(np.int8) * 2 - 1

# Gerçek bilgi çiftleri: ülke -> başkent (tat katsın diye)
GERCEK = [
    ("Türkiye", "Ankara"), ("Fransa", "Paris"), ("Japonya", "Tokyo"),
    ("Mısır", "Kahire"), ("Kanada", "Ottawa"), ("Brezilya", "Brasilia"),
    ("Rusya", "Moskova"), ("İtalya", "Roma"), ("İspanya", "Madrid"),
    ("Almanya", "Berlin"), ("Yunanistan", "Atina"), ("İran", "Tahran"),
    ("Hindistan", "Yeni Delhi"), ("Çin", "Pekin"), ("Kenya", "Nairobi"),
    ("Norveç", "Oslo"), ("İsveç", "Stokholm"), ("Macaristan", "Budapeşte"),
    ("Portekiz", "Lizbon"), ("Avustralya", "Kanberra"),
]

print()
print("=" * 74)
print("  DENEY 2: SUPERPOZISYON")
print(f"  Bellek: TEK vektör, {D:,} sayı (~40 KB). Ne kadar bilgi taşır?".replace(",", "."))
print("=" * 74)

# ---- Bölüm A: 300 çift yaz, gerçek örneklerle geri oku ----
M_ORNEK = 300
anahtarlar = rasgele_vektor(M_ORNEK)
deger_havuzu = rasgele_vektor(SOZLUK)          # sözlük: 1000 olası değer
deger_indeksleri = rng.integers(0, SOZLUK, size=M_ORNEK)
# ilk 20 çifti gerçek başkent bilgisi olarak etiketle
for i in range(len(GERCEK)):
    deger_indeksleri[i] = i

bellek = np.zeros(D, dtype=np.int32)
for i in range(M_ORNEK):
    bellek += anahtarlar[i] * deger_havuzu[deger_indeksleri[i]]

print()
print(f"  {M_ORNEK} bilgi çifti tek vektöre üst üste yazıldı. Bellek hala {D:,} sayı.".replace(",", "."))
print("  Şimdi soruyoruz:")
print()

dogru_ornek = 0
for i in range(8):
    ulke, baskent = GERCEK[i]
    cozulmus = (bellek * anahtarlar[i]).astype(np.float32)
    benzerlik = deger_havuzu.astype(np.float32) @ cozulmus
    tahmin = int(np.argmax(benzerlik))
    isaret = "DOĞRU" if tahmin == deger_indeksleri[i] else "YANLIŞ"
    if tahmin == deger_indeksleri[i]:
        dogru_ornek += 1
        cevap = baskent
    else:
        cevap = f"değer#{tahmin}"
    print(f"    {ulke:>12} -> ?   cevap: {cevap:<12} [{isaret}]")

# ---- Bölüm B: kapasite eğrisi ----
print()
print("  Peki sınır nerede? Aynı 40 KB'lık vektöre gitgide daha çok yazalım:")
print()
print(f"  {'Yazılan çift':>13} | {'Geri okuma başarısı':<40}")
print("  " + "-" * 62)

for M in [50, 100, 200, 300, 500, 800, 1200, 2000]:
    K = rasgele_vektor(M)
    V_idx = rng.integers(0, SOZLUK, size=M)
    bel = np.einsum("ij,ij->j", K.astype(np.int32),
                    deger_havuzu[V_idx].astype(np.int32))
    # tüm çiftleri toplu geri oku
    cozulmus = (bel[None, :] * K).astype(np.float32)          # M x D
    skor = cozulmus @ deger_havuzu.T.astype(np.float32)       # M x SOZLUK
    tahminler = skor.argmax(axis=1)
    basari = float((tahminler == V_idx).mean())
    cubuk = "█" * int(round(basari * 30))
    print(f"  {M:>13} | {cubuk:<30} %{basari*100:5.1f}")

print()
print("Okuma rehberi:")
print("  * Birkaç yüz çifte kadar geri okuma neredeyse kusursuz: bilgiler")
print("    birbirinin ÜSTÜNE yazıldığı halde tek tek geri çıkıyor.")
print("  * Sonra girişim (interference) başlıyor: üst üste binen bilgiler")
print("    birbirini gölgelemeye başlıyor ve başarı KADEMELİ düşüyor.")
print("  * Dikkat: sistem asla 'disk doldu' demiyor. Klasik bellek gibi")
print("    duvara çarpmıyor, hologram gibi yavaşça flulaşıyor.")
print("  * Rastgele tahmin %0.1 olurdu; en dolu halinde bile ondan çok iyi.")
print()

3_hologram.py

Belleğin parça parça silinmesine dayanıklılık testi.

Python95 satır
# -*- coding: utf-8 -*-
# DENEY 3: HOLOGRAM
# Hologramı ikiye kesersen yarım görüntü kalmaz; TAMAMININ flu hali kalır.
# Çünkü bilgi bir yere değil, her yere birden yazılmıştır.
# Burada belleğin %50'sini, %90'ını, %98'ini SİLİYORUZ ve
# hala neyi hatırladığına bakıyoruz.

import numpy as np

D = 10_000
rng = np.random.default_rng(2026)

BILGILER = [
    ("Türkiye", "Ankara"), ("Fransa", "Paris"), ("Japonya", "Tokyo"),
    ("Mısır", "Kahire"), ("Kanada", "Ottawa"), ("Brezilya", "Brasilia"),
    ("Rusya", "Moskova"), ("İtalya", "Roma"), ("İspanya", "Madrid"),
    ("Almanya", "Berlin"), ("Yunanistan", "Atina"), ("İran", "Tahran"),
    ("Hindistan", "Yeni Delhi"), ("Çin", "Pekin"), ("Kenya", "Nairobi"),
    ("Norveç", "Oslo"), ("İsveç", "Stokholm"), ("Macaristan", "Budapeşte"),
    ("Portekiz", "Lizbon"), ("Avustralya", "Kanberra"), ("Peru", "Lima"),
    ("Şili", "Santiago"), ("Küba", "Havana"), ("Irak", "Bağdat"),
    ("Suriye", "Şam"), ("Ürdün", "Amman"), ("Fas", "Rabat"),
    ("Cezayir", "Cezayir"), ("Nijerya", "Abuja"), ("Etiyopya", "Addis Ababa"),
    ("Tayland", "Bangkok"), ("Vietnam", "Hanoi"), ("Endonezya", "Cakarta"),
    ("Filipinler", "Manila"), ("Arjantin", "Buenos Aires"), ("Meksika", "Meksiko"),
    ("Polonya", "Varşova"), ("Çekya", "Prag"), ("Avusturya", "Viyana"),
    ("İsviçre", "Bern"), ("Belçika", "Brüksel"), ("Hollanda", "Amsterdam"),
    ("Danimarka", "Kopenhag"), ("Finlandiya", "Helsinki"), ("İrlanda", "Dublin"),
    ("Merkür", "1. gezegen"), ("Venüs", "2. gezegen"), ("Dünya", "3. gezegen"),
    ("Mars", "4. gezegen"), ("Jüpiter", "5. gezegen"), ("Satürn", "6. gezegen"),
    ("Uranüs", "7. gezegen"), ("Neptün", "8. gezegen"),
    ("Su", "H2O"), ("Tuz", "NaCl"), ("Altın", "Au"), ("Demir", "Fe"),
    ("Oksijen", "O2"), ("Karbon", "C"), ("Gümüş", "Ag"),
]

M = len(BILGILER)
degers = sorted(set(b for _, b in BILGILER))
V = len(degers)
deger_no = {b: i for i, b in enumerate(degers)}

def rasgele_vektor(n):
    return rng.integers(0, 2, size=(n, D)).astype(np.int8) * 2 - 1

anahtar_vek = rasgele_vektor(M)
deger_vek = rasgele_vektor(V)

bellek = np.zeros(D, dtype=np.int32)
for i, (_, b) in enumerate(BILGILER):
    bellek += anahtar_vek[i] * deger_vek[deger_no[b]]

print()
print("=" * 74)
print(f"  DENEY 3: HOLOGRAM")
print(f"  {M} bilgi tek vektöre yazıldı (başkentler, gezegenler, formüller).")
print(f"  Şimdi bu vektörü parça parça YOK EDİYORUZ.")
print("=" * 74)
print()
print(f"  {'Silinen':>9} | {'Kalan sayı':>11} | {'Hatırlanan':<38}")
print("  " + "-" * 68)

for kalan_oran in [1.0, 0.5, 0.25, 0.10, 0.05, 0.02, 0.01]:
    kalan = int(D * kalan_oran)
    maske = np.zeros(D, dtype=np.int32)
    secilen = rng.choice(D, size=kalan, replace=False)
    maske[secilen] = 1
    yarali_bellek = bellek * maske          # geri kalan her şey SIFIRLANDI

    cozulmus = (yarali_bellek[None, :] * anahtar_vek).astype(np.float32)
    skor = cozulmus @ deger_vek.T.astype(np.float32)
    tahminler = skor.argmax(axis=1)
    hedef = np.array([deger_no[b] for _, b in BILGILER])
    basari = float((tahminler == hedef).mean())

    cubuk = "█" * int(round(basari * 28))
    silinen = f"%{(1-kalan_oran)*100:.0f}"
    print(f"  {silinen:>9} | {kalan:>11,} | {cubuk:<28} %{basari*100:5.1f}".replace(",", "."))

# tek bir somut örnek: %90'ı silinmiş bellekten Türkiye'yi sor
maske = np.zeros(D, dtype=np.int32)
maske[rng.choice(D, size=D // 10, replace=False)] = 1
yarali = bellek * maske
c = (yarali * anahtar_vek[0]).astype(np.float32)
tahmin = degers[int(np.argmax(deger_vek.astype(np.float32) @ c))]
print()
print(f"  Somut örnek: belleğin %90'ı silinmişken 'Türkiye -> ?' cevabı: {tahmin}")
print()
print("Okuma rehberi:")
print("  * Klasik diskte sektörlerin %50'sini silsen dosyaların yarısı GİDER.")
print("  * Burada %50 silinince kayıp YOK, çünkü hiçbir bilgi belirli bir")
print("    hücrede yaşamıyor; hepsi vektörün TAMAMINA yayılmış durumda.")
print("  * %90, %95 silinince bile hatırlıyor; sadece giderek flulaşıyor.")
print("    Hologramın yarısını kesince bütünün flu kalması, birebir bu.")
print("  * Beynin hasara dayanıklılığı da aynı ilke: anılar tek nöronda değil,")
print("    milyonlarca sinapsın üstünde üst üste yazılı.")
print()

4_dil_tanima.py

Harf üçlüsü hipervektörleriyle, tek geçişte eğitilen dil tanıma modeli.

Python212 satır
# -*- coding: utf-8 -*-
# DENEY 4: ILK GERCEK MODEL (hyperdimensional computing mimarisi)
# Onceki deneylerdeki superpozisyon mekanizmasi burada OGRENEN bir modele donusuyor.
#
# Mimari:
#   * Her harfin 10.000 boyutlu rastgele bir imzasi var (sabit, ogrenilmez).
#   * Uclu harf grubu (trigram) = uc harf imzasinin kaydirilip carpilmasi.
#   * Bir dilin "beyni" = o dilde gorulen TUM trigramlarin tek vektore
#     ust uste yazilmasi (deney 2'deki superpozisyon, birebir).
#   * Tahmin = cumlenin vektoru hangi dil vektorune en cok benziyor?
#
# Dikkat: backprop yok, gradyan yok, GPU yok, epoch yok.
# Egitim = veriyi BIR KEZ okuyup ust uste yazmak. Bu yuzden saniyeler suruyor.

import sys
import time
import unicodedata
import numpy as np

D = 10_000

EGITIM = {
    "Türkçe": (
        "Bugün hava çok güzeldi ve sahilde uzun bir yürüyüş yaptık. "
        "Akşam yemeğinde annemin yaptığı mercimek çorbasını içtik. "
        "Teknoloji hayatımızın her alanına girmiş durumda. "
        "Kitap okumak insanın ufkunu genişletir ve hayal gücünü besler. "
        "Yarın sabah erkenden yola çıkacağız çünkü yol çok uzun. "
        "Çocuklar bahçede top oynarken biz balkonda çay içtik. "
        "İstanbul her yıl milyonlarca turisti ağırlamaya devam ediyor. "
        "Müzik dinlemek beni her zaman rahatlatır ve dinlendirir."
    ),
    "İngilizce": (
        "The weather was beautiful today and we took a long walk on the beach. "
        "Technology has entered every part of our daily lives. "
        "Reading books expands the mind and feeds the imagination. "
        "We will leave early tomorrow morning because the road is long. "
        "The children played football in the garden while we drank tea. "
        "London welcomes millions of tourists every single year. "
        "Listening to music always helps me relax after a hard day."
    ),
    "Almanca": (
        "Das Wetter war heute wunderschön und wir haben einen langen Spaziergang am Strand gemacht. "
        "Die Technologie ist in alle Bereiche unseres Lebens eingedrungen. "
        "Bücher zu lesen erweitert den Horizont und nährt die Fantasie. "
        "Wir werden morgen früh aufbrechen, denn der Weg ist lang. "
        "Die Kinder spielten im Garten Fußball, während wir Tee tranken. "
        "Berlin empfängt jedes Jahr Millionen von Touristen. "
        "Musik zu hören hilft mir immer, mich zu entspannen."
    ),
    "Fransızca": (
        "Le temps était magnifique aujourd'hui et nous avons fait une longue promenade sur la plage. "
        "La technologie est entrée dans tous les domaines de notre vie. "
        "Lire des livres élargit l'esprit et nourrit l'imagination. "
        "Nous partirons tôt demain matin car la route est longue. "
        "Les enfants jouaient au ballon dans le jardin pendant que nous buvions du thé. "
        "Paris accueille chaque année des millions de touristes. "
        "Écouter de la musique m'aide toujours à me détendre."
    ),
    "İspanyolca": (
        "El tiempo estaba precioso hoy y dimos un largo paseo por la playa. "
        "La tecnología ha entrado en todos los ámbitos de nuestra vida. "
        "Leer libros amplía la mente y alimenta la imaginación. "
        "Saldremos mañana temprano porque el camino es muy largo. "
        "Los niños jugaban al fútbol en el jardín mientras nosotros tomábamos té. "
        "Madrid recibe cada año a millones de turistas. "
        "Escuchar música siempre me ayuda a relajarme después de un día difícil."
    ),
    "İtalyanca": (
        "Il tempo oggi era bellissimo e abbiamo fatto una lunga passeggiata sulla spiaggia. "
        "La tecnologia è entrata in ogni ambito della nostra vita. "
        "Leggere libri amplia la mente e nutre l'immaginazione. "
        "Partiremo domattina presto perché la strada è molto lunga. "
        "I bambini giocavano a pallone in giardino mentre noi bevevamo il tè. "
        "Roma accoglie ogni anno milioni di turisti. "
        "Ascoltare musica mi aiuta sempre a rilassarmi."
    ),
}

# Modelin egitimde HIC GORMEDIGI cumleler
TEST = [
    ("Türkçe", "Kediler pencerenin önünde uyumayı çok sever."),
    ("Türkçe", "Bu şehirde trafik her geçen gün daha da kötüleşiyor."),
    ("Türkçe", "Dedem bize eski günlerden hikayeler anlatırdı."),
    ("Türkçe", "Sınav sonuçları önümüzdeki hafta açıklanacak."),
    ("İngilizce", "Cats love sleeping in front of the window."),
    ("İngilizce", "Traffic in this city gets worse every day."),
    ("İngilizce", "My grandfather used to tell us stories about the old days."),
    ("İngilizce", "The exam results will be announced next week."),
    ("Almanca", "Katzen schlafen sehr gerne vor dem Fenster."),
    ("Almanca", "Der Verkehr in dieser Stadt wird jeden Tag schlimmer."),
    ("Almanca", "Mein Großvater erzählte uns Geschichten von früher."),
    ("Almanca", "Die Prüfungsergebnisse werden nächste Woche bekannt gegeben."),
    ("Fransızca", "Les chats adorent dormir devant la fenêtre."),
    ("Fransızca", "La circulation dans cette ville empire chaque jour."),
    ("Fransızca", "Mon grand-père nous racontait des histoires d'autrefois."),
    ("Fransızca", "Les résultats de l'examen seront annoncés la semaine prochaine."),
    ("İspanyolca", "A los gatos les encanta dormir frente a la ventana."),
    ("İspanyolca", "El tráfico en esta ciudad empeora cada día."),
    ("İspanyolca", "Mi abuelo nos contaba historias de los viejos tiempos."),
    ("İspanyolca", "Los resultados del examen se anunciarán la próxima semana."),
    ("İtalyanca", "Ai gatti piace moltissimo dormire davanti alla finestra."),
    ("İtalyanca", "Il traffico in questa città peggiora ogni giorno."),
    ("İtalyanca", "Mio nonno ci raccontava storie dei vecchi tempi."),
    ("İtalyanca", "I risultati dell'esame saranno annunciati la settimana prossima."),
]

_harf_imza = {}

def harf_imza(c):
    # Her karakterin sabit, rastgele +1/-1 imzasi (kod noktasindan turetilir)
    if c not in _harf_imza:
        r = np.random.default_rng(1_000_003 + ord(c))
        _harf_imza[c] = (r.integers(0, 2, size=D) * 2 - 1).astype(np.int8)
    return _harf_imza[c]

def temizle(metin):
    metin = metin.lower()
    out = []
    for c in metin:
        if c.isalpha() or c == " ":
            out.append(c)
        else:
            out.append(" ")
    return " ".join("".join(out).split())

def metin_vektoru(metin):
    # Metindeki tum trigramlari tek vektore ust uste yaz (superpozisyon)
    metin = temizle(metin)
    if len(metin) < 3:
        return np.zeros(D, dtype=np.float32)
    H = np.stack([harf_imza(c) for c in metin]).astype(np.int32)   # L x D
    tri = (np.roll(H[:-2], 2, axis=1)
           * np.roll(H[1:-1], 1, axis=1)
           * H[2:])
    return tri.sum(axis=0).astype(np.float32)

def kosinus(a, b):
    na, nb = np.linalg.norm(a), np.linalg.norm(b)
    if na == 0 or nb == 0:
        return 0.0
    return float(a @ b / (na * nb))

print()
print("=" * 74)
print("  DENEY 4: İLK GERÇEK MODEL - dil tanıma")
print("  Mimari: hyperdimensional computing (deney 2'nin öğrenen hali)")
print("=" * 74)

# ---- EGITIM ----
t0 = time.perf_counter()
model = {dil: metin_vektoru(metin) for dil, metin in EGITIM.items()}
sure = time.perf_counter() - t0

toplam_karakter = sum(len(m) for m in EGITIM.values())
model_boyut = len(model) * D * 4 / 1024

print()
print(f"  Eğitim verisi : 6 dil, toplam {toplam_karakter:,} karakter".replace(",", "."))
print(f"  Eğitim süresi : {sure:.2f} saniye (CPU, tek geçiş, backprop YOK)")
print(f"  Model boyutu  : 6 vektör x {D:,} sayı = {model_boyut:.0f} KB".replace(",", "."))
print()

# ---- TEST: modelin hic gormedigi cumleler ----
print("  Modelin eğitimde HİÇ görmediği cümlelerle sınav:")
print()
dogru = 0
dil_skor = {}
for gercek_dil, cumle in TEST:
    v = metin_vektoru(cumle)
    skorlar = {dil: kosinus(v, mv) for dil, mv in model.items()}
    tahmin = max(skorlar, key=skorlar.get)
    ok = tahmin == gercek_dil
    dogru += ok
    dil_skor.setdefault(gercek_dil, [0, 0])
    dil_skor[gercek_dil][0] += ok
    dil_skor[gercek_dil][1] += 1
    isaret = "+" if ok else "X"
    kisa = cumle if len(cumle) <= 46 else cumle[:43] + "..."
    print(f"   [{isaret}] {kisa:<46} -> {tahmin}")

print()
print(f"  {'Dil':<12} | Başarı")
print("  " + "-" * 24)
for dil, (d, t) in dil_skor.items():
    print(f"  {dil:<12} | {d}/{t}")
print("  " + "-" * 24)
print(f"  {'TOPLAM':<12} | {dogru}/{len(TEST)}  (%{100*dogru/len(TEST):.1f})")

# ---- Interaktif: kendi cumleni dene ----
if len(sys.argv) > 1:
    girdi = " ".join(sys.argv[1:])
    v = metin_vektoru(girdi)
    skorlar = sorted(((kosinus(v, mv), dil) for dil, mv in model.items()), reverse=True)
    print()
    print(f"  Senin cümlen: \"{girdi}\"")
    for s, dil in skorlar[:3]:
        cubuk = "█" * max(0, int(s * 40))
        print(f"    {dil:<12} {cubuk} {s:.3f}")
    print(f"  Tahmin: {skorlar[0][1]}")

print()
print("Okuma rehberi:")
print("  * Bu gerçek bir model: veri gördü, örüntü çıkardı, hiç görmediği")
print("    cümlelerde genelleme yapıyor. Ama içinde tek bir nöron ağı yok.")
print("  * Her dilin tüm trigram istatistiği, deney 2'deki superpozisyonla")
print("    TEK vektöre üst üste yazıldı. Dilin kimliği o vektörün yönü.")
print("  * Eğitim maliyeti fark: benzer işi yapan bir sinir ağı binlerce")
print("    adım gradyan inişi ister; bu mimari veriyi bir kez okudu.")
print("  * Kendi cümleni denemek için:")
print("    .venv/bin/python 4_dil_tanima.py \"buraya bir cümle yaz\"")
print()

5_unutmayan_model.py

Üç öğrencili unutma yarışı: klasik ağ, holografik bellek ve uykulu hibrit.

Python244 satır
# -*- coding: utf-8 -*-
# DENEY 5: UNUTMAYAN MODEL (yapay hipokampus)
#
# Problem: catastrophic forgetting. Sinir agina once A'yi sonra B'yi ogretirsen
# B'yi ogrenirken A'yi siler. Beyin bunu iki bellekle cozuyor:
#   hipokampus = aninda, tek seferde yazar (bizim holografik vektorumuz)
#   korteks    = yavas, genelleyerek ogrenir (sinir agi)
#   uyku       = hipokampus gunun anilarini kortekse tekrar oynatir (ruya)
#
# Deney: 5 "gun" suren bir veri akisi. Her gun 10 YENI konu (sinif) geliyor.
# Her aksam o gune kadarki TUM konulardan sinav var. Uc ogrenci yarisiyor:
#
#   Ogrenci A (klasik)     : sinir agi, backprop (elle yazildi), sadece gunun
#                            verisiyle calisir. Beklenti: eskiyi ezer.
#   Ogrenci B (holografik) : TEK vektore ust uste yazan bellek (deney 2/3).
#                            Egitim yok, aninda yazma. Beklenti: unutmaz.
#   Ogrenci C (hibrit)     : gunduz A ile BIREBIR AYNI egitimi alir, ayrica
#                            hipokampusa (holografik vektor) aninda yazar.
#                            Gece uyur: hipokampustan uretilen RUYALARLA tum
#                            eski konulari tekrar eder. A ile tek farki UYKU.
#
# Her sey numpy, her sey CPU, veri sentetik (internet yok).

import numpy as np
import time

rng = np.random.default_rng(5150)

# ---------------- deney sabitleri ----------------
GIRDI = 100          # ham girdi boyutu
D = 20_000           # hipervektor boyutu
GUN = 5              # akis kac gun suruyor
SINIF_GUN = 10       # her gun kac yeni konu geliyor
SINIF = GUN * SINIF_GUN
ORNEK_EGT = 200      # konu basina gunluk egitim ornegi
ORNEK_TEST = 50      # konu basina test ornegi
GURULTU = 1.0        # veri zorlugu
GIZLI = 256          # sinir agi gizli katmani
EPOCH = 3            # gunluk egitim turu
RUYA = 60            # uykuda konu basina uretilen ruya sayisi
RUYA_GURULTU = 1.0   # ruya gurultusu / gercek deneyim gurultusu orani

# ---------------- veri evreni ----------------
prototipler = rng.standard_normal((SINIF, GIRDI)).astype(np.float32)
projeksiyon = rng.standard_normal((GIRDI, D)).astype(np.float32) / np.sqrt(GIRDI)

def ornek_uret(sinif_no, adet):
    x = prototipler[sinif_no] + GURULTU * rng.standard_normal((adet, GIRDI)).astype(np.float32)
    return x

def kodla(x):
    # ham girdi -> +1/-1 hipervektor (sabit rastgele projeksiyon + isaret)
    return np.sign(x @ projeksiyon).astype(np.int8)

# ---------------- Ogrenci A ve C'nin korteksi: elle yazilmis sinir agi ----------------
class SinirAgi:
    def __init__(self, seed):
        r = np.random.default_rng(seed)
        self.W1 = (r.standard_normal((D, GIZLI)) / np.sqrt(D)).astype(np.float32)
        self.b1 = np.zeros(GIZLI, dtype=np.float32)
        self.W2 = (r.standard_normal((GIZLI, SINIF)) / np.sqrt(GIZLI)).astype(np.float32)
        self.b2 = np.zeros(SINIF, dtype=np.float32)
        self.vW1 = np.zeros_like(self.W1); self.vb1 = np.zeros_like(self.b1)
        self.vW2 = np.zeros_like(self.W2); self.vb2 = np.zeros_like(self.b2)

    def ileri(self, X):
        h = np.maximum(0.0, X @ self.W1 + self.b1)
        return h, h @ self.W2 + self.b2

    def egit(self, X, y, epoch, lr=0.02, mom=0.9, parti=100):
        n = len(X)
        for _ in range(epoch):
            sira = rng.permutation(n)
            for i in range(0, n, parti):
                idx = sira[i:i + parti]
                Xb = X[idx].astype(np.float32)
                yb = y[idx]
                h, logit = self.ileri(Xb)
                logit -= logit.max(axis=1, keepdims=True)
                p = np.exp(logit); p /= p.sum(axis=1, keepdims=True)
                p[np.arange(len(yb)), yb] -= 1.0
                p /= len(yb)                       # softmax + cross-entropy gradyani
                gW2 = h.T @ p
                gb2 = p.sum(axis=0)
                gh = p @ self.W2.T
                gh[h <= 0] = 0.0
                gW1 = Xb.T @ gh
                gb1 = gh.sum(axis=0)
                # momentumlu SGD
                self.vW2 = mom * self.vW2 - lr * gW2; self.W2 += self.vW2
                self.vb2 = mom * self.vb2 - lr * gb2; self.b2 += self.vb2
                self.vW1 = mom * self.vW1 - lr * gW1; self.W1 += self.vW1
                self.vb1 = mom * self.vb1 - lr * gb1; self.b1 += self.vb1

    def tahmin(self, X, gorulen):
        _, logit = self.ileri(X.astype(np.float32))
        return np.argmax(logit[:, :gorulen], axis=1)

# ---------------- Ogrenci B ve C'nin hipokampusu: TEK holografik vektor ----------------
sinif_anahtari = (rng.integers(0, 2, size=(SINIF, D)) * 2 - 1).astype(np.int8)

class Hipokampus:
    def __init__(self):
        self.M = np.zeros(D, dtype=np.int64)      # TEK bellek vektoru

    def yaz(self, enc, sinif_no):
        # gunun her ornegi aninda, tek seferde ust uste yazilir
        self.M += (enc.astype(np.int64) * sinif_anahtari[sinif_no]).sum(axis=0)

    def hatirla(self, sinif_no):
        # bag cozme: sinifin anisini geri cagir (uzerinde digerlerinin golgesi var)
        return (self.M * sinif_anahtari[sinif_no]).astype(np.float32)

    def tahmin(self, enc, gorulen):
        R = (self.M[None, :] * sinif_anahtari[:gorulen].astype(np.int64)).astype(np.float32)
        R /= np.linalg.norm(R, axis=1, keepdims=True) + 1e-9
        return np.argmax(enc.astype(np.float32) @ R.T, axis=1)

    def ruya_gor(self, sinif_no, adet):
        # Ruya = yeniden yasanan deneyim:
        # 1) aniyi geri cagir  2) girdi uzayina geri coz (kaba ters projeksiyon)
        # 3) gercekci gurultuyle yeniden yasa  4) yeniden kodla
        r = self.hatirla(sinif_no)
        x_tahmini = r @ projeksiyon.T
        x_tahmini *= np.sqrt(GIRDI) / (np.linalg.norm(x_tahmini) + 1e-9)
        X = x_tahmini[None, :] + RUYA_GURULTU * GURULTU * rng.standard_normal((adet, GIRDI)).astype(np.float32)
        return kodla(X)

# ---------------- ogrenciler ----------------
ogrA = SinirAgi(seed=1)          # klasik
ogrB = Hipokampus()              # holografik
ogrC_hipo = Hipokampus()         # hibritin hizli bellegi
ogrC_korteks = SinirAgi(seed=2)  # hibritin yavas bellegi

# test setleri (her gunun konulari icin sabit)
test_enc, test_y = [], []
for g in range(GUN):
    siniflar = range(g * SINIF_GUN, (g + 1) * SINIF_GUN)
    X = np.concatenate([ornek_uret(s, ORNEK_TEST) for s in siniflar])
    y = np.repeat(list(siniflar), ORNEK_TEST)
    test_enc.append(kodla(X))
    test_y.append(y)

print()
print("=" * 74)
print("  DENEY 5: UNUTMAYAN MODEL")
print(f"  {GUN} gunluk akis, her gun {SINIF_GUN} yeni konu, aksamlari genel sinav")
print("  A = klasik sinir agi   B = holografik bellek   C = hibrit (uykulu)")
print("=" * 74)

sonuc = {"A": np.full((GUN, GUN), np.nan), "B": np.full((GUN, GUN), np.nan), "C": np.full((GUN, GUN), np.nan)}
t0 = time.perf_counter()

for gun in range(GUN):
    siniflar = list(range(gun * SINIF_GUN, (gun + 1) * SINIF_GUN))
    gorulen = (gun + 1) * SINIF_GUN

    # --- gunduz: gunun verisi geliyor ---
    X = np.concatenate([ornek_uret(s, ORNEK_EGT) for s in siniflar])
    y = np.repeat(siniflar, ORNEK_EGT)
    enc = kodla(X)

    # A: gunun verisiyle klasik egitim (eski gunlerin verisi YOK, silindi)
    ogrA.egit(enc, y, EPOCH)

    # B: aninda yazma, egitim yok
    for s in siniflar:
        ogrB.yaz(enc[y == s], s)

    # C gunduz: A ile birebir ayni egitim + hipokampusa aninda yazma
    ogrC_korteks.egit(enc, y, EPOCH)
    for s in siniflar:
        ogrC_hipo.yaz(enc[y == s], s)

    # --- gece: C uyuyor, hipokampus o gune kadarki TUM konulari ruyada oynatiyor ---
    ruya_X, ruya_y = [], []
    for s in range(gorulen):
        ruya_X.append(ogrC_hipo.ruya_gor(s, RUYA))
        ruya_y.append(np.full(RUYA, s))
    ogrC_korteks.egit(np.concatenate(ruya_X), np.concatenate(ruya_y), EPOCH)

    # --- aksam sinavi: o gune kadar gorulen HER gunun konulari ---
    for g in range(gun + 1):
        dogruA = (ogrA.tahmin(test_enc[g], gorulen) == test_y[g]).mean()
        dogruB = (ogrB.tahmin(test_enc[g], gorulen) == test_y[g]).mean()
        dogruC = (ogrC_korteks.tahmin(test_enc[g], gorulen) == test_y[g]).mean()
        sonuc["A"][gun, g] = dogruA
        sonuc["B"][gun, g] = dogruB
        sonuc["C"][gun, g] = dogruC

    ort = {k: np.nanmean(sonuc[k][gun, :gun + 1]) * 100 for k in "ABC"}
    print(f"\n  GUN {gun + 1} bitti  (konu sayisi: {gorulen})   "
          f"genel ortalama ->  A: %{ort['A']:.0f}   B: %{ort['B']:.0f}   C: %{ort['C']:.0f}")

sure = time.perf_counter() - t0

# ---------------- rapor ----------------
print()
print("=" * 74)
print("  SONUC 1: 1. GUNUN KONULARININ AKIBETI (unutma egrisi)")
print("=" * 74)
print()
print(f"  {'':14}" + "".join(f"Gün {g+1:>2}   " for g in range(GUN)))
for ad, k in [("A klasik", "A"), ("B holografik", "B"), ("C hibrit", "C")]:
    satir = "".join(f"%{sonuc[k][g, 0]*100:5.1f}  " for g in range(GUN))
    print(f"  {ad:<14}{satir}")
print()
print("  (Satirlar: 1. gun konularinin her gun sonundaki sinav notu)")

print()
print("=" * 74)
print("  SONUC 2: SON GUN GENEL SINAVI (50 konunun tamami)")
print("=" * 74)
print()
for ad, k in [("A klasik", "A"), ("B holografik", "B"), ("C hibrit", "C")]:
    notlar = sonuc[k][GUN - 1] * 100
    ort = np.nanmean(notlar)
    cubuk = "█" * int(round(ort * 0.4))
    detay = " ".join(f"%{n:.0f}" for n in notlar)
    print(f"  {ad:<14} {cubuk:<42} ort %{ort:5.1f}   (gun gun: {detay})")

hafiza_kb = D * 8 / 1024
veri_mb = GUN * SINIF_GUN * ORNEK_EGT * D / (1024 * 1024)
print()
print("=" * 74)
print("  KUNYE")
print("=" * 74)
print(f"  Toplam sure                : {sure:.1f} saniye (CPU)")
print(f"  Toplam gosterilen ornek    : {GUN * SINIF_GUN * ORNEK_EGT:,}".replace(",", "."))
print(f"  Ham anilarin boyutu        : ~{veri_mb:.0f} MB (kimse saklamadi)")
print(f"  C'nin hipokampusu          : TEK vektor, {hafiza_kb:.0f} KB")
print(f"  A ile C arasindaki TEK fark: C geceleri ruya goruyor")
print()
print("Okuma rehberi:")
print("  * A, her yeni gunle eskiyi ezdi: catastrophic forgetting, canli yayin.")
print("  * B hic unutmadi cunku hicbir sey 'uzerine' yazilmadi; her sey tek")
print("    vektorde ust uste, yan yana degil ic ice duruyor (deney 2-3).")
print("  * A ve C AYNI sinir agi, AYNI gunduz egitimi. Tek degisken uyku:")
print("    C gece, hipokampusundan (tek holografik vektor) urettigi ruyalarla")
print("    eski konulari tekrar etti. Ham verinin binde biri boyutunda bir")
print("    bellek, sinir aginin unutma hastaligini tedavi etti.")
print("  * Beyindeki teoriye 'complementary learning systems' deniyor;")
print(f"    burada calisan hali {hafiza_kb:.0f} KB'lik bir hipokampusla kuruldu.")
print()

6_gercek_veri.py

Aynı mimari gerçek el yazısı rakamlarda; epizodik hipokampus ve rüya görselleştirme.

Python369 satır
# -*- coding: utf-8 -*-
# DENEY 6: GERCEK VERI (el yazisi rakamlar, split-MNIST)
#
# Deney 5'in mimarisi oyuncak veriden cikip gercek dunyaya giriyor.
# Gorev: 5 gunluk akis, her gun 2 yeni rakam ogreniliyor:
#   Gun 1: 0,1   Gun 2: 2,3   Gun 3: 4,5   Gun 4: 6,7   Gun 5: 8,9
# Her aksam o gune kadarki TUM rakamlardan sinav (gercek MNIST test seti).
#
# Yarisanlar:
#   A (klasik)     : sinir agi, sadece gunun verisi. Beklenti: eskiyi ezer.
#   B (holografik) : tek vektorluk epizodik bellek, egitimsiz.
#   C (hibrit)     : A ile AYNI ag + AYNI gunduz egitimi. Tek fark: geceleri
#                    hipokampusundan urettigi ruyalarla eskiyi tekrar eder.
#   IDEAL          : tum gunlerin verisini ayni anda goren ag (hile, referans).
#
# Yenilik (deney 5'e gore): hipokampus artik EPIZODIK. Her rakam icin tek
# ortalama degil, YUVA'lar var: benzer yazim stilleri ayni yuvaya birikiyor
# (hipokampusun "pattern separation" isinin kaba hali). Ruyada her yuva ayri
# geri cagriliyor, boylece ruyalar farkli el yazisi stillerini de tasiyor.
# Her sey yine TEK bellek vektorunde, ust uste.

import gzip
import time
from pathlib import Path
import numpy as np

rng = np.random.default_rng(6060)
DEBUG = False

# ---------------- sabitler ----------------
D = 50_000           # hipervektor boyutu
GIZLI = 256          # sinir agi gizli katmani
EPOCH = 3            # gunluk egitim turu
EGT_SINIF = 1000     # rakam basina egitim ornegi
TEST_SINIF = 500     # rakam basina test ornegi
YUVA = 20            # hipokampusta rakam basina stil yuvasi
RUYA_YUVA = 10       # uykuda yuva basina ruya
KALITE_ORAN = 0.5    # ruya kalite kapisi: gecenin medyan kalitesinin bu orani
                     # altindaki (bozulmus) anilardan ruya uretilmez
GUNLER = [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]

# ---------------- MNIST yukle ----------------
VERI = Path(__file__).parent / "veri"

def idx_oku(dosya, offset):
    with gzip.open(VERI / dosya, "rb") as f:
        return np.frombuffer(f.read(), dtype=np.uint8, offset=offset)

trX = idx_oku("train-images-idx3-ubyte.gz", 16).reshape(-1, 784).astype(np.float32) / 255.0
trY = idx_oku("train-labels-idx1-ubyte.gz", 8)
teX = idx_oku("t10k-images-idx3-ubyte.gz", 16).reshape(-1, 784).astype(np.float32) / 255.0
teY = idx_oku("t10k-labels-idx1-ubyte.gz", 8)

egt_X, egt_y, tst_X, tst_y = {}, {}, {}, {}
for r in range(10):
    i = np.where(trY == r)[0][:EGT_SINIF]
    egt_X[r], egt_y[r] = trX[i], np.full(len(i), r)
    j = np.where(teY == r)[0][:TEST_SINIF]
    tst_X[r], tst_y[r] = teX[j], np.full(len(j), r)

# ---------------- holografik kodlayici (dogrusal, HRR tarzi) ----------------
# Not: sign()'li ikili kodlama siniflandirmada iyi ama geri COZUMU bozuyor
# (tum rakamlarin ortak arka plani korele girisim yaratiyor). Dogrusal
# projeksiyonda decode neredeyse kayipsiz: r @ P.T ~ orijinal goruntu.
PIKSEL_ORT = 0.1307
projeksiyon = rng.standard_normal((784, D)).astype(np.float32) / np.sqrt(784)

def kodla(X):
    return (X - PIKSEL_ORT) @ projeksiyon

# ---------------- sinir agi (elle backprop, deney 5 ile ayni) ----------------
class SinirAgi:
    def __init__(self, seed):
        r = np.random.default_rng(seed)
        self.W1 = (r.standard_normal((784, GIZLI)) / np.sqrt(784)).astype(np.float32)
        self.b1 = np.zeros(GIZLI, dtype=np.float32)
        self.W2 = (r.standard_normal((GIZLI, 10)) / np.sqrt(GIZLI)).astype(np.float32)
        self.b2 = np.zeros(10, dtype=np.float32)
        self.vW1 = np.zeros_like(self.W1); self.vb1 = np.zeros_like(self.b1)
        self.vW2 = np.zeros_like(self.W2); self.vb2 = np.zeros_like(self.b2)

    def ileri(self, X):
        h = np.maximum(0.0, X @ self.W1 + self.b1)
        return h, h @ self.W2 + self.b2

    def egit(self, X, y, epoch, lr=0.05, mom=0.9, parti=100):
        n = len(X)
        for _ in range(epoch):
            sira = rng.permutation(n)
            for i in range(0, n, parti):
                idx = sira[i:i + parti]
                Xb, yb = X[idx], y[idx]
                h, logit = self.ileri(Xb)
                logit -= logit.max(axis=1, keepdims=True)
                p = np.exp(logit); p /= p.sum(axis=1, keepdims=True)
                p[np.arange(len(yb)), yb] -= 1.0
                p /= len(yb)
                gW2 = h.T @ p; gb2 = p.sum(axis=0)
                gh = p @ self.W2.T; gh[h <= 0] = 0.0
                gW1 = Xb.T @ gh; gb1 = gh.sum(axis=0)
                self.vW2 = mom * self.vW2 - lr * gW2; self.W2 += self.vW2
                self.vb2 = mom * self.vb2 - lr * gb2; self.b2 += self.vb2
                self.vW1 = mom * self.vW1 - lr * gW1; self.W1 += self.vW1
                self.vb1 = mom * self.vb1 - lr * gb1; self.b1 += self.vb1

    def tahmin(self, X, gorulen):
        _, logit = self.ileri(X)
        maske = np.full(10, -1e9, dtype=np.float32)
        maske[list(gorulen)] = 0.0
        return np.argmax(logit + maske, axis=1)

def ruya_cesitle(img, adet):
    # ruyadan gercekci varyasyonlar: keskinlestir + kucuk kaydirmalar +
    # parlaklik oynamasi. Genis alan gurultusu YOK: gercek rakamlarda fon
    # parlamasi olmaz, ekleyince ag ruya/gercek ayrimini ogrenip sinavda
    # ruyada ogrendigini kullanamiyor (bunu deneyerek bulduk).
    keskin = np.clip((img - 0.25) * 2.2, 0.0, 1.0).reshape(28, 28)
    out = np.empty((adet, 784), dtype=np.float32)
    for k in range(adet):
        dy, dx = rng.integers(-2, 3), rng.integers(-2, 3)
        v = np.roll(np.roll(keskin, dy, axis=0), dx, axis=1)
        out[k] = (v * rng.uniform(0.85, 1.05)).ravel()
    return out

# ---------------- epizodik hipokampus: TEK vektor + stil yuvalari ----------------
sinif_anahtari = (rng.integers(0, 2, size=(10, D)) * 2 - 1).astype(np.int8)
yuva_anahtari = (rng.integers(0, 2, size=(YUVA, D)) * 2 - 1).astype(np.int8)

class Hipokampus:
    def __init__(self):
        self.M = np.zeros(D, dtype=np.float64)        # TEK bellek vektoru
        self.yuva_ort = {}                            # calisma ani: stil merkezleri
        self.yuva_n = {}

    def yaz(self, X, enc, rakam):
        # gunun ornekleri stil yuvalarina ayrilir (kucuk bir k-means,
        # hipokampusun pattern separation isinin kaba hali) ve her yuva
        # (rakam anahtari x yuva anahtari) ile baglanip TEK vektore yazilir
        merkez = X[rng.choice(len(X), YUVA, replace=False)].copy()
        for _ in range(4):
            uzaklik = ((X[:, None, :] - merkez[None, :, :]) ** 2).sum(axis=2)
            atama = uzaklik.argmin(axis=1)
            for j in range(YUVA):
                sec = atama == j
                if sec.any():
                    merkez[j] = X[sec].mean(axis=0)
        sayilar = np.bincount(atama, minlength=YUVA)
        self.yuva_n[rakam] = sayilar
        for j in range(YUVA):
            sec = atama == j
            if sec.any():
                bag = (sinif_anahtari[rakam] * yuva_anahtari[j]).astype(np.float64)
                self.M += bag * enc[sec].sum(axis=0)

    def hatirla(self, rakam, yuva):
        bag = (sinif_anahtari[rakam] * yuva_anahtari[yuva]).astype(np.float64)
        return (self.M * bag).astype(np.float32)

    def coz(self, rakam, yuva):
        # geri cagir -> piksel uzayina geri coz -> arka plani temizle
        r = self.hatirla(rakam, yuva)
        img = r @ projeksiyon.T / D                   # kaba ters projeksiyon
        img -= np.percentile(img, 60)
        img = np.clip(img, 0.0, None)
        m = img.max()
        if m < 1e-6:
            return None
        return (img / m) ** 1.3                       # kontrast toparlama

    def ruya_kalitesi(self, img, rakam, yuva):
        # ruyayi yeniden kodla, hipokampustaki aniyla tutarli mi?
        v = kodla(img[None, :])[0]
        r = self.hatirla(rakam, yuva)
        return float(v @ r / (np.linalg.norm(v) * np.linalg.norm(r) + 1e-9))

    def uyku_ruyalari(self, rakamlar, adet_per_yuva):
        # tum (rakam, yuva) anilarini geri coz, kaliteyi olc, gecenin medyan
        # kalitesine gore bozuklari ele, kalanlardan ruya uret
        adaylar = []
        for r in rakamlar:
            n = self.yuva_n[r]
            for j in range(YUVA):
                if n[j] < 20:
                    continue
                img = self.coz(r, j)
                if img is None:
                    continue
                adaylar.append((r, img, self.ruya_kalitesi(img, r, j), n[j]))
        if not adaylar:
            return np.zeros((0, 784), dtype=np.float32), np.zeros(0, dtype=np.int64)
        esik = KALITE_ORAN * float(np.median([a[2] for a in adaylar]))
        X, y = [], []
        for r, img, q, nj in adaylar:
            if q < esik:
                continue
            adet = max(1, int(round(adet_per_yuva * YUVA * nj / EGT_SINIF)))
            X.append(ruya_cesitle(img, adet))
            y.append(np.full(adet, r))
        return np.concatenate(X), np.concatenate(y)

    def hayal(self, rakam):
        # en dolu yuvanin geri cozumu (gorsellestirme icin)
        return self.coz(rakam, int(np.argmax(self.yuva_n[rakam])))

    def tahmin(self, enc, gorulen):
        # test ornegi hangi (rakam, yuva) anisina en cok benziyor?
        adaylar, etiket = [], []
        for r in gorulen:
            for j in range(YUVA):
                if self.yuva_n[r][j] < 20:
                    continue
                v = self.hatirla(r, j)
                nv = np.linalg.norm(v)
                if nv > 1e-6:
                    adaylar.append(v / nv)
                    etiket.append(r)
        A = np.stack(adaylar)
        skor = enc.astype(np.float32) @ A.T
        return np.array(etiket)[np.argmax(skor, axis=1)]

# ---------------- ascii gorsellestirme ----------------
def ascii_ciz(img28, genislik=28):
    palet = " .:-=+*#%@"
    img = img28.reshape(28, 28)
    satirlar = []
    for y in range(0, 28, 2):                 # dikeyde 2 satiri birlestir
        s = ""
        for x in range(28):
            v = (img[y, x] + img[min(y + 1, 27), x]) / 2
            s += palet[min(int(v * 9.99), 9)]
        satirlar.append(s)
    return satirlar

# ---------------- deney ----------------
ogrA = SinirAgi(1)
ogrB = Hipokampus()
ogrC = SinirAgi(2)
ogrC_hipo = Hipokampus()

print()
print("=" * 74)
print("  DENEY 6: GERCEK VERI (el yazisi rakamlar)")
print("  5 gunluk akis, her gun 2 yeni rakam, aksamlari genel sinav")
print("=" * 74)

sonuc = {k: np.full((5, 5), np.nan) for k in "ABC"}
gorulen = []
t0 = time.perf_counter()

for gun, rakamlar in enumerate(GUNLER):
    gorulen.extend(rakamlar)

    X = np.concatenate([egt_X[r] for r in rakamlar])
    y = np.concatenate([egt_y[r] for r in rakamlar])
    karistir = rng.permutation(len(X))
    X, y = X[karistir], y[karistir]
    enc = kodla(X)

    # gunduz
    ogrA.egit(X, y, EPOCH)
    ogrC.egit(X, y, EPOCH)                    # A ile birebir ayni egitim
    for r in rakamlar:
        sec = y == r
        ogrB.yaz(X[sec], enc[sec], r)
        ogrC_hipo.yaz(X[sec], enc[sec], r)

    # gece: C uyuyor. Bellek konsolidasyonu iki kaynaktan beslenir:
    #   eski gunler -> hipokampus ruyalari (oze inmis, bulanik anilar)
    #   bugun       -> taze epizodik bellek (henuz tam cozunurlukte)
    eski = [r for r in gorulen if r not in rakamlar]
    ruya_X, ruya_y = ogrC_hipo.uyku_ruyalari(eski, RUYA_YUVA)
    taze_sec = np.concatenate([rng.choice(np.where(y == r)[0], 200, replace=False) for r in rakamlar])
    gece_X = np.concatenate([ruya_X, X[taze_sec]])
    gece_y = np.concatenate([ruya_y, y[taze_sec]])
    if DEBUG:
        sayim = {r: int((gece_y == r).sum()) for r in gorulen}
        print(f"    [debug] gece tekrari -> {sayim} (bugunkuler taze, eskiler ruya)")
    ogrC.egit(gece_X, gece_y, EPOCH)

    # aksam sinavi
    for g in range(gun + 1):
        tx = np.concatenate([tst_X[r] for r in GUNLER[g]])
        ty = np.concatenate([tst_y[r] for r in GUNLER[g]])
        tenc = kodla(tx)
        sonuc["A"][gun, g] = (ogrA.tahmin(tx, gorulen) == ty).mean()
        sonuc["B"][gun, g] = (ogrB.tahmin(tenc, gorulen) == ty).mean()
        sonuc["C"][gun, g] = (ogrC.tahmin(tx, gorulen) == ty).mean()

    ort = {k: np.nanmean(sonuc[k][gun, :gun + 1]) * 100 for k in "ABC"}
    print(f"\n  GUN {gun + 1} bitti  (rakamlar: {gorulen})")
    print(f"  genel ortalama ->  A: %{ort['A']:.0f}   B: %{ort['B']:.0f}   C: %{ort['C']:.0f}")

# ideal dunya: tum veriyi ayni anda goren ag (hile, ust sinir)
ideal = SinirAgi(3)
tumX = np.concatenate([egt_X[r] for r in range(10)])
tumy = np.concatenate([egt_y[r] for r in range(10)])
kar = rng.permutation(len(tumX))
ideal.egit(tumX[kar], tumy[kar], EPOCH)
tX = np.concatenate([tst_X[r] for r in range(10)])
tY = np.concatenate([tst_y[r] for r in range(10)])
ideal_acc = (ideal.tahmin(tX, range(10)) == tY).mean()

sure = time.perf_counter() - t0

# ---------------- rapor ----------------
print()
print("=" * 74)
print("  SONUC 1: 1. GUNUN RAKAMLARININ (0 ve 1) AKIBETI")
print("=" * 74)
print()
print(f"  {'':14}" + "".join(f"Gün {g+1:>2}   " for g in range(5)))
for ad, k in [("A klasik", "A"), ("B holografik", "B"), ("C hibrit", "C")]:
    satir = "".join(f"%{sonuc[k][g, 0]*100:5.1f}  " for g in range(5))
    print(f"  {ad:<14}{satir}")

print()
print("=" * 74)
print("  SONUC 2: SON GUN GENEL SINAVI (10 rakamin tamami, gercek test seti)")
print("=" * 74)
print()
for ad, k in [("A klasik", "A"), ("B holografik", "B"), ("C hibrit", "C")]:
    notlar = sonuc[k][4] * 100
    ort = np.nanmean(notlar)
    cubuk = "█" * int(round(ort * 0.4))
    print(f"  {ad:<14} {cubuk:<42} ort %{ort:5.1f}")
cubuk = "█" * int(round(ideal_acc * 100 * 0.4))
print(f"  {'IDEAL (hile)':<14} {cubuk:<42} ort %{ideal_acc*100:5.1f}   <- tum veriyi ayni anda gordu")

# ruya gorsellestirme: hipokampusun 5 gun sonra "3" ruyasi
print()
print("=" * 74)
print("  C'NIN RUYASI: hipokampustaki tek vektorden geri cozulen '3' anisi")
print(f"  (solda gercek bir 3, sagda {D*8/1024:.0f} KB'lik bellekten dogan ruya)")
print("=" * 74)
print()
gercek3 = tst_X[3][0]
ruya3 = ogrC_hipo.hayal(3)
sol = ascii_ciz(gercek3)
sag = ascii_ciz(ruya3)
for a, b in zip(sol, sag):
    print(f"   {a}     {b}")

hafiza_kb = D * 8 / 1024
veri_mb = 10 * EGT_SINIF * 784 * 4 / (1024 * 1024)
print()
print("=" * 74)
print("  KUNYE")
print("=" * 74)
print(f"  Toplam sure            : {sure:.1f} saniye (CPU)")
print(f"  Egitim verisi          : {10 * EGT_SINIF:,} gercek el yazisi ornegi (~{veri_mb:.0f} MB)".replace(",", "."))
print(f"  C'nin hipokampusu      : TEK vektor, {hafiza_kb:.0f} KB ({YUVA} stil yuvasi x 10 rakam)")
print(f"  A ile C'nin TEK farki  : C geceleri ruya goruyor")
print()
print("Okuma rehberi:")
print("  * A gercek veride de coktu: sadece son gunu biliyor.")
print("  * C'nin uykusu asil gorevini yapti: 1. gunun rakamlari 5 gun sonra")
print("    hala buyuk olcude hatirlaniyor (A'da %0). Ama toplamda C da B de")
print("    IDEAL'in cok altinda, cunku ruyalar bulanik: yuva ortalamalari")
print("    4/9, 3/5/8 gibi ince ayrimlari tasiyamiyor.")
print("  * DURUST BULGU: gercek veride darbogaz unutma degil, RUYA SADAKATI.")
print("    Tek vektorun kapasitesi ile ani sadakati arasindaki takas, bu")
print("    deneyin duvara carparak kesfettigi gercek sinir. Literaturdeki")
print("    'generative replay' arastirmalari da tam bu duvarda ugrasiyor;")
print("    bir gunde, evdeki bilgisayarda, alanin gercek acik problemine")
print("    vardik. Sonraki adim belli: daha sadik ruya ureten bellek.")
print("  * Yine de ruyaya bak: yuz binlerce sayinin arasindan, tek vektorden")
print("    '3' fikrinin hayaleti geri cikiyor. Superpozisyon gercek dunyada")
print("    da calisiyor; sadece cozunurlugu henuz yetmiyor.")
print()

7_backpropsuz.py

Forward-Forward algoritmasının Türkçe cümlelerle dört perdelik sınavı.

Python553 satır
# -*- coding: utf-8 -*-
# DENEY 7: BACKPROP'SUZ OGRENME (Forward-Forward, Turkce cumlelerle)
#
# Saldirdigimiz varsayim: "ogrenme = backprop". Backprop tum katmanlarin
# kilitli senkron calismasini ister, her ara degeri hafizada tutar ve
# turevlenemeyen tek bir islemde zincir kopar. Beyin bunlarin hicbirini
# yapmiyor. Hinton'in Forward-Forward'i (2022) alternatifi: geri gecis yok,
# iki ILERI gecis var. Her katman KENDI BASINA ogrenir:
#   gercek veri (dogru etiketli)   -> "iyilik" puanini yukselt
#   sahte veri (yanlis etiketli)   -> "iyilik" puanini dusur
#
# Veri: 6 konuda Turkce cumleler (spor, ekonomi, saglik, teknoloji,
# yemek, doga). Kodlayici: deney 4'un trigram hipervektorleri.
#
# Dort perde:
#   1) Yaris    : backprop vs Forward-Forward, ayni ag, ayni veri
#   2) Sabotaj  : katmanlar arasina turevsiz kara kutu -> backprop olur, FF olmez
#   3) Kopukluk : FF katmanlari sirayla, birbirinden habersiz egitilir
#   4) Ruya     : FF'in sahte verisi deney 2'nin holografik ruyalarindan

import sys
import time
import numpy as np

rng = np.random.default_rng(7070)

D = 4096             # cumle hipervektoru boyutu
GIZLI = 256          # ana deney gizli katman
GIZLI_KUCUK = 32     # sabotaj deneyi gizli katman (dar bogaz, katman 1 onemli olsun)
ETIKET_GUC = 0.25    # etiketin girdiye gomulme siddeti
ESIK = 2.0           # FF iyilik esigi
FF_EPOCH = 150
BP_EPOCH = 250
TURETME = 400        # konu basina turetilen sentetik egitim cumlesi

# ---------------------------------------------------------------- veri
KONULAR = {
    "spor": (
        ["Takım dün akşamki maçta rakibini üç golle mağlup etti.",
         "Hakem penaltı noktasını gösterince tribünler ayağa kalktı.",
         "Milli takım kampı bu yıl yüksek irtifada yapılacak.",
         "Transfer döneminde kulüp iki yeni oyuncuyla anlaştı.",
         "Sakatlığını atlatan kaptan ilk on birdeki yerini aldı.",
         "Şampiyonluk yarışı son haftaya kadar sürecek gibi görünüyor.",
         "Antrenör basın toplantısında oyun planını savundu.",
         "Basketbol takımımız son çeyrekte farkı kapatıp öne geçti.",
         "Maratonda dereceye giren sporcular madalyalarını aldı.",
         "Kaleci uzatma dakikalarında inanılmaz bir kurtarışa imza attı.",
         "Voleybolda filenin sultanları seriyi üç sıfır kazandı.",
         "Genç oyuncu attığı harika golle taraftarın sevgilisi oldu.",
         "Derbi öncesi biletler saatler içinde tükendi.",
         "Teknik direktör savunmadaki hataların üzerinde çalıştıklarını söyledi.",
         "Yüzücümüz kendi rekorunu kırarak finale yükseldi.",
         "Ligin ilk yarısı namağlup tamamlanırsa tarih yazılmış olacak.",
         "Orta saha oyuncusu kırmızı kart görünce takım on kişi kaldı.",
         "Tenis turnuvasının final maçı beş sete uzadı.",
         "Kulüp başkanı yeni stadın açılış tarihini duyurdu.",
         "Güreşçimiz finalde rakibini tuşla yenerek altın madalya kazandı."],
        ["Kupa maçında kaleci üç önemli kurtarışa imza attı.",
         "Antrenör derbi öncesi oyuncularının sakatlık durumunu açıkladı.",
         "Takım şampiyonluk yarışında rakibine puan farkını açtı.",
         "Genç forvet transfer döneminde kulüple sözleşme imzaladı.",
         "Basketbol maçı son çeyrekte uzatmaya gitti.",
         "Tribünler golden sonra takımına destek verdi."]),
    "ekonomi": (
        ["Merkez bankası faiz kararını bu perşembe açıklayacak.",
         "Dolar kuru haftaya yatay bir seyirle başladı.",
         "Enflasyon rakamları beklentilerin üzerinde geldi.",
         "Borsa güne yüzde iki yükselişle açıldı.",
         "İhracat rakamları geçen yıla göre artış gösterdi.",
         "Asgari ücret görüşmeleri aralık ayında başlayacak.",
         "Altın fiyatları küresel piyasalardaki belirsizlikle yükseldi.",
         "Şirketin üçüncü çeyrek bilançosu kar açıkladı.",
         "Bütçe görüşmeleri meclis genel kurulunda devam ediyor.",
         "Yatırımcılar gözünü istihdam verilerine çevirdi.",
         "Petrol fiyatlarındaki düşüş pompaya indirim olarak yansıdı.",
         "Bankalar konut kredisi faizlerini aşağı çekti.",
         "Vergi düzenlemesi küçük esnafa muafiyet getiriyor.",
         "Kira artış oranı yeniden değerleme rakamına endekslendi.",
         "Ekonomistler yıl sonu büyüme tahminlerini revize etti.",
         "Cari açık verisi piyasalarda karşılık buldu.",
         "Tahvil getirileri son ayların en yüksek seviyesini gördü.",
         "Perakende satışlar bayram etkisiyle canlandı.",
         "Kripto para piyasasında sert dalgalanmalar yaşandı.",
         "Yeni teşvik paketi sanayi yatırımlarını hedefliyor."],
        ["Merkez bankası enflasyon beklentilerini yukarı revize etti.",
         "Dolar ve altın haftayı yükselişle kapattı.",
         "Borsa faiz kararı öncesinde yatay seyretti.",
         "Bankalar taşıt kredisi faizlerini indirdi.",
         "İhracat ve istihdam verileri piyasaları hareketlendirdi.",
         "Yatırımcılar bütçe görüşmelerini yakından takip ediyor."]),
    "sağlık": (
        ["Doktor hastaya bol sıvı tüketmesini önerdi.",
         "Grip vakaları soğukların artmasıyla yükselişe geçti.",
         "Düzenli yürüyüş kalp sağlığını koruyor.",
         "Aşı takvimine uymak çocukları ağır hastalıklardan koruyor.",
         "Uzmanlar günde en az yedi saat uyku öneriyor.",
         "Ameliyat sonrası iyileşme süreci beklenenden hızlı ilerledi.",
         "Sağlıklı beslenme bağışıklık sistemini güçlendiriyor.",
         "Yüksek tansiyon sessiz ilerleyen bir hastalıktır.",
         "Diş hekimi altı ayda bir kontrol muayenesi tavsiye etti.",
         "Hastanenin yeni yoğun bakım servisi hizmete açıldı.",
         "Fazla şeker tüketimi karaciğeri yoruyor.",
         "Fizik tedavi seansları bel ağrısını hafifletti.",
         "Kan bağışı kampanyasına yoğun katılım oldu.",
         "Erken teşhis kanser tedavisinde hayat kurtarıyor.",
         "Mevsim geçişlerinde alerjik şikayetler artabiliyor.",
         "Eczaneler nöbet çizelgesine göre hizmet veriyor.",
         "Göz kuruluğuna karşı ekran molaları öneriliyor.",
         "Hamilelikte folik asit takviyesi önem taşıyor.",
         "Aile hekimi düzenli kan tahlili yaptırmayı önerdi.",
         "Stres yönetimi migren ataklarını azaltabiliyor."],
        ["Doktor düzenli uyku ve sağlıklı beslenme önerdi.",
         "Grip aşısı için hastaneye başvurular arttı.",
         "Erken teşhis tedavi sürecini kısaltıyor.",
         "Fizik tedavi hastanın bel ağrılarını azalttı.",
         "Uzmanlar şeker tüketimini azaltmayı tavsiye ediyor.",
         "Kan tahlili sonuçları vitamin eksikliğini gösterdi."]),
    "teknoloji": (
        ["Yeni telefon modeli katlanabilir ekranla geliyor.",
         "Yapay zeka destekli asistan toplantı notlarını özetliyor.",
         "Şirket bulut sunucularını yenilenebilir enerjiyle çalıştırıyor.",
         "Güncelleme bataryanın şarj ömrünü uzatıyor.",
         "Yazılımcılar açık kaynak projeye gönüllü katkı veriyor.",
         "İşlemci üreticisi üç nanometre çipini tanıttı.",
         "Elektrikli araç tek şarjla altı yüz kilometre gidiyor.",
         "Siber saldırı girişimi güvenlik duvarına takıldı.",
         "Oyun konsolunun yeni sürümü rekor satışla açıldı.",
         "Uydu interneti kırsal bölgelere yüksek hız getirdi.",
         "Akıllı saat kalp ritmindeki düzensizliği tespit edebiliyor.",
         "Robot süpürge haritalama özelliğiyle odaları öğreniyor.",
         "Veri merkezinin soğutması deniz suyuyla sağlanıyor.",
         "Tarayıcıya gelen özellik reklam izleyicilerini engelliyor.",
         "Drone ile kargo teslimatı pilot bölgede denendi.",
         "Kuantum bilgisayar araştırmaları yeni bir aşamaya geçti.",
         "Sanal gerçeklik gözlüğü eğitim simülasyonlarında kullanılıyor.",
         "Şifre yerine parmak izi ile giriş yaygınlaşıyor.",
         "Grafik kartı fiyatları yeni nesille birlikte düştü.",
         "Otonom sürüş yazılımı şehir içi testlere başladı."],
        ["Yeni işlemci yapay zeka hesaplamalarını hızlandırıyor.",
         "Telefonun güncellemesi batarya sorununu çözdü.",
         "Siber güvenlik yazılımı saldırıyı anında engelledi.",
         "Elektrikli araçların şarj altyapısı genişliyor.",
         "Akıllı saat uyku ve kalp verilerini kaydediyor.",
         "Bulut sunucularına yeni güvenlik katmanı eklendi."]),
    "yemek": (
        ["Mercimek çorbasına bir tutam nane çok yakışır.",
         "Hamuru mayalanmaya ılık bir yerde bırakın.",
         "Kebabın yanında közlenmiş biber servis edildi.",
         "Baklavanın şerbeti soğuk dökülürse çıtır kalır.",
         "Zeytinyağlı yaprak sarma sabırla sarılır.",
         "Fırından yeni çıkan ekmeğin kokusu sokağı sardı.",
         "Menemene soğan koyup koymamak hep tartışma konusu.",
         "Pilavın suyu ölçülü olursa tane tane olur.",
         "Mantı hamuru ince açıldıkça lezzeti artar.",
         "Balığın yanına roka ve limon eklendi.",
         "Kek kalıbını önceden yağlamayı unutmayın.",
         "Turşu kurarken kaya tuzu tercih edilmeli.",
         "İmam bayıldı zeytinyağlıların şahıdır.",
         "Kahvaltıda sofraya sıcak poğaça geldi.",
         "Et haşlanırken köpüğünü almak gerekir.",
         "Salataya nar ekşisi ekşi bir tat katar.",
         "Yoğurdun mayası akşamdan çalınır.",
         "Köftenin harcına bayat ekmek içi konur.",
         "Şerbetli tatlılar bayram sofralarının vazgeçilmezi.",
         "Sebzeleri buharda pişirmek vitaminleri korur."],
        ["Çorbaya nane ve limon eklemeyi unutmayın.",
         "Fırında pişen ekmeğin kokusu mutfağı sardı.",
         "Zeytinyağlı sarma sofranın yıldızı oldu.",
         "Hamur mayalandıktan sonra ince açılır.",
         "Kebap közlenmiş biber ve pilavla servis edildi.",
         "Şerbeti soğuk dökülen baklava çıtır oldu."]),
    "doğa": (
        ["Yarın kuzey bölgelerde sağanak yağış bekleniyor.",
         "Hafta sonu sıcaklıklar mevsim normallerinin üzerine çıkacak.",
         "Dağların zirvesine mevsimin ilk karı düştü.",
         "Lodos nedeniyle boğaz hattındaki seferler iptal edildi.",
         "Göl kıyısındaki kuş cenneti göçmen kuşları ağırlıyor.",
         "Şiddetli rüzgar bazı bölgelerde ağaçları devirdi.",
         "Kuraklık barajlardaki doluluk oranını düşürdü.",
         "Sabah saatlerinde yoğun sis görüş mesafesini azalttı.",
         "İlkbaharla birlikte yaylalar rengarenk çiçeklerle kaplandı.",
         "Meteoroloji beş il için sarı kodlu uyarı yayımladı.",
         "Orman yangını ekiplerin müdahalesiyle kontrol altına alındı.",
         "Gece sıcaklığı sıfırın altına düşünce yollar buzlandı.",
         "Deprem sonrası artçı sarsıntılar devam etti.",
         "Nehrin debisi eriyen karlarla birlikte yükseldi.",
         "Sahillerde deniz suyu sıcaklığı yirmi dereceyi aştı.",
         "Dolu yağışı seralarda hasara yol açtı.",
         "Kelebek vadisi ziyaretçilerine görsel şölen sunuyor.",
         "Ay tutulması gece yarısı çıplak gözle izlendi.",
         "Şehirde hava kirliliği kış aylarında artıyor.",
         "Milli parktaki geyik sayısı korumayla birlikte arttı."],
        ["Meteoroloji hafta sonu için sağanak yağış uyarısı yaptı.",
         "Şiddetli lodos deniz seferlerini aksattı.",
         "Barajlardaki doluluk oranı yağışlarla birlikte yükseldi.",
         "Zirvelere düşen kar yolları ulaşıma kapattı.",
         "Yoğun sis sabah saatlerinde trafiği yavaşlattı.",
         "Orman yangını rüzgarın etkisiyle büyüdü."]),
}
SINIF = list(KONULAR.keys())
C = len(SINIF)

# ------------------------------------------------ kodlayici
# Deney 4'un harf-uclusu kodlamasi DIL ayirt etmek icindi; burada tum
# cumleler Turkce, konu bilgisi KELIMELERDE. O yuzden: kelime tabanli
# hipervektorler (Turkce ekler icin kaba kok kirpma) + morfoloji koprusu
# olarak dusuk agirlikli trigram karisimi.
import zlib

_harf, _kelime = {}, {}

def harf(c):
    if c not in _harf:
        r = np.random.default_rng(1_000_003 + ord(c))
        _harf[c] = (r.integers(0, 2, size=D) * 2 - 1).astype(np.int8)
    return _harf[c]

def kelime_vek(w):
    if w not in _kelime:
        r = np.random.default_rng(zlib.crc32(w.encode("utf-8")))
        _kelime[w] = (r.integers(0, 2, size=D) * 2 - 1).astype(np.float32)
    return _kelime[w]

def kodla(cumle):
    m = "".join(c if (c.isalpha() or c == " ") else " " for c in cumle.lower())
    m = " ".join(m.split())
    kelimeler = [w[:6] for w in m.split()]       # kaba kok: ilk 6 harf
    vk = np.zeros(D, dtype=np.float32)
    for w in kelimeler:
        vk += kelime_vek(w)
    H = np.stack([harf(c) for c in m]).astype(np.int32)
    tri = (np.roll(H[:-2], 2, axis=1) * np.roll(H[1:-1], 1, axis=1) * H[2:])
    vt = tri.sum(axis=0).astype(np.float32)
    v = vk / (np.linalg.norm(vk) + 1e-9) + 0.4 * vt / (np.linalg.norm(vt) + 1e-9)
    v[:C] = 0.0                                  # ilk 6 boyut etiket yuvasi
    return v / (np.linalg.norm(v) + 1e-9)

def etiket_gom(X, y):
    X = X.copy()
    X[np.arange(len(X)), y] = ETIKET_GUC
    return X

gercekX = np.stack([kodla(s) for k in SINIF for s in KONULAR[k][0]])
gercekY = np.array([i for i, k in enumerate(SINIF) for _ in KONULAR[k][0]])
teX = np.stack([kodla(s) for k in SINIF for s in KONULAR[k][1]])
teY = np.array([i for i, k in enumerate(SINIF) for _ in KONULAR[k][1]])

# Veri turetme: 120 el yazmasi cumle iki ogrenciye de az. Her konunun
# kelime havuzundan rastgele "cumleler" turetiyoruz; torba-kelime
# kodlamasinda bu, konunun soz dagarcigini ogretmenin dogal yolu.
turet_X, turet_y = [], []
for i, k in enumerate(SINIF):
    havuz = list({w for s in KONULAR[k][0]
                  for w in "".join(c if (c.isalpha() or c == " ") else " " for c in s.lower()).split()})
    for _ in range(TURETME):
        n = int(rng.integers(4, 9))
        secim = [havuz[j] for j in rng.integers(0, len(havuz), n)]
        turet_X.append(kodla(" ".join(secim)))
        turet_y.append(i)
trX = np.concatenate([gercekX, np.stack(turet_X)])
trY = np.concatenate([gercekY, np.array(turet_y)])

# ------------------------------------------------ backprop agi (referans)
class BackpropAgi:
    def __init__(self, gizli, seed, kara_kutu=None):
        r = np.random.default_rng(seed)
        self.kk = kara_kutu
        self.W1 = (r.standard_normal((D, gizli)) / np.sqrt(D)).astype(np.float32)
        self.b1 = np.zeros(gizli, dtype=np.float32)
        self.W2 = (r.standard_normal((gizli, gizli)) / np.sqrt(gizli)).astype(np.float32)
        self.b2 = np.zeros(gizli, dtype=np.float32)
        self.W3 = (r.standard_normal((gizli, C)) / np.sqrt(gizli)).astype(np.float32)
        self.b3 = np.zeros(C, dtype=np.float32)

    def ileri(self, X):
        h1 = np.maximum(0, X @ self.W1 + self.b1)
        z = self.kk(h1) if self.kk else h1
        h2 = np.maximum(0, z @ self.W2 + self.b2)
        return h1, z, h2, h2 @ self.W3 + self.b3

    def egit(self, X, y, epoch, lr=0.1, mom=0.9):
        v = [np.zeros_like(p) for p in (self.W1, self.b1, self.W2, self.b2, self.W3, self.b3)]
        son_g1 = 0.0
        for _ in range(epoch):
            h1, z, h2, logit = self.ileri(X)
            logit -= logit.max(axis=1, keepdims=True)
            p = np.exp(logit); p /= p.sum(axis=1, keepdims=True)
            p[np.arange(len(y)), y] -= 1.0
            p /= len(y)
            gW3 = h2.T @ p; gb3 = p.sum(axis=0)
            gh2 = p @ self.W3.T; gh2[h2 <= 0] = 0
            gW2 = z.T @ gh2; gb2 = gh2.sum(axis=0)
            gz = gh2 @ self.W2.T
            # kara kutu varsa STANDART zincir kurali burada kopar: round'un
            # turevi sifir. (straight-through estimator gibi yaklasik cozumler
            # literaturde var; bu deneyde bilerek kapsam disi.)
            gh1 = np.zeros_like(gz) if self.kk else gz
            gh1 = gh1.copy(); gh1[h1 <= 0] = 0
            gW1 = X.T @ gh1; gb1 = gh1.sum(axis=0)
            son_g1 = float(np.abs(gW1).mean())
            for vel, par, g in zip(v, (self.W1, self.b1, self.W2, self.b2, self.W3, self.b3),
                                   (gW1, gb1, gW2, gb2, gW3, gb3)):
                vel *= mom; vel -= lr * g
                par += vel
        return son_g1

    def dogruluk(self, X, y):
        return float((np.argmax(self.ileri(X)[3], axis=1) == y).mean())

# ------------------------------------------------ Forward-Forward katmani
class FFKatman:
    # Kendi basina ogrenen katman: disaridan gradyan ALMAZ, gradyan VERMEZ.
    def __init__(self, girdi, cikti, seed, lr=0.02):
        r = np.random.default_rng(seed)
        self.W = (r.standard_normal((girdi, cikti)) / np.sqrt(girdi)).astype(np.float32)
        self.b = np.zeros(cikti, dtype=np.float32)
        self.lr = lr
        self.mW = np.zeros_like(self.W); self.vW = np.zeros_like(self.W)
        self.mb = np.zeros_like(self.b); self.vb = np.zeros_like(self.b)
        self.t = 0

    def ileri(self, X):
        return np.maximum(0, X @ self.W + self.b)

    def iyilik(self, X):
        h = self.ileri(X)
        return (h * h).sum(axis=1)

    def _adam(self, gW, gb):
        self.t += 1
        for g, m, v, p in ((gW, self.mW, self.vW, self.W), (gb, self.mb, self.vb, self.b)):
            m *= 0.9; m += 0.1 * g
            v *= 0.999; v += 0.001 * g * g
            mh = m / (1 - 0.9 ** self.t)
            vh = v / (1 - 0.999 ** self.t)
            p -= self.lr * mh / (np.sqrt(vh) + 1e-8)

    def ogren(self, Xpos, Xneg):
        # YEREL kural: pozitifte iyiligi esigin ustune, negatifte altina it.
        # Buradaki turev sadece BU katmanin icinde: baska katman bilmiyor.
        gW = np.zeros_like(self.W); gb = np.zeros_like(self.b)
        for X, isaret in ((Xpos, 1.0), (Xneg, -1.0)):
            h = self.ileri(X)
            g = (h * h).sum(axis=1)
            s = 1.0 / (1.0 + np.exp(np.clip(isaret * (g - ESIK), -30, 30)))
            dh = (-isaret * s)[:, None] * 2 * h / len(X)
            gW += X.T @ dh
            gb += dh.sum(axis=0)
        self._adam(gW, gb)
        return None

def normalize(h):
    return h / (np.linalg.norm(h, axis=1, keepdims=True) + 1e-9)

def ff_egit(katmanlar, Xpos, Xneg, epoch, kara_kutu=None):
    # KOPUK egitim: katman 1 tamamen bitmeden katman 2 BASLAMIYOR.
    # Katman 2, katman 1'e hicbir sinyal gondermiyor: sadece veri akiyor.
    P, N = Xpos, Xneg
    for i, kat in enumerate(katmanlar):
        for _ in range(epoch):
            kat.ogren(P, N)
        P2, N2 = kat.ileri(P), kat.ileri(N)
        if kara_kutu is not None and i == 0:
            P2, N2 = kara_kutu(P2), kara_kutu(N2)
        P, N = normalize(P2), normalize(N2)

def ff_dogruluk(katmanlar, X, y, kara_kutu=None):
    n = len(X)
    puan = np.zeros((n, C), dtype=np.float32)
    for c in range(C):
        G = etiket_gom(X, np.full(n, c))
        for i, kat in enumerate(katmanlar):
            puan[:, c] += kat.iyilik(G)
            G2 = kat.ileri(G)
            if kara_kutu is not None and i == 0:
                G2 = kara_kutu(G2)
            G = normalize(G2)
    return float((np.argmax(puan, axis=1) == y).mean())

def negatif_uret(X, y):
    # klasik FF negatifi: gercek cumle + YANLIS etiket
    yanlis = (y + rng.integers(1, C, size=len(y))) % C
    return etiket_gom(X, yanlis)

kara_kutu = lambda h: np.round(h * 2.0) / 2.0     # turevi olmayan islem

print()
print("=" * 74)
print("  DENEY 7: BACKPROP'SUZ ÖĞRENME (Forward-Forward, Türkçe cümleler)")
print(f"  Veri: 6 konu, {len(trX)} eğitim + {len(teX)} test cümlesi (hepsi Türkçe)")
print("=" * 74)

# ---------------- PERDE 1: yaris ----------------
t0 = time.perf_counter()
bp = BackpropAgi(GIZLI, seed=1)
bp.egit(trX, trY, BP_EPOCH)
bp_sure = time.perf_counter() - t0

t0 = time.perf_counter()
ff = [FFKatman(D, GIZLI, seed=11), FFKatman(GIZLI, GIZLI, seed=12)]
ff_egit(ff, etiket_gom(trX, trY), negatif_uret(trX, trY), FF_EPOCH)
ff_sure = time.perf_counter() - t0

print()
print("  PERDE 1: YARIŞ (aynı mimari: 4096 -> 256 -> 256)")
print("  " + "-" * 66)
print(f"  Backprop        : eğitim %{bp.dogruluk(trX, trY)*100:5.1f} | test %{bp.dogruluk(teX, teY)*100:5.1f} | {bp_sure:4.1f} sn")
print(f"  Forward-Forward : eğitim %{ff_dogruluk(ff, trX, trY)*100:5.1f} | test %{ff_dogruluk(ff, teX, teY)*100:5.1f} | {ff_sure:4.1f} sn")
print("  (FF'te geri geçiş YOK: her katman sadece kendi çıktısına baktı)")

# ---------------- PERDE 2: sabotaj ----------------
bp_temiz = BackpropAgi(GIZLI_KUCUK, seed=2)
bp_temiz.egit(trX, trY, BP_EPOCH)
bp_kutulu = BackpropAgi(GIZLI_KUCUK, seed=2, kara_kutu=kara_kutu)
son_gradyan = bp_kutulu.egit(trX, trY, BP_EPOCH)

ff_temiz = [FFKatman(D, GIZLI_KUCUK, seed=21), FFKatman(GIZLI_KUCUK, GIZLI_KUCUK, seed=22)]
ff_egit(ff_temiz, etiket_gom(trX, trY), negatif_uret(trX, trY), FF_EPOCH)
ff_kutulu = [FFKatman(D, GIZLI_KUCUK, seed=21), FFKatman(GIZLI_KUCUK, GIZLI_KUCUK, seed=22)]
ff_egit(ff_kutulu, etiket_gom(trX, trY), negatif_uret(trX, trY), FF_EPOCH, kara_kutu=kara_kutu)

print()
print("  PERDE 2: SABOTAJ (dar ağ: 4096 -> 32 -> 32, katmanlar arasına")
print("  türevi olmayan kara kutu kondu: sinyal kuantalanıyor)")
print("  " + "-" * 66)
print(f"  Backprop  temiz    : test %{bp_temiz.dogruluk(teX, teY)*100:5.1f}")
print(f"  Backprop  kutulu   : test %{bp_kutulu.dogruluk(teX, teY)*100:5.1f}   <- 1. katmana ulaşan gradyan: {son_gradyan:.8f}")
print(f"  FF        temiz    : test %{ff_dogruluk(ff_temiz, teX, teY)*100:5.1f}")
print(f"  FF        kutulu   : test %{ff_dogruluk(ff_kutulu, teX, teY, kara_kutu=kara_kutu)*100:5.1f}   <- FF kara kutuyu umursamadı")

# ---------------- PERDE 4: ruya negatifleri ----------------
sinif_anahtar = (rng.integers(0, 2, size=(C, D)) * 2 - 1).astype(np.float32)
M = np.zeros(D, dtype=np.float64)
for i in range(len(gercekX)):
    M += (gercekX[i] * sinif_anahtar[gercekY[i]]).astype(np.float64)

tum_kelimeler = list({w[:6] for k in SINIF for s in KONULAR[k][0]
                      for w in "".join(c if (c.isalpha() or c == " ") else " " for c in s.lower()).split()})

def ruya(c, adet):
    # Iki basarisiz denemeden sonra ogrenilen ders: ruyanin gurultusu bile
    # GERCEGIN DOKUSUNDA olmali. Gauss gurultusu ruyayi yapay bir kabuga
    # hapsediyor, ag o kabuga asiri uyum yapiyor ve gercek cumleye tasimiyor.
    # Simdi ruya = sinif anisi + rastgele GERCEK KELIME dokusu: yapisi
    # gercek bir cumleninkiyle ayni.
    r = (M * sinif_anahtar[c]).astype(np.float32)
    r = r / (np.linalg.norm(r) + 1e-9)
    G = np.empty((adet, D), dtype=np.float32)
    for i in range(adet):
        doku = np.zeros(D, dtype=np.float32)
        for j in rng.integers(0, len(tum_kelimeler), int(rng.integers(3, 8))):
            doku += kelime_vek(tum_kelimeler[j])
        doku /= np.linalg.norm(doku) + 1e-9
        agirlik = rng.uniform(0.4, 1.2)
        G[i] = agirlik * r + doku
    G = normalize(G)
    G[:, :C] = 0.0
    return G

# Ilk denememizde negatifleri ruyadan, pozitifleri gercekten verdik ve
# sistem COKTU (%0): ag "gercek mi ruya mi" kestirmesini ogrenip etiketi
# tamamen yok saydi. FF'in yasasi: negatif, pozitiften SADECE ogretmek
# istedigin boyutta farkli olmali. Cozum: pozitif de ruya olsun.
# Ag, gercek cumleyi HIC gormeden, sadece kendi ruyalariyla egitiliyor.
ruyaX_p, ruyaY_p, ruyaX_n = [], [], []
for c in range(C):
    adet = len(trX) // C
    ruyaX_p.append(ruya(c, adet))
    ruyaY_p.append(np.full(adet, c))
    ruyaX_n.append(ruya(c, adet))
ruyaX_p = np.concatenate(ruyaX_p); ruyaY_p = np.concatenate(ruyaY_p)
ruyaX_n = np.concatenate(ruyaX_n)
yanlis = (ruyaY_p + rng.integers(1, C, size=len(ruyaY_p))) % C

ff_ruya = [FFKatman(D, GIZLI, seed=31), FFKatman(GIZLI, GIZLI, seed=32)]
ff_egit(ff_ruya, etiket_gom(ruyaX_p, ruyaY_p), etiket_gom(ruyaX_n, yanlis), FF_EPOCH)

# olcumler: ruya-ici sinav, gercek sinav, ve ogrenmesiz taban cizgisi
ruya_teX = np.concatenate([ruya(c, 30) for c in range(C)])
ruya_teY = np.concatenate([np.full(30, c) for c in range(C)])
ruya_ici = ff_dogruluk(ff_ruya, ruya_teX, ruya_teY)
Rm = np.stack([(M * sinif_anahtar[c]).astype(np.float32) for c in range(C)])
Rm /= np.linalg.norm(Rm, axis=1, keepdims=True) + 1e-9
taban = float((np.argmax(teX @ Rm.T, axis=1) == teY).mean())

print()
print("  PERDE 4: SADECE RÜYAYLA ÖĞRENME (dürüst sonuç: henüz BAŞARISIZ)")
print("  " + "-" * 66)
print("  120 gerçek cümle TEK vektöre yazıldı ve kenara kondu. FF ağı gerçek")
print("  cümleyi HİÇ görmedi: pozitifi de negatifi de rüyalardan aldı.")
print(f"  FF (gerçek veriyle eğitilen)   : test %{ff_dogruluk(ff, teX, teY)*100:5.1f}")
print(f"  FF (sadece rüyayla eğitilen)   : rüya sınavı %{ruya_ici*100:5.1f} | gerçek test %{ff_dogruluk(ff_ruya, teX, teY)*100:5.1f}")
print(f"  En yakın rüya yönü (öğrenmesiz): gerçek test %{taban*100:5.1f}   <- sinyal bellekte VAR")
print("  Üç farklı rüya üretimi denendi (gauss, değişken yarıçap, kelime")
print("  dokusu); üçünde de ağ rüyayı ezberledi ama gerçeğe taşımadı.")

print()
print("=" * 74)
print("  OKUMA REHBERİ")
print("=" * 74)
print("  * PERDE 1: FF, backprop'suz öğrendi. Ağ boyunca geri geçiş yok; her")
print("    katman kendi 'iyilik' puanıyla baş başa. Terim notu: katman KENDİ")
print("    yerel hedefinin türevini kullanmaya devam ediyor; doğru terim")
print("    'gradyansız' değil 'backprop'suz'. Ayrıca test kümesi 36 cümle,")
print("    her cümle ~2.8 puan; küçük farklara istatistiksel anlam yükleme.")
print("  * PERDE 2: asıl gösteri. Kara kutu backprop'un gradyanını SIFIRLADI,")
print("    1. katman ölü doğdu. FF fark bile etmedi, çünkü hiçbir katman")
print("    diğerinin içini görmek zorunda değil. Kusurlu/analog/ucuz donanımda")
print("    öğrenmenin kapısı bu (Hinton'ın 'mortal computation' hayali).")
print("  * PERDE 3 aslında hep sahnedeydi: FF katmanları SIRAYLA eğitildi;")
print("    katman 2 başladığında katman 1 çoktan emekliye ayrılmıştı ve")
print("    katman 1'e tek bir bayt bile geri dönmedi. Eğitim, senkron tek")
print("    parça bir canavar olmak zorunda değil: katmanlar ayrı makinelere,")
print("    ilkece internete bile dağıtılabilir.")
print("  * PERDE 4 çuvalladı ve bu, deneyin en öğretici sonucu: bellekteki")
print("    sinyal gerçek testi öğrenmesiz %86 sınıflandırmaya yetiyor, FF")
print("    rüya sınavını %98 geçiyor, ama rüyada öğrendiği özellikler gerçeğe")
print("    TRANSFER OLMUYOR. FF, pozitif/negatifi ayıran EN KOLAY özelliği")
print("    seçiyor; o özellik çoğu zaman istediğimiz kavram değil, üretimin")
print("    bir yan izi. Deney 6'nın dersi üçüncü kez başka kılıkta karşımıza")
print("    çıktı: üretilen deneyim gerçeğin dağılımında değilse, öğrenilen")
print("    şey gerçeğe geçmiyor. Açık problem olarak kayıtlara geçti.")
print("  * DÜRÜST NOT: bu kolay bir görev ve FF backprop'tan yavaş ve nazlı.")
print("    Büyük ölçekte FF'in backprop'u yakalayıp yakalayamayacağı açık")
print("    araştırma sorusu. Buradaki iddia 'daha iyi' değil: 'başka bir yol")
print("    VAR' ve o yol veri merkezine mahkum değil.")
print()

# ---------------- canli test: kendi cumleni dene ----------------
if len(sys.argv) > 1:
    girdi = " ".join(sys.argv[1:])
    v = kodla(girdi)[None, :]
    bp_tahmin = SINIF[int(np.argmax(bp.ileri(v)[3][0]))]
    puan = np.zeros(C, dtype=np.float32)
    for c in range(C):
        G = etiket_gom(v, np.array([c]))
        for kat in ff:
            puan[c] += float(kat.iyilik(G)[0])
            G = normalize(kat.ileri(G))
    sira = np.argsort(-puan)
    p = puan - puan.min()
    p = p / (p.max() + 1e-9)
    print("=" * 74)
    print(f"  CANLI TEST: \"{girdi}\"")
    print("=" * 74)
    print(f"  Backprop tahmini        : {bp_tahmin}")
    print(f"  Forward-Forward tahmini : {SINIF[sira[0]]}")
    print("  FF iyilik puanları (aday konu başına):")
    for c in sira:
        cubuk = "█" * int(round(p[c] * 30))
        print(f"    {SINIF[c]:<10} {cubuk} {puan[c]:.1f}")
    print()

Yorumlar

Bu form reCAPTCHA ile korunur; Google Gizlilik Politikası ve Hizmet Şartları geçerlidir.

İlk yorumu sen yap.

İlgili Yazılar