tsonubin commited on
Commit
8b065a3
·
verified ·
1 Parent(s): 7d7dae3

DetailNet r2: weights, config and model card

Browse files
Files changed (3) hide show
  1. README.md +99 -0
  2. config.json +30 -0
  3. model.safetensors +3 -0
README.md ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ library_name: pytorch
4
+ pipeline_tag: image-to-image
5
+ tags:
6
+ - video-super-resolution
7
+ - super-resolution
8
+ - apple-silicon
9
+ - videotoolbox
10
+ - research
11
+ ---
12
+
13
+ # DetailNet r2
14
+
15
+ A small recurrent network (about 1M parameters) that adds fine texture on top of the output of **Apple's on-device video super-resolution**, VideoToolbox's `VTSuperResolutionScaler`. It's for upscaling 720p video to 4K (×3) on Apple silicon. It was trained entirely on a MacBook Pro (M5 Max, 64 GB).
16
+
17
+ > **Research release. By eye, r2 is not a visible improvement over Apple AI.** On our metrics it is as steady as Apple's output, handles scene cuts more cleanly, and is closer to ground truth on LPIPS. But the extra fine detail it adds (1.13× Apple's) is too small to see, and it missed its own goal of 1.5×. It's published so others can build on the approach, not as a better upscaler to use today.
18
+
19
+ - **Code, benchmark and training pipeline:** https://github.com/tsonubin/metafx-upscale
20
+ - **License:** Apache-2.0
21
+
22
+ ## How it works
23
+
24
+ For each frame, at source resolution (for example 1280×720), DetailNet takes:
25
+ - `x_t`, `x_prev`: the current and previous source frames (RGB, 0–1);
26
+ - `base`: Apple AI's output for the frame, resized to exactly 3× the source (RGB, 0–1);
27
+ - `flow4`: VideoToolbox optical flow between `x_prev` and `x_t`, in source pixels, with channels `back_x, back_y, fwd_x, fwd_y`;
28
+ - its own previous texture and hidden state, warped along the flow so the invented texture stays locked to the scene.
29
+
30
+ It returns `detail`, a zero-mean, high-pass texture layer at 3× resolution. The final frame is `base + strength · detail`, so the model can't change brightness, color or shapes. Its state is reset at scene cuts and wherever the flow is invalid.
31
+
32
+ | | |
33
+ |---|---|
34
+ | Architecture | conv3×3 → 12 residual blocks (64 channels) → texture head (pixel shuffle ×3, high-pass) + hidden-state head (32 channels, tanh) |
35
+ | Parameters | 972,795 (3.9 MB, float32) |
36
+ | Scale | ×3 only (720p → 4K). It needs Apple AI's base, so it runs on macOS 26+ |
37
+ | Cost | About 0.03–0.04 s per frame on MPS for a 704×424 source crop, on top of Apple AI's ≈0.35 s per frame |
38
+
39
+ ## Results
40
+
41
+ These are go / no-go gates on the project's benchmark (12 clips from broadcast nature documentaries), compared with `apple-base`, Apple AI's output before compression.
42
+ - **Detail** and **jitter** are ratios to Apple AI, measured on five real 720p → 4K clips. Jitter is motion-compensated frame-to-frame change; lower is steadier.
43
+ - **LPIPS** is measured on five ground-truth clips: real 1080p frames shrunk to 640×360, upscaled ×3 and compared with the original. Lower is better.
44
+
45
+ | Gate | Target | r2 | Apple AI |
46
+ |---|---|---|---|
47
+ | Fine detail | ≥ 1.5× | **1.13×** (fail) | 1.00× |
48
+ | Jitter, all motion | ≤ 1.1× | 1.00× | 1.00× |
49
+ | Jitter static / slow / fast | ≤ 1.1× each | 0.94 / 0.97 / 1.07 | 1.00 |
50
+ | Pulse (4-frame shimmer) | ≤ 1.1 | 1.01 | n/a |
51
+ | Detail leaking across a cut | ≤ Apple's | **0.14** | 0.52 |
52
+ | LPIPS vs real 1080p (×3) | ≤ Apple's | **0.252** | 0.317 |
53
+
54
+ Its measured wins come mostly from smoothing away Apple's slightly painterly artifacts, which LPIPS rewards. Side by side at 1:1, the two are hard to tell apart. Scaling the texture up 3× reaches 1.59× detail, but jitter rises to 1.28×, so the texture isn't locked well enough to amplify.
55
+
56
+ ## Usage
57
+
58
+ ```python
59
+ from safetensors.torch import load_file
60
+ from detailnet.model import DetailNet, compose # from the GitHub repo
61
+
62
+ net = DetailNet(scale=3, channels=64, blocks=12, hidden=32).eval()
63
+ net.load_state_dict(load_file("model.safetensors"))
64
+
65
+ prev_detail, hidden = net.zero_state(1, h, w, "cpu") # reset at the first frame and at every cut
66
+ detail, hidden = net(x_t, x_prev, base, flow4, prev_detail, hidden)
67
+ frame = compose(base, detail, strength=1.0) # base + strength * detail, clamped to [0, 1]
68
+ prev_detail = detail
69
+ ```
70
+
71
+ **Producing the inputs:**
72
+ - The repo's Swift CLI writes `x_t`, `base` and `flow4` as frame dumps: `metalfx-upscale input.mp4 out.mp4 --engine ml --size 3x --dump-source S --dump-base B --dump-flow F`.
73
+ - The exact reset and flow-cleaning rules are in `detailnet/run_bench.py` and `detailnet/train.py` (`run_sequence`).
74
+ - There is no end-to-end "upscale my video with DetailNet" tool yet. The repo runs it over benchmark clips; putting it into the upscaler and app was planned as the next milestone.
75
+
76
+ ## Training
77
+
78
+ - **Data:** about 1,100 short sequences (720p and 1080p) cut from broadcast nature documentaries (ABC, Australian Broadcasting Corporation). The footage is copyrighted and isn't distributed; only the trained weights are released.
79
+ - **Teacher:** FlashVSR v1.1, a one-step streaming diffusion super-resolution model (Apache-2.0). We ported it to Apple's MPS and ran it offline to make texture targets.
80
+ - **Losses:**
81
+ - perceptual (LPIPS / DISTS) plus L1, against the teacher;
82
+ - a temporal lock term that penalizes texture changes not explained by optical flow;
83
+ - a ping-pong consistency term.
84
+ - **Schedule:**
85
+ - 14,000 iterations, batch 4, 160×90 source crops, learning rate 2e-4 with a cosine schedule, seed 1;
86
+ - initialised from r1's checkpoint at iteration 18,000;
87
+ - about 10 hours per round on the M5 Max.
88
+
89
+ ## Limitations
90
+
91
+ - **Not a visible improvement over Apple AI** (see above). Treat it as a baseline for further work, for example an adversarial loss or a stronger temporal lock.
92
+ - **Hard dependencies:** ×3 only, and it needs Apple AI's output and VideoToolbox optical flow, so macOS 26+ on Apple silicon.
93
+ - **Narrow training data:** one footage domain only (nature documentaries) and SDR only.
94
+
95
+ ## Attribution
96
+
97
+ - **Teacher:** FlashVSR v1.1 (Apache-2.0).
98
+ - **Base upscaler:** Apple VideoToolbox `VTSuperResolutionScaler`, which runs on the user's Mac; nothing from Apple is redistributed.
99
+ - **Footage:** used for training only, not distributed.
config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architecture": "DetailNet",
3
+ "release": "r2",
4
+ "scale": 3,
5
+ "channels": 64,
6
+ "blocks": 12,
7
+ "hidden": 32,
8
+ "parameters": 972795,
9
+ "training": {
10
+ "iters": 14000,
11
+ "batch": 4,
12
+ "lr": 0.0002,
13
+ "weight_decay": 0.0001,
14
+ "w_perc": 1.0,
15
+ "w_l1": 1.0,
16
+ "w_lock": 1.0,
17
+ "w_pp": 0.5,
18
+ "seed": 1,
19
+ "crop": [
20
+ 160,
21
+ 90
22
+ ],
23
+ "reset_prob": 0.15,
24
+ "pp_prob": 0.2,
25
+ "perc_frames": 4,
26
+ "grad_clip": 1.0,
27
+ "initialised_from": "r1 (iteration 18000)",
28
+ "device": "Apple M5 Max (MPS)"
29
+ }
30
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8188eff2ca81b3166f4814be8687dee65ccd5e570dbdb01484e97e4d00093784
3
+ size 3895972