flowchart TD
Q1{"Dynamic batch\nsize needed?"}
Q1 -- Yes --> DYN["dynamic_axes={'input': {0: 'batch_size'}}"]
Q1 -- No --> STAT["No dynamic_axes\n(fixed shape, smaller model)"]
Q2{"do_constant_folding?"}
Q2 -- Yes --> CF["Pre-folds constants\nat export time"]
Q2 -- No --> NCF["Larger graph\nbut more transparent"]
Q3{"opset version?"}
Q3 -- "17 (recommended)" --> OPS17["Broad ORT support\nLayerNorm as first-class op"]
Q3 -- "<11" --> OPS_OLD["Missing Resize,\nRange ops"]
Q3 -- ">20" --> OPS_NEW["Newest features,\ncheck ORT version support"]
2. Graph Optimization Pipeline
This flow covers src/graph_optimizer/optimization_pipeline.py,
constant_folder.py, and fusion_analyzer.py.
flowchart TD
INPUT_MODEL["Input: raw .onnx file\n(from export step)"]
subgraph Scan["Pre-optimization Analysis"]
direction TB
FU["FusionAnalyzer.find_patterns()\nDetect Conv+BN+Relu,\nMatMul+Add, etc."]
CF["ConstantFolder.analyse()\nCount foldable nodes"]
GI["GraphInspector.inspect()\nNode count, op types, shapes"]
end
subgraph Levels["Apply ORT Levels (OptimizationPipeline)"]
direction TB
L0["SessionOptions.graph_optimization_level\n= ORT_DISABLE_ALL\n→ save optimized_ORT_DISABLE_ALL.onnx"]
L1["= ORT_ENABLE_BASIC\n→ constant folding, identity elim\n→ save optimized_ORT_ENABLE_BASIC.onnx"]
L2["= ORT_ENABLE_EXTENDED\n→ + Conv+BN folding, op fusion\n→ save optimized_ORT_ENABLE_EXTENDED.onnx"]
L3["= ORT_ENABLE_ALL\n→ + layout optimization\n→ save optimized_ORT_ENABLE_ALL.onnx"]
end
subgraph PostAnalysis["Post-optimization Analysis"]
direction TB
NC["NodeCounter.compare_counts()\nNode reduction per level"]
FA["FusionAnalyzer.compare_fusion()\nBN nodes before/after"]
CF2["ConstantFolder.compare()\nFolded node delta"]
end
REPORT["Structured Log Report\n+ comparison charts"]
INPUT_MODEL --> Scan
Scan --> Levels
L0 --> L1 --> L2 --> L3
Levels --> PostAnalysis
PostAnalysis --> REPORT
BatchNorm Folding - Node-level Detail
flowchart LR
subgraph RAW["Before (ORT_ENABLE_BASIC)"]
direction TB
CW["Conv weights\nW: [32,1,3,3]"]
CB["Conv bias\nb: [32]"]
C["Conv node"]
BNW["BN.weight γ\nBN.bias β\nBN.mean μ\nBN.var σ²"]
BN["BatchNorm node\n(ε=1e-5)"]
RL["Relu node"]
CW & CB --> C --> BN
BNW --> BN --> RL
end
subgraph FUSED["After (ORT_ENABLE_EXTENDED)"]
direction TB
FW["Fused Conv weights\nW' = W · (γ/√(σ²+ε))"]
FB["Fused Conv bias\nb' = b·(γ/√(σ²+ε)) + β − μ·(γ/√(σ²+ε))"]
FC["Conv node\n(BN absorbed)"]
FR["Relu node"]
FW & FB --> FC --> FR
end
RAW -- "ORT_ENABLE_EXTENDED" --> FUSED
3. Inference Request Flow with EP Selection
This flow covers src/inference_engine/ort_inference.py and
src/inference_engine/execution_providers.py.
sequenceDiagram
participant App as Application
participant Sel as ExecutionProviderSelector
participant ORT as ort.InferenceSession
participant EP1 as CUDAExecutionProvider
participant EP2 as CPUExecutionProvider
App->>Sel: build_provider_list(['CUDA', 'CPU'])
Sel->>Sel: ort.get_available_providers()
alt CUDA available
Sel-->>App: ['CUDAExecutionProvider', 'CPUExecutionProvider']
else CUDA not available
Sel-->>App: ['CPUExecutionProvider']
end
App->>ORT: InferenceSession(model, providers=[...])
ORT->>ORT: Load and optimize graph
ORT->>ORT: Partition nodes to EPs
loop For each node in graph
ORT->>EP1: Can you run this op?
alt EP1 supports op
EP1-->>ORT: Yes
ORT->>EP1: Execute node
else EP1 doesn't support op
ORT->>EP2: Execute node (fallback)
end
end
App->>ORT: session.run(None, {"input": data})
ORT->>EP1: Execute Conv, Gemm (GPU ops)
EP1-->>ORT: intermediate tensor
ORT->>EP2: Execute unsupported ops (CPU fallback)
EP2-->>ORT: output tensor
ORT-->>App: [output_array]