|
Download readme.md from MayMeHappy/mul: direct link, hf CLI and curl.
- Browser
- Download file 5.73 kB
-
https://huggingface.co/MayMeHappy/mul/resolve/main/readme.md
- Command line
-
hf download hf://MayMeHappy/mul/readme.md
-
curl -L -o readme.md https://huggingface.co/MayMeHappy/mul/resolve/main/readme.md
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 开边波动更大。