시퀀스 모델링¶
- 이미 시공간에 정의된 수많은 문제를 해결하는 과정에서 중요한 점은 시간의 개념을 적용한다는 것
- 자연어 처리에서도 순차적으로 입력을 넣고, 입력에 따라 모델의 은닉 상태가 순차적으로 변하며, 상태에 따라 출력 결과가 순차적으로 반환되는 함수가 필요함
- 이러한 시간 개념 또는 순서 정보를 사용하여 입력을 학습하는 것을 시퀀셜 모델링이라고 함
- 신경망뿐만 아니라(은닉 마르코프 모델이나 조건부 랜덤 펄드 등의) 다양한 방법을 통해 이런 문제에 접근할 수 있음
- 신경망에서는 순환 신경망(RNN)이라는 아키텍처를 통해 효율적으로 문제를 해결할 수 잇음
1. 순환 신경망¶
자연어 처리에 RNN을 적용하는 사례¶
- 입력: 다수/ 출력: 단일 -> many to one
- 가장 흔한 예제가 감성 분석과 같은 텍스트 분류 예제
- 단어(토큰) 개수만큼 입력이 RNN에 들어가고, 마지막 time-step의 결괏값을 받아서 softmax 함수를 통해 해당 입력 텍스트의 클래스를 예측하는 확률 분포를 근사하도록 동작
- 자연어 처리에서 단어는 불연속적인 이산 분포로부터 샘플링된 샘플.
- x_i는 원핫 벡터로 표현되고, 임베딩 계층을 거쳐 정해진 차원의 단어 임베딩 벡터인 Dense 벡터로 표현되어 RNN에 입력으로 주어짐
- 정답 또한 불연속적 값인 단어 또는 클래스. softmax 함수를 통해 멀티눌리 확률분포를 표현함
- 또한 원래의 정답도 원핫벡터가 되어 교차 엔트로피 손실함수를 통해 sfotmax 결괏값 벡터와 비교하여 손실값을 구함
- 이 때 사실 RNN은 모든 time-step에 대해 출력을 반환하지만, 여기서는 나머지를 버리고 하나의 time-step에 대해서만 값을 취함. 따라서 신경망은 역전파를 통해서 해당 time-step 출력값에 필요한 정보를 모으도록 훈련됨
- [입력: 다수/ 출력: 다수 -> many to many], [입력: 단일/ 출력: 다수 -> one to many]
- 많이 이용하는 방법은 모든 time-step의 출력값을 사용하는 것.
- 언어 모델이나 기계번역으로 구현하는 것에 대해 살펴 보겠지만, 굳이 그런 방법이 아니어도 문장을 입력으로 주고, 단어별 형태소를 분류하는 문제처럼 여러 가지 방법으로 응용 할 수 있음
- 여전히 입력은 불연속적인 값이 되고, 출력 또한 불연속적인 값이 됨.
- 따라서 각 time-step별로 불연속적 샘플인 원핫 벡터를 입력으로 받아 임베딩 계층을 거쳐 Dense 벡터를 만들어 RNN을 거치고, RNN은 time-step 별로 결과물을 출력한 뒤, time-step별로 softmax 함수를 거쳐 이산 확률 분포의 형태로 만듬. 이후 불연속적인 원핫벡터로 구성된 정답과 비교하여 손실을 구함
- 대부분의 경우 RNN은 여러 층과 양방향으로 구현할 수 있음. 하지만 입출력이 서로 같은 데이터를 공유할 경우에는 양방향 RNN을 사용할 수 없음.
- 즉, 이전 time-step의 출력값이 현재 time-step의 입력으로 쓰이는 모델 구조라면 양방향 RNN을 사용할 수 없음.
- 이렇게 이전 자신의 상태(출력)가 현재 자신의 상태를 결정하는 모델을
자기회귀모델(AR)
이라고 함.
정리¶
- 자연어 처리에서 거의 대부분의 입출력 형태는 모두 불연속적인 값을 가짐. 즉, 회귀 문제가 아닌 분류 문제에 가까움. 따라서 우리는 쉽게 교차 엔트로피 손실함수를 사용하여 신경망을 훈련할 수 있음
- 이처럼 RNN은 가변길이의 입력을 받아 가변길이의 출력을 내어줄 수 있는 모델
- 하지만 가장 기초적인 바닐라 RNN은 time-step이 길어질수록 앞의 데이터를 기억하지 못하는 치명적인 단점이 있음.
- 이를 해결하기 위해 LSTM이나 GRU같은 응용 아키텍처들이 나왔고 훌륭한 개선책으로 쓰이는 중
2. LSTM¶
- RNN은 가변길이의 시퀀셜 데이터에 형태 입력에는 훌륭하기 동작하지만, 그 길이가 길어지면 앞서 입력된 데이터를 잊어버리는 단점 존재. 하지만 LSTM의 등장으로 RNN의 단점을 보완할 수 있게 됨
- LSTM은 기존 RNN의 은닉 상태 이외에도 별도의 cell state라는 변수를 두어 그 기억력을 증가시킴
- 그 뿐만 아니라, 여러 가지 gate를 둠으로써 기억하거나, 잊어버리거나, 출력하고자 하는 데이터의 양을 상황에 따라 제어 가능
- 이 때문에 LSTM의 수식은 RNN에 비해 매우 복잡해짐
- 또한 여전히 긴 길이의 데이터에 대해 기억하지 못한다는 문제점은 남아있음
3. GRU¶
- GRU는 LSTM의 간소화 버전. 기존 SLTM이 복잡한 모델인 데 비해 더 간단하면서도 성능이 비슷한 것이 특징
- GRU 또한 LSTM과 마찬가지로 시그모이드로 구성된 reset gate와 update gate가 있음.
- 마찬가지로 시그모이드 함수로 인해 게이트의 출력값은 0과 1사이로 나오므로, 데이터의 흐름을 게이트를 열고 닫아 제어 가능. 기존 LSTM 대비 게이트의 숫자가 줄어들고, 게이트에 딸려있던 파라미터들도 그만큼 줄어듦
- GRU는 LSTM대비 더 가벼운 몸집을 자랑하지만, 아직까지는 LSTM을 사용하는 빈도가 더 높음
4. 그래디언트 클리핑¶
- RNN은 BPTT를 통해 시간에 역행하여 기울기를 구함. 매 time-step마다 RNN의 파라미터에 기울기가 더해지므로, 출력의 길이에 따라 기울기의 크기가 달라짐
- 기울기의 크기인 norm이 너무 큰 경우, 가장 쉬운 대처 방법은 학습률로 아주 작은 값을 취하는 것
- 그래디언트 클리핑은 신경망 파라미터 theta의 norm(보통 L2 norm)을 구하고, 이 norm의 크기를 제한하는 방법
- 따라서 기울기 벡터의 방향은 유지하되, 그 크기는 학습이 망가지지 않을 정도로 줄어들 수 있음
- norm의 최댓값을 사용자가 지정해주어야 하지만, 최댓값보다 큰 norm을 가진 기울기 벡터의 경우에만 그래디언트 클리핑을 수행하므로 능동적으로 학습률을 조절하는 것과 비슷한 효과
- 그래디언트 클리핑은 RNN 계열의 학습 및 훈련에 널리 쓰이는 방법
- 기울기 Norm이 정해진 최댓값보다 클 경우 기울기 벡터를 최댓값보다 큰 만큼의 비율로 나누어줌
- 이는 학습의 발산을 방지함과 동시에 기울기의 방향 자체가 바뀌지 않고 유지되므로, 모델 파라미터 theta가 학습해야 하는 방향을 잃지 않게 함
- 즉, 손실함수를 최소화 하기 위한 기울기의 방향은 유지한채로 크기만 조절함
- 다만, 기존의 SGD가 아닌, 아담과 같은 동적인 학습률을 갖는 optimizer를 사용할 경우라면 굳이 그래디언트 클리핑을 적용하지 않아도 괜찮음.
- 물론 안전장치로 적용하는 것은 괜찮은 생각
- 파이토치에서도 그래디언트 클리핑 기능을 함수를 통해 제공하므로 쉽게 사용가능
In [ ]:
import torch.optim as optim
import torch.nn.utils as torch_utils
learning_rate = 1.
max_grad_norm = 5.
optimizer = optim.SGD(model.parameters(), lr=learning_rate)
# In order to avoid gradient exploding, we apply gradient clipping
torch_utils.clip_grad_norm_(model.parameters(), max_grad_norm)
# Take a step of gradient descent
optimizer.step()
In [ ]:
'자연어, 비전' 카테고리의 다른 글
카카오톡 대화 내용으로 개인별 워드클라우드(wordcloud) 그리기 (1) | 2022.06.22 |
---|---|
transformer 구현 및 설명 (0) | 2021.06.03 |
워드 임베딩 (0) | 2020.11.10 |
단어 유사도 정리 (0) | 2020.11.09 |
자연어 처리를 위한 전처리 과정 정리 (0) | 2020.11.06 |