Search
Duplicate

6-3 RNN 실습 : 성씨 국적 분류(2)

SurnameClassifier 모델

이제 성씨를 분류하는 모델, SurnameClassifier 모델을 생성해봅니다. 이 모델은 임베딩 층, ElmanRNN 층, 그리고 Linear층으로 구성됩니다. SequenceVocabulary를 통해 정수로 매핑한 토큰을 모델에 입력을 해주면, 먼저 임베딩 층을 사용해 정수를 임베딩합니다. 그 후, RNN으로 시퀀스의 벡터 표현, 즉 성씨의 각 문자에 대한 은닉 벡터를 계산해줍니다. 이때 전체 시퀀스 입력을 거친 결과물은 성씨의 마지막 문자에 해당하는 벡터가 되겠죠? 이제 마지막으로, 이 최종 벡터를 Linear층으로 전달해 예측 벡터를 계산합니다.
SurnameClassifier 모델은 아래 4개의 매개변수를 받습니다.
문자 임베딩 크기(embedding_size 데이터형 int)
임베딩할 문자 개수(num_embeddings 데이터형 int)
클래스 개수(num_classes 데이터형 int)
RNN의 은닉 상태 크기 (rnn_hidden_size 데이터형 int)
이때, 임베딩 크기와 클래스 개수는 데이터에 따라 결정되는 값이지만, 임베딩할 문자 개수와 RNN 은닉 상태 크기는 값을 직접 정해주어야하는 하이퍼파라미터입니다.
class SurnameClassifier(nn.module): '''RNN으로 특성을 추출하고 MLP로 분류하는 분류 모델''' def __init__(self, embedding_size, num_embeddings, num_classes, rnn_hidden_size, batch_first = True, padding_idx = 0): super(SurnameClassifier, self).__init__() self.emb = nn.Embedding(num_embeddings = num_embeddings, embedding_dim = embedding_size, padding_idx = padding_idx) self.rnn = ElmanRNN(input_size = embedding_size, hidden_size = rnn_hidden_size, batch_first = batch_first) self.fc1 = nn.Linear(in_features = rnn_hidden_size, out_features = rnn_hidden_size) self.fc2 = nn.Linear(in_features = rnn_hidden_size, out_features = num_classes) def forward(self, x_in, x_lengths = None, apply_softmax = False): '''분류기의 정방향 계산''' x_embedded = self.emb(x_in) y_out = self.rnn(x_embedded) if x_lengths is not None: y_out = column_gather(y_out, x_lengths) else: y_out = y_out[:, -1, :] y_out = F.dropout(y_out, 0.5) y_out = F.relu(self.fc1(y_out)) y_out = F.dropout(y_out, 0.5) y_out = self.fc2(y_out) if apply_softmax: y_out = F.softmax(y_out, dim = 1) return y_out
Python
복사
forward()는 배치 속 각 시퀀스의 마지막 벡터를 찾아주는 매서드입니다. column() 함수를 이용하여 배치의 행 인덱스를 순회하면서 시퀀스의 마지막 벡터를 추출합니다.
forward() 메서드는 3개의 매개변수를 입력받습니.
입력 데이터 텐서 (x_in 데이터형 torch.Tensor)
배치 속 각 시퀀스의 길이 (x_lengths 데이터형 torch.Tensor)
소프트맥스 활성화 함수를 위한 플래그 (apply_softmax 데이터형 bool)
def column_gather(y_out, x_lengths): '''y_out에 있는 각 데이터 포인트에서 마지막 벡터를 추출합니다.''' x_lengths = x_lengths.long().detach().cpu().numpy() - 1 out = [] for batch_index, column_index in enumerate(x_lengths): out.append(y_out[batch_index, column_index]) return torch.stack(out) ''' 매개변수: y_out (torch.FloatTensor, torch.cuda.FloatTensor) shape: (batch, sequence, feature) x_lengths (torch.LongTensor, torch.cuda.LongTensor) shape: (batch,) 반환값: y_out (torch.FloatTensor, torch.cuda.FloatTensor) shape: (batch, feature) '''
Python
복사

모델 훈련과 결과

우선 배치 하나에 모델을 적용하고 예측 벡터를 계산합니다. 그 후, 손실을 계산하여 손실값과 옵티마이저로 그레이디언트를 구하고 이를 토대로 모델의 가중치를 업데이트합니다. 이 훈련 과정을 모든 배치에 반복해주며 모델의 성능을 높여주는 최적의 하이퍼파라미터를 찾아줍니다.
이전 글 읽기