Phips commited on
Commit
174aa1f
Β·
verified Β·
1 Parent(s): d0e8590

restore full README (was clobbered by dir upload)

Browse files
Files changed (1) hide show
  1. README.md +160 -40
README.md CHANGED
@@ -2,33 +2,95 @@
2
  license: apache-2.0
3
  language:
4
  - en
 
 
5
  tags:
6
  - super-resolution
7
  - image-restoration
 
 
 
8
  - pytorch
9
  - onnx
10
  - ncnn
11
  - spandrel
12
- - chaiNNer
13
- pipeline_tag: image-to-image
 
 
 
14
  ---
15
 
16
  # NERVE
17
 
18
  **Norm-free Efficient Restoration for Various Edge devices**
19
 
20
- A lightweight super-resolution architecture that is simple to train, fast to run,
21
- and works everywhere: **traiNNer-redux**, **chaiNNer**, **ONNX Runtime**,
22
- **ncnn**, **CoreML**.
23
-
24
- > Short version: copy `nerve_arch.py` into traiNNer-redux, train with the sample
25
- > configs, use the released `.safetensors` / `.onnx` / `.ncnn` models anywhere.
26
- > One architecture, one size, no fused/unfused pairs. Details below.
27
 
28
  Part of the **BODY** suite by **Philip Hofmann** β€” networks built to be
29
- *real-world usable first*, not benchmark-chasing. See
30
  [Relation to HEART](#relation-to-heart) for which one to pick.
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  ---
33
 
34
  ## Quickstart
@@ -42,11 +104,24 @@ Pick a model and run it:
42
  | upscale a clean image 4x | `models/4x_NERVE_release.safetensors` |
43
  | upscale a clean image 2x | `models/2x_NERVE_release.safetensors` |
44
  | restore a blurry / noisy / JPEG-y image 4x | `models/4x_NERVE_OTF_gan.safetensors` |
45
- | run in the browser / on a phone / in a game engine | the `onnx/` or `ncnn/` files |
46
-
47
- - **chaiNNer / spandrel**: drop the `.safetensors` in β€” it auto-detects NERVE.
48
- - **ONNX Runtime / TensorRT / DirectML**: use `onnx/*.onnx` (dynamic H/W).
49
- - **ncnn**: use `ncnn/*.ncnn.param` + `*.ncnn.bin` (fp16).
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  - Input: RGB, any size. Output: 2x or 4x.
51
 
52
  ### As a trainer (want to train your own)
@@ -105,7 +180,7 @@ setting `path.pretrain_network_g` in your training config to a file from
105
  | `models/2x_NERVE_release.safetensors` | **2x official pretrain** | clean bicubic, 31.84 dB / 0.9255 SSIM (Urban100) |
106
  | `models/4x_NERVE_release.safetensors` | **4x official pretrain** | clean bicubic, 25.09 dB / 0.7531 SSIM (Urban100) |
107
  | `models/4x_NERVE_OTF_fidelity.safetensors` | 4x OTF fidelity | restore degraded input; the pretrain for OTF GAN finetunes |
108
- | `models/4x_NERVE_OTF_gan.safetensors` | 4x OTF GAN | **sharpest real-world output** (topiq 0.430 / lpips 0.290) |
109
  | `onnx/4x_NERVE_1x3xHxW_fp32_op20.onnx` | 4x release, dynamic ONNX | onnxslim-optimized, fp32 |
110
  | `onnx/2x_NERVE_1x3xHxW_fp32_op20.onnx` | 2x release, dynamic ONNX | onnxslim-optimized, fp32 |
111
  | `onnx/4x_NERVE_OTF_fidelity_1x3xHxW_fp32_op20.onnx` | 4x OTF fidelity, dynamic ONNX | onnxslim-optimized, fp32 |
@@ -132,6 +207,25 @@ expensive early training.
132
 
133
  ---
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  ## Architecture
136
 
137
  ```
@@ -144,18 +238,8 @@ expensive early training.
144
  misses β€” that's why it stays small and trains fast.
145
  - **ICNR-initialized** PixelShuffle head (checkerboard-free by construction).
146
  - The op graph is trivial: `Conv, Add, ReLU, DepthToSpace, Resize`. That's the
147
- entire reason it exports to dynamic ONNX and converts to ncnn/CoreML without
148
- custom ops or fused/unfused pairs.
149
-
150
- **Design philosophy.** NERVE trades the last fraction of a dB of PSNR for
151
- everything that actually matters in production:
152
- - **One variant.** No S/M/L, no fused vs unfused, no attention-window caveats.
153
- - **Clean to train.** Norm-free, bf16-stable, a single loss for the base stage.
154
- - **Clean to deploy.** Standard ops only; what you train is what you export.
155
- - **Maintainable.** One ~90-line arch file a maintainer can read in full.
156
-
157
- It does **not** chase benchmark leaderboards. It is the model you can hand to
158
- someone and they can train, export, and ship it the same afternoon.
159
 
160
  ## What we actually tested
161
 
@@ -174,22 +258,25 @@ development log β€” including dead ends and raw numbers β€” is in
174
  variant made thin lines *worse* and was reverted.
175
  - **OTF/GAN capability**: the small net trained productively under the full
176
  Real-ESRGAN OTF GAN recipe (no collapse).
 
 
 
177
  - **Deployability**: dynamic-ONNX export + ORT parity and ncnn conversion were
178
  verified at every stage (the numbers are in the log).
 
 
 
179
 
180
- ## Examples
181
 
182
- `examples/*_compare.png` feed real images in **as-is** (not downscaled) and
183
- show the 4x result: **input** | **bicubic x4** | **NERVE 4x release** |
184
- **NERVE 4x OTF GAN**. The bicubic column is the baseline; the OTF GAN column
185
- is the released showcase model.
186
 
187
- - `examples/realphoto_compare.png` (street scene)
188
- - `examples/ani_compare.png` (anime)
189
- - `examples/manga_compare.png` (manga)
190
- - `examples/text_compare.png` (text)
191
- - `examples/noisy_compare.png` (noisy input)
192
- - `examples/stablediffusion_compare.png` (AI-generated)
193
 
194
  ## Relation to HEART
195
 
@@ -207,6 +294,12 @@ Rule of thumb: **HEART for maximum quality, NERVE for maximum practicality.**
207
  Both export to dynamic ONNX; NERVE additionally converts to ncnn cleanly
208
  because it has no attention ops.
209
 
 
 
 
 
 
 
210
  ---
211
 
212
  ## Repository layout
@@ -216,13 +309,40 @@ nerve_arch.py the architecture (single file)
216
  configs/ example training configs (+ 4x_NERVE_onnx.yml for ONNX export)
217
  models/ pretrained checkpoints (see table above)
218
  onnx/ dynamic fp32 ONNX (opset 20, onnxslim-optimized)
219
- ncnn/ ncnn fp16 param/bin (fixed 256x256 input)
220
  docs/ABLATIONS.md the full development/ablation log (what we tested)
221
  examples/ real-image comparisons (input vs bicubic vs release vs GAN)
222
  scripts/export_dynamic.py checkpoint β†’ dynamic ONNX exporter (+ ORT verify)
223
  LICENSE Apache-2.0
224
  ```
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  ## License
227
 
228
  Apache-2.0 (this repository's code and pretrained weights).
 
2
  license: apache-2.0
3
  language:
4
  - en
5
+ library_name: pytorch
6
+ pipeline_tag: image-to-image
7
  tags:
8
  - super-resolution
9
  - image-restoration
10
+ - image-to-image
11
+ - sisr
12
+ - real-world-restoration
13
  - pytorch
14
  - onnx
15
  - ncnn
16
  - spandrel
17
+ - chainner
18
+ - edge
19
+ - mobile
20
+ datasets:
21
+ - Phips/lucid-cc0-v2-hc-512
22
  ---
23
 
24
  # NERVE
25
 
26
  **Norm-free Efficient Restoration for Various Edge devices**
27
 
28
+ A lightweight super-resolution architecture that is simple to train and fast to
29
+ run. Released models are **verified** with **traiNNer-redux** (training) and
30
+ **ONNX Runtime** + **ncnn** (inference). The op set is standard, so other
31
+ runtimes (**CoreML**, **TensorRT**, DirectML, ...) are expected to work too β€”
32
+ but they are not tested here.
 
 
33
 
34
  Part of the **BODY** suite by **Philip Hofmann** β€” networks built to be
35
+ real-world usable first, not benchmark-chasing. See
36
  [Relation to HEART](#relation-to-heart) for which one to pick.
37
 
38
+ > Short version: copy `nerve_arch.py` into traiNNer-redux, train with the sample
39
+ > configs, then run the `.safetensors`, `.onnx`, or `.ncnn` models. One
40
+ > architecture, one size, no fused/unfused pairs. Details below.
41
+
42
+ ![NERVE 4x on anime β€” input | bicubic | release | OTF GAN](examples/ani_compare.png)
43
+ *Input (as-is) | bicubic x4 | NERVE 4x release | NERVE 4x OTF GAN.*
44
+
45
+ ![NERVE 4x on a noisy image](examples/noisy_compare.png)
46
+ ![NERVE 4x on a Stable-Diffusion image](examples/stablediffusion_compare.png)
47
+
48
+ ---
49
+
50
+ ## Why NERVE?
51
+
52
+ There are strong and established SR networks already. This is the honest case
53
+ for when NERVE is worth your time β€” and when it is not.
54
+
55
+ This project comes out of a trainer's frustration rather than a benchmark goal.
56
+ After training hundreds of SISR models (see
57
+ [Phhofm/models](https://github.com/Phhofm/models)), the recurring annoyance was
58
+ networks that felt like *paper* networks: they chase leaderboard metrics with
59
+ techniques that leave you juggling an unfused and a fused checkpoint, or whose
60
+ dynamic-ONNX conversion is fragile. This network is the opposite of that β€” built
61
+ so a trainer can pick it up, train it, and convert it to dynamic ONNX without
62
+ headaches.
63
+
64
+ **Strengths of NERVE**
65
+ - **Real-world usability over metric chasing.** Trained on a CC0 dataset with
66
+ the full Real-ESRGAN OTF degradation pipeline; the OTF GAN model restores
67
+ degraded images, not just clean bicubic downsamples.
68
+ - **One file, one variant.** A single readable architecture file and one model
69
+ size. No S/M/L matrix, no fused-vs-unfused checkpoints, nothing to fuse before
70
+ deploy β€” what you train is what you ship.
71
+ - **Export just works.** Dynamic-shape ONNX (verified, ORT parity ~1e-5) and a
72
+ clean ncnn conversion. Standard ops only (`Conv / Add / ReLU / DepthToSpace /
73
+ Resize`).
74
+ - **Boring, stable training.** Norm-free, bf16 AMP, no gradient clipping, a
75
+ single Charbonnier loss for the base stage.
76
+ - **Small and fast.** ~1.8M params β€” SPAN-class size but conv-only, suited to
77
+ mobile, edge, web and game engines.
78
+ - **Maintainable for years.** One op set, no exotic dependencies, ~85-line arch.
79
+
80
+ **When to pick something else.** If the goal is maximum PSNR/LPIPS on academic
81
+ benchmarks, or a large transformer, NERVE is not aiming there β€” use HEART, HAT,
82
+ ATD, DAT2, or one of the community networks below. NERVE aims at simplicity,
83
+ deployability and hassle-free training.
84
+
85
+ **Credit where it is due.** None of this exists in a vacuum. SISR has many
86
+ strong architectures and generous community members, for example HAT, ATD and
87
+ DAT2, the community network work of [umzi](https://github.com/umzi2) and
88
+ [Kim2091](https://github.com/Kim2091), fdat by
89
+ [sharekhan](https://github.com/stinkybread), and
90
+ [the-database](https://github.com/the-database) (traiNNer-redux, its benchmarks
91
+ and its models). This list is far from complete β€” apologies to anyone not named;
92
+ the SISR community has a great many people contributing a great deal.
93
+
94
  ---
95
 
96
  ## Quickstart
 
104
  | upscale a clean image 4x | `models/4x_NERVE_release.safetensors` |
105
  | upscale a clean image 2x | `models/2x_NERVE_release.safetensors` |
106
  | restore a blurry / noisy / JPEG-y image 4x | `models/4x_NERVE_OTF_gan.safetensors` |
107
+ | run on-device / inside an engine | the `onnx/` or `ncnn/` files |
108
+
109
+ - **ONNX Runtime** (verified): use `onnx/*.onnx` (dynamic H/W). TensorRT /
110
+ DirectML should work too (same op set) but are untested here.
111
+ - **ncnn** (verified, fp16): `ncnn/*.ncnn.param` + `*.ncnn.bin`. Feed images with
112
+ `Mat.from_pixels`:
113
+ ```python
114
+ import ncnn
115
+ net = ncnn.Net(); net.load_param("4x_NERVE_fp16.ncnn.param"); net.load_model("4x_NERVE_fp16.ncnn.bin")
116
+ ex = net.create_extractor()
117
+ ex.input("in0", ncnn.Mat.from_pixels(bgr_uint8, ncnn.Mat.PixelType.PIXEL_BGR2RGB, w, h))
118
+ out = ex.extract("out0")[1] # CHW float, 4x
119
+ ```
120
+ (Use `from_pixels`; the ncnn Python binding's raw-array constructor misbehaves
121
+ on large inputs. Outputs are fp16, so expect small deviations at hard edges.)
122
+ - **chaiNNer**: load the `onnx/*.onnx` files directly. Loading the
123
+ `.safetensors` via spandrel needs NERVE registered in your chaiNNer/spandrel
124
+ build (not upstream yet).
125
  - Input: RGB, any size. Output: 2x or 4x.
126
 
127
  ### As a trainer (want to train your own)
 
180
  | `models/2x_NERVE_release.safetensors` | **2x official pretrain** | clean bicubic, 31.84 dB / 0.9255 SSIM (Urban100) |
181
  | `models/4x_NERVE_release.safetensors` | **4x official pretrain** | clean bicubic, 25.09 dB / 0.7531 SSIM (Urban100) |
182
  | `models/4x_NERVE_OTF_fidelity.safetensors` | 4x OTF fidelity | restore degraded input; the pretrain for OTF GAN finetunes |
183
+ | `models/4x_NERVE_OTF_gan.safetensors` | 4x OTF GAN | **sharpest real-world output** (topiq 0.430 / lpips 0.290, Urban100 OTF val) |
184
  | `onnx/4x_NERVE_1x3xHxW_fp32_op20.onnx` | 4x release, dynamic ONNX | onnxslim-optimized, fp32 |
185
  | `onnx/2x_NERVE_1x3xHxW_fp32_op20.onnx` | 2x release, dynamic ONNX | onnxslim-optimized, fp32 |
186
  | `onnx/4x_NERVE_OTF_fidelity_1x3xHxW_fp32_op20.onnx` | 4x OTF fidelity, dynamic ONNX | onnxslim-optimized, fp32 |
 
207
 
208
  ---
209
 
210
+ ## Examples
211
+
212
+ Real images are fed in **as-is** (not downscaled) and upscaled 4x. For each
213
+ image there are two comparisons:
214
+
215
+ - `examples/*_compare.png` β€” whole image at **full resolution**: **input** |
216
+ **bicubic x4** | **NERVE 4x release** | **NERVE 4x OTF GAN**.
217
+ - `examples/*_1to1.png` β€” a **1:1 native-pixel center crop**.
218
+
219
+ The bicubic column is the baseline; the OTF GAN column is the released showcase
220
+ model. The source inputs are in `examples/inputs/`.
221
+
222
+ - `examples/realphoto_compare.png` (street scene)
223
+ - `examples/ani_compare.png` (anime)
224
+ - `examples/manga_compare.png` (manga)
225
+ - `examples/text_compare.png` (text)
226
+ - `examples/noisy_compare.png` (noisy input)
227
+ - `examples/stablediffusion_compare.png` (AI-generated)
228
+
229
  ## Architecture
230
 
231
  ```
 
238
  misses β€” that's why it stays small and trains fast.
239
  - **ICNR-initialized** PixelShuffle head (checkerboard-free by construction).
240
  - The op graph is trivial: `Conv, Add, ReLU, DepthToSpace, Resize`. That's the
241
+ entire reason it exports to dynamic ONNX and converts to ncnn (verified)
242
+ without custom ops or fused/unfused pairs; CoreML is expected but untested.
 
 
 
 
 
 
 
 
 
 
243
 
244
  ## What we actually tested
245
 
 
258
  variant made thin lines *worse* and was reverted.
259
  - **OTF/GAN capability**: the small net trained productively under the full
260
  Real-ESRGAN OTF GAN recipe (no collapse).
261
+ - **Runtime validation**: every released `.safetensors` loads (strict) and runs;
262
+ every `.onnx` loads in ONNX Runtime; the ncnn models were run at multiple input
263
+ sizes up to 720x720 (2880x2880 output).
264
  - **Deployability**: dynamic-ONNX export + ORT parity and ncnn conversion were
265
  verified at every stage (the numbers are in the log).
266
+ - **Not tested here** (community welcome): TensorRT / DirectML *speed* and
267
+ fixed-shape static exports, CoreML, and on-device benchmarks. Train more
268
+ variants, benchmark, and share β€” the arch is standard ops only.
269
 
270
+ ## Training data & license
271
 
272
+ All released NERVE models were trained **only** on
273
+ [`Phips/lucid-cc0-v2-hc-512`](https://huggingface.co/datasets/Phips/lucid-cc0-v2-hc-512),
274
+ a **CC0** dataset β€” the released weights are clean to use commercially.
 
275
 
276
+ We did **not** optimize for benchmark leaderboards. If you want higher
277
+ PSNR/LPIPS numbers, training on larger academic datasets (DIV2K, Flickr2K,
278
+ LSDIR, ...) is expected to score better; NERVE is a normal architecture, train
279
+ it on whatever you like.
 
 
280
 
281
  ## Relation to HEART
282
 
 
294
  Both export to dynamic ONNX; NERVE additionally converts to ncnn cleanly
295
  because it has no attention ops.
296
 
297
+ Side-by-side comparisons on the same inputs (`input | bicubic | both release
298
+ models | both OTF GAN models`), each with a 1:1 crop:
299
+ `examples/OST_009_nerve_vs_heart_*` and `examples/00003_nerve_vs_heart_*`
300
+ (Real-ESRGAN test set), plus `examples/realphoto_nerve_vs_heart_*` and
301
+ `examples/noisy_nerve_vs_heart_*`.
302
+
303
  ---
304
 
305
  ## Repository layout
 
309
  configs/ example training configs (+ 4x_NERVE_onnx.yml for ONNX export)
310
  models/ pretrained checkpoints (see table above)
311
  onnx/ dynamic fp32 ONNX (opset 20, onnxslim-optimized)
312
+ ncnn/ ncnn fp16 param/bin
313
  docs/ABLATIONS.md the full development/ablation log (what we tested)
314
  examples/ real-image comparisons (input vs bicubic vs release vs GAN)
315
  scripts/export_dynamic.py checkpoint β†’ dynamic ONNX exporter (+ ORT verify)
316
  LICENSE Apache-2.0
317
  ```
318
 
319
+ ## Help wanted (community welcome)
320
+
321
+ The goal here is **real-world usability** β€” easy training, hassle-free dynamic
322
+ ONNX, simple and robust to maintain β€” **not** leaderboard chasing. So NERVE's
323
+ strength is *simplicity for trainers*; there's still plenty worth measuring.
324
+ Pick anything below and open an issue/PR/discussion with your numbers.
325
+
326
+ **Benchmarks** (deliberately not chased here)
327
+ - Train on an academic dataset (DIV2K / Flickr2K / LSDIR) and compare against
328
+ SPAN, SRVGGNetCompact, HAT, Real-ESRGAN (PSNR / SSIM / LPIPS).
329
+ - Perceptual metrics (LPIPS / TopIQ / MUSIQ) on real-world degraded images.
330
+
331
+ **Speed & deployment** (not benchmarked here)
332
+ - TensorRT / DirectML latency + peak VRAM on the dynamic ONNX.
333
+ - Static-shape ONNX (e.g. `1x3x256x256`) vs dynamic: speed + memory.
334
+ - fp16 vs fp32 ONNX.
335
+ - ncnn on-device (Android / iOS): latency + memory.
336
+ - CoreML conversion + on-device test.
337
+ - Mobile CPU (XNNPACK / ORT Mobile / ncnn).
338
+
339
+ **Models & code**
340
+ - More finetunes (illustration, manga, denoise, 1x restoration).
341
+ - Architecture experiments β€” see [`docs/ABLATIONS.md`](docs/ABLATIONS.md) for
342
+ what we already tested (and rejected).
343
+
344
+ Small, measured contributions are welcome.
345
+
346
  ## License
347
 
348
  Apache-2.0 (this repository's code and pretrained weights).