Views
No views yet
Optimized ONNX export of FeyNoBg (BiRefNet-based background removal model), benchmarked exhaustively on CPU with FP32, FP16, and Dynamic INT8 quantization.
| File | Description | Size |
|---|---|---|
feynobg_fp32.onnx | Full precision ONNX export | ~1.1 GB |
feynobg_fp16.onnx | Half precision export | ~556 MB |
feynobg_int8_dynamic.onnx | Dynamic INT8 quantized (recommended for CPU) | ~1.3 GB |

1git clone https://huggingface.co/mmahdi-sz/FeyNobg-ONNX
2cd FeyNobg-ONNX
3pip install onnxruntime numpy pillow1import numpy as np
2import onnxruntime as ort
3from PIL import Image
4
5# ── Load model ──────────────────────────────────────────────────────────────
6# Recommended: Dynamic INT8 + 8 cores for the best latency/cost ratio
7ONNX_PATH = "feynobg_int8_dynamic.onnx"
8NUM_CORES = 8 # adjust to your server's core count
9
10sess_opts = ort.SessionOptions()
11sess_opts.intra_op_num_threads = NUM_CORES
12sess_opts.inter_op_num_threads = 1
13sess_opts.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
14
15session = ort.InferenceSession(
16 ONNX_PATH,
17 sess_options=sess_opts,
18 providers=["CPUExecutionProvider"]
19)
20
21# ── Preprocess ──────────────────────────────────────────────────────────────
22def preprocess(image_path: str, size=(1024, 1024)) -> np.ndarray:
23 img = Image.open(image_path).convert("RGB").resize(size)
24 x = np.array(img, dtype=np.float32) / 255.0
25 mean = np.array([0.485, 0.456, 0.406])
26 std = np.array([0.229, 0.224, 0.225])
27 x = (x - mean) / std
28 return x.transpose(2, 0, 1)[np.newaxis].astype(np.float32) # [1, 3, H, W]
29
30# ── Inference ───────────────────────────────────────────────────────────────
31input_tensor = preprocess("your_image.jpg")
32input_name = session.get_inputs()[0].name
33
34alpha_mask = session.run(None, {input_name: input_tensor})[0] # [1, 1, H, W]
35mask = (alpha_mask[0, 0] * 255).clip(0, 255).astype(np.uint8)
36Image.fromarray(mask).save("output_mask.png")
37print("Done! Mask saved to output_mask.png")pip install nobg torch1import nobg
2import torch
3from PIL import Image
4
5model = nobg.AutoModel.from_pretrained("nobg/FeyNobg")
6model.eval()
7
8# ... standard PyTorch inferenceNote: PyTorch (16 cores, no pinning) averages 40,743ms per image. The ONNX INT8 model on 8 pinned cores achieves 11,165ms — 3.6× faster.
taskset (no OS interference).| Model Variant | Optimization | 4 Cores | 8 Cores | 12 Cores | IoU ↑ | MAE ↓ |
|---|---|---|---|---|---|---|
| FP32 | ORT_ENABLE_ALL | 17,849ms | 11,971ms | 14,325ms | 1.000 | 0.0004 |
| FP32 | ORT_ENABLE_BASIC | 18,230ms | 12,723ms | 15,760ms | 1.000 | 0.0004 |
| FP16 | ORT_ENABLE_ALL | 19,156ms | 13,382ms | 16,966ms | 1.000 | 0.0004 |
| FP16 | ORT_ENABLE_BASIC | 19,154ms | 13,218ms | 16,870ms | 1.000 | 0.0004 |
| Dynamic INT8 | ORT_ENABLE_ALL | 15,868ms | 11,165ms | 14,568ms | 1.000 | 0.0004 |
| Dynamic INT8 | ORT_ENABLE_BASIC | 16,938ms | 12,876ms | 15,706ms | 1.000 | 0.0004 |
| PyTorch FP32 (baseline, 16 cores) | — | — | — | 40,743ms | 1.000 | 0.0004 |
✅ Zero quality degradation. All ONNX variants (FP32, FP16, Dynamic INT8) achieveIoU = 1.000andMAE = 0.0004compared to ground-truth masks — identical to the original PyTorch model.

| Cores | Latency | Speedup vs PyTorch | Notes |
|---|---|---|---|
| 1 | 45,300ms | 0.9× | — |
| 2 | 26,101ms | 1.6× | — |
| 4 | 15,897ms | 2.6× | — |
| 6 | 12,577ms | 3.2× | — |
| 8 | 11,165ms | 3.6× | ⭐ Value Sweet Spot |
| 10 | 9,936ms | 4.1× | — |
| 12 | 9,350ms | 4.4× | 🏆 Max Performance |
| 14 | 9,359ms | 4.4× | Plateau — no further gain |
| Finding | Detail |
|---|---|
| 🏆 Best overall | Dynamic INT8 + ORT_ENABLE_ALL + 8 cores → 11.2s |
| ⚡ Absolute fastest | Dynamic INT8 + 12 pinned cores → 9.35s |
| 🔬 Quality | All ONNX variants: IoU = 1.000, MAE = 0.0004 (no degradation) |
| 🐢 FP16 on CPU | Slower than FP32 (CPU lacks native FP16 math units) |
| 📉 PyTorch vs ONNX INT8 | 40.7s → 9.4s = 4.4× speedup at peak |
| 🧠 RAM bottleneck | Plateau after 12 cores — memory-bound workload |
1git clone https://huggingface.co/mmahdi-sz/FeyNobg-ONNX
2cd FeyNobg-ONNX
3
4# Create virtualenv
5python -m venv venv && source venv/bin/activate
6pip install onnxruntime numpy pillow
7
8# Run scaling benchmark (1–14 cores, generates CSV + chart)
9python hf_scaling_benchmark.py
10
11# Run full 4/8/12 core benchmark (all variants)
12python run_benchmark.pyAll benchmarks usetaskset -c 0-<N-1>to strictly pin CPU cores at the OS level, preventing thread migration and ensuring reproducible measurements.
| Property | Value |
|---|---|
| CPU | AMD EPYC-Genoa Processor (16-core) |
| RAM | DDR5 (Sufficient for 1.3GB model + inference buffers) |
| OS | Linux (Ubuntu) |
| ONNX Runtime | Latest stable |
| Python | 3.13 |
| Input resolution | 1024 × 1024 |
@model{feynobg,
author = {nobg},
title = {FeyNoBg: BiRefNet-based Background Removal},
year = {2024},
url = {https://huggingface.co/nobg/FeyNobg}
}