我想使用 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 利用率数据:
最佳答案
这里有一些想法。我没有你的数据集,所以我不能完全确定这些会解决你的问题,但我有足够的信心将其发布为答案而不是评论。
首先。您的 X_train
是 40'000 x 3072,其中每个行 是一个数据向量,每个列 是一个变量或特征。您需要 3072 x 3072 的协方差矩阵:将 rowvar=False
传递给 np.cov
。
我不太确定为什么 40'000 x 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
标志)并直接从那里计算白化矩阵,而无需评估昂贵的外积为协方差矩阵。)
关于python - 从 Numpy 的 SVD 分解中获得负 S 值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55131665/