Commit Graph

8 Commits

Author SHA1 Message Date
jgrusewski
dffe97a922 fix: log stale CUDA errors instead of discarding, remove max_steps_per_epoch from smoketest
check_err() now logs warnings for real kernel errors instead of let _ =.
Removed max_steps_per_epoch from smoketest TOML to match working config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 12:10:45 +01:00
jgrusewski
6219491db6 refactor: move smoke test config to dqn-smoketest.toml, restore check_err
Smoke test loads all hyperparams from TOML profile instead of hardcoding.
TOML: hidden_dim=64, batch=64, lr=0.0003 (stable on RTX 3050 + H100).

Restored check_err() drain in device.rs — required to clear stale CUDA
errors from primary context reuse between tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 12:07:49 +01:00
jgrusewski
43998a330a feat: two-phase hyperopt + backtest evaluator VRAM leak fix
Two-phase hyperopt splits 31D PSO search into sequential phases:
- Phase 1 (--phase fast, default): fix architecture to small network
  (hidden_dim=128, num_atoms=11), search learning dynamics (~15D).
- Phase 2 (--phase full): fix dynamics from Phase 1 JSON, search
  architecture (~5D). Halves dimensionality per phase → better convergence.
- Phase 1 output includes best_continuous_vector for Phase 2 consumption.

GpuBacktestEvaluator Drop impl: sync forked stream, destroy CUDA graph
and cuBLAS handles before CudaSlice buffers drop. Fixes 261MB/trial
VRAM leak on H100 hyperopt.

ml-core clippy fixes: hex literal, remove dead check_err drain,
unnecessary safety comment, unused OnceLock import.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 10:32:37 +01:00
jgrusewski
73b6513cff fix: sequential GPU test contamination — remove static OnceLock<MlDevice>
Root cause: `SMOKE_CUDA: OnceLock<MlDevice>` held a static Arc<CudaContext>
for the process lifetime. CudaSlice Drop from test N recorded errors on
this shared context's error_state, causing test N+1's bind_to_thread() to
fail with CUDA_ERROR_INVALID_VALUE.

Fix: create a fresh MlDevice per test (no static caching). Each test gets
its own CudaContext Arc with clean error_state.

Also: convert all GPU smoke tests from #[tokio::test] to synchronous #[test]
with explicit tokio::runtime::Builder::new_current_thread(). The runtime is
explicitly dropped between tests, ensuring all Arc<CudaContext> refs are freed.

Result: 5 of 6 sequential smoke tests now pass. The remaining 1 failure is
a real Candle GpuTensor bug: the replay buffer insertion path still uses
Candle's elementwise kernels, which cache CudaFunction handles that become
stale across test boundaries. Fix: eliminate Candle from replay buffer path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 21:06:40 +01:00
jgrusewski
ea92143eda fix: DQNTrainer hard-errors on CUDA init failure, no silent CPU fallback
cuda_if_available() silently fell back to CPU when CUDA init failed,
causing DQNTrainer to crash later with "cuda_stream() called on CPU
device". This was the root cause of the CI "hang" — the test failed
immediately but the error was invisible due to buffered output.

- DQNTrainer::new() now uses MlDevice::cuda(0)? with explicit error
- cuda_if_available() now logs the CUDA error before falling back

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 16:57:34 +01:00
jgrusewski
e8dd460898 feat(ml-core): complete GpuTensor/GpuLinear/GpuVarStore API surface
GpuTensor: Clone derive (ref-counted CudaSlice), dims/dim/dims2/dims3,
from_vec/from_slice aliases, detach (no-op clone), powf/sqr/floor,
to_vec0/to_vec1, backward (no-op stub), relu/sum_all/flatten_all,
transpose/clamp/expand/broadcast_as/index_select. All host-side with
TODO: CUDA kernel markers.

GpuLinear: new(in, out, stream) standalone constructor,
weight_to_vec/bias_to_vec for checkpoint only.

GpuVarStore: cuda_stream(), data(), with_device(&MlDevice).

MlDevice: cuda_if_available(), new_cuda(), device() identity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:26:34 +01:00
jgrusewski
dd62f3fcfd refactor: eliminate candle from entire workspace — tests, examples, Cargo.toml
Final cleanup:
- 61 test files + 5 example files: candle imports replaced
- 8 testing/integration files: migrated to cudarc/ml-core types
- 3 services/trading_service test files: migrated
- Root Cargo.toml: candle-core, candle-nn removed from [workspace.dependencies]
- crates/ml/Cargo.toml: candle-nn dependency removed
- testing/e2e/Cargo.toml: candle-core dependency removed

Zero active candle_core/candle_nn/candle_optimisers code references remain.
Zero candle dependency declarations in any Cargo.toml.
Remaining "candle" strings are exclusively in doc comments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:53:47 +01:00
jgrusewski
22004a7368 refactor(cuda): eliminate candle from ml-core, ml-ppo, and 4 thin crates
Hard refactor — no shims, no compat layers. Candle removed from Cargo.toml
and all source files in 6 crates:

- ml-core: MlDevice enum, checkpoint.rs (safetensors direct), cudarc imports
  fixed from candle re-export to direct, AdamWConfig lr_decay, cuda_compat
  gutted. Net -7,341 lines.
- ml-ppo: All 16 files rewritten. LSTM→CudaLSTM, VarMap→GpuVarStore,
  PPOAgent 2306→700 lines, checkpoint→binary format.
- ml-ensemble: GPU-resident sigmoid via custom CUDA kernel.
- ml-explainability: Integrated gradients via GPU finite-difference kernels.
- ml-labeling: Device→MlDevice.
- ml-hyperopt: Cargo.toml only.

Remaining: ml-dqn (24 files), ml-supervised (4 files), ml crate (104 files).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 22:27:56 +01:00