LoRA微调TRELLIS.2:188双鞋把F-score从0.276拉到0.803
通用 3D 生成模型在处理特定品类时往往细节失真。本文介绍如何通过 LoRA 技术微调 TRELLIS.2,仅针对几何结构阶段进行训练,在保留原有纹理能力的同时,显著提升鞋类等特定物体的生成精度。我们将拆解从数据预处理、适配器注入到训练评估的完整流程,并提供可在 Hugging Face Jobs 或本地 Docker
为什么通用模型搞不定特定物体
3D生成在机器人、仿真、娱乐这些方向用得越来越多,可有个老毛病一直没解决:通用模型很难守住某个领域的硬规矩。拿椅子或鞋来说,生成结果乍一看还行,细看就露馅——鞋底歪了、椅腿不对称。说到底,现有3D表示格式太杂,GLB、PLY文件,还有神经辐射场(NeRF)、3D高斯泼溅(3DGS),各有各的脾气。
TRELLIS系列就是想治这个病。它搞了一套统一的潜在表示(unified latent representation),解码器能把这种内部表示转成你想要的任何3D输出格式。也就是说,不必为每种格式各训一个模型。后来的TRELLIS.2又把3D结构的表示能力往上提了一截,可它骨子里还是个“通才”。真要让它在某个垂直领域(家具、鞋类之类)显得专业,直接拿来用往往不够准。
这次实验的目的很直接:拿Google Scanned Objects (GSO)数据集里的188个鞋类物体去微调TRELLIS.2,看能不能让它生成的鞋底更靠谱。结果是,LoRA微调之后,模型在没见过的测试集上F-score从0.276升到0.803,Chamfer距离也从0.174降到0.033。方法找对了,小数据集照样能让大模型学会“专精”。
TRELLIS.2的工作流水线
动手改代码之前,先得弄明白TRELLIS.2怎么把一张2D图片变成3D模型。整条流水线分五个主要阶段,LoRA适配器要插的地方就在其中。
1. 图像编码
第一步,BiRefNet先把输入图片的背景抠掉。然后DINOv3-L编码器把处理过的图片转成特征tokens。这些tokens相当于指南针,后面的3D生成全靠它们指路。
2. 稀疏结构生成(Sparse Structure Flow)
这里跑的是一个扩散Transformer(DiT),负责预测物体的粗略形状。它吐出大小为16³ × 8的小潜在向量,再由变分自编码器(VAE)解码器变成64 × 64 × 64的占据网格(occupancy grid)。网格里每个体素(voxel)标记该位置是否属于物体。整体轮廓在这一步就定了,所以LoRA适配器加在这里。
3. O-Voxel与结构化潜在变量
O-Voxel是TRELLIS.2的核心3D格式,属于稀疏体素网格,只留物体表面的体素。每个体素存局部几何信息(比如网格顶点)和材质属性。这种格式效率很高:CPU几秒就能把网格转成O-Voxel,GPU反向转换也快。模型只算约10%的非空体素,计算量因此大幅下降。
4. 几何生成(Shape Flow)
到了这一步,Shape Flow DiT拿占据网格和DINOv3特征tokens,生成更精细的潜在变量。另一个VAE解码器再把它转成分辨率高达512 × 512 × 512的O-Voxel几何数据。物体细节形状好不好,关键看这里,所以LoRA适配器同样加在这一阶段。
5. 材质生成与网格创建
最后,Texture Flow DiT依据形状潜在变量和图像特征,生成表面的颜色、金属度、粗糙度和透明度。这一阶段我们没有加LoRA。原因是我们数据集只有漫反射颜色图(diffuse color maps),缺训练所需的独立材质贴图。硬训的话,模型可能把光照效果当成表面属性,甚至出现“灾难性遗忘”,把原本不错的纹理生成能力丢掉。基座模型在颜色和纹理上已经够用,我们干脆冻结它,专心解决形状问题。
为什么要用LoRA?
实验数据集很小,只有188双鞋。这个规模下,全量微调(Full Fine-tuning)不光成本高,还容易把模型原有的通用知识弄坏。LoRA(低秩适应)只训练小型适配器矩阵,原始权重保持冻结,可训练参数量少了,显存需求也降了。
这次实验一共训练了约930万个适配器参数。具体配置是:
- Sparse-Structure Flow DiT:注意力机制和前馈网络(MLP)层用rank 8的适配器。
- Shape Flow DiT:只在注意力层用rank 16的适配器。
适配器矩阵的大小由Rank值决定。Rank越高,适配器能学的东西越多,计算开销也跟着涨。形状控制这种任务比较复杂,Rank稍高一些是必要的。
实战指南:从预处理到训练
为了便于复现,我们准备了两个Docker镜像,一个管预处理,一个管微调。既能在Hugging Face Jobs上跑,也能在本地用Docker跑。
第一步:数据预处理
预处理要做的事有两件:把 GLB 或 OBJ 网格转成 TRELLIS.2 训练用的潜在表示,以及渲染出条件图像。
具体来说,预处理容器会调 Blender,借 xvfb-run 无头跑,给每个物体渲出 16 个视角的图。这些图之后会当训练的条件输入用。另一边,容器还会跑 TRELLIS.2 的预处理流水线,把潜在变量提出来。
下面是放到 Hugging Face Jobs 上跑的示例命令:
export HF_TOKEN=hf_xxx
hf jobs run -d --flavor a100-large --timeout 6h --secrets HF_TOKEN \
cr.hf.co/suvadityamuk/trellis2-finetuning-prep:latest \
trellis2-prep \
--meshes your-username/my-meshes \
--push-to your-username/my-meshes-trellis2 \
--private --holdout 0.05 \
--views 16 --workers 8其中几个参数值得说明:
--flavor a100-large用的是 80GB 显存的 A100 显卡。--holdout 0.05划出 5% 的数据当测试集,这部分不参与训练。--views 16每个物体渲 16 个视角。
188 个物体,整套预处理在 A100 上跑完大概 1 小时。处理好的数据会推到 Hugging Face Hub,训练时直接读就行。
第二步:LoRA 微调
训练容器会载入预先处理好的数据集,按配置文件起训练。模式有两种:ss一种只微调 Sparse-Structure Flow,shape另一种只微调 Shape Flow。
训练命令示例:
# 微调 Sparse-Structure Flow DiT
hf jobs run -d --flavor a100-large --timeout 12h --secrets HF_TOKEN \
cr.hf.co/suvadityamuk/trellis2-finetuning-train:latest \
trellis2-train --config ss \
--latents your-username/my-meshes-trellis2 \
--push-to your-username/my-trellis2-lora \
--run-name ss_lora \
--push-path ss_lora \
--trackio-space your-username/trellis2-trackio
# 微调 Shape Flow DiT
hf jobs run -d --flavor a100-large --timeout 12h --secrets HF_TOKEN \
cr.hf.co/suvadityamuk/trellis2-finetuning-train:latest \
trellis2-train --config shape \
--latents your-username/my-meshes-trellis2 \
--push-to your-username/my-trellis2-lora \
--run-name shape_lora \
--push-path shape_lora \
--trackio-space your-username/trellis2-trackio \
--set max_steps=3000 i_save=500想在自己机器上跑的话,把hf jobs run换成标准的docker run命令,再把对应的卷挂上就行。
训练 pipeline 内部机制
注入适配器
TRELLIS.2 的前向传播是自己写的,标准PeftModel()包装器套不上去。这种情况下我们调的是inject_adapter_in_model()函数,直接把适配器插进模型层级里。为了让数值保持稳定,可训练(trainable)的适配器权重留在 fp32,前向传播则走 bf16 自动混合精度,显存能省下一些。
损失函数与训练循环
目标函数用的是整流流匹配(Rectified Flow Matching),原理跟 Stable Diffusion 3、Flux 这些图像生成模型一致。TRELLIS.2 预训练阶段同样采用这个目标,所以拿来做微调很合适。
训练循环的关键环节如下:
- 采样时间步 t:按配置来,Sparse-Structure Flow 用 logitNormal 分布,Shape Flow 用均匀分布。
- 加噪声:依据时间步 t,把干净数据和随机噪声混在一起。
- 预测速度:模型给出 t × 1000 时刻的速度场。
- 算损失:预测速度和目标速度(也就是数据的导数)之间求均方误差(MSE)。
梯度爆炸要防,所以每次优化器步骤之前先做梯度裁剪。另外还用了梯度累积(gradient accumulation),每 4 个小批次才更新一次权重,等效批大小为 16。
结果评估:鞋底终于像样了
我们在 Sparse-Structure Flow 和 Shape Flow 上各训练了一个适配器。A100 上,Sparse-Structure 花了 7.2 小时,Shape Flow 是 3.6 小时。
训练损失曲线看着是在降,可这并不能直接说明几何质量。真正的检验落在保留下来的那 9 个测试物体(held-out objects)上。
对比下来,基座模型生成的鞋子鞋底常常是扁的或者歪的;经过 LoRA 微调之后,鞋底结构和真实扫描数据对得很准。定量指标也支持这个判断:
- F-score @ 0.02:由 0.276 升到 0.803。这个指标把精确率和召回率合在一起看,越高越好。
- Chamfer Distance:从 0.174 降到 0.033。它量的是生成表面和参考表面之间的距离,越低越好。
- Normal Consistency:由 0.530 涨到 0.804。这一项反映表面法线方向是否一致,越高代表表面越平滑自然。
9 个测试物体上,微调后的模型 F-score 全部明显上升。策略的有效性由此得到验证:把纹理阶段冻住,只专注微调几何结构阶段,数据不足带来的副作用能避开,特定品类的生成质量也能精准提上去。
接下来可以做什么?
这轮实验说明 LoRA 用在 3D 生成模型微调上是行得通的。关键的一条经验是:训练目标要跟问题、跟数据对得上。鞋类这类物体几何结构复杂、纹理却相对标准,微调结构阶段拿到的收益最大。
往后这套做法还能搬到别的 3D 生成模型上,比如 Pixal3D 和 UniLat3D。另一方面,高斯泼溅和世界生成模型(如 HunyuanWorld 2.0 和 NVIDIA Lyra 2.0)也在发展,针对这些新架构怎么设计高效的微调方案,同样是值得摸索的方向。它们的表示形式和训练流水线可能不一样,但“小数据、精微调”这个思路照样能用。
手上如果有特定的 3D 资产数据集,不妨拿这套流程试一下。代码和预训练适配器已经开源,欢迎到社区里交流反馈。