코딩(Coding)/기계학습

[기계학습] 로지스틱 회귀(분류 Classification)(Logistic Regression) (Part 2/2)

J.S.Y 2022. 1. 25. 22:17
728x90

이전 포스팅의 개념적인 부분을 python의 pytorch 패키지를 통해 구현하는 포스팅입니다.
이전 포스팅을 보고오세요~ :D (https://jsy-coding-blog.tistory.com/47)
포스팅에서 사용하는 PPT 자료는 제 Github에서 pdf 형식으로 받을 수 있습니다.

(https://github.com/JoSangYeon/Machine_Learning_Project/blob/master/PPT/01.%20Machine%20Learning.pdf)

Logistic Regression

분류 문제

지난 포스팅 복습

image

 

image

 

image

 

image

코드 실습(With Pytorch)

패키지 Import

import numpy as np
import pandas as pd

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader

print(torch.__version__)
1.10.1

예제 Data 생성

# 예제
x_data = [[0],[2],[1],[9],[10]]
y_data = [[0],[0],[0],[1],[1]]

X = torch.tensor(np.array(x_data)).float()
Y = torch.tensor(np.array(y_data)).float()

print(X)
print(Y)
tensor([[ 0.],
        [ 2.],
        [ 1.],
        [ 9.],
        [10.]])
tensor([[0.],
        [0.],
        [0.],
        [1.],
        [1.]])

예제로 사용할 데이터는 간단하게 PPT에서 봤던 데이터이다.
x가 0

5이면 Y는 0이고 5

10이면 Y는 1이다.

Model 정의(가설 정의)

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()

        self.fc1 = nn.Linear(1, 1)

        self.act_fn = nn.Sigmoid()

    def forward(self, input):
        x = self.fc1(input)
        x = self.act_fn(x)
        return x

model = MyModel()
opt = optim.Adam(model.parameters())
loss_fn = nn.BCELoss()

print(model)
MyModel(
  (fc1): Linear(in_features=1, out_features=1, bias=True)
  (act_fn): Sigmoid()
)

모델은 간단하게 nn.Module로 sub-Classing하였다.
모델의 연산은 다음과 같다.(forward() 메소드 참고)

  1. input_Node : 1, output_Node : 1인 Linear Layer를 정의한다.
  2. 해당 Linear Layer의 output을 Sigmoid 함수에 대입한다.

모델 학습

# 학습
model.train()
for epoch in range(1, 1001):
    x, y = X, Y

    opt.zero_grad()

    output = model(x)
    loss = loss_fn(output, y)

    loss.backward()
    opt.step()

    if epoch % 25 == 0:
        print("EPOCH {}  >>>  Loss : {:.5f}".format(epoch, loss))
EPOCH 25  >>>  Loss : 0.96217
EPOCH 50  >>>  Loss : 0.93793
EPOCH 75  >>>  Loss : 0.91404
EPOCH 100  >>>  Loss : 0.89053
EPOCH 125  >>>  Loss : 0.86741
EPOCH 150  >>>  Loss : 0.84471
EPOCH 175  >>>  Loss : 0.82245
EPOCH 200  >>>  Loss : 0.80066
EPOCH 225  >>>  Loss : 0.77935
EPOCH 250  >>>  Loss : 0.75858
EPOCH 275  >>>  Loss : 0.73837
EPOCH 300  >>>  Loss : 0.71877
EPOCH 325  >>>  Loss : 0.69983
EPOCH 350  >>>  Loss : 0.68159
EPOCH 375  >>>  Loss : 0.66413
EPOCH 400  >>>  Loss : 0.64750
EPOCH 425  >>>  Loss : 0.63176
EPOCH 450  >>>  Loss : 0.61699
EPOCH 475  >>>  Loss : 0.60323
EPOCH 500  >>>  Loss : 0.59052
EPOCH 525  >>>  Loss : 0.57887
EPOCH 550  >>>  Loss : 0.56828
EPOCH 575  >>>  Loss : 0.55868
EPOCH 600  >>>  Loss : 0.55000
EPOCH 625  >>>  Loss : 0.54213
EPOCH 650  >>>  Loss : 0.53493
EPOCH 675  >>>  Loss : 0.52826
EPOCH 700  >>>  Loss : 0.52201
EPOCH 725  >>>  Loss : 0.51606
EPOCH 750  >>>  Loss : 0.51033
EPOCH 775  >>>  Loss : 0.50475
EPOCH 800  >>>  Loss : 0.49927
EPOCH 825  >>>  Loss : 0.49388
EPOCH 850  >>>  Loss : 0.48854
EPOCH 875  >>>  Loss : 0.48325
EPOCH 900  >>>  Loss : 0.47801
EPOCH 925  >>>  Loss : 0.47280
EPOCH 950  >>>  Loss : 0.46764
EPOCH 975  >>>  Loss : 0.46251
EPOCH 1000  >>>  Loss : 0.45743

Loss가 순차적으로 줄어든 것을 볼 수 있다.

성능 검증

# 성능 검증
# X, Y를 그대로 넣어서 제대로 분류하는 확인
def decision_boundary(output):
    return (output >= torch.tensor([0.5])).float()

model.eval()

output = model(X)
output = decision_boundary(output)
print("모델이 예측한 값 :",output.view(-1))
print("실제 값 : ", Y.view(-1))
print("정확도 : {}%".format(((output == Y).view(-1).sum() / 5. * 100.).item()))
모델이 예측한 값 : tensor([0., 1., 0., 1., 1.])
실제 값 :  tensor([0., 0., 0., 1., 1.])
정확도 : 80.0%

1000번을 학습하고 기존의 X,Y를 대입해보았다.
Train 데이터에 대해서 정확도는 80%(5개중 4개 맞았다.)

새로운 데이터가 추가 되었다.

데이터 정의

# 예제
x_data = [[0],[2],[1],[9],[10],[20],[5]]
y_data = [[0],[0],[0],[1],[1], [1], [0]]

X = torch.tensor(np.array(x_data)).float()
Y = torch.tensor(np.array(y_data)).float()

print(X)
print(Y)
tensor([[ 0.],
        [ 2.],
        [ 1.],
        [ 9.],
        [10.],
        [20.],
        [ 5.]])
tensor([[0.],
        [0.],
        [0.],
        [1.],
        [1.],
        [1.],
        [0.]])

모델 정의

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()

        self.fc1 = nn.Linear(1, 1)

        self.act_fn = nn.Sigmoid()

    def forward(self, input):
        x = self.fc1(input)
        x = self.act_fn(x)
        return x

model = MyModel()
opt = optim.Adam(model.parameters())
loss_fn = nn.BCELoss()

print(model)
MyModel(
  (fc1): Linear(in_features=1, out_features=1, bias=True)
  (act_fn): Sigmoid()
)

학습

# 학습
model.train()
for epoch in range(1, 1001):
    x, y = X, Y

    opt.zero_grad()

    output = model(x)
    loss = loss_fn(output, y)

    loss.backward()
    opt.step()

    if epoch % 25 == 0:
        print("EPOCH {}  >>>  Loss : {:.5f}".format(epoch, loss))
EPOCH 25  >>>  Loss : 0.87950
EPOCH 50  >>>  Loss : 0.80764
EPOCH 75  >>>  Loss : 0.74866
EPOCH 100  >>>  Loss : 0.70152
EPOCH 125  >>>  Loss : 0.66421
EPOCH 150  >>>  Loss : 0.63451
EPOCH 175  >>>  Loss : 0.61047
EPOCH 200  >>>  Loss : 0.59060
EPOCH 225  >>>  Loss : 0.57378
EPOCH 250  >>>  Loss : 0.55923
EPOCH 275  >>>  Loss : 0.54639
EPOCH 300  >>>  Loss : 0.53487
EPOCH 325  >>>  Loss : 0.52439
EPOCH 350  >>>  Loss : 0.51474
EPOCH 375  >>>  Loss : 0.50575
EPOCH 400  >>>  Loss : 0.49733
EPOCH 425  >>>  Loss : 0.48937
EPOCH 450  >>>  Loss : 0.48181
EPOCH 475  >>>  Loss : 0.47461
EPOCH 500  >>>  Loss : 0.46770
EPOCH 525  >>>  Loss : 0.46107
EPOCH 550  >>>  Loss : 0.45468
EPOCH 575  >>>  Loss : 0.44851
EPOCH 600  >>>  Loss : 0.44254
EPOCH 625  >>>  Loss : 0.43676
EPOCH 650  >>>  Loss : 0.43114
EPOCH 675  >>>  Loss : 0.42569
EPOCH 700  >>>  Loss : 0.42038
EPOCH 725  >>>  Loss : 0.41521
EPOCH 750  >>>  Loss : 0.41017
EPOCH 775  >>>  Loss : 0.40525
EPOCH 800  >>>  Loss : 0.40046
EPOCH 825  >>>  Loss : 0.39577
EPOCH 850  >>>  Loss : 0.39119
EPOCH 875  >>>  Loss : 0.38672
EPOCH 900  >>>  Loss : 0.38234
EPOCH 925  >>>  Loss : 0.37805
EPOCH 950  >>>  Loss : 0.37385
EPOCH 975  >>>  Loss : 0.36974
EPOCH 1000  >>>  Loss : 0.36571

성능 검증

# 성능 검증
# X, Y를 그대로 넣어서 제대로 분류하는 확인
def decision_boundary(output):
    return (output >= torch.tensor([0.5])).float()

model.eval()

output = model(X)
output = decision_boundary(output)
print("모델이 예측한 값 :",output.view(-1))
print("실제 값 : ", Y.view(-1))
print("정확도 : {:.2f}%".format(((output == Y).view(-1).sum() / 7. * 100.).item()))
모델이 예측한 값 : tensor([0., 0., 0., 1., 1., 1., 1.])
실제 값 :  tensor([0., 0., 0., 1., 1., 1., 0.])
정확도 : 85.71%

다변수 회귀 분류

PPT 복습

image

 

image

 

image

 

image

학습 데이터 정의

# 예제
x_data = [[1.2, 3.4],[1.1, 3.2],[1.5, 3.7],
          [5.2, 0.7],[4.7, 0.6],[5.6, 0.9],
          [7.7, 6.6],[7.5, 7.2],[8.1, 6.2]]
y_data = [0,0,0,
          1,1,1, 
          2,2,2]

X = torch.tensor(x_data)
Y = torch.tensor(y_data)

print(X)
print(Y)
tensor([[1.2000, 3.4000],
        [1.1000, 3.2000],
        [1.5000, 3.7000],
        [5.2000, 0.7000],
        [4.7000, 0.6000],
        [5.6000, 0.9000],
        [7.7000, 6.6000],
        [7.5000, 7.2000],
        [8.1000, 6.2000]])
tensor([0, 0, 0, 1, 1, 1, 2, 2, 2])

Feature는 2개이고 Label은 1이다.

Label : One-Hot Encoding

# Label을 3개의 클래스를 가지도록 one-hot encoding 해줌
Y = F.one_hot(Y, num_classes=3).float()
Y
tensor([[1., 0., 0.],
        [1., 0., 0.],
        [1., 0., 0.],
        [0., 1., 0.],
        [0., 1., 0.],
        [0., 1., 0.],
        [0., 0., 1.],
        [0., 0., 1.],
        [0., 0., 1.]])

3개의 Y값을 가지기 때문에, One-Hot Encoding을 통해 label값을 변경해준다.

모델 정의

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()

        self.fc1 = nn.Linear(2, 3)

        self.act_fn = nn.Softmax(dim=1)

    def forward(self, input):
        x = self.fc1(input)
        x = self.act_fn(x)
        return x

model = MyModel()
opt = optim.Adam(model.parameters())
loss_fn = nn.CrossEntropyLoss()

print(model)
MyModel(
  (fc1): Linear(in_features=2, out_features=3, bias=True)
  (act_fn): Softmax(dim=1)
)

모델은 다음과 같다.

  1. input_Node : 2, output_Node 3을 가지는 Linear Layer를 정의한다.
  2. Linear Layer의 결과값을 softmax함수에 대입하여 확률값으로 변환한다.
    • 각 노드의 값은 해당 input이 해당 Label일 확률을 의미한다.
  3. 최적화 알고리즘은 Adam을 사용했고, 오차함수는 Cross-Entropy이다.

학습

# 학습
model.train()
for epoch in range(1, 1501):
    x, y = X, Y

    opt.zero_grad()

    output = model(x)
    loss = loss_fn(output, y)

    loss.backward()
    opt.step()

    if epoch % 25 == 0:
        print("EPOCH {}  >>>  Loss : {:.5f}".format(epoch, loss))
EPOCH 25  >>>  Loss : 1.02031
EPOCH 50  >>>  Loss : 1.00895
EPOCH 75  >>>  Loss : 0.99802
EPOCH 100  >>>  Loss : 0.98769
EPOCH 125  >>>  Loss : 0.97803
EPOCH 150  >>>  Loss : 0.96896
EPOCH 175  >>>  Loss : 0.96031
EPOCH 200  >>>  Loss : 0.95159
EPOCH 225  >>>  Loss : 0.94148
EPOCH 250  >>>  Loss : 0.92642
EPOCH 275  >>>  Loss : 0.90064
EPOCH 300  >>>  Loss : 0.86479
EPOCH 325  >>>  Loss : 0.82898
EPOCH 350  >>>  Loss : 0.79900
EPOCH 375  >>>  Loss : 0.77486
EPOCH 400  >>>  Loss : 0.75522
EPOCH 425  >>>  Loss : 0.73892
EPOCH 450  >>>  Loss : 0.72510
EPOCH 475  >>>  Loss : 0.71318
EPOCH 500  >>>  Loss : 0.70275
EPOCH 525  >>>  Loss : 0.69351
EPOCH 550  >>>  Loss : 0.68525
EPOCH 575  >>>  Loss : 0.67780
EPOCH 600  >>>  Loss : 0.67103
EPOCH 625  >>>  Loss : 0.66486
EPOCH 650  >>>  Loss : 0.65920
EPOCH 675  >>>  Loss : 0.65399
EPOCH 700  >>>  Loss : 0.64917
EPOCH 725  >>>  Loss : 0.64471
EPOCH 750  >>>  Loss : 0.64056
EPOCH 775  >>>  Loss : 0.63669
EPOCH 800  >>>  Loss : 0.63309
EPOCH 825  >>>  Loss : 0.62971
EPOCH 850  >>>  Loss : 0.62654
EPOCH 875  >>>  Loss : 0.62357
EPOCH 900  >>>  Loss : 0.62078
EPOCH 925  >>>  Loss : 0.61815
EPOCH 950  >>>  Loss : 0.61567
EPOCH 975  >>>  Loss : 0.61332
EPOCH 1000  >>>  Loss : 0.61111
EPOCH 1025  >>>  Loss : 0.60901
EPOCH 1050  >>>  Loss : 0.60702
EPOCH 1075  >>>  Loss : 0.60513
EPOCH 1100  >>>  Loss : 0.60334
EPOCH 1125  >>>  Loss : 0.60164
EPOCH 1150  >>>  Loss : 0.60002
EPOCH 1175  >>>  Loss : 0.59847
EPOCH 1200  >>>  Loss : 0.59700
EPOCH 1225  >>>  Loss : 0.59560
EPOCH 1250  >>>  Loss : 0.59426
EPOCH 1275  >>>  Loss : 0.59298
EPOCH 1300  >>>  Loss : 0.59175
EPOCH 1325  >>>  Loss : 0.59058
EPOCH 1350  >>>  Loss : 0.58946
EPOCH 1375  >>>  Loss : 0.58838
EPOCH 1400  >>>  Loss : 0.58735
EPOCH 1425  >>>  Loss : 0.58636
EPOCH 1450  >>>  Loss : 0.58541
EPOCH 1475  >>>  Loss : 0.58449
EPOCH 1500  >>>  Loss : 0.58361

1500번 학습을 하였고, Loss는 순차적으로 잘 줄어든 것을 볼 수 있다.

성능 검증

# 성능 검증
# X, Y를 그대로 넣어서 제대로 분류하는 확인
def calc_acc(output, y):
    p_m_val, p_m_idx = torch.max(output, dim=1)
    y_m_val, y_m_idx = torch.max(y, dim=1)
    return (p_m_idx == y_m_idx).sum()


model.eval()

output = model(X)
acc = calc_acc(output, Y)
print("모델이 예측한 값 :",output)
print("실제 값 : ", Y)
print("정확도 : {:.2f}%".format(acc / 9. * 100.))
모델이 예측한 값 : tensor([[9.4259e-01, 2.4447e-03, 5.4970e-02],
        [9.4027e-01, 3.1480e-03, 5.6586e-02],
        [9.3180e-01, 2.2921e-03, 6.5911e-02],
        [9.0985e-05, 9.5731e-01, 4.2603e-02],
        [2.1392e-04, 9.5028e-01, 4.9503e-02],
        [6.0590e-05, 9.5549e-01, 4.4447e-02],
        [1.0728e-02, 2.2483e-02, 9.6679e-01],
        [2.6211e-02, 8.5016e-03, 9.6529e-01],
        [3.7751e-03, 4.9346e-02, 9.4688e-01]], grad_fn=<SoftmaxBackward0>)
실제 값 :  tensor([[1., 0., 0.],
        [1., 0., 0.],
        [1., 0., 0.],
        [0., 1., 0.],
        [0., 1., 0.],
        [0., 1., 0.],
        [0., 0., 1.],
        [0., 0., 1.],
        [0., 0., 1.]])
정확도 : 100.00%

 

 

 

 

학습했던 데이터에 대해서 정확도는 100%가 나왔다.
물론 과적합일 수도 있지만, 이는 코드 실습에 의의를 두고 싶다.

다음 포스팅에서는 흔한 IRIS 데이터를 통한 실습 프로젝트를 진행하고자 한다.

728x90