자연어 처리

https://www.edwith.org/deepnlp/joinLectures/17363

 

딥러닝을 이용한 자연어 처리 강좌소개 : edwith

- 조경현 교수

www.edwith.org

edwith 조경현 교수님의 자연어 처리 강좌 중, C. Text Classification & Sentence Representation 부분을 정리한 글입니다.

 

사실 학교 보고서로 제출한 내용인데 그냥 그대로 놓고 있긴 좀 아까워서...ㅎㅎ

 

 

 

 

1. 텍스트 분류란?

텍스트 분류란, 단어, 문장 또는 지문 전체를 두고 카테고리 별로 구분하는 것을 의미합니다. 이미지 분류 문제와 비슷하게 지도 학습 (supervised learning)으로 작업을 하게 됩니다.

텍스트 분류에는 다양한 종류가 있습니다.

 

1.     감성 분석

말 그대로, 문장 또는 지문의 감성을 분석하는 것입니다.

대표적인 예시로, 영화 리뷰를 보고 긍정적인 리뷰인지 부정적인 리뷰인지 분석하는 것이 있습니다.

가령 이 영화는 역대 최악의 영화이다라는 문장을 분석한다면, “부정적인 리뷰로 분류하는 것이 맞겠지요.

 

2.     카테고리 분류

이것도 말 그대로 문장이나 지문을 카테고리 별로 분류하는 것입니다.

어떤 블로그의 글을 보고 그 글이 IT관련 글인지, 스포츠 관련 글인지 등등을 분류하는 것도 이 카테고리 분류로 볼 수 있겠고, 나에게 온 메일이 스팸 메일인지 그냥 메일인지 분류하는 것도 카테고리 분류로 볼 수 있겠습니다.

 

3.     의도 분류

이것도 또 말 그대로 문장의 의도를 분류하는 것입니다.

가령 챗봇한테 오늘 주말에 영업하는 안산 중앙동에 있는 식당 추천해 줘라고 말을 했을 때, 챗봇한테 이 말이 어떤 의도를 갖고 한 말인지 분류하게 하는 것입니다. 위의 경우에는 식당 추천이 의도가 될 것이고, 그러면 챗봇은 그 의도 안에서 오늘 주말에 영업”, “안산 중앙동에 있는이라는 두 구문을 알아서 잘 해석해서 답을 알려 줄 것입니다.

 

 

 

 

 

2.     문장과 토큰

문장을 그냥 그대로 곧이곧대로 자연어 처리 모델에 적용하는 것은 사실상 불가능합니다.

그렇기 때문에 문장을 자연어 처리 모델에 적용시킬 때는, 문장을 토큰이라는 단위로 나눕니다.

이 때, 토큰은 매우 추상적이고, 임의적인 성질을 지닙니다.

예를 들자면, 분명 늑대와 개는 비슷한 성질을 가졌지만 말은 아예 다르고, “수학수화는 매우 다른 의미를 가졌지만 말은 굉장히 비슷합니다.

문장을 토큰으로 나누는 방식은 굉장히 다양합니다.

자연어 처리를 공부하는 중입니다.” 라는 문장만 보더라도,

·       자연어, 처리를, 공부하는, 중입니다 (띄어쓰기로 나누기),

·       자연어, 처리, , 공부, 하는, , 입니다 (형태소로 나누기),

·       , , , (공백), , , , (공백), , , , , (공백), , , , (어절마다 나누기)

등등이 있습니다.

 

, 이렇게 나눈 토큰들을 컴퓨터에게 주려면 이 토큰들을 숫자로 변환해 주어야 합니다.

이미지를 컴퓨터에 입력할 때 픽셀 값으로 입력하는 것과 비슷한 맥락입니다.

이 토큰들을 숫자로 변환해 주기 위해, 이 토큰들로 Vocabulary(단어장)을 만들어서 인덱스 값을 토큰들에 부여합니다.

가령 위 예시에서 형태소로 나누었다고 했을 때, Vocabulary(자연어, 처리, , 공부, 하는, , 입니다) 로 나누어져 있다면 자연어0, “공부3, “입니다6이 될 것입니다.

 

 

하지만, 우리들은 비슷한 의미를 가진 토큰은 가깝게, 다른 의미를 가진 토큰은 멀리 배치하고 싶습니다. 그런 점에서 위처럼 저렇게 막 배열하는 것은 큰 의미가 없습니다.

이렇게 비슷한 의미를 가진 토큰은 가까이, 다른 의미를 가진 토큰은 멀리 배치하기 위해서 실행할 수 있는 것이 One-hot Encoding입니다.

One-hot Encoding이란, 길이가 단어장(V)인 벡터에서, 단어의 인덱스 위치에 있는 값만 1, 나머지는 모두 0으로 두는 형식입니다.

 

가령 위 예시에서 공부One-hot Encoding 하게 되면

[0, 0, 0, 1, 0, 0, 0]으로 인코딩 될 것입니다.

그러나 그냥 이렇게 인코딩만 한다고 해서 단어의 유사성이 거리에 영향을 미치게 되진 않습니다. (One-hot Encoding을 하면 모든 토큰들의 거리가 동일해 집니다.)

 

 

이를 해결하기 위해, Embedding이라는 과정을 거치게 됩니다.

Embedding이란, 각 토큰을 일종의 테이블에 집어넣는 방식입니다. 이를 하기 위해서, 인공 신경망의 Weight W에다가 One-hot Encoding된 각 토큰을 내적하게 됩니다. 이렇게 하면, 모든 토큰들은 이제 더 큰 차원의 연속적인 벡터로 변환되게 됩니다. 이렇게 변환된 토큰들은 이제 각각의 토큰의 거리가 달라지기 때문에, 여기서 의미의 유사성을 찾을 수 있게 됩니다.

 

 

 

 

3.     문장을 표현하는 방법들 (CBoW, RN, CNN, Self Attention, RNN)

이제 Vocabulary에 있는 토큰을 처리하는 것은 끝났습니다.

하지만, 이것 만으로는 충분하지 않습니다. 우리는 문장을 input값으로 집어넣는 것이지, 각각의 토큰을 input 값으로 넣어주는 것이 아니기 때문입니다.

 

하지만 각각의 문장은 모두 길이가 다릅니다. 엄청나게 긴 문장이 있는가 하면, 엄청나게 짧은 문장도 있기 마련입니다. 이 길이가 다른 문장들을 그대로 모델에 집어넣는 것은 사실상 불가능합니다. 그렇기 때문에, 이 문장을 나타내는 방법이 중요하게 됩니다. 각 토큰을 나타낸 것 같이 말입니다.

이 때 사용하는 방법 중 CBow, RN, CNN, Self Attention, RNN 방식을 알아봅시다.

 

 

·       CBoW (Continuous Bag of Words)

CBow는 그냥 문장에 담겨 있는 토큰의 평균값을 내는 매우 간단한 방식으로 문장을 나타냅니다. 이게 뭔 이상한 짓인가 생각이 들기도 하지만, 충격적이게도 이 방식은 굉장히 성능이 좋다고 합니다. 연산 속도도 매우 빠르고, 성능도 괜찮기 때문에 어떤 자연어 처리 문제를 만나도 일반적인 baseline 역할을 해 준다고 합니다.

 

 

·       RN (Relation Network)

Relation Network는 말 그대로, 단어들 사이의 관계를 보는데, 문장 안의 모든 토큰 쌍을 보고, 각 쌍에 대한 신경망을 만드는 방식으로 이루어 집니다.

가령 인덱스 값으로 본다면, (1, 2), (1, 3), …, (1, n), (2, 3), (2, 4), …. 같이 쌍을 지어 준 뒤에, 각 쌍에 대한 신경망을 만들어서 (W 곱하고 b 더하고…) 그 값들을 전부 다 평균을 내 줍니다.

물론 두 단어를 묶는 게 아니라 세 단어, 네 단어, … 끼리 묶을 수도 있지만, 이렇게 묶는 단어의 수가 늘어나면 늘어날수록 연산 횟수가 기하급수적으로 늘어나게 됩니다. (효율성이 떨어지게 됩니다.)

이 방식을 채용하면 단어들 사이의 연관성을 파악하면서 문장을 표현할 수 있다는 장점이 있지만, 아예 관계없는 단어 쌍도 같이 계산한다는 단점이 존재합니다.

 

 

·       CNN (Convolutional Neural Network)

이미지 처리에서 쓰던 CNN을 그대로 1차원 형식으로 가져와서 문장에 적용합니다.

문장 안에서 CNN을 사용해서 층을 쌓고, 그 층(layer)에서 다시 CNN을 사용해서 layer을 중첩하는 방식으로 진행됩니다.

이렇게 하면, 점층적으로 더 넓은 범위의 토큰들 사이의 관계를 파악할 수 있습니다.

필터의 크기가 3이었다고 한다면, 첫번째 layer에서는 주변 3개의 단어와의 관계를 파악하고, 두 번째 layer에서는 주변 5개의 단어와의 관계를 파악하고하는 식입니다.

이렇게 문장을 보면, 단어 -> 다중 단어 표현 -> 구문 -> 문장 순으로 문장을 분석하는 인간의 인식과도 알맞게 됩니다.

 

 

·       Self Attention

위에서 언급했던 RNCNN을 다시 봅시다.

RN에서 t번째 토큰의 표현은 f(xt,x1) + f(xt, x2) + f(xt , x3) + … + f(xt, xT)로 볼 수 있고,

CNN에서 t번째 토큰의 표현은 f(xt, xt-k) + … + f(xt,xt) + … + f(xt, xt+k)로 볼 수 있습니다.

그런데, CNN은 가중치를 xt근처 k개를 1, 나머지를 0이라고 둔 RN이라고 볼 수도 있게 됩니다.

그런데, 이렇게 가중치를 1 또는 0으로 두는 것이 아니고 0에서 1 사이의 값으로 둘 수 있을 것 같습니다.

RN에다가 가중치를 1 또는 0을 두어서 CNN 연산을 할 것이 아니라, 토큰마다의 연관성을 찾는 function을 두어서 그 function값을 가중치로 둘 수도 있는데, 이를 Self Attention 방식이라고 합니다. (function은 또 다른 인공 신경망으로 구할 수 있습니다.)

이러면 이제 RN처럼 단어들마다 가중치를 곱해줘서 연관성이 없는 단어들은 가중치를 0에 가깝게 두고, 연관성이 있는 단어들은 가중치를 1에 가깝게 둬서 연관성이 높은 토큰을 강조하고, 연관성이 낮은 토큰을 억제할 수 있습니다.

또한, 먼 거리에서도 연관성이 높은 단어들을 가져올 수 있고, 짧은 거리에서도 마찬가지로 가능하니 거리에 큰 영향을 받지 않게 됩니다.

하지만, 계산 복잡도가 굉장히 높다는 단점이 있습니다.

 

·       RNN (Recurrent Neural Network)

다른 방식으로는 RNN이 있습니다. 이 방식은 단어 처음과 끝 모두의 쌍을 맺어주며 나아가는 Self Attention 방식과는 달리 그냥 문장을 처음부터 쭉 읽어가면서, 매번 토큰 하나씩을 읽을 때 마다 메모리에 토큰을 저장해 가면서 나아갑니다. 토큰들을 메모리에 압축시키는 형식인 것입니다. 그렇게 마지막에 나온 메모리 벡터를 갖고 문장을 표현하게 됩니다.

단점으로, 토큰을 하나하나 읽어야 하는 특성 상 연산 속도가 다른 것들보다 느리게 되고, 순차적으로 읽는다는 점 때문에 나아가면 나아갈수록 예전에 읽어왔던 메모리를 잊게 되어 정보의 손실이 일어납니다. 이 점들은 나중에 나온 LSTM, GRU와 같은 RNN의 변형이 나오면서 어느 정도 해결됩니다.

 

 

 

이렇게 자연어 처리의 기본적인 부분만 가볍게(?) 살펴 보았습니다.

앞으로 시간이 더 난다면 조금 더 깊게, 조금 더 많은 내용을 살펴보고 싶습니다만,

공업 일반 1인 1프로젝트로 다시 강화 학습을 공부할 예정이라 시간이 날지 모르겠습니다.

+ Recent posts