稀疏编码是一种信号处理技术,它将信号表示为一组基函数的稀疏组合。在本例中,使用Ricker小波(也称为墨西哥帽或高斯的二阶导数)作为基函数。尽管Ricker小波不是表示像本例中的分段常数信号的最佳核,但通过添加不同宽度的原子,可以看到其对信号表示的影响。这也激发了学习字典以最好地适应信号类型的想法。右侧更丰富的字典在大小上并不更大,而是进行了更重的子采样以保持相同的数量级。
在下面的代码示例中,首先定义了一个函数来生成离散的子采样Ricker(墨西哥帽)小波,然后创建了一个由Ricker小波组成的字典。生成了一个简单的信号,并使用不同的稀疏编码方法对其进行了变换。这些方法包括正交匹配追踪(OMP)和Lasso。还展示了软阈值去偏技术。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import SparseCoder
def ricker_function(resolution, center, width):
""“离散子采样Ricker(墨西哥帽)小波”""
x = np.linspace(0, resolution-1, resolution)
x = (2 / (np.sqrt(3 * width) * np.pi**0.25)) * (1 - ((x - center)**2 / width**2)) * np.exp(-((x - center)**2) / (2 * width**2))
return x
def ricker_matrix(width, resolution, n_components):
""“由Ricker(墨西哥帽)小波组成的字典”""
centers = np.linspace(0, resolution-1, n_components)
D = np.empty((n_components, resolution))
for i, center in enumerate(centers):
D[i] = ricker_function(resolution, center, width)
D /= np.sqrt(np.sum(D**2, axis=1))[:, np.newaxis]
return D
resolution = 1024
subsampling = 3 # 子采样因子
width = 100
n_components = resolution // subsampling # 计算小波字典
# 计算固定宽度的小波字典
D_fixed = ricker_matrix(width=width, resolution=resolution, n_components=n_components)
D_multi = np.r_[
tuple(ricker_matrix(width=w, resolution=resolution, n_components=n_components//5) for w in (10, 50, 100, 500, 1000))
]
# 生成一个信号
y = np.linspace(0, resolution-1, resolution)
first_quarter = y < resolution/4
y[first_quarter] = 3.0
y[np.logical_not(first_quarter)] = -1.0
# 列出不同的稀疏编码方法
estimators = [
("OMP", "omp", None, 15, "navy"),
("Lasso", "lasso_lars", 2, None, "turquoise"),
]
lw = 2
plt.figure(figsize=(13, 6))
for subplot, (D, title) in enumerate(zip((D_fixed, D_multi), ("固定宽度", "多个宽度"))):
plt.subplot(1, 2, subplot + 1)
plt.title("Sparse coding against %s dictionary" % title)
plt.plot(y, lw=lw, linestyle="--", label="原始信号")
# 进行小波近似
for title, algo, alpha, n_nonzero, color in estimators:
coder = SparseCoder(dictionary=D, transform_n_nonzero_coefs=n_nonzero, transform_alpha=alpha, transform_algorithm=algo)
x = coder.transform(y.reshape(1, -1))
density = len(np.flatnonzero(x))
x = np.ravel(np.dot(x, D))
squared_error = np.sum((y - x)**2)
plt.plot(x, color=color, lw=lw, label="%s: %s nonzero coefs,\n%.2f error" % (title, density, squared_error))
# 软阈值去偏
coder = SparseCoder(dictionary=D, transform_algorithm="threshold", transform_alpha=20)
x = coder.transform(y.reshape(1, -1))
_, idx = np.where(x != 0)
x[0, idx], _, _, _ = np.linalg.lstsq(D[idx, :].T, y, rcond=None)
x = np.ravel(np.dot(x, D))
squared_error = np.sum((y - x)**2)
plt.plot(x, color="darkorange", lw=lw, label="Thresholding w/ debiasing:\n%d nonzero coefs, %.2f error" % (len(idx), squared_error))
plt.axis("tight")
plt.legend(shadow=False, loc="best")
plt.subplots_adjust(0.04, 0.07, 0.97, 0.90, 0.09, 0.2)
plt.show()
上述代码展示了如何使用不同的稀疏编码方法来近似一个简单的信号。首先定义了Ricker小波函数和生成Ricker小波字典的函数。然后,生成了一个简单的信号,并使用不同的稀疏编码方法对其进行了变换。这些方法包括正交匹配追踪(OMP)和Lasso。还展示了软阈值去偏技术。通过比较不同方法的结果,可以看到添加不同宽度的原子对信号稀疏表示的影响。