各个文章链接及代码均附在下文中,便于读者参考学习。
一、DRRN摘要
最近,基于卷积神经网络 (CNN) 的模型在单图像超分辨率 (SISR) 方面取得了巨大成功。由于深度网络的优势,这些 CNN 模型学习了从低分辨率输入图像到高分辨率目标图像的有效非线性映射,但代价是需要大量的参数。本文提出了一种非常深的 CNN 模型(多达 52 个卷积层),称为深度递归残差网络 (DRRN),该模型致力于深度而简洁的网络。具体来说,以全局和局部方式采用残差学习,以减轻训练非常深的网络的难度;递归学习用于控制模型参数,同时增加深度。广泛的基准测试表明,DRRN 的性能明显优于 SISR 的最新技术,同时使用的参数要少得多。代码可在 https://github.com/tyshiwo /DRRN CVPR17 获得。
1. 研究背景与问题
CNN在SISR中的成功:摘要开篇指出,基于CNN的模型在单图像超分辨率(SISR)任务中表现优异,因其能够学习从低分辨率(LR)到高分辨率(HR)的复杂非线性映射。
现存问题:传统深度CNN模型(如VDSR、EDSR)需要大量参数,导致计算成本高、内存占用大,难以在资源受限的场景中应用。
2. 核心方法:DRRN的设计
(1) 深度与轻量化的平衡
超深网络(52层):DRRN通过堆叠多达52个卷积层,构建了当时最深的SISR网络之一,旨在通过深度提升性能。
递归学习(Recursive Learning):
参数共享:递归结构重复使用同一组卷积层(如16次递归),显著减少参数量(仅297K,比VDSR减少80%)。
等效深度:通过递归实现深层网络的表达能力,而无需实际增加参数。
(2) 残差学习的双重应用
全局残差(Global Residual):整个网络直接学习LR到HR的残差(高频细节),类似VDSR,缓解梯度消失问题。
局部残差(Local Residual):每个递归块内部引入残差连接,进一步优化训练稳定性(类似ResNet中的残差块)。
3. 技术优势
参数量与性能的权衡:在参数量远少于同期模型(如DRCN、MemNet)的情况下,DRRN在Set5、Set14等基准数据集上达到更高的PSNR/SSIM。
训练效率:双重残差设计(全局+局部)使超深网络(52层)的训练成为可能,避免了梯度爆炸/消失问题。
4. 实验结果与贡献
实验验证:通过大量基准测试(如Urban100对复杂纹理的恢复),DRRN证明了其在参数量减少的同时,性能优于当时的SOTA方法。
5. 关键术语关联
递归(Recursive) ≠ 循环(Recurrent):DRRN的递归是层级参数共享,而非RNN的时间步递归。
残差(Residual):同时借鉴了ResNet(局部残差)和VDSR(全局残差)的思想,形成多层次残差学习。
6. 后续影响与局限
影响:DRRN为轻量化深度超分辨率模型提供了范式,后续工作(如CARN、IDN)进一步结合递归与动态结构。
局限:递归结构可能限制模型灵活性,且52层的等效深度在极端场景(如4×超分)仍可能欠拟合。
总结
DRRN的核心创新在于通过递归结构实现参数高效性,同时结合双重残差学习解决超深网络训练难题。其摘要突出“深度且轻量”的矛盾统一,成为SISR领域轻量化设计的重要里程碑。
二、模型架构分析

1.递归与残差
递归块(Red Dashed Box):
红色虚线框内是一个递归块(recursive block),由两个残差单元(residual units)组成。每个残差单元的结构类似ResNet中的基础单元(绿色虚线框),但通过递归机制实现了更深层的特征提取。
- 残差单元设计:每个单元包含卷积层(浅绿/浅红色)和跳跃连接(⊕),缓解梯度消失问题。
- 权重共享:递归块内对应的卷积层共享权重(如所有浅绿色层共享参数,浅红色层共享参数),显著减少参数量。
递归机制:递归块被多次展开(如图中可能隐含的重复调用),通过同一组参数的多次复用增强模型表达能力,同时避免参数爆炸。这与DRCN(图c)的递归层类似,但DRRN结合了残差连接,优化了梯度流动。
监督输出(Light Blue):最终输出(浅蓝色)通过损失函数直接监督,与VDSR、DRCN等超分辨率网络的端到端训练方式一致。
DRRN的独特优势:结合了ResNet的残差学习和DRCN的递归参数共享,在超分辨率任务中既能训练极深网络,又保持参数高效性。
模型 | 核心结构 | 权重共享 | 关键创新点 |
---|---|---|---|
ResNet | 残差单元(绿色框) | 无 | 跳跃连接解决 深度网络退化问题 |
VDSR | 全局跳跃连接(紫色线) | 无 | 极深网络+全局残差学习 |
DRCN | 递归层( 蓝色框) | 递归层内卷积层共享权重 | 递归结构复用参数 |
DRRN | 递归块(红色框)+ 残差单元 | 递归块内对应卷积层共享 | 残差+递归双重优化 |

图2是文中所描述的DRRN超分架构,代码实现进行了“结构扁平化”处理,将论文中的 RB 模块与递归嵌套展平为一个 for 循环,提高简洁性。原文中还说:没有递归结构时,DRRN 就变成了 VDSR,即图1(b)所示。
2.VDSR
原文链接:CVPR 2016 Open Access Repository
Pytorch开源代码:https://github.com/twtygqyy/pytorch-vdsr
简要模型框架
简要的模型示意图如图1(b)所示,开源代码中先将输入1通道灰度图像转为64通道特征图,然后通过中间18层卷积+ReLU堆叠(残差块),然后将64通道特征图变为1通道图像(输出的是残差图像),最终,将残差图像与原图相加,输出高分辨率图像。
VDSR创新点、优点与不足
创新点:
-
深度网络结构:VDSR采用了非常深的卷积神经网络(18层),这是其创新之一。相比传统的浅层网络,它能够捕获更加复杂的图像细节和特征。
-
残差学习:VDSR通过学习图像的残差(高分辨率图像与低分辨率图像之间的差值),而不是直接预测高分辨率图像。这样可以显著提高训练的稳定性和效果。
-
端到端训练:VDSR直接通过端到端训练,从低分辨率图像学习高分辨率图像,避免了需要手动提取特征等复杂步骤。
优点:
-
性能提升:由于网络较深,能够捕捉更多的细节信息,VDSR在超分辨率任务上相比传统方法(如双线性插值、双三次插值)提供了显著的性能提升。
-
高效性:通过残差学习,VDSR能减少训练过程中的梯度消失问题,提高了网络的收敛速度,训练效果也更好。
-
无需预处理:VDSR是一种端到端的学习方法,省去了传统方法中对图像进行额外预处理和特征提取的步骤。
-
适用于各种尺度:VDSR能够在多种低分辨率尺度上工作,适应性较强。
不足:
-
计算量大:VDSR是一个非常深的网络,需要大量的计算资源,尤其在训练时,可能对硬件要求较高(如显存占用较大)。
-
对数据量的依赖:深度网络往往需要大量的数据进行训练,因此在数据量较少的情况下,模型的泛化能力可能受限。
-
超分辨率限制:尽管VDSR在许多测试中表现优异,但它仍然无法处理极端低分辨率(非常模糊的图像),在某些特定场景下可能无法达到预期效果。
核心代码
import torch
import torch.nn as nn
from math import sqrt
# 定义一个基本的卷积+ReLU模块,是VDSR网络的基本构建单元
class Conv_ReLU_Block(nn.Module):
def __init__(self):
super(Conv_ReLU_Block, self).__init__()
# 定义一个卷积层:输入64通道,输出64通道,卷积核大小3x3,步长1,填充1,保持尺寸不变
self.conv = nn.Conv2d(
in_channels=64,
out_channels=64,
kernel_size=3,
stride=1,
padding=1,
bias=False # 不使用偏置
)
# 定义激活函数 ReLU
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
# 前向传播:先卷积再ReLU激活
return self.relu(self.conv(x))
# 定义VDSR网络结构
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 输入层:将1通道灰度图像转为64通道特征图
self.input = nn.Conv2d(
in_channels=1,
out_channels=64,
kernel_size=3,
stride=1,
padding=1,
bias=False
)
# 中间18层卷积+ReLU堆叠(残差块)
self.residual_layer = self.make_layer(Conv_ReLU_Block, 18)
# 输出层:将64通道特征图变为1通道图像(输出的是残差图像)
self.output = nn.Conv2d(
in_channels=64,
out_channels=1,
kernel_size=3,
stride=1,
padding=1,
bias=False
)
# ReLU激活函数
self.relu = nn.ReLU(inplace=True)
# 权重初始化(He初始化),适合ReLU激活
for m in self.modules():
if isinstance(m, nn.Conv2d):
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(0, sqrt(2. / n))
# 构建多个Conv_ReLU_Block
def make_layer(self, block, num_of_layer):
layers = []
for _ in range(num_of_layer):
layers.append(block())
# 使用Sequential将所有模块打包成一个网络层
return nn.Sequential(*layers)
# 前向传播过程
def forward(self, x):
# 保存原始输入图像,用于后续残差连接
residual = x
# 输入卷积 + ReLU
out = self.relu(self.input(x))
# 中间的18个残差模块
out = self.residual_layer(out)
# 输出卷积,生成残差图像
out = self.output(out)
# 将残差图像与原图相加,输出高分辨率图像
out = torch.add(out, residual)
return out
总结
VDSR通过深度残差网络架构实现了超分辨率的显著提升,尤其在高分辨率恢复方面表现强劲,但其计算需求较大,且在数据量较少或低分辨率图像极端模糊的情况下仍有一定限制。
3.DRCN
原文链接:CVPR 2016 Open Access Repository
pytorch开源代码:https://github.com/fungtion/DRCN

DRCN创新点、优点与不足
创新点
- 深度递归结构:通过递归层(同一卷积层重复使用,权重共享)构建极深的网络(16层),但参数量仅与3层网络相当,解决了传统深度模型参数量爆炸的问题。
- 递归监督与跳跃连接:引入中间监督(Intermediate Supervision),对每个递归输出计算损失,缓解梯度消失;最终通过跳跃连接融合多层特征,提升细节恢复能力。
- 多层级特征融合:采用递归-多路径结构,结合不同递归深度的特征,增强对多尺度信息的利用。
优点
- 参数量高效:权重共享的递归设计大幅减少参数,降低过拟合风险,适合小数据训练(如SR任务)。
- 性能提升:在Set5/Set14等基准上优于SRCNN等早期模型,尤其在纹理细节恢复上表现更好。
- 结构灵活性:递归深度可调,平衡计算成本与性能。
不足
- 训练难度大:递归结构导致梯度传播路径过长,尽管有中间监督,仍易出现梯度不稳定或退化问题。
- 计算效率低:递归需串行计算,难以并行化,推理速度慢于非递归模型(如VDSR、EDSR)。
- 性能局限:后续的残差学习(如EDSR)和注意力机制(如RCAN)进一步提升了性能,DRCN在复杂场景下恢复效果有限。
核心代码
给出的开源代码中并没有显式地使用残差连接,或者原作者的代码只是简单地用了常规的卷积网络结构。如果需要实现残差连接,通常我们会在每个卷积块中加入跳跃连接(skip connections),通过加法操作将输入特征图与经过卷积后的特征图相加。以下是对原文代码降解:
import torch
import torch.nn as nn
class DRCN(nn.Module):
def __init__(self, n_class):
super(DRCN, self).__init__()
# 1. 编码器部分:提取图像特征
self.enc_feat = nn.Sequential()
# 第一层卷积:输入图像1个通道(灰度图),输出100个通道,卷积核大小为5,填充为2保持图像大小,ReLU激活,最大池化降采样
self.enc_feat.add_module('conv1', nn.Conv2d(in_channels=1, out_channels=100, kernel_size=5, padding=2))
self.enc_feat.add_module('relu1', nn.ReLU(True))
self.enc_feat.add_module('pool1', nn.MaxPool2d(kernel_size=2, stride=2))
# 第二层卷积:输入100个通道,输出150个通道,卷积核大小为5,填充为2,ReLU激活,最大池化降采样
self.enc_feat.add_module('conv2', nn.Conv2d(in_channels=100, out_channels=150, kernel_size=5, padding=2))
self.enc_feat.add_module('relu2', nn.ReLU(True))
self.enc_feat.add_module('pool2', nn.MaxPool2d(kernel_size=2, stride=2))
# 第三层卷积:输入150个通道,输出200个通道,卷积核大小为3,填充为1(保持空间尺寸不变),ReLU激活
self.enc_feat.add_module('conv3', nn.Conv2d(in_channels=150, out_channels=200, kernel_size=3, padding=1))
self.enc_feat.add_module('relu3', nn.ReLU(True))
# 2. 编码器的全连接层:将卷积后的特征映射到更高维的空间
self.enc_dense = nn.Sequential()
# Flatten卷积层输出(200通道,8x8特征图)并通过一个全连接层将特征压缩为1024维
self.enc_dense.add_module('fc4', nn.Linear(in_features=200 * 8 * 8, out_features=1024))
self.enc_dense.add_module('relu4', nn.ReLU(True))
# Dropout层,防止过拟合
self.enc_dense.add_module('drop4', nn.Dropout2d())
# 继续通过全连接层压缩到1024维
self.enc_dense.add_module('fc5', nn.Linear(in_features=1024, out_features=1024))
self.enc_dense.add_module('relu5', nn.ReLU(True))
# 3. 预测层:根据编码后的特征预测图像的标签
self.pred = nn.Sequential()
# Dropout层,进一步防止过拟合
self.pred.add_module('dropout6', nn.Dropout2d())
# 分类预测层:通过全连接层输出类别数为n_class的预测结果
self.pred.add_module('predict6', nn.Linear(in_features=1024, out_features=n_class))
# 4. 解码器部分:重建图像
self.rec_dense = nn.Sequential()
# 解码器的全连接层,将1024维特征映射回200 * 8 * 8维度
self.rec_dense.add_module('fc5_', nn.Linear(in_features=1024, out_features=1024))
self.rec_dense.add_module('relu5_', nn.ReLU(True))
# 将1024维特征映射为200 * 8 * 8维度
self.rec_dense.add_module('fc4_', nn.Linear(in_features=1024, out_features=200 * 8 * 8))
self.rec_dense.add_module('relu4_', nn.ReLU(True))
# 解码器的卷积层,逐步恢复图像的空间信息
self.rec_feat = nn.Sequential()
# 第三层反卷积:将200通道恢复为150通道,并使用上采样操作恢复空间尺寸
self.rec_feat.add_module('conv3_', nn.Conv2d(in_channels=200, out_channels=150, kernel_size=3, padding=1))
self.rec_feat.add_module('relu3_', nn.ReLU(True))
self.rec_feat.add_module('pool3_', nn.Upsample(scale_factor=2)) # 上采样操作
# 第二层反卷积:将150通道恢复为100通道,并使用上采样操作恢复空间尺寸
self.rec_feat.add_module('conv2_', nn.Conv2d(in_channels=150, out_channels=100, kernel_size=5, padding=2))
self.rec_feat.add_module('relu2_', nn.ReLU(True))
self.rec_feat.add_module('pool2_', nn.Upsample(scale_factor=2)) # 上采样操作
# 第一层反卷积:将100通道恢复为1通道,输出重建的图像(灰度图)
self.rec_feat.add_module('conv1_', nn.Conv2d(in_channels=100, out_channels=1, kernel_size=5, padding=2))
def forward(self, input_data):
# 编码器部分:通过卷积层提取图像特征
feat = self.enc_feat(input_data)
feat = feat.view(-1, 200 * 8 * 8) # 展平特征图,传递到全连接层
feat_code = self.enc_dense(feat) # 通过全连接层进行特征压缩
# 分类预测:通过全连接层预测图像的标签
pred_label = self.pred(feat_code)
# 解码器部分:将编码后的特征映射回图像空间
feat_encode = self.rec_dense(feat_code) # 解码特征
feat_encode = feat_encode.view(-1, 200, 8, 8) # 恢复图像尺寸
img_rec = self.rec_feat(feat_encode) # 通过解码器生成重建图像
# 返回分类结果和重建图像
return pred_label, img_rec
总结
DRCN通过递归结构和权重共享实现了参数量与深度的平衡,为早期深度超分模型的代表,但其训练复杂性和计算效率限制了实际应用,后续研究更多转向残差和密集连接结构。
4.DRRN
原文链接:CVPR 2017 Open Access Repository
开源代码:https://github.com/tyshiwo/DRRN_CVPR17
pytorch代码:https://github.com/jt827859032/DRRN-pytorch/tree/master
DRRN创新点、优点与不足
📌 创新点
- 递归残差块(Recursive Residual Block):结合递归(权重共享)和残差学习(Residual Learning),构建更深的网络(如25层),但参数仅相当于少量独立残差块。每个递归块重复使用同一组卷积层(类似DRCN),但引入局部残差连接(Block-wise Skip Connection),缓解梯度消失。
- 多层次残差结构:全局残差(Global Residual Learning)直接学习低分辨率(LR)到高分辨率(HR)的映射,加速收敛。局部残差(Local Residual Learning)在递归块内部优化细节,增强高频信息恢复。
- 参数高效性:通过递归共享参数(如1个残差块递归16次),大幅减少参数量(比VDSR少60%),但性能更优。
✅ 优点
- 性能更强:在Set5/Set14等基准上超越DRCN、VDSR等模型,尤其在高倍超分(如×4)中表现更好。
- 训练更稳定:残差结构 + 递归监督缓解了深层网络的梯度问题,比DRCN更易优化。
- 计算成本低:参数共享设计减少内存占用,适合资源受限场景。
❌ 不足
- 推理速度慢:递归结构需串行计算,难以并行化,实时性不如非递归模型(如EDSR)。
- 性能天花板:后续的密集连接(如MemNet)和注意力机制(如RCAN)进一步提升了复原能力,DRRN在复杂纹理上仍有限。
- 调参复杂:递归深度和残差权重的平衡需要精细调整。
🔍 对比DRCN的改进
- 保留递归:延续DRCN的权重共享思想,但用残差块替代普通卷积,提升特征复用效率。
- 强化监督:通过全局+局部残差,隐式实现多层监督,无需显式中间损失(简化训练流程)。
核心代码
文献中的模型框架只是示意图,而开源代码中对于这个DRRN是设置了 25 次递归(示意图中是2次),其他详细解释如下所示,代码设计与文献中的示意图完美贴合:
import torch
import torch.nn as nn
import torch.nn.functional as F
from math import sqrt
# 定义 DRRN 网络结构(Deep Recursive Residual Network)
class DRRN(nn.Module):
def __init__(self):
super(DRRN, self).__init__()
# 第一层:输入图像(1通道灰度图)通过卷积升维到128通道
self.input = nn.Conv2d(
in_channels=1, # 输入通道数为1(灰度图)
out_channels=128, # 卷积后通道变为128
kernel_size=3, # 卷积核大小3×3
stride=1, # 步长为1
padding=1, # 填充为1(保持尺寸不变)
bias=False # 不使用偏置项
)
# 定义递归块中的两个卷积层(会共享参数,每次递归调用相同的 conv1(绿色) 和 conv2(红色))
self.conv1 = nn.Conv2d(128, 128, 3, 1, 1, bias=False)
self.conv2 = nn.Conv2d(128, 128, 3, 1, 1, bias=False)
# 最后一层卷积:将通道从128恢复到1,用于输出图像(对应文献中的最后的灰色卷积层)
self.output = nn.Conv2d(128, 1, 3, 1, 1, bias=False)
# 激活函数:ReLU,使用 inplace 节省显存
self.relu = nn.ReLU(inplace=True)
# 初始化卷积层参数(Kaiming He 初始化方法)
for m in self.modules():
if isinstance(m, nn.Conv2d):
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(0, sqrt(2. / n)) # 均值为0,方差为 2/n
def forward(self, x):
"""
前向传播过程(输入图像 -> 特征提取 -> 多层递归残差块 -> 重建图像)
"""
residual = x # 保留输入图像,用于后面的全局残差连接
# 第一层卷积 + ReLU,提取初始特征
inputs = self.input(self.relu(x))
# 初始化中间变量
out = inputs
# 递归残差学习模块,重复25次,相当于文献中红色虚线框部分(使用相同的 conv1 和 conv2 参数)
for _ in range(25):
temp = self.conv1(self.relu(out)) # 第一个卷积 + ReLU
temp = self.conv2(self.relu(temp)) # 第二个卷积 + ReLU
out = torch.add(temp, inputs) # 局部残差连接(局部输入 + 输出)
# 最后一层卷积 + ReLU,通道数恢复到1,灰色部分
out = self.output(self.relu(out))
# 全局残差连接:输出图像 + 原始输入
out = torch.add(out, residual)
return out
总结
DRRN是递归结构与残差学习的经典结合,平衡了参数效率和性能,但后续模型通过更复杂的连接方式(如密集连接、注意力)进一步超越它。