@dongxi
2017-12-07T21:47:34.000000Z
字数 3416
阅读 1066
数理统计
CS231n
降维
假设说我们有一个矩阵
而奇异值就是为了完成这一过程而诞生的,它的几何意义就是对于任意一个矩阵,找到一组两两正交的单位向量序列,使得经过这一矩阵的转换以后产生的新的向量序列仍然保持两两正交。而奇异值就是指产生新的向量序列的长度。
实际上,矩阵应该就是新的向量序列与原本的正交序列之间的雅各比矩阵。
假设矩阵作用于正交单位向量和上之后,得到的和仍然满足正交条件,如下图所示:
同时用和表示对应方向的单位向量,则会有:
奇异值分解的公式如下:
奇异值的应用也十分广泛,可以用于噪音消除、数据分析、数据压缩等方面,具体可以参考参考条目二。这里我们主要以图片的压缩为例,进行一些简单的理解。我们使用bing的壁纸来做一个简单的实验,以下是这张图片的原图:
通过奇异值分解,我们可以得到这个图片具有个奇异值,我们从中挑选一定数量的奇异值压缩图片,我们从10个奇异值开始:
实际上,只有10个奇异值,也就是全部奇异值的我们就可以看到图片的大致轮廓了,而在50个奇异值的情况下,我们已经可以较清晰的认识到整个图片的样子:
最后,我们选择108个奇异值,也就是全部奇异值的,其实跟原图已经没有很大差别了:
而对于108个奇异值的情况,我们只需要保存个参数,而对于原图我们总共需要保存个参数,压缩以后参数数目减小为了原来的,由此可见压缩效果还是很可观的。
代码如下:
import numpy as np
from PIL import Image
def rebuild_img(u, sigma, v, num):
u_len = len(u)
v_len = len(v)
temp = np.zeros((u_len, v_len))
for k in np.arange(num):
uk = u[:, k].reshape(u_len, 1)
vk = v[k].reshape(1, v_len)
temp += sigma[k] * np.dot(uk, vk)
temp[temp < 0] = 0
temp[temp > 255] = 255
return np.rint(temp).astype('uint8')
if __name__ == '__main__':
img = Image.open('test-2.jpg', 'r')
temp = np.array(img)
u_a, sigma_a, v_a = np.linalg.svd(temp[:, :, 0])
u_g, sigma_g, v_g = np.linalg.svd(temp[:, :, 1])
u_b, sigma_b, v_b = np.linalg.svd(temp[:, :, 2])
print(len(sigma_a))
print(len(u_a))
print(len(v_a))
for num in np.arange(10, 100, 10):
R = rebuild_img(u_a, sigma_a, v_a, num)
G = rebuild_img(u_g, sigma_g, v_g, num)
B = rebuild_img(u_b, sigma_b, v_b, num)
new_img = np.stack((R, G, B), 2)
Image.fromarray(new_img).save('SVD-IMG\\test_' + str(num) + '.jpg')