본문 바로가기

AI/PyTorch

PyTorch #로지스틱 회귀(Logistic Regression)

로지스틱 회귀(Logistic Regression)

- 말은 회귀지만 회귀 모델이 아닌 분류 모델

- 선형 방정식을 사용한 분류 알고리즘, 계산한 값을 0과 1사이로 압축

- 시그모이드 함수(이진 분류) 나 소프트맥스 함수(다중 분류)를 사용해 클래스 확율을 출력 가능

 

 


시그모이드 함수(Sigmoid fuction)

 

1. W가 1이고 b가 0인 그래프 생성

- x가 0일 때 0.5의 출력값을 가짐

- x가 매우 커지면 1에 수렴

- x가 매우 작아지면 0에 수렴

 

# Mtplotlib 과 Numpy 임포트
%matplotlib inline
import numpy as np # 넘파이 사용
import matplotlib.pyplot as plt # 맷플롯립사용

# Numpy를 사용해 시그모이드 함수 정의
def sigmoid(x): # 시그모이드 함수 정의
    return 1/(1+np.exp(-x))
    
x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)

plt.plot(x, y, 'g')
plt.plot([0,0],[1.0,0.0], ':') # 가운데 점선 추가
plt.title('Sigmoid Function')
plt.show()

 

 

2. W값의 변화에 따른 경사도 변화

- W값이 0.5일 때 빨간색, W값이 1일 때 초록색, W의 값이 2일 때 파란색 선

- W값이 커지면 경사가 커지고 W 값이 작아지면 경사가 작아짐

 

x = np.arange(-5.0, 5.0, 0.1)
y1 = sigmoid(0.5*x)
y2 = sigmoid(x)
y3 = sigmoid(2*x)

plt.plot(x, y1, 'r', linestyle='--') # W의 값이 0.5일때
plt.plot(x, y2, 'g') # W의 값이 1일때
plt.plot(x, y3, 'b', linestyle='--') # W의 값이 2일때
plt.plot([0,0],[1.0,0.0], ':') # 가운데 점선 추가
plt.title('Sigmoid Function')
plt.show()

 

 

3. b값의 변화에 따른 좌, 우 이동

- b의 값에 따라서 그래프가 좌, 우로 이동한다.

 

x = np.arange(-5.0, 5.0, 0.1)
y1 = sigmoid(x+0.5)
y2 = sigmoid(x+1)
y3 = sigmoid(x+1.5)

plt.plot(x, y1, 'r', linestyle='--') # x + 0.5
plt.plot(x, y2, 'g') # x + 1
plt.plot(x, y3, 'b', linestyle='--') # x + 1.5
plt.plot([0,0],[1.0,0.0], ':') # 가운데 점선 추가
plt.title('Sigmoid Function')
plt.show()

 

 

4. 시그모이드 함수를 이용한 분류

- 시그모이드 함수는 입력값이 한없이 커지면 1에 수렴, 입력값이 작아지면 0에 수렴

- 시그모이드 함수의 출력값은 0과 1사이의 값을 가짐, 이를 이용해 분류 작업에 사용

 

 

5. 비용 함수(Cost function)

- 시그모이드 함수에서 최적의 W와 b를 찾을 수 있는 함수는 로그 함수

 

 


파이토치로 로지스틱 회귀 구현

 

 

1. 랜덤 시드 지정 후 데이터 로드, 모델 초기화, 옵티마이저 설정 후 학습 진행

 

# 도구 임포트
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# 랜덤 시드 지정
torch.manual_seed(1)

# 데이터셋 텐서로 선언
x_data = [[1, 2], [2, 3], [3, 1], [4, 3], [5, 3], [6, 2]]
y_data = [[0], [0], [0], [1], [1], [1]]
x_train = torch.FloatTensor(x_data)
y_train = torch.FloatTensor(y_data)

# 모델 초기화
W = torch.zeros((2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

# optimizer 설정
optimizer = optim.SGD([W, b], lr=1)

# 학습 실행
nb_epochs = 1000
for epoch in range(nb_epochs + 1):

    # Cost 계산
    hypothesis = torch.sigmoid(x_train.matmul(W) + b)
    # cost = -(y_train * torch.log(hypothesis) + 
    #          (1 - y_train) * torch.log(1 - hypothesis)).mean()
    cost = F.binary_cross_entropy(hypothesis, y_train) # 파이토치에서 제공하는 로지스틱 회귀 비용 함수


    # cost로 H(x) 개선
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 100번마다 로그 출력
    if epoch % 100 == 0:
        print('Epoch {:4d}/{} Cost: {:.6f}'.format(
            epoch, nb_epochs, cost.item()
        ))

 

 

2. 훈련 데이터를 그대로 입력으로 사용했을 때 예측 값 확인

 

# 훈련 데이터를 그대로 입력으로 사용했을 때 예측 값 확인
hypothesis = torch.sigmoid(x_train.matmul(W) + b)
print(hypothesis)

 

 

3. 0.5를 넘으면 True, 넘지 않으면 False로 값을 정하여 출력

 

# 0.5를 넘으면 True, 넘지 않으면 False로 값을 정하여 출력
prediction = hypothesis >= torch.FloatTensor([0.5])
print(prediction)

 

 

4. 훈련이 끝난 상태의 W와 b의 값 출력

 

# 훈련이 끝난 상태의 W와 b의 값 출력
print(W)
print(b)

 

 

 


nn.Module로 구현하는 로지스틱 회귀

 

 

1. 도구 임포트 및 훈련 데이터 선언

 

# 도구 임포트
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# 랜덤 시드 지정
torch.manual_seed(1)

# 훈련 데이터 텐서로 선언
x_data = [[1, 2], [2, 3], [3, 1], [4, 3], [5, 3], [6, 2]]
y_data = [[0], [0], [0], [1], [1], [1]]
x_train = torch.FloatTensor(x_data)
y_train = torch.FloatTensor(y_data)

 

 

2. nn.Sequential()을 사용해 로지스틱 회귀 구현

- nn.Sequential()dms nn.Module 층을 차례로 쌓을 수 있게 해줌

- 수식과 시그모이드 함수 등과 같은 여러 함수들을 연결해주는 역할

 

# nn.Sequential()을 사용해 로지스틱 회귀 구현
model = nn.Sequential(
   nn.Linear(2, 1), # input_dim = 2, output_dim = 1
   nn.Sigmoid() # 출력은 시그모이드 함수를 거친다
)

 

 

3. 모델 훈련

 

# 경사 하강법을 사용해 훈련
# optimizer 설정
optimizer = optim.SGD(model.parameters(), lr=1)

nb_epochs = 1000
for epoch in range(nb_epochs + 1):

    # H(x) 계산
    hypothesis = model(x_train)

    # cost 계산
    cost = F.binary_cross_entropy(hypothesis, y_train)

    # cost로 H(x) 개선
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 20번마다 로그 출력
    if epoch % 10 == 0:
        prediction = hypothesis >= torch.FloatTensor([0.5]) # 예측값이 0.5를 넘으면 True로 간주
        correct_prediction = prediction.float() == y_train # 실제값과 일치하는 경우만 True로 간주
        accuracy = correct_prediction.sum().item() / len(correct_prediction) # 정확도를 계산
        print('Epoch {:4d}/{} Cost: {:.6f} Accuracy {:2.2f}%'.format( # 각 에포크마다 정확도를 출력
            epoch, nb_epochs, cost.item(), accuracy * 100,
        ))

 

 

4. 기존 훈련 데이터로 예측값 확인

 

# 기존 훈련 데이터를 입력해 예측값 확인
model(x_train)

 

 

5. 훈련 후의 W와 b값 출력

 

print(list(model.parameters()))

 

 

 


클래스로 파이토치 모델 구현

 

 

1. 기존 로지스틱 회귀 모델 형태

 

# 기존 로지스틱 회귀 모델
model = nn.Sequential(
   nn.Linear(2, 1), # input_dim = 2, output_dim = 1
   nn.Sigmoid() # 출력은 시그모이드 함수를 거친다
)

 

 

2. 위 내용을 클래스로 구현

 

# 위 내용을 클래스로 구현
class BinaryClassifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(2, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        return self.sigmoid(self.linear(x))

 

 

3. 로지스틱 회귀를 클래스로 구현

 

# 도구 임포트
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# 랜덤 시드 지정
torch.manual_seed(1)

# 데이터 로딩
x_data = [[1, 2], [2, 3], [3, 1], [4, 3], [5, 3], [6, 2]]
y_data = [[0], [0], [0], [1], [1], [1]]
x_train = torch.FloatTensor(x_data)
y_train = torch.FloatTensor(y_data)

# 클래스로 모델 생성
class BinaryClassifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(2, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        return self.sigmoid(self.linear(x))

# 모델 객체 생성
model = BinaryClassifier()

# optimizer 설정
optimizer = optim.SGD(model.parameters(), lr=1)

nb_epochs = 1000
for epoch in range(nb_epochs + 1):

    # H(x) 계산
    hypothesis = model(x_train)

    # cost 계산
    cost = F.binary_cross_entropy(hypothesis, y_train)

    # cost로 H(x) 개선
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 20번마다 로그 출력
    if epoch % 10 == 0:
        prediction = hypothesis >= torch.FloatTensor([0.5]) # 예측값이 0.5를 넘으면 True로 간주
        correct_prediction = prediction.float() == y_train # 실제값과 일치하는 경우만 True로 간주
        accuracy = correct_prediction.sum().item() / len(correct_prediction) # 정확도를 계산
        print('Epoch {:4d}/{} Cost: {:.6f} Accuracy {:2.2f}%'.format( # 각 에포크마다 정확도를 출력
            epoch, nb_epochs, cost.item(), accuracy * 100,
        ))

에포트 160 이후로 생략

 

 


참고:

https://wikidocs.net/book/2788

 

PyTorch로 시작하는 딥 러닝 입문

이 책은 딥 러닝 프레임워크 PyTorch를 사용하여 딥 러닝에 입문하는 것을 목표로 합니다. 이 책은 2019년에 작성된 책으로 비영리적 목적으로 작성되어 출판 ...

wikidocs.net

 

반응형