图像超分辨率任务通常被建模为从低分辨率输入到高分辨率输出的回归问题。以SRCNN、EDSR为代表的模型使用L1或L2损失训练,输出的往往是一个最接近平均结果的图像。这种确定性映射忽略了低分辨率图像天然存在的多解性:同一张模糊的小图可能来自多张不同的高分辨率原图。把超分当作回归问题会丢失高频纹理,导致边缘过于平滑。SRFlow换了一种思路,它把超分辨率建模成条件分布学习问题,借助归一化流和可逆网络,让模型能从同一个低分辨率输入中采样出多张合理的高分辨率图像。下面将从概率建模、可逆结构、训练损失和采样实现展开。

一、概率视角下的超分辨率
传统超分辨率模型的输出是确定的。对于给定的低分辨率输入x,网络只预测一个高分辨率输出y_hat。这种做法的优点在于训练和评估简单,但问题也很突出:低分辨率图像是多个高分辨率图像经过下采样后的共同投影,本质上是一个一对多的问题。若训练集中存在相同低分辨率图对应不同高分辨率纹理的情况,使用L1或L2损失会让模型趋向于输出所有可能高分辨率图的平均,这种平均结果往往缺乏高频细节,看起来非常平滑甚至模糊。
把超分改成条件生成问题后,目标变成学习p(y|x)。GAN类方法通过生成器与判别器的对抗训练来隐式逼近这个分布,能产生较锐利的纹理,但对抗训练不稳定,容易出现模式崩溃。归一化流则提供了一种显式建模概率分布的方式:假设高分辨率图像y和潜变量z之间存在可逆变换,那么p(y|x)可以通过变量替换公式精确计算。训练目标是最大化对数似然,不需要判别器,也不存在模式崩溃问题。
SRFlow正是基于这一思想。它把低分辨率图像作为条件输入到可逆网络中,让潜变量z经过一系列可逆层变换成高分辨率图像y。由于映射是可逆的,给定y可以唯一得到z,反之给定z可以生成一个确定的y。训练完成后,只需要改变z的采样值,就能从同一个低分辨率输入中得到多张不同的高分辨率图像。
二、可逆网络结构拆解
SRFlow的主干由多个flow step堆叠而成。每个flow step通常包含激活归一化、可逆1x1卷积和仿射耦合层。激活归一化类似批归一化,但使用逐通道的缩放和平移参数,在初始化时让每个通道的输出接近零均值和单位方差。可逆1x1卷积用于混合通道信息,它本质是一个正交矩阵,保证行列式容易计算并且可逆。仿射耦合层则是可逆网络的核心,它把输入沿通道分成两部分,一部分保持不变,另一部分通过一个由条件特征驱动的神经网络预测缩放系数和平移量,再对这部分做仿射变换。
条件归一化流与普通归一化流的区别在于,缩放和偏移网络不仅接受当前特征,还接受低分辨率图像编码后的条件向量。低分辨率图先经过一个编码网络提取多尺度特征,这些特征被输入到每一个仿射耦合层的参数预测网络中。这样,从潜变量到高分辨率图像的映射会随着低分辨率内容而变化,实现了条件生成。
下面是一个简化的仿射耦合层实现,展示了前向和逆向计算。前向用于训练时从高分辨率图像计算潜变量以及对数行列式,逆向用于推理时从潜变量生成高分辨率图像。
import torch
import torch.nn as nn
class AffineCoupling(nn.Module):
def __init__(self, dim, cond_dim, hidden=64):
super().__init__()
self.net = nn.Sequential(
nn.Linear(dim // 2 + cond_dim, hidden),
nn.ReLU(),
nn.Linear(hidden, hidden),
nn.ReLU(),
nn.Linear(hidden, dim),
)
def forward(self, x, cond, reverse=False):
a, b = x.chunk(2, dim=1)
params = self.net(torch.cat([a, cond], dim=1))
log_s, t = params.chunk(2, dim=1)
log_s = torch.tanh(log_s)
if reverse:
a = (a - t) * torch.exp(-log_s)
else:
a = a * torch.exp(log_s) + t
return torch.cat([a, b], dim=1), log_s.sum(dim=1)
这段代码中,forward函数在前向模式下将a分量做缩放和平移,同时返回对数行列式。反向模式下则根据相同的缩放和平移参数恢复原始的a分量。由于变换只作用于a分量,而b分量保持不变,整个操作可逆且雅可比矩阵是三角矩阵,行列式就是缩放系数的乘积。多个这样的层叠加后,网络整体仍然可逆。
实际实现中还会加入多尺度结构,在多个分辨率上分别进行处理。低分辨率特征可以通过双线性插值或转置卷积恢复到对应尺度,再作为条件输入。多尺度结构能减少计算量,同时让网络更好地建模不同频率的纹理。
三、训练目标与损失函数
SRFlow的核心训练目标是负对数似然损失。假设潜变量z服从标准正态分布,通过可逆网络将高分辨率图像y映射为z,变量替换公式给出对数密度为log p(y|x)=log p(z)+log|det(dz/dy)|。其中log|det|是所有可逆层对数行列式的累加。训练时最小化负对数似然,等价于最大化条件分布的对数似然。
仅有似然损失有时会产生偏平滑的结果,因为最大似然在数据量有限时倾向于覆盖所有模式的平均,这与回归损失的模糊趋势类似。SRFlow在实际训练中通常会加入内容损失或感知损失,有时也会加入对抗损失作为正则。内容损失约束生成图像与真实高分辨率图像在特征空间的距离,感知损失则使用预训练VGG网络的特征差异。这些辅助损失可以提升生成图像的清晰度和感知质量。
下面的代码展示了如何计算一个简化的负对数似然损失。z是正向传播得到的潜变量,log_det是所有层对数行列式的总和。
def nll_loss(z, log_det):
log_pz = -0.5 * (z * z).sum(dim=1) - 0.5 * z.shape[1] * torch.log(torch.tensor(2 * 3.1415926535))
return -(log_pz + log_det).mean()
训练时还可以对潜变量的方差进行温度缩放。标准正态先验可能让模型过于集中,降低采样多样性。通过调整先验方差,可以在训练和推理阶段控制生成样本的随机程度。温度参数越大,采样时潜变量偏离均值越远,生成图像的差异也越大,但过大会导致纹理失真。
四、采样过程与多样性控制
推理时,SRFlow从标准正态分布中采样潜变量z,然后将z输入到可逆网络的反向路径,配合低分辨率图像的条件特征,逐步解码为高分辨率图像。由于每次采样得到的z不同,生成的高分辨率图像在纹理、边缘走向等高频细节上会有所变化。这个过程与GAN中随机噪声的作用类似,但SRFlow不需要判别器来保证分布匹配,而是通过精确的似然训练来学习条件分布。
为了控制生成结果的多样性,可以引入温度系数T。采样时使用均值为0、方差为T平方的正态分布。当T等于1时,等价于训练时的先验分布;当T小于1时,采样值接近均值,生成图像的差异变小,通常更接近平均结果;当T大于1时,差异增大,纹理更丰富,但可能出现不自然的伪影。实际应用中可以针对不同场景调节T,以在图像质量和多样性之间取得平衡。
temperature = 0.9
z = torch.randn(batch, latent_dim, device=device) * temperature
with torch.no_grad():
sr = model(z, lr_feature, reverse=True)
与GAN类超分方法相比,SRFlow的主要优势在于训练更稳定,不会出现生成器与判别器之间的模式崩溃,同时能够直接计算似然,便于模型选择。它的缺点是计算量较大,因为正向和反向都需要经过全部可逆层,而且参数量通常比同等容量的CNN更大。此外,归一化流要求变换可逆,这在一定程度上限制了网络结构的设计空间。尽管如此,在需要多样化解码、医学成像、图像恢复等对可靠性要求较高的场景中,SRFlow提供了一种有价值的替代方案。
从工程落地角度看,SRFlow适合作为超分辨率任务中的多样性生成模块,也可以与其他恢复网络结合。训练时建议先单独训练似然损失,再逐步加入感知损失或对抗损失进行微调,以避免早期训练不稳定。采样阶段根据实际需求调节温度系数,并通过LPIPS等感知指标评估生成样本之间的多样性,从而选择合适的工作点。