Quanta / quanta_sim_v5_nonlinear_simple.py
NextGenC's picture
Upload 11 files
8e35b08 verified
# quanta_sim_v5_nonlinear_simple.py
import neat
import numpy as np
import os
import logging
import pickle
import random
import math
import datetime
import itertools
import traceback # Hata ayıklama için
# --- Loglama Ayarları ---
log_filename = f"quanta_log_v5_nonsimple_{datetime.datetime.now():%Y%m%d_%H%M%S}.log"
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("="*70)
logger.info("Quanta Simülatörü Başlatılıyor (Sürüm 5 - Non-Linear Hedefler + Basitlik)")
logger.info(f"Başlangıç Zamanı: {datetime.datetime.now()}")
logger.info("="*70)
# --- Simülasyon Parametreleri ---
NUM_TEST_VALUES_PER_AXIS = 4 # Değerlendirme için ızgara boyutu (4x4=16 nokta)
NUM_TRIALS_PER_PAIR = 30 # Her girdi çifti için deneme sayısı
MAX_GENERATIONS = 300 # Zor problem için artırılmış nesil sayısı
# Fitness fonksiyonundaki hata ağırlıkları
W_PA0 = 1.0
W_PB0 = 1.0
W_CORR = 1.5 # Korelasyon genellikle daha zordur
TOTAL_WEIGHT = W_PA0 + W_PB0 + W_CORR
# Karmaşıklık Cezası Ağırlıkları (Deneme yanılma ile ayarlanabilir!)
COMPLEXITY_PENALTY_WEIGHT_NODE = 0.001
COMPLEXITY_PENALTY_WEIGHT_CONN = 0.0005
num_test_points = NUM_TEST_VALUES_PER_AXIS ** 2
total_trials_per_genome = num_test_points * NUM_TRIALS_PER_PAIR
logger.info(f"Eksen Başına Test Değeri: {NUM_TEST_VALUES_PER_AXIS} ({num_test_points} test noktası)")
logger.info(f"Girdi Çifti Başına Deneme: {NUM_TRIALS_PER_PAIR} (Toplam {total_trials_per_genome} deneme/genom)")
logger.info(f"Maksimum Nesil: {MAX_GENERATIONS}")
logger.info(f"Fitness Hata Ağırlıkları: P(A0)={W_PA0:.1f}, P(B0)={W_PB0:.1f}, Corr={W_CORR:.1f}")
logger.info(f"Karmaşıklık Ceza Ağırlıkları: Düğüm={COMPLEXITY_PENALTY_WEIGHT_NODE}, Bağlantı={COMPLEXITY_PENALTY_WEIGHT_CONN}")
# --- Doğrusal Olmayan Hedef Fonksiyonları ---
def target_PA0(x1, x2):
# P(A=0) hedefi (0.1 ile 0.9 arasında salınır)
return 0.5 + 0.4 * math.sin(math.pi * x1)
def target_PB0(x1, x2):
# P(B=0) hedefi (0.1 ile 0.9 arasında salınır)
return 0.5 + 0.4 * math.cos(math.pi * x2)
def target_Corr(x1, x2):
# Hedef Korelasyon (0 ile -0.8 arasında salınır)
return -0.8 * math.sin(math.pi * x1 * x2)
logger.info(f"Hedef P(A=0|x1,x2) = 0.5 + 0.4*sin(pi*x1)")
logger.info(f"Hedef P(B=0|x1,x2) = 0.5 + 0.4*cos(pi*x2)")
logger.info(f"Hedef Corr(A,B|x1,x2) = -0.8*sin(pi*x1*x2)")
# --- Korelasyon Hesaplama Yardımcı Fonksiyonu ---
def calculate_correlation(pA0, pB0, pA0B0, epsilon=1e-9):
pA1 = 1.0 - pA0
pB1 = 1.0 - pB0
covariance = pA0B0 - pA0 * pB0
varA = pA0 * pA1
varB = pB0 * pB1
denominator = math.sqrt((varA + epsilon) * (varB + epsilon))
if denominator < epsilon: return 0.0
correlation = covariance / denominator
return max(-1.0, min(1.0, correlation))
# --- NEAT Fitness Fonksiyonu ---
def eval_genomes(genomes, config):
axis_values = np.linspace(0.0, 1.0, NUM_TEST_VALUES_PER_AXIS)
test_input_pairs = list(itertools.product(axis_values, repeat=2))
for genome_id, genome in genomes:
genome.fitness = 0.0 # Başlangıç fitness
try:
net = neat.nn.FeedForwardNetwork.create(genome, config)
except Exception as e:
logger.error(f"Genome {genome_id} ağ oluşturma hatası: {e}")
genome.fitness = -30.0
continue
total_weighted_error_sum = 0.0
# Performans Değerlendirme
for input_pair in test_input_pairs:
x1, x2 = input_pair
targ_pA0 = target_PA0(x1, x2)
targ_pB0 = target_PB0(x1, x2)
targ_corr = target_Corr(x1, x2)
count_A0, count_B0, count_A0B0 = 0, 0, 0
for _ in range(NUM_TRIALS_PER_PAIR):
try:
output1, output2 = net.activate(input_pair)
res_A = 0 if output1 < 0.5 else 1
res_B = 0 if output2 < 0.5 else 1
if res_A == 0: count_A0 += 1
if res_B == 0: count_B0 += 1
if res_A == 0 and res_B == 0: count_A0B0 += 1
except Exception as e:
# Aktivasyon hatalarını loglamak çok fazla çıktı üretebilir
pass
# Gözlemlenen değerler
if NUM_TRIALS_PER_PAIR > 0:
obs_pA0 = count_A0 / NUM_TRIALS_PER_PAIR
obs_pB0 = count_B0 / NUM_TRIALS_PER_PAIR
obs_pA0B0 = count_A0B0 / NUM_TRIALS_PER_PAIR
else:
obs_pA0, obs_pB0, obs_pA0B0 = 0.5, 0.5, 0.25
obs_corr = calculate_correlation(obs_pA0, obs_pB0, obs_pA0B0)
# Hatalar
error_pA0 = (obs_pA0 - targ_pA0) ** 2
error_pB0 = (obs_pB0 - targ_pB0) ** 2
error_corr = (obs_corr - targ_corr) ** 2
weighted_error = (W_PA0 * error_pA0 + W_PB0 * error_pB0 + W_CORR * error_corr) / TOTAL_WEIGHT
total_weighted_error_sum += weighted_error
# Temel fitness
average_weighted_error = total_weighted_error_sum / len(test_input_pairs)
base_fitness = max(0.0, 1.0 - math.sqrt(average_weighted_error))
# Karmaşıklık Cezası
num_nodes = len(genome.nodes)
num_connections = len(genome.connections)
complexity_penalty = (COMPLEXITY_PENALTY_WEIGHT_NODE * num_nodes +
COMPLEXITY_PENALTY_WEIGHT_CONN * num_connections)
# Final fitness
final_fitness = max(0.0, base_fitness - complexity_penalty)
genome.fitness = final_fitness
# --- NEAT Çalıştırma Fonksiyonu ---
def run_neat(config_file):
logger.info(f"NEAT yapılandırması yükleniyor: {config_file}")
config = None # Önce None olarak tanımla
try:
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation,
config_file)
logger.info(f"Yapılandırma: Giriş={config.genome_config.num_inputs}, Çıkış={config.genome_config.num_outputs}, Pop={config.pop_size}, Eşik={config.fitness_threshold}")
except Exception as e:
logger.critical(f"Yapılandırma dosyası yüklenemedi: {config_file} - Hata: {e}")
return None
logger.info("Yeni popülasyon oluşturuluyor...")
p = neat.Population(config)
# Raporlayıcılar
p.add_reporter(neat.StdOutReporter(True))
checkpoint_prefix = 'neat-checkpoint-v5-'
# Checkpointer her 25 nesilde bir kaydetsin
p.add_reporter(neat.Checkpointer(25, filename_prefix=checkpoint_prefix))
logger.info(f"Checkpoint dosyaları '{checkpoint_prefix}*' olarak kaydedilecek.")
logger.info(f"Evrim başlıyor (Maksimum {MAX_GENERATIONS} nesil)...")
winner = None # Önce None olarak tanımla
try:
winner = p.run(eval_genomes, MAX_GENERATIONS)
logger.info(' ' + "="*30 + " Evrim Tamamlandı " + "="*30)
except Exception as e:
logger.critical(f"Evrim sırasında kritik bir hata oluştu: {e}")
logger.error(traceback.format_exc()) # Tam hata izini logla
# Hata durumunda bile popülasyonun en iyisini almayı deneyebiliriz (checkpoint yoksa)
if not winner and p and p.best_genome:
logger.warning("Evrim hata ile durdu, bulunan son en iyi genom kullanılıyor.")
winner = p.best_genome
# return None # Hata durumunda çıkmak yerine devam etmeyi deneyelim
# En iyi genomu işle (hata olsa bile 'winner' dolu olabilir)
if winner:
logger.info(f'En iyi genom bulundu/kullanıldı (Final Fitness: {winner.fitness:.6f}):')
num_nodes = len(winner.nodes)
num_connections = len(winner.connections)
logger.info(f'Kazanan Karmaşıklığı: {num_nodes} Düğüm, {num_connections} Bağlantı')
# En iyi genomu kaydet
winner_filename = "winner_genome_v5.pkl"
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}")
# --- Final Test ---
logger.info(" " + "="*20 + " En İyi Genom Detaylı Testi (Non-Linear) " + "="*20)
try:
# Eğer config yüklenmemişse (ilk hatada), testi atla
if config is None:
logger.error("Yapılandırma yüklenemediği için final test atlanıyor.")
raise RuntimeError("Config object is None, cannot create network.")
winner_net = neat.nn.FeedForwardNetwork.create(winner, config)
test_trials_final = 1000 # Final test için deneme sayısı
logger.info(f"En iyi ağ, farklı girdi çiftleriyle {test_trials_final} kez test ediliyor...")
final_axis_values = np.linspace(0.0, 1.0, 6) # 6x6 = 36 nokta test
final_test_pairs = list(itertools.product(final_axis_values, repeat=2))
final_total_weighted_error_sq_sum = 0.0
hdr = f"{'Input (x1,x2)': <14} {'Tgt(PA0,PB0,Corr)': <22} {'Obs(PA0,PB0,Corr)': <22} {'Err^2(Comb)': <10}"
logger.info(hdr)
logger.info("-" * len(hdr))
for input_pair in final_test_pairs:
x1, x2 = input_pair
targ_pA0 = target_PA0(x1, x2)
targ_pB0 = target_PB0(x1, x2)
targ_corr = target_Corr(x1, x2)
count_A0, count_B0, count_A0B0 = 0, 0, 0
for _ in range(test_trials_final):
output1, output2 = winner_net.activate(input_pair)
res_A = 0 if output1 < 0.5 else 1
res_B = 0 if output2 < 0.5 else 1
if res_A == 0: count_A0 += 1
if res_B == 0: count_B0 += 1
if res_A == 0 and res_B == 0: count_A0B0 += 1
obs_pA0 = count_A0 / test_trials_final
obs_pB0 = count_B0 / test_trials_final
obs_pA0B0 = count_A0B0 / test_trials_final
obs_corr = calculate_correlation(obs_pA0, obs_pB0, obs_pA0B0)
error_pA0 = (obs_pA0 - targ_pA0) ** 2
error_pB0 = (obs_pB0 - targ_pB0) ** 2
error_corr = (obs_corr - targ_corr) ** 2
weighted_error_sq = (W_PA0 * error_pA0 + W_PB0 * error_pB0 + W_CORR * error_corr) / TOTAL_WEIGHT
final_total_weighted_error_sq_sum += weighted_error_sq
tgt_str = f"({targ_pA0:.2f},{targ_pB0:.2f},{targ_corr:.2f})"
obs_str = f"({obs_pA0:.2f},{obs_pB0:.2f},{obs_corr:.2f})"
logger.info(f"({x1:.2f}, {x2:.2f}) {tgt_str: <22} {obs_str: <22} {weighted_error_sq:<10.5f}")
final_avg_weighted_error_sq = final_total_weighted_error_sq_sum / len(final_test_pairs)
final_rmse_equivalent = math.sqrt(final_avg_weighted_error_sq)
logger.info("-" * len(hdr))
logger.info(f"Final Ortalama Ağırlıklı Karesel Hata (MSE ~): {final_avg_weighted_error_sq:.6f}")
logger.info(f"Final Kök Ort. Karesel Hata (~RMSE): {final_rmse_equivalent:.6f}")
logger.info(f"Not: Bu RMSE, karmaşıklık cezasını içermez, sadece performans ölçümüdür.")
logger.info("-" * len(hdr))
except Exception as e:
logger.error(f"En iyi genom test edilirken hata oluştu: {e}")
logger.error(traceback.format_exc())
else:
logger.warning("Evrim sonunda test edilecek bir kazanan genom bulunamadı.")
logger.info("="*70)
logger.info("Quanta Simülatörü Adım 5 (Non-Linear + Basitlik) tamamlandı.")
logger.info(f"Bitiş Zamanı: {datetime.datetime.now()}")
logger.info("="*70)
# return winner # Fonksiyondan bir şey döndürmeye gerek yoksa kaldırılabilir
if __name__ == '__main__':
# Betiğin bulunduğu dizini al
local_dir = os.path.dirname(os.path.abspath(__file__))
# V5 config dosyasının tam yolunu oluştur
config_path = os.path.join(local_dir, 'config-feedforward-v5.txt')
if not os.path.exists(config_path):
logger.critical(f"Yapılandırma dosyası bulunamadı: {config_path}")
logger.critical(f"Lütfen '{os.path.basename(config_path)}' dosyasını betikle aynı klasöre koyun.")
else:
try:
run_neat(config_path)
except Exception as main_e:
logger.critical(f"Ana program akışında beklenmedik bir hata oluştu: {main_e}")
logger.error(traceback.format_exc())