페이지

2021년 8월 17일 화요일

딥러닝을 통한 한글 문장의 감성분석은 어떻게 할까? – 2편

 1편에서 감성분석 처리절차, Bert 언어모델, Kobert, 네이버 영화펑 코퍼스 로드까지 살펴보았다. 이제 이어서 KobertTokenizer 환경 준비부터 모델 훈련 평가까지의 절차를 살펴보도록 하자.

KobertTokenizer 환경 준비

우선 아래와 같이 huggingface transformers google sentencepieceimport 한다.



Huggingface transformers 로부터 Kobert 를 사용하려면 여기 에 있는 tokenization_kobert.py 내용을 프로그램내로 복사해온 후에 KobertTokenizer import 한다.



아래 그림 6의 ①은 senterpiece unicode 형식의 ‘_’ 을 정의한 것. ②는 KobertTokenizer sentencepiece를 필요로 함을 설명. ③은 사전 학습된 토크나이저 모델을 가져올 주소. Huggingface 의 모델 리포지토리에도 있다. ④는 관련 어휘사전. 8002개의 token을 가지고 있다. 역시 huggingface 리포지토리에도 있다. ⑤ 소문자 변환 구성을 False 해 주어야 한다. ⑤ 는 사전 학습 tokenizer position embedding: 크기는 512 로 정의.

 



<그림 6. Tokenization_kobert.py KobertTokenizer class 변수 정의>

 

아래 그림 7과 같이 tokenize 함수를 보면 ①번에 Sentencepiece 토크나이즈를 사용하는 것을 알 수 있다. ②번은 분절된 토큰의 끝이 “,” 이고 길이가 1이상 경우에 그 토큰의 언더바“_“를 없애고 다시 sentencepiece 토큰화를 시도하여 cur_pieces에 대입한다. ③은 이러한 cur_pieces 의 처음이 언더바”_”인 경우, 하나의 컬럼 요소인 경우 전체를 cur_pieces 로 지정한다. ④는 컬럼 요소가 2인 경우에는 두번째 컬럼을 첫번행의 값으로 치환한다. 이렇게하여 각각 new_pieces 에 담긴 값을 리턴한다. 언더바(“_”)가 분절의 처음에 위치한 것을 이용하여 그 이후 분절에 활용하는 것을 알 수 있다.



 

<그림 7. KobertTokenizer 내의 tokenize 함수>

 

자 이제KobertToknizer 를 이전 그림 6에서 ‘monologg/kobert”로 정의하였던 구성을 통해 호출해보자.



Tokenizer.tokenize 를 통해 토큰화 된 결과를 확인한다. Encode 는 인코딩된 숫자로 나타나고 나중에 decode 를 하면 원문으로 복원된다.



지금까지 huggingface에서 제공하는 한글 형분석기에 기반한 사전 학습된 KobertTokenizer 에 대해 알아보았다.

 

Naver 문장들을Bert input 용 변환

자 이제 다음 일은 네이버 영화평 15만개의 train 데이터들을 Bert 에 입력되는 형식과 맞추어 주는 일을 해야 한다. 이렇게 하는 이유는 33억 어절로 사전 학습된 Bert base 모델의 전이 학습에 더해서 네이버 영화평 한글 데이터들을 입력으로 한 추가 layer 를 추가하여 파인 튜닝을 실시할 계획이어서 앞의 그림 3BERT 에 입력되는 토큰의 임베딩 형식과 같이 네이버 데이터를 변환해 주어야 한다.

Bert 형식의 토큰 임베딩 형식은 예를 들어 입력최대 길이를 64(max_length=64)로 정의할 경우, 아래와 같이 한글 문장에 해당하는 부분은 인코딩 숫자로 나머지는 1로 채워진다.



Bert 형식의 mask 임베딩 형식은 아래와 같이 한글 문장에 해당하는 부분은 1, 나머지는 0으로 채워진다. 임베딩되는 형식은 ①과 같은 표현식으로 토큰 숫자만큼 1(valid_num * [1]) 그리고 나머지는 0으로 (64 – valid_num) * [0])으로 임베딩된다.



자 그럼 네이버 영화평 문장들을 Bert input 용으로 하기위해 토큰 input, segment input, mask input 형식으로 데이터들을 변환해보자.

아래 그림 8을 보면 네이버 데이터프레임을 입력으로하는 convert_data 함수다. ① 네이버 테이블을 한 행의 문장씩 읽어 들여 ② 해당되는 네이버 문장의 컬럼(document)에 해당하는 문장을 global 로 선언된 KobertTokenizer 를 통해 인코딩한다. ③은 바로 전에 살펴본 mask 임베딩 형식과 같이 한글 토큰만큼 1을 나머지는 0을 넣어준다. ④ 네이버 영화평은 Bert처럼 두 개의 이어지는 문장이 아니라 단일 문장이어서 한 문장 최대길이 64 길이만큼 0으로 채운다. ⑤번은 ①번의 for 루프만큼 해당 문장의 타겟 즉 0 혹은 1의 레이블을 targets 리스트에 추가(append)한다. 그리고 ⑥에서 [토큰, 마스크, 세그먼트]와 함께 타겟을 리턴 한다.



<그림 8. 네이버 영화평 문장의 Bert input 형식으로의 변환>

 

그리고 아래의 load_data 함수는 네이버의 문장과 레이블 데이터프레임을 위의 convert_data를 통하여 변환한 변환된 문장 data_x 와 레이블 data_y 로 리턴 한다.



네이버 train, test 데이터를 load_data 를 통해 Bert input 에 맞게 변환한다.

 





<그림 9. Bert 입력 용으로 변환된 네이버 훈련 및 테스트 데이터>

 

Bert Model 구축

Huggingface transformer 라이브러리는 다양한 Bert 분류 모델을 제공한다. Tensorflow 환경의 TFBert의 사전 훈련 모델을 사용하여 ①과 같이 정의한다. ,,④를 통해 토큰, 마스크 및 세그먼트 입력을 정의. ⑤ 인풋이 토큰, 마스크, 세그먼트 인 모델 정의

 



<그림 10. Bert 모델 정의>

다음으론 Rectified Adam Optimizer를 정의. 이를 위하여 ①과 같이Tensorflow addon을 설치하고 import, Rectified Adam Optimizer 를 정의, warmup 비율을 10% 로 하여 처음 learning rate 를 ④와 같은 1e-5 로 시작하여 전체 공정의 10%를 최대값인 5e-5가 될 때까지 점진적으로 올려준다.

 



<그림 11. Rectified Adam Optimizer 정의>

 

파인 튜닝을 위해 Bert 사전 학습 모델위에 아래와 같은 layer 들을 모델에 추가한다. ①은 이전 그림 10의 ⑤인 bert_outputs 를 입력으로 0.5 값으로 dropout 층을 추가한다. 번에서 긍정 부정을 판별할 sigmoid 이진 판별이 Dense 층을 추가한다. ③번에서 이전 모델을 입력으로하여 입력이 토큰, 마스크, 세그먼트인 모델 정의 ④에서 Rectified Adam Optimizer BinaryCrossentropy loss 그리고 accuracy metrics 를 쓰는 모델 컴파일

 



<그림 12. 파인 튜닝 모델 정의>

 

  아래 그림 13를 보면 ①번에 Bert 에 입력되기위한 토큰, 마스크, 세그먼트 입력이 bert_outputs 으로부터 만들어져 있고 ②번에 Bert base 모델이 ③번에 dropout ④에 dense layer 를 확인 할 수 있다. 92,187,649 파라미터 수를 확인한다.

 



<그림 13. 모델 summary>

 

아래 그림 14과 같이 모델 훈련을 시작한다. ①번에 이전 그림 9train_x, train_y를 입력으로, epoch2batch_size64 (메모리 부하를 염두에 두고 낮게 설정), validation_data test_x test_y를 입력.

 

    





<그림 14. 모델 훈련>

 

훈련 결과 2번의 epoch를 수행하였는데 google colab으로 1시간 20분 정도 소요되었고 ②번과 같이 accuracy 0.892, validated accuracy 0.883을 달성하였다.

결언

 지금까지 2편에 걸쳐 딥러닝을 이용한 감성분석 모델 구축 방법을 살펴보았다. 네이버 영화평 코퍼스를 이용하여 한글 형분석기가 반영된 Kobert 사전 훈련 tokenizer를 활용하여 huggingface transformers 가 제공하는 Bert 사전 훈련 모델 베이스를 전이 학습으로 사용하였다. 이에 더하여 네이버를 Bert 입력용으로 변환한 데이터들을 입력으로 하여 긍정 부정을 판별하는 이진 분류기를 추가하는 파인 튜닝을 통하여 epoch 2회 훈련에 accuracy 0.892를 달성하였다. 그림 4에서 Kobert의 경우 0.901 accuracy 를 달성하였다고 문헌에 나와있는데, epoch 4이상으로 늘리면 달성이 가능할 것으로 기대된다.

 

딥러닝을 통한 한글 문장의 감성분석은 어떻게 할까? – 1편

 감성 분석(Sentiment Analysis)

감성 분석이란 자연어처리 기술을 사용하여 문장 혹은 문서에서의 표현이 긍정, 부정 혹은 중립인지를 판별하는 기술이다. 아래 그림 1과 같이 약 15만건의 훈련용 데이터세트의 각 행에 id 컬럼과, document 컬럼에 영화평과 label 컬럼에 1(긍정) 혹은 0(부정)의 정보가 들어있는 네이버의 영화평 코퍼스를 사용하여 감성분석을 살펴본다.

 



<그림 1. 네이버 영화평 데이터세트 예>

감성 분석 처리 절차

딥러닝을 통한 대략적인 감성 분석 처리 절차는 아래 그림2와 같다. Huggingface Kobert 사전 학습 모델을 전이받아 훈련하는데 있어 수행은 Google Colab 을 이용하였다. Huggingface transformers import 해 쓰려면 Tensorflow 2.5 이상이 필요하다. Huggingface BERT, BART, ELECTRA 등등의 최신 자연어처리 알고리즘들을 Tensorflow, Torch로 구현한 transformers repository 를 제공하여 많이 사용한다.

최근 발표된 Bert 라는 언어모델에 기반해서 한글 데이터세트에서 보다 좋은 성능을 보이는 Kobert 언어모델을 사용한다. 순서는 아래 그림 2와 같은 순서로 진행한다.

1.    관련 라이브러리와 네이버 영화평 코퍼스를 다운받는다.

2.    최신 tensorflow 버전 2.5 이상에서 동작하는 huggingface 사의 kobert tokenizer 를 사용하기 위하여 이곳에서  KobertTokenizer 내용을 주피터 노트북 셀로 복사해 옴.

3.    Bert 입력 형태로 네이버 영화평 데이터가 입력될 수 있도록 데이터 변환

4.    Bert 사전학습 모델을 전이학습을 통한 모델 구축

5.    이 사전학습 모델위에 긍정. 부정 분류를 위한 이진(binary)분류기의 층을 파인 튜닝을 위해 추가

6.    모델 훈련 및 평가

 



<그림 2. 감성 분석 처리 절차>

 

Bert 언어모델

  2020년 구글이 공개한 AI 언어모델 BERT(Bidirectional Encoder Representations from Transformers)는 일부 성능 평가에서 인간보다 더 높은 정확도를 보이는 AI 기반 최첨단 딥러닝 모델이다. 언어 모델이란 자연어의 법칙을 컴퓨터로 모사한 모델인데, 보통 주어진 단어 들로부터 그 다음에 등장할 단어의 확률을 예측하는 방식으로 학습되어, 다음에 등장할 단어를 잘 예측하는 모델은 그 언어의 특성이 잘 반영된 모델이고 문맥을 잘 계산하는 좋은 언어 모델로 간주한다. 좋은 예로, Google 검색 창에서 딥러닝을 이용한이라는 문장을 치면 다음에 이어서 화면에 나타나는 문장들을 보고 얼마나 우리말에 자연스럽고 합당한 문장이 이어지는 가를 보는 것과 같다. 가장 기초적인 언어모델은 Markov 체인인데 이전 뉴스레터의 7 8를 참고하기 바란다.

2017년 이전의 자연어처리에서 주로 사용되어 온 재귀신경망(Recurrent Neural Network)구조를 완전히 배제하고 attention 만으로 이전의 자연어처리의 문제점들을 극복한 transformer 라는 획기적인 구조가 발표되고 이후 구글은 Bert를 발표한다. Bert transformer 의 인코더-디코더 구조 중에 인코더 만을 사용한다. Transformer 에 대해서는 이전 뉴스레터 4를 참고.

Bert 는 약 30억 어절의 영어데이터와 3만개의 토큰을 사전으로 활용하여 언어 이해모델을 사전 학습. 학습 방법도 특징이 있는데 첫째, 두개의 문장을 문장 순서로 학습하여 두번째 이어서 오는 문장이 순서에 맞는 문장인지를 학습. 둘째, 양방향으로 학습하여 가려진 단어를 맞추는 방식으로 학습. 예를 들어,


저 남자는 ()에 출근했다. 회사에 출근하자마자 ()를 마셨다   라는 문장이 있을 때,

   번과 ②번 마스크에 대하여 회사커피라고 맞추는 방식의 훈련이다.

 



<그림 3. BERT 에 입력되는 토큰의 임베딩>

 

위의 그림3과 같이 이러한 Bert에 입력되는 두개의 문장은 Token, Segment, Position이라는 임베딩이 단어 임베딩 단위로 이루어져 Bert 에 입력된다. 이때 최종 입력되는 형태인 그림 최상단의 input 을 보면 ①과 같이 문장 처음에 [CLS]가 삽입되고 ②와 같이 문장 일부를 가려(MASK)버리고,  ③과 같이 문장과 다음 문장을 구별하는 [SEP] 구별자가 들어가고 ④와 같이 단어 임베딩으로 WordPiece tokenizer 를 사용하는데playing play ##ing 로 어절이 분리된다.

-     Token EmbeddingsBert에 입력으로 들어가는 문장을 tokenizing 한 후, index 번호를 매긴 것

-     Segment Embedding 은 문장과 다음 문장을 구분하는 것.

-     Position Embedding 은 입력되는 단어 위치를 내부적으로 자동 인식하기 위함

 우리는 네이버의 한글 영화평 코퍼스를 입력데이터로 사용하기 때문에 네이버의 데이터 형식을 Bert 가 인식할 수 있는 형태로 변환해야 하기 때문에 이렇게 Bert 가 어떻게 학습되었는가에 맞추어 형식을 일치시켜야 한다.

Huggingface 사의 github 를 보면 아래 그림 4와 같이 모델 별F1 score 를 볼 수 있다. Bert-Mutilingual 모델은 Bert147개국 언어에서 사용할 수 있도록 제공한 모델이다. 이렇게 단기간에 다양한 언어에 적용가능한 것은 WordPiece 방식의 토크나이저 덕분이다. 그런데 KoBERT 가 가장 좋은 성능을 보인다. 이제 KoBERT 를 살펴보자.

 



<그림 4. 한국어처리에 대한 Bert 의 성능[1]>

 

KoBERT

 한국어 언어모델로 Bert를 대상으로 진행된 연구로는 본 과제에서 사용되는 SKT brain Kobert 가 있다. 92백만개 파라미터를 가지고 있으며, 한국어 위키, 뉴스의 약 3.2억개 단어를 훈련하였고 sentencepiece tokenizer 기반으로 어휘사전은 8,000여개이다. 서울대의 KR-BERT 99백만 파라미터를 가지고 있으며, 한국어 2.3억개를 훈련하였고 양방향 wordpiece tokernizer 기반으로 어휘사전은 12,367개다. ETRI Bert 는 한글 형태소 기반의 언어 모델이며 1억천만개 파라미터를 가지고 있으며, 47억개의 형태소를 학습하였고 한글 형태소기반 tokenizer 를 사용하여 어휘사전은 30,797개다. 이외에 SDS KoreALBERT 44억개 단어를 훈련하였고 구글의 ALBERT 언어 모델에 기반한다.

Tokenizer 역시 각 사가 다른 tokenizer 를 기반으로 하고 있다. 본 과제에서는 SKT Brainsentencepiece tokenizer에 기반한 huggingface에 등재된 Kobert tokenizer를 사용한다.

형태소란 더 분석하면 뜻이 없어지는 말의 단위다. 한글은 교착어이므로 명사에 조사가 붙어있는 경우가 많고 복합명사도 많다. 그래서 의미 단위로 교착어를 분리시키면 좋은 tokenizer를 얻고 성능도 좋아진다. 그런 의미에서, ETRI 의 형분석기 tokenizer 는 한글 성능을 향상시킬 여지를 좀 더 가지고 있다고 볼 수 있다.

 

Tokenizer

토크나이저는 입력 문장을 단어 혹은 서브 단어 단위로 쪼갠 후 사전에 등록된 아이디로 변환해주는 과정이다.

[“Do”, “n’t”, “you”, “love”, “Bert”, “?”, “we”, “sure”, “do”, “.”]

위의 예는 단어 단위의 분절이지만, 문자 단위에 비해 어휘사전(vocab.txt)이 엄청 커지므로 메모리에 문제를 야기한다. 문자 단위 토크나이저는 단순하고 메모리를 적게 사용하지만, 문맥을 이해할 의미 있는 단위로 학습하는데 지장을 준다.

기계가 문제를 풀 때, 모르는 단어가 등장하면 자연어처리가 까다로워진다. 이와 같이 모르는 단어로 인해 문제를 푸는 것이 어려워진 상황을 Out-Of-Vocabulary(OOV) 문제라고 한다. 서브 워드 분리 작업은 하나의 단어가 여러 서브 워드 들의 조합 (, birthplace = birth + place)으로 구성된 경우가 많기 때문에 하나의 단어를 서브 단어로 분리해서 인코딩 및 임베딩 하겠다는 의도를 가진 전처리 작업이다.

[“I”, “have”, “a”, “new”, “gp”, “##u”, “!”, ]

위의 예는 BertTokenizer “I have a new GPU!”를 분절한 예이다. 서브 워드 분절은 의미 있는 단어 혹은 서브 워드 단위의 표현을 학습하면서도 합리적인 사전(vocabulary)크기를 유지할 수 있다는 점이 큰 장점이다. Byte-pair-encoding(BPE)는 이 논문에서 처음으로 고안되었고 우선 단위 출현 빈도수를 사전 토큰화 한다. 즉 아래와 같이 ‘hug’ ‘pug’ 등의 빈도 수를 표시한다.

( ‘hug’, 10),  (‘pug’, 5),  (‘pun’, 12),  (‘bun’, 4),  (‘hugs’, 5)

이후 위의 분절에서 가장 많이 등장하는 문자 쌍을 찾아 어휘 사전에 등록하고 치환된 단어 분절을 계속 빈도 수에 따라 계속 결합해 나간다.

(‘h’ ‘ug’,  10) (‘p’ ‘ug’,   5) (‘p’ ‘un’,  12) (‘b’ ‘un’,  4) (‘hug’  ‘s’ , 5)

BPE는 문자 단위에서 빈도 수가 많은 쌍(pair)을 찾아 점차적으로 단어 집합을 만들어가는 방식을 취한다. Wordpiece 는 이 논문에서 제안되어 Bert에서 활용된 서브 워드 토크나이즈 알고리즘이며 BPE 의 변형 알고리즘이다. Wordpiece 는 모든 단어의 앞에 _를 붙이는데 이는 decode 를 위한 것으로 복원할 때 현재 있는 모든 띄어쓰기를 전부 제거하고, 언더바(_)를 띄어쓰기로 바꾼다.

 

SentencePiece

  구글은 Bert wordpiece 를 사용했지만 구현체를 공개하지 않아 대부분의 한국어NLP 개발자들은 SentencePiece 를 사용한다. 구글은 센텐스피스라는 BPE 와 기타 서브 워드 토크나이징을 포함한 알고리즘을 발표한다. 논문 은 여기 그리고 github 는 여기를 참고.  센텐스피스는 단어 분리 알고리즘을 사용하기위해서 사전 토큰화 작업없이 전처리를하지않은 raw 데이터에 바로 단어 토크나이저를 사용할 수 있다는 이점을 제공한다.

Kobert 로 네이버 영화평 한 문장을 토크나이즈 하면 아래 그림 5와 같이 나타난다.



<그림 5. Kobert tokenizer 출력 예>

네이버 영화평 코퍼스 로드

  아래와 같이 git clone을 통해 네이버 영화평 코퍼스를 가져온다.


설치된nsmc 밑에 있는 ratings_train.txt (훈련데이터세트 15만건), ratings_test.txt(테스트세트, 5만건)pandas 테이블형식으로 로드 한다.



Train에 로드된 데이터를 확인해본다. id, document, label의 테이블 형식으로 로드 되어있다.


 

지금까지 감성분석 처리절차, Bert 언어모델, Kobert, 네이버 영화펑 코퍼스 로드까지 살펴보았다. 2편에서 KonertTokenizer 환경 준비부터 훈련 및 평가까지 살펴보겠다.