개발자의 스터디 노트
MLP로 성씨 분류하기 (3) : 평가, 추론, 분석 하기 본문
MLP로 학습한 모델을 평가해보도록 하겠습니다. 평가는 테스트 데이터 셋으로 진행합니다. 훈련 데이터의 정확도가 테스트 데이터의 정확도보다 높게 나옴을 알 수 있습니다. 모델은 항상 훈련하는 데이터에서 더 높은 성능이 나옵니다. 따라서 훈련 세트의 성능이 새로운 데이터에도 적용된다고 생각해서는 안됩니다.
1. 테스트 셋 데이터에서 평가하기
# 가장 좋은 모델을 사용해 테스트 세트의 손실과 정확도를 계산합니다
classifier.load_state_dict(torch.load(train_state['model_filename']))
classifier = classifier.to(args.device)
dataset.class_weights = dataset.class_weights.to(args.device)
loss_func = nn.CrossEntropyLoss(dataset.class_weights)
dataset.set_split('test')
batch_generator = generate_batches(dataset,
batch_size=args.batch_size,
device=args.device)
running_loss = 0.
running_acc = 0.
classifier.eval()
for batch_index, batch_dict in enumerate(batch_generator):
# 출력을 계산합니다
y_pred = classifier(batch_dict['x_surname'])
# 손실을 계산합니다
loss = loss_func(y_pred, batch_dict['y_nationality'])
loss_t = loss.item()
running_loss += (loss_t - running_loss) / (batch_index + 1)
# 정확도를 계산합니다
acc_t = compute_accuracy(y_pred, batch_dict['y_nationality'])
running_acc += (acc_t - running_acc) / (batch_index + 1)
train_state['test_loss'] = running_loss
train_state['test_acc'] = running_acc
print("테스트 손실: {};".format(train_state['test_loss']))
print("테스트 정확도: {}".format(train_state['test_acc']))
테스트 손실: 1.7831668853759768;
테스트 정확도: 46.31249999999999
2. 새로운 성씨 분류하기
새로운 성씨를 분류하는 코드입니다. 문자열로 성씨를 전달하면 이 함수는 먼저 벡터화 과정을 적용한 다음 모델 예측을 만듭니다. apply_softmax 플래그를 True로 설정해서 result에 확률을 담았습니다. 다중 분류임으로 모델 예측은 클래스 확률의 리스트입니다. 파이토치 텐서의 max() 메서를 사용해 확률이 가장 높은 클래스를 선택합니다.
def predict_nationality(surname, classifier, vectorizer):
"""새로운 성씨로 국적 예측하기
매개변수:
surname (str): 분류할 성씨
classifier (SurnameClassifer): 분류기 객체
vectorizer (SurnameVectorizer): SurnameVectorizer 객체
반환값:
가장 가능성이 높은 국적과 확률로 구성된 딕셔너리
"""
vectorized_surname = vectorizer.vectorize(surname)
vectorized_surname = torch.tensor(vectorized_surname).view(1, -1)
result = classifier(vectorized_surname, apply_softmax=True)
probability_values, indices = result.max(dim=1)
index = indices.item()
predicted_nationality = vectorizer.nationality_vocab.lookup_index(index)
probability_value = probability_values.item()
return {'nationality': predicted_nationality, 'probability': probability_value}
new_surname = input("분류하려는 성씨를 입력하세요: ")
classifier = classifier.to("cpu")
prediction = predict_nationality(new_surname, classifier, vectorizer)
print("{} -> {} (p={:0.2f})".format(new_surname,
prediction['nationality'],
prediction['probability']))
분류하려는 성씨를 입력하세요: McMahan
McMahan -> Irish (p=0.43)
3. 새로운 성씨에 대해 최상위 k 개 예측 만들기
def predict_topk_nationality(name, classifier, vectorizer, k=5):
"""새로운 성씨에 대한 최상위 K개 국적을 예측합니다
매개변수:
surname (str): 분류하려는 성씨
classifier (SurnameClassifer): 분류기 객체
vectorizer (SurnameVectorizer): SurnameVectorizer 객체
k (int): the number of top nationalities to return
반환값:
딕셔너리 리스트, 각 딕셔너리는 국적과 확률로 구성됩니다.
"""
vectorized_name = vectorizer.vectorize(name)
vectorized_name = torch.tensor(vectorized_name).view(1, -1)
prediction_vector = classifier(vectorized_name, apply_softmax=True)
probability_values, indices = torch.topk(prediction_vector, k=k)
# 반환되는 크기는 (1,k)입니다
probability_values = probability_values.detach().numpy()[0]
indices = indices.detach().numpy()[0]
results = []
for prob_value, index in zip(probability_values, indices):
nationality = vectorizer.nationality_vocab.lookup_index(index)
results.append({'nationality': nationality,
'probability': prob_value})
return results
new_surname = input("분류하려는 성씨를 입력하세요: ")
classifier = classifier.to("cpu")
k = int(input("얼마나 많은 예측을 보고 싶나요? "))
if k > len(vectorizer.nationality_vocab):
print("앗! 전체 국적 개수보다 큰 값을 입력했습니다. 모든 국적에 대한 예측을 반환합니다. :)")
k = len(vectorizer.nationality_vocab)
predictions = predict_topk_nationality(new_surname, classifier, vectorizer, k=k)
print("최상위 {}개 예측:".format(k))
print("===================")
for prediction in predictions:
print("{} -> {} (p={:0.2f})".format(new_surname,
prediction['nationality'],
prediction['probability']))
분류하려는 성씨를 입력하세요: McMahan
얼마나 많은 예측을 보고 싶나요? 5
최상위 5개 예측:
===================
McMahan -> Irish (p=0.43)
McMahan -> Scottish (p=0.24)
McMahan -> Czech (p=0.07)
McMahan -> Vietnamese (p=0.07)
McMahan -> German (p=0.05)
최상위 예측을 여러 개 확인하면 종종 도움이 됩니다. 예를 들어 NLP에는 최상위 예측 k 개를 선택한 다음 다른 모델을 사용해 순위를 다시 매기는 관행이 있습니다. 파이토치는 이런 예측을 쉽게 얻도록 해주는 torch.topk() 함수를 제공합니다.
'파이썬 > 파이토치 자연어처리' 카테고리의 다른 글
CNN 하이퍼 파라미터 (0) | 2022.02.22 |
---|---|
MLP로 성씨 분류하기 (4) : MLP 규제 적용하기 (0) | 2022.02.19 |
MLP로 성씨 분류하기 (2) : 학습 하기 (0) | 2022.02.19 |
MLP로 성씨 분류하기 (1) : 학습 준비하기 (0) | 2022.02.18 |
다층 퍼셉트론 (0) | 2022.02.17 |