Skip to content

Commit 3511a43

Browse files
committed
Broaden ONNX PR bench coverage with large 3x3 and medium GEMM cases
The small suite only had a 1x128 GEMV and 64x64 convs, so the blocked multi-row GEMM kernels and the large 3x3 stride-1 path went unmeasured. Add a large-spatial conv (80x80, 64->128), a wide-channel conv (20x20, 256->256) and a 256x512x512 GEMM, and factor the conv/GEMM graph builders into shared helpers.
1 parent 25c8edd commit 3511a43

2 files changed

Lines changed: 159 additions & 53 deletions

File tree

benchmarks/perf-runners/onnx-pr-bench/src/main.rs

Lines changed: 117 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,15 @@ fn tensor(shape: Vec<usize>, data: Vec<f32>) -> Result<Tensor, String> {
175175
Tensor::from_vec(shape, data).map_err(|e| format!("tensor build failed: {e}"))
176176
}
177177

178-
fn prepare_small(asset_dir: &Path) -> Result<(), String> {
179-
std::fs::create_dir_all(asset_dir)
180-
.map_err(|e| format!("create {}: {e}", asset_dir.display()))?;
181-
let conv = OnnxExportGraph {
178+
fn conv3x3_relu_graph(
179+
in_c: usize,
180+
out_c: usize,
181+
h: usize,
182+
w: usize,
183+
w_scale: f32,
184+
b_scale: f32,
185+
) -> Result<OnnxExportGraph, String> {
186+
Ok(OnnxExportGraph {
182187
nodes: vec![
183188
OnnxExportNode {
184189
op_type: "Conv".to_string(),
@@ -206,21 +211,85 @@ fn prepare_small(asset_dir: &Path) -> Result<(), String> {
206211
initializers: vec![
207212
(
208213
"weight".to_string(),
209-
tensor(vec![8, 3, 3, 3], patterned(8 * 3 * 3 * 3, 0.01))?,
214+
tensor(
215+
vec![out_c, in_c, 3, 3],
216+
patterned(out_c * in_c * 3 * 3, w_scale),
217+
)?,
218+
),
219+
(
220+
"bias".to_string(),
221+
tensor(vec![out_c], patterned(out_c, b_scale))?,
210222
),
211-
("bias".to_string(), tensor(vec![8], patterned(8, 0.005))?),
212223
],
213224
inputs: vec![OnnxExportValueInfo {
214225
name: "input".to_string(),
215-
shape: vec![1, 3, 64, 64],
226+
shape: vec![1, in_c as i64, h as i64, w as i64],
216227
}],
217228
outputs: vec![OnnxExportValueInfo {
218229
name: "output".to_string(),
219-
shape: vec![1, 8, 64, 64],
230+
shape: vec![1, out_c as i64, h as i64, w as i64],
220231
}],
221232
opset_version: 13,
222233
int64_initializers: Vec::new(),
223-
};
234+
})
235+
}
236+
237+
fn gemm_relu_graph(
238+
m: usize,
239+
k: usize,
240+
n: usize,
241+
w_scale: f32,
242+
b_scale: f32,
243+
) -> Result<OnnxExportGraph, String> {
244+
Ok(OnnxExportGraph {
245+
nodes: vec![
246+
OnnxExportNode {
247+
op_type: "Gemm".to_string(),
248+
name: "gemm".to_string(),
249+
inputs: vec![
250+
"input".to_string(),
251+
"weight".to_string(),
252+
"bias".to_string(),
253+
],
254+
outputs: vec!["gemm_out".to_string()],
255+
attributes: vec![
256+
OnnxExportAttr::Float("alpha".to_string(), 1.0),
257+
OnnxExportAttr::Float("beta".to_string(), 1.0),
258+
OnnxExportAttr::Int("transB".to_string(), 1),
259+
],
260+
},
261+
OnnxExportNode {
262+
op_type: "Relu".to_string(),
263+
name: "relu".to_string(),
264+
inputs: vec!["gemm_out".to_string()],
265+
outputs: vec!["output".to_string()],
266+
attributes: Vec::new(),
267+
},
268+
],
269+
initializers: vec![
270+
(
271+
"weight".to_string(),
272+
tensor(vec![n, k], patterned(n * k, w_scale))?,
273+
),
274+
("bias".to_string(), tensor(vec![n], patterned(n, b_scale))?),
275+
],
276+
inputs: vec![OnnxExportValueInfo {
277+
name: "input".to_string(),
278+
shape: vec![m as i64, k as i64],
279+
}],
280+
outputs: vec![OnnxExportValueInfo {
281+
name: "output".to_string(),
282+
shape: vec![m as i64, n as i64],
283+
}],
284+
opset_version: 13,
285+
int64_initializers: Vec::new(),
286+
})
287+
}
288+
289+
fn prepare_small(asset_dir: &Path) -> Result<(), String> {
290+
std::fs::create_dir_all(asset_dir)
291+
.map_err(|e| format!("create {}: {e}", asset_dir.display()))?;
292+
let conv = conv3x3_relu_graph(3, 8, 64, 64, 0.01, 0.005)?;
224293
export_onnx_model_to_file(
225294
&conv,
226295
"yscv-pr-bench",
@@ -365,56 +434,51 @@ fn prepare_small(asset_dir: &Path) -> Result<(), String> {
365434
)
366435
.map_err(|e| format!("export small residual: {e}"))?;
367436

368-
let gemm = OnnxExportGraph {
369-
nodes: vec![
370-
OnnxExportNode {
371-
op_type: "Gemm".to_string(),
372-
name: "gemm".to_string(),
373-
inputs: vec![
374-
"input".to_string(),
375-
"weight".to_string(),
376-
"bias".to_string(),
377-
],
378-
outputs: vec!["gemm_out".to_string()],
379-
attributes: vec![
380-
OnnxExportAttr::Float("alpha".to_string(), 1.0),
381-
OnnxExportAttr::Float("beta".to_string(), 1.0),
382-
OnnxExportAttr::Int("transB".to_string(), 1),
383-
],
384-
},
385-
OnnxExportNode {
386-
op_type: "Relu".to_string(),
387-
name: "relu".to_string(),
388-
inputs: vec!["gemm_out".to_string()],
389-
outputs: vec!["output".to_string()],
390-
attributes: Vec::new(),
391-
},
392-
],
393-
initializers: vec![
394-
(
395-
"weight".to_string(),
396-
tensor(vec![64, 128], patterned(64 * 128, 0.002))?,
397-
),
398-
("bias".to_string(), tensor(vec![64], patterned(64, 0.001))?),
399-
],
400-
inputs: vec![OnnxExportValueInfo {
401-
name: "input".to_string(),
402-
shape: vec![1, 128],
403-
}],
404-
outputs: vec![OnnxExportValueInfo {
405-
name: "output".to_string(),
406-
shape: vec![1, 64],
407-
}],
408-
opset_version: 13,
409-
int64_initializers: Vec::new(),
410-
};
437+
let gemm = gemm_relu_graph(1, 128, 64, 0.002, 0.001)?;
411438
export_onnx_model_to_file(
412439
&gemm,
413440
"yscv-pr-bench",
414441
"small_gemm_relu_1x128",
415442
&asset_dir.join("small-gemm-relu-1x128.onnx"),
416443
)
417-
.map_err(|e| format!("export small gemm: {e}"))
444+
.map_err(|e| format!("export small gemm: {e}"))?;
445+
446+
// Large-spatial 3×3 stride-1 conv — the dominant Winograd workload in YOLO
447+
// backbones. 80×80 output amortises the input/output transforms, so this is
448+
// where Winograd should beat im2col+GEMM and where vectorising the
449+
// transforms shows up cleanly, without the e2e noise of a full YOLO graph.
450+
let wino_spatial = conv3x3_relu_graph(64, 128, 80, 80, 0.004, 0.002)?;
451+
export_onnx_model_to_file(
452+
&wino_spatial,
453+
"yscv-pr-bench",
454+
"winograd_3x3_80x80_c64",
455+
&asset_dir.join("winograd-3x3-80x80-c64.onnx"),
456+
)
457+
.map_err(|e| format!("export winograd spatial: {e}"))?;
458+
459+
// Wide-channel 3×3 stride-1 conv — few tiles, large weight transform. Isolates
460+
// the per-inference weight-transform + pack cost (256×256 across 16 tiles),
461+
// the term that currently makes Winograd lose; caching packed weights should
462+
// move this case the most.
463+
let wino_channels = conv3x3_relu_graph(256, 256, 20, 20, 0.002, 0.001)?;
464+
export_onnx_model_to_file(
465+
&wino_channels,
466+
"yscv-pr-bench",
467+
"winograd_3x3_20x20_c256",
468+
&asset_dir.join("winograd-3x3-20x20-c256.onnx"),
469+
)
470+
.map_err(|e| format!("export winograd channels: {e}"))?;
471+
472+
// Medium GEMM (M=256, K=512, N=512) — exercises the blocked multi-row
473+
// (mr12/mr6) microkernels, unlike the 1×128 GEMV which only hits the m=1 path.
474+
let gemm_mid = gemm_relu_graph(256, 512, 512, 0.002, 0.001)?;
475+
export_onnx_model_to_file(
476+
&gemm_mid,
477+
"yscv-pr-bench",
478+
"gemm_relu_256x512x512",
479+
&asset_dir.join("gemm-relu-256x512x512.onnx"),
480+
)
481+
.map_err(|e| format!("export medium gemm: {e}"))
418482
}
419483

420484
struct XorShift(u32);

benchmarks/perf-runners/onnx-pr-bench/suite.json

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,48 @@
108108
"source": "random"
109109
}
110110
]
111+
},
112+
{
113+
"name": "winograd_3x3_80x80_c64",
114+
"model": "winograd-3x3-80x80-c64.onnx",
115+
"iters": 100,
116+
"iters_env": "YSCV_PR_BENCH_SMALL_ITERS",
117+
"fill": "random",
118+
"inputs": [
119+
{
120+
"name": "input",
121+
"shape": [1, 64, 80, 80],
122+
"source": "random"
123+
}
124+
]
125+
},
126+
{
127+
"name": "winograd_3x3_20x20_c256",
128+
"model": "winograd-3x3-20x20-c256.onnx",
129+
"iters": 150,
130+
"iters_env": "YSCV_PR_BENCH_SMALL_ITERS",
131+
"fill": "random",
132+
"inputs": [
133+
{
134+
"name": "input",
135+
"shape": [1, 256, 20, 20],
136+
"source": "random"
137+
}
138+
]
139+
},
140+
{
141+
"name": "gemm_relu_256x512x512",
142+
"model": "gemm-relu-256x512x512.onnx",
143+
"iters": 200,
144+
"iters_env": "YSCV_PR_BENCH_SMALL_ITERS",
145+
"fill": "random",
146+
"inputs": [
147+
{
148+
"name": "input",
149+
"shape": [256, 512],
150+
"source": "random"
151+
}
152+
]
111153
}
112154
]
113155
}

0 commit comments

Comments
 (0)