DetailNet r2: weights, config and model card
Browse files- README.md +99 -0
- config.json +30 -0
- 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
|