본문 바로가기

개발 공부/딥러닝

[Deep Learning] PyTorch 모델 평가 | Confusion Matrix와 Heatmap으로 이진분류 결과 확인하기

이번에는 학습된 모델의 Accuracy만 확인하는 것에서 끝나지 않고,

실제값과 예측값을 저장 → Confusion Matrix 생성 → Heatmap으로 시각화

하는 과정까지 이어서 진행했다.

그리고 이 과정에서도 계속 중요하게 등장한 것이 Tensor의 Shape과 데이터 타입이었다.

⠀

1. Accuracy만으로는 어떤 데이터를 틀렸는지 알기 어렵다

앞에서는 모델의 전체 Accuracy를 계산했다.

accuracy = accuracy_fn(
    y_true=targets,
    y_pred=te_round.squeeze()
)

Accuracy를 보면 전체 데이터 중 몇 %를 맞혔는지는 알 수 있다.

하지만 예를 들어 Accuracy가 95%라고 해도

  • 실제 5를 5가 아니라고 얼마나 틀렸는지
  • 실제 5가 아닌 숫자를 5라고 얼마나 틀렸는지

까지는 알 수 없다.

그래서 이번에는 Confusion Matrix를 이용해 실제값과 예측값의 관계를 더 자세히 확인했다.

⠀

2. 다시 확인한 Shape의 중요성

강의에서 다시 강조된 부분은 squeeze()였다.

이진분류 모델의 출력은 마지막 target_size=1이기 때문에 일반적으로

(batch, 1)

형태다.

반면 Target은

(batch,)

형태다.

즉 예를 들어

예측값 : (100, 1)
정답   : (100,)

이 된다.

두 Tensor가 가지고 있는 값의 개수는 같아 보여도 Shape은 다르다.

따라서 예측값을 실제 Target과 비교하려면

te_round.squeeze()

를 사용해

(100, 1)
↓
(100,)

으로 맞춰줘야 한다.

📌 이번 강의에서 다시 강조된 점

함수를 사용한다고 해서 항상 Tensor의 차원이 바뀌는 것은 아니다.

Sigmoid → 값만 변경, Shape 유지
round   → 값만 변경, Shape 유지
squeeze → Shape 변경

따라서 딥러닝에서는 현재 Tensor가 몇 차원인지 계속 확인하는 습관이 중요하다.

⠀

3. Confusion Matrix를 만들려면 실제값과 예측값을 저장해야 한다

Confusion Matrix에는 두 가지 값이 필요하다.

실제값 y_true
예측값 y_pred

하지만 Test DataLoader에서는 Batch 단위로 데이터가 들어오기 때문에, 각 Batch의 결과를 계속 모아야 한다.

그래서 빈 리스트를 먼저 만든다.

그리고 Test Loop를 반복하면서 실제값과 예측값을 저장한다.

⠀

4. append가 아니라 extend를 사용한 이유

여기서 append()와 extend()의 차이도 다시 확인했다.

예를 들어

a = [1, 2, 3]

을 리스트에 넣을 때

result.append(a)

를 사용하면

[[1, 2, 3]]

처럼 리스트 자체가 하나의 원소로 들어간다.

반면

result.extend(a)

를 사용하면

[1, 2, 3]

처럼 각각의 값이 기존 리스트에 이어서 들어간다.

이번에는 Batch별 예측값을 하나의 전체 예측 리스트로 이어붙여야 하기 때문에 extend()를 사용했다.

⠀

5. Tensor를 NumPy로 변환하는 이유

모델 학습과 추론은 PyTorch Tensor를 사용했다.

하지만 이번 Confusion Matrix는 sklearn의 함수를 이용한다.

from sklearn.metrics import confusion_matrix

즉 지금까지 사용하던 PyTorch 영역에서 sklearn 영역으로 넘어가는 것이다.

그래서 Tensor 형태의 값을 NumPy 형태로 변환한다.

te_round.numpy()
targets.numpy()

최종적으로 리스트에 저장한 뒤 다시 NumPy Array로 변환할 수 있다.

np.array(lst_te_y)
np.array(lst_te_pred)

📌 내가 기억할 부분

PyTorch 모델
→ Tensor

sklearn 평가 함수
→ NumPy 사용

처럼 서로 다른 라이브러리를 연결할 때 데이터 타입을 맞춰주는 과정이 필요할 수 있다.

⠀

6. Confusion Matrix 만들기

실제값과 예측값을 모두 모았다면 Confusion Matrix를 계산할 수 있다.

여기서

normalize='true'

를 사용하면 단순한 개수가 아니라 실제 클래스별 비율로 확인할 수 있다.

예를 들어 데이터 개수가 클래스마다 다르면 단순 Count만 비교하는 것보다 비율로 보는 것이 결과를 해석하기 더 편하다.

⠀

7. Heatmap으로 시각화하기

Confusion Matrix를 숫자 배열로만 봐도 되지만, Heatmap으로 표현하면 어느 부분에서 모델이 잘 맞추고 틀리는지 훨씬 쉽게 볼 수 있다.

축을 볼 때는

x축 → Predicted
y축 → Actual

이라는 점을 확인해야 한다.

📌 Heatmap에서 보는 것

대각선 방향의 값은 실제값과 예측값이 일치한 경우다.

반대로 대각선 밖의 값은 모델이 다른 클래스로 잘못 예측한 경우다.

즉 Accuracy 하나만 볼 때보다 어떤 방향의 오분류가 발생했는지까지 확인할 수 있다.

⠀

8. 왜 비율로 보는가

강의에서는 Heatmap을 확인할 때 normalize를 적용해 비율로 표현하는 것을 강조했다.

예를 들어 한 클래스가 1,000개이고 다른 클래스가 100개라면 단순 개수만 비교할 경우 데이터가 많은 클래스의 숫자가 당연히 더 크게 나타난다.

반면 클래스별 비율을 사용하면

실제 Class 0 중 몇 %를 제대로 맞췄는가
실제 Class 1 중 몇 %를 제대로 맞췄는가

처럼 해석할 수 있다.

따라서 클래스별 모델 성능을 비교하기 편해진다.

⠀

9. 이번 실습의 전체 흐름

Test DataLoader
↓
Model
↓
Logit
↓
Sigmoid
↓
round
↓
squeeze
↓
Batch별 예측값 저장
↓
Tensor → NumPy
↓
실제값 / 예측값 전체 수집
↓
Confusion Matrix
↓
normalize
↓
Heatmap

앞에서는 모델을 학습시키는 것이 중심이었다면, 이번에는 학습된 모델의 결과를 어떻게 해석할 것인지까지 연결했다.

⠀

10. 핵심 정리

개념기억할 내용

squeeze (batch, 1)을 (batch,)로 변경
Sigmoid 값은 변경하지만 Shape은 그대로
round 확률을 0/1로 변경하지만 Shape은 그대로
extend Batch별 결과를 하나의 리스트로 이어붙임
.numpy() Tensor를 NumPy 형태로 변환
Confusion Matrix 실제값과 예측값의 관계를 확인
normalize 클래스별 결과를 비율로 확인
Heatmap Confusion Matrix를 시각적으로 확인

이번 실습에서 가장 기억할 부분은,

모델 평가도 결국 Shape과 데이터 타입을 정확하게 이해해야 제대로 연결할 수 있다는 점이다.

단순히 Accuracy가 높다고 끝내는 것이 아니라,

실제값
vs
예측값

을 직접 비교하면서 어떤 데이터를 잘 맞히고 어떤 데이터를 틀리는지 확인하는 과정까지 이어져야 모델을 제대로 평가할 수 있다.

반응형