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