CNN은 이미지에 대해 적용되었다. 그렇다면 이미지가 아닌 단어, 문장 같은 건 어떻게 해야지?
1. RNN
RNN은 시간적으로 연속성이 있는 데이터를 처리하려고 고안한 것이다! 이때 기억이라는 것을 이용한다. 기억이란 현재까지 입력 데이터를 요약한 정보를 말한다. 따라서 새로운 입력이 네트워크로 들어올 때마다 기억을 조금씩 수정한다. 최종적으로 남겨진 기억은 모든 입력 전체를 요약한 정보이다.
=> 사람과 굉장히 유사하지 않은가? 사람도 새로운 정보를 알게되면 이전에 알고 있던 것에서 이를 추가하지 않는가!
위의 그림에 대해서 짧게 설명하겠다.
● 첫번째 입력(x1)이 들어오면 첫번째 기억(h1)이 만들어진다.
● 두번째 입력(x2)이 들어오면 기존 기억(h1)과 새로운 기억을 참고하여 새 기억(h2)을 만든다.
따라서 입력 길이만큼 이 과정을 반복할 수 있고 외부 입력과 자신의 이전 상태를 입력받아 현재 상태를 갱신한다!
RNN은 여러가지 유형을 가진다. 어떤게 있는지 알아보자
# RNN의 유형
● 일대일 : 순환 구조가 아닌, 순방향 네트워크 구조이다.
● 알대다 : 입력이 하나, 출력이 다수이다. ex) 이미지 갱신(이미지를 입력해서 이미지에 대한 설명을 문장으로 출력)
● 다대일 : 입력이 다수, 출력이 하나이다. ex) 감성 분석기(문장을 입력해서 긍정/부정을 출력)
● 다대다 : 입력과 출력이 다수인 구조이다 . 파이토치에서는 시퀀스 투 시퀀스를 이용한다. ex) 언어를 번역하는 자동 번역기
● 동기화 다대다 : 입력과 출력이 다수인 구조이다. ex) 문장에서 다음에 나올 단어 예측, 프레임 수준 모델 예측
아래에 다대일과 다대다 유형을 나타내었다.
정리하자면...
다음 볼 내용은 RNN에서 가장 잘 이해해야할 내용이라고 생각한다.
# RNN 계층과 셀
먼저 계층과 셀의 차이에 대해 알아보자. 계층은 입력된 배치 순서대로 모두 처리하지만 셀은 오직 하나의 단계만 처리한다. 이 차이를 알고있자. 그림을 보면 알 수 있듯이 RNN 계층은 셀을 래핑하여 동일한 셀을 여러 단계에 적용하였다. 셀은 실제 계산에도 사용하고 단일 입력과 과거 상태를 가져와서 출력과 새로운 기억을 생성한다.
=> RNN은 자연어 처리(음성 인식, 단어 의미 판단) 등에 대한 처리가 가능하다! (+손글씨, 시계열 데이터....)
셀과 계층에 대해서도 알았으니 이제 어떤 구조를 가지고 있는지 알아보자
# RNN 구조
x(t-1)에서 h(t-1)을 얻고 다음단계에서 h(t-1)과 xt를 사용하여 과거 정보와 현재 정보를 반영한다.
● Wxh : 입력층에서 은닉층으로 전달되는 가중치
● Whh : t 시점의 은닉층에서 t+1 시점의 은닉층으로 전달되는 가중치
● Wxy : 은닉층에서 출력층으로 전달되는 가중치
이때 가중치들은 모든 시점에 동일하다는 것을 주의하자!!
각 계층과 오차에 대해 더 알아보자
● 은닉층 : 계산을 위해 xt와 h(t-1)이 필요하다. 즉, 이전 은닉층 x 은닉층 →은닉층 가중치+입력층
→ 은닉층 가중치 x 현재 입력값이다!
● 출력층 : 출력층 가중치 x 현재 은닉층에 softmax를 적용하였다. 우리가 흔히 아는 그 방법이다!
위의 식들을 참고하자
우리가 이전에 사용했던 feedforward와는 달리 각 단계마다 오차를 측정한다. 이때 MSE를 Loss Function으로 사용했다.
RNN도 당연히 순방향이 있으면 역전파가 존재한다. 하지만 RNN에서의 역전파는 BPTT를 이용하여 모든 단계마다 처음부터 끝까지 역전파를 진행한다. 즉 각 단계에서 구한 오차를 이용하여 가중치와 바이어스를 업데이트 한다.
여기서 BPTT라는 말을 처음 들어봤을텐데 이는 각 단계마다 오차를 측정하고 이전 단계로 전달하는 것을 말한다. 그래서 BPTT는 오차가 멀리 전파될 수록 계산량이 많아지고 기울기 소실 문제가 발생하는데 이를 해결하기 위해 생략된 BPTT를 사용하거나 LSTM 및 GRU를 사용한다.
일반적으로는 계층의 유닛 개수를 늘리는 것보다 계층 자체의 개수를 늘리는 것이 성능에 좋다. 은닉층 층수는 인공 신경망이 비선형 문제를 조금 더 잘 학습할 수 있도록 해주기 때문이다. 이에 반해 층 안의 뉴런은 가중치와 bias를 업데이트하는 용도로 사용된다. 따라서 우리는 과적합을 주의하여 계층 개수를 잘 조절하여 늘려야 한다!
코드로 셀과 계층을 구현해보았다.
먼저 셀 구조를 한번 보자.
class RNNCell_Encoder(nn.Module):
def __init__(self, input_dim, hidden_size):
super(RNNCell_Encoder, self).__init__()
self.rnn = nn.RNNCell(input_dim, hidden_size) # 훈련 데이터셋의 feature 개수, 은닉층의 개수
def forward(self, inputs):
bz = inputs.shape[1]
ht = torch.zeros((bz, hidden_size)).to(device)
for word in inputs:
ht = self.rnn(word, ht) # 현재의 상태 = 입력 벡터, 이전 상태
return ht
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.em = nn.Embedding(len(TEXT.vocab.stoi), embedding_dim) # 임베딩 : 자연어를 기계가 이해할 수 있는 숫자의 나열인 벡터로 바꾼 결과 or 그 과정 전체
self.rnn = RNNCell_Encoder(embedding_dim, hidden_size) # 암베딩 할 벡터의 차원, 은닉층 개수
self.fc1 = nn.Linear(hidden_size, 256)
self.fc2 = nn.Linear(256, 3)
def forward(self, x):
x = self.em(x)
x = self.rnn(x)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
중간에 임베딩이라는 단어가 보인다. 이게 대체 뭐지?
임베딩은 자연어를 기계가 이해할 수 있는 숫자의 나열인 벡터로 바꾼 결과 or 그 과정 전체를 의미한다!!
계층 구조의 코드도 보자.
class BasicRNN(nn.module):
def __init__(self, n_layers, hidden_dim, n_vocab, embed_dim, n_classes, dropout_p=0.2):
super(BasicRNN, self).__init__()
self.n_layers = n_layers
self.embed = nn.Embedding(n_vocab, embed_dim)
self.hidden_dim = hidden_dim
self.dropout = nn.Dropout(dropout_p)
self.rnn = nn.RNN(embed_dim, self.hidden_dim, num_layers=self.n_layers,
batch_first=True) # 훈련 데이터셋의 특성 개수(칼럼 개수), RNN 개층의 개수
self.out = nn.Linear(self.hidden_dim, n_classes)
def forward(self, x):
x = self.embed(x)
h_0 = self._init_state(batch_size=x.size(0))
x, _ = self.rnn(x, h_0)
h_t = x[:,-1,:]
self.dropout(h_t)
logit = torch.sigmoid(self.out(h_t))
return logit
def _init_state(self, batch_size = 1):
weight = next(self.parameters()).data
return weight.new(self.n_layers, batch_size, self.hidden_dim).zero_()
모델 성능이 좋지 않다면 다른 모델로 변경하여 테스트를 진행해 보아야 한다. 이렇게 여러 유형의 모델을 적용한 후 결과가 가장 좋은 모델을 선택한다. 또한 하이퍼파라미터를 튜닝해 나가는 과정이 필요하므로 데이터 분석은 꽤 많은 시간이 필요한다.
코드를 같이 보면서 이론을 곱씹어보면 잘 이해될 것이다.
다음 시간에는 RNN의 문제를 해결하기 위해 사용하는 LSTM과 GRU에 대해서 알아보자!
'AI > DeepLearning' 카테고리의 다른 글
[DL] Performance Optimization (1) | 2024.11.15 |
---|---|
[DL] LSTM & GRU & 양방향 RNN (0) | 2024.11.15 |
[DL] 시계열 분석 (1) | 2024.11.08 |
[DL] CNN (2) | 2024.11.08 |
[DL] 딥러닝의 구조 (3) | 2024.10.01 |