audit: ISV-ify 10 more design constants — Schulman + bootstraps + streaming α
Per `feedback_isv_for_adaptive_bounds` + user "do all except floors
and clamp bounds": 10 more constants moved from kernel-side `#define`s
into ISV slots (78 slots total now).
## Slot additions (468-477)
RL_SCHULMAN_TOLERANCE_INDEX (468, =1.5) — shared by 4 controllers
RL_SCHULMAN_ADJUST_RATE_INDEX (469, =1.5) — shared by 4 controllers
RL_STREAM_ALPHA_INDEX (470, =0.05) — shared by var + kurt streaming
RL_KURT_GAUSSIAN_INDEX (471, =3.0)
RL_KURT_NOISE_FLOOR_INDEX (472, =1.0)
RL_TAU_BOOTSTRAP_INDEX (473, =0.005)
RL_EPS_BOOTSTRAP_INDEX (474, =0.2)
RL_ROLLOUT_BOOTSTRAP_INDEX (475, =2048)
RL_REWARD_SCALE_BOOTSTRAP_INDEX (476, =1.0)
RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX (477, =10.0)
## Skipped (per user "do all except floors and clamp bounds")
* `*_MIN`/`*_MAX` clamp bounds (algebraic domain — risk γ=1.5 nonsense)
* Numerical floors: ABS_MEAN_FLOOR=1e-6, M2_SQ_FLOOR=1e-12, EPS_PNL=1e-3
(risk div-by-zero if mis-tuned)
* C51 atom layout (V_MIN/V_MAX) — architecture, not config
## Wiring
* Shared Schulman pattern: 4 controllers (ppo_clip, target_tau,
rollout_steps, plus per_α independent KURT slots) now read TOLERANCE
+ ADJUST_RATE from the same 2 ISV slots. Single source of truth.
* Each controller's bootstrap (1st-emit on sentinel-zero) reads
isv[*_BOOTSTRAP_INDEX] instead of #define value. The `prev ==
BOOTSTRAP` first-observation replace-direct check also reads from
ISV.
* 2 streaming kernels (var + kurt) share RL_STREAM_ALPHA_INDEX.
## Diag bake-in
JSONL `isv_config` block grows by 10 new fields: schulman_tolerance,
schulman_adjust_rate, stream_alpha, kurt_gaussian, kurt_noise_floor,
tau_bootstrap, eps_bootstrap, rollout_bootstrap,
reward_scale_bootstrap, ppo_ratio_clamp_bootstrap. Total isv_config
fields: 26.
Also includes windowed action_entropy fix (was structurally 0 at
b_size=1) — accumulates EMA-smoothed action distribution over
~1k-step window, computes entropy on the windowed dist. Makes the
exploration metric meaningful at b_size=1.
## Slot total
RL_SLOTS_END: 468 → 478. **78 total ISV slots.**
## Verified gates (local sm_86)
G1 isv_bootstrap ✅ (with 10 new assertions)
G3 controllers ✅
G4 target_update ✅
integrated_smoke ✅
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -43,8 +43,9 @@
|
||||
//
|
||||
// Per `pearl_no_atomicadd`: single-thread kernel.
|
||||
|
||||
#define STREAM_ALPHA 0.05f
|
||||
#define M2_SQ_FLOOR 1e-12f
|
||||
// ISV-driven streaming-EMA α (was 0.05f #define).
|
||||
#define RL_STREAM_ALPHA_INDEX 470
|
||||
#define M2_SQ_FLOOR 1e-12f
|
||||
|
||||
// clamp_slot: ISV slot holding the output ceiling
|
||||
// (RL_TD_KURTOSIS_CLAMP_INDEX = 448). Seeded once at
|
||||
@@ -71,14 +72,17 @@ extern "C" __global__ void rl_kurtosis_streaming(
|
||||
for (int b = 0; b < b_size; ++b) batch_mean += x[b];
|
||||
batch_mean /= (float)b_size;
|
||||
|
||||
// ISV-driven streaming-EMA α (shared with var/|mean| kernel).
|
||||
const float stream_alpha = isv[RL_STREAM_ALPHA_INDEX];
|
||||
|
||||
// Streaming mean with first-observation bootstrap.
|
||||
const float mean_prev = isv[mean_slot];
|
||||
float mean_new;
|
||||
if (mean_prev == 0.0f) {
|
||||
mean_new = batch_mean;
|
||||
} else {
|
||||
mean_new = (1.0f - STREAM_ALPHA) * mean_prev
|
||||
+ STREAM_ALPHA * batch_mean;
|
||||
mean_new = (1.0f - stream_alpha) * mean_prev
|
||||
+ stream_alpha * batch_mean;
|
||||
}
|
||||
isv[mean_slot] = mean_new;
|
||||
|
||||
@@ -90,20 +94,20 @@ extern "C" __global__ void rl_kurtosis_streaming(
|
||||
const float m2_prev = isv[m2_slot];
|
||||
float m2_new;
|
||||
if (m2_prev == 0.0f && mean_prev == 0.0f) {
|
||||
m2_new = dev2; // first observation
|
||||
m2_new = dev2;
|
||||
} else {
|
||||
m2_new = (1.0f - STREAM_ALPHA) * m2_prev
|
||||
+ STREAM_ALPHA * dev2;
|
||||
m2_new = (1.0f - stream_alpha) * m2_prev
|
||||
+ stream_alpha * dev2;
|
||||
}
|
||||
isv[m2_slot] = m2_new;
|
||||
|
||||
const float m4_prev = isv[m4_slot];
|
||||
float m4_new;
|
||||
if (m4_prev == 0.0f && mean_prev == 0.0f) {
|
||||
m4_new = dev4; // first observation
|
||||
m4_new = dev4;
|
||||
} else {
|
||||
m4_new = (1.0f - STREAM_ALPHA) * m4_prev
|
||||
+ STREAM_ALPHA * dev4;
|
||||
m4_new = (1.0f - stream_alpha) * m4_prev
|
||||
+ stream_alpha * dev4;
|
||||
}
|
||||
isv[m4_slot] = m4_new;
|
||||
|
||||
|
||||
@@ -47,11 +47,11 @@
|
||||
// Kurtosis of a standard normal = 3.0 ("excess kurtosis 0" with the
|
||||
// alternative convention). Used as the breakpoint above which we start
|
||||
// raising α.
|
||||
#define KURT_GAUSSIAN 3.0f
|
||||
// ISV-driven kurtosis-to-α lift scale per `feedback_isv_for_adaptive_bounds`.
|
||||
// Default 7.0 — at kurt=10, lift = 0.2 of [PER_ALPHA_MIN, MAX]. Seeded
|
||||
// by rl_isv_write at init.
|
||||
#define RL_KURT_LIFT_SCALE_INDEX 459
|
||||
// ISV-driven kurtosis interpretation constants per
|
||||
// `feedback_isv_for_adaptive_bounds`.
|
||||
#define RL_KURT_GAUSSIAN_INDEX 471
|
||||
#define RL_KURT_NOISE_FLOOR_INDEX 472
|
||||
#define RL_KURT_LIFT_SCALE_INDEX 459
|
||||
// Noise-floor gate: if the streaming kurtosis estimator emits a value
|
||||
// below this magnitude, treat it as "no signal" (sentinel-zero proxy)
|
||||
// and hold α at the prior value. Without this, on the first few steps
|
||||
@@ -61,7 +61,7 @@
|
||||
// MIN despite zero real signal. Matches the defensive noise-floor
|
||||
// pattern on the other controllers (per
|
||||
// pearl_multiplicative_controllers_need_bounded_step_and_noise_floor).
|
||||
#define KURT_NOISE_FLOOR 1.0f
|
||||
// (KURT_NOISE_FLOOR — was 1.0f #define — now isv[RL_KURT_NOISE_FLOOR_INDEX])
|
||||
#define WIENER_ALPHA_FLOOR 0.4f
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
@@ -102,7 +102,7 @@ extern "C" __global__ void rl_per_alpha_controller(
|
||||
// differences before tails accumulate). Hold α at prev to avoid
|
||||
// dragging toward PER_ALPHA_MIN on cold-start.
|
||||
const float td_kurtosis_ema = isv[input_slot];
|
||||
if (td_kurtosis_ema > 0.0f && td_kurtosis_ema < KURT_NOISE_FLOOR) {
|
||||
if (td_kurtosis_ema > 0.0f && td_kurtosis_ema < isv[RL_KURT_NOISE_FLOOR_INDEX]) {
|
||||
// Real signal present but below the noise floor — hold prev.
|
||||
// (Strict sentinel zero handled by the prev==0 bootstrap path
|
||||
// below, which derives target from the current EMA so the
|
||||
@@ -120,7 +120,7 @@ extern "C" __global__ void rl_per_alpha_controller(
|
||||
// The 0.4-0.6 baseline keeps the steady-state output near PER's
|
||||
// canonical 0.6 (when input EMA stabilises at kurt=10) while
|
||||
// leaving headroom to lift toward 1.0 under heavy tails.
|
||||
const float kurt_excess = fmaxf(0.0f, td_kurtosis_ema - KURT_GAUSSIAN);
|
||||
const float kurt_excess = fmaxf(0.0f, td_kurtosis_ema - isv[RL_KURT_GAUSSIAN_INDEX]);
|
||||
const float kurt_lift_scale = isv[RL_KURT_LIFT_SCALE_INDEX];
|
||||
float target = 0.4f + 0.2f * (kurt_excess / kurt_lift_scale);
|
||||
target = fmaxf(PER_ALPHA_MIN, fminf(target, PER_ALPHA_MAX));
|
||||
|
||||
@@ -44,22 +44,14 @@
|
||||
#define RL_PPO_CLIP_INDEX 402
|
||||
#define EPS_MIN 0.05f
|
||||
#define EPS_MAX 0.5f
|
||||
#define EPS_BOOTSTRAP 0.2f
|
||||
// ISV-driven KL target per `feedback_isv_for_adaptive_bounds`. Default
|
||||
// 0.01 (canonical PPO Schulman 2017). Tunable at runtime by re-seeding
|
||||
// via `rl_isv_write`. The NOISE_FLOOR is derived multiplicatively from
|
||||
// this (target × 0.01) so adjusting the target proportionally adjusts
|
||||
// the floor — no separate slot needed.
|
||||
#define RL_KL_TARGET_INDEX 454
|
||||
// Noise-floor fraction: KL below `target × this` is dominated by
|
||||
// numerical noise — hold ε unchanged.
|
||||
#define KL_NOISE_FLOOR_FRAC 0.01f
|
||||
// In-band tolerance: KL within ±33% of target is "good enough" and
|
||||
// the controller holds. Outside this band it adjusts.
|
||||
#define KL_TOLERANCE 1.5f
|
||||
// Per-step multiplicative adjustment when KL is out-of-band.
|
||||
#define KL_ADJUST_RATE 1.5f
|
||||
#define WIENER_ALPHA_FLOOR 0.4f
|
||||
// ISV-driven bootstrap + KL target per `feedback_isv_for_adaptive_bounds`.
|
||||
#define RL_EPS_BOOTSTRAP_INDEX 474
|
||||
#define RL_KL_TARGET_INDEX 454
|
||||
// Schulman pattern parameters — global slots shared by 4 controllers.
|
||||
#define RL_SCHULMAN_TOLERANCE_INDEX 468
|
||||
#define RL_SCHULMAN_ADJUST_RATE_INDEX 469
|
||||
#define KL_NOISE_FLOOR_FRAC 0.01f
|
||||
#define WIENER_ALPHA_FLOOR 0.4f
|
||||
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
@@ -91,7 +83,7 @@ extern "C" __global__ void rl_ppo_clip_controller(
|
||||
const float eps_prev = isv[RL_PPO_CLIP_INDEX];
|
||||
// Bootstrap on sentinel 0.0 per pearl_first_observation_bootstrap.
|
||||
if (eps_prev == 0.0f) {
|
||||
isv[RL_PPO_CLIP_INDEX] = EPS_BOOTSTRAP;
|
||||
isv[RL_PPO_CLIP_INDEX] = isv[RL_EPS_BOOTSTRAP_INDEX];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,15 +100,15 @@ extern "C" __global__ void rl_ppo_clip_controller(
|
||||
if (kl_ema < kl_noise_floor) return;
|
||||
|
||||
// Bounded multiplicative adjustment (Schulman-style adaptive KL).
|
||||
// Schulman params from ISV — shared with target_tau, rollout_steps.
|
||||
const float tolerance = isv[RL_SCHULMAN_TOLERANCE_INDEX];
|
||||
const float adjust_rate = isv[RL_SCHULMAN_ADJUST_RATE_INDEX];
|
||||
float ratio;
|
||||
if (kl_ema > kl_target * KL_TOLERANCE) {
|
||||
// KL too high → tighten ε.
|
||||
ratio = 1.0f / KL_ADJUST_RATE;
|
||||
} else if (kl_ema < kl_target / KL_TOLERANCE) {
|
||||
// KL too low (but above noise floor) → widen ε.
|
||||
ratio = KL_ADJUST_RATE;
|
||||
if (kl_ema > kl_target * tolerance) {
|
||||
ratio = 1.0f / adjust_rate;
|
||||
} else if (kl_ema < kl_target / tolerance) {
|
||||
ratio = adjust_rate;
|
||||
} else {
|
||||
// In-band: hold.
|
||||
ratio = 1.0f;
|
||||
}
|
||||
float eps_target = eps_prev * ratio;
|
||||
@@ -127,7 +119,7 @@ extern "C" __global__ void rl_ppo_clip_controller(
|
||||
// for the rationale — the Wiener blend's bootstrap contamination
|
||||
// would otherwise leave 60% of the canonical default in the
|
||||
// output on the first real KL observation.
|
||||
if (eps_prev == EPS_BOOTSTRAP) {
|
||||
if (eps_prev == isv[RL_EPS_BOOTSTRAP_INDEX]) {
|
||||
isv[RL_PPO_CLIP_INDEX] = eps_target;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
#define RL_PPO_CLIP_INDEX 402
|
||||
#define RL_PPO_RATIO_CLAMP_MAX_INDEX 440
|
||||
|
||||
#define PPO_RATIO_CLAMP_BOOTSTRAP 10.0f
|
||||
// ISV-driven bootstrap (was 10.0f #define).
|
||||
#define RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX 477
|
||||
// ISV-driven margin multiplier per `feedback_isv_for_adaptive_bounds`.
|
||||
// Default 10.0 — clamp_max = (1+ε) × this. Seeded by rl_isv_write
|
||||
// at init. Tuning lower tightens the importance-ratio bound.
|
||||
@@ -87,7 +88,7 @@ extern "C" __global__ void rl_ppo_ratio_clamp_controller(
|
||||
|
||||
// Bootstrap on sentinel 0.0 per pearl_first_observation_bootstrap.
|
||||
if (prev == 0.0f) {
|
||||
isv[RL_PPO_RATIO_CLAMP_MAX_INDEX] = PPO_RATIO_CLAMP_BOOTSTRAP;
|
||||
isv[RL_PPO_RATIO_CLAMP_MAX_INDEX] = isv[RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ extern "C" __global__ void rl_ppo_ratio_clamp_controller(
|
||||
// step and this is the first real ε observation"; blending with the
|
||||
// bootstrap would leave 60% of the 10.0 constant in the output even
|
||||
// when ε says target should be much smaller (or larger).
|
||||
if (prev == PPO_RATIO_CLAMP_BOOTSTRAP) {
|
||||
if (prev == isv[RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX]) {
|
||||
isv[RL_PPO_RATIO_CLAMP_MAX_INDEX] = target;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
#define RL_REWARD_SCALE_INDEX 406
|
||||
#define REWARD_SCALE_MIN 1e-3f
|
||||
#define REWARD_SCALE_MAX 1e3f
|
||||
#define REWARD_SCALE_BOOTSTRAP 1.0f
|
||||
// ISV-driven bootstrap (was 1.0f #define).
|
||||
#define RL_REWARD_SCALE_BOOTSTRAP_INDEX 476
|
||||
// Floor for the mean_abs_pnl_ema denominator to guard against div-by-zero
|
||||
// when the EMA hasn't accumulated any closed trades yet.
|
||||
#define EPS_PNL 1e-3f
|
||||
@@ -77,7 +78,7 @@ extern "C" __global__ void rl_reward_scale_controller(
|
||||
const float prev = isv[RL_REWARD_SCALE_INDEX];
|
||||
// Bootstrap on sentinel 0.0 per pearl_first_observation_bootstrap.
|
||||
if (prev == 0.0f) {
|
||||
isv[RL_REWARD_SCALE_INDEX] = REWARD_SCALE_BOOTSTRAP;
|
||||
isv[RL_REWARD_SCALE_INDEX] = isv[RL_REWARD_SCALE_BOOTSTRAP_INDEX];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -114,7 +115,7 @@ extern "C" __global__ void rl_reward_scale_controller(
|
||||
// feeds V regression at magnitude 500× the atom support's
|
||||
// ±1 expectation. Replacing directly with target eliminates
|
||||
// this cold-start contamination.
|
||||
if (prev == REWARD_SCALE_BOOTSTRAP) {
|
||||
if (prev == isv[RL_REWARD_SCALE_BOOTSTRAP_INDEX]) {
|
||||
isv[RL_REWARD_SCALE_INDEX] = target;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,29 +45,17 @@
|
||||
// updates lag the data so far behind that the importance ratios blow
|
||||
// past the clip band.
|
||||
|
||||
#define RL_N_ROLLOUT_STEPS_INDEX 404
|
||||
#define ROLLOUT_MIN 256.0f
|
||||
#define ROLLOUT_MAX 8192.0f
|
||||
#define ROLLOUT_BOOTSTRAP 2048.0f
|
||||
// ISV slot holding the adaptive regression target. Per
|
||||
// `feedback_isv_for_adaptive_bounds`: target lives in ISV (seeded at
|
||||
// trainer init by rl_streaming_clamp_init, visible in diag,
|
||||
// modifiable at runtime) rather than as a kernel-side `#define`.
|
||||
// Default 5.0 — matches the b_size=1 streaming regime where var/|mean|
|
||||
// naturally lives in [1, 10]. Prior `#define = 0.1` was wrong for the
|
||||
// streaming regime, causing 99.99% WIDEN events in alpha-rl-cvf86.
|
||||
#define RL_ADV_VAR_RATIO_TARGET_INDEX 449
|
||||
// Noise-floor multiplier: input below TARGET × NOISE_FLOOR_FRAC is
|
||||
// numerical noise — hold. Derived multiplicatively from the
|
||||
// ISV-resident target so adjusting the target proportionally
|
||||
// adjusts the floor.
|
||||
#define ADV_VAR_RATIO_NOISE_FLOOR_FRAC 0.01f
|
||||
// In-band tolerance: input within ±33 % of target → hold.
|
||||
#define ADV_VAR_RATIO_TOLERANCE 1.5f
|
||||
// Per-step bounded multiplicative adjustment. 1.5× == 50% growth /
|
||||
// 33% shrinkage per fire.
|
||||
#define ADV_VAR_RATIO_ADJUST_RATE 1.5f
|
||||
#define WIENER_ALPHA_FLOOR 0.4f
|
||||
#define RL_N_ROLLOUT_STEPS_INDEX 404
|
||||
#define ROLLOUT_MIN 256.0f
|
||||
#define ROLLOUT_MAX 8192.0f
|
||||
// ISV-driven bootstrap + target.
|
||||
#define RL_ROLLOUT_BOOTSTRAP_INDEX 475
|
||||
#define RL_ADV_VAR_RATIO_TARGET_INDEX 449
|
||||
// Schulman params from shared global slots (same as ppo_clip, target_tau).
|
||||
#define RL_SCHULMAN_TOLERANCE_INDEX 468
|
||||
#define RL_SCHULMAN_ADJUST_RATE_INDEX 469
|
||||
#define ADV_VAR_RATIO_NOISE_FLOOR_FRAC 0.01f
|
||||
#define WIENER_ALPHA_FLOOR 0.4f
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// rl_rollout_steps_controller:
|
||||
@@ -102,7 +90,7 @@ extern "C" __global__ void rl_rollout_steps_controller(
|
||||
const float prev = isv[RL_N_ROLLOUT_STEPS_INDEX];
|
||||
// Bootstrap on sentinel 0.0 per pearl_first_observation_bootstrap.
|
||||
if (prev == 0.0f) {
|
||||
isv[RL_N_ROLLOUT_STEPS_INDEX] = ROLLOUT_BOOTSTRAP;
|
||||
isv[RL_N_ROLLOUT_STEPS_INDEX] = isv[RL_ROLLOUT_BOOTSTRAP_INDEX];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,17 +116,14 @@ extern "C" __global__ void rl_rollout_steps_controller(
|
||||
// how far input is from target. After several consecutive
|
||||
// out-of-band observations the output drifts smoothly toward
|
||||
// MIN/MAX, but a single observation can't slam it there.
|
||||
const float tolerance = isv[RL_SCHULMAN_TOLERANCE_INDEX];
|
||||
const float adjust_rate = isv[RL_SCHULMAN_ADJUST_RATE_INDEX];
|
||||
float scale;
|
||||
if (advantage_var_over_abs_mean
|
||||
> adv_var_target * ADV_VAR_RATIO_TOLERANCE) {
|
||||
// Noisy → widen.
|
||||
scale = ADV_VAR_RATIO_ADJUST_RATE;
|
||||
} else if (advantage_var_over_abs_mean
|
||||
< adv_var_target / ADV_VAR_RATIO_TOLERANCE) {
|
||||
// Clean → shrink.
|
||||
scale = 1.0f / ADV_VAR_RATIO_ADJUST_RATE;
|
||||
if (advantage_var_over_abs_mean > adv_var_target * tolerance) {
|
||||
scale = adjust_rate;
|
||||
} else if (advantage_var_over_abs_mean < adv_var_target / tolerance) {
|
||||
scale = 1.0f / adjust_rate;
|
||||
} else {
|
||||
// In-band: hold.
|
||||
scale = 1.0f;
|
||||
}
|
||||
float target = prev * scale;
|
||||
@@ -146,7 +131,7 @@ extern "C" __global__ void rl_rollout_steps_controller(
|
||||
|
||||
// First-observation replace-directly per
|
||||
// `pearl_first_observation_bootstrap`.
|
||||
if (prev == ROLLOUT_BOOTSTRAP) {
|
||||
if (prev == isv[RL_ROLLOUT_BOOTSTRAP_INDEX]) {
|
||||
isv[RL_N_ROLLOUT_STEPS_INDEX] = target;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,17 +28,14 @@
|
||||
#define RL_TARGET_TAU_INDEX 401
|
||||
#define TAU_MIN 0.001f
|
||||
#define TAU_MAX 0.05f
|
||||
#define TAU_BOOTSTRAP 0.005f
|
||||
// ISV-driven Q-divergence target per `feedback_isv_for_adaptive_bounds`.
|
||||
// Default 0.01 (seeded by rl_isv_write at init). Noise floor derives
|
||||
// multiplicatively from this value.
|
||||
#define RL_DIV_TARGET_INDEX 457
|
||||
#define DIV_NOISE_FLOOR_FRAC 0.01f
|
||||
// In-band tolerance: divergence within ±33 % of target → hold.
|
||||
#define DIV_TOLERANCE 1.5f
|
||||
// Bounded per-step multiplicative adjustment.
|
||||
#define DIV_ADJUST_RATE 1.5f
|
||||
#define WIENER_ALPHA_FLOOR 0.4f
|
||||
// ISV-driven bootstrap + target.
|
||||
#define RL_TAU_BOOTSTRAP_INDEX 473
|
||||
#define RL_DIV_TARGET_INDEX 457
|
||||
// Schulman params from shared global slots (same as ppo_clip).
|
||||
#define RL_SCHULMAN_TOLERANCE_INDEX 468
|
||||
#define RL_SCHULMAN_ADJUST_RATE_INDEX 469
|
||||
#define DIV_NOISE_FLOOR_FRAC 0.01f
|
||||
#define WIENER_ALPHA_FLOOR 0.4f
|
||||
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
@@ -70,7 +67,7 @@ extern "C" __global__ void rl_target_tau_controller(
|
||||
const float tau_prev = isv[RL_TARGET_TAU_INDEX];
|
||||
// Bootstrap on sentinel 0.0 per pearl_first_observation_bootstrap.
|
||||
if (tau_prev == 0.0f) {
|
||||
isv[RL_TARGET_TAU_INDEX] = TAU_BOOTSTRAP;
|
||||
isv[RL_TARGET_TAU_INDEX] = isv[RL_TAU_BOOTSTRAP_INDEX];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,10 +84,12 @@ extern "C" __global__ void rl_target_tau_controller(
|
||||
|
||||
// Bounded multiplicative adjustment.
|
||||
float ratio;
|
||||
if (q_divergence_norm > div_target * DIV_TOLERANCE) {
|
||||
ratio = DIV_ADJUST_RATE;
|
||||
} else if (q_divergence_norm < div_target / DIV_TOLERANCE) {
|
||||
ratio = 1.0f / DIV_ADJUST_RATE;
|
||||
const float tolerance = isv[RL_SCHULMAN_TOLERANCE_INDEX];
|
||||
const float adjust_rate = isv[RL_SCHULMAN_ADJUST_RATE_INDEX];
|
||||
if (q_divergence_norm > div_target * tolerance) {
|
||||
ratio = adjust_rate;
|
||||
} else if (q_divergence_norm < div_target / tolerance) {
|
||||
ratio = 1.0f / adjust_rate;
|
||||
} else {
|
||||
ratio = 1.0f;
|
||||
}
|
||||
@@ -106,7 +105,7 @@ extern "C" __global__ void rl_target_tau_controller(
|
||||
// the controller's first emit. Write target directly instead.
|
||||
// Subsequent steps (where prev has drifted off bootstrap via
|
||||
// earlier blends) take the Wiener path below.
|
||||
if (tau_prev == TAU_BOOTSTRAP) {
|
||||
if (tau_prev == isv[RL_TAU_BOOTSTRAP_INDEX]) {
|
||||
isv[RL_TARGET_TAU_INDEX] = tau_target;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
// Per `pearl_no_atomicadd`: single-thread kernel (all state lives in
|
||||
// ISV slots updated by thread 0, output also written by thread 0).
|
||||
|
||||
#define STREAM_ALPHA 0.05f
|
||||
// ISV-driven streaming-EMA α (was 0.05f #define).
|
||||
#define RL_STREAM_ALPHA_INDEX 470
|
||||
#define ABS_MEAN_FLOOR 1e-6f
|
||||
|
||||
// out_slot: ISV slot to write var/|mean| to (e.g.
|
||||
@@ -68,14 +69,17 @@ extern "C" __global__ void rl_var_over_abs_mean_streaming(
|
||||
for (int b = 0; b < b_size; ++b) batch_mean += x[b];
|
||||
batch_mean /= (float)b_size;
|
||||
|
||||
// ISV-driven streaming-EMA α (shared with kurtosis kernel).
|
||||
const float stream_alpha = isv[RL_STREAM_ALPHA_INDEX];
|
||||
|
||||
// Streaming mean update with first-observation bootstrap.
|
||||
const float mean_prev = isv[mean_slot];
|
||||
float mean_new;
|
||||
if (mean_prev == 0.0f) {
|
||||
mean_new = batch_mean;
|
||||
} else {
|
||||
mean_new = (1.0f - STREAM_ALPHA) * mean_prev
|
||||
+ STREAM_ALPHA * batch_mean;
|
||||
mean_new = (1.0f - stream_alpha) * mean_prev
|
||||
+ stream_alpha * batch_mean;
|
||||
}
|
||||
isv[mean_slot] = mean_new;
|
||||
|
||||
@@ -87,12 +91,10 @@ extern "C" __global__ void rl_var_over_abs_mean_streaming(
|
||||
const float m2_prev = isv[m2_slot];
|
||||
float m2_new;
|
||||
if (m2_prev == 0.0f && mean_prev == 0.0f) {
|
||||
// First observation: M2 starts at the current squared dev
|
||||
// (which is 0 since batch_mean = mean_new on the first step).
|
||||
m2_new = dev2;
|
||||
} else {
|
||||
m2_new = (1.0f - STREAM_ALPHA) * m2_prev
|
||||
+ STREAM_ALPHA * dev2;
|
||||
m2_new = (1.0f - stream_alpha) * m2_prev
|
||||
+ stream_alpha * dev2;
|
||||
}
|
||||
isv[m2_slot] = m2_new;
|
||||
|
||||
|
||||
@@ -47,12 +47,16 @@ use ml_alpha::rl::isv_slots::{
|
||||
RL_LR_V_STEPS_SINCE_BEST_INDEX, RL_LR_V_WARMUP_COUNTER_INDEX,
|
||||
RL_ADV_VAR_RATIO_CLAMP_INDEX, RL_ADV_VAR_RATIO_TARGET_INDEX, RL_ADV_VAR_STREAM_M2_INDEX,
|
||||
RL_ADV_VAR_STREAM_MEAN_INDEX, RL_DIV_TARGET_INDEX, RL_ENTROPY_TARGET_FRAC_INDEX,
|
||||
RL_IMPROVEMENT_THRESHOLD_INDEX, RL_KL_TARGET_INDEX, RL_KURT_LIFT_SCALE_INDEX,
|
||||
RL_EPS_BOOTSTRAP_INDEX, RL_IMPROVEMENT_THRESHOLD_INDEX, RL_KL_TARGET_INDEX,
|
||||
RL_KURT_GAUSSIAN_INDEX, RL_KURT_LIFT_SCALE_INDEX, RL_KURT_NOISE_FLOOR_INDEX,
|
||||
RL_K_LOOP_DIVISOR_INDEX, RL_K_LOOP_MAX_INDEX, RL_LOSS_LAMBDA_AUX_INDEX,
|
||||
RL_LR_BOOTSTRAP_INDEX, RL_LR_DECAY_FACTOR_INDEX, RL_LR_LOSS_EMA_ALPHA_INDEX,
|
||||
RL_LR_MAX_INDEX, RL_LR_MIN_INDEX, RL_LR_WARMUP_STEPS_INDEX,
|
||||
RL_PLATEAU_PATIENCE_INDEX, RL_PPO_CLAMP_MARGIN_INDEX, RL_Q_ARG_VS_PI_AGREE_INDEX,
|
||||
RL_REWARD_CLAMP_LOSS_INDEX, RL_REWARD_CLAMP_WIN_INDEX,
|
||||
RL_PLATEAU_PATIENCE_INDEX, RL_PPO_CLAMP_MARGIN_INDEX,
|
||||
RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX, RL_Q_ARG_VS_PI_AGREE_INDEX,
|
||||
RL_REWARD_CLAMP_LOSS_INDEX, RL_REWARD_CLAMP_WIN_INDEX, RL_REWARD_SCALE_BOOTSTRAP_INDEX,
|
||||
RL_ROLLOUT_BOOTSTRAP_INDEX, RL_SCHULMAN_ADJUST_RATE_INDEX, RL_SCHULMAN_TOLERANCE_INDEX,
|
||||
RL_STREAM_ALPHA_INDEX, RL_TAU_BOOTSTRAP_INDEX,
|
||||
RL_MAX_ABS_SCALED_REWARD_PRE_CLAMP_INDEX, RL_MEAN_ABS_PNL_EMA_INDEX,
|
||||
RL_MEAN_TRADE_DURATION_EMA_INDEX, RL_N_ROLLOUT_STEPS_INDEX, RL_PER_ALPHA_INDEX,
|
||||
RL_PI_GRAD_NORM_EMA_INDEX, RL_PPO_CLIP_INDEX, RL_PPO_LOG_RATIO_ABS_MAX_INDEX,
|
||||
@@ -404,6 +408,15 @@ fn main() -> Result<()> {
|
||||
// Per-step scratch (replaced each step via mapped-pinned helpers).
|
||||
|
||||
// ── Training loop. ───────────────────────────────────────────────
|
||||
// Windowed action distribution — EMA-smoothed across recent steps
|
||||
// so action_entropy is meaningful at b_size=1 (per-step act_hist
|
||||
// is one-hot, H=0; windowed dist captures actual policy variety).
|
||||
// α = 1/1000 → half-life ≈ 690 steps. Tracks the recent ~1k steps'
|
||||
// action distribution; entropy of normalised windowed_act_hist is
|
||||
// a real exploration signal.
|
||||
let mut windowed_act_hist: [f32; 9] = [0.0; 9];
|
||||
const WINDOWED_ACT_ALPHA: f32 = 1.0 / 1000.0;
|
||||
|
||||
let t_start = std::time::Instant::now();
|
||||
for step in 0..cli.n_steps {
|
||||
let pair = loader
|
||||
@@ -478,18 +491,29 @@ fn main() -> Result<()> {
|
||||
act_hist[a as usize] += 1;
|
||||
}
|
||||
}
|
||||
// audit — action entropy H(action_dist) per step.
|
||||
// Computed from act_hist; high entropy = exploring, low entropy =
|
||||
// collapsed to a few actions. Already computable post-hoc from
|
||||
// action_hist but emitting saves analysis cost + makes
|
||||
// exploration-collapse visible at a glance.
|
||||
// audit — action entropy H(action_dist) windowed.
|
||||
//
|
||||
// Per-batch act_hist is one-hot at b_size=1 so per-step entropy
|
||||
// is structurally 0. Maintain an EMA-smoothed action histogram
|
||||
// across recent steps (α=1/1000, half-life ≈ 690 steps) and
|
||||
// compute entropy on the normalised window. This captures the
|
||||
// actual policy exploration variety over the recent run.
|
||||
let total_actions: u32 = act_hist.iter().sum();
|
||||
let action_entropy: f32 = if total_actions > 0 {
|
||||
act_hist
|
||||
if total_actions > 0 {
|
||||
for i in 0..9 {
|
||||
let p_step = (act_hist[i] as f32) / (total_actions as f32);
|
||||
windowed_act_hist[i] = (1.0 - WINDOWED_ACT_ALPHA)
|
||||
* windowed_act_hist[i]
|
||||
+ WINDOWED_ACT_ALPHA * p_step;
|
||||
}
|
||||
}
|
||||
let win_sum: f32 = windowed_act_hist.iter().sum();
|
||||
let action_entropy: f32 = if win_sum > 1e-9 {
|
||||
windowed_act_hist
|
||||
.iter()
|
||||
.filter(|&&c| c > 0)
|
||||
.map(|&c| {
|
||||
let p = (c as f32) / (total_actions as f32);
|
||||
.filter(|&&p| p > 1e-9)
|
||||
.map(|&p_raw| {
|
||||
let p = p_raw / win_sum;
|
||||
-p * p.ln()
|
||||
})
|
||||
.sum()
|
||||
@@ -693,6 +717,16 @@ fn main() -> Result<()> {
|
||||
"lr_loss_ema_alpha": isv[RL_LR_LOSS_EMA_ALPHA_INDEX],
|
||||
"lr_decay_factor": isv[RL_LR_DECAY_FACTOR_INDEX],
|
||||
"loss_lambda_aux": isv[RL_LOSS_LAMBDA_AUX_INDEX],
|
||||
"schulman_tolerance": isv[RL_SCHULMAN_TOLERANCE_INDEX],
|
||||
"schulman_adjust_rate": isv[RL_SCHULMAN_ADJUST_RATE_INDEX],
|
||||
"stream_alpha": isv[RL_STREAM_ALPHA_INDEX],
|
||||
"kurt_gaussian": isv[RL_KURT_GAUSSIAN_INDEX],
|
||||
"kurt_noise_floor": isv[RL_KURT_NOISE_FLOOR_INDEX],
|
||||
"tau_bootstrap": isv[RL_TAU_BOOTSTRAP_INDEX],
|
||||
"eps_bootstrap": isv[RL_EPS_BOOTSTRAP_INDEX],
|
||||
"rollout_bootstrap": isv[RL_ROLLOUT_BOOTSTRAP_INDEX],
|
||||
"reward_scale_bootstrap":isv[RL_REWARD_SCALE_BOOTSTRAP_INDEX],
|
||||
"ppo_ratio_clamp_bootstrap": isv[RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX],
|
||||
},
|
||||
// audit — Q vs π action agreement EMA at slot 407
|
||||
// (previously dead). 1.0 = perfect ranking consistency,
|
||||
|
||||
@@ -35,9 +35,11 @@
|
||||
//! | 447-448 | Streaming output clamp ceilings | rl_streaming_clamp_init (seed) |
|
||||
//! | 449 | adv_var_ratio target (controller) | rl_streaming_clamp_init (seed) |
|
||||
//! | 450-451 | K-loop divisor + max | rl_streaming_clamp_init (seed) |
|
||||
//! | 452-461 | 10 ISV-driven design constants | rl_isv_write (seed loop) |
|
||||
//! | 452-461 | 10 ISV-driven design constants (first batch) | rl_isv_write (seed loop) |
|
||||
//! | 462-467 | 6 LR-controller numerics + aux λ | rl_isv_write (seed loop) |
|
||||
//! | 468-477 | 10 design constants (Schulman + bootstraps + streaming α + kurt refs) | rl_isv_write |
|
||||
//!
|
||||
//! Total: 62 slots; `RL_SLOTS_END = 462`.
|
||||
//! Total: 78 slots; `RL_SLOTS_END = 478`.
|
||||
|
||||
/// Discount factor γ. Controller input: mean trade duration / anchor.
|
||||
/// Bootstrap 0.99.
|
||||
@@ -503,6 +505,49 @@ pub const RL_LR_DECAY_FACTOR_INDEX: usize = 466;
|
||||
// separate path. Adding aux to ISV for full coverage:
|
||||
pub const RL_LOSS_LAMBDA_AUX_INDEX: usize = 467;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// Schulman bounded-step pattern parameters (shared by 4 multiplicative
|
||||
// controllers — ppo_clip, target_tau, rollout_steps, per_α). Made
|
||||
// global because all 4 use the same algorithm with identical defaults.
|
||||
|
||||
/// In-band tolerance for Schulman controllers: input within ±33 % of
|
||||
/// target → hold. Default 1.5.
|
||||
pub const RL_SCHULMAN_TOLERANCE_INDEX: usize = 468;
|
||||
|
||||
/// Per-step bounded multiplicative adjustment for Schulman controllers.
|
||||
/// Default 1.5 (50 % growth / 33 % shrinkage per fire).
|
||||
pub const RL_SCHULMAN_ADJUST_RATE_INDEX: usize = 469;
|
||||
|
||||
/// Streaming-EMA α shared by var/|mean| and kurtosis streaming kernels.
|
||||
/// Default 0.05 (half-life ≈ 14 steps).
|
||||
pub const RL_STREAM_ALPHA_INDEX: usize = 470;
|
||||
|
||||
/// Kurtosis of standard normal (Pearson). Default 3.0. Tuning permits
|
||||
/// domain-specific overrides.
|
||||
pub const RL_KURT_GAUSSIAN_INDEX: usize = 471;
|
||||
|
||||
/// Kurtosis noise-floor for per_α controller. Default 1.0.
|
||||
pub const RL_KURT_NOISE_FLOOR_INDEX: usize = 472;
|
||||
|
||||
// Controller bootstrap values — first-emit defaults previously held
|
||||
// in kernel-side `#define`s.
|
||||
|
||||
/// τ bootstrap (target-net soft update Polyak step). Default 0.005.
|
||||
pub const RL_TAU_BOOTSTRAP_INDEX: usize = 473;
|
||||
|
||||
/// ε bootstrap (PPO clip half-width canonical default). Default 0.2.
|
||||
pub const RL_EPS_BOOTSTRAP_INDEX: usize = 474;
|
||||
|
||||
/// Rollout-steps bootstrap. Default 2048 (matches K-loop divisor so
|
||||
/// K=1 at controller bootstrap).
|
||||
pub const RL_ROLLOUT_BOOTSTRAP_INDEX: usize = 475;
|
||||
|
||||
/// Reward-scale bootstrap (raw passthrough). Default 1.0.
|
||||
pub const RL_REWARD_SCALE_BOOTSTRAP_INDEX: usize = 476;
|
||||
|
||||
/// PPO ratio-clamp bootstrap. Default 10.0.
|
||||
pub const RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX: usize = 477;
|
||||
|
||||
/// Last RL-allocated slot index (exclusive). The integrated trainer
|
||||
/// extends `ISV_TOTAL_DIM` to at least this value at trainer init time.
|
||||
pub const RL_SLOTS_END: usize = 468;
|
||||
pub const RL_SLOTS_END: usize = 478;
|
||||
|
||||
@@ -1170,7 +1170,7 @@ impl IntegratedTrainer {
|
||||
// (slot, value) pair — pure device write, no HtoD per
|
||||
// `feedback_no_htod_htoh_only_mapped_pinned`.
|
||||
{
|
||||
let isv_constants: [(usize, f32); 16] = [
|
||||
let isv_constants: [(usize, f32); 26] = [
|
||||
(crate::rl::isv_slots::RL_REWARD_CLAMP_WIN_INDEX, 1.0),
|
||||
(crate::rl::isv_slots::RL_REWARD_CLAMP_LOSS_INDEX, 3.0),
|
||||
(crate::rl::isv_slots::RL_KL_TARGET_INDEX, 0.01),
|
||||
@@ -1181,13 +1181,23 @@ impl IntegratedTrainer {
|
||||
(crate::rl::isv_slots::RL_KURT_LIFT_SCALE_INDEX, 7.0),
|
||||
(crate::rl::isv_slots::RL_PPO_CLAMP_MARGIN_INDEX, 10.0),
|
||||
(crate::rl::isv_slots::RL_LR_WARMUP_STEPS_INDEX, 2000.0),
|
||||
// audit additions:
|
||||
(crate::rl::isv_slots::RL_LR_BOOTSTRAP_INDEX, 1e-3),
|
||||
(crate::rl::isv_slots::RL_LR_MIN_INDEX, 1e-4),
|
||||
(crate::rl::isv_slots::RL_LR_MAX_INDEX, 1e-2),
|
||||
(crate::rl::isv_slots::RL_LR_LOSS_EMA_ALPHA_INDEX, 0.05),
|
||||
(crate::rl::isv_slots::RL_LR_DECAY_FACTOR_INDEX, 0.5),
|
||||
(crate::rl::isv_slots::RL_LOSS_LAMBDA_AUX_INDEX, 1.0),
|
||||
// Batch 3 — Schulman pattern + streaming α + kurt refs + bootstraps.
|
||||
(crate::rl::isv_slots::RL_SCHULMAN_TOLERANCE_INDEX, 1.5),
|
||||
(crate::rl::isv_slots::RL_SCHULMAN_ADJUST_RATE_INDEX, 1.5),
|
||||
(crate::rl::isv_slots::RL_STREAM_ALPHA_INDEX, 0.05),
|
||||
(crate::rl::isv_slots::RL_KURT_GAUSSIAN_INDEX, 3.0),
|
||||
(crate::rl::isv_slots::RL_KURT_NOISE_FLOOR_INDEX, 1.0),
|
||||
(crate::rl::isv_slots::RL_TAU_BOOTSTRAP_INDEX, 0.005),
|
||||
(crate::rl::isv_slots::RL_EPS_BOOTSTRAP_INDEX, 0.2),
|
||||
(crate::rl::isv_slots::RL_ROLLOUT_BOOTSTRAP_INDEX, 2048.0),
|
||||
(crate::rl::isv_slots::RL_REWARD_SCALE_BOOTSTRAP_INDEX, 1.0),
|
||||
(crate::rl::isv_slots::RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX, 10.0),
|
||||
];
|
||||
let cfg_isv = LaunchConfig {
|
||||
grid_dim: (1, 1, 1),
|
||||
|
||||
@@ -24,15 +24,19 @@
|
||||
|
||||
use ml_alpha::rl::isv_slots::{
|
||||
RL_ADV_VAR_RATIO_CLAMP_INDEX, RL_ADV_VAR_RATIO_TARGET_INDEX, RL_DIV_TARGET_INDEX,
|
||||
RL_ENTROPY_COEF_INDEX, RL_ENTROPY_TARGET_FRAC_INDEX, RL_GAMMA_INDEX,
|
||||
RL_IMPROVEMENT_THRESHOLD_INDEX, RL_KL_TARGET_INDEX, RL_KURT_LIFT_SCALE_INDEX,
|
||||
RL_ENTROPY_COEF_INDEX, RL_ENTROPY_TARGET_FRAC_INDEX, RL_EPS_BOOTSTRAP_INDEX,
|
||||
RL_GAMMA_INDEX, RL_IMPROVEMENT_THRESHOLD_INDEX, RL_KL_TARGET_INDEX,
|
||||
RL_KURT_GAUSSIAN_INDEX, RL_KURT_LIFT_SCALE_INDEX, RL_KURT_NOISE_FLOOR_INDEX,
|
||||
RL_K_LOOP_DIVISOR_INDEX, RL_K_LOOP_MAX_INDEX, RL_LOSS_LAMBDA_AUX_INDEX,
|
||||
RL_LR_BOOTSTRAP_INDEX, RL_LR_DECAY_FACTOR_INDEX, RL_LR_LOSS_EMA_ALPHA_INDEX,
|
||||
RL_LR_MAX_INDEX, RL_LR_MIN_INDEX, RL_LR_WARMUP_STEPS_INDEX,
|
||||
RL_MEAN_TRADE_DURATION_EMA_INDEX, RL_N_ROLLOUT_STEPS_INDEX, RL_PER_ALPHA_INDEX,
|
||||
RL_PLATEAU_PATIENCE_INDEX, RL_PPO_CLAMP_MARGIN_INDEX, RL_PPO_CLIP_INDEX,
|
||||
RL_PPO_RATIO_CLAMP_MAX_INDEX, RL_REWARD_CLAMP_LOSS_INDEX, RL_REWARD_CLAMP_WIN_INDEX,
|
||||
RL_REWARD_SCALE_INDEX, RL_SLOTS_END, RL_TARGET_TAU_INDEX, RL_TD_KURTOSIS_CLAMP_INDEX,
|
||||
RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX, RL_PPO_RATIO_CLAMP_MAX_INDEX,
|
||||
RL_REWARD_CLAMP_LOSS_INDEX, RL_REWARD_CLAMP_WIN_INDEX, RL_REWARD_SCALE_BOOTSTRAP_INDEX,
|
||||
RL_REWARD_SCALE_INDEX, RL_ROLLOUT_BOOTSTRAP_INDEX, RL_SCHULMAN_ADJUST_RATE_INDEX,
|
||||
RL_SCHULMAN_TOLERANCE_INDEX, RL_SLOTS_END, RL_STREAM_ALPHA_INDEX, RL_TARGET_TAU_INDEX,
|
||||
RL_TAU_BOOTSTRAP_INDEX, RL_TD_KURTOSIS_CLAMP_INDEX,
|
||||
};
|
||||
use ml_alpha::trainer::integrated::{IntegratedTrainer, IntegratedTrainerConfig};
|
||||
use ml_alpha::trainer::perception::PerceptionTrainerConfig;
|
||||
@@ -174,6 +178,16 @@ fn g1_isv_bootstrap_writes_canonical_values() {
|
||||
|| slot == RL_LR_LOSS_EMA_ALPHA_INDEX
|
||||
|| slot == RL_LR_DECAY_FACTOR_INDEX
|
||||
|| slot == RL_LOSS_LAMBDA_AUX_INDEX
|
||||
|| slot == RL_SCHULMAN_TOLERANCE_INDEX
|
||||
|| slot == RL_SCHULMAN_ADJUST_RATE_INDEX
|
||||
|| slot == RL_STREAM_ALPHA_INDEX
|
||||
|| slot == RL_KURT_GAUSSIAN_INDEX
|
||||
|| slot == RL_KURT_NOISE_FLOOR_INDEX
|
||||
|| slot == RL_TAU_BOOTSTRAP_INDEX
|
||||
|| slot == RL_EPS_BOOTSTRAP_INDEX
|
||||
|| slot == RL_ROLLOUT_BOOTSTRAP_INDEX
|
||||
|| slot == RL_REWARD_SCALE_BOOTSTRAP_INDEX
|
||||
|| slot == RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -236,6 +250,16 @@ fn g1_isv_bootstrap_writes_canonical_values() {
|
||||
assert!((isv[RL_LR_LOSS_EMA_ALPHA_INDEX] - 0.05).abs() < EPS);
|
||||
assert!((isv[RL_LR_DECAY_FACTOR_INDEX] - 0.5).abs() < EPS);
|
||||
assert!((isv[RL_LOSS_LAMBDA_AUX_INDEX] - 1.0).abs() < EPS);
|
||||
assert!((isv[RL_SCHULMAN_TOLERANCE_INDEX] - 1.5).abs() < EPS);
|
||||
assert!((isv[RL_SCHULMAN_ADJUST_RATE_INDEX] - 1.5).abs() < EPS);
|
||||
assert!((isv[RL_STREAM_ALPHA_INDEX] - 0.05).abs() < EPS);
|
||||
assert!((isv[RL_KURT_GAUSSIAN_INDEX] - 3.0).abs() < EPS);
|
||||
assert!((isv[RL_KURT_NOISE_FLOOR_INDEX] - 1.0).abs() < EPS);
|
||||
assert!((isv[RL_TAU_BOOTSTRAP_INDEX] - 0.005).abs() < EPS);
|
||||
assert!((isv[RL_EPS_BOOTSTRAP_INDEX] - 0.2).abs() < EPS);
|
||||
assert!((isv[RL_ROLLOUT_BOOTSTRAP_INDEX] - 2048.0).abs() < EPS);
|
||||
assert!((isv[RL_REWARD_SCALE_BOOTSTRAP_INDEX] - 1.0).abs() < EPS);
|
||||
assert!((isv[RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX] - 10.0).abs() < EPS);
|
||||
|
||||
eprintln!(
|
||||
"G1 OK — bootstraps: γ={:.4} τ={:.4} ε={:.4} entropy_coef={:.4} \
|
||||
|
||||
@@ -28,16 +28,20 @@ use cudarc::driver::CudaStream;
|
||||
use ml_alpha::rl::isv_slots::{
|
||||
RL_ADVANTAGE_VAR_RATIO_EMA_INDEX, RL_ADV_VAR_RATIO_CLAMP_INDEX,
|
||||
RL_ADV_VAR_RATIO_TARGET_INDEX, RL_DIV_TARGET_INDEX, RL_ENTROPY_COEF_INDEX,
|
||||
RL_ENTROPY_OBSERVED_EMA_INDEX, RL_ENTROPY_TARGET_FRAC_INDEX, RL_GAMMA_INDEX,
|
||||
RL_IMPROVEMENT_THRESHOLD_INDEX, RL_KL_PI_EMA_INDEX, RL_KL_TARGET_INDEX,
|
||||
RL_KURT_LIFT_SCALE_INDEX, RL_K_LOOP_DIVISOR_INDEX, RL_K_LOOP_MAX_INDEX,
|
||||
RL_ENTROPY_OBSERVED_EMA_INDEX, RL_ENTROPY_TARGET_FRAC_INDEX, RL_EPS_BOOTSTRAP_INDEX,
|
||||
RL_GAMMA_INDEX, RL_IMPROVEMENT_THRESHOLD_INDEX, RL_KL_PI_EMA_INDEX,
|
||||
RL_KL_TARGET_INDEX, RL_KURT_GAUSSIAN_INDEX, RL_KURT_LIFT_SCALE_INDEX,
|
||||
RL_KURT_NOISE_FLOOR_INDEX, RL_K_LOOP_DIVISOR_INDEX, RL_K_LOOP_MAX_INDEX,
|
||||
RL_LOSS_LAMBDA_AUX_INDEX, RL_LR_BOOTSTRAP_INDEX, RL_LR_DECAY_FACTOR_INDEX,
|
||||
RL_LR_LOSS_EMA_ALPHA_INDEX, RL_LR_MAX_INDEX, RL_LR_MIN_INDEX, RL_LR_WARMUP_STEPS_INDEX,
|
||||
RL_MEAN_ABS_PNL_EMA_INDEX, RL_MEAN_TRADE_DURATION_EMA_INDEX, RL_N_ROLLOUT_STEPS_INDEX,
|
||||
RL_PER_ALPHA_INDEX, RL_PLATEAU_PATIENCE_INDEX, RL_PPO_CLAMP_MARGIN_INDEX,
|
||||
RL_PPO_CLIP_INDEX, RL_PPO_RATIO_CLAMP_MAX_INDEX, RL_Q_DIVERGENCE_EMA_INDEX,
|
||||
RL_REWARD_CLAMP_LOSS_INDEX, RL_REWARD_CLAMP_WIN_INDEX, RL_REWARD_SCALE_INDEX,
|
||||
RL_SLOTS_END, RL_TARGET_TAU_INDEX, RL_TD_KURTOSIS_CLAMP_INDEX, RL_TD_KURTOSIS_EMA_INDEX,
|
||||
RL_PPO_CLIP_INDEX, RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX, RL_PPO_RATIO_CLAMP_MAX_INDEX,
|
||||
RL_Q_DIVERGENCE_EMA_INDEX, RL_REWARD_CLAMP_LOSS_INDEX, RL_REWARD_CLAMP_WIN_INDEX,
|
||||
RL_REWARD_SCALE_BOOTSTRAP_INDEX, RL_REWARD_SCALE_INDEX, RL_ROLLOUT_BOOTSTRAP_INDEX,
|
||||
RL_SCHULMAN_ADJUST_RATE_INDEX, RL_SCHULMAN_TOLERANCE_INDEX, RL_SLOTS_END,
|
||||
RL_STREAM_ALPHA_INDEX, RL_TARGET_TAU_INDEX, RL_TAU_BOOTSTRAP_INDEX,
|
||||
RL_TD_KURTOSIS_CLAMP_INDEX, RL_TD_KURTOSIS_EMA_INDEX,
|
||||
};
|
||||
use ml_alpha::trainer::integrated::{IntegratedTrainer, IntegratedTrainerConfig};
|
||||
use ml_alpha::trainer::perception::PerceptionTrainerConfig;
|
||||
@@ -144,6 +148,16 @@ fn g3_per_step_controllers_move_isv_outputs_when_fed_real_emas() {
|
||||
|| slot == RL_LR_LOSS_EMA_ALPHA_INDEX
|
||||
|| slot == RL_LR_DECAY_FACTOR_INDEX
|
||||
|| slot == RL_LOSS_LAMBDA_AUX_INDEX
|
||||
|| slot == RL_SCHULMAN_TOLERANCE_INDEX
|
||||
|| slot == RL_SCHULMAN_ADJUST_RATE_INDEX
|
||||
|| slot == RL_STREAM_ALPHA_INDEX
|
||||
|| slot == RL_KURT_GAUSSIAN_INDEX
|
||||
|| slot == RL_KURT_NOISE_FLOOR_INDEX
|
||||
|| slot == RL_TAU_BOOTSTRAP_INDEX
|
||||
|| slot == RL_EPS_BOOTSTRAP_INDEX
|
||||
|| slot == RL_ROLLOUT_BOOTSTRAP_INDEX
|
||||
|| slot == RL_REWARD_SCALE_BOOTSTRAP_INDEX
|
||||
|| slot == RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -171,6 +185,16 @@ fn g3_per_step_controllers_move_isv_outputs_when_fed_real_emas() {
|
||||
assert!((isv_before[RL_LR_LOSS_EMA_ALPHA_INDEX] - 0.05).abs() < 1e-7);
|
||||
assert_eq!(isv_before[RL_LR_DECAY_FACTOR_INDEX], 0.5);
|
||||
assert_eq!(isv_before[RL_LOSS_LAMBDA_AUX_INDEX], 1.0);
|
||||
assert_eq!(isv_before[RL_SCHULMAN_TOLERANCE_INDEX], 1.5);
|
||||
assert_eq!(isv_before[RL_SCHULMAN_ADJUST_RATE_INDEX], 1.5);
|
||||
assert!((isv_before[RL_STREAM_ALPHA_INDEX] - 0.05).abs() < 1e-7);
|
||||
assert_eq!(isv_before[RL_KURT_GAUSSIAN_INDEX], 3.0);
|
||||
assert_eq!(isv_before[RL_KURT_NOISE_FLOOR_INDEX], 1.0);
|
||||
assert!((isv_before[RL_TAU_BOOTSTRAP_INDEX] - 0.005).abs() < 1e-7);
|
||||
assert!((isv_before[RL_EPS_BOOTSTRAP_INDEX] - 0.2).abs() < 1e-7);
|
||||
assert_eq!(isv_before[RL_ROLLOUT_BOOTSTRAP_INDEX], 2048.0);
|
||||
assert_eq!(isv_before[RL_REWARD_SCALE_BOOTSTRAP_INDEX], 1.0);
|
||||
assert_eq!(isv_before[RL_PPO_RATIO_CLAMP_BOOTSTRAP_INDEX], 10.0);
|
||||
|
||||
// Populate each EMA-input slot with a non-zero value via the
|
||||
// R3 ema_update_per_step bootstrap path (sentinel-zero → first
|
||||
|
||||
Reference in New Issue
Block a user