이미지 분류에서 모자이크 확대를위한 클래스 레이블을 만드는 방법은 무엇입니까?

Dec 07 2020

에서 클래스 레이블을 만들려면 CutMix또는 MixUp형의 확대, 우리가 사용할 수있는 betanp.random.beta이나 scipy.stats.beta와 같은 두 개의 레이블을 위해 다음을 수행하십시오

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

하지만 이미지 가 두 개 이상 이면 어떨까요? 에서 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)


그러나 여기에 동기를 부여하는 몇 가지 예가 더 있습니다. 데이터는 Cassava Leaf 대회 에서 가져온 것입니다.


그러나이 증가 된 샘플에서 적절한 레이블을 얻기 위해 우리는 다음과 같은 것을 시도했습니다. 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 , λ베타 분포 베타 (α, α)로부터 float 번호입니다. ,이 (가 α=1) 가장 잘 수행 되는 것을 보았습니다 . 이제 α==1항상 승인 λ하면 균일 분포에서 샘플링 되었다고 말할 수 있습니다 . .

간단히 우리는 λ값이 0에서 1이되는 부동 소수점 숫자 라고 말할 수 있습니다 .

따라서 2 개의 이미지에 대해서만 λ첫 번째 이미지에 사용하면 미지의 나머지 부분을 간단히 계산할 수 있습니다 1-λ.

그러나 3 개의 이미지 λ에 대해 첫 번째 이미지에 사용하면 해당 단일에서 다른 2 개의 미지수계산할 수 없습니다λ . 정말로 그렇게하려면 3 개의 이미지에 대해 2 개의 난수가 필요합니다. 같은 방식 n으로 이미지 수에 대해 n-1숫자 랜덤 변수 가 필요 하다고 말할 수 있습니다 . 그리고 모든 경우에 합계는 1. (예 λ + (1-λ) == 1:). 합계가 아닌 1경우 레이블이 잘못됩니다!

이 목적을 위해 Dirichlet 분포 는 합이 1이되는 양을 생성하는 데 도움이되므로 유용 할 수 있습니다. Dirichlet 분포 랜덤 변수는 베타 분포의 다변량 일반화로 볼 수 있습니다.

>>> 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 개의 이미지를 하나의 이미지로 결합하는 것입니다. 우리는 각 차원에서 중간 점 (분리 점 표시)을 무작위로 샘플링하여이를 달성 할 수 있습니다. 이것은 4 개의 숫자를 1로 합산하는 다소 복잡한 요구 사항을 제거합니다. 대신 이제 목표는 균일 한 분포에서 2 개의 독립적 인 값을 샘플링하는 것입니다. 훨씬 간단하고 직관적 인 대안입니다.

따라서 기본적으로 두 가지 값을 샘플링합니다.

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

각 이미지의 기여도가 눈에 띄는 사실적인 모자이크를 생성하려면 [0, 1]이 아닌 [0.25 0.75]에서 값을 샘플링 할 수 있습니다.

이 두 값은 모자이크 문제를 매개 변수화하는 데 충분합니다. 모자이크의 각 이미지는 다음 좌표로 확장 된 영역을 차지합니다. 모자이크 이미지의 크기는 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'을 만들 수 있습니다.

이 링크에서 방정식을 볼 수 있습니다.