Comment créer une étiquette de classe pour l'augmentation de la mosaïque dans la classification d'image?
Pour créer une étiquette de classe CutMix
ou MixUp
une augmentation de type, nous pouvons utiliser beta
comme np.random.beta
ou scipy.stats.beta
et procéder comme suit pour deux étiquettes:
label = label_one*beta + (1-beta)*label_two
Mais que faire si nous avons plus de deux images? Dans YoLo4 , ils ont essayé une augmentation intéressante appelée Mosaic Augmentation pour les problèmes de détection d'objets. Contrairement à CutMix
ou 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 de chaque coordonnée d'instance et donc possible d'obtenir la vérité terrain appropriée, ici . Mais pour les seuls cas de classification d'images, comment pouvons-nous faire cela?
Voici une entrée .
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 inner-outer
boucle! 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)

Cependant, voici quelques autres exemples de motivation. Les données proviennent du concours de la feuille de manioc .
Cependant, pour obtenir le bon label de cet échantillon augmenté, nous avons essayé quelque chose comme ça, 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 des 4 échantillons, comme la façon dont chacun d'eux couvre la zone à l'intérieur mosaic_image
, de sorte que nous pouvons multiplier chacun 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)
Réponses
Nous savons déjà que, dans CutMix , λ
est un nombre flottant de la distribution bêta Beta (α, α). Nous avons vu, quand α=1
, il fonctionne le mieux. Maintenant, si nous accordons α==1
toujours, nous pouvons dire que λ
c'est échantillonné à partir de la distribution uniforme. .
Nous pouvons simplement dire qu'il λ
s'agit simplement d'un nombre à virgule flottante dont la valeur sera de 0 à 1.
Donc, seulement pour 2 images, si nous utilisons λ
pour la 1ère image, nous pouvons calculer la partie inconnue restante simplement par 1-λ
.
Mais pour 3 images, si nous utilisons λ
pour la 1ère image, nous ne pouvons pas calculer 2 autres inconnues à partir de cette seule λ
. Si nous voulons vraiment le faire, nous avons besoin de 2 nombres aléatoires pour 3 images. De la même manière, on peut dire que pour le n
nombre d'images, on a besoin de la n-1
variable aléatoire number. Et dans tous les cas, la sommation devrait être 1
. (par exemple, λ + (1-λ) == 1
). Si la somme ne l'est pas 1
, l'étiquette sera erronée!
À cette fin, la distribution de Dirichlet peut être utile car elle permet de générer des quantités qui totalisent 1. Une variable aléatoire distribuée par Dirichlet peut être considérée comme une généralisation multivariée d'une distribution bêta.
>>> 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]])
Dans CutMix , la taille de la partie recadrée d'une image a une relation avec λ
laquelle pondération les étiquettes correspondantes.


Donc, pour plusieurs λ
, 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
Une autre façon d'aborder ce problème consiste à considérer les lignes de séparation pour les dimensions de largeur et de hauteur. Lors de la construction de l'image mosaïque, l'objectif est de combiner 4 images en une seule image. Nous pouvons y parvenir en échantillonnant au hasard les points médians (indiquant les points de séparation) dans chaque dimension. Cela supprime l'exigence plutôt compliquée d'échantillonner 4 nombres totalisant jusqu'à 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 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érez que l'image de la mosaïque a des dimensions LxH et les points médians de chaque dimension sont représentés respectivement par w et h .
- en haut à gauche - (0, 0) à (w, h)
- en haut à droite - (w, 0) à (W, h)
- en bas à gauche - (0, h) à (w, H)
- en bas à droite - (w, h) à (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 l'image «0» 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
vous pouvez voir l'équation sur ce lien