ISTA与稀疏编码
本人习惯
注释
我自己的想法或者例子,不必要
代码
function [...] = fun(...)
....
end
稀疏编码
稀疏编码是什么鬼
图像可以认为是 n × m × 3 n \times m \times 3 n×m×3的一个矩阵,随着图像清晰度的提升,以目前主流的1920*1800图像为例,单单一个图片就可能有 1920 × 1080 × 3 ≥ 6 × 1 0 6 1920 \times 1080 \times 3 \geq 6 \times 10^{6} 1920×1080×3≥6×106,在假设每个位置使用256色( 2 8 2^8 28种颜色需要8bit,也就是1B),一张图片的大小已经大于6MB,未经压缩的1080P视频每分钟数据量约为 1920 × 1080 × 3 × 30 × 60 ≥ 1 × 1 0 10 1920 \times 1080 \times 3 \times 30 \times 60 \geq 1 \times 10^{10} 1920×1080×3×30×60≥1×1010,一分钟超过一个G的存储量显然目前的存储技术无法解决,只能从无损压缩图像->无损压缩视频这个思路出发。虽然JPEG提供了一种无损压缩算法,但是速度较慢。一般情况下,对于实时性要求高或数据传输成本高的情况(例如医疗影像\卫星图像),有损压缩成为了一种必要之恶。
稀疏编码是一种依托优化思想出现的压缩方式,他从两个方向出发对图像进行压缩:
- 保真度
对于原始的信号X,我们希望有一个信号Y充分逼近X,有如下关系:
X = Y + ϵ \begin{aligned} X = Y + \epsilon \end{aligned} X=Y+ϵ
其中 ϵ \epsilon ϵ为噪声,我们在这里希望噪声造成的影响最小,即:
Y ∗ = arg min Y B ( X , Y ) \begin{aligned} Y^* = {\arg\min}_Y B(X,Y) \end{aligned} Y∗=argminYB(X,Y)
其中 B ( X , Y ) = ∣ ∣ Y − X ∣ ∣ p p = ∣ ∣ ϵ ∣ ∣ p p B(X,Y)=||Y-X||_p^p = ||\epsilon||_p^p B(X,Y)=∣∣Y−X∣∣pp=∣∣ϵ∣∣pp
从B的定义考虑,若我们选择p=2,B(X,Y)可以认为是均方误差(MSE),我们希望其误差尽量小。 也是一种合理的解释呢!
接下来,我们给定一个Y的表示方法
Y = D ⋅ Z \begin{aligned} Y = D \cdot Z \end{aligned} Y=D⋅Z
显然,如果D是n维空间的一组标准正交基,Z就相当于是Y在D上映射的坐标,且对于指定的D,Z有唯一表示,我们希望Z有某种优秀的性质。那么我们有几个方向可以考虑- 推断D的结构,通过数据对D进行优化,保证得到的Z拥有好的性质,但是这太难了,对于不同的数据,很难用矩阵论的方法对D进行推断。
- 如果上述结构不进行推断,仍可以通过机器学习算法例如BP神经网络优化来优化这个矩阵D,使得D对于一个特定场景具有较好的性质。确实是一种好的思想。但是如果D发生变化,Z将无法通过简单的矩阵乘法变回信号Y,显然如果空间的基发送变化,这组基上的坐标都将失去原来的意义。需要大量的数据才能保证在某一问题上D有良好的效果。只能考虑继续优化思路。
- 我们先给定一组标准正交基S,再给定一些列向量,写成矩阵P,如果D = [S P], 那么P中所有向量均可由S线性表出,此时D(之后称为字典)可以称为一个超完备的集合,此时Z的表示不再唯一,为后续对于Z某种性质的优化提供了可能性。(*对于ISTA我们考虑到这里就结束了,但是仍然可以对此进行改进,如果有好的想法欢迎私信探讨)
关于字典,我觉得是他通过一个拥有优秀性质的Z表示了蕴含复杂信息的Y
- 稀疏性
对于一个向量Z,Z中非0元素个数为u, 则称Z为u稀疏的(u-Sparse)。对于一个充分稀疏的向量Z,使用Z{Site, Value}表示更加节省空间(类似图论算法中的两种存图结构:邻接矩阵和邻接表),是一种可行的压缩方式。
那么如何对通过优化保证稀疏性呢?Z = [0,0,1,0,0,0,3,0,0,0,0,0,1,0,0,2,0,5,0,0,0,0,0,0,0,0,0,0,0] Z{Site, Value} = [{2,1},{6,3},{12,1},{15,2},{17,5}] 很明显sizeof(Z)>sizeof(Z{Site, Value})
Z ∗ = arg min Z S ( X , Y ) = ∣ ∣ Z ∣ ∣ 0 \begin{aligned} Z^* = {\arg\min}_Z S(X,Y) = ||Z||_0 \end{aligned} Z∗=argminZS(X,Y)=∣∣Z∣∣0
是一种很好的想法,但是L-0范数显然是非凸的,优化难度巨大,属于NP-Hard问题,只能智取,不可强攻。
IDEAs:
1. 使用贪心算法(one can say it nearly always choose all the suboptimal solution)
2. 使用群体智能算法(some said only works well on low-dimension question)
3. 放宽条件(some called of ’松弛‘, which may be a good idea)
根据大佬的证明,将0范数放宽到1范数是可行的,故原问题转化为:
Z ∗ = arg min Z S ( Z ) = ∣ ∣ Z ∣ ∣ 1 \begin{aligned} Z^* = {\arg\min}_Z S(Z) = ||Z||_1 \end{aligned} Z∗=argminZS(Z)=∣∣Z∣∣1优秀的糅合怪LASSO格式的稀疏优化
我们有两种思路将上述问题糅合起来,就是稀疏编码的目标:
在有足够保真度的区域找到稀疏性最好的点:
Z ∗ = arg min Z S ( Z ) \begin{aligned} Z^* = {\arg\min}_Z S(Z) \end{aligned} Z∗=argminZS(Z) s . t . B ( X , D ⋅ Z ) < = e \begin{aligned} s.t. B(X,D \cdot Z) <= e \end{aligned} s.t.B(X,D⋅Z)<=e
在稀疏性足够好的区域找到保真度最高的点: Z ∗ = arg min Z B ( X , D ⋅ Z ) \begin{aligned} Z^* = {\arg\min}_Z B(X,D \cdot Z) \end{aligned} Z∗=argminZB(X,D⋅Z) s . t . S ( Z ) < = u \begin{aligned} s.t.S(Z) <= u \end{aligned} s.t.S(Z)<=u
使用罚函数法把上述两个问题都可以转化为如下LASSO格式: Z ∗ = arg min Z B ( X , D ⋅ Z ) + λ S ( Z ) \begin{aligned} Z^* = {\arg\min}_Z B(X,D \cdot Z) + \lambda S(Z) \end{aligned} Z∗=argminZB(X,D⋅Z)+λS(Z)
这就是我们接下来要优化的问题了。迭代软阈值算法
软阈值函数
h θ ( x ) = s i g n ( x ) × m a x ( a b s ( x ) − θ , 0 ) h_\theta(x) = sign(x) \times max(abs(x)-\theta, 0) hθ(x)=sign(x)×max(abs(x)−θ,0)
Other`s Description about Soft Thresholding: https://blog.csdn.net/jbb0523/article/details/52103257
ISTA
由LASSO问题的解形式可以得到( Z 0 = 0 ⃗ Z_0=\vec 0 Z0=0):
Z t + 1 = Z t − 1 L W d T ( W d Z t − X ) = 1 L W d T X + ( I − 1 L W d T W d ) Z t \begin{aligned} Z_{t+1} = Z_t - \frac{1}{L}W_d^T(W_dZ_t-X) \\ = \frac{1}{L}W_d^TX+(I-\frac{1}{L}W_d^TW_d)Z_t \end{aligned} Zt+1=Zt−L1WdT(WdZt−X)=L1WdTX+(I−L1WdTWd)Zt
若取
S = I − 1 L W d T W d W e = 1 L W d T L ≥ r a n k ( W d T W d ) S = I - \frac{1}{L}W_d^TW_d\\ W_e = \frac{1}{L}W_d^T\\ L \ge rank(W_d^TW_d) S=I−L1WdTWdWe=L1WdTL≥rank(WdTWd)
则迭代公式可化为:
Z t + 1 = W e X + S Z t \begin{aligned} Z_{t+1} = W_eX+SZ_t \end{aligned} Zt+1=WeX+SZt
若每一次迭代后经过一次激活则有:
Z t + 1 = h θ ( W e X + S Z t ) \begin{aligned} Z_{t+1} = h_\theta(W_eX+SZ_t) \end{aligned} Zt+1=hθ(WeX+SZt)
则有如下算法模型(RNN):
python 实现:
in ista.py
from utils import sh
import numpy as np
class ISTA:
_w_d = np.asmatrix([])
_lambda = 0
_l = 0
_alpha = 0
'''
init(wd, lam, l)
wd 字典 wd
lam 系数 lambda
l 常数 l
'''
def __init__(self, wd, lam, lip, alpha):
self._w_d = np.asmatrix(wd)
self._lambda = lam
eig, eig_vs = np.linalg.eig(np.dot(wd.T, wd))
r = np.max(eig)
if r > lip:
print('L is not suitable where l = %f but eig_max(wd) = %f' % (lip, r))
print('now L is changed to eig_max(wd) + 1 which larger than eig_max(wd)')
lip = r + 1
del eig, eig_vs
self._l = lip
self._alpha = alpha
self.we = self._w_d.T / self._l
self.beta = self._alpha / self._l
'''
y,e = do_train(x, eps, itm)
x 原向量 x
eps 误差限 epsilon
itm 最大迭代次数 iterate_times_max
'''
def _work(self, x, eps):
z = np.zeros((self._w_d.shape[1], 1))
it = 0
err_t = []
while True:
it += 1
t = np.dot(self._w_d, z) - x
z1 = sh(z - self.we * t, self.beta)
err = np.linalg.norm(z - z1)
err_t.append(err)
if err < eps:
break
z = z1
return z, it, np.asarray(err_t)
def do_work(self, args):
assert args.__len__() == 2
return self._work(args[0], args[1])
in utils.py
import numpy as np
def sh(x, theta):
return np.multiply(np.sign(x), np.maximum(np.abs(x) - theta, 0))
def model_work(model, *args):
return model.do_work(args);
in entrance.py
from utils import model_train, model_work
from ista import ISTA
import numpy as np
import tensorflow as tf
from scipy.linalg import orth
def get_wd(m, n):
psi = np.eye(m)
phi = np.random.randn(n, m)
phi = np.transpose(orth(np.transpose(phi)))
return np.dot(phi, psi)
def get_x_z(m, k, wd):
z = np.zeros([m, 1])
ind = np.random.choice(a=m, size=k, replace=False, p=None)
z[ind, 0] = np.random.randn(1, k) * 10
return np.dot(wd, z), z
def call_ista(wd, lam, lip, alpha, x, eps):
model = ISTA(wd, lam, lip, alpha)
return model_work(model, x, eps)
def test_ista(m, n, k, wd, x, z, lam, lip, alpha, eps):
zr, it, err = call_ista(wd, lam, lip, alpha, x, eps)
with open('ista.txt', 'w') as f:
for i in range(m):
f.write('%03.3f %03.3f\n' % (z[i, 0], zr[i, 0]))
print(it)
print(err)
def train_lista(m, n, k, wd, lam, L, alpha, eps, times):
# model = Lista(...)
for i in range(times):
x, z = get_x_z(m, k, wd)
# train_model(model,x,z,T)
pass
def main():
m, n, k = 1024, 256, 8
wd = get_wd(m, n)
x, z = get_x_z(m, k, wd)
L = 2
lam = 0.1
alpha = 0.1
eps = 0.001
test_ista(m, n, k, wd, x, z, lam, L, alpha, eps)
if __name__ == '__main__':
main()
matlab代码
% CSDN不支持matlab代码,这里使用lua近似替代,可能有显示问题
% author sunwei
% at 2020.10.11
function z = sh(beta, theta)
% sh为软阈值函数简写
% 传入一个向量beta,一个阈值theta
% z 为软阈值变换的结果
z = sign(beta).*max(abs(beta)-theta,0);
end
function [x,z] = get_x_z(m,k,wd)
% 随机信号生成
% z为`稀疏信号`
% x为`原始信号`
% 为方便验证,实际上原始信号通过稀疏信号生成
z = zeros(m,1);
ind = randperm(m);
ind = ind(1:k);
z(ind) = randn(1,k) * 10;
x = wd*z;
end
function [zr, it] = ista(wd, L, alpha, x, eps)
% wd 字典
% alpha sh参数的一部分
% L 李普希斯常数(一个大于wd'*wd)的常数
% x 得到的信号
% eps 误差
[~,n] = size(wd);
z = zeros(n,1);
it = 0;
while true
t = z - 1/L*wd'*(wd*z-x);
zr = sh(t, alpha/L);
it = it + 1;
if((z-zr)'*(z-zr) < eps) break; end
z = zr;
end
end
function test_ista()
m = 1024; n = 256; k = 6;
wd = randn(n,m);
wd = orth(wd')';
[x, z] = get_x_z(m,k,wd);
eig_val = eig(wd'*wd);
L = max(eig_val) + 1;
lam = 0.1;
alpha = 0.1;
eps = 0.001;
[zr, it] = ista(wd, L, alpha, x, eps);
t = 1:m;
plot(t,z,t,zr)
fprintf('it = %d, err = %d', it, (z-zr)'*(z-zr));
end
补充:
- 下一篇:LISTA 基于学习的迭代压缩软阈值算法(Paper: Learning Fast Approximations of Sparse Coding)
- 关于稀疏表示可以看一看Coursera上的https://www.coursera.org/learn/image-processing,Duke大学的Professor还是厉害的。
python fprintf('it = %d, err = %d', it, (z-zr)'*(z-zr));
一句有问题,err应该是 稀疏性提供的误差+保真度提供的误差