在Numpy中从SVD分解获得负S值?

问题描述 投票:4回答:1

我想使用ZCA对CIFAR10数据集进行白化。输入X_train的形状(40000,32,32,3),其中40000是图像的数量,32x32x3是每个图像的大小。我正在使用this answer的代码来达到这个目的:

X_flat = np.reshape(X_train, (-1, 32*32*3))
# compute the covariance of the image data
cov = np.cov(X_flat, rowvar=True)   # cov is (N, N)
# singular value decomposition
U,S,V = np.linalg.svd(cov)     # U is (N, N), S is (N,)
# build the ZCA matrix
epsilon = 1e-5
zca_matrix = np.dot(U, np.dot(np.diag(1.0/np.sqrt(S + epsilon)), U.T))
# transform the image data       zca_matrix is (N,N)
zca = np.dot(zca_matrix, X_flat)    # zca is (N, 3072)

但是,在运行时我遇到以下警告:

D:\toolkits.win\anaconda3-5.2.0\envs\dlwin36\lib\site- packages\ipykernel_launcher.py:8: RuntimeWarning: invalid value encountered in sqrt

所以在我得到SVD输出后,我尝试了:

print(np.min(S)) # prints -1.7798217

这是意料之外的,因为S只能有正值。此外,ZCA白化结果不正确,它包含nan值。

我尝试通过重新运行相同的代码再次重现这一次,这次我没有遇到任何警告或任何负面的S值,但我得到了:

print(np.min(S)) # prints nan

为什么会发生这种情况的任何想法?


更新:重新启动内核以释放CPU和RAM资源,并尝试再次运行此代码。再次得到相同的警告,以负值向np.sqrt()喂食。不确定它是否有帮助,但我还附加了cpu和ram利用率数据:

activity monitor figures

python numpy linear-algebra svd
1个回答
2
投票

以下是一些想法。我没有你的数据集,所以我不能完全确定这些会解决你的问题,但我有足够的信心发布这个作为答案而不是评论。

第一。你的X_train是40'000到3072,其中每一行是一个数据向量,每列是一个变量或特征。你想要3072乘3072的协方差矩阵:在rowvar=False中传递给np.cov

我不确定为什么40'000到40'000协方差矩阵的SVD正在发散。假设你有足够的RAM来存储12 GB协方差矩阵,我能想到的一件事是数值溢出,因为你可能没有像ZCA(以及任何其他美白技术)所预期的那样去除数据的平均值?

第二个。删除均值:X_zeromean = X_flat - np.mean(X_flat, 0)

如果你这样做,那么必须稍微修改最后一步(使尺寸排列)。这是使用统一随机数据的快速检查:

import numpy as np
X_flat = np.random.rand(40000, 32*32*3)
X_zeromean = X_flat - np.mean(X_flat, 0)
cov = np.cov(X_zeromean, rowvar=False)
U,S,V = np.linalg.svd(cov)
epsilon = 1e-5
zca_matrix = np.dot(U, np.dot(np.diag(1.0/np.sqrt(S + epsilon)), U.T))
zca = np.dot(zca_matrix, X_zeromean.T) # <-- transpose needed here

作为一个完整性检查,np.cov(zca)现在非常接近身份矩阵,因此需要(zca将翻转尺寸作为输入)。

(作为旁注,这是一种非常昂贵且数值不稳定的白化数据阵列的方法:你不需要计算协方差然后采用SVD - 你做了两倍的工作。你可以采取瘦的SVD数据矩阵本身(带有np.linalg.svd标志的full_matrices=False)并直接从那里计算白化矩阵,而无需为协方差矩阵评估昂贵的外积。)

© www.soinside.com 2019 - 2024. All rights reserved.