mul / readme.md
MayMeHappy's picture
Upload folder using huggingface_hub
90ca518 verified
|
Raw History Blame Contribute Delete
5.73 kB
# 多分辨率网格生成 · 推理
点云条件下的**多分辨率八叉树网格生成**:低分辨率生成器逐级长出粗网格,高分辨率细分器把它推到 512 格。
## 流程
```
输入 mesh ──采样点云──┐
▼
┌───────── 生成器 (TSSR 三前向离散扩散) ─────────┐
│ 格2 → 格4 → 格8 → 格16 → 格32 → 格64 每级20步 │
│ └补洞┘ └补洞┘ │
└──────────────────────┬─────────────────────────┘
▼
┌────────── 细分器 (acc_uni) ──────────┐
│ 格64 → 格128 → 格256 → 格512 每级20步 │
└──────────────────────────────────────┘
▼
final_res512_plain.obj
```
**生成器**每级把上一级网格重新编码成八叉树 token,用离散扩散预测该级完整子码。
TSSR 解码每步三次前向:mask 预测 → no-mask 精修 → 逐 token 分类器挑可疑位置 re-mask,
避免 MaskGIT 式"一旦揭示即定死"的错误累积。
**细分器**只做细分不做生成,粗输入上的破洞它补不出来——这是 res32/res64 要先补洞再喂下去的原因。
## 目录
```
.
├── scripts/ 入口
│ ├── infer.py 端到端推理
│ ├── eval.py 评测(CD / HD / 法向一致性)
│ └── strip_ckpt.py 权重瘦身: 剥离优化器、合并 EMA
├── models/ 模型
│ ├── generator.py 生成器(骨干 → 双云注入 → TSSR)
│ ├── subdivider.py 细分器
│ └── point_conditioner.py 点云条件编码器
├── modules/ 算子与管线
│ ├── pipeline.py 多级级联主管线
│ ├── attention.py MLA 等注意力原语
│ ├── octree_codec.py 八叉树 tokenizer(numba 加速)
│ ├── octree_codec_acc.py 细分器口径的 tokenizer
│ ├── octree_decode.py 子码 → mesh 解码
│ ├── token_utils.py token 通路
│ └── miche/ Michelangelo 点云编码器(第三方)
├── dataset/ 数据处理与点云采样
├── utils/ 配置、网格工具、补洞、指标
├── configs/ generator.yaml / subdivider.yaml
└── ckpt/ 权重(见 ckpt/README.md)
```
## 安装
```bash
conda create -n mulres python=3.12 -y && conda activate mulres
pip install -r requirements.txt
# flash-attn 用与 torch/CUDA 匹配的预编译 wheel, 不要从源码构建
```
## 使用
```bash
# 全部 mesh
python scripts/infer.py --data /path/to/meshes --out_dir outputs/run1
# 只跑前 20 个
python scripts/infer.py --data /path/to/meshes --out_dir outputs/run1 --ncase 20
# 指定 case(文件名子串, 带尾点防前缀误配: "a." 不匹配 "a1.glb")
python scripts/infer.py --data /path/to/meshes --out_dir outputs/run1 --case "model_a.,model_b."
# 面数太密: 给连接头"空连接"类加 logit 偏置(0.3 约 -25% 面, 保真度几乎不变)
python scripts/infer.py --data /path/to/meshes --out_dir outputs/run1 --empty_bias 0.3
```
每个 case 输出一个子目录:
| 文件 | 说明 |
|---|---|
| `final_res512_plain.obj` | **最终结果** |
| `res{2,4,8,16,32,64}_plain.obj` | 生成器各级产物(补洞后) |
| `*_sr_64to128_depth7.obj` 等 | 细分器各级产物 |
| `gt_original.obj` | 归一化后的原始输入(塌缩前) |
| `gt_original_dec.obj` | 塌缩后的输入(级联起点与条件点云的来源) |
| `gt_res{N}.obj` | 输入经 tokenizer 编解码的天花板, 用于逐级对照 |
| `pc_full.ply` / `pc_target_res{N}.ply` | 注入的条件点云 |
## 评测
```bash
# 预测目录需扁平: <case>_y.obj ; GT 目录: <case>.glb 或 .obj
python scripts/eval.py /path/to/pred_flat --gt /path/to/gt_meshes
```
输出倒角距离(L1/L2)、豪斯多夫距离、法向一致性 |NC| 与 NC。
> 解码不编码面的绕序,有向法向随机,所以看 **|NC|**(约 0.85),`NC (Real)` 接近 0 属预期。
## 参数
`scripts/infer.py` 固化了默认配方,更细的控制用环境变量(定义见 `modules/pipeline.py` 顶部):
| 变量 | 默认 | 说明 |
|---|---|---|
| `STAGE` | `2,4,8,16,32,64` | 生成器级联阶梯(产物真实体素格) |
| `STEPS` | `20` | 生成器每级扩散步数 |
| `SUPERRES_TO` / `SUPERRES_STEPS` | `512` / `20` | 细分终点与每级步数 |
| `FILL` / `FILL_MIN_RES` | `1` / `0` | 级联内补洞; `FILL_MIN_RES=64` 则只在格 64 补 |
| `SR_FILL_IN` / `SUPERRES_FIX_HOLES` | `1` / `1` | 细分入口 / 每级输出补洞 |
| `DECIMATE_RATIO` | `0.5` | 输入预塌缩比(0=不塌缩) |
| `EMPTY_BIAS` | `0` | >0 稀疏化控面数 |
| `CASE_STEM` | — | 文件名子串过滤(在 `NCASE` 截断**之后**生效) |
## 已知行为
- **步数**:20 与 40 步保真度无差别;10 步会让开边 +27%、非流形 +34%。20 是性价比点。
- **补洞是置换不是净赚**:开边 −16% 的代价是非流形 +12%。要纯净拓扑用 `--no_fill`。
- **分辨率终点**:生成器自己走到格 64 比走到格 32 再交给细分器更好(非流形 −59%、CD −6%),
代价是开边变多——细分器会把粗输入的破洞一路放大。
- **GPU 非确定性**:flash-attn / bf16 的归约顺序不固定,同配置重跑面数有约 3% 波动,单 case 开边波动更大。