PyTorch's Binary Classification

duckbill413·2024년 8월 8일
0

PyTorch

목록 보기
5/5
post-thumbnail

Binary Classification (이진 분류 모델)

  • 이진 분류 모델은 데이터를 두 개의 상호 배타적인 카테고리 또는 클래스 중 하나로 분류
  • 예를 들어 이메일이 스팸인지 아닌지, 암 환자가 있는지 없는지 등
  • 주어진 학습 데이터를 사용하여 특징 변수와 목표 변수 사이의 관계를 학습

학습데이터, 테스트데이터의 분리

  • 머신러닝 모델의 성능을 올바르게 평가하기 위해 학습 데이터와 테스트데이터의 분리가 필요하다.
  • sklearntrain_test_split 을 사용해서 간편하게 분리해 볼 수 있다.
from sklearn.model_selection import train_test_split

# 예제 데이터 (X: 특성, y: 레이블)
X = [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
y = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]

# 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

print("훈련 세트:", X_train, y_train)
print("테스트 세트:", X_test, y_test)
  • test_size: test_size 를 30% 로 추출
  • random_state = 42 관습적으로 사용됨
훈련 세트: [[1], [8], [3], [10], [5], [4], [7]] [0, 1, 0, 1, 0, 1, 0]
테스트 세트: [[9], [2], [6]] [0, 1, 1]

Data to Tensor

  • 배치 처리를 위해서는 목표 변수의 형태가 [N, 1] 이 되어야 하므로 Data 를 Tensor로 변환해야 할 수 있음
  • 2차원으로의 변환에는 unsqueeze 함수가 사용됨

Dataset & DataLoader Class

  • 데이터의 로딩과 배치를 관리하는 데 사용되는 중요한 클래스

Dataset

  • Dataset 클래스는 데이터셋을 정의하는 기본 클래스
  • 데이터셋은 입력 데이터와 레이블(타겟)을 저장하고, 데이터의 인덱스를 통해 샘플을 반환하는 역할
  • Dataset 클래스를 상속받아 커스터마이즈할 수 있습니다.
  • 주요 메서드
    • __len__(): 데이터셋의 크기(샘플 수)를 반환합니다.
    • __getitem__(index): 인덱스에 해당하는 데이터를 반환합니다.
from torch.utils.data import Dataset

class CustomDataset(Dataset):
    def __init__(self, data, labels):
        self.data = data
        self.labels = labels

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        sample = self.data[idx]
        label = self.labels[idx]
        return sample, label

DataLoader

  • DataLoader 클래스는 Dataset에서 데이터를 로딩
  • 배치 처리, 셔플, 멀티스레딩 등을 지원하는 도구
  • 학습 및 평가 과정에서 데이터의 배치 처리를 자동으로 수행합니다.
  • 주요 매개변수
    • dataset: Dataset 객체를 입력으로 받습니다.
    • batch_size: 한 배치에 포함할 샘플 수를 지정합니다.
    • shuffle: 데이터를 매 epoch마다 무작위로 섞을지 여부를 지정합니다.
    • num_workers: 데이터 로딩을 병렬 처리할 스레드 수를 지정합니다.
from torch.utils.data import DataLoader

# DataLoader 객체 생성
dataloader = DataLoader(dataset, batch_size=2, shuffle=True, num_workers=1)

# 데이터 로딩 예제
for batch in dataloader:
    samples, labels = batch
    print(samples, labels)

미니 배치 경사하강법

  • 경사 하강법과 확률적 경사하강법 사이의 절충안
  • 데이터셋을 여러 개의 미니 배치로 나누고, 각 미니 배치를 사용하여 기울기를 계산하고 파라미터를 업데이트
  • 학습 과정
    1. 각 미니 배치에 대해 손실 함수를 계산하고 기울기 계산
    2. 기울기를 사용하여 모델 파라미터를 업데이트
    3. 이 과정을 모든 미니 배치에 대해 반복
  • 장점
    • 효율성: 메모리와 계산 자원 소모가 줄어듭니다. 전체 데이터셋을 처리하는 것보다 적은 메모리로도 학습이 가능
    • 속도: 전체 데이터셋을 사용하는 것보다 빠르게 수렴할 수 있음
    • 일반화 성능: 노이즈가 포함된 기울기 업데이트로 인해 모델이 더 잘 일반화될 수 있음
  • 단점
    • 하이퍼파라미터 조정: 미니 배치의 크기와 학습률 등의 하이퍼파라미터 조정이 필요합니다.
    • 변동성: 미니 배치 단위로 업데이트하기 때문에 각 배치에 따라 기울기가 변동성이 있을 수 있습니다.

로지스틱 회귀 알고리즘

로지스틱 회귀(Logistic Regression)는 이진 분류 문제를 해결하기 위해 널리 사용되는 알고리즘입니다. 주로 두 가지 클래스 중 하나로 데이터를 분류하는 데 사용되며, 특히 확률적 해석이 가능한 모델입니다. 로지스틱 회귀는 선형 회귀와 비슷하지만, 출력값을 확률로 변환하여 이진 분류를 수행합니다.

  • 로지스틱 회귀의 원리
    • 선형 함수 로지스틱 회귀는 입력 특징 벡터 x와 파리미터 벡터w의 선형 조합을 계산
      z=wTx+bz = w^Tx + b
      w는 가중치 벡터, b는 편향(basis)
    • 시그모이드 함수 선형 조합 z를 시그모이드 함수를 통과시켜 0과 1사이의 확률로 변환
      σ(z)=11+ez\sigma(z) = \frac{1}{1 + e^{-z}}
      출력값은 클래스 1에 속할 확률 p
    • 결정 경계 로지스틱 회귀는 확률 p가 0.5 보다 크면 클래스 1로, 그렇지 않으면 클래스 0으로 예측
import torch
import torch.nn as nn

class LogisticRegression(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(LogisticRegression, self).__init__()
        # 선형 계층 정의: 입력 차원 -> 출력 차원
        self.linear = nn.Linear(input_dim, output_dim)

    def forward(self, x):
        # 선형 계층을 통해 입력 데이터를 통과시키고 시그모이드 함수 적용
        out = self.linear(x)
        out = torch.sigmoid(out) # sigmoid 를 이용하여 결과 값을 0~1로 압축 
        return out

이진 교차 엔트로피 (Binary Cross Entropy, BCE)

  • 이진 분류 모델의 출력값은 시그모이드 함수의 값으로 0~1의 값을 가진다. 따라서, 해당 값을 0과 1로 분류하기 위해 이진 교차 엔트로피(Binary Cross Entropy, BCE) 를 사용함
  • 이진 분류 문제에서 모델의 예측 성능을 평가하기 위해 사용되는 손실 함수
  • 모델이 입력 데이터에 대해 특정 클래스일 확률을 출력
  • PyTorch에서는 교차 엔트로피 손실 함수를 nn.BCELoss클래스를 통해 사용할 수 있음
  • 이진 교차 엔트로피 손실 함수
    L(y,y^)=[ylog(y^)+(1y)log(1y^)]L(y, \hat{y}) = - \left[ y \log(\hat{y}) + (1 - y) \log(1 - \hat{y}) \right]
  • 전체 데이터셋에 대한 손실 함수
    E(W,b)=i=1N[tilog(yi)+(1ti)log(1yi)]E(W, b) = -\sum_{i=1}^{N} \left [t_i \log(y_i) + (1 - t_i) \log(1 - y_i) \right]
  • 최대 가능도 추정 (Maximum Likelihood Estimation, MLE)
    • 최대 가능도 추정은 주어진 데이터가 관측될 확률을 최대화하는 파라미터를 찾는 방법
    • 이진 교차 엔트로피 손실 함수는 실제 레이블과 모델의 예측 확률 사이의 차이를 측정하며, 최대 가능도 추정(MLE)은 모델의 파라미터를 관측된 데이터의 가능도를 최대화하는 방향으로 추정합니다.
    • 이진 교차 엔트로피 손실 함수로그 가능도 함수의 음수로 해석할 수 있으므로, 이진 교차 엔트로피 손실 함수를 최소화하는 과정은 MLE를 통해 파라미터를 추정하는 것과 동일한 결과를 제공합니다.

로지스틱 회귀 데이터의 학습 실습

  • 미니 배치를 사용한 로지스틱 회귀 모델을 학습하는 예제 코드
  • PyTorch의 DataLoader 를 사용하여 미니 배치로 데이터를 불러오고, 각 미니배치에 대해 모델을 학습시키는 방식을 사용
  1. 데이터 준비 및 DataLoader 생성

    import torch
    import torch.nn as nn
    import torch.optim as optim
    from torch.utils.data import DataLoader, TensorDataset
    
    # Logistic Regression 모델 정의
    class LogisticRegression(nn.Module):
        def __init__(self, input_dim, output_dim):
            super(LogisticRegression, self).__init__()
            self.linear = nn.Linear(input_dim, output_dim)
        
        def forward(self, x):
            out = self.linear(x)
            out = torch.sigmoid(out)
            return out
    
    # 입력 데이터 및 레이블 (예시 데이터)
    X_train = torch.tensor([[1.0, 2.0], [2.0, 3.0], [3.0, 4.0], [4.0, 5.0], [5.0, 6.0], [6.0, 7.0]], dtype=torch.float32)
    y_train = torch.tensor([[0.0], [0.0], [1.0], [1.0], [1.0], [0.0]], dtype=torch.float32)
    
    # TensorDataset과 DataLoader를 사용하여 데이터셋을 미니배치로 나누기
    dataset = TensorDataset(X_train, y_train)
    dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
  2. 모델 및 학습 설정

    # 모델 초기화
    input_dim = X_train.shape[1]  # 입력 피처의 수
    output_dim = 1                # 출력 차원 (이진 분류의 경우 1)
    model = LogisticRegression(input_dim, output_dim)
    
    # 손실 함수 및 옵티마이저 정의
    criterion = nn.BCELoss()  # Binary Cross-Entropy Loss
    optimizer = optim.SGD(model.parameters(), lr=0.01)
    
    # 학습 설정
    num_epochs = 1000  # 전체 학습 반복 횟수
  3. 학습 루프

    # 모델을 학습 모드로 설정
    model.train()
    
    # 학습 루프
    for epoch in range(num_epochs):
        epoch_loss = 0.0
        
        for batch in dataloader:
            X_batch, y_batch = batch  # 미니배치 불러오기
            
            # 순전파: 모델에 입력 데이터를 전달하여 출력값 계산
            outputs = model(X_batch)
            
            # 손실 계산
            loss = criterion(outputs, y_batch)
            
            # 역전파 및 옵티마이저 스텝 (파라미터 업데이트)
            optimizer.zero_grad()  # 옵티마이저의 기울기 초기화
            loss.backward()        # 역전파를 통해 기울기 계산
            optimizer.step()       # 옵티마이저가 파라미터 업데이트
            
            # 배치 손실을 누적
            epoch_loss += loss.item() * X_batch.shape[0]
        
        # 평균 손실 계산
        epoch_loss /= len(dataset)
        
        # 학습 진행 상황 출력 (매 100 에포크마다)
        if (epoch + 1) % 100 == 0:
            print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.4f}')
    
    # 학습이 끝나면 모델을 평가 모드로 전환
    model.eval()
    
    # 평가 모드에서 모델 테스트 (예시 데이터)
    with torch.no_grad():  # 평가 시에는 기울기 계산을 하지 않음
        test_outputs = model(X_train)
        print("Test outputs after training:", test_outputs)
  4. 결과 확인

    • 학습 모드 결과
      Epoch [100/1000], Loss: 0.7071
      Epoch [200/1000], Loss: 0.6871
      Epoch [300/1000], Loss: 0.6651
      Epoch [400/1000], Loss: 0.6644
      Epoch [500/1000], Loss: 0.6619
      Epoch [600/1000], Loss: 0.6909
      Epoch [700/1000], Loss: 0.6869
      Epoch [800/1000], Loss: 0.6610
      Epoch [900/1000], Loss: 0.6928
      Epoch [1000/1000], Loss: 0.6928
    • 평가 모드 결과
      tensor([[0.3268],
              [0.3961],
              [0.4699],
              [0.5450],
              [0.6181],
              [0.6862]])
profile
같이 공부합시다~

0개의 댓글

관련 채용 정보