컴퓨터 비전에서 가장 핵심 과업은 '이미지 분류'이다.
일단 이미지와 라벨에 대한 데이터를 모으고,
머신러닝으로 분류기를 훈련시킨 후,
테스트 이미지들을 분류한 것에 대한 평가를 진행한다.
training 단계에서는 training set을 입력으로 받아 feature를 추출한 후,
그 set의 label들을 feature와 함께 입력받아 분류기의 학습을 진행한다.
이후 결과를 낸 것이 학습된 분류기이다.
testing 단계에서는 test set을 입력으로 받아 feature를 추출한 후,
label을 제외하고, training 단계에서 학습된 분류기에 feature만을 넣은 후,
그 feature에 대한 예측을 출력한다.
ConvNet
이건 Convolution Layer로 이루어진 모델이다.
원래의 1차원 벡터들이 input-hidden-output을 통과하는 형태에서
3차원 배열들이 input-hidden-output을 통과하는 형태로 변화했다.
만약 Fully Connected Layer라면,
32*32*3 (h*w*c)를 stretch 하면 3072*1이 되고,
이를 hidden layer와 연결하고, 출력과 연결하는 방식으로 진행된다.
Convolution Layer는,
필터를 통과하는 것이다! 이렇게 하면 그냥 쭉 늘리는 것보다 공간 정보를 알아내기에 수월하다.
이런 형태인데, 따라서 filter 하나당 한 층이 출력되고, filter의 개수가 output depth이다.
즉 이런 식으로, 32*32*5인 데이터에 6개의 5*5*3 filter를 통과시키면 28*28*6이 되는 것이다.
보통 필터를 조금만 통과시킨 걸 Low-level features라 하고, 많이 통과시킨 걸 High-level feature라 한다.
stride라는 것이 있는데, 이건 보통 이미지 출력 크기를 줄일 때 사용된다.
만약 stride=2라면 한 픽셀에 필터를 적용한 후 2칸 건너뛰고 필터를 적용하고.. 이런 식으로 되는 것이다.
pad라는 거는 입력 이미지에 테두리를 추가해주는 것이다.
왜냐면 필터를 거치면 이미지의 크기가 줄어드니 그걸 방지하기 위해서이다.
Receptive fields
이건 출력 결과가 입력의 어느 부분에서 영향을 받았는지를 나타낸다.
예를 들어 conv filter가 3*3이었다면, 하나의 결과가 출력될 텐데,
그 결과는 당연히 입력의 3*3 크기를 반영한 것일 것이다.
즉, 3*3 conv filter를 적용시킨다고 할 때,
layer1->layer2->layer3 이렇게 통과시켜서 layer3의 한 픽셀은 layer1의 5*5 픽셀을 담은 것이라는 뜻!
layer3의 한 픽셀의 receptive field는 5*5다 라고 한당.
따라서 당연히 conv filter를 여러번 적용하면 receptive field는 늘어날 수밖에 없다!
Pooling
image의 크기를 줄인다면, filter의 크기가 같더라도 담은 정보의 크기는 커진다.
근데 무턱대고 image의 크기를 줄이기엔 정보의 손실이 생긴다.
그래서 일단 conv filter를 적용시키다가, receptive fields의 크기가 너무 안 늘어난다면 중간중간 이미지 크기를 줄이는 방식으로 진행한다.
줄이는 방법은 여러가지가 있는데,
그중 max pooling이 가장 평범하다.
만약 2*2 filter로 max pooling을 stride 2로 한다면, 4*4 image는 2*2가 된다.
그래서 보통 ConvNet의 구조는,
(Conv-ReLU-Conv-ReLU-POOL) 요런 구조를 반복하다가, FC로 출력 class 개수에 차원을 맞춘다.
여기서 stride=1로 계속 진행하다가, 반으로 줄이고 싶다면 잠깐 stride=2로 변경한다.
Activation function
주로 사용되는 함수는 ReLU로,
f(x) = max(0, x)의 식이다.
이 activation function이 왜 필요하냐 하면, 만약 모든 layer가 선형으로 연결돼있다면?
Z = W1*X이고, Y = W2*Z 이런 식으로 될 텐데.. 그럼 그냥
Y = W2 * W1 * X 이렇게 될 것이다. 그럼 저 가중치가 의미가 없어짐.. 그냥 W3 = W1 * W2 이렇게 표현 가능..
그래서 아무리 많은 layer를 쌓았대도 의미가 없어지는 것이다..
따라서 활성화함수를 사용하는 것! 식으로 표현하면 Y = W2 * f(W1, X) 이렇게 나타낼 수 있다!
활성화함수의 종류는
Sigmoid, tanh, ReLU, Leaky ReLU, Maxout, ELU 등이 있다.
Architectures
위의 내용들을 활용한 다양한 모델이 있다.
이걸 보기 전에 잠깐, output size에 대해 알아보겠다.
input shape, padding, stride, filter size를 알고 있을 때, output shape는 어떻게 되는가?!
Wout = int[(Win+2p-k)/s]+1 이 된다.
Wout은 output image의 width, Win은 input image의 width, p는 padding, k는 kernel(filter) size, s는 stride
AlexNet - First CNN-based winner
if input = 227*227*3
First layer(Conv1) : 96 11*11(*3 - 요건 너무 당연해서 생략할 때도 있음) filters at stride 4
-> parameters : (11*11*3)*96
-> output volume : 55*55*96
Second layer(Pool1) : 3*3 filters at stride 2
-> parameters : 0
-> output volume : 27*27*96
#parameter = 0
위의 Conv layer는 update해야 하는 구간이지만,
이 Pooling layer는 어떤 것을 update하는 곳이 아니기에 parameter가 없다.
요거 함 계산해보기! 각 layer를 통과한 뒤의 결과가 바로 옆에 써진 차원임..
ZFNet : AlexNet에서 hyperparameters를 향상시킨 것..
VGG & GoogleNet : Deeper Networks..
VGGNet
3*3 filter가 좋다는 것을 입증한.
Small filters, Deeper networks
AlexNet은 8 layer였지만, VGG는 16에서 19개의 layer들이 있다.
신기한 건, Conv layer들이 모두 3*3 at stride 1, pad 1이고,
Pooling layer들이 모두 2*2 max pooling at stride 2라는 것이다.
왜 작은 필터들만을 썼냐? 하면,
어차피 3*3 conv layer를 3번 쌓는 거나, 7*7 conv layer를 1번 쌓는 거나
effective receptive field는 똑같을 것이기 때문이다.
그럼 저 두 개가 뭔 차이냐면,
파라미터의 개수가 다르다.
만약 C개의 channel이 있다면, 각 layer당 #parameter는
3*3 layer를 3번 쌓으면 3*(3*3*C*C)이고,
7*7 layer를 1번 쌓으면 7*7*C*C 이다.
여기서 C가 두 번 있는 이유는, input의 channel 한 번, output의 channel 한 번이다.
보통 대부분의 메모리는 앞의 conv layer에서 사용되고,
대부분의 파라미터는 마지막의 FC에서 사용된다.
GoogleNet
Deeper networks, with computational efficiency
22 layers, AlexNet/VGGNet에 비해 #parameter가 현저히 적고, FC layer가 없다(물론 마지막에 class 개수 맞춰주는 FC는 있음)!
이건 간단히 말하면, 깊고 넓은 신경망을 위해 '인셉션 모듈'을 추가한 것인데,
특징을 효율적으로 추출하기 위해 1*1, 3*3, 5*5의 합성곱 연산을 각각 수행한다. 여러 관점에서 보는 것!
근데 뭐.. 입출력의 hw가 같아야 하니 3*3이나 5*5에선 패딩을 추가해야 하긴 한다.
그리고 원래의 CNN은 막 엄청 정교하고 빽빽하게 연결돼있는데, 관련성이 높은 노드끼리만 연결하는 '희소 연결'을 사용하여 연산량을 줄이고 과적합도 해결할 수 있다.
이런 형태로 생겼다.
저 inception module에서, 맨앞 1*1 conv를 1, 3*3 conv를 2, 그 뒤를 3, 그 뒤를 4라 하면,
filter concatenation은 그 1, 2, 3, 4 를 뒤로 연결해 붙인 형태이다.
따라서 해상도(h, w) 크기는 당연히 같아야 하고, 총 이어진 크기는 (h, w, 4c)가 된다.
근데 이렇게 하면 계산 복잡도에서 문제가 생긴다.
layer가 어떻게 구성돼있는지 확인하면서 봐보겠다.
일단 Previous Layer에 연결돼있는 1*1 conv layer들은, 차원을 줄이기 위해 있는 것이다.
연산량을 줄이기 위해!
원랜 저 층이 없는 형태였지만, 윗층이 상대적으로 연산량이 많으니까 그 전체 미리 채널을 줄여줬다.
그런데.. 이 1*1 conv layer들에서는 병목현상이 발생한다.
왜냐면 저렇게 줄이면 당연히 데이터의 손실이 나기 때문에..!
그래서 저 층들은 연산량이 많은 경우에만 쓴다.
그리고 그림에서 볼 수 있듯 저 구조가 계속 쭈욱 연결돼있는 것이다.
저 구조가 나오기 전에 쭉 붙어있는 애들은 Stem Network로, Conv-Pool-2x Conv-Pool 형태이다.
그리고 중간에 저 구조들이 여럿 붙어있는 애들을 Stacked Inception Modules라 한다.
저기에 가끔 붙어있는 저 layer stack 들이 loss를 계산해준다.
그리고 마지막으로 붙어있는 층들이 Classifier output이다.
저곳에서의 과정은,
일단 마지막 Inception module의 출력이 h*w*c인데, 그걸 avg pooling을 해서 1*1*c로 만들어준다. (c, )인 벡터!
그 후 FC를 통과시켜 목표 클래스 개수로 만든다.
깊은 네트워크로, 계산의 효율을 올림.
22 layer, Efficient Inception module, FC 줄이기, AlexNet에 비해 파라미터 12배 적음, VGG-16에 비해 파라미터 27배 적음
ILSVRC에서 top 5
memory와 params 계산하는 부분 한 번 더 확인. (12장 50, 52p)
Bottleneck block
병목 블록. 뒤의 구조를 이해하기 위해 필요하다.
층을 깊이 쌓을수록 파라미터는 무제한으로 커지는데, 이를 해결하는 것!
왼쪽은 ResNet34의 Residual block이고, 오른쪽은 ResNet50의 Residual block이다.
병목블록이 추가된 것은 ResNet50이다.
더 층이 깊어졌는데 어떻게 파라미터가 줄어들지? 하면,
만약 원래 입력이 256개의 channel이 있었다면, 이를 1X1 Conv를 사용해 64개의 channel로 줄여서 거기서 다시 Conv layer를 계산해주고 이를 256개의 channel로 다시 늘리는 것이다.
ResNet
간단히 말하면,
네트워크 깊이가 무조건 깊다고 해서 성능이 좋아지는 것은 아니기에 이 문제를 해결하기 위해 residual block을 도입한 것.
이 residual block은 기울기가 잘 전파될 수 있도록 일종의 short-cut을 만들어 준다.
왜냐면 앞의 GoogleNet은 층이 22개인데 ResNet은 152개의 층이기에, 기울기 소멸 문제가 생길 수 있다. 그래서 short-cut으로 기울기 소멸 방지!
152 layers - revolution of depth in ISLVRC
residual connection을 사용하는 방식이다.
F(x) + x !
이렇게 하면 함수를 통과하지 않은, x만의 성질을 같이 가져갈 수 있다.
layer를 더 깊게 쌓는다고 해서 좋진 않다. 보통 더 안 좋다. 그치만 과적합 때문은 아니다.
깊은 모델은 얕은 모델보다 더 많은 표현력을 가진다.
깊은 모델이 안좋은 이유는, 최적화가 힘들기 때문이다.
따라서 위의 문제를 해결하기 위해, residual connection이 사용된다.
residual connection이 왜..?
만약 위의 식을 F(x)+x = H(x)라고 한다면,
F(x)가 0일 때 H(x)=x가 될 것이다.
여기서 원하는 건, H(x)를 직접 구하는 게 아니라 F(x) = H(x)-x (잔차) 를 이용하자는 거다.
이 구조에서는 특이하게도, 모든 conv layer는 3*3 형태이고, 2개씩 붙어있다.
그리고 주기적으로 stride를 2로 설정해서 downsampling을 진행한다.
또한 마지막에 output class로 변환하는 FC 1000만 존재하고, 다른 FC는 존재하지 않는다.
ResNet은 layer 깊이에 따라 여러 종류가 있는데,
18, 34, 50, 101, 152가 있다.
여기서도 구글넷처럼 효율을 높이기 위해 bottleneck layer를 사용한다.
즉, 아래 그림과 같이 되는 것이다. 마지막에 다시 28*28*256이 되는 것은 residual connection을 위해 차원을 맞춰주는 것!
각 구조간 메모리와 연산량을 비교했을 때, VGG가 가장 안 좋고, GoogleNet이 가장 효율적이다.
AlexNet은 연산량 측면에서만 좋고, 메모리와 정확도 측면에선 좋지 않다.
ResNet은 정확도가 높고, 모델에 따라 다르지만 적당한 효율성을 가지고 있다.
이런 ResNet을 조금 더 발달시킨 것이 SENet이다.
channel의 중요도를 계산해서 진행하기에, 결과적으로 마지막 층은 거의 0에 가까운, 필요없는 channel이 된다.
그리고 ResNet에서 residual block을 조금 더 키운 것이 wide residual block이다.
원래 3*3 conv, F 였던 것을 3*3 conv, F*k 로 바꾼 것이다.
그리고 또!!! ResNet을 발전시킨 것이 있는데, ResNeXt이다.
그리고 또다른 네트워크.. DensNet
MobileNet
!!!중요!!!
H*W*C -> H*W*C 로 갈 때 3*3 conv를 쓰는데,
여기서 계산량은?
conv layer에서 3*3*C, 출력의 H*W*C를 곱해서 9CCHW이다.
파라미터는 conv layer에서 3*3*C개, 출력의 C를 곱해서 9CC이다.
'AI > 컴퓨터비전' 카테고리의 다른 글
Image Classification (0) | 2024.12.15 |
---|---|
Image segmentation (3) | 2024.12.09 |
Feature Matching (1) | 2024.11.25 |
Corner Detection (0) | 2024.11.15 |
image warping (0) | 2024.06.16 |