Data science/딥러닝

[딥러닝] 5. 다중 클래스 분류 모델링 - Iris

endingo 2025. 4. 7. 19:50

★ 다중클래스 분류의 목적함수는 CrossEntropyLoss()

★ 다중클래스 분류의 활성화함수는 Softmax() 지정할 필요없음

★ 은닉층의 활성화함수는 ReLU()

★ 다중클래스의 가변수화는 integer incoding

 

 

1. 데이터 준비

 

1) 데이터 준비

 

data.drop(target, axis=1): target은 없애고 특성수만 존재하도록

data.loc[:,target]: target만 존재하도록

target = 'Species'
x = data.drop(target, axis = 1)
y = data.loc[:, target]

 

 

 

2)  integer encoding - 다중클래스의 가변수화

 

- 다중 클래스 분류 모델링을 위해서는 y는 integer encoding을 먼저 수행해야됨

- LabelEncoder()는 문자열로 된 클래스를 정수로 변환해주는 클래스

- fit_transform(y)는 y 데이터에 있는 고유 클래스들을 학습하고, 각각을 0부터 시작하는 정수로 바꿔준다.

 

예를 들어, ['setosa', 'versicolor', 'virginica']가 있다면,

  • setosa → 0
  • versicolor → 1
  • virginica → 2
le = LabelEncoder()
y = le.fit_transform(y)
y[:5]

 

앞의 5개만 출력했다 => 모두 setosa였네?

 

 

- le.classes: 어떤 클래스들이 어떤 숫자로 매핑되었는지 확인 0부터 시작이다.

le.classes_

 

- le.inverse_transform(y): 다시 문자열로 되돌리고 싶으면

le.inverse_transform(y)

 

 

3) 데이터 분할

train_test_split()

훈련용: x_train, y_train

검증용: x_val, y_val

x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=.3, random_state = 20)

 

4) 스케일링

범위값을 같게 조정

scaler.fit_transform

scaler = MinMaxScaler()
x_train = scaler.fit_transform(x_train)
x_val = scaler.transform(x_val)

 

2. 모델링

 

1) 딥러닝을 위한 준비작업

어레이 => 텐서 => 텐서 조합결합 => 데이터 로더

train_loader, x_val_ts, y_val_ts = make_DataSet(x_train, x_val, y_train, y_val, 32)

 

- 잘 전달됐는지 확인

# 첫번째 배치만 로딩해서 살펴보기
for x, y in train_loader:
    print(f"Shape of x [rows, columns]: {x.shape}")
    print(f"Shape of y: {y.shape} {y.dtype}")
    break

 

배치: 32

특성수: 4 

 

2) 모델선언

 

다중 클래스 분류 같은 경우는  목적함수에 활성화함수가 포함되어있기에 신경망만 선언해주면됨

n_feature = x.shape[1]
# 외우기
n_class = len(le.classes_)

# 모델 구조 설계
model = nn.Sequential(
            nn.Linear(n_feature, n_class),  # 출력층 활성화 함수를 지정하지 않음
        ).to(device)

print(model)

 

특성수 4로 들어와서 3개의 다중 클래스로 분류되는 신경망

 

3) 목적함수, 옵티마이저 선언

 

nn.CrossEntropyLoss(): 내부에 softmax있음

Adam()

loss_fn = nn.CrossEntropyLoss()       # Cross Entropy : 이 손실 함수는 내부에 SoftMax 연산이 포함(출력층 활성화함수 지정 안함)
optimizer = Adam(model.parameters(), lr=0.1)

 

4) 모델 훈련

epochs = 100
tr_loss_list, val_loss_list = [], []

for t in range(epochs):
    tr_loss = train(train_loader, model, loss_fn, optimizer, device)
    val_loss,_ = evaluate(x_val_ts, y_val_ts, model, loss_fn, device)

    # 리스트에 loss 추가 --> learning curve 그리기 위해.
    tr_loss_list.append(tr_loss)
    val_loss_list.append(val_loss)

    print(f"Epoch {t+1}, train loss : {tr_loss:4f}, val loss : {val_loss:4f}")

 

- 학습된 파라미터 확인

for name, param in model.named_parameters():
    if param.requires_grad:
        print(f"Parameter: {name}, Value: {param.data}")

 

- 학습 곡선

dl_learning_curve(tr_loss_list, val_loss_list)

5) 모델 평가

- 예측결과를 nn.Softmax함수로 변환 => 확률값

- 그 중 가장 큰 값의 인덱스로 변환 => np.argmax()

 

ⅰ. 예측결과를 일단 확인

evaluate()

# 1. 예측결과
_, pred = evaluate(x_val_ts, y_val_ts, model, loss_fn, device)

# 다중 분류의 예측 결과는 2차원 구조
pred.numpy()[:5]

 

ⅱ. 결과값을 SoftMAX로 변환

nn.functional.softmax()

# 2. softmax로 변환
pred = nn.functional.softmax(pred, dim=1)
pred[:5]

확률값으로 변환되었다.

ⅲ. 가장 큰 값의 인덱스를 표시하여 클래스 분류를 하는ㄱ

# 3. 가장 큰 값의 인덱스
pred = np.argmax(pred.numpy(), axis = 1)
pred[:5]

첫번째 행에서 가장 확률이 높은 것 0 세토사

두번째 행에서 가장 확률이 높은 것  1 버지칼라

세번째 행에서 가장 확률이 높은 것  1 버지칼라

네번째 행에서 가장 확률이 높은 것  2 버지니카

마지막 행에서 가장 확률이 높은 것  1 버지칼라

 

6) 혼동행렬에서 정보뽑기

confusion_matrix(y_val_ts.numpy(), pred)

print(classification_report(y_val_ts.numpy(), pred, target_names=le.classes_))

3. 은닉층 추가

 

1) 모델선언

다중 클래스 분류에서 은닉층은 ReLU()로 사용하고

마지막 활성함수는 Cross 목적함수가 softmax 함수를 품고있으므로 선언 안 해도된다.

n_feature = x.shape[1]
n_class = len(le.classes_)

# 모델 구조 설계
model = nn.Sequential(
            nn.Linear(n_feature, 4),
            nn.ReLU(),
            nn.Linear(4, 3),
            nn.ReLU(),
            nn.Linear(3, n_class),
        ).to(device)

print(model)

 

모델 평가일 때 각 각의 클래스의 예측값 구하기 => 확률화 => 확률 가장 높은 애 선택