画像分類でモザイク増強用のクラスラベルを作成するにはどうすればよいですか?

Dec 07 2020

でクラスラベルを作成しCutMixたりMixUp、拡張を入力betanp.random.betaたりするscipy.stats.betaには、2つのラベルに対して次のようにまたはを使用できます。

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

しかし、3つ以上の画像がある場合はどうなりますか?でYoLo4、彼らはと呼ばれる興味深い増強しようとしたモザイク増強を物体検出の問題のために。違ってCutMix、またはMixUp、この増強はで増強サンプルを作成し4枚の画像。オブジェクト検出の場合、各インスタンス座標のシフトを計算できるため、ここで適切なグラウンドトゥルースを取得できます。しかし、画像分類の場合のみ、どうすればそれを行うことができますか?

これがスターターです。

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

これは、この拡張のために作成した関数です。(inner-outerループが醜い!効率的にできるかどうか提案してください。)

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

現在、ラベルが間違っている拡張サンプル。

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


しかし、ここにあなたをやる気にさせるいくつかの例があります。データはキャッサバリーフコンペティションからのものです。


ただし、この拡張サンプルから適切なラベルを取得するために、次のようなことを試みました。たとえば、外側のループと内側のループ内のバッチでの相互作用ごとに、それぞれがどのようにカバーするかなど、4つのサンプルの分布を計算できる場合を考えます。内の領域mosaic_image。これにより、それぞれに分布確率を掛けることができ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)
            

回答

4 UzzalPodder Dec 07 2020 at 20:43

CutMixではλ、ベータ分布Beta(α、α)からの浮動小数点数であることはすでにわかっています。が、α=1最高のパフォーマンスを発揮することを確認しました。さて、α==1常に付与すると、それλは一様分布からサンプリングされたと言えます。

簡単に言うλと、値が0から1になる浮動小数点数です。

したがって、2つの画像の場合のみλ、1番目の画像に使用すると、残りの未知の部分を簡単に計算できます1-λ

しかし、3つの画像の場合λ、最初の画像に使用すると、その単一の画像から他の2つの未知数計算することできませんλ。本当にそうしたいのであれば、3つの画像に対して2つの乱数が必要です。同様にn、画像のn-1数については、確率変数の数が必要であると言えます。そして、すべての場合において、合計はである必要があります1。(たとえば、λ + (1-λ) == 1)。合計がそうでない1場合、ラベルは間違っています!

この目的では、合計が1になる量を生成するのに役立つため、ディリクレ分布が役立つ場合があります。ディリクレ分布確率変数は、ベータ分布の多変量一般化と見なすことができます。

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

CutMix、画像のクロッピングされた部分の大きさは、と関係有しλた対応するラベルを重み付け。

したがって、複数のλ場合は、それに応じて計算する必要もあります。

# 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

この問題を調べる別の方法は、幅と高さの両方の寸法の分離線を考慮することです。モザイク画像を作成するときの目標は、4つの画像を1つの画像に結合することです。これは、各次元の中間点(分離点を示す)をランダムにサンプリングすることで実現できます。これにより、合計1つになる4つの数値をサンプリングするというかなり複雑な要件がなくなります。代わりに、今の目標は、一様分布から2つの独立した値をサンプリングすることです。これは、はるかに単純で直感的な代替手段です。

したがって、基本的に、2つの値をサンプリングします。

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

各画像の寄与が目立つリアルなモザイクを生成するために、[0、1]からではなく、[0.250.75]から値をサンプリングできます。

これらの2つの値は、モザイク問題をパラメーター化するのに十分です。モザイク内の各画像は、次の座標にまたがる領域を占めます。モザイク画像の次元がWxHであり、各次元の中点がそれぞれwhで表されていることを考慮してください。

  • 左上-(0、0)から(w、h)
  • 右上-(w、0)から(W、h)
  • 左下-(0、h)から(w、H)
  • 右下-(w、h)から(W、H)

サンプリングされた中点は、クラスラベルの計算にも役立ちます。クラスラベル全体への対応する寄与として、モザイク内で各画像が占める領域を使用することにしたとしましょう。たとえば、4つのクラス{0、1、2、3}に属する4つの画像について考えてみます。ここで、「0」の画像が左上、「1」が右上、「2」が左下、「3」が右下を占めると仮定します。次のようにクラスラベル「L」を作成できます。

あなたはこのリンクで方程式を見ることができます