这是 python 中美白图像的正确方法吗?
Is this the correct way of whitening an image in python?
我正在尝试 zero-center
和 whiten
CIFAR10
数据集,但我得到的结果看起来像随机噪声!
Cifar10
数据集包含 60,000
个大小为 32x32
的彩色图像。训练集包含 50,000
和测试集分别包含 10,000
图像。
以下代码片段显示了我为使数据集变白所做的过程:
# 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
输出:
cov.shape = (3072L, 3072L)
(3072L, 3072L) (3072L,) (3072L, 3072L)
(50000L, 3072L)
(50000L, 32L, 32L, 3L)
(32L, 32L, 3L)
并尝试显示生成的图像:
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()
顺便说一句 data_train[0].shape
是 (3,32,32)
,
但是如果我根据我得到
重塑变白的图像
TypeError: Invalid dimensions for image data
这可能只是一个可视化问题吗?如果是这样,我怎么能确定是这样呢?
更新:
感谢@AndrasDeak,我以这种方式修复了可视化代码,但输出看起来仍然是随机的:
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])
更新二:
这是我 运行 下面给出的一些命令时得到的:
如下图所示,toimage 可以很好地显示图像,但试图重塑它会弄乱图像。
# 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()
出于某种奇怪的原因,这是我一开始得到的,但在几次尝试之后,它变成了以前的图像。
让我们来看看这个。正如您所指出的,CIFAR 包含存储在矩阵中的图像;每个图像是一行,每行有 3072 列 uint8
数字 (0-255)。图像为 32x32 像素,像素为 RGB(三通道颜色)。
# 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)
事实证明,列的排序有点有趣:所有红色像素值排在第一位,然后是所有绿色像素,然后是所有蓝色像素。这使得查看图像变得棘手。这个:
import matplotlib.pyplot as plt
plt.imshow(X[6].reshape(32,32,3))
plt.show()
给出这个:
所以,为了便于查看,让我们用 reshape
和 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)
现在:
plt.imshow(X[6].reshape(32,32,3))
plt.show()
给出:
好的,开始ZCA美白。我们经常被提醒,在美化数据之前 zero-center 数据非常重要。在这一点上,对您包含的代码进行观察。据我所知,计算机视觉将颜色通道视为另一个特征维度;图像中单独的 RGB 值没有什么特别之处,就像单独的像素值没有什么特别之处一样。它们都只是数字特征。因此,当您计算平均像素值时,考虑到颜色通道(即,您的 mean
是 r,g,b
值的元组),我们将只计算平均值 image值。注意 X
是一个 N 行 3072 列的大矩阵。我们会将每一列视为 "the same kind of thing" 与其他每一列一样。
# zero-centre the data (this calculates the mean separately across
# pixels and colour channels)
X = X - X.mean(axis=0)
在这一点上,让我们也做全局对比度归一化,它经常应用于图像数据。我将使用 L2 范数,它使每个图像的矢量幅度为 1:
X = X / np.sqrt((X ** 2).sum(axis=1))[:,None]
人们可以很容易地使用其他东西,比如标准偏差 (X = X / np.std(X, axis=0)
) 或 min-max 缩放到某个区间,比如 [-1,1]。
快到了。在这一点上,我们还没有大幅修改我们的数据,因为我们只是移动和缩放它(线性变换)。为了显示它,我们需要将图像数据返回到 [0,1] 范围内,所以让我们使用辅助函数:
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])
孔雀在这里看起来稍微亮一些,但这只是因为我们拉伸了它的像素值以填充区间 [0,1]:
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)
正在看(show(zca[6])
):
现在的孔雀肯定不一样了。你可以看到 ZCA 已经通过颜色 space 旋转了图像,所以它看起来像是旧电视上的图片,色调设置不正常。不过还是能认出来。
大概是因为我使用了 epsilon
值,转换后的数据的协方差不完全相同,但相当接近:
>>> (np.cov(zca, rowvar=True).argmax(axis=1) == np.arange(zca.shape[0])).all()
True
1 月 29 日更新
我不太确定如何解决您遇到的问题;目前您的问题似乎出在原始数据的形状上,所以我建议您先解决这个问题,然后再尝试继续 zero-centring 和 ZCA。
一方面,您更新的四个图中的第一个图看起来不错,表明您以正确的方式加载了 CIFAR 数据。我认为第二个图是由 toimage
生成的,它会自动找出哪个维度具有颜色数据,这是一个很好的技巧。另一方面,在那之后的东西看起来很奇怪,所以好像哪里出了问题。我承认我不能完全理解你脚本的状态,因为我怀疑你正在交互式工作(笔记本),当它们不起作用时重试(稍后详细介绍),并且你正在使用代码你没有在你的问题中显示。特别是,我不确定您是如何加载 CIFAR 数据的;您的屏幕截图显示了一些 print
语句(Reading training data...
等)的输出,然后当您将 train_data
复制到 X
并打印 shape
时 X
,形状已经重塑为(N, 3, 32, 32)
。就像我说的那样,更新图 1 往往表明重塑已正确发生。从图 3 和图 4 中,我认为您在某处混淆了矩阵维度,所以我不确定您是如何进行重塑和转置的。
请注意,由于以下原因,请务必小心重塑和转置。 X = X.reshape(...)
和 X = X.transpose(...)
代码正在原地 修改矩阵 。如果你多次这样做(就像在 jupyter notebook 中不小心发生的那样),你将一遍又一遍地打乱矩阵的轴,并且绘制数据将开始看起来非常奇怪。此图显示了我们迭代重塑和转置操作时的进展:
这个进程不会向后循环,或者至少不会快速循环。由于数据的周期性规律(例如图像的 32 像素行结构),您往往会在这些不正确的 reshape-transposed 图像中出现条带。我想知道这是否是你更新中四个情节中的第三个发生的事情,看起来少了很多 radom 比你问题的原始版本中的图像。
你更新的第四张图是孔雀的彩色负片。我不确定你是怎么得到的,但我可以通过以下方式重现你的输出:
plt.imshow(255 - X[6].reshape(32,32,3))
plt.show()
给出:
如果您使用我的 show
辅助函数,并且您混淆了 m
和 M
,那么您可以获得此信息的一种方法是:
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()
我遇到了同样的问题:生成的预测值不正确:
对于每个
,浮点图像的值应为 [0-1.0]
def toimage(data):
min_ = np.min(data)
max_ = np.max(data)
return (data-min_)/(max_ - min_)
注意:此功能仅用于可视化!
但是请注意 "decorrelation" 或 "whitening" 矩阵是如何计算的 @wildwilhelm
zca_matrix = np.dot(U, np.dot(np.diag(1.0/np.sqrt(S + epsilon)), U.T))
这是因为相关矩阵的特征向量的 U 矩阵实际上是这个:SVD(X) = U,S,V 但 U 是 X*X 而不是 X 的 EigenBase https://en.wikipedia.org/wiki/Singular-value_decomposition
最后一点,我宁愿只将像素和 RGB 通道作为模态来考虑统计单位,而不是将图像作为统计单位,将像素作为模态。
我已经在 CIFAR 10 数据库上试过了,效果很好。
图像示例:顶部图像具有 RGB 值 "withened",底部是原始图像
图像示例 2:在训练和损失中没有 ZCA 转换性能
图像示例 3:ZCA 变换在训练和损失中的表现
如果你想线性缩放图像以具有零均值和单位范数,你可以像 Tensofrlow tf.image.per_image_standardization
一样进行图像白化。在文档之后,您需要使用以下公式独立规范化每个图像:
(image - image_mean) / max(image_stddev, 1.0/sqrt(image_num_elements))
请记住,mean
和 standard deviation
应该针对图像中的 所有值 进行计算。这意味着我们不需要指定计算它们的 axis/axes。
在没有 Tensorflow 的情况下实现的方法是使用 numpy
如下:
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
我正在尝试 zero-center
和 whiten
CIFAR10
数据集,但我得到的结果看起来像随机噪声!
Cifar10
数据集包含 60,000
个大小为 32x32
的彩色图像。训练集包含 50,000
和测试集分别包含 10,000
图像。
以下代码片段显示了我为使数据集变白所做的过程:
# 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
输出:
cov.shape = (3072L, 3072L)
(3072L, 3072L) (3072L,) (3072L, 3072L)
(50000L, 3072L)
(50000L, 32L, 32L, 3L)
(32L, 32L, 3L)
并尝试显示生成的图像:
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()
顺便说一句 data_train[0].shape
是 (3,32,32)
,
但是如果我根据我得到
TypeError: Invalid dimensions for image data
这可能只是一个可视化问题吗?如果是这样,我怎么能确定是这样呢?
更新:
感谢@AndrasDeak,我以这种方式修复了可视化代码,但输出看起来仍然是随机的:
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])
更新二:
这是我 运行 下面给出的一些命令时得到的:
如下图所示,toimage 可以很好地显示图像,但试图重塑它会弄乱图像。
# 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()
出于某种奇怪的原因,这是我一开始得到的,但在几次尝试之后,它变成了以前的图像。
让我们来看看这个。正如您所指出的,CIFAR 包含存储在矩阵中的图像;每个图像是一行,每行有 3072 列 uint8
数字 (0-255)。图像为 32x32 像素,像素为 RGB(三通道颜色)。
# 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)
事实证明,列的排序有点有趣:所有红色像素值排在第一位,然后是所有绿色像素,然后是所有蓝色像素。这使得查看图像变得棘手。这个:
import matplotlib.pyplot as plt
plt.imshow(X[6].reshape(32,32,3))
plt.show()
给出这个:
所以,为了便于查看,让我们用 reshape
和 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)
现在:
plt.imshow(X[6].reshape(32,32,3))
plt.show()
给出:
好的,开始ZCA美白。我们经常被提醒,在美化数据之前 zero-center 数据非常重要。在这一点上,对您包含的代码进行观察。据我所知,计算机视觉将颜色通道视为另一个特征维度;图像中单独的 RGB 值没有什么特别之处,就像单独的像素值没有什么特别之处一样。它们都只是数字特征。因此,当您计算平均像素值时,考虑到颜色通道(即,您的 mean
是 r,g,b
值的元组),我们将只计算平均值 image值。注意 X
是一个 N 行 3072 列的大矩阵。我们会将每一列视为 "the same kind of thing" 与其他每一列一样。
# zero-centre the data (this calculates the mean separately across
# pixels and colour channels)
X = X - X.mean(axis=0)
在这一点上,让我们也做全局对比度归一化,它经常应用于图像数据。我将使用 L2 范数,它使每个图像的矢量幅度为 1:
X = X / np.sqrt((X ** 2).sum(axis=1))[:,None]
人们可以很容易地使用其他东西,比如标准偏差 (X = X / np.std(X, axis=0)
) 或 min-max 缩放到某个区间,比如 [-1,1]。
快到了。在这一点上,我们还没有大幅修改我们的数据,因为我们只是移动和缩放它(线性变换)。为了显示它,我们需要将图像数据返回到 [0,1] 范围内,所以让我们使用辅助函数:
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])
孔雀在这里看起来稍微亮一些,但这只是因为我们拉伸了它的像素值以填充区间 [0,1]:
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)
正在看(show(zca[6])
):
现在的孔雀肯定不一样了。你可以看到 ZCA 已经通过颜色 space 旋转了图像,所以它看起来像是旧电视上的图片,色调设置不正常。不过还是能认出来。
大概是因为我使用了 epsilon
值,转换后的数据的协方差不完全相同,但相当接近:
>>> (np.cov(zca, rowvar=True).argmax(axis=1) == np.arange(zca.shape[0])).all()
True
1 月 29 日更新
我不太确定如何解决您遇到的问题;目前您的问题似乎出在原始数据的形状上,所以我建议您先解决这个问题,然后再尝试继续 zero-centring 和 ZCA。
一方面,您更新的四个图中的第一个图看起来不错,表明您以正确的方式加载了 CIFAR 数据。我认为第二个图是由 toimage
生成的,它会自动找出哪个维度具有颜色数据,这是一个很好的技巧。另一方面,在那之后的东西看起来很奇怪,所以好像哪里出了问题。我承认我不能完全理解你脚本的状态,因为我怀疑你正在交互式工作(笔记本),当它们不起作用时重试(稍后详细介绍),并且你正在使用代码你没有在你的问题中显示。特别是,我不确定您是如何加载 CIFAR 数据的;您的屏幕截图显示了一些 print
语句(Reading training data...
等)的输出,然后当您将 train_data
复制到 X
并打印 shape
时 X
,形状已经重塑为(N, 3, 32, 32)
。就像我说的那样,更新图 1 往往表明重塑已正确发生。从图 3 和图 4 中,我认为您在某处混淆了矩阵维度,所以我不确定您是如何进行重塑和转置的。
请注意,由于以下原因,请务必小心重塑和转置。 X = X.reshape(...)
和 X = X.transpose(...)
代码正在原地 修改矩阵 。如果你多次这样做(就像在 jupyter notebook 中不小心发生的那样),你将一遍又一遍地打乱矩阵的轴,并且绘制数据将开始看起来非常奇怪。此图显示了我们迭代重塑和转置操作时的进展:
这个进程不会向后循环,或者至少不会快速循环。由于数据的周期性规律(例如图像的 32 像素行结构),您往往会在这些不正确的 reshape-transposed 图像中出现条带。我想知道这是否是你更新中四个情节中的第三个发生的事情,看起来少了很多 radom 比你问题的原始版本中的图像。
你更新的第四张图是孔雀的彩色负片。我不确定你是怎么得到的,但我可以通过以下方式重现你的输出:
plt.imshow(255 - X[6].reshape(32,32,3))
plt.show()
给出:
如果您使用我的 show
辅助函数,并且您混淆了 m
和 M
,那么您可以获得此信息的一种方法是:
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()
我遇到了同样的问题:生成的预测值不正确:
对于每个
,浮点图像的值应为 [0-1.0]def toimage(data):
min_ = np.min(data)
max_ = np.max(data)
return (data-min_)/(max_ - min_)
注意:此功能仅用于可视化!
但是请注意 "decorrelation" 或 "whitening" 矩阵是如何计算的 @wildwilhelm
zca_matrix = np.dot(U, np.dot(np.diag(1.0/np.sqrt(S + epsilon)), U.T))
这是因为相关矩阵的特征向量的 U 矩阵实际上是这个:SVD(X) = U,S,V 但 U 是 X*X 而不是 X 的 EigenBase https://en.wikipedia.org/wiki/Singular-value_decomposition
最后一点,我宁愿只将像素和 RGB 通道作为模态来考虑统计单位,而不是将图像作为统计单位,将像素作为模态。 我已经在 CIFAR 10 数据库上试过了,效果很好。
图像示例:顶部图像具有 RGB 值 "withened",底部是原始图像
图像示例 2:在训练和损失中没有 ZCA 转换性能
图像示例 3:ZCA 变换在训练和损失中的表现
如果你想线性缩放图像以具有零均值和单位范数,你可以像 Tensofrlow tf.image.per_image_standardization
一样进行图像白化。在文档之后,您需要使用以下公式独立规范化每个图像:
(image - image_mean) / max(image_stddev, 1.0/sqrt(image_num_elements))
请记住,mean
和 standard deviation
应该针对图像中的 所有值 进行计算。这意味着我们不需要指定计算它们的 axis/axes。
在没有 Tensorflow 的情况下实现的方法是使用 numpy
如下:
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