
在 Diffusers 中使用 Scheduled Pseudo-Huber Loss 训练文生图模型原理、调度策略与实战【免费下载链接】diffusers Diffusers: State-of-the-art diffusion models for image, video, and audio generation in PyTorch.项目地址: https://gitcode.com/GitHub_Trending/di/diffusers导读本文介绍 Hugging Face Diffusers 仓库中 research_projects/scheduled_huber_loss_training 这一研究项目它基于论文Scheduled Pseudo-Huber Loss论文编号 2403.16728原始实现为 SPHL-for-stable-diffusion对官方训练脚本进行改造为文生图text-to-image模型的训练引入了对异常样本outliers更鲁棒的损失函数与按时间步timestep调度的损失尺度参数。读完本文你将掌握该研究项目提供的全部脚本、三个核心命令行参数--loss_type、--huber_schedule、--huber_c、三种huber_c调度策略的数学原理与源码级实现以及如何在 DreamBooth 与 LoRA 等典型训练场景中直接复用这套脚本。一、项目定位为文生图训练引入调度式 Pseudo-Huber 损失在标准扩散模型训练中模型通过最小化噪声预测误差来学习去噪。官方脚本默认使用 L2MSE损失而 L2 损失对远离真实值的预测即异常样本产生的超大残差会给予平方级放大的梯度这会让模型被少数异常数据带偏。Scheduled Pseudo-Huber Loss以下简称 SPHL通过一条平滑、有界的损失曲线替代 L2使得大残差对梯度的贡献被钳制在一个可控范围内同时保持小残差附近接近 L2 的精细梯度更进一步它把损失尺度参数huber_c与采样到的扩散时间步t绑定形成随噪声强度变化的调度策略从而在保护模型不被异常样本带偏与保留正常样本的学习信号之间取得平衡。本目录正是 Diffusers 官方对这一思路的实现它没有新造一套训练框架而是以官方 examples/text_to_image 与 examples/dreambooth 脚本为蓝本在其上增加 SPHL 支持。二、为什么值得使用两种典型受益场景README 明确给出了两个适用场景这也是判断何时应该放弃默认 L2的直接依据数据集可能被污染如果你怀疑训练数据集的某一部分已损坏噪声图、错配图文、异常像素等这些离群样本若参与训练会扭曲模型本应输出的内容。SPHL 对离群残差的有界惩罚可以让模型无视这些坏样本的误导。希望提升生成图片的美学质量通过弱化模型受某一类异常图片的过度影响帮助模型更好地解耦disentangle不同概念使输出画面更干净、更符合预期分布。关于该问题更详细的动机讨论可参见官方仓库中的 Issue #7488README 中注明其提供了完整描述本目录所有脚本的--loss_type参数帮助文本也引用了该 Issue。三、脚本布局四种训练任务的 SPHL 化版本该研究项目按任务拆分为两个子目录共 8 个脚本全部是对对应 vanilla 训练脚本的直接改造子目录脚本对应 vanilla 脚本text_to_image/train_text_to_image.pytrain_text_to_image.pytext_to_image/train_text_to_image_lora.pytrain_text_to_image_lora.pytext_to_image/train_text_to_image_sdxl.pytrain_text_to_image_sdxl.pytext_to_image/train_text_to_image_lora_sdxl.pytrain_text_to_image_lora_sdxl.pydreambooth/train_dreambooth.pytrain_dreambooth.pydreambooth/train_dreambooth_lora.pytrain_dreambooth_lora.pydreambooth/train_dreambooth_lora_sdxl.pytrain_dreambooth_lora_sdxl.py从源码结构看SD/SDXL、全参数微调/LoRA、文生图/DreamBooth 这几条常见训练链路都已被覆盖因此本文介绍的核心机制损失函数、参数、调度可以平移到其中任意一个脚本。四、核心实现conditional_loss损失函数逐行拆解SPHL 的全部数学实现收敛在conditional_loss函数中该函数在 train_text_to_image.py 与 train_dreambooth.py 中定义完全一致签名如下def conditional_loss( model_pred: torch.Tensor, # 模型预测的噪声或 v 目标 target: torch.Tensor, # 训练目标真实噪声或速度 reduction: str mean, # mean / sum / none loss_type: str l2, # l2 / huber / smooth_l1 huber_c: float 0.1, # 损失尺度参数使用调度版本时由 timestep 决定 ):它依据loss_type分发到三种损失if loss_type l2: loss F.mse_loss(model_pred, target, reductionreduction) elif loss_type huber: loss 2 * huber_c * (torch.sqrt((model_pred - target) ** 2 huber_c**2) - huber_c) elif loss_type smooth_l1: loss 2 * (torch.sqrt((model_pred - target) ** 2 huber_c**2) - huber_c)三者的关系值得注意l2即官方默认的 MSE当huber_c不被使用时训练循环中会把huber_c固定为 1源码注释为 may be anything, as its not used。huber2 * huber_c * (sqrt(d² huber_c²) - huber_c)其中d model_pred - target。当|d|远小于huber_c时该式近似于d²保留 L2 的精细梯度当|d|远大于huber_c时近似于2 * huber_c * |d|L1 行为梯度有界从而实现小误差细调、大误差钝化。系数2 * huber_c用于归一化使得小残差处的曲率与 L2 一致。smooth_l1与huber共享同一平方根表达式但不乘huber_c系数即2 * (sqrt(d² huber_c²) - huber_c)。它同样具有平滑、有界的大残差行为但整体梯度量级不再受huber_c缩放等于把尺度信息全部交由huber_c的数值本身表达。此外reduction支持mean/sum/none前两者直接调用torch.mean/torch.sumnone用于配合 Min-SNR 逐样本加权详见第七节。若传入未知loss_type函数会抛出NotImplementedError。五、三个核心命令行参数SPHL 功能通过三个命令行参数暴露以 train_dreambooth.py 为例text_to_image 脚本参数一致--loss_type {l2,huber,smooth_l1} # 默认 l2 --huber_schedule {constant,exponential,snr} # 默认 snr --huber_c FLOAT # 默认 0.1--loss_type选择损失函数。l2等价于关闭 SPHL此时其余两个参数无效huber与smooth_l1会激活按时间步调度的huber_c。帮助文本明确写道该参数是否为 timestep-scheduled 的损失以及详细说明参见 Issue #7488。--huber_schedulehuber_c随时间步变化的策略默认snr可选constant不调度、exponential指数衰减、snr按信噪比调度。它是Scheduled一词的落点。--huber_cPseudo-Huber 的尺度参数默认0.1。仅当loss_type为huber或smooth_l1时生效当loss_typel2时该值被忽略。六、三种huber_c调度策略的数学与源码训练循环中huber_c的计算集中在采样时间步之后、前向传播之前train_text_to_image.pydreambooth 脚本同构。源码注释# NOTE: if youre using the scheduled version, huber_c has to depend on the timesteps already明确了关键约束使用调度版本时huber_c必须先由时间步计算得到。三种策略逐段对照1.constant恒定huber_c args.huber_c不做任何调度全程使用用户指定的固定值。此时 SPHL 退化为一个全局鲁棒损失。2.exponential指数衰减alpha -math.log(args.huber_c) / noise_scheduler.config.num_train_timesteps huber_c math.exp(-alpha * timestep)先由huber_c基值反解出衰减率alpha -ln(huber_c) / TT为num_train_timesteps如 1000再按当前时间步t计算huber_c(t) exp(-alpha * t)。由于t越大噪声越强、exp值越小这意味着高噪声大 t时huber_c变小、损失更接近 L1、对大残差更钝感低噪声小 t时huber_c变大、损失更接近 L2、保留细节学习。当t0时huber_c 1当tT时huber_c args.huber_c因此--huber_c在指数策略中实际定义了最大噪声步处的尺度下限。3.snr按信噪比调度默认alphas_cumprod noise_scheduler.alphas_cumprod[timestep] sigmas ((1.0 - alphas_cumprod) / alphas_cumprod) ** 0.5 huber_c (1 - args.huber_c) / (1 sigmas) ** 2 args.huber_c从 DDPM 调度器的alphas_cumprodᾱ_t查表得到当前时间步的信噪比再由σ_t sqrt((1 - ᾱ_t) / ᾱ_t)算出噪声尺度最后映射为huber_c(t) (1 - c) / (1 σ_t)² c。该式在低噪声σ 小时趋近于 1、在高噪声σ 大时趋近于args.huber_c与exponential的趋势一致但尺度变化与扩散过程的实际信噪比直接挂钩理论上更能对齐各时间步去噪难度的真实分布因此被选为默认策略。无论哪种策略huber_c都只依赖单一采样时间步torch.randint(0, num_train_timesteps, (1,))随后通过timesteps.repeat(bsz)广播到整个 batch以保证同 batch 内共享一致的损失尺度而l2分支则直接为每个样本独立采样时间步形状(bsz,)。七、训练循环中的完整集成链路以 text_to_image 脚本为例SPHL 完整接入训练主循环编码与加噪vae.encode(...).latent_dist.sample()得到潜在表示noise torch.randn_like(latents)采样噪声可选--noise_offset与--input_perturbation偏移。时间步采样与huber_c计算如上节所述按loss_type分支采样时间步并计算huber_c。前向与目标构造unet(noisy_latents, timesteps, encoder_hidden_states)得到model_pred目标target根据prediction_type决定——epsilon时取noisev_prediction时取noise_scheduler.get_velocity(latents, noise, timesteps)。损失计算默认直接调用conditional_loss(..., reductionmean)若启用--snr_gammaMin-SNR 加权对应论文 2303.09556则先用reductionnone逐元素计算 SPHL再按 SNR 权重mse_loss_weights逐样本加权并求均值——说明SPHL 与 Min-SNR 加权可以叠加使用v_prediction时权重需加 1 以保持速度目标的最小权重。DreamBooth 先验保持当--with_prior_preservation开启时batch 被torch.chunk(..., 2, dim0)拆成实例样本与先验样本二者分别调用conditional_loss计算prior_loss与实例loss再按prior_loss_weight合并。SPHL 与 DreamBooth 的先验保持机制完全兼容。此外训练细节梯度累积、mixed_precision、EMA、checkpoint 恢复resume_from_checkpoint、accelerate多卡、日志上报等均沿用 vanilla 脚本实现未做改动。八、实战如何运行README 明确说明用法与对应 vanilla Diffusers 脚本完全一致。因此只需在官方脚本的启动命令基础上追加 SPHL 三个参数即可。以标准文生图训练为例数据目录为本地图片文件夹accelerate launch train_text_to_image.py \ --pretrained_model_name_or_path runwayml/stable-diffusion-v1-5 \ --train_data_dir /path/to/images \ --resolution 512 --center_crop --random_flip \ --train_batch_size 1 --gradient_accumulation_steps 4 \ --max_train_steps 15000 \ --learning_rate 1e-05 --lr_scheduler constant \ --output_dir sd-sphl \ --loss_type huber \ --huber_schedule snr \ --huber_c 0.1其中--huber_schedule snr为默认值可省略。若想对比 L2 基线只需把--loss_type改回l2若想验证不同调度策略可分别尝试exponential与constant并用--huber_c调整高噪声端的鲁棒性强度。同样的参数可直接套用到DreamBooth 全参数微调train_dreambooth.py如需先验保持追加--with_prior_preservation --class_data_dir ... --prior_loss_weight 1.0LoRA 微调train_text_to_image_lora.py 与 train_dreambooth_lora.pySDXL 训练train_text_to_image_sdxl.py与train_dreambooth_lora_sdxl.pySDXL 脚本对学习率、resolution1024、文本编码器训练等有自己的默认约定请按其对应 vanilla 脚本的 README 配置其余参数。运行前请确保已安装diffusers、transformers、accelerate、datasets、peftLoRA 需要与bitsandbytes如使用 8-bit Adam等依赖并参照 examples 根目录 的安装说明准备环境。九、使用建议与注意事项何时开启 SPHL正如 README 所强调的它的价值集中在数据集疑似含异常样本与希望概念解耦更干净两类场景对于干净、均衡的数据集L2 仍是官方默认且久经验证的基线建议先跑 L2 基线再对比。huber_c的取值默认0.1通常可作为起点。它既作为恒定策略下的固定尺度也作为两种调度策略下高噪声端的下限取值越小对大残差越钝感、鲁棒性越强但过小也可能削弱高噪声步的学习信号建议小范围网格搜索。调度依赖使用huber/smooth_l1时huber_c必须由当前时间步实时计算源码注释中的硬性约束因此不要试图在训练前预先缓存一个固定huber_c。兼容性边界SPHL 已与 Min-SNR--snr_gamma、DreamBooth 先验保持、LoRA、EMA、混合精度、梯度累积、checkpoint 恢复等机制协同工作--huber_c仅在huber/smooth_l1下生效l2下会被忽略。十、小结Scheduled Pseudo-Huber Loss 研究项目以最小侵入的方式一个conditional_loss函数 三个 CLI 参数为 Diffusers 的文生图训练链路注入了对离群样本鲁棒、且随扩散时间步动态调度的损失机制。其指数衰减与SNR 调度两种策略从不同角度让huber_c与噪声强度联动高噪声步用近似 L1 的钝感损失稳住大局低噪声步用近似 L2 的精细损失雕刻细节。无论是被污染的微调数据集还是追求概念更干净的美学输出这套脚本都可以直接作为你训练实验的起点。【免费下载链接】diffusers Diffusers: State-of-the-art diffusion models for image, video, and audio generation in PyTorch.项目地址: https://gitcode.com/GitHub_Trending/di/diffusers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考