26.8.28 / Fri

BaO·2026년 8월 28일

TIL

목록 보기
12/33

적응적 학습률 (옵티마이저)

  • 가중치가 자주 변경되면 학습률이 낮춰서 미세하게 가중치를 변경
  • 가중치가 거의 변경되지 않으면 학습률을 높인다.

로지스틱 회귀 & 교차 검증

로지스틱 회귀

  • 무한대의 범위를 가지는 선형 회귀의 출력값을 0 ~ 1 사이의 확률값으로 가공하여 분류를 수행하는 분류 모델

Z=w1x1+w2x2+b\text{Z} = w^{1}x^{1} + w^{2}x^{2} + b

선형회귀와 동일하게 가중치를 활용하여 예측값 도출

Z\text{Z} : Logits, 선형회귀와 똑같은 계산식을 사용하여 얻은 예측값

  • 활성화 함수 ( Activation Function )
    • 시그모이드
      • 0 ~ 1 값으로 Logits 값을 변환
      • 예시로 0.7, 0.8, 0.2 가 주어졌을때, 0.5를 기준점으로 잡았다.
      • 0.7, 0.8은 양성 클래스(1),
      • 0.2는 음성 클래스(0)라고 판단한다.

이진 분류 : 클래스가 2가지

  • 활성화 함수 : 시그모이드 함수 ( 0 ~ 1 )

    • Z값이 커질수록 1에 수렴한다.

    • Z값이 작아질수록 0에 수렴

      11+ez\frac{1}{1+e^z}

  • 손실 함수 ( Loss Function )

    • 이진 크로스 엔트로피 - BCE ( Binary Cross Entropy )
      • loss = −(ylog⁡(y^)+(1−y)log⁡(1−y^))-(y\log(\hat{y}) + (1-y)\log(1-\hat{y}))
      • log(1) = 0
      • log(0) = 무한대
      • y^\hat{y} = 예측값 (0 ~ 1 )
      • y : 실제값
        • y = 1, y^\hat{y} = 0 이면 분류를 틀렸다
        • 분류를 틀리면 벌점이 무한에 가까워진다.
        • y = 1, y^\hat{y} = 1 이면 분류를 맞췄다
        • 분류를 맞추면 벌점이 작아진다

이진 분류 모델

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score # 실제 정답과 예측값을 비교하여 모델의 정확도를 계산하는 함수

df = pd.read_csv('Iris.csv') # 데이터 불러오기

df_binary = df[df['Species'].isin(['Iris-setosa', 'Iris-versicolor'])].copy()
# isin은 순차적으로 비교하여 지정한 값이면 반환
# python3 버전 부터 .copy() 없이 하면 복사가 아니라 참조하는 듯, 원본 데이터가 변경 되지 않도록, copy() 사용

X_binary = df_binary[['PetalLengthCm', 'PetalWidthCm']]
y_binary = df_binary['Species'].map({'Iris-setosa' : 0, 'Iris-versicolor' : 1})
# df_binary의 Species의 값을 map함수 통해서 Iris-setosa를 0으로 변환, Iris-versicolor를 1로 변환
# 모델이 영어로 구분하는게 안되서 그런듯 확인해 봐야할듯


# 훈련용 데이터와 테스트용 데이터로 나누기
X_bin_train, X_bin_test, y_bin_train, y_bin_test = train_test_split(
    X_binary, y_binary, test_size=0.2, random_state=42, stratify=y_binary
    # stratify -> 데이터의 비율을 최대한 1ㄷ1로 맞춰줌
)

# 이진 분류 모델 학습
binary_model = LogisticRegression() # 로지스틱 회귀 모델 호출
binary_model.fit(X_bin_train, y_bin_train) # 학습 시작

bin_test_preds = binary_model.predict(X_bin_test) # 테스트 데이터를 활용해서 모델의 예측값 뽑아내는 과정인듯

print(bin_test_preds) # 테스트 데이터를 예측한 값 [1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 1 0 1 1]
print(y_bin_test.values) # 실제 정답 데이터     [1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 1 0 1 1]

# 예측값의 정답률 확인하기
bin_accuracy = accuracy_score(y_bin_test, bin_test_preds) # (원래값, 예측값)
print(f' 이진 분류 테스트 정확도 : {bin_accuracy:.4f}') #  이진 분류 테스트 정확도 : 1.0000

다중 분류

Z=w1x1+w1′′x1′′+w1′′′x1′′′...+b′+b′′+b′′′Z = w_{1}x_{1} + w_{1}^{''}x_{1}^{''} + w_{1}^{'''}x_{1}^{'''} ... + b^{'} + b^{''} + b^{'''}

  • 활성화 함수 : 소프트맥스 ( SoftMax )

    • 여러개 컬럼의 예측값 중에서 가장 값이 높은 것을 선택하는 방식

    • 예측값을 전부 더하면 1이 되는 완벽한 확률 분포를 보인다.

      eZj∑j=1ceZj\frac{e^{Zj}}{\sum_{j=1}^{c} e^{Zj}}

  • One-Hot Encoding

  • 컬럼을 특정할때 0, 1, 2로 나누게 되면 잘못된 중요도로 훈련에 문제가 발생 할 수 있다.

  • 컬럼의 갯수가 3개이면 [1,0,0], [0,1,0], [0,0,1]로 독립적인 공간으로 구분하여 발생할 수 있는 문제를 방지.

  • 다중공선성

  • 차원 수의 기하급수적 증가

    • 분류 갯수가 많아지면 메모리가 부족해지고, 연산량이 증가하므로 모델의 성능이 저하된다.
    • 보완 방법
      • Sparse Categorical Cross Entropy
        • 정답 데이터를 다차원 원-핫 배열로 변환하지 않고 정수형태를 유지하며, 내부적으로 연산을 통해 다중 분류 손실을 계산하여 메모리 효율성이 뛰어나다.
      • Embedding Layer ( 실수 밀집 벡터 )
        • 처리해야 할 카테고리가 몇만개를 넘어설때 효과적인 전처리 기법
        • 실수 형태의 고밀도 연속 벡터 공간으로 압축하여 매핑
        • 정보의 손실 없이, 학습 및 연산 속도를 대폭적으로 끌어올릴 수 있다.
  • 손실 함수 ( Loss Function )

    • CCE ( Categorical Cross Entropy )

      $ \text{Loss} = -\sum{c=1}^{C}y{c}\log{(\hat{y}_c)}$

      • 선택지가 3개 이상인 다중 분류에 사용
      • 정답이면 loss를 적게, 정답이 아니면 loss를 무한대로
      • One-Hot Encodding이 필수적으로 선행 수행 되어야 한다.
    • SCCE ( Sparse Categorical Cross Entory )

      • 정수형 레이블에서 사용
      • 정답 인덱스의 확률값만 추출하여 연산
      • one-hot Encodding을 사용하지 않아서 효율적이다.
        $ \text{Loss} = -\log{(\hat{y}_{target})}$

K-Fold 교차 검증

  • train_test_split을 활용하여 분할하여 검증하는 경우, 테스트 데이터가 우연히 모델에게 유리하게 구성되거나, 동일한 검증만 반복하는 경우를 통해서 모델의 성능이 과대평가 되는 데이터 선택 편향이 발생 할 수 있다.
  • K-Fold 교차 검증을 이용하여 전체 데이터를 K개의 조각으로 공평하게 분할하여 검증을 수행한다.

다중 분류 모델

X_multi = df[['PetalLengthCm', 'PetalWidthCm']]
y_multi = df['Species'].map({'Iris-setosa' : 0, 'Iris-versicolor' : 1, 'Iris-virginica' : 2})

# 다중 분류 훈련 세트, 테스트 세트 분리하기
X_multi_train, X_multi_test, y_multi_train, y_multi_test = train_test_split(
    X_multi, y_multi, random_state=42, test_size=0.2, stratify=y_multi
)

# 다중 분류 모델 학습
multi_model = LogisticRegression()

# 교차 검증 ( K-Fold ) 수행
kf = KFold(n_splits=5, shuffle=True, random_state=42) 
# n_splits -> K의 값을 지정, 데이터를 몇개로 분할하는지 지정
cv_scores = cross_val_score(multi_model, X_multi_train, y_multi_train, cv=kf)
print(f'cv_scores : {cv_scores}')
print(f'교차 검증 정확도 평균 : {cv_scores.mean():.4f}')


multi_model.fit(X_multi_train, y_multi_train)
multi_test_pred = multi_model.predict(X_multi_test)
print(f' 예측한 값 : {multi_test_pred}')
print(f' 원래 값  : {y_multi_test.values}')

multi_accuracy = accuracy_score(y_multi_test, multi_test_pred) # 예측값의 정확도
print(f'정확도 : {multi_accuracy:.4f}')

다층 퍼셉트론 DNN

  • 입력층 -> 은닉층 : Z1=w1x1+b1Z_{1} = w_{1}x_{1} + b_{1}
  • 은닉층 -> 출력층 : Z2=w11Z1+b11Z_{2} = w_{11}Z_{1} + b_{11}
  • 입력층 -> 은닉층 -> 출력층 : Z2=w11(w1x1+b1)+b11Z_{2}= w_{11}(w_{1}x_{1}+b_{1})+b_{11}
    • Z2=wnewx1+bnewZ_{2} = w_{new}x_{1} + b_{new}

은닉층의 활성화 함수 - Activation Function

  • 선형적 -> 비선형적
  • 은닉층을 추가하여 가중치의 개수를 늘리는 이유
    • 모델이 더욱 더 복잡한 패턴을 학습하여 입력데이터의 복잡한 특징과 비선형 관계를 학습하여 정확도를 높이기 위해서.
  • 시그모이드 함수 ( 0 ~ 1 )
    • 입력층의 값이 은닉층에서 0 ~ 1로 압축되는데, 추가적인 은닉층에서 시그모이드 함수를 또 만나면 값이 지속적으로 작아진다.
    • 값이 계속 작아지며 기울기가 작아진다. 기울기가 작아지며 가중치 업데이트를 지속적으로 못하게 되며 결국 제대로 된 학습을 진행 할 수 없다.
    • Gradients 소실 문제
  • Relu 함수
    • max(Z, 0)
    • 음수는 0, 양수는 그대로 통과 시킴

0개의 댓글