@@ -10,6 +10,35 @@ use yscv_kernels::metal_backend::metal_conv::MetalInference;
1010
1111use crate :: error:: OnnxError ;
1212use crate :: loader:: { OnnxModel , OnnxNode } ;
13+ use crate :: shape_infer:: { ShapeMap , TensorShape , infer_shapes} ;
14+
15+ fn can_skip_cpu_shape_discovery ( model : & OnnxModel , shapes : & ShapeMap ) -> bool {
16+ model. nodes . iter ( ) . all ( |node| {
17+ matches ! (
18+ node. op_type. as_str( ) ,
19+ "Conv"
20+ | "Add"
21+ | "Sub"
22+ | "Mul"
23+ | "Div"
24+ | "Sigmoid"
25+ | "Relu"
26+ | "Concat"
27+ | "Transpose"
28+ | "Reshape"
29+ | "MatMul"
30+ ) && node
31+ . outputs
32+ . iter ( )
33+ . filter ( |name| !name. is_empty ( ) )
34+ . all ( |name| {
35+ shapes
36+ . get ( name)
37+ . and_then ( TensorShape :: as_known_dims)
38+ . is_some ( )
39+ } )
40+ } )
41+ }
1342
1443/// Compile a Metal execution plan for the given ONNX model.
1544/// Runs a shape-inference pass on CPU, then pre-allocates Metal buffers
@@ -31,35 +60,43 @@ pub fn compile_metal_plan(
3160 let debug_metal = false ;
3261 let mut env = TensorEnv :: from_model ( model) ;
3362 env. insert ( input_name. to_string ( ) , input_tensor. clone ( ) ) ;
34- // We need tensor shapes AND data for fallback ops. Some ops (Split) consume
35- // their inputs, so we snapshot shapes + data for fallback-eligible outputs
36- // immediately after each node executes.
37- let mut cpu_shapes: FxHashMap < String , Vec < usize > > = FxHashMap :: default ( ) ;
63+ let input_shapes: ShapeMap = FxHashMap :: from_iter ( [ (
64+ input_name. to_string ( ) ,
65+ TensorShape :: known ( input_tensor. shape ( ) . to_vec ( ) ) ,
66+ ) ] ) ;
67+ let inferred = infer_shapes ( model, & input_shapes) ;
68+ // A supported, fully-known graph needs shapes but not a CPU execution. Keep
69+ // the existing CPU walk for every other graph because fallback nodes may
70+ // need their concrete values, not merely their output dimensions.
71+ let skip_cpu_prepass = std:: env:: var ( "METAL_COMPARE" ) . is_err ( )
72+ && inferred. diagnostics . is_empty ( )
73+ && can_skip_cpu_shape_discovery ( model, & inferred. shapes ) ;
74+ let mut cpu_shapes: FxHashMap < String , Vec < usize > > = inferred
75+ . shapes
76+ . iter ( )
77+ . filter_map ( |( name, shape) | shape. as_known_dims ( ) . map ( |dims| ( name. clone ( ) , dims) ) )
78+ . collect ( ) ;
3879 let mut cpu_data: FxHashMap < String , Vec < f32 > > = FxHashMap :: default ( ) ;
39- for ( ni, node) in model. nodes . iter ( ) . enumerate ( ) {
40- if let Err ( e) = execute_node_cpu_for_metal_compile ( node, & mut env)
41- && debug_metal
42- {
43- eprintln ! (
44- " [metal] CPU pass node {} {} '{}' FAILED: {}" ,
45- ni, node. op_type, node. name, e
46- ) ;
47- }
48- // Snapshot outputs that Metal will need for cpu_fallback
49- for out_name in & node. outputs {
50- if out_name. is_empty ( ) {
51- continue ;
80+ if !skip_cpu_prepass {
81+ for ( ni, node) in model. nodes . iter ( ) . enumerate ( ) {
82+ if let Err ( e) = execute_node_cpu_for_metal_compile ( node, & mut env)
83+ && debug_metal
84+ {
85+ eprintln ! (
86+ " [metal] CPU pass node {} {} '{}' FAILED: {}" ,
87+ ni, node. op_type, node. name, e
88+ ) ;
5289 }
53- if let Some ( t ) = env . get ( out_name ) {
54- cpu_shapes . insert ( out_name . clone ( ) , t . shape ( ) . to_vec ( ) ) ;
55- // Only save data for cpu_fallback-eligible ops (shape ops, etc.)
56- // to avoid excessive memory usage.
57- // Save data for any op that might need cpu_fallback
58- // (shape ops, unknown ops, etc.) — limit to small tensors to save memory
59- let n_elem = t . len ( ) ;
60- if n_elem <= 1_000_000 {
61- // ~4MB limit per tensor
62- cpu_data . insert ( out_name . clone ( ) , t . data ( ) . to_vec ( ) ) ;
90+ // Snapshot outputs that Metal will need for cpu_fallback.
91+ for out_name in & node . outputs {
92+ if out_name . is_empty ( ) {
93+ continue ;
94+ }
95+ if let Some ( t ) = env . get ( out_name ) {
96+ cpu_shapes . insert ( out_name . clone ( ) , t . shape ( ) . to_vec ( ) ) ;
97+ if t . len ( ) <= 1_000_000 {
98+ cpu_data . insert ( out_name . clone ( ) , t . data ( ) . to_vec ( ) ) ;
99+ }
63100 }
64101 }
65102 }
0 commit comments