问题
While using zca_whitening
, my code gets stuck somewhere, neither it shows any error nor the output. When i skip the zca_whitening
and apply other transformations, the code runs perfectly. I am attaching the code snippet here. Pl help me if I am doing anything wrong here :
datagen = ImageDataGenerator(zca_whitening=True)
datagen.fit(x_train)
where >> x_train
is the set of training images (dim = 50 x 64 x 64 x 3) . After running datagen.fit
, the code shows no further output or error, seems to have the process running for an infinite time period.
on the other hand these transformations work perfectly :
datagen = ImageDataGenerator(rotation_range=0.90,
width_shift_range=0.2,
height_shift_range=0.2,
fill_mode='nearest',
horizontal_flip=True,
vertical_flip=True)
datagen.fit(x_train)
Is there anything I am missing here?
回答1:
Modify x_train
to have shape (3, 64, 64).
You can do that by using the following code: x_train = x_train.transpose((2,1,0))
This is mainly due to the switching between theano and tensorflow backend. Check dim_order
in Keras documentation.
回答2:
I disagree with @Avjiit that the problem is due to wrong shape. The problem is common and as confirmed by the keras main contributors the problem is that the zca-calculation takes very, very long, because it uses numpy.linalg.svd()
which is computationally heavy even on matrices (n*m*3), n~m~100.
There are some approaches to calculate a quick approximation of the svd, like randomized svd by scikitlearn, truncated svd by irlb, Lanczos method svd, but they are not always numerically stable.
I think I have found another very simple approximation, that appears to give good enough results and is very quick! It helps in case you have a data matrix with shape (m x n), where m is much smaller than n - e.g. you have much less images (m~1000) than number of pixels (n~100 x 100 x 3 = 30000 pixel). In such a case keras would calculate the linalg.svd(sigma)
, with sigma.shape=(30000,30000)
, which is computationally too exhausting and takes forever. But in a good approximation, instead of calculating the svd on a (n x n) matrix you could calculate it on a (m x m) matrix, by just rotating the input data X or flipping the order of the sigma
calculation to look like sigma = np.dot(flat_x, flat_x.T) / flat_x.shape[0]
. With this approach the calculation takes only ca. 10 sec, if m~1000 and n~30000. The good thing is that the eigenvectors of the linalg.svd(sigma)
are the same in both cases up to a factor, see here, slide 30. You could test this on a dataset of yours or on the inbuilt cifer set with from keras.datasets import cifar10
.
Unfortunately, I don't have the mathematical argumentation of this approach, but I have done visual inspections of the zca-images from both calculations and they look very similar:
And below is the modified keras code for creating the zca calculations. You could use it to make modifications into your keras zca code, located here: There are only 2 modifications I have made that get activated if zca_rotated=True
:
from keras.datasets import cifar10
import numpy as np
from scipy import linalg
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
X = X_train[:1000]
flat_x = np.reshape(x, (x.shape[0], x.shape[1] * x.shape[2] * x.shape[3]))
# line below lets you choose if you want to calculate the standard zca, like in keras (=False)
# or if you want to treat the input data X as rotated to simplify the calculation if X.shape[0]=m < X.shape[1]=n
zca_rotated = True
# normalize x:
flat_x = flat_x / 255.
flat_x = flat_x - flat_x.mean(axis=0)
# 1ST CHANGE IN CALCULATION BELOW
if zca_rotated == False:
sigma = np.dot(flat_x.T, flat_x) / flat_x.shape[0]
elif zca_rotated == True:
sigma = np.dot(flat_x, flat_x.T) / flat_x.shape[0]
u, s, _ = linalg.svd(sigma)
s_inv = 1. / np.sqrt(s[np.newaxis] + 0.1) # the 0.1 is the epsilon value for zca
principal_components = (u * s_inv).dot(u.T)
# below is the calculation of the actual zca-image with the fitted parameters from above
# 2ND CHANGE IN LINE BELOW
if zca_rotated == False:
whitex = np.dot(flat_x, principal_components)
elif zca_rotated == True:
whitex = np.dot(flat_x.T, principal_components)
来源:https://stackoverflow.com/questions/40735715/keras-zca-whitening-no-error-no-output-generated