📝 상세 정리
- 야호! 자연어처리의 세계로 들어왔다!
- 문제의 본질은 컴퓨터가 우리의 말을 이해하게 만드는 것
- 2.1 자연어 처리란
- 우리가 평소에 쓰는 말을 자연어라고 한다.
- 자연어 처리 (NLP)는 이 자연어를 처리하는 분야.
- 우리의 말은 문자로 구성되며, 말의 의미는 단어로 구성된다.
- 단어는 의미의 최소단위이다.
- 따라서 컴퓨터에게 단어의 의미를 이해시키는게 중요하다.
- 그 방법으로는
- 시소러스를 활용한 기법
- 통계 기반 기법
- 추론 기반 기법 (word2vec)
- 2.2 시소러스
- 단어의 의미를 나타내기 위해, 사람이 직접 단어의 의미를 정의해보자.
- 표준국어 대사전처럼 각각의 단어에 그 의미를 설명해 넣을 수 있을까?
- 시소러스는 유의어 사전으로, 뜻이 같은 단어나 비슷한 단어를 한 그룹으로 묶은 것
- 동의어 / 유의어
- 상위와 하위, 전체와 부분 등 더 세세한 관계까지 정의해둔 경우도 있다.
- 이 그래프 구조를 단어 네트워크라고 생각하고, 컴퓨터한테 가르칠 수 있지 않을까?
- WordNet
- 그런데 이런 시소러스에도 문제가 있는데..
- 시대 변화에 대응하기 어렵다
- 사람을 쓰는 비용은 크다
- 단어의 미묘한 차이를 표현할 수 있다
- 2.3 통계 기반 기법
- 이제부터는 말뭉치(corpus) 를 이용할 것
- 대량의 텍스트 데이터
- 맹목적으로 수집한거 말고, 연구나 어플리케이션을 위해 수집한 것
- 말뭉치 안에는 자연어에 대한 사람의 지식이 충분히 담겨있다고 볼 수 있다!
- 자연어 처리에는 다양한 말뭉치가 이용되는데
- 위키백과나 구글뉴스등도 되고
- 셰익스피어나 나츠메소세키씨 작품이라던지
- 일단 한번 연습을 해보자.
- 전처리
- 텍스트 데이터를 단어로 분할하고 그 분할된 단어들을 단어 ID 목록으로 변환하는 일
- 단어의 분산 표현
- 색을 코발트블루/싱크레드처럼 이름붙일수도 있지만, RGB기호로 나타낼 수도 있을 것이다
- 심지어 그쪽이 색을 더 정확하게 명시할수도 있고, 3개의 성분으로 간결한 표현도 된다
- 관련성 여부도, 정량화하기도 쉽다!!
- 그렇다면 단어도 이렇게 벡터로 표현할 수 있을까?
- 분포 가설
- 많은 연구들과 기법들이 있었는데, 그 뿌리는 다음과 같다.
- 단어의 의미는 주변 단어에 의해 형성된다
- 이를 분포 가설이라고 한다.
- 이는 단어 자체에는 의미가 없고, 그 단어가 사용된 맥락이 의미를 형성한다는 것을 내포한다.
- 앞으로 맥락이란 주변에 놓인 단어들을 가리킬 것이다.
- 윈도우 크기가 k라면 좌우 k단어씩, v[idx-k:idx+k+1] 을 의미한다.
- 일단 먼저 주변 단어를 세어보는 방법이 자연스럽게 떠오른다!
- 이를 통계 기반 기법이라고 하자.
- id값의 종류를 크기로 하는 벡터를 id에 대해 연결해서, $N^2$ 행렬을 만들 수 있다.
- 이제 벡터 사이 유사도를 측정하자.
- 내적.. 유클리드거리.. 등등 모두 쓸 수 있겠지만
- 우리는 코사인 유사도를 이용하자.
- $\text{similarity}(\mathbf{x}, \mathbf{y}) = \frac{\mathbf{x} \cdot \mathbf{y}}{||\mathbf{x}|| , ||\mathbf{y}||} = \frac{x_1 y_1 + \cdots + x_n y_n}{\sqrt{x_1^2 + \cdots + x_n^2} \sqrt{y_1^2 + \cdots + y_n^2}}$
- 이때 ${||\mathbf{x}||}$는 노름이다.
- 값은 -1에서 1 사이가 나온다.
- 이걸로 내림차순을 하든 뭘하든 해서 유사도를 계산할 수 는 있지만… 말뭉치가 작으면 문제가 많다.
- 2.4 통계 기반 기법 개선하기
- 두 단어를 그냥 이렇게 생으로 하면.. 문제가 깊다
- the car의 the같이 괘씸한 놈이 존재함
- 점별 상호정보량 (PMI)
- $\text{PMI}(x, y) = \log_2 \frac{P(x, y)}{P(x)P(y)}$
- $P(x), P(y), P(x, y)$ 는 각각 x가 일어날 확률, y가 일어날 확률, 동시에 일어날 확률
- 이 PMI값이 높을수록 관련성이 높다
- 이는 동시발생 행렬을 이용해서 다시 쓸 수 있는데
- $= \log_2 \frac{\frac{C(x, y)}{N}}{\frac{C(x)}{N} \frac{C(y)}{N}} = \log_2 \frac{C(x, y) \cdot N}{C(x) C(y)}$
- 하지만 이때 동시발생횟수가 0이면 $log_2 0$ 을 계산해야한다는 문제가 있다…
- 따라서 양의 상호정보량을 사용하자.
- $= \text{PPMI}(x, y) = \max(0, \text{PMI}(x, y))$
- 0 이상의 실수로 표현하는게 가능해졌다!
- 거대한 문제가 생겼다
- 단어가 $N$개면 차원 또한 $N$개가 된다!!!
- 차원 감소
- 물론 중요한 정보는 최대한 유지하면서 차원을 줄여야한다.
- sparse한 행렬/벡터를 중요한 축을 잘 찾아서 dense한 행렬/벡터로 만들어야 한다
- 특잇값분해(SVD)
- 임의의 행렬을 세 행렬의 곱으로 분해
- $\mathbf{X} = \mathbf{U}\mathbf{S}\mathbf{V}^T$
- $\mathbf{U}, \mathbf{V}$는 직교행렬
- $\mathbf{S}$는 대각행렬
- 근데 이게 시간복잡도가 $O(N^3)$이라서, Truncated SVD같은걸 이용하기도 한다.
- PTB 데이터셋
- 본격적인 적당한 말뭉치를 이용해보자!
- 여러가지 전처리는 좀 해두셨다
- 희소한 단어를 <unknown>으로 바꾸기
- 구체적인 숫자르 N으로 수정하기
- 각 문장의 끝에 <eos> (end of sentence) 추가하기
- 결과가 재밌다! 신기하네
- 2.5 정리
- 우리는 단어의 의미를 벡터로 인코딩하는데 성공했다! 와!
- 심지어 SVD를 이용해서 차원을 감소시키고 더 좋은 벡터를 얻어냈다! 와!!
❔질문 사항
- 윈도우를 이용해서 하면, 문법적인것 (굴절어, 교착어 등)에 대한 정보가 손실되지 않나?
- I say hello와 hello say I가 같은 의미를 가지게 되니까.
- 직교행렬을 공부하자
🔗 참고 자료