singam96/ShadeNet-5-35M: upload hf_draft
Browse files- README.md +11 -1
- config.json +7 -3
- inference/run_onnx.py +10 -4
- onnx/shadenet5_mix_refined.onnx +3 -0
- refiner/eval_onnx_mix_cpu.json +22 -15
README.md
CHANGED
|
@@ -94,7 +94,7 @@ The six-pass average is better than a single pass but costs six forward passes.
|
|
| 94 |
- **Against the labels:** see the Results table: normals recover about 94% of the six-pass gain, albedo about 60%, depth about 8%. The refiner does not reproduce the six-pass average's changes to the overall depth levels, so depth is essentially the single pass's.
|
| 95 |
- **Cost:** about 12 ms per image on top of the single pass (PyTorch, A4000) and about 0.26 s on a CPU for the 448x448 ONNX version.
|
| 96 |
|
| 97 |
-
Files: `refiner/refiner.pt` (PyTorch weights)
|
| 98 |
|
| 99 |
On the shipped 4/8-bit MIX ONNX model (CPU, same 23 images, unit-length normals): single pass 0.1755, single pass + refiner **0.1676**, six passes 0.1645. The refiner was trained on full-precision outputs, so this is the number for the file you would download.
|
| 100 |
|
|
@@ -275,6 +275,16 @@ python inference/run_onnx.py photos/ --refine --out out/
|
|
| 275 |
|
| 276 |
Each photo becomes a panel image: input, albedo, depth, normal. `--refine` runs the single pass and then the small refiner (about 12 ms more; the recommended mode, see The refiner). `--enhanced` is the six-pass post-processing described above in one switch (mirror average, rotations of ±4 degrees, unit-length normals; six forward passes); leave both flags out for the plain single pass. The whole photo is kept: its long side is scaled to 448 and the rest of the 448x448 input is filled by mirroring the photo's own edge, then the padding is cut off the maps again, so the outputs have the photo's own shape. A photo that is not square therefore uses fewer than 448 pixels on its short side. (The PyTorch model runs at 448 and 896 square; the ONNX files are fixed at 448x448.) `torch` is only used for the rotation resampling of `--enhanced`. Set `--threads` to the number of CPU cores you have: more threads than cores is slower, not faster. A hosted demo runs the same code: [ShadeNet-5 Space](https://huggingface.co/spaces/singam96/ShadeNet-5).
|
| 277 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 278 |
The PyTorch checkpoint (`checkpoints/best-l1-pruned10-ep19.ckpt`) is the full-precision reference. Loading it needs the training code, which is not published yet (the `--enhanced` switch of its `infer.py` is the same recipe), so use the ONNX file unless you have that code.
|
| 279 |
|
| 280 |
`config.json` in this repository lists the architecture, the input and output convention (7 maps in [-1, 1]: albedo, depth, normal), the supported sizes and the recommended inference settings.
|
|
|
|
| 94 |
- **Against the labels:** see the Results table: normals recover about 94% of the six-pass gain, albedo about 60%, depth about 8%. The refiner does not reproduce the six-pass average's changes to the overall depth levels, so depth is essentially the single pass's.
|
| 95 |
- **Cost:** about 12 ms per image on top of the single pass (PyTorch, A4000) and about 0.26 s on a CPU for the 448x448 ONNX version.
|
| 96 |
|
| 97 |
+
Files: `refiner/refiner.pt` (PyTorch weights), `onnx/shadenet5_refiner.onnx` (the refiner alone, fp32, fixed 448x448) and `onnx/shadenet5_mix_refined.onnx` (35 MB: the MIX model, the refiner, the clamp and the unit-length normals in **one file**, photo in and final maps out; its mean L1 is identical to running the two files one after the other). Run them with `python inference/run_onnx.py photos/ --refine` (two files) or `--merged` (the single file).
|
| 98 |
|
| 99 |
On the shipped 4/8-bit MIX ONNX model (CPU, same 23 images, unit-length normals): single pass 0.1755, single pass + refiner **0.1676**, six passes 0.1645. The refiner was trained on full-precision outputs, so this is the number for the file you would download.
|
| 100 |
|
|
|
|
| 275 |
|
| 276 |
Each photo becomes a panel image: input, albedo, depth, normal. `--refine` runs the single pass and then the small refiner (about 12 ms more; the recommended mode, see The refiner). `--enhanced` is the six-pass post-processing described above in one switch (mirror average, rotations of ±4 degrees, unit-length normals; six forward passes); leave both flags out for the plain single pass. The whole photo is kept: its long side is scaled to 448 and the rest of the 448x448 input is filled by mirroring the photo's own edge, then the padding is cut off the maps again, so the outputs have the photo's own shape. A photo that is not square therefore uses fewer than 448 pixels on its short side. (The PyTorch model runs at 448 and 896 square; the ONNX files are fixed at 448x448.) `torch` is only used for the rotation resampling of `--enhanced`. Set `--threads` to the number of CPU cores you have: more threads than cores is slower, not faster. A hosted demo runs the same code: [ShadeNet-5 Space](https://huggingface.co/spaces/singam96/ShadeNet-5).
|
| 277 |
|
| 278 |
+
Or call the single merged file directly:
|
| 279 |
+
|
| 280 |
+
```python
|
| 281 |
+
import numpy as np, onnxruntime as ort
|
| 282 |
+
sess = ort.InferenceSession("shadenet5_mix_refined.onnx")
|
| 283 |
+
# photo: float32 [1, 3, 448, 448] in [-1, 1]
|
| 284 |
+
maps = sess.run(None, {"input_rgb": photo})[0] # [1, 7, 448, 448]
|
| 285 |
+
albedo, depth, normal = maps[:, 0:3], maps[:, 3:4], maps[:, 4:7]
|
| 286 |
+
```
|
| 287 |
+
|
| 288 |
The PyTorch checkpoint (`checkpoints/best-l1-pruned10-ep19.ckpt`) is the full-precision reference. Loading it needs the training code, which is not published yet (the `--enhanced` switch of its `infer.py` is the same recipe), so use the ONNX file unless you have that code.
|
| 289 |
|
| 290 |
`config.json` in this repository lists the architecture, the input and output convention (7 maps in [-1, 1]: albedo, depth, normal), the supported sizes and the recommended inference settings.
|
config.json
CHANGED
|
@@ -47,7 +47,8 @@
|
|
| 47 |
"onnx": {
|
| 48 |
"onnx/shadenet5_mix_int4_int8.onnx": "ViT fc1/fc2 int8, everything else int4",
|
| 49 |
"onnx/shadenet5_mix2_int4_int8.onnx": "ViT fc2 int8, everything else int4",
|
| 50 |
-
"onnx/shadenet5_refiner.onnx": "the small refiner, fp32, fixed 448x448 (inputs photo and maps, output refined maps)"
|
|
|
|
| 51 |
},
|
| 52 |
"recommended_inference": {
|
| 53 |
"mode": "refine",
|
|
@@ -58,7 +59,9 @@
|
|
| 58 |
"unit_normals": true,
|
| 59 |
"forward_passes": 6,
|
| 60 |
"command": "python inference/run_onnx.py <photos> --enhanced --out out/"
|
| 61 |
-
}
|
|
|
|
|
|
|
| 62 |
},
|
| 63 |
"validation_mean_l1": {
|
| 64 |
"single_pass_unit_normals": 0.1757,
|
|
@@ -66,7 +69,8 @@
|
|
| 66 |
"six_passes": 0.1628,
|
| 67 |
"mix_onnx_single": 0.1755,
|
| 68 |
"mix_onnx_plus_refiner": 0.1676,
|
| 69 |
-
"mix_onnx_six_passes": 0.1645
|
|
|
|
| 70 |
},
|
| 71 |
"refiner": {
|
| 72 |
"pytorch": "refiner/refiner.pt",
|
|
|
|
| 47 |
"onnx": {
|
| 48 |
"onnx/shadenet5_mix_int4_int8.onnx": "ViT fc1/fc2 int8, everything else int4",
|
| 49 |
"onnx/shadenet5_mix2_int4_int8.onnx": "ViT fc2 int8, everything else int4",
|
| 50 |
+
"onnx/shadenet5_refiner.onnx": "the small refiner, fp32, fixed 448x448 (inputs photo and maps, output refined maps)",
|
| 51 |
+
"onnx/shadenet5_mix_refined.onnx": "the MIX model + the refiner + clamp + unit-length normals in one file: input `input_rgb` [1,3,448,448] in [-1,1], output `refined` [1,7,448,448]"
|
| 52 |
},
|
| 53 |
"recommended_inference": {
|
| 54 |
"mode": "refine",
|
|
|
|
| 59 |
"unit_normals": true,
|
| 60 |
"forward_passes": 6,
|
| 61 |
"command": "python inference/run_onnx.py <photos> --enhanced --out out/"
|
| 62 |
+
},
|
| 63 |
+
"single_file": "onnx/shadenet5_mix_refined.onnx",
|
| 64 |
+
"single_file_command": "python inference/run_onnx.py <photos> --merged --out out/"
|
| 65 |
},
|
| 66 |
"validation_mean_l1": {
|
| 67 |
"single_pass_unit_normals": 0.1757,
|
|
|
|
| 69 |
"six_passes": 0.1628,
|
| 70 |
"mix_onnx_single": 0.1755,
|
| 71 |
"mix_onnx_plus_refiner": 0.1676,
|
| 72 |
+
"mix_onnx_six_passes": 0.1645,
|
| 73 |
+
"mix_onnx_single_merged_file": 0.1676
|
| 74 |
},
|
| 75 |
"refiner": {
|
| 76 |
"pytorch": "refiner/refiner.pt",
|
inference/run_onnx.py
CHANGED
|
@@ -27,6 +27,7 @@ from framing import crop_to_box, display_size, letterbox, resize_maps # noqa: E
|
|
| 27 |
REPO = "singam96/ShadeNet-5-35M"
|
| 28 |
ONNX_FILE = "onnx/shadenet5_mix_int4_int8.onnx"
|
| 29 |
REFINER_FILE = "onnx/shadenet5_refiner.onnx"
|
|
|
|
| 30 |
SIZE = 448 # the ONNX files are fixed at 448x448
|
| 31 |
ROT_DEG = 4.0
|
| 32 |
|
|
@@ -50,6 +51,9 @@ def main():
|
|
| 50 |
ap.add_argument("--onnx", default=None, help="local .onnx (default: download)")
|
| 51 |
ap.add_argument("--size", type=int, default=SIZE, choices=[448],
|
| 52 |
help="the ONNX files are fixed at 448x448")
|
|
|
|
|
|
|
|
|
|
| 53 |
ap.add_argument("--refine", action="store_true",
|
| 54 |
help="single pass, then the small refiner (recommended)")
|
| 55 |
ap.add_argument("--refiner-onnx", default=None, help="local refiner .onnx (default: download)")
|
|
@@ -60,13 +64,13 @@ def main():
|
|
| 60 |
ap.add_argument("--threads", type=int, default=8,
|
| 61 |
help="ONNX Runtime threads (more than your cores is slower)")
|
| 62 |
args = ap.parse_args()
|
| 63 |
-
if args.refine
|
| 64 |
-
ap.error('use --refine
|
| 65 |
|
| 66 |
path = args.onnx
|
| 67 |
if path is None:
|
| 68 |
from huggingface_hub import hf_hub_download
|
| 69 |
-
path = hf_hub_download(REPO, ONNX_FILE)
|
| 70 |
so = ort.SessionOptions()
|
| 71 |
so.intra_op_num_threads = args.threads
|
| 72 |
sess = ort.InferenceSession(path, so, providers=["CPUExecutionProvider"])
|
|
@@ -94,7 +98,9 @@ def main():
|
|
| 94 |
square, box = letterbox(img, args.size)
|
| 95 |
x = to_tensor(square)
|
| 96 |
with torch.no_grad():
|
| 97 |
-
if args.
|
|
|
|
|
|
|
| 98 |
single = refine(x)
|
| 99 |
out = ref_sess.run(None, {"photo": np.ascontiguousarray(x.numpy()),
|
| 100 |
"maps": np.ascontiguousarray(single.numpy())})[0]
|
|
|
|
| 27 |
REPO = "singam96/ShadeNet-5-35M"
|
| 28 |
ONNX_FILE = "onnx/shadenet5_mix_int4_int8.onnx"
|
| 29 |
REFINER_FILE = "onnx/shadenet5_refiner.onnx"
|
| 30 |
+
MERGED_FILE = "onnx/shadenet5_mix_refined.onnx"
|
| 31 |
SIZE = 448 # the ONNX files are fixed at 448x448
|
| 32 |
ROT_DEG = 4.0
|
| 33 |
|
|
|
|
| 51 |
ap.add_argument("--onnx", default=None, help="local .onnx (default: download)")
|
| 52 |
ap.add_argument("--size", type=int, default=SIZE, choices=[448],
|
| 53 |
help="the ONNX files are fixed at 448x448")
|
| 54 |
+
ap.add_argument("--merged", action="store_true",
|
| 55 |
+
help="the single file with the MIX model, refiner and unit normals in one graph "
|
| 56 |
+
"(same result as --refine, one session)")
|
| 57 |
ap.add_argument("--refine", action="store_true",
|
| 58 |
help="single pass, then the small refiner (recommended)")
|
| 59 |
ap.add_argument("--refiner-onnx", default=None, help="local refiner .onnx (default: download)")
|
|
|
|
| 64 |
ap.add_argument("--threads", type=int, default=8,
|
| 65 |
help="ONNX Runtime threads (more than your cores is slower)")
|
| 66 |
args = ap.parse_args()
|
| 67 |
+
if sum([args.refine, args.enhanced, args.merged]) > 1:
|
| 68 |
+
ap.error('use one of --refine, --enhanced, --merged')
|
| 69 |
|
| 70 |
path = args.onnx
|
| 71 |
if path is None:
|
| 72 |
from huggingface_hub import hf_hub_download
|
| 73 |
+
path = hf_hub_download(REPO, MERGED_FILE if args.merged else ONNX_FILE)
|
| 74 |
so = ort.SessionOptions()
|
| 75 |
so.intra_op_num_threads = args.threads
|
| 76 |
sess = ort.InferenceSession(path, so, providers=["CPUExecutionProvider"])
|
|
|
|
| 98 |
square, box = letterbox(img, args.size)
|
| 99 |
x = to_tensor(square)
|
| 100 |
with torch.no_grad():
|
| 101 |
+
if args.merged:
|
| 102 |
+
maps = refine(x) # already refined, clamped, unit-length normals
|
| 103 |
+
elif args.refine:
|
| 104 |
single = refine(x)
|
| 105 |
out = ref_sess.run(None, {"photo": np.ascontiguousarray(x.numpy()),
|
| 106 |
"maps": np.ascontiguousarray(single.numpy())})[0]
|
onnx/shadenet5_mix_refined.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f273b36084478f6294f9acb7ec6bae50aacf973b4881e97aabdc35ed32ce2b3d
|
| 3 |
+
size 35061482
|
refiner/eval_onnx_mix_cpu.json
CHANGED
|
@@ -1,23 +1,30 @@
|
|
| 1 |
{
|
| 2 |
"MIX single pass": {
|
| 3 |
-
"albedo": 0.
|
| 4 |
-
"depth": 0.
|
| 5 |
-
"normal": 0.
|
| 6 |
-
"mean": 0.
|
| 7 |
-
"ms":
|
| 8 |
},
|
| 9 |
"MIX + refiner": {
|
| 10 |
-
"albedo": 0.
|
| 11 |
-
"depth": 0.
|
| 12 |
-
"normal": 0.
|
| 13 |
-
"mean": 0.
|
| 14 |
-
"ms":
|
| 15 |
},
|
| 16 |
"MIX six passes": {
|
| 17 |
-
"albedo": 0.
|
| 18 |
-
"depth": 0.
|
| 19 |
-
"normal": 0.
|
| 20 |
-
"mean": 0.
|
| 21 |
-
"ms":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
}
|
| 23 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"MIX single pass": {
|
| 3 |
+
"albedo": 0.1782614407332047,
|
| 4 |
+
"depth": 0.17611568907032843,
|
| 5 |
+
"normal": 0.1720099980416505,
|
| 6 |
+
"mean": 0.17546237594839462,
|
| 7 |
+
"ms": 1329.7054225748234
|
| 8 |
},
|
| 9 |
"MIX + refiner": {
|
| 10 |
+
"albedo": 0.17473657526399777,
|
| 11 |
+
"depth": 0.1759216370789901,
|
| 12 |
+
"normal": 0.15225956880527994,
|
| 13 |
+
"mean": 0.16763926038275595,
|
| 14 |
+
"ms": 1649.118575182828
|
| 15 |
},
|
| 16 |
"MIX six passes": {
|
| 17 |
+
"albedo": 0.17288330618454062,
|
| 18 |
+
"depth": 0.1700636342815731,
|
| 19 |
+
"normal": 0.15063375072634738,
|
| 20 |
+
"mean": 0.1645268970641537,
|
| 21 |
+
"ms": 8918.771418658169
|
| 22 |
+
},
|
| 23 |
+
"one merged file": {
|
| 24 |
+
"albedo": 0.17473587231791537,
|
| 25 |
+
"depth": 0.175918893645639,
|
| 26 |
+
"normal": 0.15225798798644025,
|
| 27 |
+
"mean": 0.16763758464999826,
|
| 28 |
+
"ms": 1721.9356731934981
|
| 29 |
}
|
| 30 |
}
|