Punishment update
This commit is contained in:
+120
-21
@@ -42,7 +42,8 @@
|
||||
#define NUM_TOPOLOGIES 59
|
||||
#define DUAL_PROBLEM 0
|
||||
constexpr int GLOBAL_PLANE_VALUE_COUNT = 36;
|
||||
constexpr std::uint32_t GLOBAL_OBJECTIVE_VERSION = 3;
|
||||
constexpr std::uint32_t GLOBAL_OBJECTIVE_VERSION = 4;
|
||||
constexpr std::uint32_t MIN_COMPATIBLE_ARCHIVE_OBJECTIVE_VERSION = 3;
|
||||
constexpr int CUDA_SESSION_CACHE_LIMIT = NUM_TOPOLOGIES;
|
||||
|
||||
struct StudyOptions {
|
||||
@@ -86,7 +87,8 @@ struct LocalRepairOptions {
|
||||
int cuda_chains = 0;
|
||||
int cuda_iterations = 64;
|
||||
int checkpoint_seconds = 30;
|
||||
double degeneracy_weight = 0.02;
|
||||
double degeneracy_weight = 0.01;
|
||||
bool prioritize_worst = false;
|
||||
bool use_cuda = false;
|
||||
};
|
||||
|
||||
@@ -152,7 +154,8 @@ void print_usage(const char* exe_name) {
|
||||
<< " --cuda-chains <n> Parallel GPU chains. 0 = automatic (default).\n"
|
||||
<< " --cuda-iters <n> Iterations per short GPU batch. Default: 64\n"
|
||||
<< " --checkpoint-seconds <n> Durable checkpoint period. Default: 30\n"
|
||||
<< " --degeneracy-weight <x> Degenerate-geometry penalty. Default: 0.02\n"
|
||||
<< " --degeneracy-weight <x> Worst-barrier degeneracy penalty. Default: 0.01\n"
|
||||
<< " --prioritize-worst Give depth priority to the worst current topologies.\n"
|
||||
<< " --start-planes <p> Continue batch-hunt from a saved .planes sidecar.\n"
|
||||
<< " --restarts <n> hunt-local restarts. Default: 256\n"
|
||||
<< " --stagnation <n> Iterations before hunt-local reheat. Default: 2000\n"
|
||||
@@ -2213,7 +2216,7 @@ struct GlobalMetrics {
|
||||
bool precise = false;
|
||||
};
|
||||
|
||||
double g_global_degeneracy_weight = 0.02;
|
||||
double g_global_degeneracy_weight = 0.01;
|
||||
std::string g_search_device_id = "CPU";
|
||||
|
||||
std::uint64_t topology_fingerprint() {
|
||||
@@ -2446,18 +2449,54 @@ bool add_global_archive_elite(
|
||||
return retained;
|
||||
}
|
||||
|
||||
double topology_scheduler_severity(const GlobalMetrics& metrics) {
|
||||
return static_cast<double>(global_defects(metrics)) +
|
||||
0.10 * static_cast<double>(std::max(metrics.crossings, metrics.intersections)) +
|
||||
0.01 * static_cast<double>(metrics.crossings);
|
||||
}
|
||||
|
||||
double topology_scheduler_worstness(
|
||||
const GlobalTopologyState& state,
|
||||
double best_severity,
|
||||
double worst_severity
|
||||
) {
|
||||
if (!state.has_state) {
|
||||
return 1.0;
|
||||
}
|
||||
const double span = worst_severity - best_severity;
|
||||
if (span <= 1.0e-9) {
|
||||
return 0.0;
|
||||
}
|
||||
return std::clamp(
|
||||
(topology_scheduler_severity(state.best) - best_severity) / span,
|
||||
0.0,
|
||||
1.0);
|
||||
}
|
||||
|
||||
double topology_bandit_score(
|
||||
const GlobalTopologyState& state,
|
||||
std::uint64_t total_pulls,
|
||||
std::uint64_t current_round,
|
||||
int best_defects
|
||||
double best_severity,
|
||||
double worst_severity,
|
||||
int best_defects,
|
||||
bool prioritize_worst
|
||||
) {
|
||||
const double exploration = 0.60 * std::sqrt(
|
||||
std::log(static_cast<double>(total_pulls) + 2.0) /
|
||||
(static_cast<double>(state.scheduler_pulls) + 1.0));
|
||||
const double quality_prior = state.has_state
|
||||
? 0.30 / (1.0 + std::max(0, global_defects(state.best) - best_defects))
|
||||
: 0.35;
|
||||
double quality_prior = prioritize_worst ? 0.70 : 0.35;
|
||||
if (state.has_state) {
|
||||
if (prioritize_worst) {
|
||||
quality_prior = 0.65 * topology_scheduler_worstness(
|
||||
state,
|
||||
best_severity,
|
||||
worst_severity);
|
||||
} else {
|
||||
quality_prior = 0.30 /
|
||||
(1.0 + std::max(0, global_defects(state.best) - best_defects));
|
||||
}
|
||||
}
|
||||
const double rounds_since_pull = state.scheduler_last_pull == 0
|
||||
? static_cast<double>(current_round + 1)
|
||||
: static_cast<double>(current_round - state.scheduler_last_pull);
|
||||
@@ -2695,12 +2734,20 @@ GlobalMetrics evaluate_global_state(
|
||||
const double turn_barrier =
|
||||
std::log1p(0.002 / std::max(1e-10, min_turn_sine));
|
||||
const double extent_barrier = 0.10 * std::log1p(max_vertex_norm / 100.0);
|
||||
const double worst_degeneracy_barrier = std::max({
|
||||
determinant_barrier,
|
||||
edge_barrier,
|
||||
turn_barrier,
|
||||
extent_barrier});
|
||||
const double secondary_degeneracy_barriers =
|
||||
determinant_barrier + edge_barrier + turn_barrier + extent_barrier -
|
||||
worst_degeneracy_barrier;
|
||||
metrics.min_plane_determinant = min_plane_determinant;
|
||||
metrics.relative_min_edge = relative_min_edge;
|
||||
metrics.min_turn_sine = min_turn_sine;
|
||||
metrics.max_vertex_norm = max_vertex_norm;
|
||||
metrics.degeneracy_penalty = g_global_degeneracy_weight *
|
||||
(determinant_barrier + edge_barrier + turn_barrier + extent_barrier);
|
||||
(worst_degeneracy_barrier + 0.05 * secondary_degeneracy_barriers);
|
||||
metrics.geometry_penalty =
|
||||
0.0010 * std::min(20.0, std::log1p(condition)) +
|
||||
0.0002 * std::min(20.0, std::log1p(max_vertex_norm)) +
|
||||
@@ -3306,7 +3353,9 @@ void load_mergeable_checkpoints(
|
||||
if (record.delta.topology != topology) {
|
||||
continue;
|
||||
}
|
||||
if (record.delta.objective_version != GLOBAL_OBJECTIVE_VERSION ||
|
||||
if (record.delta.objective_version <
|
||||
MIN_COMPATIBLE_ARCHIVE_OBJECTIVE_VERSION ||
|
||||
record.delta.objective_version > GLOBAL_OBJECTIVE_VERSION ||
|
||||
record.delta.topology_fingerprint != expected_fingerprint) {
|
||||
incompatible_archive_deltas += 1;
|
||||
continue;
|
||||
@@ -3641,13 +3690,14 @@ bool write_run_manifest(
|
||||
std::cerr << "Cannot write run manifest: " << manifest_path << std::endl;
|
||||
return false;
|
||||
}
|
||||
out << "format\tszilassi-global-search-v3\n"
|
||||
out << "format\tszilassi-global-search-v4\n"
|
||||
<< "run_id\t" << identity.run_id << "\n"
|
||||
<< "node_id\t" << identity.node_id << "\n"
|
||||
<< "seed\t" << options.seed << "\n"
|
||||
<< "topology_from\t" << options.topology_from << "\n"
|
||||
<< "topology_to\t" << options.topology_to << "\n"
|
||||
<< "backend\t" << (options.use_cuda ? "cuda-fp32" : "cpu-double") << "\n"
|
||||
<< "objective_version\t" << GLOBAL_OBJECTIVE_VERSION << "\n"
|
||||
<< "cuda_math\tstandard-fp32\n"
|
||||
<< "cuda_chains_requested\t" << options.cuda_chains << "\n"
|
||||
<< "cuda_chains_effective\t" << effective_cuda_chains << "\n"
|
||||
@@ -3666,8 +3716,12 @@ bool write_run_manifest(
|
||||
<< "map_elites_max_cells_per_topology\t4096\n"
|
||||
<< "cem\tdiagonal-weighted,covariance-adaptation:0.18,new-injected-only\n"
|
||||
<< "spsa\tadam:6,cpu-double,fp32-roundtrip,final-canonical-dd-gate\n"
|
||||
<< "topology_scheduler\tucb-plus-quality,full-refresh-every-5\n"
|
||||
<< "topology_scheduler\tucb-plus-reward-plus-staleness,full-refresh-every-5\n"
|
||||
<< "topology_scheduler_mode\t"
|
||||
<< (options.prioritize_worst ? "worst-first" : "quality-first") << "\n"
|
||||
<< "worst_priority_coefficient\t0.65\n"
|
||||
<< "cpu_iterations_per_trial\t" << options.iterations << "\n"
|
||||
<< "degeneracy_formula\tworst-plus-0.05-rest\n"
|
||||
<< "degeneracy_weight\t" << std::setprecision(17)
|
||||
<< options.degeneracy_weight << "\n";
|
||||
out.flush();
|
||||
@@ -4208,6 +4262,8 @@ int global_search_all(const LocalRepairOptions& options) {
|
||||
<< ", run " << run_identity.run_id
|
||||
<< ", node " << run_identity.node_id
|
||||
<< ", threads " << worker_count
|
||||
<< ", scheduler "
|
||||
<< (options.prioritize_worst ? "worst-first" : "quality-first")
|
||||
<< ", minutes " << (options.time_limit_seconds / 60.0)
|
||||
<< " ===\n";
|
||||
std::ofstream metrics_log(
|
||||
@@ -4222,7 +4278,7 @@ int global_search_all(const LocalRepairOptions& options) {
|
||||
return 2;
|
||||
}
|
||||
metrics_log
|
||||
<< "round\tunix_ns\tphase\ttopology\tdepth\tbandit_score"
|
||||
<< "round\tunix_ns\tphase\ttopology\tdepth\tbandit_score\tworstness"
|
||||
<< "\tbefore_C\tbefore_I\tafter_C\tafter_I\timproved\tbackend_error"
|
||||
<< "\tarchive_cells\tarchive_improvements\tverified\taccounted_fp32_steps"
|
||||
<< "\tnew_trials\tkernel_ms\ttransfer_ms\twall_ms"
|
||||
@@ -4243,6 +4299,13 @@ int global_search_all(const LocalRepairOptions& options) {
|
||||
<< std::endl;
|
||||
std::cout << "Topologies: " << options.topology_from << ".."
|
||||
<< options.topology_to << " (" << active_topologies.size() << ")" << std::endl;
|
||||
std::cout << "Scheduler : "
|
||||
<< (options.prioritize_worst
|
||||
? "priority to the worst current topologies"
|
||||
: "priority to the most promising topologies")
|
||||
<< std::endl;
|
||||
std::cout << "Degenerate: worst barrier + 5% of the rest, weight "
|
||||
<< options.degeneracy_weight << std::endl;
|
||||
std::cout << "Start : saved MAP-Elites/CEM seeds plus independent random starts"
|
||||
<< std::endl;
|
||||
std::cout << "Coordinates: "
|
||||
@@ -4387,22 +4450,36 @@ int global_search_all(const LocalRepairOptions& options) {
|
||||
[&](std::uint64_t sum, int item) {
|
||||
return sum + states[item].scheduler_pulls;
|
||||
});
|
||||
double current_best_severity = std::numeric_limits<double>::infinity();
|
||||
double current_worst_severity = -std::numeric_limits<double>::infinity();
|
||||
int current_best_defects = std::numeric_limits<int>::max() / 4;
|
||||
for (int item : active_topologies) {
|
||||
if (states[item].has_state) {
|
||||
const double severity = topology_scheduler_severity(states[item].best);
|
||||
current_best_severity = std::min(current_best_severity, severity);
|
||||
current_worst_severity = std::max(current_worst_severity, severity);
|
||||
current_best_defects = std::min(
|
||||
current_best_defects,
|
||||
global_defects(states[item].best));
|
||||
}
|
||||
}
|
||||
if (current_best_defects >= std::numeric_limits<int>::max() / 8) {
|
||||
if (!std::isfinite(current_best_severity)) {
|
||||
current_best_severity = 0.0;
|
||||
current_worst_severity = 0.0;
|
||||
current_best_defects = 0;
|
||||
}
|
||||
const double selection_score = topology_bandit_score(
|
||||
state,
|
||||
total_scheduler_pulls,
|
||||
static_cast<std::uint64_t>(completed_rounds + 1),
|
||||
current_best_defects);
|
||||
current_best_severity,
|
||||
current_worst_severity,
|
||||
current_best_defects,
|
||||
options.prioritize_worst);
|
||||
const double selection_worstness = topology_scheduler_worstness(
|
||||
state,
|
||||
current_best_severity,
|
||||
current_worst_severity);
|
||||
const int round_seed = static_cast<int>(
|
||||
1 + (static_cast<std::uint64_t>(static_cast<std::uint32_t>(options.seed)) +
|
||||
static_cast<std::uint64_t>(state.visits + 1) * 15485863ULL +
|
||||
@@ -4476,6 +4553,7 @@ int global_search_all(const LocalRepairOptions& options) {
|
||||
<< szilassi::checkpoint::unix_time_ns_now() << "\t"
|
||||
<< phase << "\t" << topology << "\t" << (depth ? 1 : 0) << "\t"
|
||||
<< std::setprecision(17) << selection_score << "\t"
|
||||
<< selection_worstness << "\t"
|
||||
<< (had_before ? before.crossings : -1) << "\t"
|
||||
<< (had_before ? before.intersections : -1) << "\t"
|
||||
<< (state.has_state ? state.best.crossings : -1) << "\t"
|
||||
@@ -4551,13 +4629,22 @@ int global_search_all(const LocalRepairOptions& options) {
|
||||
[&](std::uint64_t sum, int topology) {
|
||||
return sum + states[topology].scheduler_pulls;
|
||||
});
|
||||
double best_severity = std::numeric_limits<double>::infinity();
|
||||
double worst_severity = -std::numeric_limits<double>::infinity();
|
||||
int best_defects = std::numeric_limits<int>::max() / 4;
|
||||
for (int topology : active_topologies) {
|
||||
if (states[topology].has_state) {
|
||||
best_defects = std::min(best_defects, global_defects(states[topology].best));
|
||||
const double severity = topology_scheduler_severity(states[topology].best);
|
||||
best_severity = std::min(best_severity, severity);
|
||||
worst_severity = std::max(worst_severity, severity);
|
||||
best_defects = std::min(
|
||||
best_defects,
|
||||
global_defects(states[topology].best));
|
||||
}
|
||||
}
|
||||
if (best_defects >= std::numeric_limits<int>::max() / 8) {
|
||||
if (!std::isfinite(best_severity)) {
|
||||
best_severity = 0.0;
|
||||
worst_severity = 0.0;
|
||||
best_defects = 0;
|
||||
}
|
||||
std::unordered_map<int, double> bandit_scores;
|
||||
@@ -4566,7 +4653,10 @@ int global_search_all(const LocalRepairOptions& options) {
|
||||
states[topology],
|
||||
total_scheduler_pulls,
|
||||
static_cast<std::uint64_t>(completed_rounds + 1),
|
||||
best_defects);
|
||||
best_severity,
|
||||
worst_severity,
|
||||
best_defects,
|
||||
options.prioritize_worst);
|
||||
}
|
||||
std::sort(ranked.begin(), ranked.end(), [&](int a, int b) {
|
||||
if (bandit_scores[a] != bandit_scores[b]) {
|
||||
@@ -4575,9 +4665,16 @@ int global_search_all(const LocalRepairOptions& options) {
|
||||
if (states[a].has_state != states[b].has_state) {
|
||||
return states[a].has_state;
|
||||
}
|
||||
return states[a].has_state
|
||||
? better_global_metrics(states[a].best, states[b].best)
|
||||
: a < b;
|
||||
if (!states[a].has_state) {
|
||||
return a < b;
|
||||
}
|
||||
if (better_global_metrics(states[a].best, states[b].best)) {
|
||||
return true;
|
||||
}
|
||||
if (better_global_metrics(states[b].best, states[a].best)) {
|
||||
return false;
|
||||
}
|
||||
return a < b;
|
||||
});
|
||||
|
||||
const bool exploration_cycle = cycle % 5 == 4;
|
||||
@@ -4885,6 +4982,8 @@ int main(int argc, char* argv[]) {
|
||||
} else if (arg == "--degeneracy-weight" && i + 1 < argc) {
|
||||
repair_options.degeneracy_weight = std::clamp(
|
||||
std::atof(argv[++i]), 0.0, 1.0);
|
||||
} else if (arg == "--prioritize-worst") {
|
||||
repair_options.prioritize_worst = true;
|
||||
} else if (arg == "--restarts" && i + 1 < argc) {
|
||||
repair_options.restarts = std::atoi(argv[++i]);
|
||||
} else if (arg == "--stagnation" && i + 1 < argc) {
|
||||
|
||||
Reference in New Issue
Block a user