ResNet50 모델을 Keras API 없이 논문을 읽고 구현해보기
머신러닝 엔지니어로 발전하겠다고 목표로 한 만큼, 이 분야 학습에 있어서 논문 리뷰 및 코드 구현은 필수로 자리 잡았고, 어느 정도 이해를 하고 있는 모델을 중심으로 시작을 해 볼 필요성이 있을 것 같다는 판단하에 ResNet50을 첫번째 논문 리뷰 모델로 선택하게 되었다.
구글 머신러닝 부트캠프 2021을 수강하면서 Coursera 딥러닝 특화 과정을 수강했으며, 해당 강의의 CNN 파트에서 ResNet50이 이해하기 쉽고, 구현하기 쉽다는 언급을 하면서 내용 설명을 했는데, 강의에서 쉽게 설명해주던 것과는 별개로 실제 논문에서는 방정식이나 연관되어 있는 다른 논문들 설명을 엮어서 서술하기 때문에 읽는 게 쉽지 않았다.
ResNet50에 대한 논문을 읽어보고 싶다면 옆의 here 링크를 클릭해서 확인하자.
이 논문에 대한 학습은 아래와 같은 순서로 진행될 것이다.
- 왜 ResNet50이라는 모델로 성능 개선이 필요해졌는가? (논문 배경)
- 논문에서 주로 해결하고자 했던 포인트는?
- 코드 실습
- 후기
- Reference
개인적으로 논문을 3번 정도는 정독했던 것 같고, 아직도 좀 이해가 안되는데 Identity Mapping과 같은 개념을 제대로 이해 못해서 유튜브에서 다른 사람들의 논문 리뷰 내용을 함께 확인했던 것 같다.
내가 이 논문을 선택한 이유는 일전에 프로그래머스에서 제공해는 미술 작품 분류하기에 ResNet50 모델 API를 사용해봤고, 모델을 정확하게 이해하지 못하는 상황에서 코드를 쓰는 것은 영 불안해서 (나중에 현업에서 API만 갖다 쓸 것은 아니기 때문에) 직접 구현해보는 과정을 겪고 싶었다.
그럼, 논문 읽은 것을 한 번 차근차근 정리해보자.
1. 왜 ResNet50이라는 모델로 성능 개선이 필요해졌는가?
먼저 ResNet50 논문이 발간된 년도는 2015년이고, 당시 MS에서 인공지능 모델을 연구하던 분들이 이미지 인식 대회에서 이 모델로 1등을 차지하게 되어 유명세를 얻게 되었다.
모델이 발간된지 이제 6년 밖에 안되었는데 많은 사람들에게 읽히는 것을 보면 (코세라에서 딥러닝 기초 강의에서 소개할 정도로 이해하기 쉽다는 뜻이기도 하고) 이해하기 쉽다는 점, 그리고 코드 구현이 쉽다는 점 등이 꼽히는 것 같다.
(Bubble sort, Insert Sort 같은 정렬 기법들이 1970 ~80년도에 연구되어서 2000년대 초반에 학부 수업에 적용된 것을 보면, 그 때보다 압도적으로 빠르게 사람들에게 보급된 것이다.)
이 논문의 시작은 신경망의 깊이가 깊어질수록 모델을 훈련시키기 어려워진다는 것으로부터 출발하며, Layer를 더 추가한다고 해서 성능이 획기적으로 개선시키기 어렵다는 점을 얘기한다.
실제로 아직 CNN에 대해 깊게 이해하고 있는 것은 아니지만, Tensorflow 개발자 수료증 시험 볼 때, 미술 작품 분류 과제 2개를 수행할 때 CNN 모델에서 CNN 층을 성능을 높여보고 싶은 급한 마음에 층을 무작정 많이 넣었고, 특별한 이유 없이 파라미터가 2000만개가 넘어갔던 적이 있다.
ResNet이나 추후에 또 리뷰하게 될 Xception 모델을 쓰면 2000만개 사용하는 게 무슨 대수냐고 싶겠지만, 명확한 목적 없이 층을 쌓는 것은 모델 훈련 속도도 느려질 뿐만 아니라 검증 손실률도 엄청나게 올라가며, 되려 원하는 정답에서 멀어지는 Degradation 이슈가 있다.
또한 기울기 소실 (Vanishing) 또는 폭발 (Exploding)하는 이슈도 있어서 층을 쌓아서 모델을 만드는 것만으로는 한계가 있었고, 이를 해결하기 위해 등장한 것이 ResNet이다.
2. 논문에서 주로 해결하고자 했던 포인트는?
ResNet이라는 단어는 구글링해보면 바로 알겠지만 Residual Network, 즉, 잔차를 이용한 모델 학습 방법이다.
바로 위에서 층이 깊어질수록 기울기의 Vanishing or Exploding, degradation 이슈가 있고, 이러한 문제를 해결하기 위해 입력값으로 받아오는 데이터를 출력값에 연결하는 — 이를 Shortcut Connection이라 설명 — 기법을 사용한다.
내가 받아들인 내용이 맞다면, 가중치의 vanishing, exploding 문제를 해결하면서 결정적으로 degradation 을 해결하는 것으로 보인다.
이를 좀 더 도식화하면 아래의 이미지인데, 동일하게 34개의 층을 사용해서 이미지를 학습시킨다면, 위의 shortcut connection을 사용한 모델을 표현하는 것은 오른쪽의 이미지 구조가 될 것이다.
위의 이미지를 표로 간략하게 표기하면, 아래의 이미지 속 붉은 박스가 될 것이다.
성능 차이가 확실하게 나고 있으며, 층이 깊어질수록 일반적인 네트워크는 에러율이 높아지는데, ResNet은 되려 성능이 개선되는 것을 확인할 수 있다.
Residual 값을 가져와서 결과 값에 더하는 로직을 이제 이해했고, 이 로직이 일반적인 network보다 깊이가 깊을 때 성능을 향상시킨다는 것을 이론적으로 확인해봤으니, 코드 실습으로 내용을 검증해보자.
3. 코드 실습
논문에서의 실습 환경: CIFAR-10, ImageNet (ImageNet은 곧 추가 예정)
두 데이터 모두 직접적으로 다뤄본 적은 없고, ImageNet은 전처리되어 있는 데이터를 가져와 이미지 분류 모델에 전이학습 모델 형태로 사용해 본 경험만 있다.
아래 코드는 CIFAR-10을 기준으로 실습한 코드인데, 문제가 있다.
코드 스펙은 논문에서 요구하는대로 작업이 된 것 같은데 (Coursera에서 언급된 코드를 내가 CIFAR-10 데이터셋에 맞게 약간 커스터마이징을 진행했고, 코드는 에러 없이 잘 동작한다) 1 에폭에 45분씩 학습 시간이 걸린다.
케라스 API에서 제공되던 것을 쓰다가 내가 직접 이미지를 학습시키려 하다보니 문제가 발생한 것인가?
왜 이렇게 속도가 느린지 커뮤니티에 물어볼 필요가 있을 것 같다.
API만 갖다 쓰다가 내가 구현하려니까 내 맘 같이 움직이지 않는다.
조금 더 시간을 들여서 구현해보고, 어디서 문제인지 찾는데 시간이 너무 오래 걸리면 ResNet50 케라스 API 코드를 확인해보면서 검증해보자.
막상 구현해보니, 논문에서 어떻게 구현하면 된다고 언급이 충분히 되어 있어서 구현 자체는 어렵지는 않은 것 같다?
말은 이래도 이 코드 구현하느라 5일 정도 시간을 쓴 것 같다.
ImageNet 코드 실습도 빨리 해봐야겠다.
4. 후기
4–1) 앞으로 논문 읽는 방향성
사람들에게 많이 읽히는 논문일수록, 그리고 논문이 출간된지 1년 정도만 지나도 블로그에 코드와 논문 내용이 정리되어 있는 듯 싶다.
최신 논문을 빨리 따라가야겠다는 마음이 조급하긴 하지만, ResNet50의 논문으로 보건데 기존의 논문에서 한 가지 기능이 개선되는 방식으로 사용되었다는 점 등으로 보건데 이후에 읽게 될 이미지 인식과 관련한 논문들은 내용이 겹치는 부분들이 많아서 지금보다 빨리 읽을 수 있을 것 같다.
4–2) 통계 등 수학 지식에 대한 필요성
아무리 핵심적인 부분은 코드로 구현하면서 내용을 이해한다고 해도, 정작 논문을 읽을 때 수학 방정식 등에 대한 설명은 코드로 구현하기 전에 내용 이해가 도저히 안된다.
지금이야 ResNet이라 사람들이 정리한 글과 영상이 있어서 망정이지, State-of-art의 논문을 읽으면 방정식의 해석 여지를 두고, 낫 놓고 ㄱ자도 모르는 상황이 올 수 있을 것 같다. 안타깝지만 AI 모델링이나 데이터를 다루는 부분에서 수학은 꼭 필요한 것 같으니 머신러닝 수학 등에 대한 강의를 찾아보면서 지식을 늘려야겠다.
4–3) 논문 리뷰와 별개로 꾸준히 데이터를 다루는 프로젝트 참여에 대한 필요성
주어진 모델을 다양한 데이터에 적용해 볼 수 있으려면 논문 리뷰하는 상황과 병행해서 캐글 등에서 데이터를 다루는 프로젝트를 꾸준히 해 볼 필요가 있을 것 같다.
왜 ResNet50 논문 리뷰가 수학적인 부분을 제외하고, 학습이 편했나 생각해보면 내가 이미지 분류 과제를 해보면서 API 형태라고 사용해봤다는 점, 코세라에서 내용 언급이 한 번 있었다는 점 등이 고려될 수 있을 것 같고, 다양한 데이터를 변환해가면서 성능을 측정해 볼 수 있는 활용성 등을 고려해 볼 수 있을 것 같다.
머신러닝을 배우는 것이 데이터 기반 비즈니스 결정 능력에도 영향을 주는 만큼 논문에 언급된 모델 학습 + 데이터는 서로 별개의 학습으로 보기 어렵지 않을까 싶다.
4–4) Reference에 있는 논문 리스트로 새롭게 읽을 논문 탐색하기
한 편의 논문 출고를 위해 참고한 다른 논문들이 꽤 있고, 이 논문들 중에서 인용 횟수가 높은 순으로 새로운 논문 학습으로 이어질 수 있을 것 같다.
어떤 논문으로부터 시작할지 생각하는 게 막막하다면, 우선 잘 알려져 있는 논문에서 reference를 Graph 알고리즘 구조처럼 계속 타고 넘어가서 찾아보면 좋을 것 같다.
논문을 꾸준히 읽다보면, 찾아봐야하는 논문보다 읽어본 논문이 더 많아지는 시기가 올지도 모른다.
4–5) 전문 용어가 많아 읽는데 많은 시간이 소요됨
영문과를 졸업해도 전문용어가 많이 등장하는 컴퓨터 공학 논문은 다른 나라 언어랑 비슷하다. 내용에 주석이 달려도 그 주석조차 전문 용어라 해석해서 내 것으로 만드는데 시간이 꽤 많이 필요하다. 학습할 수록 이런 현상은 줄겠지만, 시간이 많이 소요되는 것을 감안하고 읽는 것이 필요할 것 같다.
4–6) 아무리 논문에 코드 설명이 잘 되어 있어도 실습 과정에서 에러는 피할 수 없다.
논문에서 내용이 친절하게 잘 언급되어 있어도, 역시 구현하는 사람이 초보자면 에러는 피해갈 수 없다.
이번에 sparse_categorical_crossentropy와 categorical_crossentropy 차이를 명확하게 알았는데 sparse는 one-hot encoding이 안되어 있는 정수 값을 분류할 때, 그리고 categorical은 one-hot encoding을 한 상태에서 사용해야한다는 점 등이다.
분명 다음에 읽을 논문은 지금보다 빨리 읽고 구현할 것 같은데, 이렇게 한 개씩 알아가는 게 아닐까 싶다.