이번 주차에는 컴퓨터 비전에 어떤 모델이 있었는지에 대해서 배운다. 물론 2022년 현재를 기준으로 최신 모델은 아니겠지만 명작에는 다 이유가 있는 법이다.
1. Classic Networks
이 강의에서는 처음에 모델 3가지를 소개한다. 그 중 첫 번째는 1998년에 나온 LeNet-5다. 손으로 쓴 숫자를 인식하기 위한 모델이라고 한다. 이미지의 크기는 32x32x1이다. gray scale이기 때문에 채널이 1개다. 그 당시에는 활성화 함수로 ReLU를 잘 사용하지 않고 시그모이드랑 tanh를 사용했다는 점과 주로 max가 아니라 average pooling을 사용했다는 점이 최신 모델과 큰 차이점인 것 같다. 그리고 파라미터 개수가 60,000개 밖에 되지 않기 때문에 현대 모델과 크기가 많이 차이 난다.
다음은 2012년의 AlexNet. 아까의 LeNet-5보다 한참 뒤에 나온 논문이다. 그래서 파라미터를 6천만 개 정도 쓰면서 모델의 크기가 확 커졌다. 입력 이미지의 크기는 227x227x3이다. 얘는 활성화 함수로 ReLU를 사용하고 pooling도 max다. 그리고 당시에는 GPU가 좀 느렸기 때문에 GPU 여러 개를 사용하기 위해서 복잡하게 설계됐다. 그리고 Local Response Normalization이라는 테크닉도 사용된 모양인데 별로 효과가 없어서 사장됐다고 한다.
마지막은 VGG-16이다. 2015년 논문이라 그런지 더 커졌다. 파라미터의 개수는 거의 1억 4천만 개 정도고 입력 이미지의 크기는 224x224x3이다. 이 논문의 시사점은 좀 중구난방으로 되어 있던 모델 구성을 일관성 있게 구성했다는 점인 것 같다. 실제로 채널의 개수를 64, 128, 256, 512 등 정리된 숫자로 사용한다. 그래서 채널 하나하나의 크기가 천천히 감소하고 채널의 개수도 천천히 증가한다.
2. ResNets
신경망의 레이어가 늘어나면 성능이 좋아진다. 하지만 그냥 마구마구 쌓아버린다고 계속 성능이 좋아지지 않는다. 기울기 소실과 폭발이 발생할 수 있기 때문이다. 그래서 ResNet 논문 저자들은 레이어를 더 쌓고도 어떻게 성능을 증가시킬 수 있을까 고민하다가 ResNet을 고안했다. 핵심 아이디어는 residual block이라는 것을 사용하는 것이다. Residual block은 레이어를 뛰어 넘어서 활성화 함수에 들어가기 전에 더 값을 더 해버린다. 왼쪽이 원래 방식이고 오른쪽이 ResNet 방식이다. F(x)를 x에 가까워지기 위해서 필요한 추가 학습이라고 생각한다면 H(x)가 x에 가까워질수록 F(x)=0으로 학습된다. 따라서 이전의 학습 과정보다 쉬워지게 된다.
ResNet은 VGG-19의 확장한 것이다. 또 VGG-19는 아까 VGG-16의 확장이다. 그림처럼 ResNet은 shortcut 내지는 skip connection이라고 불리는 방법을 통해 값을 앞으로 보내준다. 이렇게 하면 아무리 미분을 해도 x를 미분했을 때의 1이 남기 때문에 기울기 소실 문제가 발생하지 않는다.
사실 강의만 들었을 때는 이게 뭔가 하고 직관적으로 이해되지 않았다. 그래서 조금 찾아보니 optimal depth 관련 설명이 가장 이해하기 좋았던 것 같다. 레이어가 optimal depth를 넘지 않을 때에는 레이어를 추가하면 성능이 증가하지만 넘어버리면 성능이 점점 감소한다. 하지만 이 optimal depth는 알 수 없다. 이게 10일 수도 있고 30일 수도 있다. 이 문제를 ResNet이 optimal depth 이후의 가중치를 다 0으로 만들어버림으로써 optimal depth의 결과를 마지막 레이어까지 옮겨준다. 그래서 레이어를 더 많이 쌓더라도 성능이 감소하지 않게 된다.
3. Networks in Networks and 1x1 Convolutions
처음에 이게 뭔가 했는데 단순히 1x1 필터를 사용하는 게 아니었다. 이전에 배웠던 pooling의 경우는 채널 하나하나의 높이와 넓이를 줄여줬다면 이 1x1 convolution은 채널의 개수를 줄여준다. 정육면체를 앞 뒤로 눌러서 압축시킨다는 느낌이랄까. 이때 필터 개수를 조정해서 결과를 원하는 채널 수로 맞춰준다. Networks in nework라고도 한다.
그래서 이걸 사용해서 연산 비용도 줄일 수 있다. 이 방법을 사용하는 레이어를 bottleneck 레이어라고 부른다. 그냥 막 convolution 연산을 하면 연산량이 너무 많아진다. 그래서 중간에 1x1 convolution을 해서 채널의 개수를 줄인 다음에 원하는 크기로 다시 늘린다. 이렇게 하면 결과의 크기는 동일하지만 연산 비용을 획기적으로 줄일 수 있다. 그런데 강의를 들으면서 정보를 너무 축소하는 게 아닌가 하는 의문이 들긴 했지만 큰 문제는 아닌 것 같이 넘어갔다.
4. Inception Network
Network를 구성하기 위해서는 지금까지 배운 convolution과 pooling 중 어떤 연산을 할지, 만약 convolution으로 결정했다면 어떤 크기로 할지 등 결정해야 하는 사항이 많다. Inception은 고민 안 하고 다 해버린다는 마인드다. 원하는 건 다 해버리고 결과를 하나로 합친다. 이 그림 하나를 inception module이라고 부른다. 연산 비용을 줄이기 위해서 1x1 convolution도 사용했다. 대신 특이한 점이 마지막에 결과를 합치기 위해서는 max pooling을 해도 높이, 넓이가 변하면 안 된다. 따라서 패딩을 넣어서 same pooling을 해야 한다.
이걸 줄줄이 이어서 만든 게 inception network다. 이런 모델 짜는 건 진짜 어려울 것 같다. 그런데 아직 기초 강의를 듣고 있다는 점...
5. Depthwise Separable Convolution
사실 지금까지는 뭐 당연히 PC에서 연산을 한다고 가정했지만 실제로는 그렇지 않을 수도 있다. 요새는 하도 머신 러닝 이런 게 보편화돼서 핸드폰은 당연하고 다른 임베디드 디바이스에도 머신 러닝 모델이 들어간다. 이런 경우엔 자원이 충분하지 않을 수 있기 때문에 연산량을 줄이면 줄일수록 좋다. 그래서 depthwise separable convolution이라는 게 고안됐다. 이 방법을 사용하면 연산량을 감소시킬 수 있다.
이 방법은 한 번에 결과를 구하지는 못한다. Depthwise convolution부터 적용하고 pointwise convolution으로 최종 결과를 얻어낸다. 우선 비교를 위해서 보통의 convolution의 비용부터 계산했다.
다음은 depthwise convolution의 비용을 계산했다. 아까와 달리 한 번에 계산하는 것이 아니라 우선 n_c 만큼의 채널만 결과로 내보낸다.
그 이후엔 pointwise convolution을 한다. 위의 비용이랑 합쳐도 그냥 보통의 convolution보다 cost가 적다. 따라서 이 방법을 사용하면 동일한 입력, 출력 차원을 갖지만 연산량은 감소하는 장점이 있다.
6. MobileNet
그래서 depthwise separable convolution을 사용한 MobileNet이라는 모델이 있다. 이 모델은 자원이 한정적인 기기에서 작동할 수 있도록 경량화됐다. 강의에서는 v1과 v2를 소개하는데 v1은 위의 모듈을 13번 반복하고 마지막에 pooling, fully connected, softmax 레이어를 추가해서 결과를 낸다.
대신 v2는 조금 다르다. 우선 아까의 ResNet처럼 residual connection이 생기고 expansion 레이어가 추가된다. 이것 때문에 MobileNet v2는 조금 더 많은 특징을 학습할 수 있다. 그리고 이걸 bottleneck block이라고 부르고 이를 17번 반복한 이후에 결과를 낸다. 연산량과 메모리 사용량을 줄이면서 계산을 진행하기 때문에 모바일 기기에서도 잘 작동한다.
7. EfficientNet
컴퓨터 비전 모델을 구성하면서 더 좋은 결과를 내기 위해 조절해야 하는 사항은 크게 3가지 정도 된다. 첫 번째는 이미지의 해상도, 두 번째는 모델의 깊이, 세 번째는 레이어의 넓이다. 하지만 세상에 다양한 자원을 가진 디바이스가 있고 그 디바이스에서 이 중 어떤 걸 조정해야 할지는 알아내기가 매우 어렵다. 그래서 EfficientNet을 사용하면 파라미터를 조정해준다. 어떤 방식으로 이게 가능한지는 모르겠지만 앤드류 응 교수님은 이 오픈 소스를 사용해보라고 하셨다.
8. Transfer Learning
이건 저번에도 언급된 적이 있지만 조금 더 자세하게 예시를 들었다. 우선 컴퓨터 비전 영역에서는 전이 학습은 거의 무조건 해야 하는 과정인 것 같았다. 잠깐만 생각해봐도 확실히 도움 될 것 같긴 하다. 그리고 내가 추가적으로 학습시킬 수 있는 데이터가 적은 경우엔 모델을 가져와서 맨 마지막 레이어만 바꿔준다. 나머지 레이어는 고정시키고 학습시키지 않는다. 그래서 맨 마지막에서 하나 전 레이어까지는 결과는 매번 같다. 그럼 굳이 매번 계산할 필요가 없으므로 어디에다가 이 결과를 저장해놓고 맨 마지막 레이어만 계속 학습한다. 만약에 사용할 수 있는 데이터가 좀 더 늘어나게 되면 고정시켜놓은 레이어를 조금 줄이고 더 많은 레이어를 학습한다.
9. Data Augmentation
이것도 저번에 언급된 적 있는 내용이다. 데이터를 이리저리 변환시켜서 데이터의 양을 늘리는 기법이다. 저번보다 추가된 내용은 이미지의 색을 바꾸는 방법이다. 특히 PCA로 색을 변환하는 방법에 대해서도 언급하고 넘어갔다.
또한, 데이터를 로드하는 스레드를 따로 정해놓고 그 스레드에서 데이터를 로드한 다음에 변환을 수행하고 학습을 진행 중인 스레드로 이미지를 넘겨주는 방법도 소개됐다. 아마 이 방법을 쓰면 학습 속도가 더 빨라질 것 같다. 실제로 이렇게 하는지 잘 몰라서 확신은 안되지만 아마 조금 큰 모델들은 다 이렇게 병렬로 처리할 것 같긴 하다. 구현의 난이도는 올라가도 성능은 확실하지 않을까 싶다.
마지막으로는 컴퓨터 비전에 관한 자잘한 정보들을 들을 수 있었다. 요약하자면 전통적으로 컴퓨터 비전은 데이터가 적지만 그 와중에도 이미지 인식보다 객체 탐지(?) 쪽이 라벨링 붙이는 비용 때문에 데이터가 더 적다. 그리고 데이터가 적기 때문에 hand-engineering이 효과적이다. Ensembling, Multi-crop at test time 등이 방법을 쓸 수 있다 정도가 될 것 같다.
* Courera의 Deep Learning Sepcialization 강의를 수강하는데 도움이 되고자 작성한 요약문입니다. 틀린 내용 있다면 정정해주시면 감사하겠습니다.