허깅페이스라는 오픈소스 커뮤니티에서 transformers를 제공하고 있다. tensorflow나 pytorch에서 사용 가능하다.
transformer는 사전학습된 최첨단 모델들을 쉽게 다운로드하고 훈련시킬 수 있는 API와 도구를 제공합니다.
transformer에서는 TFBertModel을 사용했다.
6가지 감정으로 분류된 데이터셋을 활용
총 5만 7천개의 데이터를 활용했다.
NLP는 비정형 데이터를 다루기 때문에, 컴퓨터가 이해를 못한다. 따라서 컴퓨터가 이해할 수 있도록 텍스트를 벡터화 (임베딩) 해주었다.
- 임베딩 단계에서는 세가지 과정을 거쳤는데, 우선 토큰화를 진행해 최소 의미 단위인 토큰으로 나눠주고. (토크나이저는 KoBertTokenizer를 사용했다) 토큰별로 시퀀스를 부여해주고, 하나의 행렬로 나타내기 위해서 병렬 연산을 위해서 여러 문장의 길이를 임의로 동일하게 맞춰주는 작업이 필요한데 이는 패딩으로 진행하였다. 패딩은 최대 토큰 수인 299개를 참고하여 300개로 설정해 진행해주었다.
임베딩된 결과는 세가지로 나뉘는데, input id / attention mask / token type id 로 나뉜다. 이 세개는 Bert 에 들어갈 input 값이다.
텐서플로우에 세가지 input을 넣고, final model로는 6개의 유닛을 가진 활성화함수 softmax 인 output layer를 사용해 모델을 만들었다. 옵티마이저로는 RectifiedAdam를 사용했다. RectifiedAdam 은 Adam 모델에서 rectification을 곱해줌으로써 학습 초기에 일어날 수 있는 bad local optima problem을 해결하고, 학습 안정성을 높인 옵티마이저이다.
loss 함수로는 SparseCategoricalCrossentropy를 사용했다. 훈련 데이터의 label(target)이 one-hot vector 이면 CategoricalCrossentropy, 훈련 데이터의 label(target)이 정수이면 SparseCategoricalCrossentropy 이기 때문에 0~5까지의 정수로 라벨링된 데이터를 활용하였기 때문에 SparseCategoricalCrossentropy를 사용했다.
output layer만을 추가로 달아주면 원하는 결과를 출력해낼 수 있다. 많은 BERT 모델 중에서도 KoBERT를 사용한 이유는 "한국어"에 대해 많은 사전 학습이 이루어져 있고, 감정을 분석할 때, 긍정과 부정만으로 분류하는 것이 아닌 다중 분류가 가능한 것이 강점이기 때문이다.
이 포스팅에서 하는 작업은 바로 파인 튜닝(Fine-tuning)에 해당한다. 다른 작업에 대해서 파라미터 재조정을 위한 추가 훈련 과정을 거치는 것을 말한다. 예시를 들어보면, 우리가 하고 싶은 작업이 우울증 경향 문헌 분류라고 하였을 때, 이미 위키피디아 등으로 사전 학습된 BERT 위에 분류를 위한 신경망을 한 층 추가하는 것이다. 이미 BERT가 언어 모델 사전 학습 과정에서 얻은 지식을 활용할 수 있으므로 우울증 경향 문헌 분류에서 보다 더 좋은 성능을 얻을 수 있다.
BERT는 이미 누군가가 학습해둔 모델을 사용한다(pre-trained model)는 것을 뜻한다. 따라서 사용하는 model과 tokenizer는 항상 mapping 관계여야 한다. 예를 들어서 U 팀이 개발한 BERT를 사용하는데, V팀이 개발한 BERT의 tokenizer를 사용하면 model은 텍스트를 이해할 수 없다. U팀의 BERT의 토크나이저는 '우리'라는 단어를 23번으로 int encoding하는 반면에, V라는 BERT의 tokenizer는 '우리'라는 단어를 103번으로 int encoding해 단어와 mapping 되는 정보 자체가 달라지기 때문이다. 이 부분은 뒤에서 간단히 진행해본 실습에서 더 자세히 다뤄볼 것이다.
출력값들을 보면 3개의 array가 출력되는데, 첫 번째는 패딩된 시퀀스, 두 번째는 길이와 타입에 대한 내용, 세 번재는 어텐션 마스크 시퀀스이다. 어텐션 마스크는 지난 BERT 프로젝트 글에서도 설명했었는데, BERT에 데이터가 입력되었을 때 어텐션 함수가 적용되어 연산이 된다. 이때 1로 패딩된 값들은 연산할 필요가 없기 때문에 연산을 하지 않아도 된다고 알려주는 데이터가 있어야 하는데 그게 바로 어텐션 마스크 시퀀스인 것이다. 이렇게 BERT나 KoBERT에는 어텐션 마스크 데이터도 함께 입력되어야 한다⭐
자연어 처리에서 크롤링 등으로 얻어낸 코퍼스 데이터가 필요에 맞게 전처리되지 않은 상태라면, 해당 데이터를 사용하고자하는 용도에 맞게 토큰화(tokenization) & 정제(cleaning) & 정규화(normalization)하는 일을 하게 됩니다.
주어진 코퍼스(corpus)에서 토큰(token)이라 불리는 단위로 나누는 작업을 토큰화(tokenization)라고 합니다. 토큰의 단위가 상황에 따라 다르지만, 보통 의미있는 단위로 토큰을 정의합니다.
토큰의 기준을 단어(word)로 하는 경우, 단어 토큰화(word tokenization)라고 합니다. 다만, 여기서 단어(word)는 단어 단위 외에도 단어구, 의미를 갖는 문자열로도 간주되기도 합니다.
문장 토큰화(Sentence Tokenization)
5. 한국어에서의 토큰화의 어려움.
영어는 New York과 같은 합성어나 he's 와 같이 줄임말에 대한 예외처리만 한다면, 띄어쓰기(whitespace)를 기준으로 하는 띄어쓰기 토큰화를 수행해도 단어 토큰화가 잘 작동합니다. 거의 대부분의 경우에서 단어 단위로 띄어쓰기가 이루어지기 때문에 띄어쓰기 토큰화와 단어 토큰화가 거의 같기 때문입니다.
하지만 한국어는 영어와는 달리 띄어쓰기만으로는 토큰화를 하기에 부족합니다. 한국어의 경우에는 띄어쓰기 단위가 되는 단위를 '어절'이라고 하는데 어절 토큰화는 한국어 NLP에서 지양되고 있습니다. 어절 토큰화와 단어 토큰화는 같지 않기 때문입니다. 그 근본적인 이유는 한국어가 영어와는 다른 형태를 가지는 언어인 교착어라는 점에서 기인합니다. 교착어란 조사, 어미 등을 붙여서 말을 만드는 언어를 말합니다.
한국어 토큰화에서는 형태소(morpheme) 란 개념을 반드시 이해해야 합니다. 형태소(morpheme)란 뜻을 가진 가장 작은 말의 단위를 말합니다. 이 형태소에는 두 가지 형태소가 있는데 자립 형태소와 의존 형태소입니다.
자립 형태소: 접사, 어미, 조사와 상관없이 자립하여 사용할 수 있는 형태소. 그 자체로 단어가 된다. 체언(명사, 대명사, 수사), 수식언(관형사, 부사), 감탄사 등이 있다.
의존 형태소: 다른 형태소와 결합하여 사용되는 형태소. 접사, 어미, 조사, 어간을 말한다.
문장 : 에디가 책을 읽었다
이 문장을 띄어쓰기 단위 토큰화를 수행한다면 다음과 같은 결과를 얻습니다.
['에디가', '책을', '읽었다']
하지만 이를 형태소 단위로 분해하면 다음과 같습니다.
자립 형태소 : 에디, 책 의존 형태소 : -가, -을, 읽-, -었, -다
'에디'라는 사람 이름과 '책'이라는 명사를 얻어낼 수 있습니다. 이를 통해 유추할 수 있는 것은 한국어에서 영어에서의 단어 토큰화와 유사한 형태를 얻으려면 어절 토큰화가 아니라 형태소 토큰화를 수행해야한다는 겁니다.
결론적으로 한국어는 수많은 코퍼스에서 띄어쓰기가 무시되는 경우가 많아 자연어 처리가 어려워졌다는 것입니다.
6. 품사 태깅(Part-of-speech tagging)
단어는 표기는 같지만 품사에 따라서 단어의 의미가 달라지기도 합니다.
한국어도 마찬가지입니다. '못'이라는 단어는 명사로서는 망치를 사용해서 목재 따위를 고정하는 물건을 의미합니다. 하지만 부사로서의 '못'은 '먹는다', '달린다'와 같은 동작 동사를 할 수 없다는 의미로 쓰입니다.결국 단어의 의미를 제대로 파악하기 위해서는 해당 단어가 어떤 품사로 쓰였는지 보는 것이 주요 지표가 될 수도 있습니다. 그에 따라 단어 토큰화 과정에서 각 단어가 어떤 품사로 쓰였는지를 구분해놓기도 하는데, 이 작업을 품사 태깅(part-of-speech tagging)이라고 합니다. NLTK와 KoNLPy를 통해 품사 태깅 실습을 진행합니다.
형태소 분석기로 Okt(Open Korea Text), 메캅(Mecab), 코모란(Komoran), 한나눔(Hannanum), 꼬꼬마(Kkma)가 있습니다.
princess 와 man 거리 = d2, price와 man 간의 거리 d1이라고 한다면 d1이 더 짧아, price는 man과 가까운 의미라고 해석
한계점 : 벡터의 크기에 영향을 받는다. (magnitude of vector matter)
money라는 단어가 반복되었기 때문에 벡터의 크기가 늘어났다. 유클라디안 유사도 기반으로 보면 money를 6번 반복한 것 보다도 laundering이라는 벡터와 더 가까운 의미를 가진다고 나온다. 하지만 사실상 money money laundering은 money가 두번 반복되기 때문에 money*6번 반복하는 벡터와 더 의미가 유사하다고 할 수 있다.
Cosine Similarity
이를 극복하기 위해 사용하는 것이 코싸인 유사도.
코싸인 유사도는 두 벡터 사이의 각도를 기반으로 유사도를 결정한다.
벡터 자체의 크기는 무시하고 두 벡터 사이의 각도 기반이기 때문에 money money laundering을 money*6와 더 유사하다고 말할 수 있다.
문장이 유사하다면 같은 방향, 문장이 유사하지 않다면 90도의 방향을 (직교하는 방향)을 가질 것이다.
아래는 공식
각도가 90도 이상 커질 수 있을까?
보통은 불가능하다.
두 문장 벡터 사이의 각도는 90도 이상일 수 없다.
이유는, 문장 벡터는 문장 내의 Frequency 빈도수를 기반으로 벡터를 만들기 때문에 빈도수가 -1이 될 수 없으므로 90도가 최대라고 할 수 있다.