Object Detection(객체 탐지)를 위해서는 먼저 Object Localization에 대해서 학습하는 것이 필요하다.
Object Localization
우리는 이미 Image Classification에는 익숙하다. Classification with localization은 단순히 이 object가 자동차라는 것뿐만 아니라, 이 알고리즘이 object를 대상으로 bounding box를 표시하는 것을 의미한다. (빨간색 박스)
Detection Problem에 대해서 알아볼텐데, 사진 속에 object가 여러개인 경우가 발생한다. 이때, 모든 object를 탐지해야될뿐만 아니라 위치 또한 알아내야한다. 특히 자율주행에서 이 작업을 수행할 때, 다른 자동차들 뿐만 아니라 보행자, 오토바이, 다른 주변 물건들까지도 탐지해야할 수 있다. 지금은 하나의 object만 다루도록 한다.
우선 Classification with localization에 대해서 자세히 알아보도록 하자.
Classification with localization
우리는 이미 이미지를 분류하는 것에 대해서는 익숙할텐데, 여러 layer로 이루어진 ConvNet에 이미지를 입력해서 softmax unit이라는 output vector로 class를 예측할 수 있다.
여기서 예시로 총 4개의 class가 있고, softmax unit은 총 4개가 될 것이다. 여기서 background 는 1,2,3번이 아닌 것을 의미한다.
여기서 만약 이미지에서 자동차의 위치를 알아내고 싶다면 어떻게 해야될까?
위치를 탐지하기 위해서는 Bounding Box의 위치를 나타내는 output을 갖도록 Neural Network를 변경하면 된다. 즉, output으로 bx,by,bh,bw 가 추가될 수 있다. 이 output은 탐지된 object의 bounding box를 파라미터로 나타낸 것이다. bounding box의 중앙 좌표(bx,by)와 폭(bw) 그리고 높이(bh)에 의해서 위치를 탐지하게 된다.
여기서 왼쪽 위 모서리 (0,0), 오른쪽 아래 모서리는 (1,1) 이다.
이제 신경망이 예측하려고자 하는 training set는 object의 label뿐만 아니라 4개의 정보(bounding box)가 추가된다.
위 이미지에서는 bx=0.5, by=0.7, bh=0.3, bw=0.4 로 나타낼 수 있을 것이다.
이제, target 의 label y 를 아래와 같이 정의할 수 있다.
여기서 Pc 는 이미지에 object 가 존재하는 지에 대한 확률이다. class 1,2,3 은 Pc =1 이며, class 4는 Pc = 0 이다.
또한, bx, by, bh, bw 는 bounding box의 위치 정보이며, 나머지 c1, c2, c3 는 각 class의 확률이다.
그래서 아까전 예시인 이미지는 왼쪽과 같이 y를 나타낼 수 있고, 만약 이미지에 object가 없다면 Pc=0 이고 나머지 정보는 'don't care'로 표시된다.
다음으로는 신경망을 학습시키기 위한 Loss Function(손실 함수)에 대해서 알아보도록 하자.
기본 true label은 y 그리고 신경망을 통해 나온 prediction label은 y^이다.
그리고 MSE(mean squared error)를 사용한다면, Loss function은 다음과 같다.(y는 8개의 unit을 가지고 있다)
설명을 단순하게 하기 위해서 MSE를 예시로 설명했지만, c1,c2,c3에는 log-likelihood loss와 softmax를 사용하고, bounding box 정보에는 MSE를, 그리고 Pc에는 Logistic Regression Loss를 사용할 수도 있다.
Landmark Detection
신경망이 탐지할 object의 bounding box를 위치시키기 위해서 bx,by,bh,bw 정보를 신경망의 output으로 내보내는 방법을 살펴보았다. 더 일반적인 경우에서는 신경망에서 이미지의 주요 포인트(landmark)를 X와 Y의 좌표로 나타낼 수 있다.
얼굴 인식에서 사람 눈의 코너 부분이 어디에 있는지 인식하려고 한다고 해보자.
눈의 코너 부분의 X, Y 좌표를 가질 수 있을 것이다. 따라서 신경망의 output이 눈의 코너 부분의 좌표가 되도록 할 수 있다.
만약 두 눈의 네 개의 코너를 전부 알고 싶다면, l1x,l1y,l2x,l2y,l3x,l3y,l4x,l4y로 output을 출력하도록 수정할 수 있다. 물론 4개 지점 이상의 output도 가능하다. 만약 입을 따라서 주요 landmark를 표시하면, 우리는 입 모양을 찾아내서 이 사람이 웃고 있는지 인상을 쓰고 있는지 말할 수 있을 것이다.
얼굴에 64개의 랜드마크가 있다고 가정해보자. 우리는 이 모든 랜드마크를 포함하는 training set의 label을 생성해서 신경망이 얼굴의 주요 랜드마크가 어디에 있는지 학습시킬 수 있다.
따라서, output 으로 해당 image 가 얼굴인지 아닌지에 대한 정보 1개와 각 랜드마크의 위치 정보 128개, 총 129개의 output unit 을 가질 수 있다. 이는 얼굴의 감정을 인식하기 위한 기본 구성이 된다. (snapchat, AR filter 등에 사용)
만약, pose 를 감지하는 algorithm 을 학습한다면, 위와 같이 어꺠, 팔꿈치, 팔목 등의 몇가지 landmark 의 위치들을 정의할 수 있다. 하지만, 주의해야할 점은 landmark 가 일관성이 있어야 한다는 것이다. 즉, landmark 1은 언제나 왼쪽 눈의 코너부분이고, landmark 4는 항상 오른쪽 눈의 코너부분을 가리켜야한다는 것이다.
Object Detection
앞서 object localization과 landmark detection에 대해서 알아봤다. 이번에는 다른 object detection 알고리즘을 구성해보도록 하자. 바로, Sliding Windows Detection Algorithm 을 사용해서 Object Detection을 위해 ConvNet을 사용하는 방법이다.
만약 자동차를 detect 하는 알고리즘을 만든다고 가정해보자. input x와 output y로 label된 training set를 만들 수 있다.
그래서 이 ConvNet은 ouput y를 출력한다.(input image가 자동차인지 아닌지)
그리고 다음으로는 특정 사이즈의 window를 하나 골라서, 탐색을 시작한다.
그리고 직사각형 영역에 포함되는 이미지를 ConvNet의 입력으로 사용해서 직사각형 영역에 자동차가 있는지 없는지 확인하는 것이다. 위 이미지 위치에서는 자동차가 없다고 output을 나타낼 것이다. 그런 다음에 직사각형 box를 약간 옆쪽으로 옮기고 다시 ConvNet의 입력으로 사용해서 자동차가 있는지 확인한다.
이런 방법으로 Sliding Window Algorithm 은 빨간 사각형이 포함하는 이미지 영역을 가져와서 ConvNet으로 수행하는 작업을 반복한다. window가 위치할 수 있는 모든 위치에서 확인할 수 있도록 계속 반복한다. 만약 조금 더 빠르게 진행하고 싶다면 strides를 더 크게 지정해서 sliding window 알고리즘을 수행할 수도 있다. (정확도는 떨어진다)
그리고 더 큰 box를 사용해서 위 작업을 반복한다.
sliding window Algorithm 에 큰 단점은 바로 Computaional Cost이다. 이미지에서 많은 box 영역들을 추출해서 Convnet으로 각각 독립적으로 확인하기 때문이다. 만약 아주 큰 stride를 사용한다면, 확인할 box 영역들은 줄어들어서 더 빨라지겠지만, 성능에 안좋은 영향을 끼칠 수 있다. 그리 나쁜 방법은 아니지만, sliding window는 매우 느리고, 또한 매우 작은 stride를 사용하지 않는 한, object의 정확한 위치를 감지하는 것도 불가능하다.
Convolutional Implementation of sliding windows
위에서 보았듯이 ConvNet을 사용한 Sliding Window Algorithm 을 알아봤는데, 이 방법이 매우 느리다는 것을 보았다.
이번에는 이 알고리즘을 어떻게 Convolutional 하게 implement 할 수 있는지 알아볼 것이다. 이를 알아보기 전에 어떻게FC(Full connected) layer를 Convolutional Layer로 바꿀 수 있는지 알아보자.
Object Detection 알고리즘이 14x14x3의 input을 가진다고 가정하고, 5x5 filter 16개를 사용한다고 하자.
위 구조는 기본적으로 object를 분류하기 위한 모델이다.
object detection을 위해서 우리는 위 모델에서 FC를 400개의 5x5x16 filter로 튜닝해서 아래와 같이 convolve 시킬 것이다.
이렇게 튜닝한 모델이 어떻게 object detection(sliding window)에 사용이 될까? (OverFeat 논문에 근거)
우리는 14x14x3의 input image를 ConvNet에 통과시켜서 1x1x4의 결과를 얻었다.
만약 16x16x3의 input을 입력으로 사용한다면 어떻게 되는지 살펴보자.
기존 sliding window 알고리즘이라면, 14x14 box를 사용해서 한 칸씩 이동하면서 각각의 14x14x3 이미지가 ConvNet에 독립적으로 수행하게 된다.(stride가 2라면 16x16x3의 이미지에서 총 4번의 ConvNet 연산이 수행된다) 즉, 16x16x3 이미지를 입력으로 사용하면, 총 4개의 14x14x3의 입력을 각각 ConvNet을 수행하게 되고 겹치는 부분은 연산이 중복된다. 하지만, 위에서 튜닝한 방법을 사용하면 4개의 이미지에서 중복되는 연산이 공유가 가능하게 된다.
16x16x3을 튜닝한 ConvNet에 통과시키면 2x2x4의 output이 나오게 되고, 1x1x4의 output이 총 4개가 나오게 되는 것이다. 따라서, 튜닝을 통해서 독립적인 input으로 계산하는 것이 아닌, 4개의 input을 하나의 계산으로 결합해서 공통되는 부분을 공유하게 되는 것이다.
이를 위해서 사전에 FC layer를 Convolutional Layer 로 바꾼 것이다.
이제, 28x28x3의 이미지로 다시 한번 어떻게 결과가 나오는지 살펴보자.
기준이 되는 box의 크기가 14x14이기 때문에, 28x28x3의 이미지에서 sliding window를 적용하면 총 8x8개의 독립적인 input이 생기게 된다. 하지만 튜닝한 ConvNet을 사용하면 공통되는 연산 부분을 공유하게 되고, output으로 8x8x4의 결과를 얻을 수 있다. 이렇게 Sliding Window의 연산 비용 문제가 해결이 된다.
하지만, 여기에는 bounding box의 위치가 그리 정확하지 않다는 단점이 있는데, 이 문제는 어떻게 해결할 수 있는지 살펴보도록 하자.
Bounding Box Predictions
Slinding Window 알고리즘에 Convolutional 구현을 적용해서 계산 비용 문제를 해결했지만, 정확한 bounding box를 찾을 수가 없다는 문제가 발생했다. 즉, Slinding Window의 box를 사용해서 탐색하다보면, object가 정확하게 그 box에 위치하지 않고 object의 일부만 걸치는 문제가 발생할 수 있다는 것이다.
또한, object가 정사각형의 bounding box를 가지지 않을 수도 있다. 이러한 문제점들은 YOLO(You Only Look Once) 알고리즘을 사용함으로써 이를 해결해줄 수 있다.
input 이미지가 100x100인 경우를 예시로 살펴보자.
우선 이미지의 3x3 grid를 설정한다. (설명을 위해서 3x3으로 설정했지만, 보통 19x19 grid를 사용)
YOLO 알고리즘의 기본 아이디어는 위에서 학습했던 Image Classification과 Localization을 9개의 grid에 각각 적용하는 것이다. 그리고 training set에서 사용하는 label을 정의해주어야 하는데, 9개의 grid셀에 대해서 label y를 설정한다. 여기서 y는 위에서 본 것처럼 8차원 vector이다.(Pc,bx,by,bh,bw,c1,c2,c3) YOLO 알고리즘은 Object의 중간점(Mid Point)를 취해서, 이 중간점을 포함하는 grid 셀에 object를 할당한다.
그래서, 왼쪽 위 보라색 셀은 object가 존재하지 않기 때문에 pc=0이 되고 나머지 요소들은 'don't care'가 된다. 초록색으로 표시된 셀은 차량이 존재하고, 그 차량의 중간점이 포함되기 때문에 [1,bx,by,bh,bw,0,1,0] 으로 labeling되고, 노란색으로 표시된 셀도 마찬가지이다.
3x3 grid로 구역이 나누었고, 각 grid 셀에서 8차원 vector y를 가지고 있기 때문에, Target output 3x3x8의 형태를 가지게 되며, output은 각각의 구역과 매칭이 된다.
즉, input 100x100x3을 Conv와 MaxPool을 거쳐서 3x3x8의 output이 나오게 된다. 여기서는 3x3 grid를 사용했지만, 보통 19x19 grid를 사용하고, 19x19 grid를 사용한다면 output은 19x19x8의 형태를 띄게 된다. 19x19 grid를 사용한다면, 더욱 세밀하게 구역을 나누는 것이고, 하나의 셀에 여러개의 object가 할당될 가능성을 감소시켜준다. -> 하나의 셀에 object의 Mid Point가 두 개가 될 확률을 줄여준다.)
결국 YOLO 알고리즘은 Object Classification/Localization과 Sliding Window Convoluional Implementation을 합친 것이라고 볼 수 있다.
추가로, bounding box 의 bx, by, bh, bw 는 어떻게 encoding 해야 할까?
YOLO 알고리즘에서 각 cell에서 왼쪽 위의 점은 (0, 0)이고, 오른쪽 아래의 점은 (1, 1)이다. 그리고 너비와 높이는 cell의 전체 너비와 높이의 비율로 지정된다. 따라서 노란색 셀에 있는 차량의 bounding box 정보는 bx=0.4,by=0.3,bh=0.9,bw=0.5로 나타낼 수 있다. 그리고 bounding box의 mid point는 (0, 0)과 (1, 1) 사이의 좌표값을 가지기 때문에 항상 0과 1사이의 값을 가지게 되지만, bounding box의 너비와 높이는 각 cell의 크기를 벗어날 수 있기 때문에 1보다 커질 수 있음에 유의한다.
Bounding box 를 설정하는 방법은 여러가지가 있지만, 위 방법도 합리적인 방법 중의 하나이며, YOLO 논문을 살펴보면 훨씬 더 잘 동작할 수 있도록 파라미터화된 것들이 있다.
Intersection over union
Intersection over union(IoU)은 Object Detection이 잘 동작하는지 판단하기 위한 함수이다. 이 함수는 Object Detection 알고리즘을 평가할 때나 더 잘 동작되도록 하기 위해서 사용된다.
만약 Object Detection 알고리즘을 통해서 보라색의 bounding box를 얻었다면, 이것은 좋은 결과일까?
좋은 결과인지 판단하기 위해서 IoU 함수를 사용하고, 이 함수는 두 개의 bounding box의 Intersection over Union을 계산한다.(여기서는 보라색 박스와 빨간색 박스의 IoU 계산)
즉, 두 개의 bounding box의 전체 넓이와 겹치는 부분의 넓이의 비율을 계산하는데, 보통 IoU 값이 0.5보다 크다면 예측한 bounding box의 결과가 옳다고 판단한다.
예측된 bounding box가 실제 측정한 bounding box와 완벽하게 일치하면 IoU는 1이 되며, 일반적으로 0.5보다 크거나 같다면 그 bounding box는 합리적이라고 판단한다. 보다 엄격하게 체크하고 싶다면, 기준을 0.6 등으로 높이면 된다.
IoU는 Object Localization Detection의 정확성 여부를 평가하는 방법이고, 일반적으로는 두 bounding box 사이의 겹치는 정도의 척도라고 할 수 있다. 또한, 두 bounding box가 얼마나 비슷한지 측정하는 방법이 될 수도 있다.
이는 non-max suppression에서 사용된다.
Non-max suppression
지금까지 알아보았던 Object Detection의 문제점 중 하나는 알고리즘이 동일한 object를 여러번 탐지할 수 있다는 것이다.
즉, 위와 같이 19x19 grid를 사용했을 때, object의 Mid Point가 다양한 cell에서 포함된다고 판단될 수 있다는 것이다.
이 경우에 Non-max suppression을 사용하면 알고리즘이 하나의 object를 하나의 cell에서 한번만 탐지할 수 있도록 한다.
19x19 grid, 361개의 grid cell에서 image classification/localization을 수행하고 있기 때문에, 위와 같이 각 cell에서 object가 여기에 있다고 판단할 수 있다. (박스 옆에 숫자는 Pc를 의미한다.) 따라서, 알고리즘을 실행할 때, 각 object에 대해서 여러 번의 탐지가 이루어 질 수 있다.
여기서 non-max suppression 이 하는 일은 하나의 object에 대한 여러 detection을 정리하는 것이다. 우선 각각의 detection 과 관련된 확률을 조사한다. 즉, Pc 를 체크하는 것인데, 실제 알고리즘에서는 c1, c2, c3와 곱한 확률을 의미하지만, 여기서는 자동차 class만 판단한다고 가정하고(class가 하나만 존재) 단순히 Pc 만을 가지고 설명할 것이다. Pc 를 조사하고 가장 큰 것만 취한다. 즉, max가 아닌 것들은 억제한다. 위 이미지ㅡ이 오른쪽차량의 경우에는 0.9의 Pc 만을 취하는 것이다.
그리고 나서, non-max suppression 은 남은 box를가지고, 0.9의 box 와의 IoU 를 조사한다.
그리고, 계산된 IoU가 많이 겹쳐있어서 높다면, 그 box는 suppress 한다. 만약 낮은 IoU라면, 다른 object를 탐지했을 가능성이 높고, 제거하지 않는다. 위 경우에서는 차량만 탐지하는 예시였고, IoU 또한 높은 값으로 겹쳐있으므로 나머지 0.6, 0.7의 box는 제거된다. 이미지 왼쪽의 차량도 마찬가지이다.
따라서, non-max suppress 과정을 거치면 다음과 같이 정리가 된다.
위 예시를 통해 non-max suppression 알고리즘을 정리하면 다음과 같다. (class는 차량판단만 한다고 가정)
- 각 cell의 output 에서 Pc 를 조사해서 0.6 이하라면 제거
- 남은 box 중에서 가장 높은 Pc 를 갖는 박스를 예측된 bounding box로 선택
- 남은 box 들의 IoU(2에서 선택한 박스와의) 를 계산해서 0.5 보다 크다면, 같은 object일 확률이 높으므로 제거
여기서 class가 자동차 하나뿐이였지만, 만약, 자동차, 보행자, 오토바이로 3개의 object 를 탐지한다면, non-max suppression을 독립적으로 각각 3회 수행한다. (output class당 수행해야 함)
Anchor box
지금까지 보았듯이 Object Detection의 문제점 중의 하나는 각 grid cell이 오직 하나의 object만 감지할 수 있다는 것이다. 여기에서 우리는 anchor box라는 아이디어를 가지고 이 문제를 해결할 수 있다.
아래 예시를 보자.
위 이미지에서 자동차와 사람은 거의 동일한 Mid Point를 가지고 있다. 즉, 이전의 알고리즘을 사용한다면, output y가 탐지할 object 중의 하나를 선택해야 한다.
하지만 anchor box를 사용하면 이 문제를 해결할 수 있는데, 우선 anchor box의 모양을 미리 정의한다.
그리고 두 개의 anchor box를 output과 연관시킨다. (일반적으로 5개 or 그 이상의 anchor box를 사용함) 따라서 두개의 anchor box로 인해서 output y는 각 anchor box에 대한 8차원의 unit을 가지게 된다. 위 이미지에서 보행자는 Anchor Box 1에 더 유사하고, 자동차는 Anchor Box 2에 더 유사하기 때문에, Anchor Box 1에 대한 output은 보행자 정보로, Anchor Box 2는 자동차 정보로 encoding 할 수 있다.
Anchor Box 알고리즘을 정리하면 다음과 같다.
이전에는 학습 이미지에서 각 object는 object의 Midpoint를 포함하는 하나의 grid cell에 할당이 되었다면,
두 개의 Anchor Box를 사용함으로, 각 object는 object의 Midpoint를 포함하는 grid cell에 할당됨과 동시에 IoU가 가장 높은 Anchor Box에 할당된다.즉, object는 (grid cell, anchor box)의 쌍으로 할당이 되는 것이다.
따라서, 위 이미지 예시에서 output y는 다음과 같다.
만약 이 이미지에서 사람이 없다면, Anchor Box 1에 대한 정보에서 pc는 0이되고, 나머지는 'don't care'가 된다. 그리고 Anchor Box 2의 정보는 그대로 차량의 정보를 가지게 될 것이다.
여기서 2개의 Anchor Box를 사용했는데, 만약 3개의 object의 Midpoint가 같은 grid cell에 있다면 어떻게 될까?
이런 경우에는 알고리즘이 잘 처리하지 못하게 될 것이다. 이런 경우에 default tiebreaker(3개 이상의 object가 탐지될 경우의 예외)를 설정해두어야 한다. 실제 19x19 grid에서 두 object가 같은 midpoint를 가지는 확률이 그리 크지는 않다.
Anchor Box의 선택은 manual로 선택을 할 수도 있고, K-mean 알고리즘을 통해서 얻고자하는 유형의 object 모양끼리 그룹화할 수도 있다.
YOLO Algorithm
이번에는 위에서 알아봤던 내용들을 결합해서 YOLO Object Detection Algorithm을 정리해보자.
먼저 training set를 구성하는 방법이다.
여기서 anchor box를 두 개 사용할 것이고, class는 총 3개이기 때문에 output y의 shape는 3x3x2x8 or 3x3x16이다.(보통 anchor box별로 나누지 않고, vector 꼴로 나타내는 것으로 보임)
여기서 대부분의 grid cell은 object가 존재하지 않기 때문에, 각 anchor box의 pc는 0이고, 초록색으로 표시된 cell에만 object가 존재한다. 또한, 차량의 bounding box가 anchor box 2의 모습과 유사하기 때문에(더 높은 IoU를 가지기 때문) anchor box 2에 해당하는 정보를 구체화한다.
만약 19x19 grid cell을 사용하고, anchor box 또한 5개를 사용한다면, output y는 19x19x5x8 or 19x19x40의 shape를 갖게 된다.
그리고 예측을 하게 되면, 다음과 같다.
object가 없는 cell은 파란색과 같은 결과를 나타낼 것이고, 초록색 cell은 anchor box 2에 bounding box의 정보를 담아서 output으로 예측할 것이다.
마지막으로 non-max suppression을 수행하는데, 다른 이미지를 가지고 살펴보자.
anchor box가 두개이기 때문에, 각 grid cell은 최대 2개의 bounding box를 가질 수 있다. 여기서 낮은 확률을 가지는 예측 결과는 제거하고, 각 class에 non-max suppression을 적용해서 최종 예측결과를 얻는다.
YOLO 알고리즘은 실제로 가장 효과적인 Object Detection 알고리즘 중의 하나이다.
Region Proposals
Sliding Window 알고리즘을 떠올려보면, window들을 슬라이딩하면서 object를 탐지하는 방법이지만, 많은 구역들을 살펴보는 단점이 있다. R-CNN은 이렇게 탐지하는 것이 아닌, 이미지로부터 Region 후보군을 뽑아내서 object를 탐지하는 방법이다. 즉, 맨 오른쪽 이미지처럼 segmentation algorithm을 통해서 여러개의 집합으로 나누어서 유사한 픽셀들을 뽑아내서 object를 탐지한다.
물론 R-CNN 알고리즘은 느리지만, 이 알고리즘의 속도를 높이기 위한 연구들이 있었다.
Semantic Segmentation with U-Net
한 단계 더 발전된 알고리즘이다. 여기서는 검출된 객체 주위에 정확한 경계를 그려서 어떤 픽셀이 객체에 속하고, 어떤 픽셀이 속하지 않는지를 정확히 구분하는 것이 목표이다. 이 시맨틱 분할 알고리즘은 오늘날 많은 상업적 응용 프로그램에서도 유용하게 사용되고 있다. 픽셀별로 적절한 클래스 레이블을 개별적으로 지정해야 하는 많은 컴퓨터 비전 응용 분야에서 매우 유용한 알고리즘이다.
예를 들어 자율 주행 자동차를 만들고 있고, 아래와 같은 입력 이미지가 있다고 가정해 보자. 이 이미지에서 다른 차들의 위치를 감지하고 싶다고 해보자. 객체 검출 알고리즘을 사용하면, 다른 차량들 주위에 경계 상자들을 그리게 될 것이다. 이것만으로도 자율 주행 자동차에는 충분할 수 있다. 하지만 이미지의 모든 픽셀이 무엇인지를 학습 알고리즘이 알아내기를 원한다면, 시맨틱 분할 알고리즘을 사용하여 오른쪽과 같은 결과를 출력할 수 있다.
예를 들어, 도로를 감지하려고 하고, 도로 주위에 경계 상자를 그리려 한다면, 이는 그다지 유용하지 않을 수 있다. 반면 시맨틱 분할을 사용하면, 알고리즘은 각 픽셀이 주행 가능한 도로인지 아닌지를 레이블링하려고 한다. 아래 그림에서 어두운 녹색으로 표시된 부분이 주행 가능한 도로를 나타낸다. 시맨틱 분할의 활용 사례 중 하나는 자율 주행 자동차 팀이 주행 가능한 표면을 나타내는 픽셀들을 정확히 파악하기 위해 사용하는 것이다.
다른 응용 사례를 살펴보자.
의료 영상에서, 예를 들어 흉부 엑스레이가 주어졌을 때 특정 질환을 진단하고자 할 수 있다. 하지만 의사들에게 더 유용한 것은, 환자의 해부학적 구조에서 특정 부위가 정확히 어디인지 분할(segmentation)할 수 있는 것이다. 왼쪽 이미지에서는 폐, 심장, 그리고 쇄골(즉, 쇄골뼈)이 다른 색상으로 분할되어 있다. 이러한 분할 작업은 비정상적인 부분을 쉽게 찾아내고, 심각한 질병을 진단하며, 수술 계획을 세우는 데 도움을 줄 수 있다. 오른쪽 예시에서는 뇌 MRI 스캔을 사용하여 뇌종양을 감지하고 있다. 수작업으로 종양을 분할하는 작업은 매우 시간이 많이 걸리고 힘든 일이다. 그러나 학습 알고리즘이 종양을 자동으로 분할할 수 있다면, 이는 방사선과 의사의 시간을 많이 절약해 주고, 수술 계획에도 유용한 입력이 될 수 있다. 이 결과를 생성하는 데 사용된 알고리즘은 U-Net 이라는 알고리즘이다.
자동차를 배경에서 분할하는 예제를 사용해 보자. 이 이미지에서 자동차를 분할하는 것만이 목표라고 가정해 보자. 이 경우, 두 가지 클래스 레이블을 사용할 수 있다. 하나는 자동차를 나타내는 1번 클래스, 다른 하나는 자동차가 아닌 것을 나타내는 0번 클래스이다. 이 경우 시맨틱 분할 알고리즘, 즉 유닛 알고리즘의 작업은 이 이미지의 모든 픽셀에 대해 1 또는 0을 출력하는 것이다. 여기서 픽셀이 자동차의 일부라면 1로, 그렇지 않다면 0으로 레이블링해야 한다.
대안으로, 이 이미지를 더 세밀하게 분할하고 싶다면, 자동차를 1로 레이블링할 뿐만 아니라 건물이 어디에 있는지도 알고 싶다고 가정할 수 있다. 이 경우, 2번 클래스는 건물, 마지막으로 3번 클래스는 지면 또는 도로를 나타내게 됩니다. 이 경우, 학습 알고리즘의 작업은 각 픽셀을 다음과 같이 레이블링하는 것이다. 이처럼 픽셀별 레이블을 오른쪽으로 이동시키면, 유닛 알고리즘이 출력해야 할 결과를 얻게 된다.
이제 단일 클래스 레이블이나 경계 상자를 지정하는 좌표 대신, 신경망은 전체 레이블 행렬을 생성해야 한다. 이를 위해 어떤 신경망 아키텍처가 적합할까? 익숙한 객체 인식 신경망 아키텍처에서 시작해 보고, 이를 어떻게 수정해야 전체 레이블 행렬을 출력할 수 있을지 알아보자.
다음은 익숙한 CNN Architecture 이다. 여기서 이미지를 입력하면, 여러 층을 거쳐 클래스 레이블 y^을 생성하게된다. 이를semantic segmentation architecture 로 변경하기 위해, 마지막 몇 개의 FC layer 을 제거해 보자.
시맨틱 분할의 중요한 단계 중 하나는, 왼쪽에서 오른쪽으로 갈수록 이미지의 크기가 점차 줄어들다가, 이제 다시 점차 커져서 출력 크기와 맞추어야 한다는 점이다. 구체적으로, U-Net 아키텍처는 아래와 같이 생겼다.
유닛의 깊이가 깊어질수록 높이와 너비는 다시 커지고, 채널 수는 감소한다. 결국, 고양이의 분할 맵을 얻게 된다.
여기서 이미지를 크게 만드는 작업이 무엇인지 알아보자. 이를 설명하기 위해, transpose convolution을 구현하는 방법을 알아야 한다.
Transpose Convolutions
Normal Convolution 에 대해 익숙할 것이다. 예를 들어, 6x6x3 이미지가 입력으로 주어지면, 이를 3x3x3 필터 세트와 합성곱한다. 만약 5개의 필터를 사용하면, 최종적으로 4x4x5 크기의 출력을 얻게 된다.
Transpose Convolution 은 약간 다르게 작동한다. 예를 들어 2x2 크기의 입력을 주고, 3x3 필터를 사용하여 합성곱하면, 최종적으로 4x4 크기의 출력이 나오게 된다.
이는 원래 입력보다 큰 크기다. 이제 이 과정을 더 자세히 살펴보자.
이번 예제에서는 2x2 크기의 입력을 처리하여 4x4 크기의 출력을 얻고자 한다.
2x2에서 4x4로 확장하기 위해, 3x3 필터를 사용하도록 한다. 필터는 f x f 크기인데, 이번 예제에서는 3x3 필터를 사용할 것이다. 또한 패딩(p)을 1로 설정하고, 출력에서는 1의 패딩을 적용할 것이다. 마지막으로 이 예제에서는 stride 를 2로 설정한다. 이제 transpose convolution 이 어떻게 작동하는지 살펴보자.
먼저 입력의 좌상단 요소인 2부터 시작한다. 이 숫자 2를 필터의 모든 값에 곱하고, 3x3 크기의 출력을 해당 위치에 삽입한다. 패딩 영역은 값을 포함하지 않으므로 무시하고, 빨간색으로 강조된 영역에만 네 개의 값을 삽입한다. 예를 들어, 좌상단 항목은 0 x 2로 계산되어 0이 되고, 다음 항목은 1 x 2로 계산되어 2가 된다. 이런 식으로 나머지 값들을 계산해서 삽입한다.
다음으로, 입력의 두 번째 요소인 1을 살펴보자. 이번에는 초록색 펜을 사용한다. 마찬가지로 1을 필터의 모든 요소에 곱하고, 스트라이드가 2이므로, 숫자를 두 칸 옮겨서 삽입한다. 패딩 영역은 무시하고, 초록색으로 강조된 영역에만 값을 복사한다. 빨간색 필터와 초록색 필터가 겹치는 부분이 있으면, 초록색 값을 빨간색 값 위에 덮어쓰지 않고, 두 값을 더한다. 예를 들어, 처음 필터에서는 이미 2가 있었고, 여기에 초록색 영역의 첫 번째 값을 더하면 2+2가 된다.
다음으로 입력의 좌하단 요소인 3을 살펴본다. 필터의 모든 요소에 3을 곱하고, 한 단계 아래로 이동한다. 두 칸 아래로 이동한 후, 3x3 크기의 정사각형 영역에 값을 채워 넣는다. 예를 들어, 2x3은 6, 1x3은 3으로 계산된다.
마지막으로 입력의 마지막 요소인 2를 살펴본다. 필터의 모든 요소에 2를 곱하고, 이 블록에 더한다. 예를 들어, 1x2는 2가 되고, 나머지 요소들도 같은 방식으로 계산된다.
최종 단계는 4x4 행렬의 모든 숫자, 즉 16개의 값을 모두 더하는 것이다. 예를 들어, 첫 번째 값은 0, 두 번째 값은 2+2=4, 세 번째 값은 0, 네 번째 값은 1이 된다. 이런 식으로 모든 값을 계산해서 최종적으로 4x4 크기의 출력을 얻게 된다.
왜 이런 방식으로 해야 하는지 궁금할 수도 있다. 작은 입력을 받아서 큰 출력으로 바꾸는 여러 가지 방법이 있을 수 있는데, 이는 효과적인 방법 중 하나다. 이 필터의 모든 매개변수를 학습하게 되면, 유닛 아키텍처에서 이 방법이 좋은 결과를 가져오는 걸 알 수 있다.
유닛이 어떻게 작동하는지에 대한 직관을 빠르게 쌓기 위해 아키텍처를 간단히 살펴보겠다. 그리고 다음 영상에서는 세부 사항을 함께 살펴볼 것이다. 시작해보자.
여기 시맨틱 분할을 위한 신경망 아키텍처의 대략적인 다이어그램이 있다.
처음 부분에서는 일반적인 합성곱을 사용한다. 이 부분은 이전에 본 신경망과 유사하게 이미지를 압축하는 역할을 한다. 매우 큰 이미지에서 시작해서, 높이와 너비가 훨씬 작은 활성화로 바뀌게 된다. 이렇게 되면 공간적 정보가 많이 손실되는데, 이는 이미지의 차원이 작아졌기 때문이다. 그러나 깊이는 더 깊어진다. 예를 들어, 이 중간 층에서는 이미지의 오른쪽 아래 부분에 대략 고양이 같은 것이 있다는 것을 나타낼 수 있지만, 세부적인 공간적 정보는 높이와 너비가 작기 때문에 손실된다.
그다음 신경망의 두 번째 절반은 transpose convolution 을 사용하여 표현 크기를 원래 입력 이미지의 크기로 다시 확대한다. 그런데 이 아키텍처에 한 가지 수정을 가하면 훨씬 더 잘 작동하게 된다. 그것이 바로 U-Net 아키텍처로 변환하는 방법인데, 이는 초기 층에서 나중 층으로 넘어가는 skip connection 을 추가하는 것이다. 이렇게 초기 활성화 블록을 나중 활성화 블록으로 직접 복사하게 된다.
왜 이렇게 하는 것이 좋을까?
마지막 층에서 어떤 영역이 고양이인지 판단하는 데 두 가지 유형의 정보가 유용하기 때문이다. 첫 번째는 이전 층에서 얻는 고수준의 공간적, 고수준의 맥락 정보다. 이를 통해 신경망이 이미지의 오른쪽 아래 구석이나 오른쪽 부분에서 고양이 같은 무언가가 있다는 것을 알아낼 수 있을 것이다. 그러나 누락된 것은 매우 세밀하고 정교한 공간적 정보다. 여기 있는 이 활성화 세트는 공간 해상도가 낮아서 높이와 너비가 낮아진다. skip connection 이 하는 일은 신경망이 매우 높은 해상도의 저수준 특징 정보를 가져갈 수 있도록 하는 것이다. 이는 각 픽셀 위치에서 고양이 털 같은 것이 얼마나 있는지를 포착할 수 있게 해주며, 이 정보를 스킵 연결을 통해 나중 층에 직접 전달한다.
이렇게 하면 이 층은 낮은 해상도지만 고수준의 공간적, 고수준의 맥락 정보를 가지고 있으면서도, 동시에 저수준이지만 더 세부적인 질감 같은 정보도 가지고 있게 된다. 이를 통해 특정 픽셀이 고양이의 일부인지 여부를 판단할 수 있게 된다.
유닛이 정확히 어떻게 작동하는지에 대한 세부 사항을 살펴보자.
여기 유닛의 구조가 있다.
먼저, U-Net Architecture 가 최종적으로 어떻게 생겼는지 보여주고자 한다. 참고로, 'U-Net'이라고 불리는 이유는, 이렇게 그리면 U자 모양을 닮았기 때문이다. 이제 이 구조를 하나씩 분해하고 다시 구성해 보자.
유닛의 입력은 이미지이며, 예를 들어 높이 h, 너비 w, 그리고 RGB 채널의 3채널로 구성된 이미지를 입력으로 받을 수 있다. 이 이미지를 얇은 층으로 시각화해보자. 이전에는 신경망 층을 이렇게 3D 블록으로 그렸는데, 이는 h x w x 3의 크기를 가진다. 하지만 유닛 다이어그램을 단순화하기 위해, 이 이미지를 옆에서 본다고 상상하고, 그림의 검은색 직사각형처럼 나타내도록 하겠다. 이렇게 하면, h는 이 직사각형의 높이, 3은 깊이, 즉 채널 수가 된다. 따라서 이 구조는 매우 얇아 보인다. 유닛 다이어그램을 단순화하기 위해 3D 모양 대신 이러한 직사각형을 사용해 알고리즘을 설명하겠다.
이제 유닛의 첫 번째 부분에서는 일반적인 feed forward neural network convolution layer 를 사용한다. 검은색 화살표로 합성곱 층을 나타내며, 그 뒤에 ReLU 활성화 함수가 따른다. 다음 층에서는 채널 수가 약간 증가하지만, 크기는 여전히 h x w에 약간 더 많은 채널을 가지며, 또 다른 합성곱 층과 ReLU 활성화 함수가 이어진다.
여전히 신경망의 첫 번째 절반에 속해 있으므로, 최대 풀링(Max Pooling)을 사용하여 높이와 너비를 줄인다. 그 결과, 높이와 너비는 줄어들지만 채널 수는 증가하게 된다. 그런 다음, 두 개의 더 많은 feed forward convolution layer 와 ReLU 활성화 함수를 적용한 다음, 다시 최대 풀링을 적용한다. 이렇게 반복하여 최종적으로 위와 같은 구조를 얻을 수 있다. 지금까지는 이전에 봤던 일반적인 Conv layer와 activation function, 그리고 간헐적으로 사용된 Max Pooling layer를 사용한 것이다.
이제 이 층의 높이와 너비가 매우 작아졌음을 알 수 있다. 여기서부터 Transpose Convolution layer 를 적용하여 신경망의 차원을 다시 키워 나갈 것이다.
첫 번째 Transpose Convolution layer 에서는 위와 같은 활성화를 얻게 된다. 이 예제에서는 높이와 너비가 증가하지는 않았지만, 채널 수는 감소하였다. 하지만 유닛을 구성하기 위해 해야 할 또 다른 중요한 작업이 있다. 그것은 바로 skip connection 을 추가하는 것이다. 이 연결은 회색 화살표로 나타내며, 이 활성화 세트를 복사하여 오른쪽으로 전달한다. 이렇게 하면, Transpose convolution layer 에서 나온 연한 파란색 부분과 왼쪽에서 복사된 진한 파란색 부분이 결합된 활성화 세트를 얻게 된다. U-Net 구조를 계속해서 빌드하기 위해, 일반적인 합성곱 층과 ReLU 활성화 함수 몇 개를 더 적용하고, 다시 전치 합성곱 층을 적용한다. 이번에는 높이와 너비가 커지기 시작한다. 여기서도 skip connection 을 적용한다. 회색 화살표를 통해 활성화 세트를 복사하여 오른쪽으로 전달한다.
이 과정을 반복하여, 원래 입력 이미지의 높이와 너비로 돌아오게 된다. 그런 다음, 몇 개의 더 많은 feed forward convolution layer 를 적용하고, 마지막으로 이 구조를 semantic segmentation map 으로 mapping 하기 위해 1x1 Conv을 사용한다. 이를 자주색 화살표로 나타내며, 최종적으로 우리가 원하는 출력을 얻는다.
이 출력 층의 크기는 h x w로, 원래 입력과 같은 크기를 가지며, 클래스 수만큼의 깊이를 가진다. 예를 들어, 세 개의 클래스를 인식하려면 이 깊이는 3이 될 것이다. 분할에서 인식하려는 클래스가 10개라면, 마지막 숫자는 10이 될 것이다. 이렇게 하면 모든 픽셀에 대해 h x w 픽셀마다 해당 픽셀이 각각의 클래스에 속할 확률을 나타내는 벡터를 얻게 된다. 그런 다음, 이 n개의 클래스 중에서 arg max를 취하여 각 픽셀을 하나의 클래스로 분류하고, 오른쪽에 표시된 분할 맵처럼 시각화할 수 있다.
'연구실 > 인공지능(Coursera)' 카테고리의 다른 글
[AI 12주차] Sequence Model : 순환 신경망(RNN) (1) | 2024.08.16 |
---|---|
[AI 11주차] Face Recognition (얼굴 인식) & Neural Style Transfer(신경 스타일 전송) (0) | 2024.08.10 |
[AI 9주차] 심층 컨볼루션 모델(Deep convolution model) (0) | 2024.08.07 |
[AI 8주차] Convolution Neural Network (CNN) 기초 (0) | 2024.08.05 |
[AI 7주차] Hyperparameter Tuning, Batch Normarlization, and Programming Frameworks (0) | 2024.07.26 |