인공지능 서비스 만들기

1인 지식 기업을 꿈꾸는 30, 40대 직장인을 위한 실무 프로젝트
Deep Learning, NLP, Computer Vision, Tensorflow

[BERT] 개념 및 Chatbot 구현 세미나

NLP

인공지능 아카데미에서 인라이플 회사의 BERT 소개 및 챗봇 실습 세미나를 정리한다. 





임베딩


단어 기준 임베딩

  - Word2Vec: 비슷한 관계가 있는 단어들 끼리 벡터 공간을 값으로 갖는다. 

  - FastText: 학습속도를 빠르게 하기 위해 개선한다. 주변 단어의 벡터를 가지고 적용.


문장 기준 임베딩

  - CoVe (코브): 차가 car인지, tea인지 문맥을 통해 파악해야 한다. 

  - ELMo (엘모)




딥러닝 모델


자연어에 적용하는 기술. 문장에서 문장으로 적용

  - 딥러닝은 머신러닝을 기반으로 cell을 정의하고 => cell을 연결하여 다양한 신경망을 구성한다. => 통계처리함에 더 똑똑하다. (특정 패턴을 찾는 것임)

  - cell은 CNN, RNN, LSTM, GRU, DQN 등등.


  - CNN: 성능 떨어짐

     + 행렬 곱이여서 병렬처리가 가능한다.  

  - RNN: 회귀모델, 베이지안, CNN 

     + 순환신경망, 인풋/아웃풋/히든 을 활용하는 네트워크

     + 문장이 길때 문제 발생: 초기 입력값을 잃어버리는 문제 발생 => LSTM 적용하여 해결 (forgotten, use gate 사용-가중치주기), 역시 문제 남음

  - Seq2Seq: 문장에서 문장 분석하기 

     + 정확도 높이기 위해 Attention 사용: 인코더/디코더단의 연산결과를 attention에 저장하고 최종 결과 sequence를 만들어냄. 정보 소실을 줄이기 용도

     + Attention: 정보가 너무 많을 때 사람은 관심 있는 걸 찾는다. 즉, 딥러닝에게 관심 있는 정보를 찾는 능력을 부여함.

        질문(query)과 답(key)를 통해 관심 있는 것을 찾음

     + 병렬처리 가능


트랜스포머

  - RNN같은 시계열구조는 연산속도 느림 => Attention만 가지고 연산을 해보자

  - Positional Encoding을 넣어 같이 학습 (병렬처리를 위함) + Attention 사용

  - 더 긴 문장을 해석할 수 있게 되었다. 즉, 더 깊은 네트워크를 만들 수 있었다. => 빠른 학습 속도, 연산 속도를 나타냄.

  - BERT에서 사용함.




트랜스포머



2017년 구글이 개발한 self attention기반 인코더. 기존 seq2seq한계를 넘음. 

  - BERT는 positional encoding 사용하지 않음

 

셀프 어텐션 구조

  - 입력값은 같으나, 가중치로 Q,K,V를 구함

  - Q, K에서 어텐션 스코어를 구함. 이것을 V에 적용하여 Z를 구함

  - Q,K,V를 여러벌로 만들어 구함.

  - 마스크를 사용함

    + 인코더 마스크: 선택사항으로 값이 없는 값 => 버트에서 사용

    + 디코더 마스크: 다음 단어 예측을 위해 => 버트에서 사용안함


셀프 어텐션 효과

  - 단어간의 연관 관계 정보를 얻음

 

피드 포워드

  - 트랜스포머는 셀프 어텐션을 통해 나온 정보를 피드 포워드 네트워크르 통과시켜 정보를 정리한다. 


과적합 줄이(overfitting)기 방법

  - 드랍 아웃

    + 일부 노드연 연결을 임의로 삭제하는 것

  - 노말라이제시션

    + 값이 원하는 범위를 벗어나지 않토록 제한함

    + 배치 LN, 레이어 BN, 인스턴스 IN, 그룹 GN 노멀라이제이션등이 있다. 

    + BERT는 LN 사용한다. 


스킵 커넥션

  - 신경망도 깊이가 깊을 수록 이전것에 대한 기억을 잃어버린다. 이를 극복하기 위한 여러 방법이 있다. 

  - 기억 잃어버림(기울기 문제) => 스킵 커넥션으로 해결 노력


비선형성

  - ReLU는 시그모이드 보다 빠름 

  - ELU는(엘루) 경사 하강법에서 수렵 속도 빠름, 죽는 노드 없음

  - GELU는(겔루) 확률론적 개념을 도입하여 엘루 보다 계산 비용이 저렴하고 빠르게 수렴 => 성능 좋음




BERT


트랜스포머로 구성된 양방향 언어 표현. 자연어 처리 분야. 


접근법

  - 피처 기반 접근법: 미리 학습된 가중치의 단어별 특징을 뽑아 학습

  - 파인 튜닝 접근법: 미리 학습시킨 가중치를 불러와 미세조정(파인 튜닝)하여 사용하는 방식


구조

  - BASE: 트랜스포머 12개 

  - LARGE: 트랜스포머 24개


학습법

  - Masked 언어 모델: 양방향 맥락을 고려함, 무작위 마스킹, 파인튜닝시 마스킹안함 랜덤 사용. 

  - 다음 문장 예측: NLI, QA의 파인 튜닝을 위해 마스크된 단어를 맞추는 태스크. 50%연관된 문장들, 50% 연관안된 문장들을 찾음.


입력 데이터

  - 두개의 문장을 문장 구분자와 함께 합쳐 넣음

  - 트랜스포머 고려하여 두 문장 합쳐서 512단어 이하로 넣음

  - 워드 피스 토크나이저로 토큰된 단어를 넣음

    + 토큰 임베딩, 세그먼트 임베딩, 포지션 임베딩 합쳐 사용

    + 마지막은 패딩처리: 0000

  - https://googlebooks.byu.edu/ 8억단어, https://corpus.byu.... 25억 단어

  

파인 튜닝으로 이용하는 방법

  - 프리트레인된 가중치를 모델에 불러옴

  - 두 문장일때는 문장 구분자를 넣음 


피처 추출로 이용하는 방법

  - 문장을 넣어 단어별 가중치를 뽑아냄

  - 카카오에서 문장별 단어 벡터의 가중합의 거리를 계산하여 문장 유사도 시도 


장비

  - TPU 3.0 -> 16개 사용해서 4일 걸림 => 구글 클라우드에서 TPU v2, v3 사용가능 (1대 1시간당 $5 정도)

  - Tesla V100 -> 8개 42일 

  - RTX 2080 Ti -> 8개 68일, 64개 9일 가량 소요


한글 버트

  - 한글 버트 없음. 

  - 구글이 오픈소스로 제공하는 다국어 프리트레인 된 가중치는 베이스 모델임.

  - 한글은 프리트레인 -> 파인튠 -> 어브노멀리 해서 사용.




BERT를 위한 데이터 구성


3가지 셋을 가지고 모델을 만들어야 한다. 

  - 훈련셋: 모델 학습

  - 검증셋: 파라미터 튜닝 (1,000~10,000개)

  - 시험셋: 모델의 성능을 측정


데이터 구성 고려사항

  - 실 서비스는 검증셋, 시험셋을 동일하게 함

  - 0.01%라도 성능향상을 위해 검증셋은 10,000개 이상 구성

  - 가능하면 공인된 데이터(SQuad) 셋으로 모델을 구성한 후 그와 비슷한 데이터 구성 => 시간 낭비 줄여줌

  - 빠른 개발 사이클로 반복 검증한다. 원하는 경우 안나오면 데이터셋을 바꿔야 한다. 


데이터셋을 바꿔가며 학습 시키는 방법 종류

  - 교차 검증과 계층별 교차 검증

  - 임의 분할 교차 검증

  - 그룹 교차 검증


데이터 평가

  - 문제에 맞는 평가 지표를 선택한다. 즉, 문제에 맞는 평가지표가 필요

  - 에러분석 과정을 자동화 하면 좋다. 

   + 에러가 나면 수작업으로 데이터 분류하여 다시 데이터셋 만듦

   + 에러 분석하고 에러 제거 검증셋으로 검증의 반복


어떻게 개선할 것인가?

  - 서비스 진행하면서 데이터 셋을 추가로 반영한다.

  - 서비스 이점이 없는 데이터는(노이즈 데이터) 배제

  - 잘 못 분류된 레이블 개선




버트와 TF-IDF를 활용한 챗봇 실습


colab에서 실습함 

  - 하단 참조의 data.zip에서 train.json빼고 colab에서 파일 업로드함

  - 하단 참조의 ipynb 파일 import함


QA데이터셋을 사용 => QA 데이터: 6만건 - LG쪽에 문의

  - 사용자가 질문을 넣어서 TF-IDF에서 유사 문장을 찾아 줌. 

  - Standard Question And Answering 데이터셋: korquad dataset (http://korquad.github.io)


코드 설명

0) 준비작업

  colab에서 GPU 설정한다.


1) 문맥선택

  korquad에서 제공하는 질문/대답 데이터 셋에서 질문에 대한 문맥을 데이터세셍서 자동 선택하기.

  - TF-IDF 계산

  - 코사인 유사도를 통한 문맥 선택

[7.3.1]

if args.do_chat:

    logger.setLevel('CRITICAL')

    input_text = None

    qas_id = '56be4db0acb8001400a502ed'

    c = ContextFinder()

    c.build_model(args.predict_file)

    print('READY')


2) 데이터 전처리

  - SquadExample 객체 생성

  - 데이터 전처리 = 토큰화 + CSL / SEP + 마스크 제로패딩

  - FullTokenizer = BasicTokenizer + WordpieceTokenizer 

  - "CLS + 질문 + SEP + 문맥 + SEP" 구조를 만든다. 

  - max sequence length는 384, input sequence length 200

[7.3.2]

eval_examples = parse_input_examples(qas_id, context_text, question_text)

        eval_features = convert_examples_to_features(

            examples=eval_examples,

            tokenizer=tokenizer,

            max_seq_length=args.max_seq_length,

            doc_stride=args.doc_stride,

            max_query_length=args.max_query_length,

            is_training=False)


4) 버트모델

  - Colab의 4번 챕터 부분이 BERT관련 내용

  - 임베딩[4.4] + 트랜스포머12개 (인코딩) [4.11] [4.13] 으로 버트 모델을 구성한다. 

[4.13]

    def forward(self, input_ids, token_type_ids=None, attention_mask=None):

        if attention_mask is None:

            attention_mask = torch.ones_like(input_ids)

        if token_type_ids is None:

            token_type_ids = torch.zeros_like(input_ids)


        # We create a 3D attention mask from a 2D tensor mask.

        # Sizes are [batch_size, 1, 1, from_seq_length]

        # So we can broadcast to [batch_size, num_heads, to_seq_length, from_seq_length]

        # this attention mask is more simple than the triangular masking of causal attention

        # used in OpenAI GPT, we just need to prepare the broadcast dimension here.

        extended_attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)


        # Since attention_mask is 1.0 for positions we want to attend and 0.0 for

        # masked positions, this operation will create a tensor which is 0.0 for

        # positions we want to attend and -10000.0 for masked positions.

        # Since we are adding it to the raw scores before the softmax, this is

        # effectively the same as removing these entirely.

        extended_attention_mask = extended_attention_mask.float()

        extended_attention_mask = (1.0 - extended_attention_mask) * -10000.0


        embedding_output = self.embeddings(input_ids, token_type_ids)

        all_encoder_layers = self.encoder(embedding_output, extended_attention_mask)

        sequence_output = all_encoder_layers[-1]

        pooled_output = self.pooler(sequence_output)

        return all_encoder_layers, pooled_output


  - 데이터가 트랜스포머를 12번 통과하는 것이다.  = all_encoder_layer

  - [4.10] 트랜스포머 layer

  - 버트는 프리트레인된 모델을 가지고 파인튠해서 내가 맞게 사용하는 것으로 버트에 맞춰줘야 한다. 

  - [4.7] Attention: multi-head attention = BertAttention cell + BertIntermediate cell + BertOutput cell

  - Query, Key => Value => concat을 함

  - [4.6] Self Output

  - [4.10] Layer 정리, 

  - [4.8], [4.9] Feed-Forward

  - [4.13] sequence output 리턴: 1개만 사용

  - [4.14] start_logit, end_logit을 뽑아냄 

  - [7.3.4]~[6.1] chatbot_prediction_answer함수를 통과해서 answer를 준다. 


* colab실행 속도 향상은 data는 자신의 googel driver에 올린 후 => 소스에서 위치를 수정해서 처리한다. 




실습


colab에서 질문을 넣고 하단의 소스를 실행하면 마지막에 답변이 나온다. 





후기


- 새로운 기술에 대한 열정과 실험정신을 흡수하고 온 자리

- 기술적인 발전이 있었고, Colab같은 인공지능 실험 플랫폼도 나오고 있다는 것. 이제 대중화로 가는 길들이 하나씩 제공되고 있는 느낌이지만 좋은 모델들이 지원이 풍부한 혁신 기업에 집중되고 있다는 아쉬움도 있다. 

- 모델을 만들기위해 비용이 많이 든다. 

- 모델은 인문적 소양을 통해 이것을 수식화 하고 다시 인공지능 모델로 만들어 갈 수 있는 능력이 있어야 한다고 느낌




<참조>

- Bert 소개

- Korean Question & Answering Set

- Pytorch BERT 소스

- 인라이플 회사

- 실습파일

AI_Academy_bert_chat.ipynb

data.zip