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)

安装

conda create -n mulres python=3.12 -y && conda activate mulres
pip install -r requirements.txt
# flash-attn 用与 torch/CUDA 匹配的预编译 wheel, 不要从源码构建

使用

# 全部 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 注入的条件点云

评测

# 预测目录需扁平: <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 开边波动更大。