fix: eval mode uses Boltzmann sampling — argmax froze val_Sharpe at 0.00
All 4 branches (dir, mag, order, urgency) now use Boltzmann sampling in eval mode instead of argmax. argmax(softmax(Q/tau)) = argmax(Q) — temperature is meaningless with argmax. Every state picked the same winning action → identical trades → Sharpe=0.00 from epoch 8 onward. Boltzmann sampling with Philox seed gives deterministic but action-diverse evaluation. When Q-values differentiate, Boltzmann naturally sharpens toward the best action. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -849,22 +849,17 @@ extern "C" __global__ void experience_action_select(
|
||||
exps_d[a] = expf((qv - q_max_d) / tau_d);
|
||||
sum_e += exps_d[a];
|
||||
}
|
||||
if (eval_mode) {
|
||||
/* Eval: argmax of softmax probs — same as argmax(Q) but with
|
||||
temperature-aware tie-breaking when Q-values are equal */
|
||||
dir_idx = 0;
|
||||
for (int a = 1; a < b0_size; a++) {
|
||||
if (exps_d[a] > exps_d[dir_idx]) dir_idx = a;
|
||||
}
|
||||
} else {
|
||||
/* Training: sample from Boltzmann distribution */
|
||||
float r = philox_uniform(i, timestep, rng_ctr++) * sum_e;
|
||||
float cum = 0.0f;
|
||||
dir_idx = b0_size - 1;
|
||||
for (int a = 0; a < b0_size; a++) {
|
||||
cum += exps_d[a];
|
||||
if (r < cum) { dir_idx = a; break; }
|
||||
}
|
||||
/* Both eval and training: Boltzmann sampling from softmax probs.
|
||||
* Eval determinism comes from Philox seed (same i+timestep → same
|
||||
* sample), NOT from argmax. argmax(softmax) = argmax(Q) which
|
||||
* picks the same action for every state → val_Sharpe=0.00 freeze.
|
||||
* Boltzmann sampling differentiates even when Q-gap is small. */
|
||||
float r = philox_uniform(i, timestep, rng_ctr++) * sum_e;
|
||||
float cum = 0.0f;
|
||||
dir_idx = b0_size - 1;
|
||||
for (int a = 0; a < b0_size; a++) {
|
||||
cum += exps_d[a];
|
||||
if (r < cum) { dir_idx = a; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -888,15 +883,7 @@ extern "C" __global__ void experience_action_select(
|
||||
*
|
||||
* Temperature tau = Q-range / 3 (adaptive, prevents division by zero).
|
||||
* At tau → 0: greedy argmax. At tau → ∞: uniform random. */
|
||||
if (eval_mode) {
|
||||
/* Eval mode: pure greedy argmax for magnitude */
|
||||
mag_idx = 0;
|
||||
float best_q = (q_b1[0]);
|
||||
for (int a = 1; a < b1_size; a++) {
|
||||
float qv = (q_b1[a]);
|
||||
if (qv > best_q) { best_q = qv; mag_idx = a; }
|
||||
}
|
||||
} else if (philox_uniform(i, timestep, rng_ctr++) < eps_mag) {
|
||||
if (!eval_mode && philox_uniform(i, timestep, rng_ctr++) < eps_mag) {
|
||||
int r = (int)(philox_uniform(i, timestep, rng_ctr++) * (float)b1_size);
|
||||
mag_idx = (r >= b1_size) ? b1_size - 1 : r;
|
||||
} else {
|
||||
@@ -934,14 +921,8 @@ extern "C" __global__ void experience_action_select(
|
||||
}
|
||||
} /* end else (not in_hold) */
|
||||
|
||||
/* Branch 2: order type */
|
||||
if (eval_mode) {
|
||||
a2 = 0;
|
||||
float best_q = q_b2[0];
|
||||
for (int a = 1; a < b2_size; a++) {
|
||||
if (q_b2[a] > best_q) { best_q = q_b2[a]; a2 = a; }
|
||||
}
|
||||
} else if (philox_uniform(i, timestep, rng_ctr++) < eps_ord) {
|
||||
/* Branch 2: order type — Boltzmann for both eval and training */
|
||||
if (!eval_mode && philox_uniform(i, timestep, rng_ctr++) < eps_ord) {
|
||||
int r = (int)(philox_uniform(i, timestep, rng_ctr++) * (float)b2_size);
|
||||
a2 = (r >= b2_size) ? b2_size - 1 : r;
|
||||
} else {
|
||||
@@ -972,14 +953,8 @@ extern "C" __global__ void experience_action_select(
|
||||
}
|
||||
}
|
||||
|
||||
/* Branch 3: urgency */
|
||||
if (eval_mode) {
|
||||
a3 = 0;
|
||||
float best_q = q_b3[0];
|
||||
for (int a = 1; a < b3_size; a++) {
|
||||
if (q_b3[a] > best_q) { best_q = q_b3[a]; a3 = a; }
|
||||
}
|
||||
} else if (philox_uniform(i, timestep, rng_ctr++) < eps_urg) {
|
||||
/* Branch 3: urgency — Boltzmann for both eval and training */
|
||||
if (!eval_mode && philox_uniform(i, timestep, rng_ctr++) < eps_urg) {
|
||||
int r = (int)(philox_uniform(i, timestep, rng_ctr++) * (float)b3_size);
|
||||
a3 = (r >= b3_size) ? b3_size - 1 : r;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user