如何编写与 LSQ Tikhonov 去噪完全匹配的基于梯度下降的 Tikhonov 去噪?

计算科学 优化 最小二乘
2021-12-01 12:12:14

(注:更正后的代码贴在原代码下方。)

对于优化练习,我有兴趣从头开始编写一个简单的示例:使用梯度下降的 Tikhonov 去噪例程,它在输出中与基于 LSQ 的 Tikhonov 去噪结果完全匹配。

用于噪声信号的正则化b恢复去噪版本x, 我应用了 Tikhonov 的典型公式

Axb2+λx2

A为单位矩阵,λx为加权梯度矩阵|λx|.

在 LSQ 的情况下,这可以使用A^b^来解决,其中 A^=[I;λx] , b=[b;0]x=Ab下面的代码显示了平滑信号的结果。

使用梯度下降版本,我现在尝试最小化f其中

f(x)=0.5xb2+λx2

我通过朝着函数梯度的负方向前进来做到这一点,我相信这是

f(x)=xb+2λ2x

拉普拉斯算子。但是这段代码会产生垃圾。谁能发现我的错误?2

代码:

function tik_1d

signal = sin((1:512)/128*2*pi);
signal = signal + randn(size(signal))*0.05;
lambda = 15;
niter = 50;
signal_lsq = tik_lsq(signal, lambda);
signal_opt = tik_opt(signal, lambda, niter);
figure(1); set(gcf, 'color', 'w');
subplot(3, 1, 1); plot(signal); title('b');
subplot(3, 1, 2); plot(signal_lsq); title('LSQ x');
subplot(3, 1, 3); plot(signal_opt); title('GD x');

end

function signal_lsq = tik_lsq(signal, lambda)
    grad = gradient_matrix(signal)*lambda; %subfunction see below
    A = [eye(numel(signal)); grad];
    s = signal';
    b = [s; zeros(size(s))];
    signal_lsq = A\b;
end

function m = gradient_matrix(signal)
    n = numel(signal);
    diag1 = ones(n,1);
    diag2 = -diag1;
    m = spdiags([diag1 diag2], [0 1], n, n);
end

function signal_opt = tik_opt(signal, lambda, niter)
    e = zeros(niter,1);
    signal_opt = signal;
    tau = 0.1;
    for n = 1:niter
        e(n) = eval_f(signal_opt, signal, lambda); %subfunction see below
        diff = tau*grad_f(signal_opt, signal, lambda); %subfunction see below
        signal_opt = signal_opt - diff;
    end
    figure(2); plot(e);
end

function e = eval_f(signal_rec, signal, lambda)
    signal_grad = conv(signal_rec, [1 -1], 'same');
    e = 0.5*norm(signal_rec-signal) + norm(lambda*signal_grad);
end

function g = grad_f(signal_rec, signal, lambda)
    signal_lap = conv(signal_rec, [1 -2 1], 'same');
    g = (signal - signal_rec) + lambda*(signal_lap);
end

输出:

Tikhonov 去噪结果

更新:这是包含 Christian Clason 建议的代码:

function tik_1d

signal = sin((1:512)/128*2*pi);
signal = signal + randn(size(signal))*0.05;
lambda = 15;
niter = 500;
signal_lsq = tik_lsq(signal, lambda);
signal_opt = tik_opt(signal, lambda, niter);
figure(1); set(gcf, 'color', 'w');
subplot(4, 1, 1); plot(signal); title('b'); ylim([-1 1]);
subplot(4, 1, 2); plot(signal_lsq); title('LSQ x'); ylim([-1 1]);
subplot(4, 1, 3); plot(signal_opt); title('GD x'); ylim([-1 1]);
subplot(4, 1, 4); plot(signal_opt - signal_lsq'); title('LSQ x - GD x'); ylim([-1 1]);

end

function signal_lsq = tik_lsq(signal, lambda)
    grad = gradient_matrix(signal)*sqrt(lambda); %subfunction see below
    A = [eye(numel(signal)); grad];
    s = signal';
    b = [s; zeros(size(s))];
    signal_lsq = A\b;
end

function m = gradient_matrix(signal)
    n = numel(signal);
    diag1 = ones(n,1);
    diag2 = -diag1;
    m = spdiags([diag1 diag2], [0 1], n, n);
end

function signal_opt = tik_opt(signal, lambda, niter)
    e = zeros(niter,1);
    signal_opt = signal;
    tau = 0.001;
    for n = 1:niter
        e(n) = eval_f(signal_opt, signal, lambda); %subfunction see below
        diff = tau*grad_f(signal_opt, signal, lambda); %subfunction see below
        signal_opt = signal_opt - diff;
    end
    figure(2); plot(e);
end

function e = eval_f(signal_rec, signal, lambda)
    signal_grad = conv(signal_rec, [1 -1], 'same');
    e = 0.5*norm(signal_rec-signal) + norm(lambda*signal_grad);
end

function g = grad_f(signal_rec, signal, lambda)
    signal_lap = conv(signal_rec, [1 -2 1], 'same');
    g = (signal - signal_rec) - lambda*(signal_lap);
end

输出:

在此处输入图像描述

1个回答

您的梯度下降存在一些问题:

  1. 的梯度为\ 拉普拉斯算子。u2

    u=divu=Δu,

  2. 梯度下降不无条件地收敛,但是仅在适当地(特别是不太大的情况下)。要么手动减小步长直到收敛,要么实施适当的线搜索,例如,基于Armijo 或 Wolfe 条件

  3. 您并没有最小化与 LSQR 方法中相同的函数,因为在第一项前面有的因子,而 LSQR 函数中不存在(这实际上使您的大了一倍)。1/2λ

最后,一个挑剔:虽然这在两种方法中都是一致的,但你的梯度和矩阵对应于,而不是(前者是它通常的写法。)A^λu2λu2