Instructions to use nathansut1/sbb-binarization-onnx with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- TensorRT
How to use nathansut1/sbb-binarization-onnx with TensorRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Upload fix_onnx.py with huggingface_hub
Browse files- fix_onnx.py +215 -0
fix_onnx.py
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Fix ONNX model for TensorRT compatibility.
|
| 3 |
+
|
| 4 |
+
Takes the raw tf2onnx output (model.onnx) and produces a TRT-optimized
|
| 5 |
+
model (model_convtranspose.onnx) in three steps:
|
| 6 |
+
|
| 7 |
+
Step 2A: Fix Reshape node with -2048 batch dim -> -1
|
| 8 |
+
Step 2B: Fix Resize nodes with TF-specific attributes
|
| 9 |
+
Step 2C: Validate model
|
| 10 |
+
Step 3: Replace Resize (nearest 2x upsample) -> ConvTranspose
|
| 11 |
+
|
| 12 |
+
Usage:
|
| 13 |
+
python3 fix_onnx.py <input.onnx> <output.onnx>
|
| 14 |
+
|
| 15 |
+
Requires: pip install onnx numpy
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
import sys
|
| 19 |
+
import onnx
|
| 20 |
+
from onnx import numpy_helper, shape_inference, helper
|
| 21 |
+
import numpy as np
|
| 22 |
+
|
| 23 |
+
if len(sys.argv) < 3:
|
| 24 |
+
print(f"Usage: {sys.argv[0]} <input.onnx> <output.onnx>")
|
| 25 |
+
sys.exit(1)
|
| 26 |
+
|
| 27 |
+
INPUT_MODEL = sys.argv[1]
|
| 28 |
+
OUTPUT_MODEL = sys.argv[2]
|
| 29 |
+
|
| 30 |
+
print(f"Loading model from {INPUT_MODEL}...")
|
| 31 |
+
model = onnx.load(INPUT_MODEL)
|
| 32 |
+
print(f" opset: {[o.version for o in model.opset_import]}")
|
| 33 |
+
print(f" nodes: {len(model.graph.node)}")
|
| 34 |
+
|
| 35 |
+
fixes_applied = []
|
| 36 |
+
|
| 37 |
+
# ββ Step 2A: Fix Reshape with -2048 ββββββββββββββββββββββββββββββββββββββββββ
|
| 38 |
+
print("\n=== Step 2A: Checking Reshape nodes for -2048 ===")
|
| 39 |
+
for node in model.graph.node:
|
| 40 |
+
if node.op_type == "Reshape":
|
| 41 |
+
for init in model.graph.initializer:
|
| 42 |
+
if init.name == node.input[1]:
|
| 43 |
+
shape = numpy_helper.to_array(init).copy()
|
| 44 |
+
if -2048 in shape:
|
| 45 |
+
print(f" FOUND -2048 in initializer '{init.name}': {shape}")
|
| 46 |
+
shape[shape == -2048] = -1
|
| 47 |
+
new_init = numpy_helper.from_array(shape, init.name)
|
| 48 |
+
idx = list(model.graph.initializer).index(init)
|
| 49 |
+
model.graph.initializer.remove(init)
|
| 50 |
+
model.graph.initializer.insert(idx, new_init)
|
| 51 |
+
fixes_applied.append(f"Reshape: fixed -2048 -> -1 in '{init.name}'")
|
| 52 |
+
print(f" FIXED -> {numpy_helper.to_array(new_init)}")
|
| 53 |
+
|
| 54 |
+
# ββ Step 2B: Fix Resize node attributes ββββββββββββββββββββββββββββββββββββββ
|
| 55 |
+
print("\n=== Step 2B: Checking Resize node attributes ===")
|
| 56 |
+
resize_count = 0
|
| 57 |
+
for node in model.graph.node:
|
| 58 |
+
if node.op_type == "Resize":
|
| 59 |
+
resize_count += 1
|
| 60 |
+
node_fixes = []
|
| 61 |
+
for attr in node.attribute:
|
| 62 |
+
if attr.name == "nearest_mode" and attr.s == b"floor":
|
| 63 |
+
old_val = attr.s.decode()
|
| 64 |
+
attr.s = b"round_prefer_floor"
|
| 65 |
+
node_fixes.append(f"nearest_mode: {old_val} -> round_prefer_floor")
|
| 66 |
+
if attr.name == "coordinate_transformation_mode" and attr.s == b"tf_half_pixel_for_nn":
|
| 67 |
+
old_val = attr.s.decode()
|
| 68 |
+
attr.s = b"half_pixel"
|
| 69 |
+
node_fixes.append(f"coordinate_transformation_mode: {old_val} -> half_pixel")
|
| 70 |
+
if node_fixes:
|
| 71 |
+
print(f" Resize '{node.name}': {', '.join(node_fixes)}")
|
| 72 |
+
fixes_applied.extend([f"Resize '{node.name}': {f}" for f in node_fixes])
|
| 73 |
+
else:
|
| 74 |
+
attrs = {a.name: a.s.decode() if a.type == 3 else a for a in node.attribute}
|
| 75 |
+
print(f" Resize '{node.name}': OK (attrs: {attrs})")
|
| 76 |
+
print(f" Total Resize nodes: {resize_count}")
|
| 77 |
+
|
| 78 |
+
# ββ Step 2C: Scan for other issues βββββββββββββββββββββββββββββββββββββββββββ
|
| 79 |
+
print("\n=== Step 2C: Scanning for other potential TRT issues ===")
|
| 80 |
+
|
| 81 |
+
for node in model.graph.node:
|
| 82 |
+
if node.op_type == "Reshape":
|
| 83 |
+
for init in model.graph.initializer:
|
| 84 |
+
if init.name == node.input[1]:
|
| 85 |
+
shape = numpy_helper.to_array(init)
|
| 86 |
+
negatives = shape[shape < -1]
|
| 87 |
+
if len(negatives) > 0:
|
| 88 |
+
print(f" WARNING: Reshape '{init.name}' still has negative values: {shape}")
|
| 89 |
+
|
| 90 |
+
for node in model.graph.node:
|
| 91 |
+
if node.op_type == "LayerNormalization":
|
| 92 |
+
for attr in node.attribute:
|
| 93 |
+
if attr.name == "stash_type" and attr.i != 1:
|
| 94 |
+
print(f" WARNING: LayerNormalization '{node.name}' has stash_type={attr.i}")
|
| 95 |
+
|
| 96 |
+
op_counts = {}
|
| 97 |
+
for node in model.graph.node:
|
| 98 |
+
op_counts[node.op_type] = op_counts.get(node.op_type, 0) + 1
|
| 99 |
+
print(f" Op type distribution:")
|
| 100 |
+
for op, count in sorted(op_counts.items()):
|
| 101 |
+
print(f" {op}: {count}")
|
| 102 |
+
|
| 103 |
+
# ββ Step 3: Replace Resize (nearest 2x) -> ConvTranspose ββββββββββββββββββββ
|
| 104 |
+
#
|
| 105 |
+
# Resize nodes doing nearest-neighbor 2x upsampling cause TRT to split the
|
| 106 |
+
# model into 8+ subgraphs, with GPU<->CPU copies at each boundary.
|
| 107 |
+
# Replacing them with depthwise ConvTranspose (group=channels, 2x2 kernel
|
| 108 |
+
# of all ones, stride 2) produces identical output but TRT compiles it as
|
| 109 |
+
# a single subgraph.
|
| 110 |
+
print("\n=== Step 3: Replacing Resize nodes with ConvTranspose ===")
|
| 111 |
+
|
| 112 |
+
# Run shape inference so we know tensor dimensions
|
| 113 |
+
print(" Running shape inference...")
|
| 114 |
+
try:
|
| 115 |
+
model = shape_inference.infer_shapes(model)
|
| 116 |
+
print(" Shape inference: OK")
|
| 117 |
+
except Exception as e:
|
| 118 |
+
print(f" Shape inference WARNING: {e}")
|
| 119 |
+
|
| 120 |
+
# Build tensor shape lookup
|
| 121 |
+
tensor_shapes = {}
|
| 122 |
+
for vi in list(model.graph.value_info) + list(model.graph.input) + list(model.graph.output):
|
| 123 |
+
if vi.type.tensor_type.HasField('shape'):
|
| 124 |
+
dims = [d.dim_value if d.dim_value > 0 else -1
|
| 125 |
+
for d in vi.type.tensor_type.shape.dim]
|
| 126 |
+
tensor_shapes[vi.name] = dims
|
| 127 |
+
|
| 128 |
+
resize_nodes = [n for n in model.graph.node if n.op_type == "Resize"]
|
| 129 |
+
replaced = 0
|
| 130 |
+
|
| 131 |
+
for resize_node in resize_nodes:
|
| 132 |
+
# Only replace nearest-mode upsampling
|
| 133 |
+
mode = None
|
| 134 |
+
for attr in resize_node.attribute:
|
| 135 |
+
if attr.name == "mode":
|
| 136 |
+
mode = attr.s.decode()
|
| 137 |
+
if mode != "nearest":
|
| 138 |
+
print(f" Skipping '{resize_node.name}' (mode={mode}, not nearest)")
|
| 139 |
+
continue
|
| 140 |
+
|
| 141 |
+
# Get channel count from input shape
|
| 142 |
+
# After shape inference, tensor may be NHWC [B,H,W,C] or NCHW [B,C,H,W].
|
| 143 |
+
# Detect format: if dim[2]==dim[3] it's NCHW (square spatial), channels=dim[1].
|
| 144 |
+
input_name = resize_node.input[0]
|
| 145 |
+
input_shape = tensor_shapes.get(input_name)
|
| 146 |
+
if not input_shape or len(input_shape) != 4:
|
| 147 |
+
print(f" Skipping '{resize_node.name}' (can't determine input shape)")
|
| 148 |
+
continue
|
| 149 |
+
|
| 150 |
+
if input_shape[2] == input_shape[3]:
|
| 151 |
+
channels = input_shape[1] # NCHW
|
| 152 |
+
else:
|
| 153 |
+
channels = input_shape[3] # NHWC
|
| 154 |
+
if channels <= 0:
|
| 155 |
+
print(f" Skipping '{resize_node.name}' (dynamic channels)")
|
| 156 |
+
continue
|
| 157 |
+
|
| 158 |
+
# Create all-ones kernel: [channels, 1, 2, 2] for depthwise ConvTranspose
|
| 159 |
+
kernel_name = f"{resize_node.name}_kernel"
|
| 160 |
+
kernel_data = np.ones((channels, 1, 2, 2), dtype=np.float32)
|
| 161 |
+
model.graph.initializer.append(numpy_helper.from_array(kernel_data, kernel_name))
|
| 162 |
+
|
| 163 |
+
# Create ConvTranspose node (same input/output tensor names)
|
| 164 |
+
ct_node = helper.make_node(
|
| 165 |
+
"ConvTranspose",
|
| 166 |
+
inputs=[input_name, kernel_name],
|
| 167 |
+
outputs=list(resize_node.output),
|
| 168 |
+
name=f"{resize_node.name}_ConvTranspose",
|
| 169 |
+
kernel_shape=[2, 2],
|
| 170 |
+
strides=[2, 2],
|
| 171 |
+
pads=[0, 0, 0, 0],
|
| 172 |
+
group=channels,
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
# Swap in-place
|
| 176 |
+
idx = list(model.graph.node).index(resize_node)
|
| 177 |
+
model.graph.node.remove(resize_node)
|
| 178 |
+
model.graph.node.insert(idx, ct_node)
|
| 179 |
+
|
| 180 |
+
replaced += 1
|
| 181 |
+
fixes_applied.append(f"Resize '{resize_node.name}' -> ConvTranspose (group={channels})")
|
| 182 |
+
print(f" Replaced '{resize_node.name}' -> ConvTranspose (channels={channels})")
|
| 183 |
+
|
| 184 |
+
print(f" Replaced {replaced} Resize nodes")
|
| 185 |
+
|
| 186 |
+
# ββ Final validation βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 187 |
+
print("\n=== Final validation ===")
|
| 188 |
+
try:
|
| 189 |
+
model = shape_inference.infer_shapes(model)
|
| 190 |
+
print(" Shape inference: OK")
|
| 191 |
+
except Exception as e:
|
| 192 |
+
print(f" Shape inference WARNING: {e}")
|
| 193 |
+
|
| 194 |
+
try:
|
| 195 |
+
onnx.checker.check_model(model)
|
| 196 |
+
print(" Model validation: PASSED")
|
| 197 |
+
except Exception as e:
|
| 198 |
+
print(f" Model validation WARNING: {e}")
|
| 199 |
+
try:
|
| 200 |
+
onnx.checker.check_model(model, full_check=False)
|
| 201 |
+
print(" Model validation (relaxed): PASSED")
|
| 202 |
+
except Exception as e2:
|
| 203 |
+
print(f" Model validation (relaxed) FAILED: {e2}")
|
| 204 |
+
|
| 205 |
+
# ββ Save βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 206 |
+
print(f"\n=== Saving to {OUTPUT_MODEL} ===")
|
| 207 |
+
onnx.save(model, OUTPUT_MODEL)
|
| 208 |
+
print(f" Saved. Total fixes applied: {len(fixes_applied)}")
|
| 209 |
+
for f in fixes_applied:
|
| 210 |
+
print(f" - {f}")
|
| 211 |
+
|
| 212 |
+
remaining_resize = sum(1 for n in model.graph.node if n.op_type == "Resize")
|
| 213 |
+
total_ct = sum(1 for n in model.graph.node if n.op_type == "ConvTranspose")
|
| 214 |
+
print(f"\n Final: {len(model.graph.node)} nodes, {remaining_resize} Resize, {total_ct} ConvTranspose")
|
| 215 |
+
print("\nDone.")
|