CutMix augmentation์ ํฌ์ธํธํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์ ์ ์ฉํ ๋ ผ๋ฌธ์ด๋ค. ๋ ํฌ์ธํธํด๋ผ์ฐ๋ ๋ฐ์ดํฐ ๊ฐ์ ์ผ๋์ผ ๋์๊ด๊ณ๋ฅผ ์ฐพ๊ณ , ์ด๋ฅผ ๋ฐํ์ผ๋ก ๋ ๋ฐ์ดํฐ๋ฅผ ์๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ์ํ๋ค.
Paper: https://arxiv.org/pdf/2101.01461.pdf
Code: https://github.com/cuge1995/PointCutMix
Introduction
์ด๋ฏธ์ง ๋ฐ์ดํฐ์ ๋ํด mixed sample data augmentation (MSDA)๊ฐ ํ๋ฐํ๊ฒ ์ฌ์ฉ๋์ด ์๋ค. ๋ํ์ ์ธ ์์๋ MixUp (Zhang et al., 2018)๊ณผ CutMix (Yun et al., 2019) ๊ฐ ์๋ค.

๋ณธ ๋ ผ๋ฌธ์์๋ ํฌ์ธํธํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์ ๋ํด CutMix๋ฅผ ์ํํ๋ PointCutMix๋ฅผ ์ ์ํ๋ค.
Related Work
- ์ผ๋ฐ์ ์ผ๋ก ํฌ์ธํธํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์ ๋ํด ์ฌ์ฉ๋๋ augmentation์ผ๋ก๋ random rotation, jittering, scaling ๋ฑ์ด ์๋ค. (Qi et al., 2017a;b)
- ์ด์ธ์๋ PointAugment (Li et al., 2020), PointMixUp (Chen et al., 2020) ๋ฑ์ด ์ ์๋์๋ค.
- PointAugment์ ๊ฒฝ์ฐ๋ adversarial training์ ์ด์ฉํด augmenter๊ณผ classifier network๋ฅผ ๋์์ ํ์ต์ํค๋ ๋ฐฉ๋ฒ์ผ๋ก, ํ์ต์ด ์ด๋ ต๋ค๋ ๋จ์ ์ด ์๋ค.
- PointMixUp์ ๋ง ๊ทธ๋๋ก ํฌ์ธํธํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์ ๋ํด MixUp augmentation์ ์ํํ๋ ๋ฐฉ๋ฒ์ผ๋ก, local feature์ ์์ด๋ฒ๋ฆด ์ ์๋ค๋ ๋จ์ ์ด ์๋ค.
Method
1. Optimal assignment of point clouds
MSDA๋ฅผ ์ํํ๊ธฐ ์ํด์๋, ๋ sample์ ์ต์ ๋จ์์ ๋ํด ์ผ๋์ผ ๋์์ด ์ด๋ฃจ์ด์ง ์ ์์ด์ผ ํ๋ค.
์ต์ ๋จ์๋, ์ด๋ฏธ์ง์ ๊ฒฝ์ฐ์๋ ํฝ์ ์ ํด๋นํ๊ณ , ํฌ์ธํธํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ ํ๋์ ํฌ์ธํธ์ ํด๋นํ๋ค.
์ด๋ฏธ์ง์ ๊ฒฝ์ฐ resize, crop ๋ฑ์ ์ด์ฉํ๋ฉด ๋ sample ๊ฐ์ ํฝ์ ๊ฐ ์ผ๋์ผ ๋์์ ๊ฐ๋จํ ์ ์ํ ์ ์์ง๋ง, ํฌ์ธํธํด๋ผ์ฐ๋๋ ํด๋น ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
๋ณธ ๋ ผ๋ฌธ์์๋ PointMixUp (Chen et al., 2020)๊ณผ MSN (Liu et al., 2020a)์์ ์ฌ์ฉํ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ, Earth Mover's Distance (EMD)๋ฅผ ์ํ optimal assignment ฯโ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ๋ค.
ฯโ=argminฯโฮฆโi||x1,iโx2,ฯ(i)||2
์ด๋ ๋ ์ ์ฌ์ด ๊ฑฐ๋ฆฌ๊ฐ ์ต์๊ฐ ๋๊ฒ ํ๋ ์ผ๋์ผ ๋์ ํจ์๋ฅผ ์ฐพ๋ ๊ฒ๊ณผ ๊ฐ๋ค.
EMD๋ ฯโ๋ฅผ ์ด์ฉํด ๋ค์๊ณผ ๊ฐ์ด ์ ์๋๋ค.
EMD=1Nโi||x1,iโx2,ฯโ(i)||2
2. Mixing algorithm
PointCutMix์ ๋ชฉํ๋ ์๋ก ๋ค๋ฅธ ๋ ๊ฐ์ ํฌ์ธํธํด๋ผ์ฐ๋ ๋ฐ์ดํฐ (x1,y1), (x2,y2)๊ฐ ์ฃผ์ด์ก์ ๋ ์๋ก์ด ํฌ์ธํธํด๋ผ์ฐ๋ ๋ฐ์ดํฐ (หx,หy)๋ฅผ ์ฐพ๋ ๊ฒ์ด๋ค. ์ด๋, x๋ ํฌ์ธํธํด๋ผ์ฐ๋, y๋ classification ๋ผ๋ฒจ์ ์๋ฏธํ๋ค.
- หx=Bโ x1+(INโB)โ หx2
- หy=ฮปy1+(1โฮป)y2
์ด๋ B๋ b1,b2,...,bN์ ๋๊ฐ์ฑ๋ถ์ผ๋ก ๊ฐ๋ ๋๊ฐํ๋ ฌ๋ก, bi๋ i๋ฒ์งธ ํฌ์ธํธ๋ฅผ samplingํ ์ง๋ฅผ ๊ฒฐ์ ํ๋ 0๋๋ 1์ ๊ฐ์ด๋ค.
์ด๋ค ํฌ์ธํธ๋ฅผ samplingํ ์ง ์ ํ๋ ๋ฐฉ๋ฒ์ ๋๊ฐ์ง๊ฐ ์๋๋ฐ, ์ด๋ ๋ค์๊ณผ ๊ฐ๋ค.
1. PointCutMix-R: x1์์ randomํ๊ฒ n๊ฐ์ ํฌ์ธํธ๋ฅผ samplingํ๋ค.
2. PoitnCutMix-K: centtral point๋ฅผ ํ๋ ์ ํ๊ณ , nearest neighbor์ ์ด์ฉํด ์ฃผ์์ nโ1๊ฐ์ ์ ์ ์ ํํด samplingํ๋ค.

ฮป๋ sampling ratio๋ฅผ ์๋ฏธํ๋ฉฐ, Beta(ฮฒ,ฮฒ) ๋ถํฌ์์ ์ถ์ถ๋๋ค. ฮฒ๊ฐ ํด์๋ก ๋ถํฌ๋ narrowํด์ง๋ฉฐ, ์ด๋ ๋ชจ๋ ์ํ์ ๋ํด ๋น์ทํ sampling ratio๋ฅผ ์ฌ์ฉํจ์ ์๋ฏธํ๋ค.

์๋ก ๋ค๋ฅธ sampling ratio ฮป๊ฐ์ ๋ฐ๋ฅธ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ๋ค.

Result
Comparison on different ฯ and ฮฒ values
PointCutMix augmentation์ ์ ์ฉํ ํ๋ฅ ์ธ ฯ์, sampling ratio์ ํธ์ฐจ๋ฅผ ์กฐ์ ํ๋ ฮฒ ๊ฐ์ ๋ฐ๊ฟ๊ฐ๋ฉฐ ์คํํ๋ค.
์ฐ์ ฯ์ ๊ฒฝ์ฐ 0์ผ ๋ (augmentation์ ์ฌ์ฉํ์ง ์์) ๋ณด๋ค ํญ์ ์ฑ๋ฅ์ด ํฅ์๋๊ณ ๊ทธ ๊ฐ์ ๋ฐ๋ฅธ ์ฐจ์ด๊ฐ ๋ณ๋ก ์๋ ๋ฐ์ ๋ฐํด, PointNet๋ง ฯ ๊ฐ์ด ์ปค์ง์๋ก ์ฑ๋ฅ์ด ๊ธ๊ฒฉํ ํ๋ฝํ๋ค. PointNet์ ๊ตฌ์กฐ์ localํ feature์ ํฌ์ฐฉํ์ง ๋ชปํ๋๋ฐ, ์ ์๋ค์ ์ด๋ก ์ธํด PointNet ๊ตฌ์กฐ์๋ PointCutMix๊ฐ ํจ๊ณผ๊ฐ ์๋ค๊ณ ํ๋จ, ์ดํ์ ์คํ์์ PointNet์ ์ ์ธํ๋ค.

ฮฒ์ ๊ฒฝ์ฐ๋ ๊ฐ์ ๋ฐ๋ฅธ ์ฑ๋ฅ ์ฐจ์ด๊ฐ ๋งค์ฐ ์ ์ผ๋, RS-CNN์ ๋งค์ฐ ์์ ฮฒ๊ฐ์ ์ ํธํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ฮฒ๊ฐ์ด ์์์๋ก, ๋งค ์ํ๋ง๋ค ๋น์ทํ sampling ratio๋ฅผ ์ฌ์ฉํจ์ ์๋ฏธํ๋ค.

Classification Result
ฯ=1.0, ฮฒ=1.0์ผ๋ก ์ค์ ํ๋ค.

Baseline, PointMixUp, PointAugment ๋ฑ๊ณผ ๋น๊ตํ์ ๋ ๊ฑฐ์ ํญ์ ๊ฐ์ฅ ๋์ ์ฑ๋ฅ์ ๋ณด์๋ค.
Code (PyTorch Implementation)
์ฝ๋๋ Github์ ๊ณต๊ฐ๋ official implementation์ ์ผ๋ถ ์์ ํ๋ค.
1. Optimal assignment of point clouds
๋ Batch ๋ฐ์ดํฐ ๊ฐ์ ์ผ๋์ผ๋์ ํจ์ ๋ถ๋ถ์ด๋ค. ์ด ํจ์ ์ญ์ Gradient backpropagation์ ํตํด ํจ๊ป optimize๋๋ค.
#codes from https://github.com/cuge1995/PointCutMix/blob/main/emd/emd_module.py
class emdFunction(Function):
@staticmethod
def forward(ctx, xyz1, xyz2, eps, iters):
batchsize, n, _ = xyz1.size()
_, m, _ = xyz2.size()
assert(n == m)
assert(xyz1.size()[0] == xyz2.size()[0])
assert(n % 1024 == 0)
assert(batchsize <= 512)
xyz1 = xyz1.contiguous().float().cuda()
xyz2 = xyz2.contiguous().float().cuda()
dist = torch.zeros(batchsize, n, device='cuda').contiguous()
assignment = torch.zeros(batchsize, n, device='cuda', dtype=torch.int32).contiguous() - 1
assignment_inv = torch.zeros(batchsize, m, device='cuda', dtype=torch.int32).contiguous() - 1
price = torch.zeros(batchsize, m, device='cuda').contiguous()
bid = torch.zeros(batchsize, n, device='cuda', dtype=torch.int32).contiguous()
bid_increments = torch.zeros(batchsize, n, device='cuda').contiguous()
max_increments = torch.zeros(batchsize, m, device='cuda').contiguous()
unass_idx = torch.zeros(batchsize * n, device='cuda', dtype=torch.int32).contiguous()
max_idx = torch.zeros(batchsize * m, device='cuda', dtype=torch.int32).contiguous()
unass_cnt = torch.zeros(512, dtype=torch.int32, device='cuda').contiguous()
unass_cnt_sum = torch.zeros(512, dtype=torch.int32, device='cuda').contiguous()
cnt_tmp = torch.zeros(512, dtype=torch.int32, device='cuda').contiguous()
emd.forward(xyz1, xyz2, dist, assignment, price, assignment_inv, bid, bid_increments, max_increments, unass_idx, unass_cnt, unass_cnt_sum, cnt_tmp, max_idx, eps, iters)
ctx.save_for_backward(xyz1, xyz2, assignment)
return dist, assignment
@staticmethod
def backward(ctx, graddist, gradidx):
xyz1, xyz2, assignment = ctx.saved_tensors
graddist = graddist.contiguous()
gradxyz1 = torch.zeros(xyz1.size(), device='cuda').contiguous()
gradxyz2 = torch.zeros(xyz2.size(), device='cuda').contiguous()
emd.backward(xyz1, xyz2, gradxyz1, graddist, assignment)
return gradxyz1, gradxyz2, None, None
class emdModule(nn.Module):
def __init__(self):
super(emdModule, self).__init__()
def forward(self, input1, input2, eps, iters):
return emdFunction.apply(input1, input2, eps, iters)
2. Mixing algorithm (PointCutMix-R)
PointCutMix-R์ ์ฝ๋์ด๋ค. Batch ๋ฐ์ดํฐ์ ์์๋ฅผ ๋ฌด์์๋ก ์์ ํ ์์์ ์ ์ํ emdModule์ ์ด์ฉํด ์๋ ๋ฐ์ดํฐ์์ ์ผ๋์ผ๋์์ ๊ณ์ฐํ ํ, ๊ฐ๊ฐ์ Batch ๋ฐ์ดํฐ๋ฅผ ์ผ์ ๋น์จ๋ก ์๋๋ค.
# codes are modified from https://github.com/cuge1995/PointCutMix/blob/main/train_pointcutmix_r.py#L252
for points, label in train_loader:
target = label
r = np.random.rand(1)
if r < cutmix_prob:
lam = np.random.beta(beta, beta)
B = points.size(0)
rand_index = torch.randperm(B) #shuffled index
target_a = target
target_b = target[rand_index] #shuffled label
point_a = points #[B, num_points, num_features]
point_b = points[rand_index] #shuffled points
point_c = points[rand_index]
remd = emdModule() #optimal assignment of point clouds
_, ind = remd(point_a, point_b, 0.005, 300) #assignment function [B, num_points]
for ass in range(B):
point_c[ass] = point_c[ass][ind[ass].long(), :] #rearrange pixels that correspond to point_a
int_lam = max(int(num_points * lam), 1) #number of points to sample
gamma = np.random.choice(num_points, int_lam, replace=False, p=None) #points to sample (Random sampling)
#cutmix
for i2 in range(B):
points[i2, gamma] = point_c[i2, gamma]
#adjust lambda to exactly match point ratio
lam = int_lam * 1.0 / num_points
#pred and calculate loss
pred = model(points)
loss = loss_f(pred, target_a.long()) * (1. - lam) + loss_f(pred, target_b.long()) * lam
else:
pred = model(points)
loss = loss_f(pred, target.long())