Instructions to use moonbox-ai/VOSR-MLX with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use moonbox-ai/VOSR-MLX with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download moonbox-ai/VOSR-MLX --local-dir VOSR-MLX
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
4bit build of VOSR 2.0
Browse files- 4bit/config.json +67 -0
- 4bit/mlx_model.py +579 -0
- 4bit/model.safetensors +3 -0
4bit/config.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_type": "vosr",
|
| 3 |
+
"version": "2.0",
|
| 4 |
+
"dim": 1536,
|
| 5 |
+
"depth": 36,
|
| 6 |
+
"num_heads": 24,
|
| 7 |
+
"mlp_ratio": 4,
|
| 8 |
+
"patch_size": 2,
|
| 9 |
+
"latent_channels": 16,
|
| 10 |
+
"train_tokens": 32,
|
| 11 |
+
"enc_dim": 1024,
|
| 12 |
+
"encdim_ratio": 3,
|
| 13 |
+
"dino_depth": 18,
|
| 14 |
+
"dino_heads": 16,
|
| 15 |
+
"dino_size": 448,
|
| 16 |
+
"dino_patch": 14,
|
| 17 |
+
"vae_base_dim": 96,
|
| 18 |
+
"vae_dim_mult": [
|
| 19 |
+
1,
|
| 20 |
+
2,
|
| 21 |
+
4,
|
| 22 |
+
4
|
| 23 |
+
],
|
| 24 |
+
"vae_res_blocks": 2,
|
| 25 |
+
"latents_mean": [
|
| 26 |
+
-0.7571,
|
| 27 |
+
-0.7089,
|
| 28 |
+
-0.9113,
|
| 29 |
+
0.1075,
|
| 30 |
+
-0.1745,
|
| 31 |
+
0.9653,
|
| 32 |
+
-0.1517,
|
| 33 |
+
1.5508,
|
| 34 |
+
0.4134,
|
| 35 |
+
-0.0715,
|
| 36 |
+
0.5517,
|
| 37 |
+
-0.3632,
|
| 38 |
+
-0.1922,
|
| 39 |
+
-0.9497,
|
| 40 |
+
0.2503,
|
| 41 |
+
-0.2921
|
| 42 |
+
],
|
| 43 |
+
"latents_std": [
|
| 44 |
+
2.8184,
|
| 45 |
+
1.4541,
|
| 46 |
+
2.3275,
|
| 47 |
+
2.6558,
|
| 48 |
+
1.2196,
|
| 49 |
+
1.7708,
|
| 50 |
+
2.6052,
|
| 51 |
+
2.0743,
|
| 52 |
+
3.2687,
|
| 53 |
+
2.1526,
|
| 54 |
+
2.8652,
|
| 55 |
+
1.5579,
|
| 56 |
+
1.6382,
|
| 57 |
+
1.1253,
|
| 58 |
+
2.8251,
|
| 59 |
+
1.916
|
| 60 |
+
],
|
| 61 |
+
"quantization": {
|
| 62 |
+
"group_size": 64,
|
| 63 |
+
"bits": 4,
|
| 64 |
+
"mode": "affine"
|
| 65 |
+
},
|
| 66 |
+
"precision": "4bit"
|
| 67 |
+
}
|
4bit/mlx_model.py
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""VOSR 2.0 (cswry/VOSR, Apache-2.0) in MLX: one-step generative super-resolution.
|
| 2 |
+
|
| 3 |
+
The pipeline of inference_vosr_onestep.py (tile_size 0, the default): the low-resolution picture is bicubic-upscaled
|
| 4 |
+
to the output size, encoded by the 2D Qwen-Image VAE, and a 1.4B LightningDiT turns noise into the restored latent in
|
| 5 |
+
one flow step (t 1 -> 0), conditioned on the VAE latent (concatenated) and on DINOv2-L block 18 features of the
|
| 6 |
+
upscaled picture (cross-attention). The VAE decodes, and the wavelet color fix (cv2 GaussianBlur, sigma 5) takes the
|
| 7 |
+
low frequencies from the bicubic upscale.
|
| 8 |
+
|
| 9 |
+
Layout: NHWC throughout. Only the first 18 DINOv2 blocks are kept (VOSR reads block 18 and never the rest); its
|
| 10 |
+
position embedding is stored already interpolated to the 448x448 input VOSR always uses. Norm statistics, the
|
| 11 |
+
timestep embedding and the color fix run in float32.
|
| 12 |
+
|
| 13 |
+
import mlx_model
|
| 14 |
+
model = mlx_model.load("bf16")
|
| 15 |
+
sr = mlx_model.upscale(model, rgb_uint8, scale=4, seed=42)
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
from __future__ import annotations
|
| 19 |
+
|
| 20 |
+
import json
|
| 21 |
+
import math
|
| 22 |
+
from pathlib import Path
|
| 23 |
+
|
| 24 |
+
import mlx.core as mx
|
| 25 |
+
import mlx.nn as nn
|
| 26 |
+
import numpy as np
|
| 27 |
+
|
| 28 |
+
CONFIG = {"model_type": "vosr", "version": "2.0", "dim": 1536, "depth": 36, "num_heads": 24, "mlp_ratio": 4,
|
| 29 |
+
"patch_size": 2, "latent_channels": 16, "train_tokens": 32, "enc_dim": 1024, "encdim_ratio": 3,
|
| 30 |
+
"dino_depth": 18, "dino_heads": 16, "dino_size": 448, "dino_patch": 14, "vae_base_dim": 96,
|
| 31 |
+
"vae_dim_mult": [1, 2, 4, 4], "vae_res_blocks": 2,
|
| 32 |
+
"latents_mean": [-0.7571, -0.7089, -0.9113, 0.1075, -0.1745, 0.9653, -0.1517, 1.5508, 0.4134, -0.0715,
|
| 33 |
+
0.5517, -0.3632, -0.1922, -0.9497, 0.2503, -0.2921],
|
| 34 |
+
"latents_std": [2.8184, 1.4541, 2.3275, 2.6558, 1.2196, 1.7708, 2.6052, 2.0743, 3.2687, 2.1526, 2.8652,
|
| 35 |
+
1.5579, 1.6382, 1.1253, 2.8251, 1.916]}
|
| 36 |
+
GROUP = 64
|
| 37 |
+
IMAGENET_MEAN = np.array([0.485, 0.456, 0.406], np.float32)
|
| 38 |
+
IMAGENET_STD = np.array([0.229, 0.224, 0.225], np.float32)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def quantizable(path: str, module) -> bool:
|
| 42 |
+
return isinstance(module, nn.Linear) and module.weight.shape[-1] % GROUP == 0
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
# ------------------------------------------------------------------------------------------------ ops
|
| 46 |
+
|
| 47 |
+
def rms(x, weight, eps=1e-6):
|
| 48 |
+
y = x.astype(mx.float32)
|
| 49 |
+
y = y * mx.rsqrt(mx.mean(y * y, axis=-1, keepdims=True) + eps)
|
| 50 |
+
return y.astype(x.dtype) * weight
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class RMSNorm(nn.Module):
|
| 54 |
+
def __init__(self, dim):
|
| 55 |
+
super().__init__()
|
| 56 |
+
self.weight = mx.ones((dim,))
|
| 57 |
+
|
| 58 |
+
def __call__(self, x):
|
| 59 |
+
return rms(x, self.weight)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def layer_norm(ln, x):
|
| 63 |
+
return mx.fast.layer_norm(x.astype(mx.float32), ln.weight.astype(mx.float32), ln.bias.astype(mx.float32),
|
| 64 |
+
ln.eps).astype(x.dtype)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def bicubic_matrix(n_in: int, n_out: int) -> np.ndarray:
|
| 68 |
+
"""torch F.interpolate(mode="bicubic", align_corners=False, antialias=False) along one axis, (n_out, n_in)."""
|
| 69 |
+
A = -0.75
|
| 70 |
+
m = np.zeros((n_out, n_in), np.float64)
|
| 71 |
+
scale = n_in / n_out
|
| 72 |
+
for o in range(n_out):
|
| 73 |
+
s = (o + 0.5) * scale - 0.5
|
| 74 |
+
f = int(np.floor(s))
|
| 75 |
+
t = s - f
|
| 76 |
+
w = [((A * (t + 1) - 5 * A) * (t + 1) + 8 * A) * (t + 1) - 4 * A,
|
| 77 |
+
((A + 2) * t - (A + 3)) * t * t + 1,
|
| 78 |
+
((A + 2) * (1 - t) - (A + 3)) * (1 - t) * (1 - t) + 1,
|
| 79 |
+
((A * (2 - t) - 5 * A) * (2 - t) + 8 * A) * (2 - t) - 4 * A]
|
| 80 |
+
for j in range(4):
|
| 81 |
+
m[o, min(max(f - 1 + j, 0), n_in - 1)] += w[j]
|
| 82 |
+
return m.astype(np.float32)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def bicubic(x, size):
|
| 86 |
+
"""(B, H, W, C) float32 -> (B, size[0], size[1], C)."""
|
| 87 |
+
_, h, w, _ = x.shape
|
| 88 |
+
mh, mw = mx.array(bicubic_matrix(h, size[0])), mx.array(bicubic_matrix(w, size[1]))
|
| 89 |
+
y = mx.einsum("oh,bhwc->bowc", mh, x)
|
| 90 |
+
return mx.einsum("pw,bowc->bopc", mw, y)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# ------------------------------------------------------------------------------------------------ Qwen-Image VAE (2D)
|
| 94 |
+
|
| 95 |
+
class RMSNorm2D(nn.Module):
|
| 96 |
+
"""F.normalize over channels * sqrt(C) * gamma, in float32."""
|
| 97 |
+
|
| 98 |
+
def __init__(self, dim):
|
| 99 |
+
super().__init__()
|
| 100 |
+
self.gamma = mx.ones((dim,))
|
| 101 |
+
|
| 102 |
+
def __call__(self, x):
|
| 103 |
+
y = x.astype(mx.float32)
|
| 104 |
+
n = mx.sqrt(mx.sum(y * y, axis=-1, keepdims=True))
|
| 105 |
+
y = y / mx.maximum(n, 1e-12) * math.sqrt(y.shape[-1])
|
| 106 |
+
return (y * self.gamma.astype(mx.float32)).astype(x.dtype)
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
class ResBlock(nn.Module):
|
| 110 |
+
def __init__(self, cin, cout):
|
| 111 |
+
super().__init__()
|
| 112 |
+
self.norm1 = RMSNorm2D(cin)
|
| 113 |
+
self.conv1 = nn.Conv2d(cin, cout, 3, padding=1)
|
| 114 |
+
self.norm2 = RMSNorm2D(cout)
|
| 115 |
+
self.conv2 = nn.Conv2d(cout, cout, 3, padding=1)
|
| 116 |
+
if cin != cout:
|
| 117 |
+
self.conv_shortcut = nn.Conv2d(cin, cout, 1)
|
| 118 |
+
|
| 119 |
+
def __call__(self, x):
|
| 120 |
+
h = self.conv_shortcut(x) if "conv_shortcut" in self else x
|
| 121 |
+
x = self.conv1(nn.silu(self.norm1(x)))
|
| 122 |
+
x = self.conv2(nn.silu(self.norm2(x)))
|
| 123 |
+
return x + h
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
class VAEAttention(nn.Module):
|
| 127 |
+
def __init__(self, dim):
|
| 128 |
+
super().__init__()
|
| 129 |
+
self.norm = RMSNorm2D(dim)
|
| 130 |
+
self.to_qkv = nn.Conv2d(dim, dim * 3, 1)
|
| 131 |
+
self.proj = nn.Conv2d(dim, dim, 1)
|
| 132 |
+
|
| 133 |
+
def __call__(self, x):
|
| 134 |
+
b, h, w, c = x.shape
|
| 135 |
+
q, k, v = mx.split(self.to_qkv(self.norm(x)).reshape(b, 1, h * w, 3 * c), 3, axis=-1)
|
| 136 |
+
y = mx.fast.scaled_dot_product_attention(q, k, v, scale=c ** -0.5)
|
| 137 |
+
return self.proj(y.reshape(b, h, w, c)) + x
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
class Down(nn.Module):
|
| 141 |
+
def __init__(self, dim):
|
| 142 |
+
super().__init__()
|
| 143 |
+
self.conv = nn.Conv2d(dim, dim, 3, stride=2)
|
| 144 |
+
|
| 145 |
+
def __call__(self, x):
|
| 146 |
+
return self.conv(mx.pad(x, [(0, 0), (0, 1), (0, 1), (0, 0)]))
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
class Up(nn.Module):
|
| 150 |
+
def __init__(self, dim):
|
| 151 |
+
super().__init__()
|
| 152 |
+
self.conv = nn.Conv2d(dim, dim // 2, 3, padding=1)
|
| 153 |
+
|
| 154 |
+
def __call__(self, x):
|
| 155 |
+
b, h, w, c = x.shape
|
| 156 |
+
x = mx.broadcast_to(x[:, :, None, :, None, :], (b, h, 2, w, 2, c)).reshape(b, h * 2, w * 2, c)
|
| 157 |
+
return self.conv(x)
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
class Mid(nn.Module):
|
| 161 |
+
def __init__(self, dim):
|
| 162 |
+
super().__init__()
|
| 163 |
+
self.resnets = [ResBlock(dim, dim), ResBlock(dim, dim)]
|
| 164 |
+
self.attentions = [VAEAttention(dim)]
|
| 165 |
+
|
| 166 |
+
def __call__(self, x):
|
| 167 |
+
return self.resnets[1](self.attentions[0](self.resnets[0](x)))
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
class Encoder(nn.Module):
|
| 171 |
+
def __init__(self, dim, z_dim, mult, nres):
|
| 172 |
+
super().__init__()
|
| 173 |
+
dims = [dim * u for u in [1] + mult]
|
| 174 |
+
self.conv_in = nn.Conv2d(3, dims[0], 3, padding=1)
|
| 175 |
+
self.down_blocks = []
|
| 176 |
+
for i, (cin, cout) in enumerate(zip(dims[:-1], dims[1:])):
|
| 177 |
+
for _ in range(nres):
|
| 178 |
+
self.down_blocks.append(ResBlock(cin, cout))
|
| 179 |
+
cin = cout
|
| 180 |
+
if i != len(mult) - 1:
|
| 181 |
+
self.down_blocks.append(Down(cout))
|
| 182 |
+
self.mid_block = Mid(cout)
|
| 183 |
+
self.norm_out = RMSNorm2D(cout)
|
| 184 |
+
self.conv_out = nn.Conv2d(cout, z_dim, 3, padding=1)
|
| 185 |
+
|
| 186 |
+
def __call__(self, x):
|
| 187 |
+
x = self.conv_in(x)
|
| 188 |
+
for layer in self.down_blocks:
|
| 189 |
+
x = layer(x)
|
| 190 |
+
return self.conv_out(nn.silu(self.norm_out(self.mid_block(x))))
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
class UpBlock(nn.Module):
|
| 194 |
+
def __init__(self, cin, cout, nres, up):
|
| 195 |
+
super().__init__()
|
| 196 |
+
self.resnets = [ResBlock(cin if i == 0 else cout, cout) for i in range(nres + 1)]
|
| 197 |
+
if up:
|
| 198 |
+
self.upsamplers = [Up(cout)]
|
| 199 |
+
|
| 200 |
+
def __call__(self, x):
|
| 201 |
+
for r in self.resnets:
|
| 202 |
+
x = r(x)
|
| 203 |
+
return self.upsamplers[0](x) if "upsamplers" in self else x
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
class Decoder(nn.Module):
|
| 207 |
+
def __init__(self, dim, z_dim, mult, nres):
|
| 208 |
+
super().__init__()
|
| 209 |
+
dims = [dim * u for u in [mult[-1]] + mult[::-1]]
|
| 210 |
+
self.conv_in = nn.Conv2d(z_dim, dims[0], 3, padding=1)
|
| 211 |
+
self.mid_block = Mid(dims[0])
|
| 212 |
+
self.up_blocks = []
|
| 213 |
+
for i, (cin, cout) in enumerate(zip(dims[:-1], dims[1:])):
|
| 214 |
+
self.up_blocks.append(UpBlock(cin // 2 if i > 0 else cin, cout, nres, i != len(mult) - 1))
|
| 215 |
+
self.norm_out = RMSNorm2D(cout)
|
| 216 |
+
self.conv_out = nn.Conv2d(cout, 3, 3, padding=1)
|
| 217 |
+
|
| 218 |
+
def __call__(self, x):
|
| 219 |
+
x = self.mid_block(self.conv_in(x))
|
| 220 |
+
for b in self.up_blocks:
|
| 221 |
+
x = b(x)
|
| 222 |
+
return self.conv_out(nn.silu(self.norm_out(x)))
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
class VAE(nn.Module):
|
| 226 |
+
def __init__(self, cfg):
|
| 227 |
+
super().__init__()
|
| 228 |
+
d, z, mult, nres = cfg["vae_base_dim"], cfg["latent_channels"], cfg["vae_dim_mult"], cfg["vae_res_blocks"]
|
| 229 |
+
self.encoder = Encoder(d, 2 * z, mult, nres)
|
| 230 |
+
self.quant_conv = nn.Conv2d(2 * z, 2 * z, 1)
|
| 231 |
+
self.post_quant_conv = nn.Conv2d(z, z, 1)
|
| 232 |
+
self.decoder = Decoder(d, z, mult, nres)
|
| 233 |
+
self.z = z
|
| 234 |
+
|
| 235 |
+
def encode(self, x):
|
| 236 |
+
"""Pixels in [-1, 1] -> the posterior mode (the mean)."""
|
| 237 |
+
h = self.quant_conv(self.encoder(x.astype(self.quant_conv.weight.dtype)))
|
| 238 |
+
return h[..., :self.z].astype(mx.float32)
|
| 239 |
+
|
| 240 |
+
def decode(self, z):
|
| 241 |
+
x = self.decoder(self.post_quant_conv(z.astype(self.post_quant_conv.weight.dtype)))
|
| 242 |
+
return mx.clip(x.astype(mx.float32), -1, 1)
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
# ------------------------------------------------------------------------------------------------ DINOv2-L
|
| 246 |
+
|
| 247 |
+
class DinoBlock(nn.Module):
|
| 248 |
+
def __init__(self, dim, heads):
|
| 249 |
+
super().__init__()
|
| 250 |
+
self.heads = heads
|
| 251 |
+
self.norm1 = nn.LayerNorm(dim, eps=1e-6)
|
| 252 |
+
self.qkv = nn.Linear(dim, dim * 3)
|
| 253 |
+
self.proj = nn.Linear(dim, dim)
|
| 254 |
+
self.ls1 = mx.ones((dim,))
|
| 255 |
+
self.norm2 = nn.LayerNorm(dim, eps=1e-6)
|
| 256 |
+
self.fc1 = nn.Linear(dim, dim * 4)
|
| 257 |
+
self.fc2 = nn.Linear(dim * 4, dim)
|
| 258 |
+
self.ls2 = mx.ones((dim,))
|
| 259 |
+
|
| 260 |
+
def __call__(self, x):
|
| 261 |
+
b, n, c = x.shape
|
| 262 |
+
hd = c // self.heads
|
| 263 |
+
qkv = self.qkv(layer_norm(self.norm1, x)).reshape(b, n, 3, self.heads, hd).transpose(2, 0, 3, 1, 4)
|
| 264 |
+
y = mx.fast.scaled_dot_product_attention(qkv[0], qkv[1], qkv[2], scale=hd ** -0.5)
|
| 265 |
+
x = x + self.ls1 * self.proj(y.transpose(0, 2, 1, 3).reshape(b, n, c))
|
| 266 |
+
return x + self.ls2 * self.fc2(nn.gelu(self.fc1(layer_norm(self.norm2, x))))
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
class Dino(nn.Module):
|
| 270 |
+
def __init__(self, cfg):
|
| 271 |
+
super().__init__()
|
| 272 |
+
d, p = cfg["enc_dim"], cfg["dino_patch"]
|
| 273 |
+
g = cfg["dino_size"] // p
|
| 274 |
+
self.patch_embed = nn.Conv2d(3, d, p, stride=p)
|
| 275 |
+
self.cls_token = mx.zeros((1, 1, d))
|
| 276 |
+
self.pos_embed = mx.zeros((1, 1 + g * g, d))
|
| 277 |
+
self.blocks = [DinoBlock(d, cfg["dino_heads"]) for _ in range(cfg["dino_depth"])]
|
| 278 |
+
|
| 279 |
+
def __call__(self, x):
|
| 280 |
+
"""(B, 448, 448, 3) ImageNet-normalized -> (B, 1024, 1024) patch tokens after the last kept block."""
|
| 281 |
+
x = self.patch_embed(x.astype(self.patch_embed.weight.dtype))
|
| 282 |
+
b, h, w, c = x.shape
|
| 283 |
+
x = mx.concatenate([mx.broadcast_to(self.cls_token, (b, 1, c)), x.reshape(b, h * w, c)], axis=1)
|
| 284 |
+
x = x + self.pos_embed
|
| 285 |
+
for blk in self.blocks:
|
| 286 |
+
x = blk(x)
|
| 287 |
+
return x[:, 1:]
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
# ------------------------------------------------------------------------------------------------ LightningDiT
|
| 291 |
+
|
| 292 |
+
def rope_tables(h, w, head_dim, train_tokens):
|
| 293 |
+
"""VisionRotaryEmbeddingFast / _get_dynamic_rope: positions scaled to the 32-token training grid; the first half
|
| 294 |
+
of each head rotates with the row, the second with the column, in interleaved pairs."""
|
| 295 |
+
half = head_dim // 2
|
| 296 |
+
inv = 1.0 / (10000 ** (np.arange(0, half, 2)[:half // 2].astype(np.float32) / half))
|
| 297 |
+
|
| 298 |
+
def axis(n):
|
| 299 |
+
t = np.arange(n, dtype=np.float32) / n * train_tokens
|
| 300 |
+
return np.repeat(np.einsum("i,f->if", t, inv), 2, axis=-1) # (n, half)
|
| 301 |
+
|
| 302 |
+
fh, fw = axis(h), axis(w)
|
| 303 |
+
f = np.concatenate([np.broadcast_to(fh[:, None], (h, w, half)), np.broadcast_to(fw[None], (h, w, half))], -1)
|
| 304 |
+
f = f.reshape(h * w, head_dim)
|
| 305 |
+
return mx.array(np.cos(f)), mx.array(np.sin(f))
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
def rope(x, cos, sin):
|
| 309 |
+
s = x.shape
|
| 310 |
+
pairs = x.reshape(*s[:-1], s[-1] // 2, 2)
|
| 311 |
+
rot = mx.stack([-pairs[..., 1], pairs[..., 0]], axis=-1).reshape(s)
|
| 312 |
+
return x * cos.astype(x.dtype) + rot * sin.astype(x.dtype)
|
| 313 |
+
|
| 314 |
+
|
| 315 |
+
class SelfAttention(nn.Module):
|
| 316 |
+
def __init__(self, dim, heads):
|
| 317 |
+
super().__init__()
|
| 318 |
+
self.heads = heads
|
| 319 |
+
self.qkv = nn.Linear(dim, dim * 3)
|
| 320 |
+
self.q_norm = RMSNorm(dim // heads)
|
| 321 |
+
self.k_norm = RMSNorm(dim // heads)
|
| 322 |
+
self.proj = nn.Linear(dim, dim)
|
| 323 |
+
|
| 324 |
+
def __call__(self, x, cos, sin):
|
| 325 |
+
b, n, c = x.shape
|
| 326 |
+
hd = c // self.heads
|
| 327 |
+
qkv = self.qkv(x).reshape(b, n, 3, self.heads, hd).transpose(2, 0, 3, 1, 4)
|
| 328 |
+
q, k = rope(self.q_norm(qkv[0]), cos, sin), rope(self.k_norm(qkv[1]), cos, sin)
|
| 329 |
+
y = mx.fast.scaled_dot_product_attention(q, k, qkv[2], scale=hd ** -0.5)
|
| 330 |
+
return self.proj(y.transpose(0, 2, 1, 3).reshape(b, n, c))
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
class CrossAttention(nn.Module):
|
| 334 |
+
def __init__(self, dim, heads):
|
| 335 |
+
super().__init__()
|
| 336 |
+
self.heads = heads
|
| 337 |
+
self.q_linear = nn.Linear(dim, dim)
|
| 338 |
+
self.k_linear = nn.Linear(dim, dim)
|
| 339 |
+
self.v_linear = nn.Linear(dim, dim)
|
| 340 |
+
self.q_norm = RMSNorm(dim // heads)
|
| 341 |
+
self.k_norm = RMSNorm(dim // heads)
|
| 342 |
+
self.proj = nn.Linear(dim, dim)
|
| 343 |
+
|
| 344 |
+
def __call__(self, x, cond):
|
| 345 |
+
b, n, c = x.shape
|
| 346 |
+
m, hd = cond.shape[1], c // self.heads
|
| 347 |
+
q = self.q_norm(self.q_linear(x).reshape(b, n, self.heads, hd).transpose(0, 2, 1, 3))
|
| 348 |
+
k = self.k_norm(self.k_linear(cond).reshape(b, m, self.heads, hd).transpose(0, 2, 1, 3))
|
| 349 |
+
v = self.v_linear(cond).reshape(b, m, self.heads, hd).transpose(0, 2, 1, 3)
|
| 350 |
+
y = mx.fast.scaled_dot_product_attention(q, k, v, scale=hd ** -0.5)
|
| 351 |
+
return self.proj(y.transpose(0, 2, 1, 3).reshape(b, n, c))
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
class SwiGLU(nn.Module):
|
| 355 |
+
def __init__(self, dim, hidden):
|
| 356 |
+
super().__init__()
|
| 357 |
+
self.w12 = nn.Linear(dim, 2 * hidden)
|
| 358 |
+
self.w3 = nn.Linear(hidden, dim)
|
| 359 |
+
|
| 360 |
+
def __call__(self, x):
|
| 361 |
+
a, g = mx.split(self.w12(x), 2, axis=-1)
|
| 362 |
+
return self.w3(nn.silu(a) * g)
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
class Block(nn.Module):
|
| 366 |
+
def __init__(self, dim, heads, mlp_ratio):
|
| 367 |
+
super().__init__()
|
| 368 |
+
self.norm1 = RMSNorm(dim)
|
| 369 |
+
self.norm2 = RMSNorm(dim)
|
| 370 |
+
self.attn = SelfAttention(dim, heads)
|
| 371 |
+
self.mlp = SwiGLU(dim, int(2 / 3 * dim * mlp_ratio))
|
| 372 |
+
self.scale_shift_table = mx.zeros((6, dim))
|
| 373 |
+
self.cross_attn = CrossAttention(dim, heads)
|
| 374 |
+
|
| 375 |
+
def __call__(self, x, c0, z, cos, sin):
|
| 376 |
+
b = x.shape[0]
|
| 377 |
+
mod = self.scale_shift_table[None] + c0.reshape(b, 6, -1)
|
| 378 |
+
sh1, sc1, g1, sh2, sc2, g2 = [mod[:, i:i + 1] for i in range(6)]
|
| 379 |
+
x = x + g1 * self.attn(self.norm1(x) * (1 + sc1) + sh1, cos, sin)
|
| 380 |
+
x = x + self.cross_attn(x, z)
|
| 381 |
+
return x + g2 * self.mlp(self.norm2(x) * (1 + sc2) + sh2)
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
class TimestepEmbedder(nn.Module):
|
| 385 |
+
def __init__(self, dim, freq=256):
|
| 386 |
+
super().__init__()
|
| 387 |
+
self.freq = freq
|
| 388 |
+
self.fc1 = nn.Linear(freq, dim)
|
| 389 |
+
self.fc2 = nn.Linear(dim, dim)
|
| 390 |
+
|
| 391 |
+
def __call__(self, t):
|
| 392 |
+
half = self.freq // 2
|
| 393 |
+
freqs = mx.exp(-math.log(10000) * mx.arange(half, dtype=mx.float32) / half)
|
| 394 |
+
a = t.astype(mx.float32)[:, None] * freqs[None]
|
| 395 |
+
e = mx.concatenate([mx.cos(a), mx.sin(a)], axis=-1).astype(self.fc1.bias.dtype)
|
| 396 |
+
return self.fc2(nn.silu(self.fc1(e)))
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
class DiT(nn.Module):
|
| 400 |
+
def __init__(self, cfg):
|
| 401 |
+
super().__init__()
|
| 402 |
+
d, p, lc = cfg["dim"], cfg["patch_size"], cfg["latent_channels"]
|
| 403 |
+
self.cfg = cfg
|
| 404 |
+
self.x_embedder = nn.Conv2d(2 * lc, d, p, stride=p)
|
| 405 |
+
self.t_embedder = TimestepEmbedder(d)
|
| 406 |
+
self.t_block = nn.Linear(d, 6 * d)
|
| 407 |
+
self.blocks = [Block(d, cfg["num_heads"], cfg["mlp_ratio"]) for _ in range(cfg["depth"])]
|
| 408 |
+
self.norm_final = RMSNorm(d)
|
| 409 |
+
self.final_linear = nn.Linear(d, p * p * lc)
|
| 410 |
+
self.final_adaln = nn.Linear(d, 2 * d)
|
| 411 |
+
self.layer_norm = nn.LayerNorm(cfg["enc_dim"], eps=1e-5)
|
| 412 |
+
self.mlp_ca_fc1 = nn.Linear(cfg["enc_dim"], d * cfg["encdim_ratio"])
|
| 413 |
+
self.mlp_ca_fc2 = nn.Linear(d * cfg["encdim_ratio"], d)
|
| 414 |
+
|
| 415 |
+
def __call__(self, x, t, feats):
|
| 416 |
+
"""x: (B, H, W, 32) [lq latent, z]; t: (B,); feats: (B, M, 1024) DINOv2 tokens -> velocity (B, H, W, 16)."""
|
| 417 |
+
cfg, dt = self.cfg, self.x_embedder.weight.dtype
|
| 418 |
+
p, lc = cfg["patch_size"], cfg["latent_channels"]
|
| 419 |
+
x = self.x_embedder(x.astype(dt))
|
| 420 |
+
b, h, w, d = x.shape
|
| 421 |
+
x = x.reshape(b, h * w, d)
|
| 422 |
+
c = self.t_embedder(t)
|
| 423 |
+
c0 = self.t_block(nn.silu(c))
|
| 424 |
+
z = self.mlp_ca_fc2(nn.gelu_approx(self.mlp_ca_fc1(layer_norm(self.layer_norm, feats.astype(dt)))))
|
| 425 |
+
cos, sin = rope_tables(h, w, d // cfg["num_heads"], cfg["train_tokens"])
|
| 426 |
+
for blk in self.blocks:
|
| 427 |
+
x = blk(x, c0, z, cos, sin)
|
| 428 |
+
shift, scale = mx.split(self.final_adaln(nn.silu(c)), 2, axis=-1)
|
| 429 |
+
x = self.final_linear(self.norm_final(x) * (1 + scale[:, None]) + shift[:, None])
|
| 430 |
+
x = x.reshape(b, h, w, p, p, lc).transpose(0, 1, 3, 2, 4, 5).reshape(b, h * p, w * p, lc)
|
| 431 |
+
return x.astype(mx.float32)
|
| 432 |
+
|
| 433 |
+
|
| 434 |
+
class Model(nn.Module):
|
| 435 |
+
def __init__(self, config=None):
|
| 436 |
+
super().__init__()
|
| 437 |
+
self.config = dict(config or CONFIG)
|
| 438 |
+
self.vae = VAE(self.config)
|
| 439 |
+
self.dino = Dino(self.config)
|
| 440 |
+
self.dit = DiT(self.config)
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
def load(folder) -> Model:
|
| 444 |
+
folder = Path(folder)
|
| 445 |
+
config = json.loads((folder / "config.json").read_text())
|
| 446 |
+
model = Model(config)
|
| 447 |
+
q = config.get("quantization")
|
| 448 |
+
if q:
|
| 449 |
+
nn.quantize(model, group_size=q["group_size"], bits=q["bits"], class_predicate=quantizable)
|
| 450 |
+
model.load_weights(str(folder / "model.safetensors"), strict=True)
|
| 451 |
+
mx.eval(model.parameters())
|
| 452 |
+
return model
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
# ------------------------------------------------------------------------------------------------ pipeline
|
| 456 |
+
|
| 457 |
+
def gaussian_blur(x: np.ndarray, sigma: float = 5.0) -> np.ndarray:
|
| 458 |
+
"""cv2.GaussianBlur(x, (0, 0), sigma) for float32 HxWxC: kernel 8*sigma+1, BORDER_REFLECT_101."""
|
| 459 |
+
k = int(round(sigma * 4 * 2 + 1)) | 1
|
| 460 |
+
r = k // 2
|
| 461 |
+
g = np.exp(-((np.arange(k) - r) ** 2) / (2 * sigma * sigma))
|
| 462 |
+
g = (g / g.sum()).astype(np.float32)
|
| 463 |
+
y = mx.array(x)
|
| 464 |
+
for axis in (0, 1):
|
| 465 |
+
n = y.shape[axis]
|
| 466 |
+
idx = np.abs(np.arange(-r, n + r))
|
| 467 |
+
idx = np.where(idx > n - 1, 2 * (n - 1) - idx, idx)
|
| 468 |
+
idx = mx.array(idx)
|
| 469 |
+
yp = mx.take(y, idx, axis=axis)
|
| 470 |
+
out = 0
|
| 471 |
+
for j in range(k):
|
| 472 |
+
sl = [slice(None)] * 3
|
| 473 |
+
sl[axis] = slice(j, j + n)
|
| 474 |
+
out = out + float(g[j]) * yp[tuple(sl)]
|
| 475 |
+
y = out
|
| 476 |
+
return np.array(y)
|
| 477 |
+
|
| 478 |
+
|
| 479 |
+
def wavelet_color_fix(sr: np.ndarray, ref: np.ndarray) -> np.ndarray:
|
| 480 |
+
t, s = sr.astype(np.float32) / 255.0, ref.astype(np.float32) / 255.0
|
| 481 |
+
out = np.clip(gaussian_blur(s) + (t - gaussian_blur(t)), 0, 1) * 255.0
|
| 482 |
+
return out.astype(np.uint8)
|
| 483 |
+
|
| 484 |
+
|
| 485 |
+
def restore(model: Model, lq: np.ndarray, noise=None, seed: int = 42) -> np.ndarray:
|
| 486 |
+
"""lq: (H, W, 3) float32 in [-1, 1] at the output size, H and W multiples of 16 -> (H, W, 3) in [-1, 1]."""
|
| 487 |
+
cfg = model.config
|
| 488 |
+
x = mx.array(lq)[None]
|
| 489 |
+
mean, std = mx.array(cfg["latents_mean"]), mx.array(cfg["latents_std"])
|
| 490 |
+
lat = (model.vae.encode(x) - mean) / std
|
| 491 |
+
s = cfg["dino_size"]
|
| 492 |
+
d = mx.clip(bicubic((x + 1) * 0.5, (s, s)), 0, 1)
|
| 493 |
+
d = (d - mx.array(IMAGENET_MEAN)) / mx.array(IMAGENET_STD)
|
| 494 |
+
feats = model.dino(d)
|
| 495 |
+
z = mx.array(noise) if noise is not None else mx.random.normal(lat.shape, key=mx.random.key(seed))
|
| 496 |
+
u = model.dit(mx.concatenate([lat, z], axis=-1), mx.ones((1,)), feats)
|
| 497 |
+
out = model.vae.decode((z - u) * std + mean)
|
| 498 |
+
return np.array(out[0])
|
| 499 |
+
|
| 500 |
+
|
| 501 |
+
def upscale(model: Model, rgb: np.ndarray, scale: int = 4, noise=None, seed: int = 42,
|
| 502 |
+
color_fix: str = "wavelet") -> np.ndarray:
|
| 503 |
+
"""(h, w, 3) uint8 -> (h*scale, w*scale, 3) uint8, as inference_vosr_onestep.py (bicubic upscale with PIL first).
|
| 504 |
+
`noise`: (1, H/8, W/8, 16) float32 to fix the starting noise (H, W: the output size rounded up to 16)."""
|
| 505 |
+
from PIL import Image
|
| 506 |
+
h, w = rgb.shape[:2]
|
| 507 |
+
H, W = h * scale, w * scale
|
| 508 |
+
up = np.asarray(Image.fromarray(rgb).resize((W, H), Image.BICUBIC))
|
| 509 |
+
ph, pw = -H % 16, -W % 16
|
| 510 |
+
x = np.pad(up, [(0, ph), (0, pw), (0, 0)], mode="reflect") if ph or pw else up
|
| 511 |
+
sr = restore(model, x.astype(np.float32) / 255.0 * 2 - 1, noise, seed)[:H, :W]
|
| 512 |
+
sr = (np.clip(sr * 0.5 + 0.5, 0, 1) * 255).astype(np.uint8) # ToPILImage truncates
|
| 513 |
+
return wavelet_color_fix(sr, up) if color_fix == "wavelet" else sr
|
| 514 |
+
|
| 515 |
+
|
| 516 |
+
# ------------------------------------------------------------------------------------------------ conversion
|
| 517 |
+
|
| 518 |
+
def _conv(w):
|
| 519 |
+
return w.transpose(0, 2, 3, 1)
|
| 520 |
+
|
| 521 |
+
|
| 522 |
+
def convert(source: Path) -> dict:
|
| 523 |
+
"""runs/source (CSWRY/VOSR: VOSR2/, Qwen-Image-vae-2d/, torch_cache/checkpoints/dinov2_vitl14_pretrain.pth)
|
| 524 |
+
-> fp32 numpy in this file's layout."""
|
| 525 |
+
import torch
|
| 526 |
+
import torch.nn.functional as F
|
| 527 |
+
from safetensors.numpy import load_file
|
| 528 |
+
|
| 529 |
+
source, cfg, out = Path(source), CONFIG, {}
|
| 530 |
+
|
| 531 |
+
dit = load_file(str(source / "VOSR2" / "checkpoints" / "ema_model.safetensors"))
|
| 532 |
+
ren = {"t_embedder.mlp.0.": "t_embedder.fc1.", "t_embedder.mlp.2.": "t_embedder.fc2.", "t_block.1.": "t_block.",
|
| 533 |
+
"final_layer.norm_final.": "norm_final.", "final_layer.linear.": "final_linear.",
|
| 534 |
+
"final_layer.adaLN_modulation.1.": "final_adaln.", "mlp_ca.fc1.": "mlp_ca_fc1.",
|
| 535 |
+
"mlp_ca.fc2.": "mlp_ca_fc2.", "x_embedder.proj.": "x_embedder."}
|
| 536 |
+
for k, v in dit.items():
|
| 537 |
+
if "freqs_" in k:
|
| 538 |
+
continue # RoPE tables: recomputed per size
|
| 539 |
+
name = k
|
| 540 |
+
for a, b in ren.items():
|
| 541 |
+
if name.startswith(a):
|
| 542 |
+
name = b + name[len(a):]
|
| 543 |
+
v = v.astype(np.float32)
|
| 544 |
+
out["dit." + name] = _conv(v) if v.ndim == 4 else v
|
| 545 |
+
|
| 546 |
+
vae = load_file(str(source / "Qwen-Image-vae-2d" / "diffusion_pytorch_model.safetensors"))
|
| 547 |
+
for k, v in vae.items():
|
| 548 |
+
name = k.replace("resample.1.", "conv.")
|
| 549 |
+
v = v.astype(np.float32)
|
| 550 |
+
if name.endswith(".gamma"):
|
| 551 |
+
v = v.reshape(-1)
|
| 552 |
+
out["vae." + name] = _conv(v) if v.ndim == 4 else v
|
| 553 |
+
|
| 554 |
+
sd = torch.load(source / "torch_cache" / "checkpoints" / "dinov2_vitl14_pretrain.pth", map_location="cpu",
|
| 555 |
+
weights_only=True)
|
| 556 |
+
g = cfg["dino_size"] // cfg["dino_patch"]
|
| 557 |
+
pos = sd["pos_embed"].float()
|
| 558 |
+
m = int(math.sqrt(pos.shape[1] - 1))
|
| 559 |
+
patch = F.interpolate(pos[:, 1:].reshape(1, m, m, -1).permute(0, 3, 1, 2), mode="bicubic", antialias=False,
|
| 560 |
+
scale_factor=((g + 0.1) / m, (g + 0.1) / m))
|
| 561 |
+
assert patch.shape[-2:] == (g, g)
|
| 562 |
+
out["dino.pos_embed"] = torch.cat([pos[:, :1], patch.permute(0, 2, 3, 1).reshape(1, g * g, -1)], 1).numpy()
|
| 563 |
+
out["dino.cls_token"] = sd["cls_token"].float().numpy()
|
| 564 |
+
out["dino.patch_embed.weight"] = _conv(sd["patch_embed.proj.weight"].float().numpy())
|
| 565 |
+
out["dino.patch_embed.bias"] = sd["patch_embed.proj.bias"].float().numpy()
|
| 566 |
+
bren = {"attn.qkv.": "qkv.", "attn.proj.": "proj.", "mlp.fc1.": "fc1.", "mlp.fc2.": "fc2.",
|
| 567 |
+
"ls1.gamma": "ls1", "ls2.gamma": "ls2"}
|
| 568 |
+
for k, v in sd.items():
|
| 569 |
+
if not k.startswith("blocks."):
|
| 570 |
+
continue
|
| 571 |
+
i = int(k.split(".")[1])
|
| 572 |
+
if i >= cfg["dino_depth"]:
|
| 573 |
+
continue
|
| 574 |
+
rest = k.split(".", 2)[2]
|
| 575 |
+
for a, b in bren.items():
|
| 576 |
+
if rest.startswith(a):
|
| 577 |
+
rest = b + rest[len(a):]
|
| 578 |
+
out[f"dino.blocks.{i}.{rest}"] = v.float().numpy()
|
| 579 |
+
return out
|
4bit/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1e2f7b023f9ce25fac5dd49d7d0e4f90a19c4b11e3919a4e7f79b544f4fdee56
|
| 3 |
+
size 1006876833
|