File size: 4,967 Bytes
9d3385d 62c9d58 9d3385d 62c9d58 9d3385d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | ---
license: other
library_name: flip
tags:
- 3d
- gaussian-splatting
- triposplat
- distillation
- int4
- webgpu
base_model:
- VAST-AI/TripoSplat
---
# flip student · 2 steps · int4
TripoSplat 的扩散模型(DiT)的一个 2 步学生,量化到 int4。
上游用 20 步 Euler + CFG 3 生成 3D 高斯;这个学生用 **2 步、无 CFG** 做同一件事,
T4 上出图从 91–95 秒降到 4.6–5.0 秒(19×),权重从 1.48 GB 压到 209 MB。
**这不是一条完整管线。** 图像编码(DINOv3 + Flux2 VAE)、抠图(BiRefNet)、
解码(octree + Gaussian decoder)都是上游的,不在这里。这个仓库只替换
`ckpts/diffusion_models/triposplat_fp16.safetensors` 这一个文件。
## 文件
| 文件 | 内容 |
|---|---|
| `model.safetensors` | 763 个张量:204 个 int4(U8 成对)+ 204 个 fp16 scale + 355 个 fp16(norm/bias/embedding) |
| `dit.int4.onnx` | 同一个模型,整图 ONNX:203 个 `com.microsoft::MatMulNBits` + 剩下的 fp32 |
| `quantize.json` | 量化语义:4 bit、每 32 权重一个 fp16 scale、对称、zero point 8、沿 K 打包 |
| `config.json` | 结构参数与采样参数 |
## `dit.int4.onnx`
静态形状,输入是编码器的原始输出:
```
latent [1, 8192, 16] 噪声 / 当前状态
camera [1, 1, 5]
feature1 [1, 4101, 1280] DINOv3
feature2 [1, 4096, 128] Flux2 VAE(图内部补 5 个零 token,对齐 4101)
t [1]
-> out_latent [1, 8192, 16], out_camera [1, 1, 5]
```
6265 个节点,294 MB。259 个 MatMul 里 203 个变成了 int4;**剩下的 56 个就是 28 层注意力的
QKᵀ 和 PV**——它们没有权重,量化不到,也不该量化。
**这张图不是最快的路径,是最互通的路径。** 在 ORT-web 1.31.1 / apple metal-3 上实测
(`webgpu/onnx-probe.html`):
| 图 | ORT WebGPU | 我们的 WGSL |
|---|---|---|
| int4 MatMulNBits 1024→3072 @12294 | 789 GFLOP/s | 1591–1796 |
| 注意力,1 头 L=12294(物化) | 406 | 1789 |
| `com.microsoft::Attention` 16 头 | 1023 | 1789 |
| 卷积 3×3 128→128 @128² | 711 | 443 |
也就是说:矩阵乘交给 ORT 是 2.3 倍代价,注意力是 4.4 倍。**想跑进 60 秒,注意力得用
我们自己的核**,靠 `preferredOutputLocation: 'gpu-buffer'` 和 ORT 交接;其余走 ONNX。
卷积反而是 ORT 更快,所以 VAE 就该用 ONNX。
这张图在 CPU 上没有端到端跑过(一次前向 5 分钟,内核撑不住)。int4 的正确性证据是
矩阵乘级别的:fp32 对比 int4,cosine 0.997、rel_l2 0.073。
## 怎么接进上游
```python
from safetensors.torch import load_file
from triposplat import TripoSplatPipeline # VAST-AI/TripoSplat
# 1. 反量化:U8 成对 + fp16 scale -> 权重
# even k 在低四位,odd k 在高四位
w = (packed_to_int8(u8) - 8).float() * scale.repeat_interleave(32, dim=1)
# 2. 装进上游模块,存成 fp16 safetensors
# 3. 采样时:steps=2, shift=1.0, guidance=1.0(无 CFG)
```
`steps=50, shift=3, guidance=7` 是教师的参数,套在学生上会得到一个糊掉的模型。
## 数值(都是实测的)
量化质量,在真实采样状态上比 fp32 与「读回 int4 再反量化」的前向:
| 项 | 值 |
|---|---|
| latent cosine | 0.992 |
| latent rel-l2 | 0.123 |
| camera cosine | 0.999 |
| 密度 | 4.50 bits/weight |
| 体积 | 209,328,746 字节 |
蒸馏效果,同一 seed 与教师 20 步比(3 张 fuliji 图):
| 项 | 学生 2 步 | 教师 20 步 |
|---|---|---|
| 出图耗时(T4) | 4.6–5.0 s | 91–95 s |
| opacity 均值 | 0.48–0.50 | 0.88–0.94 |
| latent cosine vs 教师 | 0.49 / 0.67 / 0.68 | — |
| camera cosine vs 教师 | 0.98 | — |
**诚实的短处**:opacity 掉到教师的一半,scale 偏大(0.0057 对 0.0030)。
肉眼上花纹和形体保住了,边缘略虚。latent 余弦只有 0.49–0.68,但它不是质量指标——
教师自己在 4 步时的 latent 距离更远(0.46–0.61),出图反而更糊。
## 怎么训的
- 教师:TripoSplat 官方权重,20 步 Euler,guidance 3
- 数据:`DownFlow/fuliji` 的 32 张图 + 上游示例图
- 目标:段平均速度 `v* = (x_{k+n} − x_k) / Σdt`。学生 2 步的网格是 `[0, 15, 20]`
(按 σ 等分,每段 Δσ = 0.5),不是按步数均分的 `[0, 10, 20]`
- 训练:16 epoch,Adam,最终 loss 0.0787(camera 0.0213 / latent 0.0776)
2 步学生的上限由教师 20 步的终点决定,与教师 2 步无关——后者带 CFG,不是一个可比的对象。
## 许可
权重由 TripoSplat 蒸馏而来,上游条款见 [VAST-AI/TripoSplat](https://huggingface.co/VAST-AI/TripoSplat)。
此权重仅供研究,不商用。代码在 GPL-3.0 下发布。
## 引用
```bibtex
@software{flip_student_2step,
title = {flip: a distilled, int4 TripoSplat for WebGPU},
year = {2026},
note = {2-step student of the TripoSplat diffusion model}
}
```
|