docs: fix 5 chunk 2 re-review issues in CUDA backtest plan
- Task 9: memcpy_stod_inplace → memcpy_htod (cudarc 0.17 API) - Task 9: Fix transposed actions_history layout — accumulate CPU-side in window-major [window][step] layout, upload once before metrics kernel - Task 9: Replace non-existent Tensor::from_raw_buffer with download- and-reupload pattern (temporary, replaced by Task 11 GPU gather kernel) - Task 10: DqnOptimizer → DQNTrainer (hyperopt adapter) (actual struct name) - Task 10: internal_trainer type → &InternalDQNTrainer (avoids name conflict with adapter's own DQNTrainer alias) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1169,7 +1169,11 @@ pub struct GpuBacktestEvaluator {
|
||||
actions_history_buf: CudaSlice<i32>, // [n_windows * max_len]
|
||||
|
||||
// Output
|
||||
metrics_buf: CudaSlice<f32>, // [n_windows * 6]
|
||||
metrics_buf: CudaSlice<f32>, // [n_windows * 10]
|
||||
|
||||
// CPU-side action history (window-major: [window][step])
|
||||
// Accumulated during step loop, uploaded once before metrics kernel.
|
||||
actions_history_cpu: Vec<i32>, // [n_windows * max_len]
|
||||
|
||||
// Config
|
||||
n_windows: usize,
|
||||
@@ -1280,6 +1284,7 @@ impl GpuBacktestEvaluator {
|
||||
prices_buf, features_buf, window_lens_buf,
|
||||
portfolio_buf, step_rewards_buf, step_returns_buf,
|
||||
done_buf, actions_buf, actions_history_buf, metrics_buf,
|
||||
actions_history_cpu: vec![0_i32; n_windows * max_len],
|
||||
n_windows, max_len, feature_dim, config,
|
||||
})
|
||||
}
|
||||
@@ -1308,9 +1313,17 @@ impl GpuBacktestEvaluator {
|
||||
// For initial correctness, we use Candle narrow ops + small portfolio download.
|
||||
// Use Candle narrow ops to gather from GPU features tensor
|
||||
// without downloading the full buffer.
|
||||
let features_tensor = Tensor::from_raw_buffer(
|
||||
&self.features_buf, DType::F32,
|
||||
&[self.n_windows, self.max_len, self.feature_dim], device,
|
||||
// Wrap pre-uploaded CudaSlice as Candle Tensor.
|
||||
// NOTE: `Tensor::from_raw_buffer` does not exist in Candle. Use the established
|
||||
// pattern: allocate zeros tensor, extract CudaSlice via storage_and_layout(),
|
||||
// then memcpy_dtod_async. Or simply download-and-reupload for this temporary path.
|
||||
// This gather_states is replaced by a GPU gather kernel in Task 11 anyway.
|
||||
let mut flat_feats = vec![0.0_f32; self.n_windows * self.max_len * self.feature_dim];
|
||||
self.stream.memcpy_dtoh(&self.features_buf, &mut flat_feats)
|
||||
.map_err(|e| MLError::ModelError(format!("features download: {e}")))?;
|
||||
let features_tensor = Tensor::from_vec(
|
||||
flat_feats,
|
||||
(self.n_windows, self.max_len, self.feature_dim), device,
|
||||
).map_err(|e| MLError::ModelError(format!("features tensor: {e}")))?;
|
||||
|
||||
// Narrow to current step: [n_windows, feat_dim]
|
||||
@@ -1366,20 +1379,16 @@ impl GpuBacktestEvaluator {
|
||||
let actions_vec: Vec<u32> = actions_tensor.to_vec1()?;
|
||||
let actions_i32: Vec<i32> = actions_vec.iter().map(|&a| a as i32).collect();
|
||||
|
||||
// Upload actions
|
||||
self.stream.memcpy_stod_inplace(&actions_i32, &mut self.actions_buf)
|
||||
// Upload actions to GPU (cudarc 0.17: memcpy_htod, not memcpy_stod_inplace)
|
||||
self.stream.memcpy_htod(&actions_i32, &mut self.actions_buf)
|
||||
.map_err(|e| MLError::ModelError(format!("actions upload: {e}")))?;
|
||||
|
||||
// Copy actions to history buffer for metrics kernel trade counting.
|
||||
// GPU-to-GPU copy at correct offset. cudarc memcpy_dtod with offset:
|
||||
let history_offset = step * self.n_windows;
|
||||
unsafe {
|
||||
self.stream
|
||||
.memcpy_dtod(
|
||||
&self.actions_buf,
|
||||
&mut self.actions_history_buf.slice(history_offset..history_offset + self.n_windows),
|
||||
)
|
||||
.map_err(|e| MLError::ModelError(format!("actions history copy: {e}")))?;
|
||||
// Track actions in CPU-side history (window-major layout: [window][step]).
|
||||
// The metrics kernel reads actions_history[w * max_len + i], so we must match
|
||||
// that layout. A single contiguous DtoD copy can't scatter to strided offsets,
|
||||
// so we accumulate on CPU and upload once before the metrics kernel.
|
||||
for w in 0..self.n_windows {
|
||||
self.actions_history_cpu[w * self.max_len + step] = actions_i32[w];
|
||||
}
|
||||
// NOTE: Task 11 replaces the CPU gather_states above with a GPU gather kernel
|
||||
|
||||
@@ -1422,7 +1431,11 @@ impl GpuBacktestEvaluator {
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Launch metrics reduction kernel
|
||||
// 5. Upload accumulated actions history for metrics kernel trade counting
|
||||
self.stream.memcpy_htod(&self.actions_history_cpu, &mut self.actions_history_buf)
|
||||
.map_err(|e| MLError::ModelError(format!("actions_history upload: {e}")))?;
|
||||
|
||||
// 6. Launch metrics reduction kernel
|
||||
let shmem_bytes = (256 * 6 * 4) as u32; // 6 reduction arrays × 256 threads × f32
|
||||
let metrics_config = LaunchConfig {
|
||||
grid_dim: (self.n_windows as u32, 1, 1),
|
||||
@@ -1535,9 +1548,9 @@ Wire `GpuBacktestEvaluator` into the DQN hyperopt adapter's backtest evaluation.
|
||||
- Modify: `crates/ml/src/hyperopt/adapters/dqn.rs:2862-3165` (backtest evaluation section)
|
||||
- Test: `SQLX_OFFLINE=true cargo test -p ml --lib -- hyperopt_dqn --no-capture`
|
||||
|
||||
- [ ] **Step 1: Add GPU evaluator field to DqnOptimizer**
|
||||
- [ ] **Step 1: Add GPU evaluator field to DQNTrainer (hyperopt adapter)**
|
||||
|
||||
In `dqn.rs`, find the `DqnOptimizer` struct fields and add:
|
||||
In `dqn.rs`, find the `DQNTrainer (hyperopt adapter)` struct fields and add:
|
||||
|
||||
```rust
|
||||
/// GPU backtest evaluator (initialized on first use)
|
||||
@@ -1549,14 +1562,14 @@ Initialize as `None` in the builder.
|
||||
|
||||
- [ ] **Step 2: Add GPU evaluation method**
|
||||
|
||||
Add a method to `DqnOptimizer`:
|
||||
Add a method to `DQNTrainer (hyperopt adapter)`:
|
||||
|
||||
```rust
|
||||
/// Run backtest evaluation on GPU (zero CPU roundtrips during eval).
|
||||
#[cfg(feature = "cuda")]
|
||||
fn evaluate_gpu(
|
||||
&mut self,
|
||||
internal_trainer: &DQNTrainer,
|
||||
internal_trainer: &InternalDQNTrainer,
|
||||
val_close_prices: &[f64],
|
||||
window_size: usize,
|
||||
stride: usize,
|
||||
|
||||
Reference in New Issue
Block a user