Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,11 @@ include = [
# after-the-binary phase.
[package.metadata.dogfood]
gates = [
# #5803/#5804 — the moved tuner tests must still be listed by cargo exactly once, none ignored
# (behaviour guard: cargo test -- --list). It invokes cargo, so guard_tree --no-cargo never
# runs it; ci/explicit-test-commands.d/296-298 run it in the full tier (tags/release), and this wires it for the
# meta-guard (#4005 ruling C).
"scripts/check_tuner_test_move.sh",
"scripts/check_multiplatform_dogfood.sh",
# #3477 — every claimed (architecture, backend, silicon) triple has a per-host receipt
# from scripts/model_ladder.sh; dense Qwen3 on CUDA shipped broken in 0.68.1 because no
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cargo test -p aprender-core --test tuner_training_data_quality
1 change: 1 addition & 0 deletions ci/explicit-test-commands.d/296-tuner-test-move-5803.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bash scripts/check_tuner_test_move.sh --self-test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bash scripts/check_tuner_test_move.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cargo test -p aprender-compute --test tuner_falsification
15 changes: 3 additions & 12 deletions crates/aprender-compute/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,9 @@ anyhow = "1.0.100"
# Hardware capability detection (PMAT-447)
chrono = "0.4"
toml = "0.8"
# ML tuner integration (SHOWCASE-BRICK-001, Section 12) — aprender RandomForest is a
# DEV-dependency only: the SIMD foundation must not depend on the ML layer (layer
# inversion). The `ml-tuner` showcase lives in examples/ml_tuner_demo.rs + the tuner
# falsification tests, which consume aprender directly. Dev-dep path cycles are legal
# in cargo and dropped on publish, keeping the workspace a self-contained DAG (APR-MONO).
# ML tuner integration (SHOWCASE-BRICK-001, Section 12) — the SIMD foundation takes no
# dependency, not even a dev one, on the ML layer. The aprender RandomForest tests live in
# crates/aprender-core/tests/tuner_training_data_quality.rs (FLOW-010, #5803).
# NOTE: trueno-graph (=aprender-graph) removed (APR-MONO self-containment): aprender-graph
# depends on trueno, so compute→graph closed a cycle. The `execution-graph` feature's only
# trueno-graph use was the thin `to_csr()`/`graph_to_csr()` CsrGraph exporters; CSR export
Expand Down Expand Up @@ -106,9 +104,6 @@ trueno-cuda-edge = { workspace = true }
# Sparse and solver crates for contract tests
trueno-sparse = { workspace = true }
trueno-solve = { workspace = true }
# ML-tuner showcase (SHOWCASE-BRICK-001): aprender RandomForest, DEV-only to avoid the
# compute→core layer inversion. Path dev-dep cycle is legal + dropped on publish.
aprender = { path = "../aprender-core", package = "aprender-core", default-features = false }
ndarray = "0.17.2"
faer = "0.24" # For GEMM benchmark comparison (fastest pure-Rust BLAS)
matrixmultiply = "0.3" # Direct matrixmultiply crate benchmark (engine behind ndarray)
Expand Down Expand Up @@ -139,10 +134,6 @@ hardware-detect = ["dep:dirs"]
tui-monitor = ["presentar-core", "presentar-terminal", "crossterm", "trueno-gpu", "dep:tracing", "tracing-subscriber", "tracing-appender", "dep:dirs"]
# CUDA support for TUI (real hardware monitoring)
cuda = ["trueno-gpu/cuda"]
# ML-based kernel selection and throughput prediction (SHOWCASE-BRICK-001)
# Showcase: feed trueno tuner features into aprender RandomForest (example + tests only;
# aprender is a dev-dependency, so this feature activates no lib dependency).
ml-tuner = []
# NOTE: `execution-graph` feature removed (APR-MONO self-containment) — its only purpose
# was the trueno-graph CsrGraph exporters (see above). The exec-graph profiler itself
# (to_dot/to_ascii_tree, slowest-path) is always available, no graph crate needed.
Expand Down
1 change: 0 additions & 1 deletion crates/aprender-compute/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ GEMV, Quantization (Q4K/Q5K/Q6K). JIT disk cache at
| `parallel` | Rayon parallel iterators |
| `cuda-monitor` | NVIDIA device info via trueno-gpu |
| `cuda` | Full CUDA support via trueno-gpu |
| `ml-tuner` | ML-based kernel selection via aprender RandomForest |
| `execution-graph` | PTX-to-kernel call graph profiling |
| `tui-monitor` | Terminal monitoring dashboard |
| `hardware-detect` | Hardware capability detection and caching |
Expand Down
50 changes: 5 additions & 45 deletions crates/aprender-compute/book/src/ecosystem/aprender.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,12 @@ The integration provides:
- **RandomForestClassifier** for kernel selection
- Training on benchmark data for hardware-specific optimization

## Enabling the Integration
## Where the Integration Lives

Add the `ml-tuner` feature to your `Cargo.toml`:

```toml
[dependencies]
trueno = { version = "0.13", features = ["ml-tuner"] }
```

## Feature Matrix

| Feature | Default | ml-tuner |
|---------|---------|----------|
| TunerFeatures (42-dim) | Yes | Yes |
| Heuristic prediction | Yes | Yes |
| Roofline clamping | Yes | Yes |
| RandomForest regressor | No | Yes |
| RandomForest classifier | No | Yes |
| Custom model training | No | Yes |

## Usage Example

```rust
use trueno::tuner::{ThroughputRegressor, TunerFeatures, QuantType};

// Create RF-backed regressor
let mut regressor = ThroughputRegressor::with_random_forest(100);

// Collect benchmark data
let training_data: Vec<(TunerFeatures, f32)> = collect_benchmarks();

// Train the model
regressor.train_random_forest(&training_data)?;

// Use trained model for predictions
let features = TunerFeatures::builder()
.model_params_b(7.0)
.batch_size(4)
.quant_type(QuantType::Q4K)
.gpu_mem_bw_gbs(1000.0)
.build();

let pred = regressor.predict(&features);
println!("Predicted throughput: {:.1} tok/s", pred.predicted_tps);
```
The `ml-tuner` feature was removed (FLOW-010, #5803): trueno has no dependency on
aprender, so the SIMD foundation stays below the ML layer. The RandomForest showcase
runs from aprender-core's tests (`crates/aprender-core/tests/tuner_training_data_quality.rs`),
which depend on trueno, not the reverse. trueno keeps the heuristic models.

## Why aprender?

Expand Down Expand Up @@ -119,7 +80,6 @@ let model_json = fs::read_to_string("throughput_model.json")?;
let regressor: ThroughputRegressor = serde_json::from_str(&model_json)?;
```

**Note:** RandomForest models are not serialized (marked `#[serde(skip)]`). After loading, you must retrain or use heuristic fallback.

## Further Reading

Expand Down
77 changes: 8 additions & 69 deletions crates/aprender-compute/book/src/performance/ml-tuner.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,72 +82,14 @@ for (kernel, conf) in recommendation.alternatives.iter().take(3) {
| M=2-3 | VectorizedQ4K | Low batch, vectorized still efficient |
| M>=4 | BatchedQ4K | High batch, batched attention wins |

## RandomForest Models (Optional)
## RandomForest Models (Relocated)

With the `ml-tuner` feature, you can use aprender's RandomForest models for learned optimization:

```toml
# Cargo.toml
[dependencies]
trueno = { version = "0.13", features = ["ml-tuner"] }
```

### Training a Custom Regressor

```rust
use trueno::tuner::{ThroughputRegressor, TunerFeatures, QuantType};

// Create RF-backed regressor with 100 trees
let mut regressor = ThroughputRegressor::with_random_forest(100);

// Generate training data from benchmarks
let training_data: Vec<(TunerFeatures, f32)> = (0..100)
.map(|i| {
let batch = 1 + (i % 8) as u32;
let features = TunerFeatures::builder()
.model_params_b(1.5)
.batch_size(batch)
.quant_type(QuantType::Q4K)
.gpu_mem_bw_gbs(1000.0)
.cuda_graphs(batch == 1)
.build();
// Measured throughput from benchmark
let throughput = 200.0 + (batch as f32) * 80.0;
(features, throughput)
})
.collect();

// Train the model
regressor.train_random_forest(&training_data)?;

// Predictions now use learned model
let pred = regressor.predict(&features);
println!("RF prediction: {:.1} tok/s", pred.predicted_tps);
```

### Training a Custom Classifier

```rust
use trueno::tuner::{KernelClassifier, TunerFeatures, QuantType};

let mut classifier = KernelClassifier::with_random_forest(50);

// Label encoding: VectorizedQ4K=2, BatchedQ4K=3
let training_data: Vec<(TunerFeatures, u32)> = (0..100)
.map(|i| {
let batch = 1 + (i % 8) as u32;
let features = TunerFeatures::builder()
.model_params_b(1.5)
.batch_size(batch)
.quant_type(QuantType::Q4K)
.build();
let label = if batch >= 4 { 3 } else { 2 };
(features, label)
})
.collect();

classifier.train(&training_data)?;
```
The `ml-tuner` feature and the `with_random_forest` / `train_random_forest` /
`KernelClassifier::train` wrappers were removed (FLOW-010, #5803): the SIMD compute
crate must not depend on the ML layer. The aprender RandomForest showcase now lives in
`crates/aprender-core/tests/tuner_training_data_quality.rs`, which feeds `TunerFeatures`
into `aprender::RandomForestRegressor` / `RandomForestClassifier`. This crate keeps the
heuristic `ThroughputRegressor` and `KernelClassifier`.

## Full Tuner Recommendations

Expand Down Expand Up @@ -178,11 +120,8 @@ for exp in &rec.suggested_experiments {
## Running the Demo

```bash
# Default (heuristic models)
# Heuristic models
cargo run --example ml_tuner_demo

# With RandomForest models
cargo run --example ml_tuner_demo --features ml-tuner
```

## Integration with ComputeBrick
Expand Down
2 changes: 1 addition & 1 deletion crates/aprender-compute/docs/prompts/95_percent_mandate.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
--package trueno --package trueno-gpu \
--lib \
--no-default-features \
--features "parallel,cuda,wgpu,ml-tuner,execution-graph,hardware-detect,tracing" \
--features "parallel,cuda,wgpu,execution-graph,hardware-detect,tracing" \
--html
```
2. **Close the Gaps**:
Expand Down
4 changes: 2 additions & 2 deletions crates/aprender-compute/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ This directory contains examples demonstrating Trueno's high-performance compute
| `vocab_bench.rs` | Vocabulary processing benchmark | `cargo run --release --example vocab_bench` |
| `profile_vocab.rs` | Vocabulary profiling | `cargo run --release --example profile_vocab` |
| `execution_graph.rs` | Execution path graph demo | `cargo run --release --features execution-graph --example execution_graph` |
| `ml_tuner_demo.rs` | ML-based kernel selection | `cargo run --release --features ml-tuner --example ml_tuner_demo` |
| `ml_tuner_evolution.rs` | ML tuner evolution demo | `cargo run --release --features ml-tuner --example ml_tuner_evolution` |
| `ml_tuner_demo.rs` | Heuristic kernel selection and throughput prediction | `cargo run --release --example ml_tuner_demo` |
| `ml_tuner_evolution.rs` | ML tuner evolution demo | `cargo run --release --features hardware-detect --example ml_tuner_evolution` |
| `model_tracing.rs` | Model-level inference tracing | `cargo run --release --example model_tracing` |
| `tiling_demo.rs` | Tiling compute blocks | `cargo run --release --example tiling_demo` |
| `tile_profiler_demo.rs` | Tile profiler demo | `cargo run --release --example tile_profiler_demo` |
Expand Down
107 changes: 9 additions & 98 deletions crates/aprender-compute/examples/ml_tuner_demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
//!
//! Run with default (heuristic models):
//! cargo run --example ml_tuner_demo
//!
//! Run with RandomForest models (requires ml-tuner feature):
//! cargo run --example ml_tuner_demo --features ml-tuner

use trueno::tuner::{BrickTuner, KernelClassifier, QuantType, ThroughputRegressor, TunerFeatures};

Expand Down Expand Up @@ -163,101 +160,15 @@ fn demo_full_tuner(features: &TunerFeatures) {
println!();
}

/// Section 6: RandomForest models (ml-tuner showcase, SHOWCASE-BRICK-001).
///
/// The SIMD `trueno` tuner produces `TunerFeatures` vectors; this section feeds them
/// directly into `aprender::RandomForestRegressor`/`RandomForestClassifier`. aprender is
/// a **dev-dependency** of `aprender-compute`, so the compute lib itself never depends on
/// the ML layer — the showcase lives entirely here at the example layer, above both.
/// Section 6: RandomForest models (SHOWCASE-BRICK-001). The aprender half of the showcase
/// is tested in `crates/aprender-core/tests/tuner_training_data_quality.rs`: compute takes
/// no dependency on the ML layer, not even a dev one (FLOW-010, #5803).
fn demo_random_forest(features: &TunerFeatures) {
#[cfg(feature = "ml-tuner")]
{
use aprender::primitives::{Matrix, Vector};
use aprender::tree::{RandomForestClassifier, RandomForestRegressor};

println!("6. RandomForest Models (ml-tuner showcase)");
println!(" --------------------------------------");

let dim = TunerFeatures::DIM;
let n = 100usize;

// Regressor: trueno features -> predicted throughput (tok/s).
let mut xr = Vec::with_capacity(n * dim);
let mut yr = Vec::with_capacity(n);
for i in 0..n {
let batch = 1 + (i % 8) as u32;
let f = TunerFeatures::builder()
.model_params_b(1.5)
.batch_size(batch)
.quant_type(QuantType::Q4K)
.gpu_mem_bw_gbs(1000.0)
.cuda_graphs(batch == 1)
.build();
xr.extend(f.to_vector());
yr.push(200.0 + (batch as f32) * 80.0 + (i as f32 * 0.5));
}
println!(" Generated {n} regression samples");
match Matrix::from_vec(n, dim, xr) {
Ok(x_mat) => {
let mut rf = RandomForestRegressor::new(100);
match rf.fit(&x_mat, &Vector::from_vec(yr)) {
Ok(()) => {
let fx = Matrix::from_vec(1, dim, features.to_vector().to_vec())
.expect("single-row feature matrix");
let pred = rf.predict(&fx);
println!(
" RF regressor: SUCCESS — M=4 prediction {:.1} tok/s",
pred.as_slice()[0]
);
}
Err(e) => println!(" RF regressor: FAILED - {e}"),
}
}
Err(e) => println!(" RF regressor matrix: FAILED - {e}"),
}

// Classifier: trueno features -> kernel-type label (3=Batched, 2=Vectorized).
let mut xc = Vec::with_capacity(n * dim);
let mut yc: Vec<usize> = Vec::with_capacity(n);
for i in 0..n {
let batch = 1 + (i % 8) as u32;
let f = TunerFeatures::builder()
.model_params_b(1.5)
.batch_size(batch)
.quant_type(QuantType::Q4K)
.build();
xc.extend(f.to_vector());
yc.push(if batch >= 4 { 3 } else { 2 });
}
match Matrix::from_vec(n, dim, xc) {
Ok(xc_mat) => {
let mut rf = RandomForestClassifier::new(50);
match rf.fit(&xc_mat, &yc) {
Ok(()) => {
let preds = rf.predict(&xc_mat);
let correct =
yc.iter().zip(preds.iter()).filter(|(a, b)| **a == **b).count();
println!(
" RF classifier: SUCCESS — train accuracy {:.1}%",
correct as f32 / n as f32 * 100.0
);
}
Err(e) => println!(" RF classifier: FAILED - {e}"),
}
}
Err(e) => println!(" RF classifier matrix: FAILED - {e}"),
}
println!();
}

#[cfg(not(feature = "ml-tuner"))]
{
let _ = features;
println!("6. RandomForest Models");
println!(" --------------------");
println!(" [Disabled - enable with: --features ml-tuner]");
println!();
}
let _ = features;
println!("6. RandomForest Models");
println!(" --------------------");
println!(" [See aprender-core tests/tuner_training_data_quality.rs]");
println!();
}

fn main() {
Expand All @@ -279,7 +190,7 @@ fn main() {
println!(" - TunerFeatures: 42-dimension vector for ML models");
println!(" - Throughput prediction with roofline clamping (v1.1.0)");
println!(" - Kernel selection: BatchedQ4K for M>=4, VectorizedQ4K otherwise");
println!(" - RandomForest available with --features ml-tuner");
println!(" - RandomForest showcase: aprender-core tests/tuner_training_data_quality.rs");
println!();
println!("Next steps:");
println!(" cargo run --example quickstart # Basic trueno usage");
Expand Down
2 changes: 1 addition & 1 deletion crates/aprender-compute/src/tuner/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum TunerError {
ModelNotFound,
/// Prediction failed
PredictionFailed(String),
/// Training failed (ml-tuner feature)
/// Training failed
TrainingFailed(String),
/// I/O error (file operations)
Io(String),
Expand Down
Loading