Vison Only的SR——VOSR
VOSR​这篇探索的就是SR作为low-level任务能不能不依赖于text-to-image (T2I) diffusion models2026刚发表。所以这里的VO表示的就是Vision-Only generative framework。视觉语义引导利用预训练的视觉编码器从低分辨率输入中提取丰富的语义特征作为视觉语义条件来指导生成从而避免文本对齐带来的空间粗粒度问题13。面向恢复的引导策略Restoration-Oriented Guidance作者发现标准的“无条件分支”不适合从头训练的恢复模型。因此他们将其替换为“部分条件分支”保留了弱化的低分辨率结构线索锚点让模型在生成时更贴近原始输入从而有效解决语义幻觉问题13。单步蒸馏加速先训练一个多步 VOSR 教师模型然后将其蒸馏为单步学生模型大幅提升推理效率整体结构diffusion都在latent space所以先使用VAE的encoder。low-level structural conditioning和GT的structural conditioning都使用VAE得到对应下图这的蓝色虚线和实线。除了low-level structural conditioning预测velocity的时候同时考虑 high-level visual semantic guidance. semantic guidance由pretrained vision encoder如DINO获得对应下面的橙色虚线。二者是互补的因为在退化很严重的时候结构信息是不够的这时对应的HR同时有多个这就会带来歧义这时得益于semantic guidance完全在视觉域中提取因此有助于进行细粒度的复原。所以下图中粉色的是denoising backbone DITbackbone使用LightningDiT输入有三部分timestep embeddingstructural conditioning因为尺寸一致concate之后作为空间对齐的潜变量条件spatially aligned latent conditioning注入而semantic guidance以通过交叉注意力机制Cross-Attention引入。GT的structural conditioning还需要结合timestep condition进行add noise。这里的加噪声加的是高斯噪声所以VOSR使用的是diffusion的思路而不是flow matching那种线性的。diffusion在超分任务中这意味着它能生成更多样化、更逼真的纹理细节当然难度也更大。add noise负责“分布对齐”与“时序引导”。与LR分支的区别一个是“参考图”用来约束生成结果不要偏离原始图像太远一个是“当前状态”“如何在不同噪声水平下进行去噪”。预测噪声 ϵ —— 早期主流如 DDPM、Stable Diffusion 1.x/2.x预测 x —— 过渡方案如 DALL-E 2、部分 LCM预测 Velocity v —— 现代主流如 SD3、VOSR、Flow Matching模型回答的是“当前这一刻数据应该以多大的速度、朝哪个方向流动”VOSR最后预测的是velocity。训练更稳它相当于给优化目标加了一个动态的常数项让模型在整个去噪过程无论噪声多还是少中的学习难度更加均衡。路径更直在 Flow Matching 的框架下预测 Velocity 就是在学习一条从噪声直达数据的“直线高速公路”。这使得它非常适合做知识蒸馏能够完美支持单步推理一步就能精准地从 LR 潜空间“飞”到 HR 潜空间。VAEVAE是连接latent空间和像素空间的桥梁VOSR-0.5B主打端侧/低显存使用了 SD2.1 的 VAE。亮点参考了 AdcSR 的做法重新训练了一个轻量级的解码器Decoder。这能在几乎不损失解码质量的前提下大幅降低推理时的峰值显存占用。VOSR-1.4B主打极致画质采用了16通道的潜空间 VAE替代了传统的4通道。目的传统的4通道压缩会丢失大量不可逆的信息16通道能保留更多的高频细节从而提升超分效果。if args.ae_type qwen: from models.qwenimage_vae2d import AutoencoderKLQwenImage2D model_ae AutoencoderKLQwenImage2D.from_pretrained(args.ae_path) elif args.ae_type sd2: from diffusers import AutoencoderKL model_ae AutoencoderKL.from_pretrained(args.ae_path, subfoldervae)sd2的话可以使用stable-diffusion-2-1-base文生图Text-to-Image基础模型依然是一个标准的 Latent Diffusion ModelLDM由 VAE变分自编码器、U-Net去噪核心和 Text Encoder文本编码器组成。名字里带“base”是因为它是后续 768 分辨率版本的基础底座。指定subfoldervae意味着代码只会去args.ae_path/vae/这个子目录下寻找 VAE 的配置文件config.json和权重文件如diffusion_pytorch_model.safetensors。VAE变分自编码器的参数量约为83M8300万还可以使用微调之后的VAE相比于原始 VAE这种经过 MSE 微调的 VAE 在解码时能更好地保留人脸细节如睫毛、唇线和复杂的织物纹理同时信噪比PSNR和结构相似性SSIM也有显著提升from diffusers import AutoencoderKL # 直接从 Hugging Face 加载预训练模型 vae_model AutoencoderKL.from_pretrained(stabilityai/sd-vae-ft-mse)因为VAE 已经在大规模图像数据上通过重建目标训练好了VOSR 直接把它当作固定的“图像 ↔ latent”转换器在 VOSR 的训练过程中VAE 的权重是完全冻结Frozen的不参与梯度更新。所以在得到VAE之后model_ae.eval()这样DiT 的训练会简单、稳定得多。lrhr都进入VAE的encoderwith torch.no_grad(): combined torch.cat([lq, hq], dim0) if args.ae_type qwen: combined_latent (unwrapped_model_ae.encode(combined).latent_dist.sample() - latents_mean) * latents_std elif args.ae_type sd2: combined_latent unwrapped_model_ae.encode(combined.to(unwrapped_model_ae.dtype)).latent_dist.sample() * unwrapped_model_ae.config.scaling_factor lq, hq combined_latent.chunk(2, dim0)等价于lq_latent vae.encode(lq) hq_latent vae.encode(hq)不过hq latent还要再添加噪声所以大概结构是这样的LR ──VAE Encoder── LR latent ─────────┐ LR ──DINO──────── semantic features ──┼── DiT HR ──VAE Encoder── HR latent ─加噪─────┘semantic conditionyml中的enc_type控制使用的语义编码器类型。论文中对语义信息的提取VOSR-0.5B使用dinov2bVOSR-1.5B使用dinov2ldef load_dinov2(args, device): if args.enc_type dinov2b: encoder torch.hub.load(facebookresearch/dinov2, dinov2_vitb14) elif args.enc_type dinov2l: encoder torch.hub.load(facebookresearch/dinov2, dinov2_vitl14) elif args.enc_type dinov2g: encoder torch.hub.load(facebookresearch/dinov2, dinov2_vitg14)DINOv2代表这是 DINOv2 系列的自监督模型。ViT-B代表其骨干网络为 Vision Transformer-Base基础版参数量约为86M。14代表 Patch Size图像块大小为14×14像素。特征维度其输出的特征维度为7685。定位在性能与计算效率之间取得了极佳的平衡是大多数实际应用场景中的首选推荐模型也是冻结Frozen状态开启混合精度with torch.no_grad(): with accelerator.autocast(): #开启自动混合精度Auto Mixed Precision。这会让 DINOv2 的前向传播自动使用 float16半精度进行计算 raw_image (0.5*lq 0.5)*255 #在扩散模型的训练中输入图像通常被归一化到了 [-1, 1] 的区间。这里的操作是将 LR 图像从 [-1, 1] 反归一化回 的标准像素值范围。 raw_image_ preprocess_raw_image(raw_image, args) features, x_norm unwrapped_venc.forward_with_features(raw_image_) z [v for k, v in features.items() if k.startswith(layer_)] z[-1] x_norm z [z[i] for i in args.layer_dinov2b_list]按照layer_dinov2b_list挑选中间层的特征。浅层1-4层主要关注边缘、颜色、纹理等低级视觉特征。中层5-8层开始编码部件级信息Part-level和结构特征。深层9-12层整合成全局语义例如“这是一栋楼”、“这是一只猫”。在超分SR任务中模型不仅需要知道“图里是什么全局语义”更需要知道“物体的边缘和纹理长什么样结构特征”。第 8 层恰好处于中层偏深的位置它既保留了足够的局部结构信息又具备了一定的高级语义理解能力是平衡“细节恢复”和“语义引导”的绝佳选择。CLIP通过“图文对齐”学习天生懂语言擅长零样本分类比如直接认出“这是一只狗”但丢失了像素级的细节不适合做分割。DINOv2通过“纯视觉自蒸馏”学习虽然不懂语言但它对图像的局部细节、边缘、纹理、深度等像素级信息的理解达到了极致。图像级对比DINO损失同一张图片经过不同的裁剪、色彩抖动后输入给教师和学生。模型被强制要求将同一张图的不同视角在特征空间中拉近把不同图片的特征推远。局部特征预测iBOT损失教师看完整的图片而学生看的图片会被随机“遮住”一部分Mask。学生需要去预测被遮住部分的特征。这就像老师给学生看一幅画遮住一部分让学生猜从而让模型学会理解图片的局部结构和上下文关系。DIT这部分是训练的核心model是LightningDiT。在vosr.loss_fm中实际接收的是lq_mixedz_tt, z_mixed四个变量_, _, _, lq_mixed, _, _, z_mixed self._prepare_cfg_conditions(B, device, lq, z, cond_strength_aelq) z_t (1 - t_) * hq t_ * eps inp torch.cat([lq_mixed, z_t], dim1) v eps - hq v_current model(inp, t, zz_mixed)z_t是hqencoder之后加噪声的结果因为lq_mixed和z_t维度一样所以可以cat。cat之后在LightningDiT中PatchEmbed将图像 latent 转成空间 token这里使用的是自注意力。时间t也会TimestepEmbedderz_mixed通过交叉注意力注入。交叉就意味着q来自于DIT而kv来自DIVO。训练CUDA_VISIBLE_DEVICES7 torchrun --nproc_per_node1 train_vosr.py --config configs/train_yml/multi_step/VOSR_0.5B_x1.ymlyml中的train_dataset_config指向一个txt文件其中每一行又是一个txt文件内部就是这个数据集的png路径yml中的test_lq_dirtest_gt_dir则是验证集需要crop小一点否则验证的时候会内存不够。yml中有cfg_scale和weak_cond_strength_aelq。但其实cfg_scale不涉及训练因为Velocity 的 Ground Truth也就是代码里的v eps - hq是一个纯粹的数学事实不需要cfg。只是推理和蒸馏训练时会调整教师模型的输出。而weak_cond_strength_aelq会深度参与训练它参数并不是一个固定的超参数而是一个随机采样器随机采样相当于一种高级的“数据增强”让模型见识各种程度的模糊。每当模型处理一个 Batch 时系统就会从设定的范围比如[0.05, 0.25]里随机抽一个值。这个值被用来把 LR 图像向全零灰图方向进行插值生成lq_weak。yml中-c不仅指定了模型同级目录下的json还决定了args的一些参数比如使用ae_type: qwen,enc_type: dinov2l,训练之后在VOSR-main/exp_vosr中得到训练结果。yml的checkpointing_steps控制隔多少次迭代保存结果。每个checkpoint有下面这些文件要占用10G左右custom_checkpoint_0.pkl model_1.safetensors model.safetensors optimizer.bin random_states_0.pkl scheduler.binos.path.join(args.output_dir, args.exp_name)下面还会保存clean_weights先解包在转到cpu上。分布式训练如 DDP、FSDP中模型通常被包装Wrapped过直接保存可能会带上分布式相关的冗余前缀。解包后保存的是纯粹的模型权重。训练数据使用Real-ESRGAN退化得到验证使用LSDIR and RealSR 也使用相同的退化测试集使用ScreenSR通过两次拍摄屏幕得到。CFG条件扩散模型中无分类器引导CFG是一项关键技术。Classifier-free guidance (CFG)是基于Classifier Guidance分类器引导得到的不再需要分类器。Classifier Guidance需要一个额外的、预先训练好的图像分类器比如 ResNet来告诉扩散模型“这张图像不像一只猫”从而引导生成。CFG能在推理阶段显著提升生成图像的清晰度和可控性。如果只用“有条件预测”模型生成的图像虽然符合提示词但往往多样性较差或者细节不够生动。而“无条件预测”生成的图像虽然质量高、多样性好但完全不受控制随机生成。分别推理之后通过一个公式对预测结果进行线性外推​引导强度Guidance Scale​使用CFG就需要让同一个扩散模型同时学会两件事在训练阶段模型会在“全条件分支Fully conditioned branch”和“无条件分支Unconditional branch”之间随机切换。有条件生成看着提示词比如“一只猫”去噪。无条件生成不看任何提示词盲猜去噪。在文生图T2I任务中无条件分支Unconditional branch提供了一个非常自然的参考基准但是对于SR任务还是要多少参考LR结构信息的。所以VOSR 的改进方案作者提出了一种“部分条件分支Partially conditioned branch”来替代传统的无条件分支。在这个分支中模型会移除语义引导同时弱化低分辨率LR的结构引导条件分支则继续使用structural 和 semantic conditions。​语义信息z通过随机掩码动态构建了两种输入状态z_weak和z_noisedz_weak _zero_like(z) #部分条件状态移除语义的 z_weak全零。 z_noised z # 全条件状态使用完整的 z_noised。结构信息lq构建了两种输入状态lq_weak和lq_noisedweak_cond_strength_aelq random.uniform(self.args.weak_cond_strength_aelq_list[0], self.args.weak_cond_strength_aelq_list[1]) lq_weak self.interpolate(lq, torch.zeros_like(lq), weak_cond_strength_aelq, self.interp_type) lq_noised self.interpolate(lq, torch.randn_like(lq), cond_strength_aelq, interp_typesph)注意这里使用了interpolate函数对lq和第二个参数进行插值分为线性插值和球形插值。即便是condition分支也加了噪声不过使用的是高斯噪声并且是球形插值并且强度也和weak分支不一样。lq加噪lq_noised我们实际上是向模型提供了一个“带有不确定性的结构提示”。使用球面插值是因为在深度学习的潜空间Latent Space或归一化图像空间中数据通常分布在多维球面上。最后会把两种状态根据掩码进行动态混合cfg_ratio控制了weak分支的概率。hq在加噪声之后会和lq分支concatmodel的输入有三个concat结果t还有混合之后的结构信息eps torch.randn_like(lq) _, _, _, lq_mixed, _, _, z_mixed self._prepare_cfg_conditions(B, device, lq, z, cond_strength_aelq) z_t (1 - t_) * hq t_ * eps inp torch.cat([lq_mixed, z_t], dim1) v eps - hq。#终点−起点eps−hq作为Velocity 的 GT v_current model(inp, t, zz_mixed) v_error v_current - v loss (v_error ** 2).mean()模型同时预测出弱条件和条件分支的结果然后就进行cfg计算d_cur model(model_inp, model_t, zmodel_venc_fea) if t_cur self.t_end and t_cur self.t_start: d_cur_cond, d_cur_weak d_cur.chunk(2) d_cur d_cur_weak self.cfg_scale * (d_cur_cond - d_cur_weak)self.cfg_scale不同的取值| 0 | 完全采用弱条件预测 | | 0.5 | 条件与弱条件预测各占一半 | | 1 | 完全采用条件预测 | # 此时虽然完全依赖条件分支但是弱条件确实在训练中也起到了对比作用 | 1 | 沿条件方向外推即常见的 CFG 增强 | | 0 | 沿条件方向的反方向外推 | 例如取-0.5d 1.5 * d_weak - 0.5 * d_cond沿精确输入条件的反方向外推相当于LR起到的是排斥而不是吸引在预测得到velocity之后多步推理推理推理的时候LR先被resize到target的尺寸而不是在网络内部做分辨率增加原图 LR - bicubic 放大到 target_w x target_h - VAE encode 成 target 分辨率对应的 latent - DiT/VOSR 在同尺寸 latent 上恢复细节 - VAE decode 回 target 分辨率图像预测的时候​s控制了结果和LR的相似度。当s变大结果更靠近fully conditioned branchLR的约束更强当s变小则partially conditioned branch更重要约束更小为模型留出了更大的合理细节生成空间Allowing a larger space of plausible detail generation从而提升图像的感知质量。Two knobs mainly affect the trade-off between faithfulness to the LR input and generative detail (both can be set via CLI to overrideargs.json):--cfg_scale- Higher values tend to emphasize fidelity to the condition; lower values give more generative freedom. The sweet spot depends on input degradation strength. In our experiments, roughly-0.5to2is a usable range;0.5is a practical default.--weak_cond_strength_aelq- During training this is sampled uniformly in[0.05, 0.25]so the checkpoint supports a wide range at inference via the same flag (smaller - more generative, larger - more faithful). Default0.1.即便训练的时候s使用的是-0.5在推理的时候也可以取0.5或者1得到不用保真度的效果。因为HR加噪声是按照z_t (1 - t_) * hq t_ * eps所以推理的时候t0z_t HQ对应清晰目标t1z_t ε对应纯噪声。如果是 25 step近似序列为1.00 → 0.96 → 0.92 → ... → 0.08 → 0.04 → 0.00multi-step model uses 25 sampling steps512大小需要时间 2.114s, versus 2.751s for PASD, 3.943s for SeeSR, 10.036s for StableSR, and 12.550s for DiT4SR一步的话只需要0.094s。One-Step Distillation通过蒸馏得到一步扩散方法。只改变采样效率sampling efficiency不改变restoration formulationMemory-friendly Design作者研究并对比了两种针对超分任务调整的变体基于捷径Shortcut-based的方法基于递归一致性Recursive-consistency-based的方法这两种方案在基础条件和优化目标上是完全相同的唯一的区别在于用于压缩去噪轨迹的“辅助蒸馏损失auxiliary distillation loss”。经过实验验证基于递归一致性的变体在超分SR任务中表现最好因为它能在“感知质量Perceptual quality即纹理逼真度”和“结构保真度Structural fidelity即不偏离原图”之间取得更好的平衡。学生模型的定义zt当前时间步的带噪潜变量输入。t当前的时间步。r 辅助目标时间这是学生模型需要预测的“目标时间步”。当rtrt时代表局部预测Local prediction即预测当前时间步的去噪方向。当rtrt时代表压缩的跨时间预测Compressed cross-time prediction即学生模型直接一步跨越多个时间步预测未来的状态。这正是实现“单步推理”的关键。κ条件输入为了保持训练接口的一致性学生模型使用和教师模型相同的条件分支。即要么是全条件分支(cstr,csem) 要么是部分条件分支(αcstr,∅) 。拟合目标当然就是学生模型的预测和教师模型接近其中教师模型的输出这里使用的也是cfg的公式但是训练和推理使用的s要区分开来。ω 是训练阶段的超参数用来“调教”出最好的教师模型而 s 是推理阶段的超参数用来让用户“微调”最终的生成效果。两者在数学形式上虽然一样但在工程实践中是完全解耦的。使用的评价指标lpipsLPIPS_v0.1_alex-df73285e.pthLPIPS 会将两张图分别送入预训练网络提取中间层的特征图然后计算这些特征图之间的加权欧氏距离。距离越近说明两幅图在人眼看来越相似musiqmusiq_koniq_ckpt-e95806b9.pthMUSIQMulti-scale Image Quality Transformer是一种前沿的无参考图像质量评估NR-IQA指标MUSIQ 采用基于 Transformer 的架构能够直接处理原始分辨率和任意宽高比的图像无需任何预处理MUSIQ 最终会输出一个通常在0 到 100之间的连续分值分数越高代表图像质量越好区别ODTSR项目VOSRODTSR使用 VAE是是生成初值纯噪声带噪 LQ latentLQ 条件形式通道拼接独立 visual token streamLQ 是否贯穿所有 block已融合成单流作为独立 token 保留Visual-Text 交互无真实文本流joint attention采样25 step1 step