9 votes

Comment créer une étiquette de classe pour l'augmentation de la mosaïque dans la classification des images ?

Pour créer une étiquette de classe dans CutMix o MixUp l'augmentation de type, nous pouvons utiliser beta comme np.random.beta o scipy.stats.beta et faites comme suit pour deux étiquettes :

label = label_one*beta + (1-beta)*label_two

Mais que faire si nous avons plus de deux des images ? Sur YoLo4 ils ont essayé une augmentation intéressante appelée Augmentation mosaïque pour les problèmes de détection d'objets. Contrairement à CutMix o MixUp cette augmentation crée des échantillons augmentés avec 4 images. Dans les cas de détection d'objets, nous pouvons calculer le décalage des coordonnées de chaque instance et ainsi obtenir la vérité de terrain appropriée, aquí . Mais pour les cas de classification d'images uniquement, comment faire ?

Voici un démarreur .

import tensorflow as tf
import matplotlib.pyplot as plt 
import random

(train_images, train_labels), (test_images, test_labels) = \
tf.keras.datasets.cifar10.load_data()
train_images = train_images[:10,:,:]
train_labels = train_labels[:10]
train_images.shape, train_labels.shape

((10, 32, 32, 3), (10, 1))

Voici une fonction que nous avons écrite pour cette augmentation ; ( trop moche avec une boucle `inner-outer ! Veuillez suggérer si nous pouvons le faire efficacement).

def mosaicmix(image, label, DIM, minfrac=0.25, maxfrac=0.75):
    '''image, label: batches of samples 
    '''
    xc, yc  = np.random.randint(DIM * minfrac, DIM * maxfrac, (2,))
    indices = np.random.permutation(int(image.shape[0]))
    mosaic_image = np.zeros((DIM, DIM, 3), dtype=np.float32)
    final_imgs, final_lbs = [], []

    # Iterate over the full indices 
    for j in range(len(indices)): 
        # Take 4 sample for to create a mosaic sample randomly 
        rand4indices = [j] + random.sample(list(indices), 3) 

        # Make mosaic with 4 samples 
        for i in range(len(rand4indices)):
            if i == 0:    # top left
                x1a, y1a, x2a, y2a =  0,  0, xc, yc
                x1b, y1b, x2b, y2b = DIM - xc, DIM - yc, DIM, DIM # from bottom right        
            elif i == 1:  # top right
                x1a, y1a, x2a, y2a = xc, 0, DIM , yc
                x1b, y1b, x2b, y2b = 0, DIM - yc, DIM - xc, DIM # from bottom left
            elif i == 2:  # bottom left
                x1a, y1a, x2a, y2a = 0, yc, xc, DIM
                x1b, y1b, x2b, y2b = DIM - xc, 0, DIM, DIM-yc   # from top right
            elif i == 3:  # bottom right
                x1a, y1a, x2a, y2a = xc, yc,  DIM, DIM
                x1b, y1b, x2b, y2b = 0, 0, DIM-xc, DIM-yc    # from top left

            # Copy-Paste
            mosaic_image[y1a:y2a, x1a:x2a] = image[i,][y1b:y2b, x1b:x2b]

        # Append the Mosiac samples
        final_imgs.append(mosaic_image)

    return final_imgs, label

Les échantillons augmentés, actuellement avec les mauvaises étiquettes.

data, label = mosaicmix(train_images, train_labels, 32)
plt.imshow(data[5]/255)

enter image description here


Cependant, voici d'autres exemples pour vous motiver. Les données proviennent du Feuille de manioc la concurrence.


Cependant, pour obtenir l'étiquette appropriée à partir de cet échantillon augmenté, nous avons essayé quelque chose comme ceci, disons pour chaque interaction sur les lots à l'intérieur de la boucle externe et de la boucle interne si nous pouvons calculer la distribution de la 4 échantillons, comme la façon dont chacun d'entre eux couvre la zone de mosaic_image de sorte que nous pouvons les multiplier avec une probabilité de distribution de a .

    # Iterate over the full indices 
    for j in range(len(indices)): 

        b = tf.random.uniform([],0,1) # this is beta dist with alpha=1.0
        P = tf.cast( tf.random.uniform([],0,1)<=1.0, tf.int32) 

        for i in range(len(rand4indices)):
            ....
            WIDTH = tf.cast( DIM * tf.math.sqrt(1-b),tf.int32) * P  
            a = tf.cast(WIDTH*WIDTH/DIM/DIM,tf.float32)

4voto

Uzzal Podder Points 469

Nous savons déjà que, dans CutMix , est un nombre flottant issu de la distribution bêta Beta(,). Nous avons vu que, lorsque =1 il est le plus performant. Maintenant, si nous accordons ==1 toujours, on peut dire que est échantillonné à partir de la distribution uniforme. .

Nous pouvons simplement dire est juste un nombre à virgule flottante dont la valeur sera de 0 à 1.

Donc, seulement pour 2 des images, si nous utilisons pour la première image, alors nous pouvons calculer la partie inconnue restante simplement en 1- .

Mais pour 3 images, si nous utilisons pour la 1ère image, nous ne peut pas calculer les deux autres inconnues de ce seul . Si nous voulons vraiment le faire, nous avons besoin de 2 nombres aléatoires pour 3 images. De la même manière, nous pouvons dire que pour le modèle n nombre d'images, nous avons besoin de la n-1 variable aléatoire numérique. Et dans tous les cas, la somme devrait être 1 . (par exemple, + (1-) == 1 ). Si la somme n'est pas 1 l'étiquette sera fausse !

À cette fin distribution de Dirichlet peut être utile car il permet de générer des quantités dont la somme est égale à 1. Une variable aléatoire distribuée par Dirichlet peut être considérée comme une généralisation multivariée d'une distribution Beta.

>>> np.random.dirichlet((1, 1), 1)  # for 2 images. Equivalent to  and (1-)
array([[0.92870347, 0.07129653]])  
>>> np.random.dirichlet((1, 1, 1), 1)  # for 3 images.
array([[0.38712673, 0.46132787, 0.1515454 ]])
>>> np.random.dirichlet((1, 1, 1, 1), 1)  # for 4 images.
array([[0.59482542, 0.0185333 , 0.33322484, 0.05341645]])

Sur CutMix la taille de la partie recadrée d'une image est liée à la taille de l'image. qui pondèrent les étiquettes correspondantes.

enter image description here

enter image description here

Donc, pour les multiples vous devez également les calculer en conséquence.

# let's say for 4 images
# I am not sure the proper way. 

image_list = [4 images]
label_list = [4 label]
new_img = np.zeros((w, h))

beta_list = np.random.dirichlet((1, 1, 1, 1), 1)[0]
for idx, beta in enumerate(beta_list):
    x0, y0, w, h = get_cropping_params(beta, full_img)  # something like this
    new_img[x0, y0, w, h] = image_list[idx][x0, y0, w, h]
    label_list[idx] = label_list[idx] * beta

1voto

Mostly Clueless Points 11

Une autre façon d'aborder ce problème est de considérer les lignes de séparation pour les dimensions de la largeur et de la hauteur. Lors de la construction de l'image mosaïque, l'objectif est de combiner 4 images en une seule. Nous pouvons y parvenir en échantillonnant de manière aléatoire les points médians (qui représentent les points de séparation) dans chaque dimension. Cela permet de supprimer l'exigence plutôt compliquée d'échantillonner 4 nombres dont la somme est égale à 1. Au lieu de cela, l'objectif est maintenant d'échantillonner 2 valeurs indépendantes à partir d'une distribution uniforme - une alternative beaucoup plus simple et plus intuitive.

Donc, essentiellement, nous échantillonnons deux valeurs :

w = np.random.uniform(0, 1)
h = np.random.uniform(0, 1)

Pour générer des mosaïques réalistes où chaque image a une contribution notable, nous pouvons échantillonner des valeurs de [0.25 0.75] plutôt que de [0, 1]

Ces deux valeurs sont suffisantes pour paramétrer le problème de la mosaïque. Chaque image de la mosaïque occupe des zones couvertes par les coordonnées suivantes : Considérons que l'image de la mosaïque a des dimensions W x H et les points médians de chaque dimension sont représentés par w et h respectivement.

 - top left     - (0, 0) to (w, h)
 - top right    - (w, 0) to (W, h)
 - bottom left  - (0, h) to (w, H)
 - bottom right - (w, h) to (W, H)

Les points médians échantillonnés aident également à calculer les étiquettes de classe. Supposons que nous décidions d'utiliser la zone que chaque image occupe dans la mosaïque comme sa contribution correspondante à l'étiquette de classe globale. Par exemple, considérons 4 images appartenant à 4 classes {0, 1, 2, 3} . Supposons maintenant que le 0 L'image occupe le coin supérieur gauche, 1 en haut à droite, 2 en bas à gauche, et 3 en bas à droite. Nous pouvons construire l'étiquette de classe L comme suit :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X