Visual Image

이미지는 거의 대부분 2D 직사각형입니다. 즉, 가로 픽셀 수와 세로 픽셀 수가 있고, 이를 곱하면 전체 픽셀 수가 되는 방식입니다. 이미지의 가로, 세로 위치를 신경쓰지 않고 픽셀들을 길게 풀어 1D로 만드는 경우도 있고, 그렇게 만든 1D 픽셀들을 무작위로 순서를 섞어 만드는 경우도 있습니다. 후자의 경우 순서 변화에 영향을 받지 않는(permutation invariant, PI) 데이터라고 합니다. 이미지 데이터의 경우 변화를 눈으로 확인할 수 있어 직관적이고 피드백이 빠른 편입니다.


Image Augmentation

제한적인 데이터를 사용하는 머신러닝에서는 훈련 데이터에 약간의 조작을 가해 비슷하지만 다른 이미지를 만들어 훈련하곤 합니다. 특히 데이터가 엄청나게 중요해진 딥러닝에서는 이런 데이터 변조(augmentation)이 꼭 필요하게 되었습니다. 특히 실전에 가까운 응용일 수록 데이터 변조를 어떻게 했느냐가 또 하나의 중요한 포인트가 되곤 합니다. 변조를 거친 데이터와 그렇지 않은 데이터의 성능을 비교하는 것은 문제가 됩니다.

데이터 변조와 구분되어야 할 것이 데이터 전처리(preprocessing) 입니다. 전처리는 데이터 전체에 공통적으로 적용되는 알고리즘입니다. 모든 데이터가 공통적으로 거치는 동일한 과정이 전처리 입니다. 한편, 각 데이터마다 다르게 / 같은 데이터더라도 매번 다르게 적용하는 것이 데이터 변조입니다.

훈련 때 데이터 변조를 사용했다면, 테스트 데이터에도 데이터 변조를 사용할 수 있습니다. 예를 들어 훈련 때 좌우반전을 사용했었더라면 테스트 데이터들에 대해서도 좌우반전시킨 데이터를 테스트할 수 있습니다. 이 경우, 성능을 높이기 위해 동일한 테스트 데이터를 여러 번 다른 방식으로 변조시킨 후 이 결과를 종합해 해당 데이터를 맞췄는지를 볼 수 있습니다.

Crop, Rotate, Flip, Translate, Resize

가장 간단한 변조 방법은 잘라내기(crop), 회전(rotate), 뒤집기(flip) 입니다. 이미지에서 중심 부분이 중요하다고 생각하는 경우 가장자리의 픽셀들을 잘라낼 수 있습니다. 랜덤한 각도로 회전시키기도 합니다. 뒤집기도 많이 사용하는데, 보통 좌우반전을 합니다. 상하반전은 잘 하지 않습니다. 원래 이미지에서 자동차였으면 뒤집어도 자동차일 테니까, 뒤집는 것 만으로 데이터를 2배로 늘려 학습할 수 있습니다.

이미지에서 작게 잘라낸 부분은 보통 패치(patch)라고 합니다. 300x300 이미지에서 250x250 패치들을 잘라낸다고 할 때, 네 귀퉁이에서와 중앙에서 잘라내는 것 만으로 같은 라벨이 붙은 이미지 5개를 얻을 수 있습니다. 실제 제한된 데이터만으로 최고의 성능을 내야 할 때 많이 사용되는 방법입니다. 랜덤하게 패치를 잘라내는 것도 좋고, 어느 정도 규칙을 두고 잘라내는 것도 좋습니다.

회전을 잘 하지 않는 이유는 CNN의 크기가 어느 정도 커지면 회전이 들어간 데이터도 잘 분류하기 때문입니다. CNN을 쓰는 것은 어느 정도 회전에는 크게 영향을 받지는 않습니다. 하지만 넣어서 나쁠 건 없겠죠!

이미지의 크기는 유지한 채로 상하좌우로 몇 픽셀씩을 밀기도(translate) 합니다. 이 경우 빈 공간이 생기는데, 0으로 채우기도 하고(zero filling), 가장 근접한 픽셀로 채우기도 하고(nearest neighbor), 밀려난 부분을 가져와 채워넣기도(rolling) 합니다.

그 외에, 이미지의 크기가 다양한 경우가 있습니다. 이 경우 일괄적으로 크기 수정(rescale)을 통해 동일한 사이즈로 맞추고 훈련을 진행합니다. 보행자 인식을 예로 들면, 어떤 사람은 32x56 픽셀 안에 있고, 어떤 사람은 41x 78 픽셀에 있는 등 사이즈가 다양하면 일괄적으로 약간 늘리고 줄여서 32x64 픽셀 안에 들어오도록 크기를 조정합니다. 가로세로 비율(aspect ratio)이 중요한 이미지의 경우, 짧은 변을 맞추고 잘라내거나 긴 변을 맞추고 빈칸을 채우기도 합니다. 확대(zooming)도 꽤 사용되는 테크닉입니다.

Color modification

색감을 바꾸는 작업으로 색 이탈(color jittering)이 있습니다. RGB 값을 바꾸는 건데, 그냥 RGB에 랜덤 노이즈를 무작위로 더해 주기만 해도 이상한 색감이 됩니다. 좀 더 잘 하는 방법은 각 이미지에 PCA를 통해 찾은 중요 성분들만큼을 랜덤하게 더해 주는 것입니다. 이 방법은 AlexNet에서 처음 사용되었습니다. 전체 이미지의 R, G, B에 대해 공분산(covariance matrix)를 구하고, 다음과 같은 값을 각각의 픽셀에 더해 줍니다.

\(v_i\)는 고유벡터(eigen vector), \(\lambda_i\)는 고유값(eigen value), \(\alpha_i\)는 매번 새로 추출하는 랜덤한 값입니다. 앞의 두 개는 한 번만 계산해 놓으면 되기 때문에 계산이 번거롭지 않습니다. 이미지 분류는 밝기, 색상과 색상의 세기에 관련이 없기 때문에 ImageNet 같은 곳에서 좋은 결과를 얻었습니다. 이 외에도, 최근에는 색 대조(contrast)를 높이는 경우도 있다고 합니다.

Noise Addition

순수하게 원래 들어 있던 데이터만을 사용할 수도 있지만, 데이터에 노이즈를 더하거나 데이터의 일부를 누락시키는 등 여러 가지 변형을 거친 데이터를 훈련에 사용할 수도 있습니다. 일반적으로 이렇게 왜곡된 데이터를 같이 훈련시킬 경우 데이터에 꼭 필수적인 특징을 잘 찾아내도록 인공신경망 훈련이 가능합니다.

가장 대표적인으로는 가우시안 랜덤 노이즈를 더할 수 있습니다. 이 소음은 평균 0, 표준편차 1(혹은 0.1, 0.01 등)인 정규분포에서 무작위로 추출한 값을 원래 데이터에 더하는 방식으로 만들 수 있습니다. 한가지 주의해야 할 것은, 우리가 처음에 갖고 있던 데이터도 완전히 노이즈가 없거나 편향되지 않은 상태는 아니라는 점입니다. 추출되는 과정의 노이즈, 선택되는 과정의 편향 등 다양한 간섭이 이미 적용된 데이터이기 때문에 자칫 잘못하면 성능이 확 나빠지는 결과를 얻을 수도 있습니다.


Image Preprocessing

데이터 전처리는 CNN이 발전하면서 잘 사용하지 않는 추세이지만, 평균을 0으로 맞추는 작업과 데이터의 크기(scale)를 보정해 주는 것은 필수입니다.

Zero centering, Scaling

훈련 데이터 전체에 대해, 각 픽셀에 들어갈 값이 평균 0이 되도록 합니다. 즉, 전체 이미지를 더하고 갯수로 나눠 '평균 이미지'를 구하고, 이 이미지를 모든 이미지에서 빼 줍니다. 이 과정은 거의 필수입니다!

0부터 255까지 나오는 이미지에서 127.5를 빼서 평균을 0으로 맞췄다고 하더라도 입력의 범위(dynamic range)가 너무 넓은 것은 훈련이 안 되는 원인입니다. 이를 위해 간단하게 크기를 조정할 수 있습니다. [0, 255] 사이의 값을 갖는 경우 255로 나눠 [0, 1] 사이의 값으로 바꿀 수 있습니다. [0, 1] 이나 [-1, 1] 사이의 값으로 선형적으로 변환시킵니다. [0, 1]의 경우 나중에 Sigmoid 함수의 출력과 비교할 수 있고 [-1, 1]의 경우 Tanh 함수의 출력과 비교할 수 있기 때문입니다.

각 이미지에 대해 픽셀의 최댓값이 1, 최솟값이 -1이 되도록 선형적으로 크기를 보정(linear scaling)하기도 합니다. 이를 최대-최소 크기보정(max-min scaling)이라고 합니다. 보통 zero centering 과 같이 하지는 않는 것 같습니다.

Contrast Normalization

다양한 이미지로 학습하는 경우 이미지마다 밝기가 다르고 찍은 환경이 다를 수 있습니다. 이것을 어느 정도 통일해 주는 것이 대비 표준화(contrast normalization) 과정입니다. 거의 언제나, 대비 표준화를 거치고 나면 훈련에 사용하기 좋은 데이터가 됩니다.

표준화 과정은 평균을 빼고 표준편차로 나눠주는 \( \hat X = \frac{X - E(X)}{\sigma(X)} \) 과정입니다. 전체 픽셀들의 분포가 평균이 0이고 분산이 1인 정규분포로 바뀌게 됩니다. 이 과정에서 신경써야 할 것은 2가지가 있습니다.

  1. 전체 이미지에 대해서 하는지, 각각의 이미지에 대해서 하는지
  2. 전체 채널에 대해서 하는지, 각각의 채널에 대해서 하는지

전체 이미지에 대해서 하는 경우 전체 대비 표준화(Global Contrast Normalization, GCN), 각각의 이미지에 대해서 하는 경우 개별 대비 표준화(Local Contrast Normalization, LCN)라고 합니다. GCN은 feature-wise 라고 하기도 하고, LCN은 sample-wise 라고 하기도 합니다. GCN을 한다면 모든 훈련 이미지의 픽셀들에 대해 평균과 표준편차를 구하고 이 평균과 표준편차로 모든 이미지의 픽셀들을 표준화합니다. LCN을 한다면 각각의 이미지의 픽셀들에 대해 평균과 표준편차를 구하고 해당 이미지의 픽셀들을 표준화합니다. GCN과 LCN 모두 데이터에 대해 한 번만 수행해 놓으면 됩니다.

테스트 데이터에 대해서는 조금 상황이 다른데, GCN에서 사용한 평균과 표준편차 행렬은 훈련 데이터로 구한 것이기 때문입니다. GCN을 쓴 경우 훈련 데이터로 만든 평균과 표준편차를 그대로 사용합니다. LCN을 쓴 경우는 이런 문제가 없습니다.

Whitening

백색화(whitening)는 각 픽셀들의 상관관계를 (거의) 없애고 싶을 때 사용하는 방법입니다. 이상적으로 모든 픽셀들이 서로 독립적이라면 공분산(covariance) 행렬이 단위행렬이 됩니다. 이 과정에서 원본 이미지는 전체적으로 노이즈(white noise)처럼 바뀌게 되고 몇몇 특징적인 부분만이 살아남습니다. 유사한 변환으로, 특정 공분산 행렬을 유도하는 coloring 이 있습니다. 공분산을 단위행렬로 바꾸는 작업은 eigenvalue(고유값)들을 전부 1로 맞추는 과정이라고 볼 수 있습니다. 따라서, 이 과정에서 고유값을 구할 수 있는 SVD 행렬 분해가 사용됩니다. 백색화 중 가장 많이 사용되는 백색화는 ZCA whitening 입니다. 가장 잘 설명된 페이지는 ZCA 입니다. 최근에는 잘 사용하지 않습니다.

백색화를 진행하기 위해서는 반드시 평균을 0으로 맞춰줘야 하기 때문에 보통 백색화 이전에 대비 표준화가 같이 진행됩니다. LCN을 꼭 써야할 것 같지만 GCN을 쓰는 경우도 있습니다. 혹은, 평균을 빼 평균을 0으로 만들기는 하지만 표준편차로 나누지는 않기도 합니다.

공분산 식은 다음과 같습니다. 평균이 0인 경우, 공분산 식은 단순히 벡터의 곱이 됩니다. 만약 하나의 벡터에서 원소끼리의 공분산을 구하게 된다면 식은 다음과 같이 바뀝니다.

32x32 이미지의 경우, 1024차 벡터로 바꿔 공분산 행렬을 구합니다. 이 경우 1024x1024 행렬이 되고, (a, b) 번째 행렬의 원소는 a 번째 픽셀과 b 번째 픽셀이 얼마나 연관되어 있는지를 보여주게 됩니다.

우선 이미지를 일렬로 펴 공분산 행렬을 구합니다. 데이터 여러 개를 동시에 백색화를 진행하지만 공분산 행렬의 크기는 동일합니다. 32x32x3채널 데이터의 경우 일렬로 펴면 3072 차원 벡터가 됩니다. 이 이미지를 100개 동시에 백색화를 한다면 (100, 3072) 크기의 데이터가 되고, 이 데이터를 전치(transpose)해 곱하면 3072x3072 행렬을 얻습니다. 이 행렬을 데이터 개수인 100개로 나눠주면 공분산 행렬을 구하게 됩니다.

이제 이 행렬을 SVD 분해하고, 각각의 고유값을 보정합니다.

이렇게 만든 새로운 S를 사용해 백색화 행렬(whitening matrix)을 만듭니다. PC 행렬이라고 하기도합니다. \(\epsilon\)의 크기를 키울수록 전체적으로 균일한 고유값을 얻게 되기 때문에, RGB 채널을 모두 한 번에 사용하는 경우 \(\epsilon\)을 0.01 정도로 크게 해 주는 것이 도움이 된다고 합니다.

\(P\)를 원래 데이터 \(X\)에 곱하면 ZCA whitening 이 완료됩니다. 주의할 점은, 이 \(P\)를 훈련 데이터에 대해 구한 뒤 \(P\)를 그대로 이용해 테스트 데이터에 적용해야 한다는 점입니다.

원래 \(C\)와 바뀐 \(\hat C\)가 어떻게 바뀌는지 보면 우리가 목표한 바대로 공분산 행렬이 어떻게 바뀌는 지를 알 수 있습니다.