web-dev-qa-db-fra.com

Comment normaliser un tableau 4D numpy?

J'ai un tableau d'images numpy en trois dimensions ( CIFAR-10 dataset ). La forme du tableau d'images est comme ci-dessous:

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

Avant de procéder à un apprentissage approfondi, je souhaite normaliser les données pour obtenir de meilleurs résultats. Avec un tableau 1D, je sais que nous pouvons faire une normalisation min max comme ceci:

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])

Cependant, quand il s'agit d'un tableau 3D, je suis totalement perdu. Plus précisément, j'ai les questions suivantes:

  1. Sur quel axe prenons-nous le min et le max?
  2. Comment pouvons-nous implémenter cela avec la matrice 3D?

J'apprécie ton aide!


EDIT: Il s’avère que j’ai besoin de travailler avec un tableau 4D Numpy de forme (202, 32, 32, 3), de sorte que la première dimension serait l’index de l’image et les 3 dernières dimensions l’image réelle. Ce sera formidable si quelqu'un peut me fournir le code pour normaliser un tel tableau 4D. Merci!


EDIT 2: Merci au code de @ Eric ci-dessous, je l'ai compris:

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)
13
George Liu

En supposant que vous travailliez avec des données d'image de forme (W, H, 3), vous devriez probablement normaliser séparément sur chaque canal (axis=2) séparément, comme indiqué dans l'autre réponse.

Vous pouvez le faire avec:

# 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)
14
Eric
  1. Sur quel axe prenons-nous le min et le max?

Pour répondre à cette question, nous avons probablement besoin de plus d'informations sur vos données, mais en général, lorsque vous parlez d'images 3 canaux, par exemple, nous normaliserions l'utilisation des valeurs min et max par canal. cela signifie que nous effectuerions la normalisation trois fois - une fois par canal ... Voici un exemple:

    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

Edit: Je viens de penser qu’une fois que vous avez les données d’un canal (image 32x32 par exemple), vous pouvez simplement utiliser:

from sklearn.preprocessing import normalize
img_a_norm = normalize(img_a)
  1. Comment travaillons-nous avec le tableau 3D?

Eh bien, c’est une grosse question. Si vous avez besoin de fonctions telles que min et max, utilisez les versions Numpy. L'indexation, par exemple, est réalisée à l'aide de séparateurs d'axe - comme vous pouvez le constater dans l'exemple ci-dessus. Veuillez également consulter la documentation de Numpy sur ndarray @ https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html Pour en savoir plus. ils ont vraiment un ensemble incroyable d’outils pour les tableaux à n dimensions.

3
antonmik

Il y a différentes approches ici. Vous pouvez soit décider de normaliser l’ensemble du lot d’images, soit normaliser chaque image. Pour ce faire, vous pouvez soit utiliser la moyenne d'une seule image, soit la moyenne de l'ensemble du lot d'images, soit utiliser une moyenne fixe d'un autre jeu de données, par exemple vous pouvez utiliser la valeur moyenne ImageNet

Si vous voulez faire la même chose que tf.image.per_image_standardization de Tensorflow, vous devez normaliser chaque image avec la moyenne de cette image. Donc, vous parcourez toutes les images et effectuez la normalisation de tous les axes dans une seule image, comme ceci:

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)
0
tsveti_iko