일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 결정계수
- 오래간만에 글쓰네
- 파이썬 pandas
- 기술통계학
- Pandas
- 밑바닥부터 시작하는 딥러닝
- 회귀분석
- 최소자승법
- student t분포
- 가설검정
- F분포
- 코사인 유사도
- 차원축소
- 밑바닥부터 시작하는 딥러닝2
- word2vec
- 구글 BERT의 정석
- rnn
- 머신러닝
- 모두의 딥러닝
- 다층 퍼셉트론
- 자연어 처리
- 텍스트 분류
- 은준아 화이팅
- 감성분석
- 텐서플로2와 머신러닝으로 시작하는 자연어처리
- 기초통계
- numpy
- 히스토그램
- Django
- 군집화
- Today
- Total
데이터 한 그릇
RNN을 사용한 문장 생성(seq2seq모델) 본문
- 언어 모델을 이용해서 "문장 생성" 을 할 것
- seq2seq 모델을 이해 해볼 것
언어 모델을 사용한 문장 생성
RNN을 사용한 문장 생성의 순서
앞의 LSTM 신경망을 살펴봤는데, LSTM 을 살펴보면서 LSTM 을 이용한 언어 모델에 대해서도 살펴봤다.
(밑바닥 290그림)
먼저 학습된 LSTM 언어 모델이 있다고 가정해보자. 이 언어 모델은 "You say goodbye and I say hello" 라는 시퀀스 데이터를 학습했다. (먼저 학습된 모델 준비)
이 학습한 모델에 문장을 생성하기 위해서 첫 데이터로 "I" 를 입력했다고 가정해보자.
I를 입력받은 모델은 Embedding 계층을 거친 입력 데이터 Xt를 LSTM 계층으로 전달하게 되고, 가중치 매개변수 Wt 와 곱해진 이후 다음 계층인 Affine 계층으로 Ht를 전달하고 동시에 다음 시각의 LSTM 계층에도 Ht 를 전달할 것이다.
Affine 계층에서도 입력 Ht와 가중치 매개변수가 곱해지고 다음 계층인 Softmax with Loss 계층에 그 값을 전달할 것이다.
그리고 Softmax 활성화 함수에 Affine 계층에서 받은 데이터를 집어넣어서 다음에 도출될 단어들의 확률 분포가 만들어진다.(LSTM 언어 모델이 학습한 단어들이 있을텐데 그 단어들을 기준으로 다음에 나올 단어 확률 분포 생성), 이때 확률분포를 이용해서 정답을 도출하는 방식은 두 가지로 나뉜다.
첫 번째는 확률 분포에서 확률이 가장 높은 단어를 선택하는 방법이다. 이 방법은 "결정적" 인 방법으로 답이 고정적이다. 두 번째는 확률적으로 선택하는 방법으로 가장 확률이 높은 단어가 도출될 가능성이 높지만 그렇다고 100% 그 단어가 도출되진 않는다. 즉 정답이 고정적이지 않다.
이렇게 도출된 단어는 다음 LSTM 시각의 입력 데이터로 정의된다.
위의 과정을 똑같이 밟아서 정답 데이터를 도출한다
이 작업을 원하는 만큼 반복한다.(또는 <eos> 와 같은 종결 기호가 나타날 때까지 반복한다.)
이런 과정을 거쳐서 도출한 문장은 컴퓨터가 외워서 도출한 문장이 아니라 문장의 패턴을 파악하여 도출한 문장이라고 할 수 있다.
seq2seq
입력과 출력이 시계열 데이터인 문제는 아주 많다.
예를 들어 기계 번역이나 음성 인식이 이에 해당한다.
지금부터 우리는 시계열 데이터를 다른 시계열 데이터로 변환하는 모델을 생각해볼 것.
바로 seq2seq(sequence to sequence) 모델이다.
seq2seq 원리
seq2seq 모델을 Encoder - Decoder 모델이라고 부르기도 한다.
말 그대로 두 개의 모듈이 등장하는데 바로 Encoder와 Decoder이다.
Encoder 는 입력 데이터를 인코딩(부호화)하고, Decoder는 인코딩된 데이터를 디코딩(복호화) 한다.
여기서 인코딩이란 어떤 정보를 어떤 규칙에 따라 변환하는 것을 말한다. 문자코드 'A' 를 이진수 규칙에 따라서 '1000001' 로 변환하는게 인코딩이라고 할 수 있다.
디코딩이란 인코딩된 정보를 다시 원래의 정보로 되돌리는 것을 의미한다. 예를 들어서 앞서 인코딩해서 얻은 정보 '1000001' 을 다시 'A' 로 바꾸는게 디코딩이다.
seq2seq 의 구체적인 구조를 살펴보자
밑은 그 구조다.
`Input('나는 고양이로소이다') => [Encoder] [Decoder] => Output('I am a cat')`
먼저 '나는 고양이로소이다' 라는 input 정보가 Encoder 에 들어간다.
Encoder 에서 '나는 고양이로소이다' 를 인코딩한다. 그리고 그 정보를 Decoder 에게 넘긴다.
(이때 인코딩된 정보에는 번역에 필요한 정보가 조밀하게 응축되어 있다.)
Decoder 는 인코딩된 정보를 바탕으로 output을 출력한다.
이게 seq2seq 의 전체적인 그림이다.
Encoder 를 먼저 살펴보자.
먼저 Encoder 의 계층은 RNN 기반의 모델을 사용할 수 있다.
LSTM 모델이 성능이 더 좋으니 LSTM 을 사용한다고 가정하면, 시계열 방향으로 모델을 펼칠 수 있다.
입력 데이터로 문장의 단어 단위를 입력한다고 가정해보자.
히든 스테이트(h)가 각 LSTM 시각 계층마다 생성이 될것이고 그 h가 다음 시각으로 넘어가게 된다.
최종적으로 입력값이 끝나면(LSTM 마지막 계층) 최종 h가 생성이 되는데,
이 마지막 h 안에는 문장을 번역하는데 필요한 정보가 인코딩되어 있다.
그 h는 문장을 고정 길이의 벡터로 바꾼 것과 같다.
그래서 인코딩한다고 하면, 문장을 고정 길이의 벡터로 바꾼다는 것과 같다.
다음으로 Decoder 를 살펴보자.
그렇다면 어떻게 Decoder 는 Encoder 에서 생성된 벡터 h를 이용해서 새로운 문장을 만드는걸까?
앞서 설명한 문장 생성의 예를 이용하면 된다.
앞서 Encoder 모델에는 LSTM 계층밖에 존재하지 않았지만, Decoder 에서는 다음 언어를 예측하기 위해서 Affine 계층과 Softmax 계층을 생성한다.
앞서 Encoder 에서 생성했던 문장 벡터(h)는 Decoder LSTM 첫 계층에 그 이전 은닉 상태로서 입력값으로 들어오게 된다.
그리고 Decoder 의 다른 큰 특징은 구분자를 입력 받는다는 것. <eos> 는 문장의 시작과 끝을 나타낸다.
위에서 설명했던 문장 생성 순서대로 Decoder 에서도 처리 과정이 일어난다.
seq2seq 구현
Encoder 는 입력데이터를 받아서, 그 문장을 고정 길이의 벡터로 변환한 h를 도출한다.
Encoder의 순전파 과정에서 h가 만들어진다.
반대로 역전파에서는 h에 대한 기울기가 Decoder로부터 전달된다.
Decoder로 부터 전달된 h에 대한 기울기로부터 가중치 매개변수값들을 수정해 나간다.
Decoder 클래스를 구성할 때 주의해야할 점이 있다.
**Decoder 에 데이터를 학습할 때와 데이터를 생성할 때 데이터 부여 방식이 다르다.**
먼저 학습시에는 `정답을 알고 있다.` 정답을 알고 있기 때문에 LOSS 를 구할 수 있다.
먼저 첫 번째 데이터를 입력으로 부여하면 은닉 상태가 위쪽 계열로 나아감과 동시에 오른쪽 LSTM 시계열 방향으로도 나아간다. 위로 나아간 은닉 상태는 Affine 계층과 Softmax with Loss 계층을 거쳐서 다음 단어 예측에 대한 Loss 값도 도출한다.(다음에 출현할 단어에 대해서 예측부터 하고 정답과 비교해서 LOSS 값 도출)
다음 시각 계층에서도 똑같이 반복하게 되고 이를 통해서 총 LOSS를 구할 수 있게 된다.
이를 활용해서 오차역전파를 통해서 Decoder의 가중치 매개변수들을 수정함과 동시에 쭉 더 나아가 Encoder 의 가중치 매개변수 값들도 수정 가능하다.
Time 계층을 기준으로 오차역전파를 생각해볼 때, Softmax with loss 에 대한 기울기 값이 Time Affine, Time LSTM, Time Embedding 계열로 나아간다. 이때 LSTM 에서 배웠듯이 LSTM 시간 방향의 기울기는 따로 저장해놔야 한다. 즉, 기울기는 수직으로도 나아가지만 LSTM 계층에서 수평적으로도 나아간다. 따라서 수평적으로 나아가는 LSTM의 기울기를 따로 저장해둔다. 왜냐하면 이 기울기를 Encoder 의 역전파 때 전달해야만 한다.
문장을 생성할시 데이터 부여 방법은 첫 시각 계층에서 단어를 예측한 값이 다음 시각의 계층의 입력값으로 들어간다. 즉, 학습시에는 시퀀스 데이터를 한 번에 부여했는데, 생성시에는 순차적으로 부여된다.
여하튼, Decoder 는 학습시와 문장을 생성할시 동작이 다르기 때문에 Decoder 클래스를 만들 때 생성 함수를 더 만들어야 한다. generate() 함수는 Decoder 가 생성할시 사용하는 함수다.
이때 생성함수는 세 개의 인자를 받는데 그 이전의 `h상태`, `첫 문자`, 그리고 `몇 개 문자를 생성할지 length` 이다.
seq2seq 개선
효율적인 학습과 학습 속도를 개선하는 방법에 대해서 살펴보자.
입력 데이터 반전(Reverse)
입력하는 시퀀스 데이터를 반전해서 입력하면 모델 성능이 개선된다.
직관적으로 왜 그럴까 생각해보면
"나는 고양이로소이다." [인코딩, 디코딩] -> "I am a cat"
에서 "나는" 은 "I" 의 역할을 하고 있는데 기울기 역전파시 그 값이 "고양이","로소","이다" 를 거쳐가야 한다.
따라서, 꽤 먼거리를 지나쳐서 기울기 값이 전달이 되는데 "나는 고양이로소이다" 를 거꾸로 바꾸면 "I" 기울기 값이 직접 전달될 수 있다.
이런 직관적인 이해를 바탕으로 데이터를 반전시키면 성능이 올라갈 수 있다고 생각할 수 있다.
다만, 반전시킨다고 해도 단어 사이의 평균적인 거리는 그대로이다.
엿보기(Peeky)
Encoder 에서 입력된 문장은 하나의 고정된 길이의 벡터로 임베딩되어 은닉상태로 디코더의 입력으로 들어간다.
본래는 Decoder 의 첫 시각의 LSTM 만 이 정보를 받아들였는데, 이 중요한 정보를 좀 더 사용할 수 있지 않을까? 라는 아이디어로 Peeky 가 등장한다.
Encoder 로부터 얻은 은닉 상태를 모든 시각의 Affine 계층과 LSTM 계층의 입력으로 넣는다.
따라서 각 Affine계층과 LSTM 계층은 두 개의 입력 데이터를 가지게 된다.
즉 두 개의 벡터가 각 계층에 들어간다는 건데 이는 실제로 두 벡터가 연결된 것을 의미한다. 따라서 각 계층에 입력할 때 두 벡터를 연결(Concatenate) 해서 입력값으로 넣어야 한다.
이 두 가지 기술 데이터 반전과 엿보기를 통해서 엄청난 개선을 할 수 있다. 하지만 더 크게 개선할 수 있는데, 바로 어텐션이라는 기술이다. 어텐션 기술을 통해서 seq2seq 을 더 크게 개선할 수 있다.
seq2seq 을 이용하는 애플리케이션
크게 4가지 주제로 요약하면
- 기계 번역 : 한 언어의 문장을 다른 언어의 문장으로 번역
- 자동 요약 : 긴 문장을 짧은 문장으로 요약
- 질의응답 : 질문을 응답으로 변환
- 메일 자동 응답 : 받은 메일의 문장을 답변 글로 변환
챗봇
챗봇은 사람과 컴퓨터가 대화를 나누는 프로그램.
회사에서 상담원 대신 사용할 수 있다.
알고리즘 학습
소스 코드 그대로를 학습할 수 있다.
(그것도 sequence 데이터이기 때문에)
이미지 캡셔닝
지금까지는 텍스트 데이터에 한해서 seq2seq를 설명했다.
텍스트 외에도 이미지나 음성 등 다양한 데이터를 처리할 수 있다.
이미지를 문장으로 변환하는 이미지 캡셔닝(Image Captioning).
(이미지 -> 문장, 이미지 캡셔닝)
어려워 보이지만, Decoder 부분은 거의 수정하지 않고 Encoder 부분을 수정하면 된다.
텍스트 데이터에서는 Encoder 부분을 LSTM 을 사용했지만,
이미지는 CNN 을 사용한다. 이미지는 3차원 데이터이기 때문에 CNN을 거친 출력 특징 맵도 3차원 데이터이다.
Decoder 가 데이터를 읽어들일 수 있게 3차원 데이터를 flatten 으로 1차원으로 바꿔준다.
이 바꾼 데이터를 Affine 데이터를 통과시켜서 제련한 후 Decoder 의 입력값으로 넣어준다.
그러면 이미지를 Encoder 로 넣어서 그에 맞는 시퀀스 데이터를 얻을 수 있다.
(이미지를 문장으로 변환한다.)
'NLP > 밑바닥부터 시작하는 딥러닝' 카테고리의 다른 글
어텐션(Attention) (0) | 2022.01.25 |
---|---|
게이트가 추가된 RNN (0) | 2022.01.21 |
순환신경망(RNN) (0) | 2022.01.20 |
word2vec 개선 (4) | 2022.01.19 |
word2vec (0) | 2022.01.18 |