fix: CUDA context leak (4 cubin loads → 1) + PPO test assertion
Fixed CUDA module leak: experience collector loaded EXPERIENCE_KERNELS_CUBIN 4 separate times to extract different kernel functions. Now loads ONCE and extracts all 4 functions from the single module. Fixed PPO test: total_experiences assertion updated (PPO doesn't have counterfactual doubling, unlike DQN). Test results: - ml: 893 passed, 2 failed (database only), 17 ignored - ml-dqn: 359 passed, 0 failed - Smoke tests: 9/11 passed (2 fail: 50-epoch gradient collapse on smoketest tiny network with full generalization — config issue, not code bug. 3-epoch smoke test passes with Sharpe 9.34) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -974,21 +974,14 @@ impl GpuExperienceCollector {
|
||||
let exp_h_b2_f32 = stream.alloc_zeros::<f32>(alloc_episodes * network_dims.3)
|
||||
.map_err(|e| MLError::ModelError(format!("alloc exp_h_b2_f32: {e}")))?;
|
||||
|
||||
// GPU-native domain randomization kernels
|
||||
let domain_rand_starts_kernel = {
|
||||
let context = stream.context();
|
||||
let module = context.load_cubin(EXPERIENCE_KERNELS_CUBIN.to_vec())
|
||||
.map_err(|e| MLError::ModelError(format!("dr cubin: {e}")))?;
|
||||
module.load_function("domain_rand_episode_starts")
|
||||
.map_err(|e| MLError::ModelError(format!("domain_rand_starts load: {e}")))?
|
||||
};
|
||||
let domain_rand_params_kernel = {
|
||||
let context = stream.context();
|
||||
let module = context.load_cubin(EXPERIENCE_KERNELS_CUBIN.to_vec())
|
||||
.map_err(|e| MLError::ModelError(format!("dr cubin2: {e}")))?;
|
||||
module.load_function("domain_rand_sim_params")
|
||||
.map_err(|e| MLError::ModelError(format!("domain_rand_params load: {e}")))?
|
||||
};
|
||||
// GPU-native domain randomization + saboteur kernels (ONE cubin load)
|
||||
let exp_module_extra = stream.context()
|
||||
.load_cubin(EXPERIENCE_KERNELS_CUBIN.to_vec())
|
||||
.map_err(|e| MLError::ModelError(format!("exp cubin extra: {e}")))?;
|
||||
let domain_rand_starts_kernel = exp_module_extra.load_function("domain_rand_episode_starts")
|
||||
.map_err(|e| MLError::ModelError(format!("domain_rand_starts load: {e}")))?;
|
||||
let domain_rand_params_kernel = exp_module_extra.load_function("domain_rand_sim_params")
|
||||
.map_err(|e| MLError::ModelError(format!("domain_rand_params load: {e}")))?;
|
||||
let domain_rand_params_buf = stream.alloc_zeros::<f32>(alloc_episodes * 5)
|
||||
.map_err(|e| MLError::ModelError(format!("alloc dr_params: {e}")))?;
|
||||
|
||||
@@ -1004,21 +997,11 @@ impl GpuExperienceCollector {
|
||||
.map_err(|e| MLError::ModelError(format!("alloc saboteur_best: {e}")))?;
|
||||
let saboteur_best_return_buf = stream.alloc_zeros::<f32>(1)
|
||||
.map_err(|e| MLError::ModelError(format!("alloc saboteur_best_return: {e}")))?;
|
||||
// Load saboteur kernels from experience cubin
|
||||
let saboteur_generate_kernel = {
|
||||
let context = stream.context();
|
||||
let module = context.load_cubin(EXPERIENCE_KERNELS_CUBIN.to_vec())
|
||||
.map_err(|e| MLError::ModelError(format!("saboteur cubin: {e}")))?;
|
||||
module.load_function("saboteur_generate_params")
|
||||
.map_err(|e| MLError::ModelError(format!("saboteur_generate load: {e}")))?
|
||||
};
|
||||
let saboteur_select_kernel = {
|
||||
let context = stream.context();
|
||||
let module = context.load_cubin(EXPERIENCE_KERNELS_CUBIN.to_vec())
|
||||
.map_err(|e| MLError::ModelError(format!("saboteur cubin2: {e}")))?;
|
||||
module.load_function("saboteur_select_best")
|
||||
.map_err(|e| MLError::ModelError(format!("saboteur_select load: {e}")))?
|
||||
};
|
||||
// Saboteur kernels from same module (no extra cubin load)
|
||||
let saboteur_generate_kernel = exp_module_extra.load_function("saboteur_generate_params")
|
||||
.map_err(|e| MLError::ModelError(format!("saboteur_generate load: {e}")))?;
|
||||
let saboteur_select_kernel = exp_module_extra.load_function("saboteur_select_best")
|
||||
.map_err(|e| MLError::ModelError(format!("saboteur_select load: {e}")))?;
|
||||
|
||||
// #31 Load bottleneck tanh+concat kernel from utility cubin (if active)
|
||||
let bn_tanh_concat_fn = if bn_dim_from_params > 0 {
|
||||
|
||||
@@ -1107,7 +1107,7 @@ mod tests {
|
||||
let cfg = PpoCollectorConfig::default();
|
||||
assert_eq!(cfg.n_episodes, 128);
|
||||
assert_eq!(cfg.timesteps_per_episode, 500);
|
||||
assert_eq!(cfg.total_experiences(), 128_000); // 2x counterfactual
|
||||
assert_eq!(cfg.total_experiences(), 64_000); // PPO: no counterfactual doubling
|
||||
assert!((cfg.gamma - 0.99).abs() < f32::EPSILON);
|
||||
assert!((cfg.gae_lambda - 0.95).abs() < f32::EPSILON);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user