简介稀疏表示主题的MATLAB实现包面向信号处理、机器学习方向的学生与研究者以及希望把稀疏编码理论落到代码中的开发者可用于理解用少量非零原子组合表达信号、揭示数据内在结构的基本思路。压缩包为rar格式共6个文件均为m脚本整体约4KB体量轻便内容围绕主流程脚本、主成分分析、L1范数约束求解、样本读取、准确率计算与预处理等环节组织便于按模块阅读和调试。已有6567人学习下载说明其在稀疏表示入门与代码复现方面具有一定参考价值。材料涉及LASSO、BPDN等稀疏优化问题以及字典学习与K-SVD迭代思想并延伸到图像去噪、压缩感知重建等典型应用读者可据此搭建实验框架对照算法步骤理解稀疏编码、字典更新与结果评估的实现细节也可作为课程作业或科研预研的代码底稿。1. 稀疏表示到底在解什么问题一个 8×8 图像块为什么只用 5 个原子就能拼回来稀疏表示这个词第一次进入视野时场景很朴素一个 8×8 的图像块有 64 个自由度却只用字典里挑出的 5 个原子的加权和就重建到肉眼几乎看不出差别。核心假设只有一句——信号在某个过完备字典下可以用极少数原子的线性组合逼近工程上就是求解min ||x||_0 s.t. ||Dx − y||₂ ≤ ε。它能解决的问题很具体强噪声下的图像去噪、传感器丢点后的像素补全、采样率不足时的重建、特征降维前的字典学习。适合谁做图像处理、压缩感知、稀疏编码方向手里有 MATLAB并且愿意把矩阵拆开看每一步在做什么的人。2. 字典怎么来DCT 过完备字典与 K-SVD 训练的最小可跑实现稀疏表示里有条明确的分界线字典是固定的还是学出来的决定了你后面所有参数怎么调。固定字典不用训练、随时可用、可解释学习型字典更贴合数据但多了训练集构造、迭代次数、初始化三个新变量。两者我都用选择标准大概是这样数据量小于几千块、或者只是先验证思路直接用 DCT 过完备字典样本上万块、并且知道数据有固定纹理结构再上 K-SVD。2.1 过完备字典为什么能稀疏正交基给不了的自由度正交基DCT、小波的列数等于行数M N任何信号只有唯一一组系数稀疏与否全看运气——一个只含两条竖边的块在 DCT 域里系数会铺开一大片。把字典做成 M×N 且 N M方程组欠定解有无穷多个才有可能从中挑出系数最稀疏的那一个。这就是稀疏表示的全部出发点表达方式变多而不是让信号变小。代价是相干性。定义mu max_{i≠j} |dᵢᵀdⱼ| / (||dᵢ||·||dⱼ||)mu 越大两个原子越像OMP 这类贪心算法越容易选错支撑集。我踩过的经验区间大致是mu 0.3 时 OMP 一般能收敛到合理支撑0.30.6 之间要降 K、加正则或者换 LASSO超过 0.7 还硬用 OMP现象就是反复选同一批原子、重建出块状伪影。字典冗余度 N/M 一般取 24再往上稀疏度的收益递减而相干性和内存开销是线性上涨的。所以「字典越大越好」是个错觉冗余度 4 之后我基本不再往上加。另一个常被忽略的点是字典的列必须归一化。稀疏惩罚的是系数幅值不是原子的能量如果一个原子的范数是另一个的 3 倍OMP 的内积排序就会系统性地偏向它跟真正的相关性无关。这一步漏掉后面所有调参都是在错误的基础上做的。2.2 用二十行 MATLAB 构造一个 DCT 过完备字典先上构造代码。这里用 DCT-II 基在频域上复制 R 份、每份加不同偏移的方式构造冗余字典简单、可复现不依赖任何工具箱。function [D, mu] dct_dict(M, R) % 生成 M x (R*M) 的过完备 DCT 字典 % M : 原子长度8x8 的 patch 就是 64 % R : 冗余度倍数常用 2~4 % D : 列归一化的字典 % mu: 相干性指标越接近 0 越好 N R * M; D zeros(M, N); for r 0:R-1 for k 0:M-1 col r*M k 1; basis cos(pi * k * (0:M-1) / M); % DCT-II 的一列 if k 0 basis basis / sqrt(2); % DC 分量归一化 end D(:, col) basis; end end D D ./ sqrt(sum(D.^2, 1)); % 列归一化必须做 G abs(D * D); % Gram 矩阵 G(1:size(G,1)1:end) 0; % 去对角线 mu max(G(:)); end逻辑说明外层r控制冗余副本内层k遍历频点cos(pi*k*(0:M-1)/M)就是 M 点 DCT-II 的第 k 个基向量。k 0时基向量是常数向量除以sqrt(2)保证归一化后能量一致。最后一行算的是最大非对角相关系数也就是前面说的 mu后面调参时会反复用到它。参数怎么改M跟 patch 尺寸绑定8×8 就是 6416×16 是 256后者对细节的拟合更好但求解慢一个数量级R建议从 2 起步先跑通再试 4。用sqrt(sum(D.^2,1))而非vecnorm是为了兼容没有该函数的 MATLAB 版本两者等价。构造完别急着用先做一次合成验证随机造一个 K-稀疏的系数向量乘出观测再用 OMP 反解看支撑集命中率和相对误差。这一步花 30 秒能省掉后面两小时的排查。M 64; R 4; K 6; [D, mu] dct_dict(M, R); N size(D, 2); x0 zeros(N, 1); supp randperm(N, K); x0(supp) randn(K, 1); y D * x0; % 无噪合成观测 [xh, sh] omp_solve(D, y, K, 1e-8); fprintf(mu%.3f 命中 %d/%d 相对误差 %.2e\n, ... mu, numel(intersect(sh, supp)), K, norm(D*xh - y)/norm(y));如果命中率不是满分先别怀疑算法八成是字典没归一化或者 K 设得比真实稀疏度小。相对误差应当落在 1e-12 量级无噪、K 准确的前提下做不到就说明支撑集错了。2.3 K-SVD 训练字典训练块怎么切、迭代怎么停DCT 字典的问题是跟数据无关。医疗影像的纹理和工业表面缺陷的纹理完全不同拿同一个 DCT 字典去逼近稀疏度会明显变差。K-SVD 的思路是交替优化固定字典做稀疏编码再逐个原子更新用残差的 SVD 第一主成分替换原子同时更新对应系数。这套流程没有随机性结果可复现。训练集的构造比算法本身更容易出事。我一般这么做从训练图上以步长 1 抽 8×8 块每块减去自身均值这个均值单独存下来重建时加回去再除以所有块的全局标准差。千万注意是「全局」而不是「逐块」——逐块除以自身标准差等于把噪声块放大成边缘块训练出来的字典全是噪声结构。块数控制在 2 万到 5 万之间太少字典过拟合训练图太多训练时间线性上涨但收益很小。function [D, X] ksvd_train(Y, K, nIter, D0) % Y : M x P 训练样本每列一个 patch已去均值、已按全局 std 缩放 % K : 每列编码的稀疏度 % nIter: 外层迭代次数10~15 足够 % D0 : 初始字典建议用 dct_dict(M, 2) [M, P] size(Y); if nargin 4 || isempty(D0) D0 dct_dict(M, 2); end D D0; X zeros(size(D, 2), P); for it 1:nIter % ---- 1) 稀疏编码固定 D逐列求稀疏系数 ---- for p 1:P X(:, p) omp_solve(D, Y(:, p), K, 1e-6); end % ---- 2) 字典更新逐原子重估 ---- for j 1:size(D, 2) idx find(X(j, :) ~ 0); % 用到第 j 个原子的样本 if isempty(idx), continue; end Ej Y(:, idx) - D * X(:, idx) ... D(:, j) * X(j, idx); % 剔除第 j 个原子的贡献 [U, S, V] svd(Ej, econ); D(:, j) U(:, 1); % 新原子自动单位范数 X(j, idx) S(1,1) * V(:, 1); % 同步更新对应系数 end fprintf(iter %d, 平均非零系数 %.2f\n, it, mean(sum(X ~ 0, 1))); end end逻辑说明第 2 步的Ej是关键它把当前原子对残差的贡献减掉剩下的残差矩阵做 SVD第一左奇异向量作为新原子第一奇异值乘第一右奇异向量作为新系数。这样每更新一次原子重建误差单调不增。注意D(:, j) U(:, 1)天然满足单位范数所以不需要额外归一化——这也反过来说明只要初始字典归一化了后续永远保持归一化。参数怎么改K取 488×8 块的经验值nIter1015超过 15 之后平均非零系数和重建误差基本不动D0一定用 DCT 初始化随机初始化的 K-SVD 收敛慢且容易退化到只用少数几个原子。P超过 5 万时把内层for换成parfor需要并行工具箱加速比大概 46 倍。参数建议取值影响M原子长度648×8越大细节越好求解复杂度 M²NN字典大小2M4M越大越稀疏相干性同步升高K稀疏度48过小欠拟合过大开始拟合噪声nIter1015超过后收益迅速衰减P训练块数2e45e4影响泛化不线性提升3. OMP 还是 LASSO两条求解路线的 MATLAB 手写实现与选型字典搭好之后问题变成「给定 D 和 y怎么把 x 求出来」。0-范数最小化是 NP 难工程上只有两条路贪心OMP、CoSaMP和凸松弛LASSO、基追踪。前者快、无参数、支撑集明确后者慢一点但噪声下表现好得多。选错的代价很直接——用 OMP 去处理 SNR 低于 20 dB 的场景重建结果会随噪声抖得一塌糊涂。3.1 把 OMP 主循环拆成四步内积选原子、最小二乘重估、残差更新OMP 的每一步都能手算这是它最大的好处出错时你可以把中间量打印出来逐位核对不像深度学习方法那样只能当黑匣子看。function [x, supp] omp_solve(D, y, K, tol) % 正交匹配追踪OMP % D : M x N 字典约定每列已归一化 % y : M x 1 观测 % K : 最大稀疏度 % tol : 残差 2-范数阈值达到即提前退出 % x : N x 1 稀疏系数 % supp: 被选中的原子下标按选择顺序 [M, N] size(D); x zeros(N, 1); r y; % 初始残差 观测本身 supp zeros(K, 1); a []; for k 1:K c abs(D * r); % 1) 残差与全部原子的内积 if k 1 c(supp(1:k-1)) -inf; % 已选原子不重复入选 end [~, idx] max(c); % 2) 相关性最大的原子 supp(k) idx; a D(:, supp(1:k)) \ y; % 3) 在支撑集上做最小二乘重估 r y - D(:, supp(1:k)) * a; % 4) 更新残差 if norm(r) tol break; end end supp supp(supp 0); x(supp) a; end逻辑说明第 1 步的内积衡量残差与每个原子的相关性归一化之后就是余弦相似度第 2 步取最大者是贪心的核心。第 3 步是最小二乘也是最关键的一步——OMP 之所以叫「正交」就是因为每轮都重新求解整个支撑集上的系数保证残差与已选原子张成的子空间正交。第 4 步更新残差。如果不做第 3 步、只做单原子投影那就是 MP匹配追踪收敛慢且系数不唯一这是新手最常混淆的地方。参数怎么改K是硬上限还是提前停止的分界取决于你信不信tol。无噪场景把tol设成 1e-8让 K 起作用有噪场景反过来tol设成sqrt(M) * sigmasigma 是噪声标准差K 设成 23 倍预期稀疏度当兜底。M, N只影响复杂度每轮内积是M*N次乘法最小二乘是O(k²M)总共O(K·M·N)。64×256 的字典、K6单次求解在毫秒量级足够对一张 512×512 图的 26 万块做处理实际上要用重叠块加速见第 4 章。注意D(:, supp(1:k)) \ y用的是反斜杠最小二乘MATLAB 会自动选择 QR 分解。支撑集里出现近共线原子时矩阵会病态此时会出现警告或结果发散这正是后面要查相干性的原因。3.2 噪声一上来 OMP 就飘LASSO 的软阈值写法OMP 的贪心是「一旦选了就不撤销」噪声让内积排序出错时错误原子会一直留在支撑集里最终表现为重建图上出现不属于原图的纹理。LASSO 把 0-范数换成 1-范数变成凸问题没有「选了不可撤销」这回事min 0.5·||Dx − y||₂² λ||x||₁ISTA迭代软阈值是最容易手写的解法每一步就是一次梯度下降加一次软阈值收缩function x ista_lasso(D, y, lambda, nIter) % 迭代软阈值解 LASSO % lambda: 正则强度越大越稀疏 % nIter : 迭代次数通常几百到几千 L norm(D, 2)^2; % 梯度步长上界 最大奇异值平方 x zeros(size(D, 2), 1); for k 1:nIter g D * (D * x - y); % 数据项梯度 x soft_thresh(x - g / L, lambda / L); end end function s soft_thresh(v, tau) % 软阈值算子 S_tau(v) sign(v)·max(|v| - tau, 0) s sign(v) .* max(abs(v) - tau, 0); end逻辑说明L ||D||₂²是数据项梯度的 Lipschitz 常数步长取1/L保证收敛不需要手调学习率。soft_thresh把小于阈值的系数直接压成 0这是 1-范数产生稀疏性的机制——它不像 OMP 那样显式选原子而是让不重要的系数自己归零。lambda决定稀疏程度lambda越大非零系数越少。选型判据我给三条噪声明显SNR 25 dB、字典相干性偏高mu 0.4、或者你根本不知道真实稀疏度 K——这三条中任意一条成立就别用 OMP。反过来需要明确支撑集比如做故障诊断要指出是哪几个原子对应哪类故障、数据量极大要快、或者做教学演示OMP 更合适。ISTA 的缺点是收敛慢nIter上千是常态实务中会换 FISTA第 6 章给代码。3.3 停止条件与复杂度K、tol、迭代上限怎么定这三类参数是新手最容易糊弄过去的但它们的取值直接决定结果好坏。K稀疏度——不要凭感觉。合法做法是先做一次无约束最小二乘或伪逆看系数幅值的衰减曲线取「幅值掉到噪声水平」的位置作为 K 的量级。8×8 块的图像任务里K 6 是个保守起点。tol残差阈值——和噪声直接挂钩。观测噪声标准差是 sigma 时M 维残差的期望范数是sqrt(M)*sigma所以tol 1.1 * sqrt(M) * sigma比较合理。设太小会逼着算法用噪声去拟合观测重建反而更脏设太大会欠拟合块内出现平斑。迭代上限——OMP 就是 KISTA 用相对变化量判停比固定次数更稳norm(x_new - x_old) / norm(x_old) 1e-4就退出。方法单次复杂度需要 K抗噪支撑集明确OMPO(K·M·N)是弱是ISTA/LASSOO(nIter·M·N)否强否FISTAO(nIter·M·N)nIter 更小否强否4. 三类落地图像去噪、缺失像素修复与压缩感知重建的完整脚本原理讲完就该动手了。这三类任务共用同一套「字典 求解器」差别只在观测模型去噪是y x n观测满维但有噪、修复是y M ⊙ x观测有缺、压缩感知是y Φx观测维度比信号低。看清楚这个差别代码就能复用。4.1 分块稀疏去噪重叠块、均值分离与加权融合整幅图直接做稀疏表示是不现实的512×512 就是 26 万维字典根本存不下。标准做法是切成重叠小块逐块稀疏编码再按位置加权平均拼回原尺寸。重叠的意义在于抑制块边界的不连续代价是计算量翻几倍一般重叠一半步长 patch/2就够。%% 分块稀疏去噪训练好的 D OMP patch 8; K 6; sigma 0.1; step 1; tol 1.15 * sqrt(patch^2) * sigma; % 与噪声水平挂钩的残差阈值 noisy img sigma * randn(size(img)); acc zeros(size(noisy)); % 累加重建结果 wsum zeros(size(noisy)); % 累加权重 win ones(patch); % 矩形窗可换高斯窗 for i 1:step:(size(noisy,1)-patch1) for j 1:step:(size(noisy,2)-patch1) blk noisy(i:ipatch-1, j:jpatch-1); mu mean(blk(:)); % 单独处理 DC 分量 y blk(:) - mu; x omp_solve(D, y, K, tol); % 稀疏编码 rec reshape(D * x mu, patch, patch); acc(i:ipatch-1, j:jpatch-1) acc(i:ipatch-1, j:jpatch-1) win.*rec; wsum(i:ipatch-1, j:jpatch-1) wsum(i:ipatch-1, j:jpatch-1) win; end end denoised acc ./ max(wsum, eps); % 加权平均还原 psnr_v psnr(denoised, img);逻辑说明mu是先减掉的块均值。DCT 字典的 DC 原子跟其他原子的相干性很高不分离出来OMP 会花掉一个稀疏度名额去拟合亮度剩下的名额就不够表达纹理了。acc/wsum是标准的重叠块加权融合max(wsum, eps)防除零。win换成二维高斯窗能进一步压制块效应代价是边缘的权重变小。参数怎么改sigma必须知道或者估出来估不准就把tol设成1.5*sqrt(64)*sigma_hat宁可欠拟合也别过拟合。K在去噪任务里不宜超过 8因为噪声会被当成稀疏结构编码进去。step取 1 最慢最好取patch/2是常见的折中。8×8 块、512×512 图、K6单核大概跑十几秒可接受。4.2 观测不全时的修复mask 版 OMP 与压缩感知重建像素丢失的建模方式很直接只有观测到的位置参与残差计算没观测到的位置不贡献误差。实现上就是把字典和观测同时按 mask 取行其它一行不改。function x omp_masked(D, y, mask, K, tol) % 带观测掩膜的 OMP只在 masktrue 的位置计算残差 % 注意这里不要对 Dm 再归一化否则会改变原子的相对权重 Dm D(mask, :); % 只保留有观测的行 ym y(mask); x omp_solve(Dm, ym, K, tol); end逻辑说明mask是 logical 向量D(mask, :)按行取子集相当于把观测算子Φ塞进了字典里。这个过程有个前提——字典在「被采样后的空间」里仍然是过完备的也就是sum(mask) N要成立。丢失率超过 60% 之后修复质量会明显下滑70% 基本是这类方法的边界。压缩感知是同一个思路的正向版本不丢像素而是用比信号维度更少的随机测量。此时等效字典是A Φ·ΨΨ是稀疏基。n 256; m 96; % 信号 256 维只测 96 次 Phi randn(m, n) / sqrt(m); % 高斯测量矩阵 Psi dctmtx(n); % 正交 DCT 基列即原子 A Phi * Psi; % 等效字典 A A ./ sqrt(sum(A.^2, 1)); % 归一化后再求解 s zeros(n, 1); supp randperm(n, 10); % 合成一个 10-稀疏信号 s(supp) randn(10, 1); y A * s; % 观测 sh omp_solve(A, y, 12, 1e-6); % K 给一点余量 xh Psi * sh; % 回到原域 fprintf(CS 重建相对误差 %.2e\n, norm(xh - Psi*s)/norm(Psi*s));逻辑说明A Phi*Psi是「测量算子 稀疏基」的复合稀疏表示在这个复合字典上做。归一化这一步不能省高斯随机矩阵乘上 DCT 基之后各列范数不一致不归一化 OMP 会偏向范数大的原子。K给 12 而不是 10是给噪声和数值误差留余量这是压缩感知里很常见的做法。4.3 参数表patch 尺寸、K、lambda、字典规模怎么配下面这张表是这些年反复试出来的一组起点不是最优解但照着填至少不会一开始就翻车。任务patch字典规模Ktol / lambda备注图像去噪sigma0.18×864×2566tol1.15·√M·sigma先减块均值图像去噪sigma0.058×864×2564同上sigma 换掉K 要跟着降像素修复丢失 30%8×864×2568tol1e-6mask 版 OMP压缩感知m/n0.4整段n×n DCT稀疏度2tol1e-6等效字典要归一化纹理分类特征16×16256×51210训练用 LASSOK-SVD 训练5. 避坑与排查五个让重建结果直接报废的细节这一章的内容基本都是血泪经验每条都对应一个曾经让我对着屏幕怀疑人生的现象。5.1 重建图整体发灰、细节全丢字典列没归一化现象PSNR 比噪声图还低重建结果像被低通滤波过一遍块内几乎没有纹理。原因字典没有列归一化或者训练时归一化了、推理时换了另一种。稀疏惩罚的是系数幅值字典列范数不一致时OMP 的内积排序和 LASSO 的软阈值都会系统性偏移最终所有块都只用少数几个范数大的原子表达。解决字典构造和训练之后各加一行D D ./ sqrt(sum(D.^2,1))如果训练和推理分成两个脚本把归一化写进读取字典的函数里别靠人记。K-SVD 更新出的原子天然单位范数不需要额外处理这一点可以用来反查是不是自己写错了。5.2 块边界出现棋盘格DC 分量没分离现象放大看8×8 的网格线清晰可见块与块的交界处有台阶。原因没有减块均值DC 原子占掉了一个稀疏度名额纹理表达被压缩同时相邻块的均值不同重建后块间亮度跳变重叠区域平均也压不住。解决块内减均值再编码重建时加回去。在上面的去噪脚本里就是mu mean(blk(:))那两行。另一种做法是把 DC 原子单独拿出来作为第 1 列、永不参与 OMP 选择效果等价但代码更绕。5.3 去噪越去越脏K 设得比信号稀疏度大太多现象sigma 从 0.1 加到 0.15去噪结果的 PSNR 不升反降图上出现原本不存在的斑点纹理。原因OMP 的 K 是硬上限只要没到tol就一直选原子噪声在字典里总能找到相关性不错的方向。K12 的时候一个 64 维块用 12 个原子拟合参数量已经接近观测数过拟合就发生了。解决去噪任务的 K 压到 48同时把tol和噪声水平绑定。真正的判据不是 PSNR 涨没涨而是残差范数是否接近sqrt(M)*sigma——如果远小于这个值说明在拟合噪声。5.4 内存爆掉、MATLAB 直接卡死整幅图建字典现象跑压缩感知的脚本刚执行到D * D就报内存不足或者风扇狂转到无响应。原因把整幅图当成一个原子来建字典256×256 的图像就是 65536 维字典哪怕只做 2 倍冗余也是 65536×131072单精度存一次就是 34 GB。解决图像任务一律分块patch 不超过 16×16压缩感知里如果信号本身就是整段比如一维光谱字典规模控制在 n×4n 以内并且用single精度。另外 Gram 矩阵只在算相干性时需要算完立刻clear。5.5 训练时好好的换张图精度掉一半训练集和测试集预处理不一致现象K-SVD 在训练图上重建误差 0.02换到测试集就变成 0.15肉眼可见结构错乱。原因训练时除以了全局标准差并减了块均值测试时忘了做同样处理或者训练用正态化、测试用 min-max 归一化。稀疏表示对尺度极其敏感尺度一变等价于换了一个字典。解决把预处理封装成一对函数preprocess_patch和postprocess_patch训练和推理都调用同一份代码绝不复制粘贴。另外把训练时的sigma_global存进字典的.mat里一起保存加载时直接读。6. 把 OMP 换成 FISTA收敛速度、相干性与一个我常用的验收动作ISTA 稳但慢。当字典到 256×1024 这个量级、要对 26 万个块做处理时ISTA 上千次迭代是跑不完的。FISTA 就是加了个动量项同样的精度下迭代数能压到 ISTA 的三分之一到五分之一代码只多五行。function x fista_lasso(D, y, lambda, nIter) L norm(D, 2)^2; % Lipschitz 常数 x zeros(size(D, 2), 1); z x; t 1; % 动量变量 for k 1:nIter g D * (D * z - y); % 在动量点上算梯度 xn soft_thresh(z - g / L, lambda / L); tn (1 sqrt(1 4*t^2)) / 2; z xn ((t - 1) / tn) * (xn - x); % 外推一步 x xn; t tn; end end动量项(t-1)/tn的作用是把上一步的更新方向带进来走出一点「惯性」从而在平坦区域加速。注意梯度是在z而不是x上算的这是 FISTA 和 ISTA 唯一的本质区别写错这一点就等于白加。换掉求解器之后仍要确定lambda。我不喜欢网格搜索太慢常用的做法是先用lambda_max max(abs(D*y))定上界——这个值对应的解是全零再取lambda 1e-3 * lambda_max到1e-2 * lambda_max之间观察非零系数个数落在预期稀疏度的 11.5 倍就停。这个方法不用知道真值也不依赖训练集。验收动作只有一个算字典的相干性并且和上一次对比。G abs(D * D); G(1:size(G,1)1:end) 0; mu max(G(:)); fprintf(相干性 mu %.3f非零系数均值 %.1f\n, mu, mean(sum(abs(X) 1e-6, 1)));mu涨到 0.5 以上时无论 OMP 还是 FISTA 的重建质量都会出现肉眼可见的退化。这时候不要调lambda应该降字典冗余度或者加多样性约束——我吃过一次亏死磕正则参数调了一整天最后发现是训练集里同一类纹理的块占了 80%字典自然向着那一类塌缩。重采样训练集之后同样的参数下 PSNR 直接涨了 1.8 dB。如果只让我给一条建议先把mu和残差范数这两个数打印出来再谈调参其余的都可以往后放。希望帮到你。本文还有配套的精品资源点击获取