Skip to main content

컴퓨터에게 일본어를 가르치는 방법

최신 모범 사례를 활용해 KMNIST 데이터셋에서 정확도 97%에 도달하는 이미지 분류기를 학습하는 방법을 알아보세요. 이 글은 AI 번역본입니다. 오역이 의심되면 댓글로 알려주세요.
Created on September 15|Last edited on September 15

소개


안녕하세요. 안녕.こんにちは.
방금 본 그 삐뚤빼뚤한 글자들은 일본어라는 언어에서 온 것입니다. 드래곤볼 Z를 본 적이 있다면 아마 들어봤을 거예요.
출처
그런데 문제는 이겁니다. 최후의 사무라이 닌자 초필살 콤보를 터뜨릴 것처럼 보이게 만드는 그 오래된 일본 두루마리 있잖아요.
맞아요, 그거요. 저는 제대로 읽지도 못하고, 알고 보니 읽을 수 있는 사람도 거의 없더라고요.
다행히도 똑똑한 사람들이 제가 비주다마-나선수리검을 마스터하는 게 얼마나 중요한지 잘 이해하고 있어서, 딥러닝이라는 것을 발명해 줬습니다.
그러니 라면 챙기고 준비하세요. 이 글에서는 이미지로부터 일본어 문자를 정확하게 예측하는 신경망을 학습하는 방법을 보여 드리겠습니다.
좋은 결과를 얻기 위해, 저는 fastai라는 훌륭한 딥러닝 라이브러리를 사용할 예정입니다. fastai는 PyTorch 위에 구축된 래퍼로, 최신 연구에서 권장되는 모범 사례를 쉽게 구현할 수 있게 해줍니다. 이에 대한 자세한 내용은 해당 프로젝트의 페이지에서 읽어보실 수 있습니다. 문서.
그럼 시작해 봅시다.

KMNIST

좋아요, 애니메이션 자막을 만들기 전에 먼저 데이터셋이 필요합니다. 오늘은 KMNIST에 집중해 보겠습니다.
이 데이터셋은 일본의 쿠즈시지 문자 예시를 모아 10개의 레이블된 클래스로 구성했습니다. 이미지 크기는 28×28픽셀이며, 전체 이미지 수는 70,000장으로 MNIST와 동일한 구조를 따릅니다.
그런데 왜 하필 KMNIST일까요? 일단 이름에 “MNIST”가 들어가잖아요. 머신러닝 하는 사람들이 MNIST를 얼마나 사랑하는지 우리 모두 잘 알고 있잖아요.
출처
이론적으로는 스택 오버플로에서 복붙한 그 Keras 코드를 몇 줄만 살짝 바꾸면, 짜잔! 이제 당신은 다음을 할 수 있는 컴퓨터 코드를 얻게 됩니다 고대 일본 문자를 되살리기.
물론 실제로는 그렇게 간단하지 않습니다. 우선, MNIST로 귀엽게 학습시킨 그 작은 모델은 아마 기대만큼 성능이 나오지 않을 겁니다. 왜냐하면 숫자가 2인지 5인지 구분하는 일은, 지구상에서도 읽을 줄 아는 사람이 손에 꼽히는 잊혀진 필기체 문자를 판독하는 것보다 훨씬 쉬운 일이니까요.

그 밖에 짚고 넘어가자면, KMNIST의 K가 가리키는 ‘쿠즈시지’는 겨우 10글자만 있는 문자가 아닙니다. 유감스럽게도 저는 아니요 그 언어를 읽을 수 있는 몇 안 되는 전문가 중 한 명이 아니라서, 그것이 어떻게 작동하는지 세세하게 설명할 수는 없습니다.
하지만 제가 확실히 아는 게 있습니다. 이 쿠즈시지 문자 데이터셋에는 실제로 세 가지 변형이 있습니다 — KMNIST, Kuzushiji-49, 그리고 Kuzushiji-Kanji입니다.
Kuzushiji-49는 10개 대신 49개 클래스를 가진 변형입니다. Kuzushiji-Kanji는 무려 3832개 클래스가 있어서 난이도가 훨씬 높습니다.
맞습니다, 제대로 읽으셨어요. ImageNet보다 클래스 수가 세 배나 많습니다.

데이터셋을 망치지 않는 방법

가능한 한 MNIST스럽게 유지하기 위해, KMNIST 데이터셋을 공개한 연구자들은 원래 형식을 그대로 유지한 듯합니다(정말 MNIST 정신을 뼛속까지 새긴 거죠, 안 그런가요).
만약 당신이 살펴본다면 KMNIST GitHub 저장소, 데이터셋이 두 가지 형식으로 제공된다는 것을 보실 수 있습니다. 원래의 MNIST 형식과 여러 개의 NumPy 배열 형식입니다.
물론 그 링크를 누르기 귀찮았겠죠. 자, 여기 있습니다. 나중에 감사해도 됩니다.
출처
 개인적으로는 fastai를 사용할 때 NumPy 배열 형식이 더 다루기 쉬웠지만, 선택은 여러분에게 달려 있습니다. PyTorch를 사용한다면, KMNIST는 다음의 일부로 무료로 제공됩니다 torchvision.datasets.
다음 과제는 그 1만 년 된 붓놀림을 당신의 노트북(아니면 IDE, 뭐 제가 평가할 건 아니죠)으로 실제로 가져오는 일입니다. 다행히 GitHub 저장소에 download_data.py라는 유용한 스크립트가 있어서 우리가 해야 할 일을 전부 대신해 준다고 하네요. 야호!

여기서부터는 실제 코드 없이 데이터 전처리 방법만 계속 얘기하면 좀 어색해질 겁니다. 그러니 다음을 확인해 보세요 노트북 더 깊이 파고들고 싶다면.
다음으로 넘어가 보죠…


초초초 거대한 인셉션 ResNet XXXL을 써야 할까요?

짧은 답변

그럴 필요는 아마 없어요. 일반 ResNet이면 충분합니다.

조금 더 긴 답변

좋아, 봐요. 지금쯤이면 아마 이렇게 생각하고 있겠죠. “KMNIST 크다. KMNIST 어렵다. 나는 아주 새롭고 아주 근사한 모델을 써야 한다.”

제가 비자르로 목소리를 너무 과하게 냈나요?
요점은, 이런 이미지 분류 작업에서 잘하려고 반짝이는 최신 모델이 꼭 필요하지 않다는 겁니다. 잘해봐야 아주 조금의 정확도 향상을 얻는 대신, 엄청난 시간과 비용을 치르게 될 가능성이 큽니다.
대부분의 경우, 시간과 돈만 잔뜩 낭비하게 될 겁니다.
그러니 제 말대로 하세요 — 그냥 익숙하고 검증된 ResNet에만 충실하면 됩니다. 성능이 정말 좋고, 인셉션이나 DenseNet처럼 메모리를 많이 먹는 모델들에 비해 비교적 빠르고 가볍습니다. 게다가 무엇보다도 이미 오래전부터 널리 쓰여 온 모델이라, 미세 조정도 그리 어렵지 않을 겁니다.
다루는 데이터셋이 MNIST처럼 단순하면 ResNet18을 쓰세요. CIFAR10처럼 중간 난이도라면 ResNet34를 쓰세요. ImageNet처럼 정말 어렵다면 ResNet50을 쓰세요. 그보다 더 어렵다면, 아마 ResNet보다 더 좋은 모델을 쓸 여유가 있을 것입니다.
믿기지 않나요? 2019년 4월 Stanford DAWNBench 대회에서 제가 올린 상위권 참가작을 확인해 보세요:

믿기지 않나요? 2019년 4월 Stanford DAWNBench 대회에서 제가 올린 상위권 참가작을 확인해 보세요:

하이퍼파라미터 총정리

몇 달 전, 저는 이런 글을 썼습니다 적절한 하이퍼파라미터를 고르는 방법이 거대한 과제를 더 일반적으로 풀어내는 방법에 관심이 있다면, 그 글을 확인해 보세요. 여기서는 KMNIST에서 충분히 좋은 결과를 얻기 위해, 충분히 괜찮은 하이퍼파라미터를 고르는 제 과정을 안내하겠습니다.
먼저, 어떤 하이퍼파라미터를 튜닝해야 하는지 살펴보겠습니다.
우리는 이미 ResNet34를 쓰기로 했으니 그걸로 결정입니다. 레이어 수, 커널 크기, 필터 개수 같은 것들은 모델에 이미 포함되어 있으므로 따로 정할 필요가 없습니다.
거봐요, 시간이 절약된다고 했잖아요.
그럼 남은 건 세 가지 핵심입니다. 학습률, 배치 크기, 에포크 수죠. 드롭아웃 확률 같은 나머지 항목은 기본값을 그대로 써도 됩니다.
하나씩 차근차근 살펴보겠습니다.

에포크 수

에포크 수부터 시작해 봅시다. 노트북에서 모델을 직접 만져 보면 알겠지만, 우리의 학습은 꽤 효율적입니다. 몇 분만에 90% 정확도를 가볍게 넘길 수 있습니다.


애초에 학습이 이렇게 빠르다면, 에포크를 너무 많이 돌려서 과적합될 가능성은 매우 낮아 보입니다. 다른 KMNIST 모델들이 50에포크 넘게 학습해도 문제없는 사례를 많이 봤기 때문에, 0~30 범위에 머무르는 건 전혀 문제가 없습니다.
즉, 에포크에 관해 모델에 걸어 둔 제한 범위 안에서는 많을수록 좋다는 뜻입니다. 제 실험에서는 10에포크가 정확도와 학습 시간 사이의 균형을 가장 잘 맞춰 주었습니다.

학습률

지금부터 하려는 말은 많은 사람들의 심기를 건드릴 수도 있습니다. 그래도 솔직히 말하자면 — 학습률에 그렇게까지 신경 쓸 필요는 없습니다.
맞아요, 제 말이 틀리지 않았습니다. 하지만 설명할 기회를 주세요.
“흠… 잘 안 되네, 그럼 lr=3e-3 로 다시 해 보자” 같은 식으로 하기보다는, 훨씬 더 체계적이고 절제된 방식으로 적절한 학습률을 찾겠습니다.
우리는 Leslie Smith가 그의 논문에서 제안한 혁신적인 아이디어인 학습률 파인더를 사용할 것입니다. 순환 학습률에 관한 논문.
작동 방식은 다음과 같습니다:
  • 먼저 모델을 설정하고 한 에포크 동안 학습할 준비를 합니다. 모델이 학습되는 동안 학습률을 점진적으로 높일 것입니다.
  • 그 과정에서 우리는 매 반복마다 손실 값을 기록할 것입니다.
  • 마지막으로, 손실이 가장 낮을 때의 학습률을 선택합니다.
모든 과정을 마치고 손실 값을 학습률에 대해 그래프로 그려 보면, 대략 다음과 같은 형태가 나올 것입니다:

이제 들뜬 마음으로 학습률을 1e-01로 고르기 전에, 그게 최선의 선택은 아니라는 점을 알아두세요.
그건 fastai가 지수 가중 이동 평균이라는 매끄럽게 만드는 기법을 구현하기 때문입니다. 딥러닝 연구자들이 쓰는 인스타그램 필터쯤으로 생각하시면 됩니다. 이 덕분에 그래프가 이웃집 아이에게 파란 크레용을 오래 쥐여줬을 때 나올 법한 난장판처럼 보이지 않게 됩니다.

플롯을 부드럽게 보이게 하려고 일종의 평균화를 사용하고 있으므로, 러닝 레이트 파인더에서 보이는 “최소값” 지점은 실제 최소값이 아닙니다. 그것은 평균값입니다.
대신 실제로 학습률을 찾으려면, 평활화된 그래프에서 최소 지점보다 한 자리수(10배) 낮은 값을 고르는 것이 좋은 경험칙입니다. 실전에서도 대개 매우 잘 작동합니다.
지금까지 학습률 값을 무식하게 다 대입해 보며 찾아왔던 입장이라면, 이런 플로팅과 평균화 과정이 다소 낯설게 느껴질 수 있습니다. 그래서 다음을 한번 확인해 보시길 권합니다 Sylvain Gugger의 학습률 파인더 설명 더 알아보기.

배치 크기

맞아요, 딱 걸렸네요. 처음 실험할 때는 상위 제출이 그렇게 썼길래 배치 크기를 128로 사용했습니다.
알아요, 알죠. 별로 창의적이진 않네요. 하지만 그게 제가 한 일이에요. 그 뒤에 몇 가지 다른 배치 크기도 시험해 봤지만 더 나은 결과를 얻지 못했습니다. 그래서 128로 갑니다!
일반적으로 배치 크기는 최적화하기 까다로운 편입니다. 사용하는 컴퓨터 환경에 부분적으로 좌우되기 때문이죠. VRAM이 더 많은 GPU를 갖고 있다면 더 큰 배치 크기로 학습할 수 있습니다.
그러니까 제가 예를 들어 배치 크기를 2048로 쓰라고 하면, Kaggle 최고 순위를 차지해서 영원한 명예와 영광을 얻기보다는 CUDA: 메모리 부족 오류를 만나게 될 수도 있습니다.
그래서 현실적으로는 분명한 계산 자원 한계가 있기 때문에, 완벽한 배치 크기를 딱 잘라 추천하기는 어렵습니다. 가장 좋은 선택 방법은 자신의 환경에서 잘 돌아가는 값들을 직접 시험해 보는 것입니다.
그런데 양의 정수라는 광대한 바다에서 무작위로 숫자 하나를 어떻게 고르겠습니까?
사실 그럴 필요는 없습니다. GPU 메모리는 비트 단위로 구성되어 있으므로, 미니배치가 메모리에 깔끔하게 맞도록 배치 크기를 2의 거듭제곱으로 선택하는 것이 좋습니다.
제가 하겠다 싶으면 이렇게 하겠습니다. 우선 512처럼 적당히 큰 배치 크기로 시작하세요. 그러다가 모델이 이상하게 굴고 손실이 뚜렷하게 내려가지 않는다면 절반으로 줄이세요. 그다음 배치 크기를 256으로 해서 학습을 다시 돌려 보고, 이번에는 제대로 동작하는지 확인하세요.
그렇지 않다면, 처음부터 다시 반복하세요.

몇 가지 보기 좋은 그림들

여기서 최적화를 진행하다 보니, 우리가 만들어낸 수많은 모델, 지표, 하이퍼파라미터라는 거대한 혼란을 일일이 추적하기가 꽤나 어려워질 것입니다.
정확도라는 산을 오르면서도 모두 제정신을 유지할 수 있도록, 우리는 사용할 것입니다 wandb + fastai 통합.
그렇다면 wandb는 실제로 무엇을 할까요?
모델과 성능에 관한 온갖 통계를 자동으로 추적해 줍니다. 그런데 더 좋은 점은 정확도와 손실 같은 핵심 지표를 실시간으로 확인할 수 있도록 즉시 차트와 시각화를 제공한다는 것입니다!
그것만으로도 충분하지 않다면, 모든 차트와 시각화, 통계까지 클라우드에 저장해 언제 어디서든 접근할 수 있습니다.
검은 터미널 화면을 멍하니 바라보며 matplotlib을 이리저리 만지작거리던 시대는 끝났습니다.
노트북 튜토리얼 이 글에서는 fastai와 매끄럽게 연동되는 방법을 간단명료하게 소개합니다. 또한 다음도 확인해 보세요 wandb 작업 공간, 여기에서 코드를 한 줄도 쓰지 않고 제가 언급한 모든 내용을 한눈에 살펴볼 수 있습니다.

결론

이것으로 끝입니다
즉, “이것으로 끝입니다.”라는 뜻입니다.
하지만 그 정도는 굳이 제가 말해 줄 필요도 없었죠, 그렇지 않나요? 일본어 문자 데이터셋을 구하고, 학습률 파인더를 써서 적정 값을 찾고, 최신 베스트 프랙티스로 ResNet을 학습시키고, 클라우드에서 실시간 모니터링으로 모델이 성과를 내는 모습을 지켜본 뒤라면 말이에요.
맞아요, 약 20분 만에 정말 전부 해냈습니다! 스스로에게 토닥토닥 잘했다고 해 주세요.
그리고 제발 드래곤볼도 좀 보세요.



이 글은 AI로 번역되었습니다. 오역이 있을 수 있으니 댓글로 알려 주세요. 원문 보고서는 다음 링크에서 확인할 수 있습니다: 원문 보고서 보기