资讯动态

基于神经网络的压缩感知图像重构:展开网络原理与PyTorch实现

发布时间:2026/9/30 3:34:15 来源:尧图企业网站定制
简介基于神经网络的压缩感知图像重构算法论文PDF刊发于《大连工业大学学报》2020年第6期面向图像处理、压缩感知与深度学习方向的研究人员与研究生。该论文针对传统压缩图像恢复时间长、压缩率高的问题提出基于循环神经网络RNN的重构方案并与全连接网络FCN、卷积神经网络CNN进行系统比较实现128×128单通道图像在2.2%压缩率下的重构。资源共1个PDF文件、8.4MB为期刊正式排版版本包含中英文摘要、引言、理论推导、实验数据与结论等完整章节。目前已有240人浏览学习文中还对比了3个数据集、3种输入维度下的算法性能与单张图像恢复效率并验证了实时处理视频的可行性。读者可借此了解压缩感知与神经网络的结合思路为课程设计、学术论文写作或后续算法研究提供有力参考。1. 基于神经网络的压缩感知图像重构算法把迭代重构变成可训练网络一张 256×256 的灰度图像按传统采样思路要攒够几万次采样才能完整恢复。压缩感知却说只要图像在某个稀疏基下有稀疏表示用远低于奈奎斯特率的随机测量就能重建出来。过去这一步靠 OMP、ISTA、ADMM 这类迭代算法硬撑低采样率下要么画质崩要么耗时高。基于神经网络的压缩感知图像重构算法正是把“测量→稀疏重构”这套流程改造成端到端或展开网络用数据驱动的方式把重构质量和速度同时提上去。这篇笔记拆开讲清楚它的原理、选型、复现路径、参数配置和踩坑点适合做压缩成像、医学 MRI 加速和图像处理方向的同学能照着把方案跑到自己的数据上。2. 为什么要用神经网络重构从压缩感知三要素到展开网络2.1 压缩感知的三要素稀疏基、测量矩阵、重构算法压缩感知的前提是信号在某个变换域下稀疏。设图像 x 长度为 N稀疏基为 Ψ那么 x Ψθ其中 θ 只含少量非零系数。实际测量得到 y Φx ΦΨθy 的长度 M 远小于 NM/N 就是采样率。要能从欠定方程里恢复 x测量矩阵 Φ 得满足非相关性条件也就是 Φ 和 Ψ 不能同时把能量集中到同一组基上。常见做法是用高斯随机矩阵、伯努利随机矩阵或者部分傅里叶矩阵前两者在软件仿真里最省事。重构过程可以写成一个稀疏优化问题min ||θ||₀约束 y ΦΨθ。这里有个工程细节直接解 L0 是 NP 难问题实际使用 L1 松弛也就是基追踪另一种更接地气的方式是迭代阈值算法 ISTA每一步先沿测量残差方向走一小步再做软阈值收缩。传统算法的问题在于迭代次数和步长、阈值参数都靠经验调收敛慢如果图像本身不够稀疏重构结果会出现大片伪影。2.2 两类神经网络路线端到端黑匣子与模型展开基于神经网络的方案大体分两条路。第一条是端到端黑匣子把测量值 y 输入一个卷积神经网络直接输出重构图像 x̂。这类网络用大量训练数据拟合映射 y→x在采样率较高时表现不错但神经网络只在训练数据分布内有效换一个测量矩阵就得重训。第二条是模型展开把 ISTA 或 ADMM 的迭代过程按固定步数展开成网络层每一层里用可学习参数代替原算法的步长和阈值再用一个小的神经网络代替手工设计的稀疏变换或近端算子。我用一个简单对比来说明两者的差别对比项端到端黑匣子展开网络ISTA-Net 风格可解释性低看不见物理过程高每一层对应一次迭代数据量要求大容易学到数据偏置较小物理模型约束了搜索空间测量矩阵更换通常要重训可复用网络只改测量算子层重构边界条件网络自己学可能失真每层有数据一致性约束更可靠展开网络本质上是把稳定的迭代算法映射成前馈神经网络每一层做的事和多次迭代一一对应所以初值、层数、激活函数都有明确物理含义调试起来有抓手不像纯黑匣子只能靠试。2.3 展开网络为什么更适合图像重构数据一致性是保命项图像重构和普通图像增强不同我们手里握着一组原始测量数据 y任何重构结果必须在不违背 y 的前提下补细节。端到端网络容易把“看不清楚”的地方自由发挥结果可能很平滑但和真实测量对不上。展开网络每一层里都有一个数据一致性操作先计算 Φx_k − y 的测量残差再沿梯度方向修正 x_k然后才进入近端映射或去噪网络。这一步保证了网络输出不会偏离已知测量。这也是我在实际项目里坚持用展开网络的原因。训练不充分时端到端网络会编造纹理而展开网络至少能把残差压低视觉上不一定完美但不会离谱。接下来的复现步骤就以 ISTA 展开为例代码可以直接跑在自己的图像数据上。3. 最小实现用 PyTorch 复现一个 ISTA 展开重构网络3.1 准备测量矩阵与压缩感知采样整个流程的第一步是构造测量矩阵 Φ。我这里把图像切割成固定大小的 patch方便模拟压缩采样也方便直接做矩阵乘法。要注意 Φ 的归一化后面训练发不发散就看这一步了。import torch import torch.nn as nn def build_measurement_matrix(patch_len, m, seed0): # patch_len 是图像展平后的长度m 是测量数 g torch.Generator().manual_seed(seed) Phi torch.randn(m, patch_len, generatorg) # 关键按行做归一化避免采样后能量被放大 Phi Phi / (patch_len ** 0.5) return Phi def compress(x_patch, Phi): # x_patch: (B, N)Phi: (M, N)输出 (B, M) return x_patch Phi.t()这里用高斯随机测量矩阵是经验选择它在理论上和大多数稀疏基相关性低。除以 patch_len 的平方根是为了让 Φ 的行向量模长接近 1这样 y 的数值范围和 x 基本一致。测量矩阵生成后固定下来网络训练好以后换实测数据时测量算子必须和前端硬件完全一致否则重构结果没法看。3.2 定义展开网络的单层结构ISTA 展开网络的一层由两个部分组成先做梯度下降再做近端映射。这里的关键是近端映射不采用软阈值而是用一个小型卷积网络去学习因为自然图像的结构比稀疏系数复杂得多。class ISTALayer(nn.Module): def __init__(self, side_len): super().__init__() self.side_len side_len # 步长 alpha 作为可学习参数初始值取 0.1 更稳 self.alpha nn.Parameter(torch.tensor(0.1)) # 近端映射用两层卷积充当可学习的稀疏变换 self.prox nn.Sequential( nn.Conv2d(1, 32, 3, padding1), nn.ReLU(), nn.Conv2d(32, 1, 3, padding1), ) def forward(self, x, y, Phi, PhiT): # 数据一致性梯度项PhiT (Phi x - y) grad PhiT (Phi x - y) x x - self.alpha.reshape(1, 1, 1, 1) * grad.reshape_as(x) # 将向量恢复成二维图像送入卷积近端映射 x_img x.view(-1, 1, self.side_len, self.side_len) x_img self.prox(x_img) return x_img.view(-1, self.side_len * self.side_len)参数说明alpha 初始值取 0.1 是经验选择太大的步长会让训练早期梯度异常prox 网络只负责学习图像先验并不直接输出最终图像它修正的是梯度下降后可能偏离自然图像空间的中间结果。每个 ISTALayer 里包含一次测量残差修正网络有多少层就对应多少轮原始迭代。3.3 组装多层网络并写训练循环多层展开就是把多个 ISTALayer 串起来。第一层的输入用 Φ^T y 初始化这是最小二乘意义上的初始解比零向量收敛快得多也符合传统 ISTA 的做法。class ISTANet(nn.Module): def __init__(self, Phi, side_len, K6): super().__init__() self.Phi Phi self.PhiT Phi.t() self.side_len side_len self.layers nn.ModuleList( [ISTALayer(side_len) for _ in range(K)] ) def forward(self, y): # 用伪逆风格的初始化而不是全零 x self.PhiT y for layer in self.layers: x layer(x, y, self.Phi, self.PhiT) return x训练时建议每个 epoch 重新生成一次测量矩阵否则网络会记住固定的 Φ测试换一组测量数据就翻车。下面的训练循环是完整骨架from torch.optim import Adam from torch.nn import MSELoss def train_net(model, dataloader, epochs40, lr1e-3): optimizer Adam(model.parameters(), lrlr) criterion MSELoss() for epoch in range(epochs): # 每个 epoch 重新生成测量矩阵增强泛化 Phi build_measurement_matrix(N, M, seedepoch) for x_batch, _ in dataloader: x_vec x_batch.view(x_batch.size(0), -1) y compress(x_vec, Phi) # 加入轻微噪声模拟真实传感器噪声 y y torch.randn_like(y) * 0.01 pred model(y) loss criterion(pred, x_vec) optimizer.zero_grad() loss.backward() optimizer.step()train_net 里有两个容易忽略的点。一是为什么每个 epoch 都换 Phi现实中测量矩阵一旦固定网络要学习的是“该矩阵下的逆映射”这会导致在其他矩阵上表现急降随机更换测量矩阵相当于做了数据增强。二是噪声项 0.01 的来历真实传感器读数永远带噪声训练时完全无噪声会让网络对误差极敏感推理时只见一点扰动就会出现条纹。4. 关键参数与评估指标采样率、层数、损失函数怎么配4.1 采样率与测量矩阵设计采样率 M/N 决定信息量也决定重构上限。常用配置是 0.1、0.25、0.5低于 0.05 时绝大多数算法都难有可用结果。测量矩阵的类型也要注意测量矩阵适用场景注意点高斯随机阵通用仿真列之间近似正交归一化后直接用伯努利随机阵硬件实现友好只有 ±1量化误差小部分傅里叶阵MRI、雷达数据是复数网络第一层要拆成实部虚部处理需要记住一个结论网络训练时的测量矩阵要和实际系统一致。仿真里“随机生成一次”和“每次都换”都要出现在同一套流程里最终部署时如果测量矩阵是固定的应该把该矩阵重新微调模型而不是直接套用随机矩阵训练出来的权重。4.2 网络层数与损失函数权重展开层数 K 是首要权衡参数。我用的默认值是 K63 到 9 层我都试过层数太少时重构细节不足层数太多时内存占用大训练耗时变长而且反向传播的梯度经过多层测量矩阵乘法后容易衰减。如果你发现增加层数但指标不涨先去看每层输出的残差范数大概率是后层网络学成了恒等映射这时就得把层间加残差连接。损失函数方面纯 MSE 会让图像偏平滑推荐同时加上 L1 损失提升边缘锐度。为了可复现我会维护一个 0.5 * MSE 0.5 * L1 的组合这里的权重不是玄学MSE 主导整体结构L1 拉回高频细节两者均衡能得到视觉和数值都不错的结果。如果有可用的 VGG 网络视觉质量的提升会更明显但训练时间会翻倍。4.3 PSNR 与 SSIM 的正确测量方式评估重构算法不能只看一张图的主观效果。我习惯计算全局 PSNR 和 SSIM但有一点经常坑到人计算 PSNR 前必须确认像素范围一致。很多公开数据集是 0-255模型却把输入归一化到 0-1如果忘记把预测值乘回 255PSNR 会被高估。from skimage.metrics import structural_similarity as ssim def calc_metrics(pred, gt, pixel_max1.0): pred torch.clamp(pred, 0, pixel_max) gt torch.clamp(gt, 0, pixel_max) mse torch.mean((pred - gt) ** 2) psnr 10 * torch.log10(pixel_max ** 2 / mse) pred_np pred.squeeze().cpu().numpy() gt_np gt.squeeze().cpu().numpy() ssim_val ssim(gt_np, pred_np, data_rangepixel_max) return psnr.item(), ssim_val评估时至少用十个以上测试样本取平均值单张图的 PSNR 波动能超过 1dB。特别注意 SSIM 的 data_range 参数要和你归一化范围对齐否则指标完全失真。从项目经验来看PSNR 高 0.5dB 看起来不明显但它能客观反映重构质量。5. 避坑与常见问题训练发散、棋盘格、泛化差5.1 训练到一半 loss 变成 NaN现象训练几十个 batch 后 loss 突然变成 NaN查看中间变量发现测量矩阵和图像向量乘积出现超大数值。原因测量矩阵没归一化导致 y 的数值范围远超网络权重范围初始步长 alpha 设置过大梯度下降一步就越界还有一个隐藏问题训练时用了 BatchNorm 且 batch size 极小统计量波动剧烈。解决测量矩阵按 patch_len 的平方根归一化alpha 初始值从 0.1 往下调把 BatchNorm 换成 InstanceNorm 或者干脆去掉。训练循环里加一行torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)能有效防止梯度爆炸。如果一开始就 NaN优先检查 Phi 的数值范围让 y 的均值方差和 x 接近再训练。5.2 重构图像出现棋盘格或块状伪影现象PSNR 指标不低但输出图纹理像国际象棋棋盘边缘有周期性明暗条纹。原因近端映射网络里如果用了转置卷积或反卷积做上采样会产生棋盘格效应另外把图像切成独立 patch 训练测试时 patch 之间没有重叠恢复结果会在边界处跳变。解决上采样改用 PixelShuffle 操作把通道数调整后再重排像素patch 训练时让相邻 patch 重叠至少 8 像素测试时对重叠区域取平均。如果是 patch 独立预测不要直接拼图先利用重叠补偿再做一次高斯平滑。5.3 换一组数据或换测量矩阵后效果猛降现象训练集上重构接近完美验证集 PSNR 暴跌 3dB 以上同一个网络换一套测量矩阵输出出现随机噪声。原因训练时固定了单一测量矩阵网络变相记住了该矩阵的伪逆本质是过拟合到了特定测量算子。数据分布窄也是因素如果训练集只包含建筑类图像来一组自然风景自然会崩。解决训练过程里每 epoch 随机生成测量矩阵并为 y 加上 0.01 量级噪声数据增强至少做随机翻转和旋转。如果实际系统的测量矩阵真的固定那就把训练和测试矩阵保持一致但要留一部分数据做交叉验证避免评估自欺欺人。5.4 PSNR 高但视觉模糊纹理细节丢失现象重构图像整体轮廓正确但质感很肉像加了模糊滤镜。原因MSE 损失对每个像素误差平方求和优化时更倾向平均掉高频细节因为边缘误差换来的是大梯度惩罚平滑处理反而让损失更低。这是纯像素损失的通病。解决损失换成 0.5 * MSE 0.5 * L1L1 对边缘的梯度传播更友好能力允许的话加一个感知损失项用预训练网络的中间特征比较预测和真值。注意感知损失的权重不要超过 0.1否则颜色会偏移。这个坑在低采样率下尤其明显采样率 0.1 时每张图都需要看一眼纹理而不是只看指标。5.5 低采样率下重构完全失败现象将采样率压到 0.05 以下输出几乎全是噪声和光斑。原因测量量太少Φ 和 Ψ 的受限等距常数变差理论可重构条件已经不满足此时再深的网络也没有足够信息恢复图像属于物理瓶颈而不是算法缺陷。解决先从数据侧检查稀疏基是否匹配如果图像在 DCT 域稀疏却选了个小波基重构效率会大打折扣。再把网络层数从 6 加到 9 或 10去噪器容量也可以增大但不要期待突破采样率下限。我的建议是低于 0.05 就回到系统设计层想办法增加测量时间或换传感方式比调网络参数更实际。6. 进阶用法把网络当先验接到 ADMM 里换测量矩阵不用重训训练好的展开网络有一个很实用的进阶玩法把它当成图像先验插入到即插即用 ADMMPP-ADMM框架里。这样测量矩阵改变时网络主体不用重新训练只换外层求解逻辑。做法是保留去噪模块在 ADMM 迭代里交替执行数据一致性子问题和去噪子问题。def panp_admm(y, Phi, denoiser, iter_num20): PhiT Phi.t() x PhiT y z x.clone() u torch.zeros_like(x) rho 0.05 for _ in range(iter_num): # 数据一致性子问题最小化 ||Phi x - y||^2 rho||x - (z - u)||^2 x solve_linear_least_squares(Phi, y, z - u, rho) # 去噪子问题用训练好的近端网络做正则化 z denoiser(x u) u u (x - z) return z这个写法有个前提solve_linear_least_squares 要真正解线性方程不能只做一步梯度下降。常见做法是用共轭梯度法迭代 10 次即可。好处很明显训练好的卷积去噪器变成通用正则项换一套部分傅里叶测量矩阵只要更新 Phi就能复用。我在做 MRI 模拟数据时常用这个方案省去了每换一个采样轨迹就重训一遍网络的痛苦。我自己落地的习惯是先写一行单元测试验证数据一致性子问题的残差在迭代前几步就能降到 1e-3 量级再去调网络结构这个顺序能省掉一半调参时间。重构算法的坑大部分不在网络代码而是在测量算子、归一化和评估口径上把这些校准了剩下的层数和损失权重都只是锦上添花。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑