신경망 기술은 모든 업계에 큰 변화를 가져다 주고 있습니다.

우리 실생활에 직접적으로 맞닿아있는 금융업계에서도 다양한 변화가 일어나고 있는 것또한 자명한 사실입니다.

내부적으로 리얼(real)한 기술이 적용되었는지는 까봐야 알 수 있지만, 챗봇(Chatbot), 금융 사기 탐지(Fraud Detection), 대출, 보험과 같은 다양한 상품을 초개인화로 제공해주기 위한 추천 시스템(Recommendation System) 기술 등 딥러닝이 화두가 되기 이전에도 다양한 알고리즘으로 문제를 해결하고 있던 것들이 이제금 딥러닝 기술 적용으로 새로운 성능을 맛보고 있습니다. 심지어 이제 많은 사람들이 당연하고, 편하게 이용하고 있는 음성/얼굴 인식, 생체 인식 기술도 딥러닝 기술에 포함됩니다.

  • 딥러닝으로 활발하게 다뤄지는 분야들
    - 고객 서비스
    - 가격 예측
    - 포트폴리오 관리
    - 사기 탐지
    - 트레이딩 자동화
    - 리스크 관리
    - 신용 평가
    - ...

이번 글에서는 '특정' 주제를 다룰 것이다!라고 단정짓지 않고 금융에서 나타나고 있는 전반적인 변화에서, 특히 딥러닝 기술이 어떻게 활용될 수 있는지 서베이(Survey)해보기 위해 작성, 정리한 글입니다. 또, 딥러닝에 관점을 맞추는 이유는 더욱더 불확실해지고 있는 데이터를 다루기 위한 해결 요소로서 딥러닝 기술이 최적화되어 있다고 판단하기 때문입니다. 뿐만 아니라 금융업계는 지금까지 엄청난 고객 데이터를 쌓아왔기 때문에 이를 적극 활용하여 포스트 코로나 시대에서의 또다른 가치를 만들어내기 위해 힘쓰고 있습니다.
물론 아직까지는 알고리즘, 머신러닝을 활용한 기술을 무시할 수 없다는 점도 알려드립니다.

  • 이야기 순서
    • 금융업계의 숨겨진 힘: 고객 데이터
    • 고객 데이터에 딥러닝을?(금융업 관점)

금융업계의 숨겨진 힘: 고객 데이터

우리가 금융과 딥러닝을 함께 생각했을 때 가장 쉽게 떠오를 수 있는 것은 트레이딩(Trading) 관련 내용입니다. 고객은 돈만 주면 알아서 돈을 벌어오는 그런 구조요. 이에 관련해서는 대표적으로 크래프트 테크놀로지스라는 회사가 눈에 띕니다.

'적절한 타이밍에 사고/팔고 싶어! 근데 내가하긴 싫고, AI 너가 해. 그리고 돈 벌어와!'

딥러닝을 잘 모르는 고객이라면 매우 흥미로운 서비스입니다. 수시로 주가를 모니터링하지 않아도 AI가 알아서 적절한 상황을 판단하여 사고, 팔아 이익을 가져다주기 때문이죠. 여기서 잠깐, 고객의 입장과 트레이딩에 관한 기술도 매우 흥미롭지만, 우리는 전사적 차원으로 접근할 것입니다. 인공지능 기술을 탑재한 트레이딩처럼 엄청난 서비스를 고객에게 제공함으로써 자사 플랫폼에 머물게 하고 더 많은 기능을 사용하게끔 유도하게 됩니다(최근 금융업계는 플랫폼으로의 전환을 꾀하고 있다는 점을 무시할 수 없습니다). 또, 이를 달성하기 위해 먹이를 찾아나서는 기존의 행동 방식과 다르게 기술과 데이터를 적극적으로 활용하려는 움직임을 보이고 있죠.

  • 카카오의 카카오페이와 뱅크
  • 네이버의 네이버페이
  • 신한, KB, 우리 등 국내 금융업계

주식 예측, 펀딩 등을 수행하는 이런 기술은 매력적이지만 실제로 수많은 불가항적인 요소에 의해 적용, 구현하기 매우 어렵습니다. 향후 몇년 이후에는 진짜 상용화가 가능한, B2C가 가능한 Trading-Bot이 나올지도 모르겠지만, 지금은 아닐거에요.

주식 거래는 우리에게 익숙한 주제이고, 많은 사람이 이를 통해 큰 수익을 얻고자 하기 때문에 이를 통해 잠시 서론을 꾸며보았습니다. 사실 금융업계가 가지고 있는 진짜 힘은 이런 기술적인 부분이 아니라 수년간 쌓아오고, 정제해온 고객 데이터에 있습니다. 고객의 성별, 나이, 주소는 물론 거래 내역, 대출, 신용 정도 등 엄청나게 다양한 매력적인 특성(Feature)을 가지고 있습니다. 그리고 이들을 활용해서 마치 넷플릭스처럼, 유튜브처럼 뛰어난 추천 시스템을 개발해서 맞춤형 서비스를 제공하거나 미래의 행동을 미리 예측하여 그에 알맞는 고객 관리 방법을 적용할 수 있게끔 많은 노력을 기울이고 있습니다.

  • 고객 데이터로 다뤄볼 수 있는 것들
    • 추천을 통한 맞춤형 서비스 제공
    • AI 상담원 - 고객 서비스
    • 자산/리스크 관리
    • 이탈 고객 예측
    • 이 외에도 엄청 많아요.

쌓아둔 데이터도 많고, 딥러닝도 많이 발전했으니 이제 모델링을 통해 엄청 훌륭한 모델을 만들고,
고객에게 빨리 제공해서 이익을 창출할 수 있지 않을까요?

매우 힘들고 많은 시간이 소요될겁니다. 핵심적인 이유는 금융업계가 보유하고 있는 대부분의 고객 데이터가 정제되지 않은 상태라는 점 때문입니다. 또, 적재된 데이터의 특성과 양이 많아 이를 정제하는데 엄청난 비용이 소모되는 것도 사실입니다. 아마 우리가 데이터 분석을 배울때, 전체 시간의 80%는 데이터 파악에 활용한다!라고 배우는 것처럼 모델링에 투자하는 시간보다 기존 데이터를 정제하고 다시 쌓는 시간이 매우 오래 걸릴 것입니다. 하물며, 모델링을 수행한다고 해서 높은 성능을 기대하기란 매우 어려울거에요(빠른, 많은 A/B Test가 더욱 중요해지는 시점).

고객 데이터는 설계에 따라 지저분해진다면 제한없이 지저분해질 수 있는 장점(?)을 보유하고 있습니다. 이 때문에 고객 데이터를 다룸에 있어서 유명한 말인 'Garbage In, Garbage Out'이라는 말이 더욱 와닿는 것 같습니다. 부가설명이 필요없겠죠?

그렇다면 공격적인 투자도 좋지만, 선례를 조사해서 우리에게 알맞는 기술 적용을 검토해보자라는 느낌으로 금융업계에서 고객 데이터와 딥러닝을 활용해 어떤 서비스를 제공하고 있는지 더 살펴보죠.

 

고객 데이터에 딥러닝을?(금융업 관점)

1. 상품 추천과 마케팅

사실 이 부분은 따로 다루기 보다 유튜브나 넷플릭스의 추천 시스템 관점에서 생각하는 게 제일 적합하다고 생각합니다. 그럼에도 불구하고 조금만 코멘트를 추가해보죠.

우리가 자주 접하는 쇼핑몰에서의 의류, 전자 제품 등만 상품을 떠오를 수 있지만, 금융업에서 제공할 수 있는 상품은 이를테면, 예/적금 상품, 대출 상품, 보험 상품 등이 있습니다. 상품 추천이 중요한 이유는 고객을 끌어들이는 것도 있지만, 금융업계에서는 이탈 고객을 방지하는 것도 그에 못지않게 엄청 중요하기 때문입니다.

보통의 금융업계는 이탈 고객을 방지하기 위해 약간의 머신러닝 방법을 사용하는 경우나 그렇지 않은 경우를 포함해서 메일 또는 문자 메시지를 발송합니다. 일반적으로 '메일이나 문자를 주기적으로 보내서 규모의 경제처럼 고객 이탈을 방지하면 되지 않을까?'라고 생각할 수 있지만, 기업 입장에서는 이게 전부 '돈'입니다. 마케팅 비용이죠.

고객의 향후 패턴이나 특성을 고려하지 않은 내용을 포함한 메일/문자를 5번 보내서 이탈 고객 1명을 방지할 것을 딥러닝 모델을 사용해서 고객을 더욱 정확히 파악하고 이를 통해 1번의 문자로 고객의 이탈을 방지할 수 있습니다. 이를 위해서는 고객이 무엇을 원하는지를 정확히 추천할 필요가 있기 때문에 추천 시스템의 중요성은 더욱 높아지고 있습니다.

 

2. 이상 거래 탐지

이상 거래 탐지(Fraud Detection System)는 금융업계에서 아주 활발히 연구되고 있는 분야입니다. 신한, 핀크, 농협 등 FDS의 고도화를 진행하고 있습니다.

기존 룰 기반(Rule-base)으로 이상 거래를 탐지하던 방식은 시간이 지날수록 정교화되는 거래 사기를 잡아내기엔 제한적이기 때문에 많은 금융업계에서 머신러닝, 딥러닝 방법 적용에 큰 관심을 두고 개발하여 적용하고 있습니다. 여기서 사용될 모델은 기존 고객이 사용하던 거래 패턴과 사기 거래 패턴의 전체적인 맥락을 파악해서 차이점을 인식한 후 사기인지 아닌지를 우리에게 알려주어야 합니다. 그렇기에 불규칙적인 패턴을 잘잡아낼 수 있다는 큰 장점을 가진 딥러닝 모델이 관심을 받는 것이기도 합니다.
(물론 이를 위해 사람의 엄청난 노가다가..).

대표적으로 RF(Random Forest), SVM(Support Vector Machine), Machine&Deep Learning 방법을 활용해볼 수 있습니다. 이 방법들은 장점도 있는 반면, 정상/비정상 거래 데이터의 불균형, 데이터 전처리에서 사용되는 차원 축소의 효율성 문제, 실시간 탐지 특성을 유지하기 위한 컴퓨팅 파워 문제 등이 존재합니다.

대표적으로 캐글의 IEEE-CIS Fraud Detection 대회를 통해 이를 체험해 볼 수 있으며, Auto-Encoder나 LGBM과 같은 부스팅 계열 모델이 상위권을 차지하고 있는 것을 알 수 있습니다.

 

3. 이탈 고객 예측

1번에서 상품 추천 시스템을 매우 잘만들어 고객이 '이탈'이라는 생각을 하지 못하게 만들수도 있지만, 고객은 언제 변심할지 모릅니다.

이를 미연에 방지하고자 이탈 고객을 미리 예측하고, 이들에게 더욱 맞춤화된 서비스를 추천하고자하는 측면에서 기술을 적용할 수 있습니다.
- 기존 고객에게 A 제품을 마케팅할 때, 예측 모델을 통해 찾아낸 이탈 고객에게는 A 제품과 고객 특성을 파악해 얻어낸 B 제품을 동시에 추천!

고객 이탈을 예측하기 위해서는 고객의 행동적/통계적 특성을 동시에 활용해야 합니다. 물론 활용을 위해선 적재된 다양한 고객 데이터가 있어야 하는데, 이러한 점에서 금융업계는 금상첨화입니다.

기존의 Regression, Naive Bayes, Clustering, Boosting 모델과 자주 사용된 Random Forest 방법은 물론, 특성에 따라 CNN, RNN, LSTM, Auto-Encoder에서 GNN(Graph Neural Network)까지를 고려해볼 수 있습니다. 또한, Attention 모델을 사용해서 고객이 왜 이탈했는지 해석하려고 노력한 논문도 보였네요. 

 

4. 고객 서비스

고객이 서비스를 사용하다가 (간단한) 문제에 부딪혔습니다. 해결 방법을 물어보기 위해 상담원과 통화를 원하지만 상담 고객이 밀려 있어 5분, 10분, 15분, ... 하염없이 기다리다보면 회사의 서비스에 대한 고객의 불평은 커지기 마련입니다. 상담원, 마케터는 더 많은 고객의 궁금증을 내일로 미루지 않기를 원하지만, 반복적인 단순 질문으로 인해 처리가 지연될 뿐만 아니라 일의 효율성이 매우 떨어진다는 것을 자주 느낍니다.

고객 서비스를 위해 모든 금융업계가 챗봇 시스템 도입을 수행하고 있는 것은 이제금 자명한 사실이 되었습니다. 챗봇 시스템은 위의 문제를 해결해줄 수 있는 기술이자 고객에게 최고의 서비스를 제공할 수 있습니다. 챗봇은 유행성 기술이기도 하기 때문에 고객들이 필요한 정보와 얼마나 알맞는 정보를 제공할 수 있는지는 의문이라는 걱정어린 말도 엿들을 수 있습니다. 이에 대한 시나리오나 설계는 아직 모두 사람이 하고 있기 때문입니다.

아직 완벽하진 않지만, 이를 해결하기 위해 챗봇에도 추천, 랭킹 기술을 도입하는 방법이 상당 부분 고려되고 있습니다. 상담원에게 고객 대응을 위한 문장을 추천한 후, 상담원은 고객이 원하는 답변을 알맞게 변형하여 빠르게 답변할 수 있습니다.

고객 서비스에 정확한 대응을 하기 위해서는 통계적 특성과 상담 내용(음성 또는 텍스트) 등 다양한 데이터를 모델링에 사용할 수 있습니다. 또, 상담 내용 데이터는 챗봇 성능 고도화에 사용될 뿐만 아니라 추가적으로 분석해서 고객 성향과 향후 추천해주면 좋을 법한 제품까지 예측하도록 도와줄 수 있는 고급 데이터입니다.

딥러닝을 활용하여 다음과 같은 서비스를 제공할 수 있습니다.

  • 자연어 처리/생성에 사용되는 모델을 활용하여 고객의 특정 니즈를 파악하고, 감정을 분석하여 그에 알맞는 대응과 서비스를 제공할 수 있음
  • 24시간 항시 이용할 수 있는 AI 서비스

이 또한, 계속 생성되는 데이터를 실시간으로 학습하여 고객에게 더움 맞춤화된 해결 방법을 제공할 수 있기 때문에 고객 데이터의 확보가 매우 중요한 분야입니다.


사실 서비스 측면에서 파악하여 글을 작성하기로 한 것은 아니고, 세부적인 기술을 보고 싶었는데...

금융업 특성상 기술 공개가 그렇게 활발하지 않은 점과 동시에 많은 연구 논문들이 거의 비슷한 방법으로 method를 제안하고 있어 전혀 다른 결과의 글이 나온 점이 아쉽지만, 나름대로의 생각을 정리한 글입니다.

이번 글을 통해 어느 정도의 카테고리를 파악했으니, 다음 글은 데이터 처리나 모델링을 세부적으로 다뤄볼 수 있도록 노력을....

Youtube, NexFlix, Amazon 등 다양한 글로벌 및 국내 기업에서 추천 시스템은 매출 향상에 핵심적인 시스템이라고 표현해도 과언은 아닙니다. 또, 카카오, 네이버 등 음악이나 상품 서비스를 제공하고 있는 기업은 지금은 당연스럽게 사용하고 있는 기술이기 때문에 필수적으로 알아두면 좋습니다.

그뿐만 아니라 추천 시스템을 구성함에 있어서 최근 동향은 전통적인 통계 방법도 사용되지만 딥러닝 모델을 활용한 추천 시스템이 굉장히 많이 사용되고 있고, 전환되고 있는 것 같습니다.

이번 글에서도 간략하게 언급하겠지만, 모델 구조라던가 상세한 내용에 관해서는 아래 리뷰 논문을 자세히 살펴보는 것을 강력히 추천드리고, reference를 쫓아쫓아 공부하다 보면 2019년까지의 추천시스템 동향은 전부...

Are We Really Making Much Progress? A Worrying Analysis of Recent Neural Recommendation Approaches, RecSys 19


기본적으로 기존에 사용되던 추천 시스템은 협업 필터링과 콘텐츠 기반 필터링으로 나눌 수 있습니다.

 >> 협업 필터링(Collaborative Filtering, CF)

협업 필터링은 집단지성을 적극 활용한 기술입니다. 즉, 사용자의 행태를 분석하고 이와 유사한 행태를 가진 사용자에게 같은 제품을 추천하는 방식입니다. 이를 사용자 기반 협업 필터링(User-based Collaborative Filtering)라고 할 수 있습니다.
추가로 여기서 말하는 필터링(FIltering)이란, 여러 가지 항목 중 적당한 항목을 선택하는 것을 의미하는 용어입니다.

대표적으로 행렬 분해(Matrix Factorization), k-NN 등 방법이 사용됩니다.

하지만 협업 필터링에는 크게 세 가지 단점이 있습니다.

  1. 콜드 스타트(Cold Start)
    - 기존 데이터에 완전히 포함되지 않는 새로운 유형의 데이터를 만났을 때입니다. 당연히 협업 필터링은 기존 데이터를 기반으로 추천을 수행하기 때문에 큰 문제에 해당합니다.
  2. 계산 효율성
    - 기존 딥러닝에서 성능과 속도의 Trade-off 관계를 떠올리면 쉽게 이해할 수 있습니다. 기존 데이터를 많이 활용할 수록 정확한 추천을 수행할 수 있지만, 계산 측면에서 비효율적입니다.
  3. 극소수 데이터를 무시
    - 정규 분포를 떠올리면 쉽습니다. 사용자들이 유명한 제품을 주로 구매하는 것은 자명한 사실이죠. 기존 데이터가 쏠려있음으로서 소수 사용자들에게 선택받은 제품이 다른 사용자에게 추천되지 못하는 상황을 만듭니다.

 >> 콘텐츠 기반 협업 필터링(Content-based Collaborative Filtering)

콘텐츠 기반 협업 필터링은 아이템 기반 협업 필터링(Item-based Collaborative Filtering)이라고 표현하기도 하며, 협업 필터링처럼 사용자가 제품을 구매하면서 남기는 행태나 기록을 데이터로 사용하지 않고, 사용자가 선택한 항목을 분석하여 이와 유사한 항목을 추천해주는 방법입니다.

  • 음악을 분석하는 경우에는 장르, 비트, 음색 등 다양한 특징을 추출하여 이를 분석하고 유사한 형태의 곡을 사용자에게 추천해주는 것이죠.

대표적으로 딥러닝을 활용한 방법, 자연어 처리에 사용되는 latent vector 방법, tf-idf 등이 사용됩니다.

콘텐츠 기반 필터링 방법은 항목 자체를 분석하기 때문에 신규 고객에게도 유사한 항목을 추천해줄 수 있어 콜드 스타트를 해결할 수 있다는 장점이 존재합니다. 하지만 데이터 특성을 구성하는 과정이 조금 어렵다는 단점도 존재합니다.

  • 예를 들어, table data와 image data 특성을 어떤 형태로 concat해서 모델에 입력시킬 것인지 등.

위에서 살펴본 기존 두 가지 방법은 현재도 (변형해서)사용되고 있는 꽤나 훌륭한 방법입니다. 하지만 단점도 존재하기에 장점만 혼합한 방법을 사용하면 더 좋지 않을까 싶습니다.

 >> 하이브리드 협업 필터링(Hybrid Collaborative Filtering)

하이브리드 협업 필터링은 간단하게 협업 필터링과 콘텐츠 기반 필터링을 함께 사용하는 겁니다. 새로운 데이터가 들어왔을때 콜드 스타트 문제를 해결하기 위해 콘텐츠 기반 협업 필터링을 사용하다가 새로운 유형의 데이터가 시간이 지남에 따라 쌓인 후에 사용자 기반 협업 필터링으로 전환하는 방법입니다.

 

Reference

www.kocca.kr/insight/vol05/vol05_04.pdf

 

예전에 Pytorch의 Image augmentation 방법을 보고 커스텀이 되게 편리하게 구성된 것 같아 TensorFlow도 이와 같은 방법으로 augmentation하도록 만들어줬으면 좋겠다는 생각을 하고 있었는데, 연동 가능한 라이브러리 albumentation이 있었습니다.
(만들어진지 좀 됬는데 늦게 알게 됨..)

transforms.Compose([
	transforms.CenterCrop(10),
	transforms.ToTensor(),
])

torchvision의 augmentation 방법

사실 아래 공식 홈페이지 튜토리얼 코드를 보면 TensorFlow도 이와 같은 방법으로 Keras Layer를 활용한 augmentation이 가능토록 제공하고 있고, 앞으로도 이러한 방법으로 제공할 예정인가 싶습니다.

data_augmentation = tf.keras.Sequential([
  layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
  layers.experimental.preprocessing.RandomRotation(0.2),
])

출처: www.tensorflow.org/tutorials/images/data_augmentation?hl=ko


tf.image를 사용하는 방법

albumentation 라이브러리를 사용해보기 전에, tf.image를 사용해서 어떻게 augmentation 할 수 있는지 코드를 첨부합니다.

test = tf.data.Dataset.from_tensor_slices(dict(df))

# 이미지와 레이블을 얻습니다.
def get_image_label(dt):
    img_path = dt['image']
    
    image = tf.io.read_file(img_path)
    image = tf.image.decode_jpeg(image)
    image = tf.image.convert_image_dtype(image, tf.float32)
    image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])
    image = (image / 255.0)

    label = []
    
    for key in class_col:
        label.append(dt[key])
    
    return image, label

# data augment
# refer: https://www.tensorflow.org/tutorials/images/data_augmentation
def augment(image,label):
    # Add 6 pixels of padding
    image = tf.image.resize_with_crop_or_pad(image, IMG_SIZE + 6, IMG_SIZE + 6) 
    # Random crop back to the original size
    image = tf.image.random_crop(image, size=[IMG_SIZE, IMG_SIZE, 3])
    image = tf.image.random_brightness(image, max_delta=0.5) # Random brightness
    image = tf.clip_by_value(image, 0, 1)

    return image, label

    
dataset = test.map(get_image_label)
dataset = dataset.shuffle(50).map(augment).batch(4)

이 방법도 괜찮긴하지만 문제는 tf.Dataset 작동 구조를 알아야 정확히 쓸 수 있습니다.
map 함수 작동 방식이라던가, shuffle과 batch의 위치 등등..

확실히 위 방법보다 augmentation 방법을 Layer 구조로 가져가는게 훨씬 가독성이 좋아보이기도 합니다. 아래처럼요.

model = tf.keras.Sequential([
  resize_and_rescale,
  data_augmentation,
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  # Rest of your model
])

resize_and_rescale과 data_augmentation을 Sequential 안에 Layer 형태로 사용하고 있습니다.

하지만 아직 많이 쓰이고 있는 방법은 아닌 것 같기에 확실하게 자리잡기 전(?)까지 다른 방법을 사용해도 꽤나 무방합니다.

 

Albumentation 라이브러리를 사용하는 방법

사용하는 방법은 꽤나 단순합니다. 위에서 예제로 보여드렸던 코드와 형식이 동일하니까요.

먼저, 필요 라이브러리를 불러옵니다.

from tensorflow.keras.datasets import cifar10

import albumentations
import cv2
import numpy as np
import matplotlib.pyplot as plt
import cv2
# augmentation method를 import합니다.
from albumentations import (
    Compose, HorizontalFlip, CLAHE, HueSaturationValue,
    RandomBrightness, RandomContrast, RandomGamma,
    ToFloat, ShiftScaleRotate
)

torchvision의 Compose, TensorFlow의 Sequential과 Albumentation의 Compose의 사용되는 장소가 같습니다. 위에서 호출한 함수 외에도 다양한 augmentation 방법을 제공합니다. 더 궁금하면 공식 문서를 참조하고, 자세히 설명되어 있습니다.

albumentations.ai/docs/getting_started/image_augmentation/

이제 다양한 함수를 Compose안에 list 형태로 제공하고, 사용할 준비를 끝마칩니다.

# 각 함수에 대한 설명은
# https://albumentations.ai/docs/
# document를 참고하세요.
Aug_train = Compose([
    HorizontalFlip(p=0.5),
    RandomContrast(limit=0.2, p=0.5),
    RandomGamma(gamma_limit=(80, 120), p=0.5),
    RandomBrightness(limit=0.2, p=0.5),
    HueSaturationValue(hue_shift_limit=5, sat_shift_limit=20,
                       val_shift_limit=10, p=.9),
    ShiftScaleRotate(
        shift_limit=0.0625, scale_limit=0.1, 
        rotate_limit=15, border_mode=cv2.BORDER_REFLECT_101, p=0.8), 
    ToFloat(max_value=255)
])

Aug_test = Compose([
    ToFloat(max_value=255)
])

 

실험하기에 가장 좋은 예제는 tensorflow.keras.datasets에서 제공하는 CIFAR-10입니다.
또, Sequence 클래스를 상속받아 제네레이터처럼 활용할 수 있도록 합니다.
아래 코드 __getitem__ 부분의 self.augment(image=x)["image"]에서 변환 작업이 수행됩니다.

from tensorflow.python.keras.utils.data_utils import Sequence

# Sequence 클래스를 상속받아 generator 형태로 사용합니다.
class CIFAR10Dataset(Sequence):
    def __init__(self, x_set, y_set, batch_size, augmentations):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size
        self.augment = augmentations

    def __len__(self):
        return int(np.ceil(len(self.x) / float(self.batch_size)))

    # 지정 배치 크기만큼 데이터를 로드합니다.
    def __getitem__(self, idx):
        batch_x = self.x[idx * self.batch_size:(idx + 1) * self.batch_size]
        batch_y = self.y[idx * self.batch_size:(idx + 1) * self.batch_size]
        
        # augmentation을 적용해서 numpy array에 stack합니다.
        return np.stack([
            self.augment(image=x)["image"] for x in batch_x
        ], axis=0), np.array(batch_y)

# CIFAR-10 Dataset을 불러옵니다.
(x_train, y_train), (x_test, y_test) = cifar10.load_data()

BATCH_SIZE = 8

# Dataset을 생성합니다.
train_gen = CIFAR10Dataset(x_train, y_train, BATCH_SIZE, Aug_train)
test_gen = CIFAR10Dataset(x_test, y_test, BATCH_SIZE, Aug_test)

train_gen을 통해 이미지를 그려보면 다음과 같이 변환이 일어난 것을 볼 수 있습니다.

# 데이터를 그려봅시다.
images, labels = next(iter(train_gen))

fig = plt.figure()

for i, (image, label) in enumerate(zip(images, labels)):
    ax = fig.add_subplot(3, 3, i + 1)
    ax.imshow(image)
    ax.set_xlabel(label)
    ax.set_xticks([]); ax.set_yticks([])

plt.tight_layout()
plt.show()

Augmentation이 수행된 이미지

 

Reference

텐서플로우 공식 홈페이지

Albumentation Document

medium.com/the-artificial-impostor/custom-image-augmentation-with-keras-70595b01aeac

이 글은 keras 공식 문서의 'Few-Shot learning with Reptile' 글을 번역한 것입니다.


Introduction

Reptile 알고리즘은 Meta-Learning을 위해 open-AI가 개발한 알고리즘입니다. 특히, 이 알고리즘은 최소한의 training으로 새로운 task를 수행하기 위한 학습을 빠르게 진행하기 위해 고안되었습니다(Few-Shot learning). Few-shot learning의 목적은 소수의 데이터만 학습한 모델이 보지 못한 새로운 데이터를 접했을 때, 이를 분류하게 하는 것입니다. 예를 들어, 희귀병 진단이나 레이블 cost가 높은 경우에 유용한 방법이라고 할 수 있습니다. 즉, 해결해야 될 문제에서 데이터가 적을때 충분히 고려해볼만한 방법입니다.

알고리즘은 이전에 보지 못한 데이터의 mini-batch로 학습된 가중치와 고정된 meta-iteration을 통해 사전 학습된 모델 가중치 사이의 차이를 최적화하는 SGD와 함께 작동합니다. 즉, n번 만큼의 횟수에서 mini-batch로 학습하여 얻은 가중치와 모델 weight initialization 차이를 최소하하면서 optimal weight를 update하게 됩니다.
(동일 클래스 이미지에 계속해서 다른 레이블로 학습하는데 어떻게 정답을 맞추는지 정말 신기합니다. 이 부분을 알려면 더 깊게 공부해봐야 알듯...)

필요 라이브러리를 임포트합니다.

import matplotlib.pyplot as plt
import numpy as np
import random
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import tensorflow_datasets as tfds

하이퍼파라미터 정의

learning_rate = 0.003 # 학습률
meta_step_size = 0.25 # 메타 스템 크기

inner_batch_size = 25 # 학습 배치 크기
eval_batch_size = 25 # 테스트 배치 크기

meta_iters = 2000 # 학습 총 횟수
eval_iters = 5 # 평가 데이터셋 반복 횟수
inner_iters = 4 # 학습 데이터셋 반복 횟수

eval_interval = 1 # 평가 기간 설정
train_shots = 20 # 학습에서 각 클래스마다 몇 개 샘플을 가져올지
shots = 5 # 평가에서 각 클래스마다 몇 개 샘플을 가져올지
classes = 5 # 몇 개 클래스를 사용할지

여기서는 5-way 5-shot이라고 표현할 수 있겠네요(N-way, k-shot)
--> 5개 클래스에서 5장 뽑아서 이를 학습에 사용하겠다는 의미

 

데이터 준비

Omniglot 데이터셋은 각 character별로 20개 샘플을 가지고 있는 50가지 알파벳(즉, 50개의 다른 언어)으로부터 얻어진 1,623개 데이터로 이루어져 있습니다(서로 다른 나라의 문자에서 특정 클래스들을 모아둔 데이터셋입니다). 여기서 20개 샘플은 Amazon's Mechanical Turk으로 그려졌습니다.

few-shot learning task를 수행하기 위해 k개 샘플은 무작위로 선택된 n개 클래스로부터 그려진 것을 사용합니다. n개 숫자값은 몇 가지 예에서 새 작업을 학습하는 모델 능력을 테스트하는 데 사용할 임시 레이블 집합을 만드는 데 사용됩니다. 예를 들어, 5개 클래스를 사용한다고 하면, 새로운 클래스 레이블은 0, 1, 2, 3, 4가 될 것입니다.

핵심은 모델이 계속 반복해서 class instance를 보게 되지만, 해당 instance에 대해서는 계속해서 서로 다른 레이블을 보게 됩니다. 이러한 과정에서 모델은 단순하게 클래스를 분류하는 방법이 아니라 해당 데이터를 특정 클래스로 구별하는 방법을 배워야 합니다.

Omniglot 데이터셋은 다양한 클래스에서 만족할만한 개수의 샘플을 가져다 사용할 수 있기 때문에 이번 task에 적합합니다.

class Dataset:
    # 이 클래스는 few-shot dataset을 만듭니다.
    # 새로운 레이블을 만듬과 동시에 Omniglot 데이터셋에서 샘플을 뽑습니다.
    def __init__(self, training):
        # omniglot data를 포함한 tfrecord file을 다운로드하고 dataset으로 변환합니다.
        split = "train" if training else "test"
        ds = tfds.load("omniglot", split=split, as_supervised=True, shuffle_files=False)
        # dataset을 순환하면서 이미지와 클래스를 data dictionary에 담을겁니다.
        self.data = {}

        def extraction(image, label):
            # RGB에서 grayscale로 변환하고, resize를 수행합니다.
            image = tf.image.convert_image_dtype(image, tf.float32)
            image = tf.image.rgb_to_grayscale(image)
            image = tf.image.resize(image, [28, 28])
            return image, label

        for image, label in ds.map(extraction):
            image = image.numpy()
            label = str(label.numpy())
            # 레이블이 존재하지 않으면 data dictionary에 넣고,
            if label not in self.data:
                self.data[label] = []
            # 존재하면 해당 레이블에 붙여줍니다.
            self.data[label].append(image)
            # 레이블을 저장합니다.
            self.labels = list(self.data.keys())

    def get_mini_dataset(self, batch_size, repetitions, shots, num_classes, split=False):
        # num_classes * shots 수 만큼 이미지와 레이블을 가져올 것입니다.
        temp_labels = np.zeros(shape=(num_classes * shots))
        temp_images = np.zeros(shape=(num_classes * shots, 28, 28, 1))
        if split:
            test_labels = np.zeros(shape=(num_classes))
            test_images = np.zeros(shape=(num_classes, 28, 28, 1))
          
        # 전체 레이블 셋에서 랜덤하게 몇 개의 레이블만 가져옵니다.
        # self.labels는 omniglot에서 가져온 데이터의 전체 레이블을 담고 있습니다.
        # 전체 레이블에서 num_classes만큼 label을 랜덤하게 뽑습니다.
        label_subset = random.choices(self.labels, k=num_classes)
        for class_idx, _ in enumerate(label_subset):
            # few-shot learning mini-batch를 위한 현재 레이블값으로 enumerate index를 사용합니다.
            # temp_label에서는 shots 수만큼 class_idx를 가지게 됩니다.[0, 0, 0, 0, 0]
            # 해당되는 이미지의 레이블은 계속해서 변하는 점을 참고
            temp_labels[class_idx * shots : (class_idx + 1) * shots] = class_idx

            # 테스트를 위한 데이터셋을 만든다면, 선택된 sample과 label을 넣어줍니다.
            # 테스트 과정에서 temp_label과 test_label은 동일해야 합니다.
            if split:
                test_labels[class_idx] = class_idx
                images_to_split = random.choices(self.data[label_subset[class_idx]], 
                                                 k=shots + 1)
                test_images[class_idx] = images_to_split[-1]
                temp_images[class_idx * shots : (class_idx + 1) * shots] = images_to_split[:-1]
            else:
                # label_subset[class_idx]에 해당하는 이미지를 shots만큼 temp_images에 담습니다.
                # 이로써 temp_images는 label_subset[class_idx] 레이블에 관한 이미지를 가지고 있지만,
                # temp_labels는 이에 상관없이 class_idx 클래스를 가집니다.
                temp_images[
                    class_idx * shots : (class_idx + 1) * shots
                ] = random.choices(self.data[label_subset[class_idx]], k=shots)

        # TensorFlow Dataset을 만듭니다.
        dataset = tf.data.Dataset.from_tensor_slices(
            (temp_images.astype(np.float32), temp_labels.astype(np.int32))
        )
        dataset = dataset.shuffle(100).batch(batch_size).repeat(repetitions)

        if split:
            return dataset, test_images, test_labels
            
        return dataset


import urllib3

urllib3.disable_warnings()  # Disable SSL warnings that may happen during download.
train_dataset = Dataset(training=True)
test_dataset = Dataset(training=False)

 

모델 구성

def conv_bn(x):
    x = layers.Conv2D(filters=64, kernel_size=3, strides=2, padding="same")(x)
    x = layers.BatchNormalization()(x)
    return layers.ReLU()(x)


inputs = layers.Input(shape=(28, 28, 1))
x = conv_bn(inputs)
x = conv_bn(x)
x = conv_bn(x)
x = conv_bn(x)
x = layers.Flatten()(x)
outputs = layers.Dense(classes, activation="softmax")(x)

model = keras.Model(inputs=inputs, outputs=outputs)
model.compile()
optimizer = keras.optimizers.SGD(learning_rate=learning_rate)

 

모델 학습

training = []
testing = []
for meta_iter in range(meta_iters):
    frac_done = meta_iter / meta_iters
    cur_meta_step_size = (1 - frac_done) * meta_step_size
    # 현재 모델 weights를 저장합니다.
    old_vars = model.get_weights()
    # 전체 데이터셋에서 샘플을 가져옵니다.
    mini_dataset = train_dataset.get_mini_dataset(
        inner_batch_size, inner_iters, train_shots, classes
    )

    for images, labels in mini_dataset:
        with tf.GradientTape() as tape:
            preds = model(images)
            loss = keras.losses.sparse_categorical_crossentropy(labels, preds)

        grads = tape.gradient(loss, model.trainable_weights)
        optimizer.apply_gradients(zip(grads, model.trainable_weights))

    # 위의 loss로 업데이트된 weight를 가져옵니다.
    new_vars = model.get_weights()
    # meta step with SGD
    for var in range(len(new_vars)):
        new_vars[var] = old_vars[var] + (
            (new_vars[var] - old_vars[var]) * cur_meta_step_size
        )

    # meta-learning 단계를 수행했다면, 모델 가중치를 다시 업데이트해줍니다.
    model.set_weights(new_vars)

    # Evaluation loop
    if meta_iter % eval_interval == 0:
        accuracies = []
        for dataset in (train_dataset, test_dataset):
            # 전체 데이터셋에서 mini dataset을 가져옵니다.
            train_set, test_images, test_labels = dataset.get_mini_dataset(
                eval_batch_size, eval_iters, shots, classes, split=True
            )
            old_vars = model.get_weights()
            # Train on the samples and get the resulting accuracies.
            for images, labels in train_set:
                with tf.GradientTape() as tape:
                    preds = model(images)
                    loss = keras.losses.sparse_categorical_crossentropy(labels, preds)

                grads = tape.gradient(loss, model.trainable_weights)
                optimizer.apply_gradients(zip(grads, model.trainable_weights))
            
            test_preds = model.predict(test_images)
            test_preds = tf.argmax(test_preds).numpy()
            num_correct = (test_preds == test_labels).sum()

            # 평가 acc를 얻었다면 다시 weight를 초기화해야합니다.
            model.set_weights(old_vars)
            accuracies.append(num_correct / classes)

        training.append(accuracies[0])
        testing.append(accuracies[1])

        if meta_iter % 100 == 0:
            print(
                "batch %d: train=%f test=%f" % (meta_iter, accuracies[0], accuracies[1])
            )

 

결과 시각화

# First, some preprocessing to smooth the training and testing arrays for display.
window_length = 100
train_s = np.r_[
    training[window_length - 1 : 0 : -1], training, training[-1:-window_length:-1]
]
test_s = np.r_[
    testing[window_length - 1 : 0 : -1], testing, testing[-1:-window_length:-1]
]
w = np.hamming(window_length)
train_y = np.convolve(w / w.sum(), train_s, mode="valid")
test_y = np.convolve(w / w.sum(), test_s, mode="valid")

# 학습 acc를 그립니다.
x = np.arange(0, len(test_y), 1)
plt.plot(x, test_y, x, train_y)
plt.legend(["test", "train"])
plt.grid()

train_set, test_images, test_labels = dataset.get_mini_dataset(
    eval_batch_size, eval_iters, shots, classes, split=True
)

for images, labels in train_set:
    with tf.GradientTape() as tape:
        preds = model(images)
        loss = keras.losses.sparse_categorical_crossentropy(labels, preds)

    grads = tape.gradient(loss, model.trainable_weights)
    optimizer.apply_gradients(zip(grads, model.trainable_weights))

test_preds = model.predict(test_images)
test_preds = tf.argmax(test_preds).numpy()

_, axarr = plt.subplots(nrows=1, ncols=5, figsize=(20, 20))

for i, ax in zip(range(5), axarr):
    temp_image = np.stack((test_images[i, :, :, 0],) * 3, axis=2)
    temp_image *= 255
    temp_image = np.clip(temp_image, 0, 255).astype("uint8")
    ax.set_title(
        "Label : {}, Prediction : {}".format(int(test_labels[i]), test_preds[i])
    )
    ax.imshow(temp_image, cmap="gray")
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
plt.show()

 

Reference

Few-shot learning은 카카오 기술 블로그에도 설명되어 있습니다. >> 클릭

talkingaboutme.tistory.com/entry/DL-Meta-Learning-Learning-to-Learn-Fast

www.borealisai.com/en/blog/tutorial-2-few-shot-learning-and-meta-learning-i/

'# Machine Learning > TensorFlow doc 정리' 카테고리의 다른 글

tf.data tutorial 번역 (5)  (0) 2020.02.28
tf.data tutorial 번역 (4)  (1) 2020.02.27
tf.data tutorial 번역 (3)  (0) 2020.02.26
tf.data tutorial 번역 (2)  (0) 2020.02.18
tf.data tutorial 번역 (1)  (0) 2020.02.14

다양한 문제를 해결하고, 만들어내고 있는 GPT-3가 연일 화제가 되면서 인공지능 관련 모든 분야에서 굉장히 뜨거운 반응을 보이고 있습니다. NLP뿐만 아니라 Computer Vision task도 해결할 수 있음을 보였는데, 이러한 결과가 매우 매력적일 수밖에 없습니다. 물론 사용된 파라미터 수, 학습 시간 등을 고려해보면 개인적으로 어떻게 활용할 수 있을까에 대한 좌절감도 동시에 다가옵니다.

트렌드를 빠른 속도로 파악하고 제시하고 있는 Andrew Ng님도 Transformer, BERT, GPT-3가 매우 대단한 결과를 보이고 있음을 이야기하고, NLP 분야의 수요가 지속적으로 늘어날 것을 이야기할 정도입니다.

BERT에 관심이 있는, NLP에 관심이 있다면 반드시 밑의 세 가지 논문을 요약으로라도 읽어봐야 합니다.

이 중에서도 이번 글에서는 BERT를 직접 공부하면서 도움이 될만한 몇 가지 사항을 정리하였습니다. 이전에 연관 논문을 읽고 BERT라는 주제를 공부하면 매우 도움이 되겠지만, 순서가 뒤바뀌어도 문제 될게 없습니다.


BERT

Transformer architecture을 중점적으로 사용한 BERT는 Bidirectional Encoder Representations from Transformers을 의미합니다. 바로 BERT에서 살펴볼 주요한 사항을 살펴보겠습니다.

들어가기 전에, BERT는 text classification, answering 등을 해결할 수 있는 모델이지만, 이보다는 Language Representation을 해결하기 위해 고안된 구조라는 것을 알아주세요.
(즉, 단어, 문장, 언어를 어떻게 표현할까에 관한 고민이고, 이를 잘 표현할 수 있다면 다양한 task를 해결할 수 있습니다.)

 

BERT는 양방향성을 포함하여 문맥을 더욱 자연스럽게 파악할 수 있습니다.

Bidirectional은 직역하는 것과 동일하게 BERT 모델이 양방향성 특성을 가지고 이를 적용할 수 있다는 것을 의미합니다.
이를 사용하기 이전의 대부분 모델은 문장이 존재하면 왼쪽에서 오른쪽으로 진행하여 문맥(context)를 파악하는 방법을 지녔는데요. 이는 전체 문장을 파악하는 데 있어서 당연히 제한될 수 밖에 없는 한계점입니다.

쉽게 생각해보면, '나는 하늘이 예쁘다고 생각한다'라는 문장을 이해할 때, 단순히 '하늘'이라는 명사를 정해놓고 '예쁘다'라는 표현을 사용하지는 않습니다. '예쁘다'를 표현하고 싶어서 '하늘'이라는 명사를 선택했을 수도 있습니다. 즉, 앞에서 뒤를 볼수도 있지만, 뒤에서 앞을 보는 경우도 충분히 이해할 수 있어야 전체 맥락을 완전히 파악할 수 있다는 것이죠.

단방향성, 양방향성

이 예가 아니더라도 동의어를 파악하기 위해선 앞뒤 단어의 관계성을 파악해야 한다는 점을 이해할 수 있습니다.

-> 긍정적인 의미의 잘했다와 부정적인 의미의 잘했다.
ex1) A: "나 오늘 주식 올랐어!", B: "진짜 잘했다"
ex2) A: "나 오늘 주식으로 망했어", B: "진짜 잘~했다"

결론적으로는 기존 단방향성 모델은 성능 향상, 문맥 파악에 한계점이 존재했었고, 이를 해결하기 위해 양방향성을 띄는 모델을 제안하는 방향으로 진행된 것입니다. (RNN과 Bidirectional RNN의 차이점을 살펴도 같은 문제를 해결하기 위한 것을 알 수 있습니다)

 

BERT는 pre-training이 가능한 모델입니다.

이전에 존재하던 NLP 모델은 pre-training이 어려웠기 때문에 특정 task가 존재할 경우 처음부터 학습시켜야 하는 단점이 존재했습니다. 각종 Image task를 해결하는 데 있어서도 pre-trianing이 매우 큰 역할을 하고 있다는 점을 보면, NLP에서도 여러 task에 transfer하기 위해서는 이를 활용할 수 있는 모델이 매우 시급했습니다.

이에 대한 연구가 매우 활발히 진행되었고, 대표적으로 ELMO, XLNet, BERT, GPT 등 모델이 만들어지게 되었죠.

엄청난 수의 Wikipedia와 BooksCorpus 단어를 학습한 BERT를 다양한 task에 적용하고, fine-tuning해서 사용할 수 있는 것은 매우 큰 장점으로 우리에게 다가올 수 밖에 없습니다.

 

BERT는 주로 어떤 문제에 적용할 수 있을까요?

대표적으로 해결할 수 있는 몇 가지 문제를 알려드리겠습니다. 하지만 여기서 설명되지 않은 다양한 분야가 매우 다양하게 존재하다는 것을 잊어버리면 안됩니다. 아래 문제들은 대부분 NLP task에서 볼 수 있는 대표적인 문제들입니다.

  1. Question and Answering
    - 주어진 질문에 적합하게 대답해야하는 매우 대표적인 문제입니다.
    - KoSQuAD, Visual QA etc.
  2. Machine Translation
    - 구글 번역기, 네이버 파파고입니다.
  3. 문장 주제 찾기 또는 분류하기
    - 역시나 기존 NLP에서도 해결할 수 있는 문제는 당연히 해결할 수 있습니다.
  4. 사람처럼 대화하기
    - 이와 같은 주제에선 매우 강력함을 보여줍니다.
  5. 이외에도 직접 정의한 다양한 문제에도 적용 가능합니다. 물론 꼭 NLP task일 필요는 없습니다.

 

어떻게 학습되었는지 알아보자

기본적으로 BERT는 'Attention is all you need" 논문에서 볼 수 있는 Transformer 구조를 중점적으로 사용한 구조입니다. 특히
self-attiotion layer를 여러 개 사용하여 문장에 포함되어 있는 token 사이의 의미 관계를 잘 추출할 수 있습니다.

BERT는 transformer 구조를 사용하면서도 encoder 부분만 사용(아래 그림에서 왼쪽 부분)하여 학습을 진행했는데요. 기존 모델은 대부분 encoder-decoder으로 이루어져 있으며, GPT 또한, decoder 부분을 사용하여 text generation 문제를 해결하는 모델입니다. Transformer 구조 역시, input에서 text의 표현을 학습하고, decoder에서 우리가 원하는 task의 결과물을 만드는 방식으로 학습이 진행됩니다.

Attention mechanism - Attention Paper

BERT는 decoder를 사용하지 않고, 두 가지 대표적인 학습 방법으로 encoder를 학습시킨 후에 특정 task의 fine-tuning을 활용하여 결과물을 얻는 방법으로 사용됩니다.

 

어떻게 학습되었는지 알아보자 - input Representation

역시나 어떤 주제이던 데이터 처리에 관한 이야기는 빠질 수가 없습니다. BERT는 학습을 위해 기존 transformer의 input 구조를 사용하면서도 추가로 변형하여 사용합니다. Tokenization은 WorldPiece 방법을 사용하고 있습니다.

Input Representation - BERT paper

위 그림처럼 세 가지 임베딩(Token, Segment, Position)을 사용해서 문장을 표현합니다.

먼저 Token Embedding에서는 두 가지 특수 토큰(CLS, SEP)을 사용하여 문장을 구별하게 되는데요. Special Classification token(CLS)은 모든 문장의 가장 첫 번째(문장의 시작) 토큰으로 삽입됩니다. 이 토큰은 Classification task에서는 사용되지만, 그렇지 않을 경우엔 무시됩니다. 
또, Special Separator token(SEP)을 사용하여 첫 번째 문장과 두 번째 문장을 구별합니다. 여기에 segment Embedding을 더해서 앞뒤 문장을 더욱 쉽게 구별할 수 있도록 도와줍니다. 이 토큰은 각 문장의 끝에 삽입됩니다.

Position Embedding은 transformer 구조에서도 사용된 방법으로 그림고 같이 각 토큰의 위치를 알려주는 임베딩입니다.
최종적으로 세 가지 임베딩을 더한 임베딩을 input으로 사용하게 됩니다.

 

어떻게 학습되었는지 알아보자 - Pre-training

 BERT는 문장 표현을 학습하기 위해 두 가지 unsupervised 방법을 사용합니다.

  1. Masked Language Model
  2. Next Sentence Model

 

Masked Language Model (MLM)

문장에서 단어 중의 일부를 [Mask] 토큰으로 바꾼 뒤, 가려진 단어를 예측하도록 학습합니다. 이 과정에서 BERT는 문맥을 파악하는 능력을 기르게 됩니다.

ex) 나는 하늘이 예쁘다고 생각한다 -> 나는 하늘이 [Mask] 생각한다.
ex) 나는 하늘이 예쁘다고 생각한다 -> 나는 하늘이 흐리다고 생각한다.
ex) 나는 하늘이 예쁘다고 생각한다 -> 나는 하늘이 예쁘다고 생각한다.

추가적으로 더욱 다양한 표현을 학습할 수 있도록 80%는 [Mask] 토큰으로 바꾸어 학습하지만, 나머지 10%는 token을 random word로 바꾸고, 마지막 10%는 원본 word 그대로를 사용하게 됩니다.

Next Sentence Prediction (NSP)

다음 문장이 올바른 문장인지 맞추는 문제입니다. 이 문제를 통해 두 문장 사이의 관계를 학습하게 됩니다. 

문장 A와 B를 이어 붙이는데, B는 50% 확률로 관련 있는 문장(IsNext label) 또는 관련 없는 문장(NotNext label)을 사용합니다.
QA(Question Answering)나 NLI(Natural Language Inference) task의 성능 향상에 영향을 끼친다고 합니다.

 

이런 방식으로 학습된 BERT를 fine-tuning할 때는 (Classification task라면)Image task에서의 fine-tuning과 비슷하게 class label 개수만큼의 output을 가지는 Dense Layer를 붙여서 사용합니다.

 

Reference