Quanta / quanta_sim_v2_input_dep.py
NextGenC's picture
Upload 11 files
8e35b08 verified
raw
history blame contribute delete
10.6 kB
# quanta_sim_v2_input_dep.py
import neat
import numpy as np
import os
import logging
import pickle
import random
import math
import datetime
# Görselleştirme importları YOKTUR.
# --- Loglama Ayarları ---
log_filename = f"quanta_log_v2_input_dep_{datetime.datetime.now():%Y%m%d_%H%M%S}.log" # <-- V2 için dosya adı
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s',
handlers=[
logging.FileHandler(log_filename),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
logger.info("="*50)
logger.info("Quanta Simülatörü Başlatılıyor (Sürüm 2 - Girdiye Bağlı Olasılık)") # <-- GÜNCELLENDİ
logger.info("="*50)
# --- Simülasyon Parametreleri ---
# TARGET_PROB_0 artık sabit değil, girdiye göre hesaplanacak.
# Bu yüzden aşağıdaki satırları kaldırabilir veya yorum satırı yapabiliriz.
# TARGET_PROB_0 = 0.7
# TARGET_PROB_1 = 1.0 - TARGET_PROB_0
NUM_TEST_INPUTS = 6 # Farklı girdi değerlerini test etmek için kullanılacak girdi sayısı
NUM_TRIALS_PER_INPUT = 20 # Her bir girdi değeri için yapılacak deneme sayısı
# Toplam deneme sayısı = NUM_TEST_INPUTS * NUM_TRIALS_PER_INPUT (örn: 6 * 20 = 120)
MAX_GENERATIONS = 100 # <-- Gerekirse artırılabilir, problem biraz daha zorlaştı.
FITNESS_THRESHOLD = 0.98 # <-- Hedef biraz daha zor olduğu için eşiği hafifçe düşürebiliriz (isteğe bağlı)
logger.info(f"Test Edilecek Girdi Sayısı: {NUM_TEST_INPUTS}")
logger.info(f"Girdi Başına Deneme Sayısı: {NUM_TRIALS_PER_INPUT}")
logger.info(f"Toplam Değerlendirme Denemesi/Genom: {NUM_TEST_INPUTS * NUM_TRIALS_PER_INPUT}")
logger.info(f"Maksimum Nesil Sayısı: {MAX_GENERATIONS}")
logger.info(f"Fitness Eşiği: {FITNESS_THRESHOLD}")
# --- YENİ: Hedef Olasılık Fonksiyonu ---
def calculate_target_prob0(input_value):
"""
Verilen girdiye göre hedef P(0) olasılığını hesaplar.
Lineer Fonksiyon: target_P0(x) = 0.1 + 0.8 * x
"""
return 0.1 + 0.8 * input_value
logger.info(f"Hedef P(0) Fonksiyonu: P(0|x) = 0.1 + 0.8 * x")
# --- NEAT Fitness Fonksiyonu ---
# (Bu fonksiyon Sürüm 2 için önemli ölçüde güncellendi)
def eval_genomes(genomes, config):
"""
Popülasyondaki tüm genomların fitness değerlerini hesaplar.
Fitness, ağın farklı girdiler için hedeflenen olasılıkları
ne kadar iyi üretebildiğine göre belirlenir.
"""
# Test edilecek girdi değerlerini belirleyelim (0 ile 1 arasında eşit aralıklı)
test_inputs = np.linspace(0.0, 1.0, NUM_TEST_INPUTS)
# Örnek: NUM_TEST_INPUTS=6 ise -> [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]
for genome_id, genome in genomes:
genome.fitness = 0.0 # Başlangıç fitness'ı sıfırla
try:
net = neat.nn.FeedForwardNetwork.create(genome, config)
except Exception as e:
logger.error(f"Genome {genome_id} için ağ oluşturulamadı: {e}")
genome.fitness = -10.0 # Daha büyük ceza verilebilir
continue
total_squared_error = 0.0
# Her bir test girdisi için ağı değerlendir
for net_input_val in test_inputs:
net_input = (net_input_val,) # Girdiyi tuple formatına getir
target_prob_0 = calculate_target_prob0(net_input_val) # Bu girdi için hedef P(0)
count_0 = 0
# Her girdi için N kez test et
for _ in range(NUM_TRIALS_PER_INPUT):
try:
output = net.activate(net_input)
# Ağın çıktısını yorumla (< 0.5 ise 0)
if output[0] < 0.5:
count_0 += 1
except Exception as e:
logger.warning(f"Genome {genome_id}, Input {net_input_val:.2f} ağ aktivasyonunda hata: {e}")
# Hata durumunda bu denemeyi atla veya penaltı ver
pass # Şimdilik sadece atlıyoruz
# Gözlemlenen olasılığı hesapla
if NUM_TRIALS_PER_INPUT > 0:
observed_prob_0 = count_0 / NUM_TRIALS_PER_INPUT
else:
observed_prob_0 = 0.5 # Sıfıra bölme hatasını önle (pek olası değil ama güvenli)
# Bu girdi için hatanın karesini hesapla
error = (observed_prob_0 - target_prob_0) ** 2
total_squared_error += error
# logger.debug(f" Genome {genome_id}, Input {net_input_val:.2f}: TargetP0={target_prob_0:.3f}, ObsP0={observed_prob_0:.3f}, Error^2={error:.4f}")
# Ortalama Karesel Hatayı (Mean Squared Error - MSE) hesapla
average_squared_error = total_squared_error / NUM_TEST_INPUTS
# Fitness'ı hesapla: Hata ne kadar küçükse, fitness o kadar yüksek (Maks 1.0)
# Hatanın karekökünü (RMSE gibi) 1'den çıkaralım
fitness = max(0.0, 1.0 - math.sqrt(average_squared_error))
genome.fitness = fitness
# logger.info(f"Genome {genome_id}: AvgError^2 = {average_squared_error:.4f}, Fitness = {fitness:.4f}")
# --- NEAT Çalıştırma Fonksiyonu ---
def run_neat(config_file):
"""
NEAT evrimini başlatır ve yönetir.
"""
logger.info(f"NEAT yapılandırması yükleniyor: {config_file}")
try:
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation,
config_file)
# Fitness eşiğini config dosyasından değil, koddan alalım
config.fitness_threshold = FITNESS_THRESHOLD # <-- V2 için güncel eşik
logger.info(f"Yapılandırma yüklendi. Fitness Eşiği: {config.fitness_threshold}")
except Exception as e:
logger.critical(f"Yapılandırma dosyası yüklenemedi veya geçersiz: {config_file} - Hata: {e}")
return None
logger.info("Yeni popülasyon oluşturuluyor...")
p = neat.Population(config)
# İstatistikleri ve loglamayı ayarlama
p.add_reporter(neat.StdOutReporter(True)) # Konsola raporlama
# stats = neat.StatisticsReporter() # Görselleştirme YOK, bu yüzden buna gerek yok
# p.add_reporter(stats)
# Checkpoint (yedek) alma
checkpoint_prefix = 'neat-checkpoint-v2-' # <-- V2 için farklı prefix
p.add_reporter(neat.Checkpointer(10, filename_prefix=checkpoint_prefix))
logger.info(f"Checkpoint dosyaları '{checkpoint_prefix}*' olarak kaydedilecek.")
logger.info(f"Evrim başlıyor (Maksimum {MAX_GENERATIONS} nesil)...")
try:
winner = p.run(eval_genomes, MAX_GENERATIONS)
logger.info(' ' + "="*20 + " Evrim Tamamlandı " + "="*20)
except Exception as e:
logger.critical(f"Evrim sırasında kritik bir hata oluştu: {e}")
return None
# En iyi genomu göster/kaydet
if winner:
logger.info(f'En iyi genom bulundu (Fitness: {winner.fitness:.6f}):')
logger.info(f' {winner}') # Konsola detaylı genom bilgisini yazdırır
# En iyi genomu dosyaya kaydet (pickle ile)
winner_filename = "winner_genome_v2.pkl" # <-- V2 için farklı dosya adı
try:
with open(winner_filename, 'wb') as f:
pickle.dump(winner, f)
logger.info(f"En iyi genom '{winner_filename}' dosyasına başarıyla kaydedildi.")
except Exception as e:
logger.error(f"En iyi genom kaydedilemedi: {e}")
# --- YENİ: En İyi Genomu Farklı Girdilerle Test Etme ---
logger.info(" " + "="*20 + " En İyi Genom Detaylı Testi " + "="*20)
try:
winner_net = neat.nn.FeedForwardNetwork.create(winner, config)
test_trials_final = 1000 # Her girdi için final test deneme sayısı
logger.info(f"En iyi ağ, farklı girdilerle {test_trials_final} kez test ediliyor...")
test_inputs_final = np.linspace(0.0, 1.0, 11) # Daha fazla ara noktayla test edelim (0.0, 0.1, ..., 1.0)
final_total_error_sq = 0.0
results = []
for net_input_val in test_inputs_final:
target_p0 = calculate_target_prob0(net_input_val)
net_input = (net_input_val,)
count_0 = 0
for _ in range(test_trials_final):
output = winner_net.activate(net_input)
if output[0] < 0.5:
count_0 += 1
observed_p0 = count_0 / test_trials_final
error_sq = (observed_p0 - target_p0) ** 2
final_total_error_sq += error_sq
results.append({
"input": net_input_val,
"target_p0": target_p0,
"observed_p0": observed_p0,
"error_sq": error_sq
})
logger.info(f" Input={net_input_val: <4.2f} -> TargetP(0)={target_p0: <5.3f}, ObservedP(0)={observed_p0: <5.3f}, Error^2={error_sq:.5f}")
final_avg_error_sq = final_total_error_sq / len(test_inputs_final)
final_rmse = math.sqrt(final_avg_error_sq)
logger.info("-" * 40)
logger.info(f"Final Ortalama Karesel Hata (MSE): {final_avg_error_sq:.6f}")
logger.info(f"Final Kök Ortalama Karesel Hata (RMSE): {final_rmse:.6f}")
logger.info(f"Final Fitness Yaklaşımı (1 - RMSE): {1.0 - final_rmse:.6f}")
logger.info("-" * 40)
except Exception as e:
logger.error(f"En iyi genom test edilirken hata oluştu: {e}")
else:
logger.warning("Test edilecek bir kazanan genom bulunamadı.")
logger.info("="*50)
logger.info("Quanta Simülatörü Adım 2 (Girdiye Bağlı Olasılık) tamamlandı.")
logger.info("="*50)
return winner
if __name__ == '__main__':
# Yapılandırma dosyasının yolu (Python betiği ile aynı klasörde olduğunu varsayar)
local_dir = os.path.dirname(__file__)
# V1'deki config dosyasını kullanıyoruz, ismi aynı kalabilir.
config_path = os.path.join(local_dir, 'config-feedforward.txt')
if not os.path.exists(config_path):
logger.critical(f"Yapılandırma dosyası bulunamadı: {config_path}")
logger.critical("Lütfen 'config-feedforward.txt' dosyasını Python betiğiyle aynı klasöre koyun.")
else:
# NEAT'i çalıştır
run_neat(config_path)