Estoy tratando de zero-center y whiten CIFAR10 conjunto de datos, ¡pero el resultado que obtengo parece ruido aleatorio!
El conjunto de datos Cifar10 contiene 60,000 imágenes en color de tamaño 32x32. El conjunto de entrenamiento contiene 50,000 y el conjunto de prueba contiene 10,000 imágenes respectivamente.
Los siguientes fragmentos de código muestran el proceso que hice para blanquear el conjunto de datos:

# zero-center
mean = np.mean(data_train, axis = (0,2,3)) 
for i in range(data_train.shape[0]):
    for j in range(data_train.shape[1]):
        data_train[i,j,:,:] -= mean[j]

first_dim = data_train.shape[0] #50,000
second_dim = data_train.shape[1] * data_train.shape[2] * data_train.shape[3] # 3*32*32
shape = (first_dim, second_dim) # (50000, 3072) 

# compute the covariance matrix
cov = np.dot(data_train.reshape(shape).T, data_train.reshape(shape)) / data_train.shape[0] 
# compute the SVD factorization of the data covariance matrix
U,S,V = np.linalg.svd(cov)

print 'cov.shape = ',cov.shape
print U.shape, S.shape, V.shape

Xrot = np.dot(data_train.reshape(shape), U) # decorrelate the data
Xwhite = Xrot / np.sqrt(S + 1e-5)

print Xwhite.shape
data_whitened = Xwhite.reshape(-1,32,32,3)
print data_whitened.shape

Salidas:

cov.shape =  (3072L, 3072L)
(3072L, 3072L) (3072L,) (3072L, 3072L)
(50000L, 3072L)
(50000L, 32L, 32L, 3L)
(32L, 32L, 3L)

E intentando mostrar la imagen resultante:

import matplotlib.pyplot as plt
%matplotlib inline
from scipy.misc import imshow
print data_whitened[0].shape
fig = plt.figure()
plt.subplot(221)
plt.imshow(data_whitened[0])
plt.subplot(222)
plt.imshow(data_whitened[100])
plt.show()

enter image description here

Por cierto, data_train[0].shape es (3,32,32), pero si vuelvo a dar forma a la imagen blanqueada de acuerdo con eso me sale

TypeError: Invalid dimensions for image data

¿Podría ser esto solo un problema de visualización? si es así, ¿cómo puedo asegurarme de que ese sea el caso?

Actualización:
Gracias a @AndrasDeak, arreglé el código de visualización de esta manera, pero la salida aún parece aleatoria:

data_whitened = Xwhite.reshape(-1,3,32,32).transpose(0,2,3,1)
print data_whitened.shape
fig = plt.figure()
plt.subplot(221)
plt.imshow(data_whitened[0])

enter image description here

Actualización 2:
Esto es lo que obtengo cuando ejecuto algunos de los comandos dados a continuación: Como se puede ver a continuación, toimage puede mostrar la imagen muy bien, pero al tratar de remodelarla, la imagen se estropea. ingrese la descripción de la imagen aquí

# output is of shape (N, 3, 32, 32)
X = X.reshape((-1,3,32,32))
# output is of shape (N, 32, 32, 3)
X = X.transpose(0,2,3,1)
# put data back into a design matrix (N, 3072)
X = X.reshape(-1, 3072)

plt.imshow(X[6].reshape(32,32,3))
plt.show()

enter image description here

Por alguna extraña razón, esto fue lo que obtuve al principio, pero luego de varios intentos, cambió a la imagen anterior. ingrese la descripción de la imagen aquí

4
Rika 13 ene. 2017 a las 16:28

3 respuestas

La mejor respuesta

Pasemos por esto. Como señala, CIFAR contiene imágenes que se almacenan en una matriz; cada imagen es una fila y cada fila tiene 3072 columnas de números uint8 (0-255). Las imágenes son de 32x32 píxeles y los píxeles son RGB (color de tres canales).

# https://www.cs.toronto.edu/~kriz/cifar.html
# wget https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
# tar xf cifar-10-python.tar.gz
import numpy as np
import cPickle
with open('cifar-10-batches-py/data_batch_1') as input_file: 
    X = cPickle.load(input_file)
X = X['data']   # shape is (N, 3072)

Resulta que las columnas están ordenadas un poco divertidas: todos los valores de píxeles rojos son lo primero, luego todos los píxeles verdes, luego todos los píxeles azules. Esto hace que sea difícil echar un vistazo a las imágenes. Esta:

import matplotlib.pyplot as plt
plt.imshow(X[6].reshape(32,32,3))
plt.show()

Da esto:

Mixed up colour channels

Entonces, solo para facilitar la visualización, barajemos las dimensiones de nuestra matriz con reshape y transpose:

# output is of shape (N, 3, 32, 32)
X = X.reshape((-1,3,32,32))
# output is of shape (N, 32, 32, 3)
X = X.transpose(0,2,3,1)
# put data back into a design matrix (N, 3072)
X = X.reshape(-1, 3072)

Ahora:

plt.imshow(X[6].reshape(32,32,3))
plt.show()

Da:

A peacock

De acuerdo, para blanquear ZCA. Con frecuencia se nos recuerda que es muy importante centrar los datos en cero antes de blanquearlos. En este punto, una observación sobre el código que incluye. Por lo que puedo decir, la visión por computadora ve los canales de color como una dimensión más de la característica; No hay nada especial sobre los valores RGB separados en una imagen, al igual que no hay nada especial sobre los valores de píxeles separados. Todos son solo funciones numéricas. Entonces, mientras calcula el valor promedio de píxeles, respetando los canales de color (es decir, su mean es una tupla de valores r,g,b), solo calcularemos la imagen promedio valor. Tenga en cuenta que X es una matriz grande con N filas y 3072 columnas. Trataremos cada columna como "el mismo tipo de cosas" que cualquier otra columna.

# zero-centre the data (this calculates the mean separately across
# pixels and colour channels)
X = X - X.mean(axis=0)

En este punto, también hagamos la Normalización de contraste global, que a menudo se aplica a los datos de la imagen. Usaré la norma L2, que hace que cada imagen tenga una magnitud vectorial 1:

X = X / np.sqrt((X ** 2).sum(axis=1))[:,None]

Uno podría usar fácilmente otra cosa, como la desviación estándar (X = X / np.std(X, axis=0)) o la escala mínima-máxima a algún intervalo como [-1,1].

Cerca de allí. En este punto, no hemos modificado en gran medida nuestros datos, ya que los hemos cambiado y escalado (una transformación lineal). Para mostrarlo, necesitamos recuperar los datos de la imagen en el rango [0,1], así que usemos una función auxiliar:

def show(i):
    i = i.reshape((32,32,3))
    m,M = i.min(), i.max()
    plt.imshow((i - m) / (M - m))
    plt.show()

show(X[6])

El pavo real se ve ligeramente más brillante aquí, pero eso es solo porque hemos ampliado sus valores de píxeles para llenar el intervalo [0,1]:

Slightly brighter peacock

Blanqueamiento ZCA:

# compute the covariance of the image data
cov = np.cov(X, 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)    # zca is (N, 3072)

Echando un vistazo (show(zca[6])):

"Whitened" peacock

Ahora el pavo real definitivamente se ve diferente. Puede ver que el ZCA ha girado la imagen a través del espacio de color, por lo que se ve como una imagen en un televisor antiguo con el tono fuera de control. Aún reconocible, sin embargo.

Presumiblemente debido al valor epsilon que utilicé, la covarianza de mis datos transformados no es exactamente identidad, pero está bastante cerca:

>>> (np.cov(zca, rowvar=True).argmax(axis=1) == np.arange(zca.shape[0])).all()
True

Actualización 29 de enero

No estoy completamente seguro de cómo resolver los problemas que tienes; Su problema parece estar en la forma de sus datos en bruto en este momento, por lo que le aconsejaría que lo solucione primero antes de intentar pasar a cero centrado y ZCA.

Por un lado, el primer gráfico de los cuatro gráficos en su actualización se ve bien, lo que sugiere que ha cargado los datos CIFAR de la manera correcta. La segunda trama es producida por toimage, creo, que determinará automáticamente qué dimensión tiene los datos de color, lo cual es un buen truco. Por otro lado, las cosas que vienen después de eso se ven raras, por lo que parece que algo va mal en alguna parte. Confieso que no puedo seguir el estado de su script, porque sospecho que está trabajando de manera interactiva (cuaderno), reintentando las cosas cuando no funcionan (más sobre esto en un segundo), y que está usando código que no has mostrado en tu pregunta. En particular, no estoy seguro de cómo está cargando los datos CIFAR; su captura de pantalla muestra el resultado de algunas declaraciones print (Reading training data..., etc.), y luego cuando copia train_data en X e imprime el shape de {{ X6}}, la forma ya ha sido reformada en (N, 3, 32, 32). Como digo, la actualización del gráfico 1 tenderá a sugerir que la remodelación se realizó correctamente. De las parcelas 3 y 4, creo que te estás confundiendo sobre las dimensiones de la matriz en algún lugar, por lo que no estoy seguro de cómo estás reformando y transponiendo.

Tenga en cuenta que es importante tener cuidado con la remodelación y transposición, por la siguiente razón. El código X = X.reshape(...) y X = X.transpose(...) está modificando la matriz en su lugar . Si hace esto varias veces (como por accidente en el cuaderno Jupyter), barajará los ejes de su matriz una y otra vez, y trazar los datos comenzará a verse realmente extraño. Esta imagen muestra la progresión, a medida que iteramos las operaciones de remodelación y transposición:

Increasing iterations of reshape and transpose

Esta progresión no retrocede, o al menos, no retrocede rápidamente. Debido a las regularidades periódicas en los datos (como la estructura de filas de 32 píxeles de las imágenes), tiende a formar bandas en estas imágenes transpuestas de forma inadecuada. Me pregunto si eso es lo que está sucediendo en el tercero de sus cuatro parcelas en su actualización, que se ve mucho menos al azar que las imágenes en la versión original de su pregunta.

La cuarta trama de su actualización es un color negativo del pavo real. No estoy seguro de cómo está obteniendo eso, pero puedo reproducir su salida con:

plt.imshow(255 - X[6].reshape(32,32,3))
plt.show()

Que da:

Colour negative of the peacock

Una forma de obtener esto es si estuviera utilizando mi función de ayuda show, y mezcló m y M, así:

def show(i):
    i = i.reshape((32,32,3))
    m,M = i.min(), i.max()
    plt.imshow((i - M) / (m - M))  # this will produce a negative img
    plt.show()
12
wildwilhelm 29 ene. 2017 a las 17:42

Tuve el mismo problema: los valores proyectados resultantes están apagados:

Se supone que una imagen flotante tiene valores [0-1.0] para cada

def toimage(data):
    min_ = np.min(data)
    max_ = np.max(data)
    return (data-min_)/(max_ - min_)

AVISO: ¡use esta función solo para visualización!

Sin embargo, observe cómo se calcula la matriz de "decorrelación" o "blanqueamiento" @wildwilhelm

zca_matrix = np.dot(U, np.dot(np.diag(1.0/np.sqrt(S + epsilon)), U.T))

Esto se debe a que la matriz U de los vectores propios de la matriz de correlación es en realidad esta: SVD (X) = U, S, V pero U es la EigenBase de X * X no de X https://en.wikipedia.org/wiki/Singular-value_decomposition

Como nota final, preferiría considerar las unidades estadísticas solo los píxeles y los canales RGB sus modalidades en lugar de Imágenes como unidades estadísticas y píxeles como modalidades. He intentado esto en la base de datos CIFAR 10 y funciona bastante bien.

EJEMPLO DE IMAGEN: La imagen superior tiene valores RGB "con", inferior es el original

Image1

EJEMPLO DE IMAGEN2: NO ZCA transforma el rendimiento en el tren y la pérdida

Image2

EJEMPLO DE IMAGEN 3: ZCA transforma el rendimiento en el tren y la pérdida

Image1

2
Stephen Rauch 13 nov. 2017 a las 01:23

Si desea escalar linealmente la imagen para que tenga una media cero y una norma de unidad, puede hacer el mismo blanqueamiento de imagen que el tf.image.per_image_standardization . Después de la documentación, debe usar la siguiente fórmula para normalizar cada imagen de forma independiente :

(image - image_mean) / max(image_stddev, 1.0/sqrt(image_num_elements))

Tenga en cuenta que el mean y el standard deviation deben calcularse sobre todos los valores en la imagen. Esto significa que no necesitamos especificar el eje / ejes a lo largo de los cuales se calculan.

La forma de implementar eso sin Tensorflow es mediante numpy de la siguiente manera:

import math
import numpy as np
from PIL import Image

# open image
image = Image.open("your_image.jpg")
image = np.array(image)

# standardize image
mean = image.mean()
stddev = image.std()
adjusted_stddev = max(stddev, 1.0/math.sqrt(image.size))
standardized_image = (image - mean) / adjusted_stddev
0
tsveti_iko 2 nov. 2018 a las 09:42