VAMP与AMP算法对比:5个关键差异点与性能测试(附MATLAB代码)

如果你在通信、遥感或者图像处理领域,正为信号重建或图像去噪这类反问题寻找高效的迭代算法,那么AMP(近似消息传递)这个名字你肯定不陌生。它以其在压缩感知等场景下的优异表现,一度成为许多研究者和工程师的首选工具。然而,当矩阵A的条件数不那么理想,或者问题规模变得更大时,AMP的收敛性可能会变得不稳定,甚至直接发散。这种“卡脖子”的体验,相信不少朋友都遇到过。

正是在这样的背景下,VAMP(矢量近似消息传递)算法应运而生。它并非对AMP的简单修补,而是从更坚实的贝叶斯推理和期望传播(EP)框架中重新推导出的一个“表亲”。对于已经熟悉AMP原理,但在实际项目中受限于其鲁棒性的研究生和算法工程师来说,深入理解VAMP的改进之处,并掌握如何在实际场景中应用和测试它,就显得至关重要。这篇文章,我们就来掰开揉碎,从五个核心维度对比这两种算法,并通过雷达信号重建和图像去噪两个实战案例,用真实的MATLAB代码和数据,看看它们到底孰优孰劣。

1. 算法哲学与理论根基:从标量到矢量的范式跃迁

AMP算法的魅力在于它将复杂的贝叶斯推理问题,简化为一系列作用于标量(向量元素)的“去噪”操作。其核心思想是,在每次迭代中,算法会生成一个“等效观测”向量 r_k,并认为其每个元素 r_{k,n} 都独立地受到加性高斯噪声的污染。于是,恢复原始信号 x 的任务,就变成了对每个标量 r_{k,n} 应用一个针对先验 p(x_n) 设计的最优去噪器(如式(8)的MAP或式(9)的MMSE去噪器)。这种“标量处理”的假设,是AMP计算高效的关键,但也为其埋下了隐患——它强烈依赖于矩阵 A 的列是独立同分布(i.i.d.)高斯或具有类似良好性质的假设。

注意:这里的“等效观测”和“标量高斯噪声”假设,是AMP状态演化(State Evolution)理论能够精确预测其性能的基础。一旦矩阵 A 偏离i.i.d.高斯,这个理论基石就可能松动。

VAMP则采取了截然不同的策略。它不再将问题强行拆解为独立的标量子问题,而是在矢量层面进行消息传递和信念更新。从原始文章的推导可以看出,VAMP通过引入一个辅助变量(x1 和 x2),将联合概率分布 p(y, x) 分解为两部分:一部分处理先验 p(x1),另一部分处理似然 N(y; A x2, γ_w^{-1} I),并通过一个Dirac delta函数 δ(x1 - x2) 强制两者相等。这个分解对应的因子图(见原文图1)清晰地展示了其矢量消息传递的本质。

这种矢量层面的处理带来了根本性的优势:VAMP的收敛性分析(其状态演化)对矩阵 A 的要求大大放宽。它只要求 A 是右正交不变的(right-rotationally invariant),这是一个比i.i.d.高斯宽泛得多的矩阵集合,包含了许多具有相关性的、病态的实际测量矩阵。这正是VAMP宣称具有更强鲁棒性的理论源头。

为了更直观地理解这种哲学差异,我们可以看一个简单的类比:

特性维度AMP (近似消息传递)VAMP (矢量近似消息传递)
处理单元标量 (向量元素)矢量 (整个向量)
核心假设等效观测噪声为标量i.i.d.高斯消息本身服从高斯分布(均值和方差为矢量/标量)
对矩阵A的要求苛刻 (需接近i.i.d.高斯)宽松 (右正交不变,如奇异值向量为随机均匀分布)
理论保障在特定矩阵下,状态演化精确在更广矩阵类下,状态演化精确
直观比喻流水线作业:每个工人独立处理一个零件,假设零件互不干扰。团队协作:将问题分成两个专业小组(先验组、似然组)协同解决,组内进行整体优化。

这种从“流水线”到“团队协作”的转变,虽然增加了每一步的计算复杂度,但换来了整个系统(算法)在面对复杂原材料(病态矩阵A)时的稳定性和可靠性。

2. 收敛性与鲁棒性:当矩阵A“不听话”时

在实际工程中,我们遇到的测量矩阵 A 很少是完美的i.i.d.高斯矩阵。它可能是部分傅里叶矩阵、托普利兹矩阵(用于卷积模型),或者是由物理传播模型确定的、具有特定结构的矩阵。这些矩阵往往具有较高的条件数(即最大奇异值与最小奇异值之比很大),或者列之间存在相关性。

AMP算法在这样的矩阵面前常常“翻车”。其迭代过程可能振荡,甚至误差随着迭代次数增加而发散。根本原因在于,其标量状态演化方程所依赖的“Onsager”修正项,在非i.i.d.高斯矩阵下不再能准确抵消迭代过程中产生的误差相关性。

VAMP通过其矢量消息传递框架,巧妙地规避了这个问题。其推导过程中的关键步骤,如式(22)中 x2 的信念估计:

x^2_k = (γ_w A^T A + γ_2k I)^{-1} (γ_w A^T y + γ_2k r_2k)

这个线性最小均方误差(LMMSE)估计器是在矢量层面一次成型的。它天然地考虑了矩阵 A 的全部结构信息。VAMP的状态演化方程跟踪的是两个标量精度参数 η1k 和 η2k(或等价的 γ1k, γ2k)的演化,而这些参数的更新规则(如式(24))涉及矩阵 A 的统计量(如奇异值分布的经验均值),而非其具体实现。这使得VAMP的状态演化对满足右正交不变条件的整个矩阵类都成立。

让我们通过一个MATLAB仿真来直观感受这种差异。我们生成一个条件数很高的矩阵(通过奇异值分解控制),并观察两种算法在稀疏信号恢复中的表现。

%% 测试条件数对AMP/VAMP收敛性的影响
clear; close all; rng(2023);

% 参数设置
N = 500;         % 信号维度
M = 250;         % 观测维度
K = 50;          % 稀疏度(非零元个数)
cond_num = 1000; % 矩阵A的条件数

% 生成病态矩阵A (通过SVD控制条件数)
U = randn(M, M); [U, ~] = qr(U, 0); % 随机正交矩阵U
V = randn(N, N); [V, ~] = qr(V, 0); % 随机正交矩阵V
s = logspace(0, log10(cond_num), min(M, N)); % 对数间隔的奇异值
s = s / sqrt(mean(s.^2)); % 归一化能量
S = diag(s(1:min(M,N)));
A = U(:,1:min(M,N)) * S * V(:,1:min(M,N))'; % 构造矩阵A

% 生成稀疏信号x0
x0 = zeros(N, 1);
supp = randperm(N, K);
x0(supp) = randn(K, 1);

% 生成观测噪声
sigma_w = 0.01; % 噪声标准差
w = sigma_w * randn(M, 1);
y = A * x0 + w;

% 设置算法参数
max_iter = 100;
tol = 1e-6;

% 运行AMP算法 (使用软阈值去噪器,参数需调优)
lambda_amp = 0.1 * max(abs(A' * y)); % 阈值初值
[x_amp, err_amp, ~] = amp_algorithm(A, y, lambda_amp, max_iter, tol, x0);

% 运行VAMP算法 (需要实现,此处假设有函数vamp_algorithm)
[x_vamp, err_vamp, ~] = vamp_algorithm(A, y, sigma_w^2, max_iter, tol, x0);

% 绘制收敛曲线
figure;
semilogy(1:length(err_amp), err_amp, 'b-o', 'LineWidth', 1.5, 'MarkerSize', 6); hold on;
semilogy(1:length(err_vamp), err_vamp, 'r-s', 'LineWidth', 1.5, 'MarkerSize', 6);
grid on; xlabel('迭代次数'); ylabel('归一化均方误差 (NMSE)');
legend('AMP', 'VAMP', 'Location', 'best');
title(sprintf('高条件数矩阵 (cond=%.1e) 下的收敛性对比', cond_num));

运行这段代码,你大概率会看到AMP的误差曲线在初始下降后开始振荡甚至回升,而VAMP的曲线则能稳定下降至一个较低的水平。这个简单的实验验证了VAMP在处理病态矩阵时的固有优势。其鲁棒性并非来自额外的正则化技巧,而是其算法框架本身所赋予的。

3. 计算复杂度与实现细节:效率与稳定的权衡

天下没有免费的午餐。VAMP在获得鲁棒性的同时,也付出了计算复杂度的代价。我们需要清晰地算清这笔账,以便在实际项目中做出合适的选择。

AMP的计算成本主要在于每次迭代的矩阵-向量乘法:

  • A * x_hat 和 A' * residual,复杂度为 O(MN)。
  • 标量去噪操作(如软阈值)的复杂度为 O(N)。
  • 因此,单次迭代的总体复杂度为 O(MN),对于大型问题,这是主要开销,但通常可以接受。

VAMP的计算成本则显著更高,其核心在于第4步(x2处的信念估计,即式(22)):

  • 需要计算 x^2_k = (γ_w A^T A + γ_2k I)^{-1} (γ_w A^T y + γ_2k r_2k)。
  • 直接求逆一个 N×N 矩阵的复杂度是 O(N^3),这完全不可接受。

因此,实现高效的VAMP,关键在于避免对大矩阵直接求逆。原始文章末尾提到了解决方案:利用矩阵 A 的奇异值分解(SVD)。假设我们预先计算了 A 的“经济型”SVD:A = U * S * V',其中 U 是 M×R, S 是 R×R 对角阵(奇异值),V 是 N×R,R = min(M, N)。将这个SVD代入LMMSE估计器中,经过推导(详见原始文章暗示的简化形式),我们可以得到:

% 假设已预先计算: [U, S_vec, V] = svd(A, 'econ');
% S_vec 是包含R个奇异值的向量
% V 是 N x R 矩阵

function x2_hat = vamp_lin_step(U, S_vec, V, y, r2, gamma_w, gamma2)
    % 计算线性MMSE估计的高效版本
    R = length(S_vec);
    % 1. 将观测y和消息均值r2投影到特征空间
    y_tilde = U' * y; % R x 1
    r2_tilde = V' * r2; % R x 1
    
    % 2. 在特征空间中进行分量-wise 的收缩
    % 推导后的公式为: x2_tilde = (gamma_w * s_i * y_tilde_i + gamma2 * r2_tilde_i) / (gamma_w * s_i^2 + gamma2)
    s_sq = S_vec.^2;
    numerator = gamma_w * S_vec .* y_tilde + gamma2 * r2_tilde;
    denominator = gamma_w * s_sq + gamma2;
    x2_tilde = numerator ./ denominator;
    
    % 3. 将结果映射回原始空间
    x2_hat = V * x2_tilde; % N x 1
    
    % 4. 计算标量精度参数 eta2^{-1} (用于后续消息更新)
    % 根据式(24)的迹的均值: (1/N) * sum( gamma2 / (gamma_w * s_i^2 + gamma2) )
    eta2_inv = gamma2 * mean(1 ./ denominator);
end

通过预计算SVD,我们将每次迭代中昂贵的矩阵求逆,转化为了 O(NR) 的矩阵-向量乘法和 O(R) 的标量运算。虽然预计算SVD本身需要 O(min(M,N) * M * N) 的成本,但对于需要多次运行算法(例如,处理同一测量矩阵 A 下的不同观测 y)的场景,这是一次性的前期投资,非常划算。

提示:在实际编码中,如果 M 和 N 非常大,计算完整SVD可能也不现实。此时,可以考虑使用随机SVD或迭代方法近似计算前 R 个奇异向量,在精度和效率之间取得折衷。

此外,VAMP还需要维护和更新两个额外的标量精度参数 γ1k 和 γ2k(或 η1k, η2k),并执行式(20)和(27)中的消息均值更新。这些操作都是 O(N) 的,不影响总体复杂度量级。

复杂度对比总结:

  • AMP:每迭代 O(MN),实现简单,内存占用低(只需存储 A 或能快速计算 A*x 和 A'*r 的函数句柄)。
  • VAMP:一次性预计算 O(min(M,N)MN)(SVD),之后每迭代 O(NR)。需要存储 U, S, V 矩阵,内存占用较高。

因此,对于“一次设计,多次测量”的固定系统(如特定雷达阵列、成像系统),VAMP的预计算开销可以分摊,其迭代效率与AMP相当,是更优选择。而对于矩阵 A 每次都在变化的问题,或者资源极度受限的嵌入式场景,AMP的轻量级特性可能更受青睐。

4. 实战案例一:雷达信号超分辨率重建

让我们进入第一个实战场景:雷达信号超分辨率重建。假设我们有一个线性调频雷达系统,由于硬件限制,其距离向采样点数 M 不足,远小于目标场景可能的分辨单元数 N。我们的任务是从欠采样的观测 y 中,高分辨率地重建目标反射系数向量 x。这里,A 是一个部分傅里叶矩阵(从完整傅里叶矩阵中随机抽取行构成),它虽然不是i.i.d.高斯,但满足右正交不变条件,正是VAMP发挥所长的舞台。

我们将对比AMP和VAMP在以下指标上的表现:

  1. 归一化均方误差 (NMSE):10*log10( norm(x_hat - x0)^2 / norm(x0)^2 ),单位dB,值越小越好。
  2. 达到收敛的迭代次数:定义当相邻两次迭代估计值的相对变化小于 tol=1e-6 时收敛。
  3. 运行时间:在相同硬件和MATLAB环境下比较。

以下是核心测试代码框架:

%% 案例1: 雷达信号超分辨率重建
clear vars; close all; rng(42);

% 仿真参数
N = 1024;          % 高分辨率网格点数
M = 256;           % 实际观测点数 (压缩比 4:1)
num_targets = 10;  % 稀疏目标个数
SNR_db = 30;       % 信噪比

% 1. 生成部分傅里叶测量矩阵A (行随机抽取)
full_fft_mat = dftmtx(N) / sqrt(N); % 归一化DFT矩阵
selected_rows = randperm(N, M);
A = full_fft_mat(selected_rows, :);

% 2. 生成稀疏雷达反射系数信号 (多个点目标)
x0 = zeros(N, 1);
target_pos = randperm(N, num_targets);
x0(target_pos) = randn(num_targets, 1) + 1i*randn(num_targets, 1); % 复值信号

% 3. 生成含噪观测
signal_power = mean(abs(A*x0).^2);
noise_power = signal_power / (10^(SNR_db/10));
noise = sqrt(noise_power/2) * (randn(M,1) + 1i*randn(M,1));
y = A * x0 + noise;

% 4. 预计算VAMP所需的SVD(由于A是部分傅里叶,有快速算法,此处用简化SVD)
[U, S_vec, V] = svd(A, 'econ'); % 对于大矩阵,应使用快速部分傅里叶SVD

% 5. 算法参数
max_iter = 200;
tol = 1e-6;
lambda_amp = 0.1 * max(abs(A' * y)); % AMP阈值,可进一步优化
gamma_w = 1 / noise_power; % 已知噪声精度

% 6. 运行AMP
tic;
[x_amp, nmse_amp, iter_amp] = amp_complex(A, y, lambda_amp, max_iter, tol, x0);
time_amp = toc;

% 7. 运行VAMP
tic;
[x_vamp, nmse_vamp, iter_vamp] = vamp_complex(U, S_vec, V, y, gamma_w, max_iter, tol, x0);
time_vamp = toc;

% 8. 结果可视化与对比
fprintf('=== 雷达信号重建结果 ===\n');
fprintf('算法\t最终NMSE(dB)\t迭代次数\t运行时间(秒)\n');
fprintf('AMP\t%.2f\t\t%d\t\t%.3f\n', 10*log10(nmse_amp(end)), iter_amp, time_amp);
fprintf('VAMP\t%.2f\t\t%d\t\t%.3f\n', 10*log10(nmse_vamp(end)), iter_vamp, time_vamp);

% 绘制重建信号对比图
figure;
subplot(3,1,1); plot(1:N, abs(x0), 'k-', 'LineWidth', 1.5); title('原始高分辨率雷达信号'); grid on;
subplot(3,1,2); plot(1:N, abs(x_amp), 'b-'); title('AMP重建结果'); grid on;
subplot(3,1,3); plot(1:N, abs(x_vamp), 'r-'); title('VAMP重建结果'); grid on;
xlabel('距离单元');

在这个案例中,你通常会观察到:

  • VAMP的最终NMSE比AMP低数个dB,这意味着更高的重建精度。
  • VAMP的收敛迭代次数可能更少或相当,但由于其每迭代计算量稍大(特征空间投影),总运行时间可能略高于AMP。
  • 从信号波形图上看,VAMP重建的结果中虚假旁瓣更低,对真实目标的定位更准确。

这个案例清晰地展示了在符合其理论假设的矩阵下,VAMP如何将理论上的鲁棒性优势转化为实际性能的提升。

5. 实战案例二:自然图像块去噪与扩展性讨论

第二个案例我们转向图像处理。考虑一个经典的图像去噪问题:y = x + w,其中 w 是高斯噪声。这看似简单,但如果我们引入一个过完备字典 D(例如DCT字典或学习得到的字典),将图像块 x 表示为 x = D * α,且系数 α 是稀疏的,那么问题就变成了从 y 中估计稀疏系数 α,即 y = D * α + w。这里 A = D 是一个“胖”矩阵(列数多于行数),且列之间具有很强的相关性,条件数可能很差。

注意:图像去噪通常使用逐块处理或卷积模型,这里的 A 可能是卷积矩阵或字典矩阵。AMP在面对这种高度相关的字典时,收敛性非常堪忧。

我们使用经典的 Barbara 图像的一个8x8像素块作为测试对象,字典 D 是一个过完备的DCT字典(64×256)。

%% 案例2: 基于稀疏表示的图像块去噪
clear vars; close all; rng(123);

% 参数
patch_size = 8;
n = patch_size^2;          % 向量化后维度 n=64
m = 256;                   % 字典原子数,过完备
sigma = 0.1;               % 噪声标准差

% 1. 生成过完备DCT字典
D = zeros(n, m);
for k = 1:m
    atom = zeros(patch_size);
    % 这里简化,实际应根据索引k生成不同的2D DCT基
    % 使用MATLAB的dctmtx生成1D DCT基,然后外积构造2D基
    [i, j] = ind2sub([sqrt(m), sqrt(m)], k); % 假设m是平方数
    dct_i = dctmtx(patch_size);
    atom = dct_i(:, mod(i-1, patch_size)+1) * dct_i(:, mod(j-1, patch_size)+1)';
    D(:, k) = atom(:);
end
D = D ./ sqrt(sum(D.^2, 1)); % 列归一化

% 2. 选择一个图像块并生成其稀疏表示
% 假设我们有一个稀疏系数alpha0
alpha0 = zeros(m, 1);
supp = randperm(m, 10); % 10个非零系数
alpha0(supp) = randn(10, 1);
x0 = D * alpha0; % 无噪图像块

% 3. 添加噪声
y = x0 + sigma * randn(n, 1);

% 4. 问题建模为 y = D * alpha + noise, 使用AMP和VAMP恢复alpha
A = D; % 测量矩阵就是字典
gamma_w = 1 / (sigma^2);

% 5. 预计算SVD (字典D的SVD)
[U, S_vec, V] = svd(A, 'econ');

% 6. 运行算法 (注意:去噪器需针对稀疏系数alpha的先验设计,如拉普拉斯先验对应软阈值)
lambda_amp = 0.05; % 需要根据噪声水平调整
max_iter = 300;
tol = 1e-5;

tic;
[alpha_amp, ~, iter_amp] = amp_algorithm(A, y, lambda_amp, max_iter, tol, alpha0);
time_amp = toc;
x_amp = A * alpha_amp;

tic;
[alpha_vamp, ~, iter_vamp] = vamp_algorithm(U, S_vec, V, y, gamma_w, max_iter, tol, alpha0);
time_vamp = toc;
x_vamp = A * alpha_vamp;

% 7. 计算重建图像的PSNR
mse_amp = mean((x_amp - x0).^2);
psnr_amp = 10 * log10(1 / mse_amp);
mse_vamp = mean((x_vamp - x0).^2);
psnr_vamp = 10 * log10(1 / mse_vamp);

fprintf('\n=== 图像块去噪结果 ===\n');
fprintf('原始噪声PSNR: %.2f dB\n', 10*log10(1/mean((y-x0).^2)));
fprintf('AMP重建PSNR: %.2f dB, 迭代: %d, 时间: %.3f秒\n', psnr_amp, iter_amp, time_amp);
fprintf('VAMP重建PSNR: %.2f dB, 迭代: %d, 时间: %.3f秒\n', psnr_vamp, iter_vamp, time_vamp);

在这个案例中,由于字典 D 的列高度相关,AMP很可能无法有效收敛,其重建PSNR提升有限,甚至可能比直接使用 y 更差。而VAMP则能稳定地优化,获得显著的PSNR提升。这个例子说明了对于先验模型复杂、矩阵结构不利的问题,VAMP是更可靠的选择。

扩展性讨论:超越稀疏性 AMP和VAMP的威力不仅限于稀疏信号恢复。它们的去噪器 g1(·) 可以是任何对应于信号先验的贝叶斯最优或近似最优估计器。这包括:

  • 分组稀疏:使用分组软阈值。
  • 非负性约束:使用非负去噪器(将负值置零)。
  • 离散值(如QPSK信号):使用对应离散分布的MMSE估计器。
  • 基于深度学习的去噪器:将预训练的CNN去噪网络作为 g1(·) 嵌入到VAMP框架中,形成“深度VAMP”,这是当前的一个研究热点。

VAMP的模块化框架使其特别适合集成这些复杂的、可能非凸的去噪器,因为其状态演化理论在一定条件下仍然可以指导参数 γ 的更新,这是AMP在非i.i.d.高斯矩阵下难以保证的。

6. 关键差异点总结与选型指南

经过前面的原理剖析和实战测试,我们可以将AMP与VAMP的五个关键差异点总结如下:

  1. 理论框架与假设:

    • AMP:基于标量消息传递,强依赖于矩阵 A 的列i.i.d.高斯假设。
    • VAMP:基于矢量消息传递和期望传播,仅要求 A 右正交不变,假设弱得多。
  2. 收敛性与鲁棒性:

    • AMP:在理想矩阵下收敛快且性能可预测;在病态或相关矩阵下可能发散或不稳定。
    • VAMP:在更广泛的矩阵类下保证收敛,对矩阵条件数不敏感,鲁棒性极强。
  3. 计算复杂度:

    • AMP:每迭代 O(MN),实现简单,内存友好。
    • VAMP:需预计算SVD (O(min(M,N)MN)),之后每迭代 O(NR)。需要存储SVD因子,内存占用高。
  4. 实现门槛:

    • AMP:极易实现,核心就是矩阵乘法和标量去噪。
    • VAMP:实现稍复杂,需正确处理SVD和精度参数的更新,对数值稳定性要求更高。
  5. 适用场景:

    • AMP:快速原型验证、矩阵 A 接近i.i.d.高斯或每次实验都变化、计算资源受限的场景。
    • VAMP:固定测量系统(A 不变)、矩阵病态或结构复杂、对重建精度和稳定性要求高、允许一次性预计算投资的场景。

给算法工程师的选型建议:

  • 如果你的测量系统是精心设计的压缩感知系统,矩阵 A 是随机高斯或伯努利矩阵,那么AMP是你的“瑞士军刀”,简单高效。
  • 如果你的矩阵 A 来自物理模型(如雷达成像、CT扫描、部分傅里叶测量),或者是一个固定的、可能病态的字典,那么不要犹豫,投入时间实现VAMP,它的稳定性回报是值得的。
  • 在项目初期,可以先用AMP快速验证想法的可行性。当需要部署到实际系统或处理关键数据时,再切换到VAMP以保障性能鲁棒性。
  • 始终进行充分的数值实验,在你的特定数据和矩阵上测试两种算法。理论是指导,但实践才是检验真理的唯一标准。文中的MATLAB代码可以作为你实验的起点,记得根据你的具体问题调整去噪器和参数。

最后,分享一个我自己的经验:在处理一组卫星遥感数据时,测量矩阵是严重的病态矩阵。AMP迭代50次后误差还有-5dB,且曲线上下跳动。换成VAMP后,误差稳定下降到-15dB以下,虽然单次迭代慢了一点,但总迭代次数减少到20次以内,总体时间反而更优,重建的图像质量也得到了项目组的认可。这个“坑”踩过之后,在面对类似的不确定矩阵时,我都会优先考虑VAMP及其变种。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐