如何规范化 4D numpy 数组?

Posted

技术标签:

【中文标题】如何规范化 4D numpy 数组?【英文标题】:How to normalize a 4D numpy array? 【发布时间】:2017-07-16 13:25:15 【问题描述】:

我有一个三维 numpy 图像数组 (CIFAR-10 dataset)。图像数组形状如下:

a = np.random.rand(32, 32, 3)

在进行任何深度学习之前,我想对数据进行标准化以获得更好的结果。使用一维数组,我知道我们可以像这样进行最小最大归一化:

v = np.random.rand(6)
(v - v.min())/(v.max() - v.min())

Out[68]:
array([ 0.89502294,  0.        ,  1.        ,  0.65069468,  0.63657915,
        0.08932196])

但是,当涉及到 3D 阵列时,我完全迷失了。具体来说,我有以下问题:

    我们沿哪个轴取最小值和最大值? 我们如何使用 3D 数组实现这一点?

感谢您的帮助!


编辑: 事实证明,我需要使用形状为(202, 32, 32, 3) 的 4D Numpy 数组,因此第一个维度将是图像的索引,最后 3 个维度是实际图像。如果有人可以为我提供规范化这样一个 4D 数组的代码,那就太好了。谢谢!


编辑 2: 感谢@Eric 下面的代码,我已经弄清楚了:

x_min = x.min(axis=(1, 2), keepdims=True)
x_max = x.max(axis=(1, 2), keepdims=True)

x = (x - x_min)/(x_max-x_min)

【问题讨论】:

您的堆栈是 4d (image# x X x Y x RGB) 还是 3d (image# x X x Y)? 【参考方案1】:

这里有不同的方法。您可以决定对整批图像进行归一化,也可以对单个图像进行归一化。为此,您可以使用单个图像的平均值或使用整批图像的平均值或使用来自另一个数据集的固定平均值 - 例如您可以使用ImageNet 平均值。

如果您想像 Tensorflow 的 tf.image.per_image_standardization 那样做同样的事情,您应该使用该图像的平均值对每个图像进行归一化。因此,您遍历所有图像并对单个图像中的所有轴进行标准化,如下所示:

import math
import numpy as np
from PIL import Image

# open images
image_1 = Image.open("your_image_1.jpg")
image_2 = Image.open("your_image_2.jpg")
images = [image_1, image_2]
images = np.array(images)
standardized_images = []

# standardize images
for image in images:
    mean = image.mean()
    stddev = image.std()
    adjusted_stddev = max(stddev, 1.0/math.sqrt(image.size))
    standardized_image = (image - mean) / adjusted_stddev
    standardized_images.append(standardized_image)

standardized_images = np.array(standardized_images)

【讨论】:

【参考方案2】:

假设您正在处理形状为 (W, H, 3) 的图像数据,您可能应该分别对每个通道 (axis=2) 进行归一化,如另一个答案中所述。

你可以这样做:

# keepdims makes the result shape (1, 1, 3) instead of (3,). This doesn't matter here, but
# would matter if you wanted to normalize over a different axis.
v_min = v.min(axis=(0, 1), keepdims=True)
v_max = v.max(axis=(0, 1), keepdims=True)
(v - v_min)/(v_max - v_min)

【讨论】:

感谢您的回复!我实际上需要使用 4D 数组(我已经更新了我的帖子)。您能否提供进一步的指导? 感谢您的代码,我已经弄清楚了如何做到这一点! @George:是的,您所拥有的是正确的 - 您正在为每个图像和通道(轴 0 和 3)在 x 和 y(轴 1 和 2)上取最大值【参考方案3】:
    我们沿哪个轴取最小值和最大值?

要回答这个问题,我们可能需要有关您的数据的更多信息,但一般来说,例如,在讨论 3 通道图像时,我们会使用每个通道的最小值和最大值进行归一化。这意味着我们将执行 3 次归一化 - 每个通道一次。 这是一个例子:

    img = numpy.random.randint(0, 100, size=(10, 10, 3))  # Generating some random numbers
    img = img.astype(numpy.float32)  # converting array of ints to floats
    img_a = img[:, :, 0]
    img_b = img[:, :, 1]
    img_c = img[:, :, 2]  # Extracting single channels from 3 channel image
    # The above code could also be replaced with cv2.split(img) << which will return 3 numpy arrays (using opencv)

    # normalizing per channel data:
    img_a = (img_a - numpy.min(img_a)) / (numpy.max(img_a) - numpy.min(img_a))
    img_b = (img_b - numpy.min(img_b)) / (numpy.max(img_b) - numpy.min(img_b))
    img_c = (img_c - numpy.min(img_c)) / (numpy.max(img_c) - numpy.min(img_c))

    # putting the 3 channels back together:
    img_norm = numpy.empty((10, 10, 3), dtype=numpy.float32)
    img_norm[:, :, 0] = img_a
    img_norm[:, :, 1] = img_b
    img_norm[:, :, 2] = img_c

编辑:我突然想到,一旦你有了一个通道数据(例如 32x32 图像),你就可以简单地使用:

from sklearn.preprocessing import normalize
img_a_norm = normalize(img_a)
    我们如何使用 3D 阵列?

嗯,这是一个有点大的问题。如果您需要像数组方式的 min 和 max 这样的函数,我会使用 Numpy 版本。例如,索引是通过轴范围的分隔符实现的——从我上面的示例中可以看出。 另外,请参考 Numpy 的 ndarray 文档@https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html 了解更多。他们真的有一套很棒的用于 n 维数组的工具。

【讨论】:

这是错误的标准化方式,你必须从最大值中减去最小值。即img_a = (img_a - numpy.min(img_a)) / (numpy.max(img_a) - numpy.min(img_a)) 确保括号正确 @smttsp 你说得对,我打错了,修正了我原来的答案。谢谢。 “我们将执行 3 次归一化 - 每个通道一次” - 正确,但这更好地表示为 “归一化axis=-1”我>。无需为每个频道重复一次您的代码 r, g, b = cv2.split(img)也可以写成r, g, b = np.moveaxis(img, -1, 0) 感谢您的回复!我实际上需要使用 4D 数组(我已经更新了我的帖子)。您能否提供进一步的指导?

以上是关于如何规范化 4D numpy 数组?的主要内容,如果未能解决你的问题,请参考以下文章

规范化python中的numpy数组列

如何将 4D numpy 数组重塑为 3D 数组

将 NumPy 数组转换为带有列的 Pandas 数据框

将 NumPy 数组转换为带有列的 Pandas 数据框

如何规范化词嵌入(word2vec)

numpy入门