Wie erstelle ich eine Klassenbezeichnung für die Mosaikvergrößerung in der Bildklassifizierung?

Dec 07 2020

Um eine Klasse Label zu erstellen CutMixoder MixUpTyp Vergrößerung, können wir verwenden , betawie np.random.betaoder scipy.stats.betaund tun , wie für zwei Etiketten folgt:

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

Aber was ist, wenn wir mehr als zwei Bilder haben? In YoLo4 haben sie eine interessante Erweiterung namens Mosaic Augmentation für Objekterkennungsprobleme ausprobiert . Im Gegensatz zu CutMixoder MixUpwerden durch diese Erweiterung erweiterte Beispiele mit 4 Bildern erstellt. In Objekterkennungsfällen können wir die Verschiebung der einzelnen Instanzkoordinaten berechnen und so hier die richtige Grundwahrheit ermitteln . Aber wie können wir das nur für Fälle der Bildklassifizierung tun?

Hier ist eine Vorspeise .

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

Hier ist eine Funktion, die wir für diese Erweiterung geschrieben haben. (zu hässlich mit einer inner-outerSchleife! Bitte schlagen Sie vor, ob wir es effizient machen können.)

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

Die erweiterten Samples, derzeit mit den falschen Labels.

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


Hier sind jedoch einige weitere Beispiele, um Sie zu motivieren. Die Daten stammen aus dem Cassava Leaf- Wettbewerb.


Um jedoch das richtige Etikett für diese erweiterte Probe zu erhalten, haben wir Folgendes versucht, beispielsweise für jede Interaktion über die Chargen innerhalb der äußeren und inneren Schleife, wenn wir die Verteilung der 4 Proben berechnen können , z. B. wie jede von ihnen abdeckt die Fläche innerhalb mosaic_image, so dass wir jede mit der Verteilungswahrscheinlichkeit von multiplizieren können 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)
            

Antworten

4 UzzalPodder Dec 07 2020 at 20:43

Wir wissen bereits , dass in CUTMIX , λist eine Float - Zahl aus der Beta - Verteilung Beta (α, α). Wir haben gesehen, wann α=1es am besten funktioniert. Wenn wir jetzt α==1immer gewähren , können wir sagen, dass dies λaus der gleichmäßigen Verteilung entnommen wird. .

Wir können einfach sagen, dass λes sich nur um eine Gleitkommazahl handelt, deren Wert 0 zu 1 ist.

Wenn wir also nur für 2 Bilder λfür das 1. Bild verwenden, können wir den verbleibenden unbekannten Teil einfach durch berechnen 1-λ.

Aber für 3 Bilder, wenn wir λfür das 1. Bild verwenden, können wir keine anderen 2 Unbekannten aus dieser Single berechnenλ . Wenn wir das wirklich wollen, brauchen wir 2 Zufallszahlen für 3 Bilder. Ebenso können wir sagen, dass wir für die nAnzahl der Bilder die n-1Zufallsvariable number benötigen . Und in jedem Fall sollte die Summe sein 1. (zum Beispiel λ + (1-λ) == 1). Wenn die Summe nicht ist 1, ist das Etikett falsch!

Zu diesem Zweck kann die Dirichlet-Verteilung hilfreich sein, da sie dazu beiträgt, Mengen zu generieren, die sich zu 1 summieren. Eine Dirichlet-verteilte Zufallsvariable kann als multivariate Verallgemeinerung einer Beta-Verteilung angesehen werden.

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

In CutMix hat die Größe des zugeschnittenen Teils eines Bildes eine Beziehung zur λGewichtung der entsprechenden Beschriftungen.

Für mehrere λmüssen Sie sie also auch entsprechend berechnen.

# 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
1 MostlyClueless Jan 13 2021 at 13:46

Eine andere Möglichkeit, dieses Problem zu betrachten, besteht darin, die Trennlinien sowohl für die Breiten- als auch für die Höhenabmessungen zu berücksichtigen. Beim Erstellen des Mosaikbilds besteht das Ziel darin, 4 Bilder zu einem einzigen Bild zu kombinieren. Wir können dies erreichen, indem wir die Mittelpunkte (die die Trennungspunkte bezeichnen) in jeder Dimension zufällig auswählen. Dadurch entfällt die ziemlich komplizierte Anforderung, 4 Zahlen mit einer Summe von bis zu 1 abzutasten. Stattdessen besteht das Ziel nun darin, 2 unabhängige Werte aus einer gleichmäßigen Verteilung abzutasten - eine viel einfachere und intuitivere Alternative.

Wir probieren also im Wesentlichen zwei Werte aus:

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

Um realistische Mosaike zu erzeugen, bei denen jedes Bild einen spürbaren Beitrag leistet, können wir Werte von [0,25 0,75] anstatt von [0, 1] abtasten.

Diese beiden Werte reichen aus, um das Mosaikproblem zu parametrisieren. Jedes Bild im Mosaik nimmt Bereiche ein, die von den folgenden Koordinaten überspannt werden: Beachten Sie, dass das Mosaikbild die Dimensionen WxH hat und die Mittelpunkte jeder Dimension durch w bzw. h dargestellt werden.

  • oben links - (0, 0) bis (w, h)
  • oben rechts - (w, 0) bis (W, h)
  • unten links - (0, h) bis (w, H)
  • unten rechts - (w, h) bis (W, H)

Die abgetasteten Mittelpunkte helfen auch bei der Berechnung der Klassenbeschriftungen. Nehmen wir an, wir beschließen, den Bereich, den jedes Bild innerhalb des Mosaiks einnimmt, als entsprechenden Beitrag zur Gesamtklassenbezeichnung zu verwenden. Betrachten Sie beispielsweise 4 Bilder, die zu 4 Klassen gehören {0, 1, 2, 3}. Nehmen wir nun an, dass das Bild '0' oben links, '1' oben rechts, '2' unten links und '3' unten rechts belegt. Wir können das Klassenlabel 'L' wie folgt erstellen

Sie können die Gleichung unter diesem Link anzeigen