Upload run_medium_experiment.py with huggingface_hub
Browse files- run_medium_experiment.py +166 -0
run_medium_experiment.py
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Medium-length EQL experiment (10+10 epochs) to verify full pipeline."""
|
| 2 |
+
import os, sys, time
|
| 3 |
+
import numpy as np
|
| 4 |
+
from tqdm import tqdm
|
| 5 |
+
from scipy.io import loadmat
|
| 6 |
+
import tensorflow as tf
|
| 7 |
+
import matplotlib
|
| 8 |
+
matplotlib.use('Agg')
|
| 9 |
+
from matplotlib import pyplot as plt
|
| 10 |
+
|
| 11 |
+
from reproduce_eql import (
|
| 12 |
+
SymbolicNet, Constant, Identity, Square, Sin, Sigmoid, Product,
|
| 13 |
+
count_double, l12_smooth, get_folders_started, record_base_info,
|
| 14 |
+
append_text_to_summary, plot_train_vs_validation, plot_histogram,
|
| 15 |
+
plot_descaled_real_vs_prediction, generate_all_data, generate_variable_list,
|
| 16 |
+
save_weights, network
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
if __name__ == "__main__":
|
| 20 |
+
target_city = "Roskilde"
|
| 21 |
+
steps_ahead = 6
|
| 22 |
+
feature = "wind_speed"
|
| 23 |
+
target_cities = ["Esbjerg", "Odense", "Roskilde"]
|
| 24 |
+
city_index = target_cities.index(target_city)
|
| 25 |
+
|
| 26 |
+
data = loadmat('Denmark_data/wind_speed/step1.mat')
|
| 27 |
+
y_min = data["y_min_tr"][0][city_index]
|
| 28 |
+
y_max = data["y_max_tr"][0][city_index]
|
| 29 |
+
|
| 30 |
+
config = {
|
| 31 |
+
"use_rescaled_MSE": True,
|
| 32 |
+
"a_L_0.5": 5e-3,
|
| 33 |
+
"threshold_value": 7.5e-3,
|
| 34 |
+
"lambda_reg": 3.0,
|
| 35 |
+
"steps_ahead": 6,
|
| 36 |
+
"feature": feature,
|
| 37 |
+
"target_city": target_city,
|
| 38 |
+
"epochs1": 10,
|
| 39 |
+
"epochs2": 10,
|
| 40 |
+
"use_phase2": True,
|
| 41 |
+
"batch_size": 200,
|
| 42 |
+
"phase1_lr": 1e-4,
|
| 43 |
+
"phase2_lr": 1e-5,
|
| 44 |
+
"eql_number_layers": 2,
|
| 45 |
+
"optimizer": "rmsprop",
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
x_dim = 80
|
| 49 |
+
activation_funcs = [
|
| 50 |
+
*[Constant()] * 2, *[Identity()] * 4, *[Square()] * 4,
|
| 51 |
+
*[Sin()] * 2, *[Sigmoid()] * 2, *[Product()] * 2
|
| 52 |
+
]
|
| 53 |
+
n_layers = 2
|
| 54 |
+
n_double = count_double(activation_funcs)
|
| 55 |
+
width = len(activation_funcs)
|
| 56 |
+
|
| 57 |
+
init_weights = [
|
| 58 |
+
tf.random.truncated_normal([x_dim, width + n_double], stddev=0.1),
|
| 59 |
+
tf.random.truncated_normal([width, width + n_double], stddev=0.5),
|
| 60 |
+
tf.random.truncated_normal([width, 1], stddev=1.0)
|
| 61 |
+
]
|
| 62 |
+
model = SymbolicNet(n_layers, funcs=activation_funcs, initial_weights=init_weights)
|
| 63 |
+
phase1_optimizer = tf.keras.optimizers.RMSprop(learning_rate=1e-4)
|
| 64 |
+
|
| 65 |
+
experiment_number = get_folders_started()
|
| 66 |
+
print("\n" + "*" * 10 + " Experiment {} ".format(experiment_number) + "*" * 10 + "\n")
|
| 67 |
+
record_base_info(experiment_number, **config)
|
| 68 |
+
|
| 69 |
+
x_train, y_train = generate_all_data("train", steps_ahead, feature, city_index)
|
| 70 |
+
x_test, y_test = generate_all_data("test", steps_ahead, feature, city_index)
|
| 71 |
+
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(200)
|
| 72 |
+
val_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(200)
|
| 73 |
+
|
| 74 |
+
# Phase 1
|
| 75 |
+
best_val_loss = float('inf')
|
| 76 |
+
best_val_weights = None
|
| 77 |
+
train_loss_results = []
|
| 78 |
+
valid_loss_results = []
|
| 79 |
+
|
| 80 |
+
for epoch in range(config["epochs1"]):
|
| 81 |
+
epoch_loss_avg = tf.keras.metrics.MeanSquaredError()
|
| 82 |
+
for xb, yb in tqdm(train_dataset, desc=f"P1 Epoch {epoch+1}", leave=False):
|
| 83 |
+
with tf.GradientTape() as tape:
|
| 84 |
+
yp = model(xb)
|
| 85 |
+
err = tf.keras.losses.MeanSquaredError()(yb * (y_max - y_min) + y_min, yp * (y_max - y_min) + y_min)
|
| 86 |
+
reg = l12_smooth(model.get_weights(), 5e-3)
|
| 87 |
+
loss = err + 3.0 * reg
|
| 88 |
+
grads = tape.gradient(loss, model.get_weights())
|
| 89 |
+
phase1_optimizer.apply_gradients(zip(grads, model.get_weights()))
|
| 90 |
+
epoch_loss_avg.update_state(yb, yp)
|
| 91 |
+
|
| 92 |
+
train_mse = epoch_loss_avg.result().numpy()
|
| 93 |
+
val_mse = tf.keras.metrics.MeanSquaredError()
|
| 94 |
+
for xv, yv in val_dataset:
|
| 95 |
+
val_mse.update_state(yv, model(xv))
|
| 96 |
+
val_mse = val_mse.result().numpy()
|
| 97 |
+
|
| 98 |
+
train_loss_results.append(train_mse)
|
| 99 |
+
valid_loss_results.append(val_mse)
|
| 100 |
+
if val_mse < best_val_loss:
|
| 101 |
+
best_val_loss = val_mse
|
| 102 |
+
best_val_weights = [w.numpy() for w in model.get_weights()]
|
| 103 |
+
print(f"P1 Epoch {epoch+1}: val MSE improved to {val_mse:.4e} (train {train_mse:.4e})")
|
| 104 |
+
else:
|
| 105 |
+
print(f"P1 Epoch {epoch+1}: val MSE {val_mse:.4e} (train {train_mse:.4e})")
|
| 106 |
+
|
| 107 |
+
save_weights(best_val_weights, experiment_number, "phase1", best_val_loss)
|
| 108 |
+
append_text_to_summary(experiment_number, f"phase 1 best MSE validation: {best_val_loss}\n")
|
| 109 |
+
plot_train_vs_validation(experiment_number, config["epochs1"], train_loss_results, valid_loss_results, "phase1")
|
| 110 |
+
plot_histogram(experiment_number, best_val_weights[0], "phase1", "weights1", 5e-3)
|
| 111 |
+
plot_histogram(experiment_number, best_val_weights[1], "phase1", "weights2", 5e-3)
|
| 112 |
+
plot_histogram(experiment_number, best_val_weights[2], "phase1", "weights3", 5e-3)
|
| 113 |
+
|
| 114 |
+
# Phase 2
|
| 115 |
+
masked_weights = []
|
| 116 |
+
for w_i in best_val_weights:
|
| 117 |
+
mask = tf.cast(tf.constant(tf.abs(w_i) > 7.5e-3), tf.float32)
|
| 118 |
+
masked_weights.append(tf.multiply(w_i, mask))
|
| 119 |
+
|
| 120 |
+
model2 = SymbolicNet(n_layers, funcs=activation_funcs, initial_weights=masked_weights)
|
| 121 |
+
opt2 = tf.keras.optimizers.RMSprop(learning_rate=1e-5)
|
| 122 |
+
|
| 123 |
+
train_loss_results2 = []
|
| 124 |
+
valid_loss_results2 = []
|
| 125 |
+
best_val_loss2 = float('inf')
|
| 126 |
+
best_val_weights2 = None
|
| 127 |
+
|
| 128 |
+
for epoch in range(config["epochs2"]):
|
| 129 |
+
epoch_loss_avg = tf.keras.metrics.MeanSquaredError()
|
| 130 |
+
for xb, yb in tqdm(train_dataset, desc=f"P2 Epoch {epoch+1}", leave=False):
|
| 131 |
+
with tf.GradientTape() as tape:
|
| 132 |
+
yp = model2(xb)
|
| 133 |
+
err = tf.keras.losses.MeanSquaredError()(yb * (y_max - y_min) + y_min, yp * (y_max - y_min) + y_min)
|
| 134 |
+
grads = tape.gradient(err, model2.get_weights())
|
| 135 |
+
opt2.apply_gradients(zip(grads, model2.get_weights()))
|
| 136 |
+
epoch_loss_avg.update_state(yb, yp)
|
| 137 |
+
|
| 138 |
+
train_mse = epoch_loss_avg.result().numpy()
|
| 139 |
+
val_mse = tf.keras.metrics.MeanSquaredError()
|
| 140 |
+
for xv, yv in val_dataset:
|
| 141 |
+
val_mse.update_state(yv, model2(xv))
|
| 142 |
+
val_mse = val_mse.result().numpy()
|
| 143 |
+
|
| 144 |
+
train_loss_results2.append(train_mse)
|
| 145 |
+
valid_loss_results2.append(val_mse)
|
| 146 |
+
if val_mse < best_val_loss2:
|
| 147 |
+
best_val_loss2 = val_mse
|
| 148 |
+
best_val_weights2 = [w.numpy() for w in model2.get_weights()]
|
| 149 |
+
print(f"P2 Epoch {epoch+1}: val MSE improved to {val_mse:.4e} (train {train_mse:.4e})")
|
| 150 |
+
else:
|
| 151 |
+
print(f"P2 Epoch {epoch+1}: val MSE {val_mse:.4e} (train {train_mse:.4e})")
|
| 152 |
+
|
| 153 |
+
save_weights(best_val_weights2, experiment_number, "phase2", best_val_loss2)
|
| 154 |
+
plot_train_vs_validation(experiment_number, config["epochs2"], train_loss_results2, valid_loss_results2, "phase2")
|
| 155 |
+
|
| 156 |
+
expr = network(best_val_weights2, activation_funcs, generate_variable_list(26, 80)[:80], threshold=0)
|
| 157 |
+
append_text_to_summary(experiment_number, f"Formula after phase2: {expr}\n")
|
| 158 |
+
print(f"\nExtracted formula: {expr}")
|
| 159 |
+
|
| 160 |
+
best_model = SymbolicNet(n_layers, funcs=activation_funcs,
|
| 161 |
+
initial_weights=[tf.constant(w) for w in best_val_weights2])
|
| 162 |
+
yp = best_model(x_test)
|
| 163 |
+
mae = plot_descaled_real_vs_prediction(experiment_number, y_test, yp, y_min, y_max)
|
| 164 |
+
append_text_to_summary(experiment_number, f"MAE: {mae}\n")
|
| 165 |
+
print(f"\nMAE: {mae}")
|
| 166 |
+
print("\nMedium experiment complete!")
|