我现在正在尝试学习用于LASSO回归的ADMM算法(Boyd 2010)。
我在page上找到了一个很好的例子。
matlab代码显示为here。
我尝试将其转换为python语言,以便我可以更好地理解。
以下是代码:
import scipy.io as io
import scipy.sparse as sp
import scipy.linalg as la
import numpy as np
def l1_norm(x):
return np.sum(np.abs(x))
def l2_norm(x):
return np.dot(x.ravel().T, x.ravel())
def fast_threshold(x, threshold):
return np.multiply(np.sign(x), np.fmax(abs(x) - threshold, 0))
def lasso_admm(X, A, gamma):
c = X.shape[1]
r = A.shape[1]
C = io.loadmat("C.mat")["C"]
L = np.zeros(X.shape)
rho = 1e-4
maxIter = 200
I = sp.eye(r)
maxRho = 5
cost = []
for n in range(maxIter):
B = la.solve(np.dot(A.T, A) + rho * I, np.dot(A.T, X) + rho * C - L)
C = fast_threshold(B + L / rho, gamma / rho)
L = L + rho * (B - C);
rho = min(maxRho, rho * 1.1);
cost.append(0.5 * l2_norm(X - np.dot(A, B)) + gamma * l1_norm(B))
cost = np.array(cost).ravel()
return B, cost
data = io.loadmat("lasso.mat")
A = data["A"]
X = data["X"]
B, cost = lasso_admm(X, A, gamma)
我发现损失函数在100次迭代后没有收敛。矩阵B并不倾向于稀疏,另一方面,matlab代码在不同的情况下工作。
我已经检查了不同的输入数据并与Matlab输出进行了比较,但我仍然无法获得提示。
有人可以试一试吗?
提前谢谢。
答案 0 :(得分:1)
我的直觉是,为什么这不符合您的期望是la.solve()
电话。 la.solve()
假设矩阵是满秩并且是独立的(即可逆)。当你在MATLAB中使用\
时,MATLAB所做的是如果矩阵是满秩,则找到精确的逆。但是,如果矩阵不是这种方式(即超定或欠定),则系统的解决方案通过最小二乘法来解决。我建议您修改该通话,以便您使用lstsq
代替solve
。因此,只需将la.solve()
来电替换为:
sol = la.lstsq(np.dot(A.T, A) + rho * I, np.dot(A.T, X) + rho * C - L)
B = sol[0]
请注意,除了解决方案之外,lstsq
还会在4元素元组中返回一大堆输出。系统的解决方案是这个元组的第一个元素,这就是我B = sol[0]
的原因。还返回的是残差的总和(第二个元素),等级(第三个元素)和你在求解时试图反转的矩阵的奇异值(第四个元素)。
我注意到了一些特点:
L
初始化为零矩阵,使L = zeros(size(X));
。但是,在Python代码中,您将L
初始化为:L = np.zeros(C.shape);
。您正在使用不同的变量来确定L
的形状。显然,
如果存在尺寸不匹配,代码将无法工作,但这是另一回事。不确定这是否会影响您的解决方案。到目前为止,我还没有找到任何与众不同的东西,所以请尝试修复并告诉我。