본문 바로가기
수업 복습/머신러닝과 딥러닝

파이토치로 구현한 논리회귀

by 김복칠 2024. 1. 12.

1. 단항 논리회귀(Logistic Regression) 실습

  • 분류를 할 때 사용하며, 선형 회귀 공식으로부터 나왔기 때문에 논리회귀라는 이름이 붙여짐
  • 직선 하나(선형 회귀)를 사용해서 분류를 예측한다면 제대로 예측하지 못할 경우가 많음

  • SIgmoid 함수 (Logistic 함수)를 사용하여 정확도를 높일 수 있음

2. 시그모이드(Sigmoid) 함수

  • 예측값을 0에서 1사이의 값이 되도록 만듦
  • 0에서 1사이의 연속된 값을 출력으로 하기 때문에 보통 0.5를 기준으로 구분
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

torch.manual_seed(2024)
x_train = torch.FloatTensor([[0], [1], [3], [5], [8], [11], [15], [20]])
y_train = torch.FloatTensor([[0], [0], [0], [0], [0], [1], [1], [1]])
print(x_train.shape)
# 결과 : torch.Size([8, 1])
print(y_train.shape)
# 결과 : torch.Size([8, 1])

model = nn.Sequential(
    nn.Linear(1,1),        
    nn.Sigmoid()           
)
  • 임의의 데이터를 만들어 줍니다
  • 이후 학습을 진행할 모델을 만들어줍니다
  • 여기서 시그모이드는 이지선다, 즉 결과가 두가지 중에 하나를 선택하는 경우에 사용하는 함수라는걸 알 수 있습니다
  • 생성한 모델을 확인해 보면 1차원적 데이터를 받은 뒤 하나의 결과를 반환하는 구조로 만들어져 있습니다
  • 그리고 Linear(학습과정) 이 두개 이상 쌓여있는 경우를 딥러닝 이라고 합니다 
  • 이런 경우에 시그모이드 함수를 사용합니다

3. 비용 함수

  • 논리 회귀에서는 nn.BCELoss() 함수를 사용하여 Loss를 계산
  • Binary Cross Entropy
y_pred = model(x_train)
loss = nn.BCELoss()(y_pred, y_train)
optimizer = optim.SGD(model.parameters(),lr=0.01)

epochs = 1000

for epoch in range(epochs + 1):
    y_pred = model(x_train)
    loss = nn.BCELoss()(y_pred, y_train)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0:
        print(f'Epoch : {epoch}/{epochs} Loss : {loss : 6f}')

print(list(model.parameters()))

x_test = torch.FloatTensor([[12]])
y_pred = model(x_test)

y_bool = (y_pred >= 0.5).float()
print(y_bool)
# 결과 : tensor([[1.]])
  • 이후 학습된 결과를 평가해 보는 과정을 진행해보겠습니다
  • 먼저 만들어진 모델에 데이터를 학습시켜 y_pred를 만들어 줍니다
  • 이후 BCELoss() 함수를 통해 결과와 학습의 차이를 loss라는 변수에 넣어준 뒤 optimizer에 SGD 함수를 사용하여 model의 파라미터를 만들어 줍니다
  • SGD는 랜덤으로 선택한 하나의 데이터에 대해서만 계산하는 경사 하강법입니다
  • 이후 학습을 시켜주고 다시 파라미터를 다시 확인해줍니다
  • 이제 학습이 잘 끝났는지 확인해주기 위해 x_test 데이터를 생성해주고 model에 넣어서 y_pred를 다시 만들어 줍니다
  • 이후 sigmoid 함수 특성을 이용해 0.5 이상일 경우 1이 나오고 미만일경우 0이 출력되는 조건을 만들어서 결과를 확인해 줍니다

4. 다항 논리회기 실습

x_train = [[1, 2, 1, 1],
           [2, 1, 3, 2],
           [3, 1, 3, 4],
           [4, 1, 5, 5],
           [1, 7, 5, 5],
           [1, 2, 5, 6],
           [1, 6, 6, 6],
           [1, 7, 7, 7]]
y_train = [0, 0, 0, 1, 1, 1, 2, 2]

x_train = torch.FloatTensor(x_train)
y_train = torch.LongTensor(y_train)

model = nn.Sequential(
    nn.Linear(4, 3)         # 입력 피처의 개수가 4, 출력 클래스의 개수가 3
)

y_pred = model(x_train)

# CrossEntropyLoss() 함수 안에 소프트맥스 함수가 포함되어 있음
loss = nn.CrossEntropyLoss()(y_pred, y_train)
optimizer = optim.SGD(model.parameters(),lr=0.1)

epochs = 1000

for epoch in range(epochs + 1):
    y_pred = model(x_train)
    loss = nn.CrossEntropyLoss()(y_pred, y_train)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0:
        print(f'Epoch : {epoch}/{epochs} Loss : {loss : 6f}')
        
print(list(model.parameters()))

x_test = torch.FloatTensor([[1, 7, 8, 7]])
y_pred = model(x_test)
y_prob = nn.Softmax(1)(y_pred)

print(f'0일 확률 : {y_prob[0][0]:.2f}')
print(f'1일 확률 : {y_prob[0][1]:.2f}')
print(f'2일 확률 : {y_prob[0][2]:.2f}')
# 결과 : 0일 확률 : 0.00 // 1일 확률 : 0.01 // 2일 확률 : 0.99
  • 다항 논리회귀 실습도 단항과 과정은 같습니다
  • 먼저 데이터를 생성해주고 Tensor 형태로 변환해 줍니다
  • 이때 y_train 은 다항으로 반환 받아야 하기때문에 정수로 받아주어야 합니다
  • 그래서 LongTensor() 를 사용해서 바꾸어 줍니다
  • 이후 모델을 생성해주고 loss와 optimizer를 설정해 줍니다
  • 이때 loss는 CrossEntropyLoss()를 사용해 주는데 이는 다항으로 결과를 반환받기 때문입니다
  • CrossEntropyLoss() 안에는 softmax() 함수가 포함되어 있기 때문에 이를 사용해 줍니다
  • 이후 단항과 같은 과정을 거쳐 결과를 확인해 줍니다

5. 경사 하강법의 종류

5-1. 배치 경사 하강법

  • 가장 기본적인 경사 하강법(Vanilla Gradient Descent)
  • 데이터셋 전체를 고려하여 손실함수를 계산
  • 한 번의 Epoch에 모든 파라미터 업데이트를 단 한번만 수행
  • Batch의 개수와 Iteration은 1이고, Batch Size는 전체 데이터의 갯수
  • 파라미터 업데이트할 때 한 번에 전체 데이터셋을 고려하기 때문에 모델 학습 시 많은 시간과 메모리가 필요하다는 단점

5-2. 학률적 경사 하강법

  • 확률적 경사 하강법(Stochastic Gradient Descent)은 배치 경사 하강법이 모델 학습시 많은 시간과 메모리가 필요하다는 단점을 개선하기 위해 제안된 기법
  • Batch Size를 1로 설정하여 파라미터를 업데이트 하기 때문에 배치 경사 하강법보다 훨씬 빠르고 적은 메무리로 학습이 진행
  • 파라미터 값의 업데이트 폭이 불안정하기 때문에 정확도가 낮은 경우가 생길 수 있음

5-3. 미니 배치 경사 하강법

  • 미니 배치 경사 하강법(Mini-Batch Gradient Descent)은 Batch Size를 설정한 size로 사용하는게 보편적

6. 경사 하강법의 여러가지 알고리즘

6-1. SGD(확률적 경사 하강법)

  • 매개변수 값을 조정 시 전체 데이터가 아니라 랜덤으로 선택한 하나의 데이터에 대해서만 계산하는 방법

6-2. 모멘텀(Momentum)

  • 관성이라는 물리학의 법칙을 응용한 방법
  • 경사 하강법에 관성을 더 해줌
  • 접선의 기울기에 한 시점 이전의 접선의 기울기값을 일정한 비율만큼 반영

6-3. 아다그라드(Adagrad)

  • 모든 매개변수에 동일한 학습률(Learning rate)을 적용하는 것은 비효율적이라는 생각에서 만들어진 학습 방법
  • 처음에는 크게 학습하다가 조금씩 작게 학습시킴

6-4. 아담(Adam)

  • 모멘텀 + 아다그라드

6-5. AdamW

  • Adam optimizer의 변형
  • Adam의 일부 약점(가중치 감소)과 성능 향상을 위해 고안

7. 와인 품종 예측해보기

  • sklearn.datasets.load_wine : 이탈리아의 같은 지역에서 재배된 세가지 다른 품종으로 만든 와인을 화학적으로 분석한 결과에 대한 데이터셋
# 13개의 성분을 분석하여 어떤 와인인지 구별하는 딥러닝 모델을 구축
# 단, 데이터를 섞은 후 train 데이터를 80%, test 데이터를 20%로 하여 테스트
# 데이터의 0번 인덱스가 어떤 와인인지 출력하고 정확도도 출력해보자
# (Adam을 사용, optim.Adam(model.parameters(), lr=0.01))

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split

x_data, y_data = load_wine(return_X_y=True, as_frame=True)
x_data = torch.FloatTensor(x_data.values)
y_data = torch.LongTensor(y_data.values)

x_train, x_test, y_train, y_test = train_test_split(x_data,y_data, test_size=0.2, random_state=2023)

model = nn.Sequential(
    nn.Linear(13, 3)
)
optimizer = optim.Adam(model.parameters(), lr=0.01)

epochs = 1000

for epoch in range(epochs + 1):
    y_pred = model(x_train)
    loss = nn.CrossEntropyLoss()(y_pred, y_train)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if epoch % 100 == 0:
        y_prob = nn.Softmax(1)(y_pred)
        y_pred_index = torch.argmax(y_prob, axis=1)
        y_train_index = y_train
        accuracy = (y_train_index == y_pred_index).float().sum() / len(y_train) * 100
        print(f'Epoch {epoch:4d}/{epochs} Loss:{loss:.6f} Accuracy:{accuracy:.2f}%')
        
y_pred = model(x_test)
y_prob = nn.Softmax(1)(y_pred)

print(f'0번 품종일 확률 : {y_prob[0][0]:.2f}')
print(f'1번 품종일 확률 : {y_prob[0][1]:.2f}')
print(f'2번 품종일 확률 : {y_prob[0][2]:.2f}')
# 결과 : 0번 품종일 확률 : 0.00 // 1번 품종일 확률 : 0.08 // 2번 품종일 확률 : 0.92

 

 

'수업 복습 > 머신러닝과 딥러닝' 카테고리의 다른 글

딥러닝  (0) 2024.01.16
데이터 로더  (1) 2024.01.16
파이토치로 구현한 선형회귀  (2) 2024.01.09
파이토치  (1) 2024.01.09
KMeans(미완성)  (0) 2024.01.09