File size: 13,150 Bytes
8e35b08 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# 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()) |