14장
합성곱 신경망을 사용한 컴퓨터 비전
합성곱 신경망convolutional neural network (CNN) 은 대뇌의 시각피질 연구에서부터 시작되었고, 이미지 인식분야에 사용되고, 현재 이미지 검색 서비스, 자율주행 자동차, 영상 자동 분류 시스템 과같은 시각 분야말고, 음성 인식voice recognition, 자연어 처리natural language processing 에도 많이 사용된다.
여기에서 CNN의 기원, 구성요소, 구현, 뛰어난 성능의 CNN 구조, 객체 탐지object detection, 시맨틱 분할semactic segmentation 등등에 대해 설명한다.
14.1 시각 피질 구조
1950년대 즈음에 원숭이를 대상으로 시각피질안의 많은 뉴런이 작은 국부 수용장local receptive field 을 가지는 것을 보였고, 이는 뉴런이 시야의 일부 범위 안에 있는 시각자극에만 반응한다는 의미이다. 어떤 뉴런은 수평적 이미지에, 각도의 선분에, 큰 수용장을 가져 저수준 패턴이 조합된 더 복잡한 패턴에 반응하는 점을 보였고, 이 뉴런들이 겹치게 합쳐져서 전체 시야를 감싸게 된다.
이러한 고수준 뉴런은 저수준 뉴런의 출력에 기반하는 아이디어로, 전체 시야 영역에 포함된 모든 종류의 복잡한 패턴을 감지할 수 있게된다.
이미지 인식에 합성곱 신경망, 합성곱 층, 풀링 층 등을 사용한다. 이미지인식에 완전연결층을 사용하지 않는 이유는, 이미지 크기가 작을 경우에는 괜찮은데, 이미지가 고해상도가 될수록 파라미터수가 급격하게 늘어나게되는 반면, CNN은 층을 부분적으로 연결하고 가중치를 공유해서 이 문제를 해결한다.
14.2 합성곱 층
CNN의 가장 중요한 요소는 합성곱 층convolutional layer 이고, 합성곱층의 뉴런은 수용장 안에 있는 픽셀에만 연결된다. 이러한 합성곱 층들이 모여서 저수준에서 고수준 특성으로 조합해나간다.
어떤 층의 i, j 위치의 뉴런은 이전층의 i~ i + f_h - 1 , j ~ j + f_w - 1 까지의 출력에 연결된다. f_h, f_w 는 수용장의 높이와 너비이다.
끝쪽 뉴런의 합성곱을 계산하기 위해서 입력주위에 0 을 추가하는 것이 제로패딩zero padding 이라고 한다.
수용장 사이에 간격을 스트라이드stride 라고하고, 큰 입력층을 작은 층에 연결할 수 있게 해서 계산복잡도를 낮춰준다.
5x7 입력층, 1 제로패딩, 3x3 수용장, 2 스트라이드를 적용하면, 3x4 층에 연결된다.
14.2.1 필터
필터filter, 합성곱 커널convolution kernel 이라고부르는 뉴런 가중치 세트하나에 하나의 특성맵feature map 을 생성한다. 뉴런 가중치는 훈련하는동안 합성곱 층이 자동으로 해당 문제에 가장 유용한 필터를 찾고 상위 층은 이들을 연결해서 더 복잡한 패턴을 학습한다.
14.2.2 여러가지 특성맵 쌓기
실제 합성곱층은 여러가지 필터를 가지고 필터마다 하나의 특성 맵을 출력해 3D로 표현하는것이 정확하다. 각 특성맵의 픽셀은 하나의 가중치 뉴런(필터)이고 하나의 특성맵에서 뉴런의 가중치를 공유하지만, 다른특성맵은 다른 파라미터를 사용한다. 한 특성맵에서 가중치를 공유한다는 특성때문에, CNN이 패턴을 인식하도록 학습되었으면, 다른위치에 있는 패턴도 인식가능하다.
입력이미지는 컬러 채널channel 마다 하나씩 서브층으로 구성된다. 일반적으로 RGB 채널이고, 흑백이미지는 하나의 채널을 가진다. 또 많은 채널을 가지는 이미지가 있을수 있다.

z i, j ,k : k 특성맵에서 i행, j 열에 있는 뉴런의 출력
S_h, S_w : 스트라이드 크기
f_h, f_w : 수용장의 크기 (필터 크기)
x i`, j`, k` : 이전층의 뉴런의 출력
b_k : k 특성맵의 편향 -> 전체 밝기를 조정하는 다이얼의 의미
w_u,v,k`,k : 현재 층의 k 특성맵의 모든 뉴런과 u행 v열 k`특성맵에 위치한 입력 사이의 연결 가중치
14.2.3 텐서플로 구현
텐서플로의 이미지는 [높이, 너비, 채널]의 3D 형태로 표현되고, 미니배치 차원이 추가될 수 있다. 합성곱 층의 가중치는
[f_h, f_w, f_n`, f_n] 의 4D 형태로 표현되고, 편향은 [f_n] 형태로 간단히 나타난다.
tf.nn.conv2d() : images ( 이미지 픽셀값 4D 텐서 ) , filters ( 일련의 필터 4D 텐서 ), strides (1이나 4개의 원소를 갖는 1D 벡터로 지정가능하다. [배치스트라이드 , 수평, 수직 값 , 채널 스트라이드] 이런식으로 구성된다. ), padding ( valid or same 으로 지정되고, valid는 제로패딩을 사용하지않는 필터가 이미지를 넘어가지 않음, same은 출력의 크기가 입력에 스트라이드를 나눠올림한 것과 같도록 한다. 즉 입력 5x5 , 2 이면 3x3 으로 되도록함. )
컨볼루션 레이어에는 많은 하이퍼파라미터가 존재하고, 정확한 값을 찾으려면 교차편집을 이용하고 많은 시간이 걸린다. 그래도 많은 곳에서 사용하는 CNN구조에서 하이퍼파라미터에 대한 통찰을 얻을 수 있다.
14.2.4 메모리 요구 사항
합성곱층은 많은 양의 RAM을 필요로한다는게 문제가 될수 있다. 정방향의 계산 중간과정을 역방향계산을 위해 기록해야 되는데 예를들어 5x5 필터, 스트라이드 1, same 패딩을 사용해서 150x100x3 크기의 특성맵 200개를 만드는 합성곱층에 사용하는 파라미터수는 필터의 파라미터수 (5 x 5 x 3 + 1 ) X 필터 개수 ( 200 ) = 15,200 개로 완전연결층에 비해서는 적지만, 특성맵 200개에 150x100의 뉴런에 각 5x5x3 개의 가중치를 가지기때문에 총 2억2천500만개의 실수곱을 기록해야한다. 출력만 하더라도 각 실수가 32비트 정밀도로 표현된다면 200x150x100x32 비트 = 약12MB를 필요로 하고 샘플수가 100개면 1.2GB의 RAM을 필요로 하게된다.
추론시에는 다음층에 대한 계산이 끝나면 이번층메모리를 해제해도 괜찮지만, 훈련시에는 역방향의 그레디언트를 계산해야되기 때문에 모든 층의 정방향 계산과정을 가지고 있어야 한다. 그래서 많은 RAM을 필요로 하게된다.
메모리를 줄이기위해 미니배치 크기를 줄이거나, 특성맵 크기, 개수를 줄이거나, 32비트 정밀도 대신 16비트를 사용하거나, 여러장치에 CNN을 분산시키는 방법이 있다.
14.3 풀링 층
풀링층의 목적은 계산량과 메모리 사용량 ( 과대적합을 줄이는 효과 ) , 파라미터수를 줄이기 위해서 부표본subsample 을 만드는 것이다.
풀링층의 각 뉴런은 이전 층의 수용장안의 뉴런들과 연결되어 있고, 크기, 스트라이드, 패딩을 지정한다. 그런데 가중치가 없고 단지 수용장 뉴런값들의 최대값, 최소값 등을 계산하는 함수역할만 한다. 최대값이 최대 풀링 층max pooling layer 이고 각 채널에 독립적으로 적용되어 입력과 출력이 같은 채널수를 가진다.
맥스 풀링층은 계산량, 메모리 사용량, 파라미터수를 줄여주는것 뿐아니라, 작은 변화에도 일정 수준의 불변성invariance 을 만들어준다. 즉 한두픽셀 움직이더라도 수용층에 포함되면 결국 같은 값을 출력하기 때문에 이동 불변성translation invariance 를 갖는다. 이동뿐아니라 약간의 회전, 확대, 축소에 대한 불변성을 갖는다.
하지만 매우 파괴적이여서 2x2 커널, 스트라이드 2 를 사용한다고하면 출력이 양방향 절반 줄어, 정보의 3/4 을 잃게된다. 또한 불변성을 필요로 하지 않는 시멘틱 분할 같은 경우에, 입력이 이동하면 출력도 이동해야하는 등변성equivariance 를 목표로 할때 적합하지 않다.
14.3.1 텐서플로 구현
https://colab.research.google.com/drive/1Mifc3y0tjaHuiUKjGEK46-TxAV1aIWhz#scrollTo=MaxPooling
keras.layers.MaxPool2D( ) : 커널 크기(2 ,2) , 스트라이드( 커널 크기 ), 패딩 (valid)
keras.layers.AvgPool2D( ) : 최대값이 아닌 평균을 계산함 나머진 동일
평균 풀링은 정보 손실이 적지만, 맥스 풀링이 성능이 더 좋아서 보통 맥스풀링을 사용한다.
풀링을 깊이방향으로 수행해 다양한 특성을 학습 할 수 있다. 예를들어 동일패턴이 회전된 여러개의 필터를 학습하면 특성맵의 깊이방향 최대 풀링은 회전에 상관없이 출력을 만든다. 즉 필터의 학습 종류에 따라 불변성을 학습할 수 있다.
tf.nn.max_pool( ) : 깊이 방향 풀링층을 저수준 API를 활용해서 구현이 가능하다. ksize, strides, padding 에 ksize와 strides를 채널 방향으로 지정해서 구현.
keras.layers.GlobalAvgPool2D( ) : 전역 평균 풀링 층global average pooling layer -> 입력과 높이와 너비가 같은 커널 크기를 갖는 평균 풀링층과 동일하게 동작한다.
14.4 CNN 구조
전형적인 CNN 구조는 합성곱층+relu층 몇개에 풀링층을 몇번 반복하는 식으로 구성된다. 네트워크를 통과할수록 이미지는 작아지지만 특성수는 점점 깊어지는것이 일반적이다. 그리고 가장 위 몇층에는 완전연결 층으로 구성된 피드포워드 신경망feedfoward neural network가 추가되고 마지막 층에서 ( 소프트맥스 함수를 사용하여 ) 예측을 수행한다.
합성곱층에서 큰 커널을 사용하는것은 자주하는 흔한 실수이다. 5x5 커널을 사용하는것과 3x3 커널 두개를 쌓는것이 파라미터와 계산량이 적고 일반적으로 좋은 성능을 보여준다. 그런데 처음 합성곱 층에는 일반적으로 큰 크기의 커널( 5이상 ) 과 2이상의 스트라이드를 사용한다.
https://colab.research.google.com/drive/1Mifc3y0tjaHuiUKjGEK46-TxAV1aIWhz#scrollTo=MNIST_CNN_Model
CNN은 출력층에 다다를수록 필터 개수가 많아진다. 저수준 특성의 개수는 적지만( 수평선, 동심원, ... ) 저수준 특성들을 연결하여 만든 고수준 특성은 다양하고 많기 때문에 이런구조가 합리적이다.
CNN을 더 잘이해하기
ILSVRC 이미지넷 대회 ( https://image-net.org ) 에서 우승한 모델들의 발전 과정을 살펴봐본다.
LeNet-5 -> AlexNet -> GoogLeNet -> ResNet
14.4.1 LeNet-5
층 | 종류 | 특성 맵 | 크기 | 커널 크기 | 스트라이드 | 활성화 함수 |
입력 | 입력 | 1 | 32x32 | - | - | - |
C1 | 합성곱 | 6 | 28x28 | 5x5 | 1 | tanh |
S2 | 평균 풀링 | 6 | 14x14 | 2x2 | 2 | tanh |
C3 | 합성곱 | 16 | 10x10 | 5x5 | 1 | tanh |
S4 | 평균 풀링 | 16 | 5x5 | 2x2 | 2 | tanh |
C5 | 합성곱 | 120 | 1x1 | 5x5 | 1 | tanh |
F6 | 완전 연결 | - | 84 | - | - | tanh |
출력 | 완전 연결 | - | 10 | - | - | RBF |
- MNIST 는 제로 패딩되어 32x32 크기로 정규화되어 모델에 주입된다. 그래서 네트워크에서 패딩을 적용하지 않는다.
- 평균 풀링은 각 뉴런의 평균을 계산하고, 각 특성맵마다 있는 학습가능한 계수값과 편향에 대해서 곱하고 더한다음 활성화 함수를 적용한다.
- C3의 대부분의 뉴런은 S2의 6개 특성맵 전부 연결되는게 아니라, 3~4개랑만 연결된다. 논문 참조
- 출력층은 특이한데, 입력과 가중치 행렬의 곱을 구하는게 아니라, 각 뉴런에서 입력 벡터와 가중치 벡터 사이의 유클리드 거리를 측정한다. 요즘엔 잘못된 예측을 줄이고, 그레디언트 값이 크고 빠르게 수렴되는 크로스엔트로피 비용함수를 주로 사용한다.
14.4.2 AlexNet
2012년 이미지넷 대회에서 큰차이로 우승한 네트워크이다. 처음으로 합성곱을 연속해서 쌓았고, LeNet과 비슷한지만 더 깊은 구조를 가지고 있다.
층 | 종류 | 특성 맵 | 크기 | 커널 크기 | 스트라이드 | 패딩 | 활성화 함수 |
입력 | 입력 | 3 (RGB) | 227x227 | - | - | - | - |
C1 | 합성곱 | 96 | 55x55 | 11x11 | 4 | valid | ReLU |
S2 | 최대 풀링 | 96 | 27x27 | 3x3 | 2 | valid | - |
C3 | 합성 곱 | 256 | 27x27 | 5x5 | 1 | same | ReLU |
S4 | 최대 풀링 | 256 | 13x13 | 3x3 | 2 | valid | - |
C5 | conv | 384 | 13x13 | 3x3 | 1 | same | ReLU |
C6 | conv | 384 | 13x13 | 3x3 | 1 | same | ReLU |
C7 | conv | 256 | 13x13 | 3x3 | 1 | same | ReLU |
F8 | MaxPool | 256 | 6x6 | 3x3 | 2 | valid | - |
F9 | Dense | - | 4096 | - | - | - | ReLU |
F10 | Dense | - | 4096 | - | - | - | ReLU |
출력 | 출력 | - | 1000 | - | - | - | SoftMax |
깊은 신경망에서 과대적합을 줄이기위해서 F9, F10의 출력에 드롭아웃 50%를 적용하고, 훈련 이미지를 랜덤하게 여러 간격으로 이동하거나 수평대칭, 조명을 바꾸는 등 데이터 증식data augmentation 을 수행하였다.
[데이터 증식]
인공적으로 진짜 같은 샘플을 생성해 훈련 세트크기를 늘려 과대적합을 줄이는 규제로 사용 될 수 있다. 생성된 샘플은 진짜와 구분이 불가능해야 의미가 있고, 그렇지 않으면 잡음을 추가하는 것과 다를게없다. 모델이 덜 민감해지도록 바라는 방식으로 훈련세트를 변형할 수 있다. 예를들어 데이터셋의 크기를 변화시켜 훈련하면 모델이 크기 변화에 덜 민감해진다.
AlexNet 에서 C1과 C3층의 ReLU 단계후에 LRNlocal reponse normalization 이라고 하는 정규화단계를 적용하였다.
층의 특성맵에 강하게 활성화된 뉴런이 있으면, 다른 특성맵의 같은 위치의 뉴런을 억제하는 방식으로 정규화된다. 이는 특성맵들이 다양하게 학습되도록 유도한다.

b_i : i 특성맵, u 행, v 열에 위치한 뉴런의 정규화된 출력, 위는 현재 위치에 뉴런에 해당하는 식임. ( 출려값 )
a_i : ReLU 단계를 지나고 정규화 되기 전 뉴런의 활성화 값 ( 입력값 )
k, alpha, beta, r : 하이퍼파라미터로 k 는 편향, r : 깊이 반경depth radius
f_n : 특성맵의 수
요약 설명 : r / 2 길이만큼 위아래 특성맵의 현재 뉴런가중치와 같은 위치의 가중치들의 제곱합을 현재 뉴런 가중치에 나눈다.
AlexNet에 사용된 하이퍼 파라미터는 r = 2, alpha = 0.00002, beta = 0.75, k = 1 로 설정함
14.4.3 GoogLeNet
2014년에 구글 리서치 크리스찬 세게디등이 개발해 톱-5 에러율을 7%로 낮췄다. 이게 가능했던 이유는 네트워크가 이전보다 훨신 깊었기 때문이다. 인셉션 모듈inception module 이라는 서브 네트워크를 가져 파라미터를 훨씬 효과적으로 사용했다. (AlexNet 보다 10배 적은 파라미터를 사용했다.)
" 3x3+1 (S) " 는 3x3 커널에, 1 스트라이드, same 패딩을 사용했다는 의미이다.

처음 입력신호가 복사되어 네 부분의 다른 층으로 주입된다. 모든 층은 ReLU 활성화함수, same 패딩을 사용한다.
각각 파란색 층은 1x1, 3x3, 5x5 의 다른 커널 크기로 다른 크기의 패턴을 학습한다.
모두 스트라이드 1과 same 패딩을 사용해서 입출력 크기가 모두 동일하다. 그래서 마지막 출력을 조합하는 깊이 연결 층depth concatenation layer 에서, 필터들을 깊이방향으로 쌓을 수 있다.
인셉션 모듈에서 1x1 합성곱 층을 사용하는 이유는 무엇일까? 하나의 픽셀만 처리하는데 특성을 잡을 수 있을까?
- 공간상의 패턴을 잡을수는 없지만, 깊이 차원을 따라 놓인 패턴을 잡을 수 있다. 즉 각 특성맵의 패턴말고 특성맵들간의 패턴을 찾을 수 있다.
- 입력보다 더 적은 특성맵을 출력하게 해서, 차원을 줄이는 의미인 병목 층bottleneck layer 의 역할을 한다. 그니깐 특성맵수가 256개인 입력에서 128 으로 3x3 을 수행할 때보다, 256 -> 128, 1x1 -> 128 3x3 이 더 파라미터를 적게 사용한다고 하는것 같다.
- 합성곱 층의 쌍 ([1x1, 3x3], [1x1, 5x5]) 이 더 복잡한 패턴을 감지할 수 있는 하나의 강력한 합성곱층처럼 작동한다.그니깐 3x3 , 5x5를 사용하는 것보다, 1x1-3x3, 1x1-5x5 를 연결해서 사용하는게 더 복잡한 패턴을 잘 감지한다 라고하는것 같다. 확인해보고싶다.
인셉션 모듈은 여러 크기의 복잡한 패턴이 담긴 특성맵을 출력하는 뽕맞은 합성곱 층이라고 한다.
대신 단점은 각 합성곱 층의 합성곱 커널의 수는 하이퍼 파라미터로 지정한다고 한다. 즉 인셉션 모듈을 추가할 때마다 6개의 파라미터가 더 늘어난다. 대신 범용적으로 씌이는 값이 있을 것 같다.
----------------> 입력 | -----------------------> | 인셉션 / 256 320 128 128 160 32 |
합성곱 / 64, 7x7 + 2 (S) | 최대 풀링 / 832, 3x3 + 2 (S) | |
최대 풀링 / 64, 3x3 + 2 (S) | 인셉션 / 112 288 64 64 144 32 |
인셉션 / 256 320 128 128 160 32 |
LRN (정규화) | 인셉션 / 128 256 64 64 128 24 |
인셉션 / 384 384 128 128 192 48 |
합성곱 / 64, 1x1 + 1 (S) | 인셉션 / 160 224 64 64 112 24 |
전역 평균 풀링 / 1024, 7x7 + 1 (V) |
합성곱 / 192, 3x3 + 1 (S) | 인셉션 / 192 208 48 64 96 16 |
드롭아웃 / 40% |
LRN | 최대 풀링 / 480, 3x3 + 2 (S) | 완전 연결 / 1000 unit |
최대 풀링 / 192, 3x3 + 2 (S) | 인셉션 128 192 96 64 128 32 |
SoftMax |
------------------------------> | 인셉션 64 128 32 32 96 16 |
출력 --------------> |
- 처음 두층은 계산의 양을 줄이기 위해 이미지의 높이와 너비를 4배로 줄이는데, 많은 정보를 유지하기 위해 첫 층에 큰 크기의 커널을 사용한다.
- LRN 층은 특성맵의 뉴런간 정규화를 수행한다.
- 이후 1x1 층이 병목 층처럼 작동하고, 두 합성곱 쌍이 똑똑한 합성곱 처럼 작동한다.
- LRN 층으로 다양한 패턴을 학습하도록 한다.
- 계산속도를 높이기 위해 최대 풀링 층으로 이미지를 2배로 줄인다.
- 9 개의 인셉션 모듈이 길게 이어지고, 차원 감소와 속도향상을 위해 중간에 몇개의 맥스 풀링층을 넣는다.
- 인셉션 모듈이 끝나고 전역 평균 풀링으로 각 특성맵의 평균을 출력한다. 여기서 공간정보를 잃는다. ( 이미 공간이 많이 줄어들어서 괜찮다 ) 위치 추정이 아니라 분류 모델이기 때문에, 물체가 어디 있는지는 중요하지 않다고 한다. 여기서의 차원 축소를 통해 완전연결층이 필요없어지고 파라미터를 크게 아껴 과대적합의 위험도 줄어든다.
- 규제를 위해 드롭아웃을 사용하고, 1000개의 클래스의 확률을 위해 완전연결 소프트 맥스를 수행해 출력한다.
14.4.4 VGGNet
VGG visual geometry group 연구소에서 개발한 VGGNet 은 단순하고 고전적인 구조로 2~3개의 합성곱 뒤에 풀링 층이 나오는 블럭이 반복되는 구조이다. 필터수도 많지만 3x3 크기만 사용한다.
14.4.5 ResNet
https://colab.research.google.com/drive/1Mifc3y0tjaHuiUKjGEK46-TxAV1aIWhz#scrollTo=ResNet
잔차 네트워크 residual network ( ResNet ) 을 사용해 2015 대회에서 3.6% 이하의 top-5 에러율을 기록해 우승했다. 우승한 네트워크는 152개의 층으로 구성된 극도로 깊은 CNN이고, 더 적은 파라미터를 이용해 점점더 깊은 네트워크를 구성하는 트렌드를 만들었고, 이 깊은 네트워크를 가능하게한 핵심 요소는 스킵 연결skip connection ( 숏컷 연결shortcut connection ) 이다. 즉 어떤 층에 주입되는 신호가 상위층의 출력에도 더해지도록 한다.
신경망은 목적함수를 최소화하는 방향으로 학습되는데, 원래는 h(x)를 모델링했지만, 입력 x 를 모델의 출력에 더한다고 하면 h(x) = f(x) + x 가되고, 더해지는 입력 x 에는 어느 파라미터도 존재하지 않기때문에, 네트워크는 h(x) 대신 f(x) - x 를 비용함수로 학습하게된다. 이를 잔차 학습residual learning 이라고 한다.
초기 네트워크는 가중치를 0에 가깝게 초기화해 네트워크출력이 0 에 가까운 값을 내는데, 스킵연결을 추가하면 출력이 f(x) - x = 0 이되고 f(x) = x 로 서브네트워크가 입력과 같은 값을 출력해서, 초기에 항등함수 identity function 를 모델링한다. 목적함수가 항등함수와 비슷하면 훈련이 매우 빨라진다. ( 왜? )
또한 스킵연결을 많이 연결하고 훈련을 진행하면, 학습되지 않은 층이나, 역전파를 방해하는 층을 스킵하고 훈련을 진행 할 수 있다. 스킵 연결로 입력신호가 전체 네트워크에 영향을 끼칠수 있기 때문이다. 원래는 입력이 층을 지나 변형되고 다음층으로 넘겨지기 마련인데, 스킵연결으로 입력을 뛰어넘을 수 있다. 심층 잔차 네트워크는 스킵 연결을 가진 작은 신경망인 잔차유닛 residual unit 을 쌓은 것이다.
ResNet 구조
구글의 인셉션 네트워크에서 인셉션 모듈이 등장하기 전과 출력부분은 동일하고, 중간에 단순한 잔차 유닛을 매우 깊게 배열한다. 각 잔차 유닛은 LRN말고 BatchNormalization 을 수행한다. 또한 잔차유닛의 배열에는 풀링층이 없다.
특성맵의 수는 몇개의 잔차 유닛마다 2배씩, 크기는 4배로 줄어든다. ( 풀링층이 아닌 스트라이드 2 인 합성곱 층으로 ) 크기가 4배 줄어드는 잔차 유닛의 경우, 입력과 잔차유닛출력 크기가 동일하지 않기 때문에 바로 더해지지 못하고 입력을 스트라이드 2인 1x1 합성곱층을 퉁과시켜 출력에 더해서 스킵연결을 구현한다.
ResNet-34
합성곱 + 완전 연결층 34개로 이루어진 ResNet으로 64개 특성맵 RU 3개, 128개 RU 4개, 256개 RU 6개, 512개 RU 3개를 포함한다.
ResNet-152
이 네트워크는 조금 다른 잔차유닛을 가진다. 256개 특성맵을 가진 RU에 2개의 3x3 합성곱 대신 세 개의 합성곱 층을 사용한다.
병목층으로 작동하는 64개의 특성맵의 1x1 합성곱 층 -> 64개 특성 맵의 3x3 합성곱 층 -> 원본깊이 복원 256개 특성맵 1x1 합성곱 층 으로 이루어진다. 256개 맵 RU 3개, 512개 맵 RU 8개, 1024개 맵 RU 36개, 2048개 맵 RU 3개를 포함한다.
14.4.6 Xception
https://colab.research.google.com/drive/1Mifc3y0tjaHuiUKjGEK46-TxAV1aIWhz#scrollTo=Xception
GooLeNet의 변종으로 프랑수아 숄레가 2016년 제안한 Xception이다. 대규모 비전문제에서 성능이 뛰어나고 인셉션 모듈을 깊이별 분리 합성곱 층depthwise separable convolution layer( 간단히 분리 합성곱 ) 으로 대체한다. 일반적인 합성곱 층은 공간상의 패턴( 타원, 사각형 형태 등..) 과 채널사이 패턴을 동시에 잡기 위한 필터를 사용하지만, 분리 합성곱 층은 공간 패턴과 채널 패턴을 분리하여 모델링할수 있다고 가정한다. 첫번째 부분은 각 특성맵 마다 하나의 필터를 적용한 합성곱 층이고, 두번째 부분은 채널 사이 패턴만 조사한다. 1x1 필터만 사용한 일반 합성곱 층이다. 이 분리합성곱 층은 입력 채널에 하나의 공간 필터를 가지기 때문에 채널이 너무작은 경우에 사용하는 것을 피하는 것이 좋다. 이러한 이유로 Xception 에서는 2개의 일반 합성곱 층에서 시작하고 나머지는 분리 합성곱층을 사용한다.
Xception 을 GoogLeNet의 변종으로 간주하는 이유는 인셉션 모듈에서는 1x1 합성곱을 채널간 패턴을 파악하는 용도로 사용하고 그위에 일반적인 공간상 패턴을 파악하는 합성곱을 사용하기 때문에 인셉션 모듈을 일반 합성곱 층과 분리 합성곱층의 중간이라고 생각할 수 있다.
분리 합성곱 층이 일반적인 합성곱층보다 파라미터, 메모리, 연산을 더 적게 사용하고 일반적으로 성능이 더높아 기본적으로 이 층을 사용하는 것을 고려해보아야 한다.
14.4.7 SENet
SENet은 2017년 2.25% 에러율이라는 기록으로 우승했다. 인셉션 네트워크와 ResNet을 확장한 버전인 SE-Incetion, SE-ResNet을 발표하였다. 인셉션 모듈이나 잔차유닛과같은 모든 유닛에 SE 블록 block 이라는 작은 신경망을 추가하여 성능을 향상시켰다.
인셉션 모듈에선 인셉션 모듈의 출력과 모듈의 출력을 입력으로 받는 SE 블록의 출력을 서로 곱해서 출력을 생성하고,
잔차 유닛에선 스킵 연결 + ( 잔차유닛 출력 x 잔차유닛 출력을 입력으로 받는 SE블록 출력 ) 을 통해 출력을 생성한다.
SE블럭은 유닛의 출력을 깊이 차원에 초점을 맞추어 분석한다. ( 공간 패턴은 유닛에게 맡긴다. ) 어떤 특성이 일반적으로 동시에 크게 활성화되는지를 학습한다. ( 유닛에 학습이 잘되지않은 상태면 오히려 안좋을 듯 ) 이렇게 연관된 특성정보들을 학습하고 이 정보를 통해서 특성맵을 보정한다. 예를들어 눈코입의 활성을 학습한 SE 블럭이 새로운 특성맵에서 눈입만 활성화되었다면 코 특성맵의 출력을 높이는 방식으로 작동한다.( 정확히 말하면 관련되지않은 특성맵값을 줄인다. ) 이 코 특성맵이 코인지 아닌지 다른요소와 헷갈릴때 이 학습된 SE 블럭이 도움을 줄 수 있다.
하나의 SE 블럭은 3개의 층으로 구성된다. 전역 평균 풀링 층 -> ReLU를 사용하는 밀집층 -> 시그모이드를 사용하는 밀집 층으로 구성된다. 처음 전역 평균 풀링 층은 특성 맵에 대한 평균 활성화 값을 계산한다. 특성맵개수와 동일한 크기의 벡터가 출력된다. 다음 층에서 입력보다 훨씬 적은 뉴런수를 가진 완전연결층을 통해서 압축한다. 일반적으로 16배 적은 뉴런수를 사용한다. 이 저차원 벡터는 특성 응답의 분포를 표현한다. ( 임베딩 ) 이 병목층으로 SE 블록이 특성들의 조합에 대한 일반적인 표현을 학습한다. 마지막 출력층은 이 임베딩을 받아 특성맵마다 0과 1사이의 하나의 숫자를 담은 보정된 벡터를 출력한다. 다음 이 보정된 벡터와 특성맵과 곱해 관련없는 특성값을 낮추고 관련있는 특성값은 그대로 유지한다. ( 전반적으로 특성값이 줄어들거같음 )
14.5 케라스를 사용해 ResNet-34 CNN 구현하기
ResNet
https://colab.research.google.com/drive/1Mifc3y0tjaHuiUKjGEK46-TxAV1aIWhz#scrollTo=Resnet_Implement
Inception
Xception
14.7 사전훈련된 모델을 사용한 전이학습
Xception을 사용한 꽃이미지 분류하기
https://colab.research.google.com/drive/1Mifc3y0tjaHuiUKjGEK46-TxAV1aIWhz#scrollTo=Xception
- 데이터셋 받아오기
- 데이터셋을 훈련, 검증, 테스트 셋으로 분리
- 전처리함수를 만들어서 데이터셋 전처리하기
- 데이터 증식함수 만들어서 부족한 데이터셋 증식하기
- 데이터 증식에 keras.preprocessing.image.ImageDataGenerator 사용해보기
- Xception 모델 받아와서 마지막 전역 평균 풀링층과 밀집 출력증 제거하기.
- 훈련 초기에는 사전훈련된 층의 가중치를 동결시켜 과도한 가중치 변형 피하기
- 초기 훈련이 종료후 가중치를 해제하고 다시 컴파일한다. 이때 사전훈련 가중치의 훼손을 피하기위해서 작은 학습률을 사용한다.
14.8 분류와 위치 추정
물체의 위치를 추정하는 것은 회귀작업으로 나타낼 수 있다. 물체의 바운딩박스bounding box 를 예측하는것, 4개의 숫자를 예측하는 것이다. 네 개의 유닛을 가진 밀집층을 추가하고, MSE 손실을 사용해 훈련한다.
이미지 바운딩박스를 추가하기위한 오픈소스 레이블 도구
VGG image Annotator, LabelImg, OpenLabeler, ImgLab
유료
LabelBox, Supervisely
레이블을 예측하는 모델과, 바운딩박스를 예측하는 모델 2개를 각기 다른 loss함수로 훈련한다. 이에 따라서 label이 2개로 늘어나야된다. 결과적으로 각 원소를 ( images, (class_labels, bounding_boxes)) 의 형태로 훈련된다.
MSE는 모델을 훈련하기 위한 비용함수로 사용할 수는 있지만, 잘 예측하는지에 대한 지표로는 부족하다. 따라서 널리사용되는 IoU intersection over union 값을 사용한다. 이값은 예측한 바운딩 박스와 타깃 바운딩 박스의 교집합을 합집합으로 나눈 것이다. 교집합과 합집합이 같으면 1이고, 합집합이 커지거나, 교집합이 작아지면 점점 낮아진다.
바운딩 박스의 손실함수는 수평, 수직 좌표의 오차를 제곱 + 높이, 너비의 제곱근의 오차를 제곱하여 사용한다.
14.9 객체 탐지
하나의 이미지에서 여러 물체를 분류하고 위치 추정하는 작업을 객체 탐지object detection 이라고 한다. 몇년 전까지 널리사용되던 방법은 물체분류와 위치를 찾는 모델을 훈련하고, 이미지를 훑어 찾는 방법이다. 예를들어 이미지를 6x8격자로 나누고, 하나의 CNN이 3x3 영역을 지나가면서 장미꽃의 부분부분을 감지하고, 슬라이딩하면서 모든 3x3 영역을 감지하고, 영역을 넓혀 4x4 로 늘려 슬라이딩할 수 있다.
이 방법은 매우 쉽지만, 조금씩 다른 위치에서 같은 물체를 여러번 감지해 연산의 중복이생기고, 불필요한 바운딩박스를 제거하기 위한 사후작업이 필요하다. 흔히 NMS non-max-suppression 방식을 사용한다.
NMS
- CNN에 또 다른 꽃이 존재하는지 확률을 추정하기 위해 존재여부objectness 출력을 추가해 존재 여부가 어떤 임계값 이하인 바운드박스는 모두 삭제한다. 실제로 꽃이 들어있지 않은 바운딩 박스가 모두 삭제된다.
- 존재 여부 점수가 높은 바운딩 박스를 찾고, 이 박스와 IoU 점수가 높은, 많이 중첩된 다른 박스들을 모두 제거한다.
- 더는 제거할 바운딩 박스가 없을 때까지 2단계를 반복한다.
이러한 방식의 CNN을 여러 번 실행시켜야해서 많이 느려서 완전 합성곱 신경망 fully convolutional network (FCN) 을 사용한다.
14.9.1 완전 합성곱 신경망
조너선 롱 등이 시멘틱 분할을 위한 논문에서 FCN 아이디어를 처음 소개했다. 키 아이디어는 합성곱의 마지막 밀집 출력층을 1x1 stride 1 인 합성곱으로 대체한다는 아이디어 이다. 예를들어 CNN네트워크 마지막 출력층 이전에 100x7x7 특성맵을 반환하는 층에 유닛이 200개인 완전연결층을 출력으로 하는 네트워크에서 완전연결층을 kernel_size=7, strides=1, padding="valid" 인 합성곱으로 변경하면, 출력은 200x1x1 의 특성맵을 반환할 것이다. 이건 완전연결층과 수행하는 계산이 완전히 동일하다. 차이는 출력이 [batch_size, 200] 에서 [batch_size, 1, 1, 200] 인 것이다. 밀집층을 합성곱층으로 동일하게 변경하려면, 필터개수와 유닛개수가 같고, 커널사이즈가 입력사이즈와 동일해야하고 valid 패딩을 사용해야 한다.
그러면 완전연결층과 합성곱층이 동일한작업을 하는데 왜 변경하는 것일까?
밀집층은 입력크기에 크게 상관이있다. 층의 입력이 100x7x7 , 출력이 200 으로 정해지면 변경될 수 없는 단점이 있다. 그런데 합성곱층은 층의 입력이 100x7x7 이든, 100x14x14 이든 필터를 움직이면서 동적으로 출력이 변경될 수 있는 장점이 있다. 대신에 필터수는 동일해야된다. 100x7x7 이면 200x1x1 의 출력, 100x14x14 이면 200x8x8 크기를 출력한다.
예를들어 꽃 분류, 위치 추정을 수행하는 하나의 CNN은 224x224 이미지에서 훈련했고, 10개의 숫자를 출력할때, 0~4 출력은 소프트맥스로 클래스 분류를 위한 클래스별 확률을 만들고, 5번째 출력은 로지스틱 활성화 함수를 통과해 물체 존재여부 점수를, 6~9 출력은 그대로 바운딩 박스의 좌표와 높이, 너비를 나타낸다.
기존 훈련된 밀집층의 가중치를 그대로 합성곱층 가중치에 옮겨도되고, 훈련전 CNN을 FCN으로 변경 가능하다.
224x224 크기의 이미지가 주입되었을 때, 출력층 직전의 합성곱 층 (병목층) 이 7x7 크기의 특성맵을 출력한다고 가정하면, 이 FCN에 448x448 크기의 이미지를 주입하면, 병목층은 7x7 대신 14x14 크기의 특성맵을 출력하고(네트워크가 same 패딩만 사용하고, 나누어 떨어지지 않는 스트라이드를 사용할 경우 병목층 출력 크기는 더 작아진다.) , 출력은 10x8x8 (위에서 말한 10개의 숫자) 크기의 출력을 생성할 것이다. 이 출력의 각 셀 ( 각 특성맵의 같은위치 )은 10개의 숫자를 담고있고, 10개의 숫자가 64개 있는데, 이것이 의미하는 것은 CNN이 행 방향으로 8스텝, 열 방향으로 8스텝 슬라이딩해서 총 64번의 CNN을 수행한 것과 동일하다. 14x14 이미지에 7x7 윈도가 슬라이딩하면 8x8 개의 예측이 만들어진다. FCN은 딱 한번만 이미지를 처리하기 때문에 훨씬 효율 적이다. 이 같이 딱 한번만 본다는 의미의 YOLOyou only look once 는 매우 유명한 객체 탐지방법이다.
14.9.2 YOLO
조지프 레프먼의 논문에서 제안한 매우 빠르고 정확한 객체 탐지구조로 실시간 비디오에서도 사용가능한 객체탐치 알고리즘이다.
YOLOv3 구조의 중요한 차이점
- 각 격자 셀마다 45개의 숫자를 출력하는데, 20개의 클래스 확률, 5개의 바운딩 좌표출력을 위한 숫자 20개(5x4), 각 바운딩 좌표의 존재여부 점수를 위한 숫자 5개 를 출력한다.
- YOLOv3는 바운딩박스 중심의 좌표를 절대좌표로 사용하지않고, 각 셀에 대한 상대좌표를 예측한다. 슬라이딩하는 영역에 대한 상대좌표를 말하는 것 같다. (0, 0) 은 왼쪽위, (1, 1)은 오른쪽아래를 의미한다. 각 바운딩 박스의 중심은 각 격자셀 안에 놓인 것 만을 예측하도록 훈련되고, 로지스틱 함수를 이용해서 좌표를 0~1 사이가 되도록 만든다.
- 신경망을 훈련전에 앵커 박스anchor box ( 사전 바운딩 박스 bounding box prior ) 라 부르는 대표적인 박스 크기를 찾는다. 어떻게 찾냐면 훈련 세트의 바운딩박스들의 k-mean 를 통해서 ( 클러스터링 ) 대표적인 바운딩 박스 높이와 너비를 찾는다. 예를들어 훈련세트에 보행자가 많으면 앵커박스 중 하나는 전형적인 보행자 크기의 바운딩 박스 크기가 된다. 격자 셀마다, 바운딩박스 5개를 예측하는데 각 앵커박스의 크기를 얼마나 조정할 것인지 예측한다. 각 격자 셀과 각 앵커박스마다 네트워크는 수직, 수평방향의 스케일 조정 비율의 로그값을 예측한다. 예를들어 한 격자셀의 한 앵커 박스의 크기가 100x50 이면, 이 앵커박스와 이 격자 셀에 해당하는 예측을 수행해서 수직 log(1.5), log(0.9) 라는 스케일 조정 값을 예측하게 되고, 결국 바운딩박스의 크기는 150x45 로 예측되게 된다. 이러한 앵커박스로 적절한 차원의 바운딩 박스 크기를 예측할 가능성이 높아, 적합한 박스 크기를 빠르게 학습할 수 있어서 훈련 속도를 높힌다.
- 네트워크는 다른 크기의 이미지를 통해서 훈련된다. 훈련동안 몇번의 배치마다 랜덤하게 새로운 이미지 크기를 선택한다 ( 330x330 ~ 608x608 ). 이로인해 다른 스케일의 객체를 감지하는 방법을 학습한다. 또한 YOLOv3 알고리즘을 다른스케일에 사용가능하다. 작은 스케일은 정확도가 떨어지지만 속도가 빠르다. 문제에 따른 적절한 트레이드-오프를 선택해야한다.
mAP mean average precision
객체탐지에서 널리사용되는 지표는 mAP mean average precision 이다. 정밀도( 진짜 양성 / 진짜 양성 + 거짓 양성 ) 와 재현율 ( 진짜 양성 / 진짜 양성 + 거짓 음성 ) 에는 트레이드 오프가 있다. 그런데 재현율이 낮을때 정밀도와 재현율이 동시에 상승하는 영역이 있을 수 있다. 한 분류기가 10% 재현율에서 90% 정밀도를 달성하고, 20% 재현율에서 96% 정밀도를 달성한다면, 10% 재현율에서 분류기가 제공할 수 있는 최대 정밀도를 찾아야 한다. 따라서 공정한 모델의 성능을 판단하는데 최소 0% ~ 100% 까지 재현율에서의 최대 정밀도를 계산하고, 이 최대 정밀도를 평균한다. 이를 평균 정밀도 average precision ( AP ) 이라고 한다. 두개 이상의 클래스에는 각 클래스의 AP를 구하고, 이를 평균한다. 이것이 mAP 이다.
객체 탐지에서는 시스템에서 클래스를 탐지했지만, 위치가 잘못되었다면(바운딩 박스가 객체를 벗어나는 경우), 절못된 예측으로 판단한다. 그 범위를 정하는 방법으로, IoU(intersection over union) 임계점을 정하는 것이다. 이 값이 0.5보다 크면 올바른 예측, 낮으면 잘못된 예측으로 분류하는 방법이다. 이 것을 mAP@0.5 ( mAP@50% , mAP@50 ) 라고한다. 또는 각각의 IoU 임계값 (0.5 , 0.55, ... , 0.95 ) 에 대해서 mAP를 구하고 평균하는 것을 지표로 사용한다. ( mAP@[.50:.95] ) 이건 평균 mAP이다. (평균 평균 평균 정밀도 ㅋㅋ)
객체탐지 모델중 SSD, Faster R-CNN 같은 모델들이 텐서플로 허브에 포팅되어있다.
Faster R-CNN의 경우 이미지가 처음에 하나의 CNN을 통과후 RPN region proposal network 으로 전달해 객체가 들어있을 가능성이 높은 바운딩 박스를 추출한다. 이 출력으로 바운딩 박스마다 분류기를 실행하는 방식이다.
14.10 시멘틱 분할
객체 탐지의 바운딩박스를 구하는 것보다 더 정밀한 픽셀 단위로 구분하는 방법이다.
시멘틱 분할semantic segmentation 에서 각 픽셀은 속해져있는 객체의 클래스로 분류된다. 같은 클래스들끼리는 구분되지 않는다.
이 작업에서 가장 어려운것은 이미지가 CNN을 거치면서 위치 정보를 잃어버리기 때문에 어딘가에 사람이 있다고 알 수 있지만, 그보다 더 정확히는 알 수 없다. 객체 탐지와 마찬가지로 문제 해결을 위해 다양하고 복잡한 접근 방법이 있지만, 2015년 조너선 롱 등이 단순한 해결책을 제시했다.
먼저 사전훈련된 CNN을 FCN으로 변환한다. (병목층 이후 층을 Dense -> CNN으로)
입력 이미지에 적용하는 전체 스트라이드 ( 1이 아닌 스트라이드의 합 ) 을 32로 지정한다. ( 마지막 층이 입력이미지보다 32배 작은 특성맵을 출력한다. ) 주요한 부분은 해상도를 32배로 늘리는 업샘플링 층upsampling layer 을 추가하는 것이다.
이미지 사이즈를 늘리는 업샘플링 방법에는 선형보간bilinear interpolation 등이 있지만, 전치 합성곱 층transposed convolutional layer 을 사용한다. 이미지 사이사이에 0 으로 채워진 빈행 과 열을 삽입하여 늘리고, 합성곱을 수행한다.
==
keras.layers.Conv2DTranspose( )
전치 합성곱 층의 스트라이드는 필터의 스텝크기가 아니라, 입력이 얼마나 늘어나는지로 정의된다.
keras.layers.Conv1D
keras.layers.Conv3D
dilation_rate : 매개변수를 2이상으로 지정하면 아트루스 합성곱 층atrous convolutional layer 이 되서 필터가 업샘플링된다.
tf.nn_.depthwise_conv2d( ) : 깊이방향 합성곱 층depthwise convolutional layer 을 만든다. 모든 필터를 개개의 입력 채널에 독립적으로 적용한다. fn 개의 필터, fn'의 채널에 fn x fn' 개의 특성맵을 출력한다.
==
떨어진 정확도를 개선하기위해, 아래쪽 층에서부터 스킵연결을 추가한다. CNN을 수행하기전 특성맵을 F1, 수행후 특성맵을 F2 이고 F1의 2배 다운샘플링 이라고하면, F2 를 2배 업샘플링한 특성맵 + F1 -> 16배 업샘플링 : 총 32배 업샘플링이 수행된다.
비슷하게, 두번의 스킵연결을 사용해서 업샘플링이 가능하고, 원본 이미지 보다 더 크게 업샘플링하는 초해상도super-resolution 이 가능하다.
인스턴스 분할instance segmentation : 시멘틱불할과 비슷하지만 같은 클래스를 구분하는 방법. Mask-R-CNN 구조로 Faster R-CNN을 확장해 각 바운딩 박스에 대해 픽셀 마스크를 추가로 생성한다. 물체마다 클래스확률, 바운딩 박스, 바운딩박스에 물체 구분 픽셀 마스크를 얻을 수 있다.
적대적 학습adversarial learning, 싱글-샷 학습single-shot learning, 캡슐 네트워크capsule networks 등 구조들도 있다.