본문 바로가기
AI/딥러닝

02. 선형 회귀(단항, 다중) | 경사하강법

by 사라리24 2024. 6. 18.
SMALL



1. 단항 선형 회귀 실습

* 한 개의 입력이 들어가서 한 개의 출력이 나오는 구조

 

 

  • import

       
        import torch # 오픈 소스 기계 학습 라이브러리 모듈
        import torch.nn as nn # nn 이란? 인경신경망을 구현하기 위한 도구와 모듈제공
        import torch.optim as optim # optim 이란 다양한 최적화 알고리즘 구현
        import matplotlib.pyplot as plt


 

 

  • 가격을 생성할 때 랜덤한 수 생성

       

        # 파이썬 코드를 재실행해도 같은 결과가 나올 수 있도록 랜덤시드를 설정
        torch.manual_seed(2024)



 

 

 

  • 데이터 직접 만들기

          # 1차원 텐서를 생성 / 텐서란? 다차원 배열을 나타내는 데이터 구조
          ( 기본적으로 숫자데이터를 저장하고 다양한 수학적 연산을 수행)

        X_train = torch.FloatTensor([[1],[2],[3]])  # 1,2,3을 실수 형태로 저장
        y_train = torch.FloatTensor([[2],[4],[6]])  # 2,4,6을 실수 형태로 저장

        print(X_train)
        print(X_train.shape)
        print(y_train)
        print(y_train.shape)


 

 

  • 산점도 그리기

       
      # 산점도 그림
      # x_train x축에 해당하는 입력 데이터 ,y_train y축에 해당하는 목표 변수(타깃)
      plt.figure(figsize = (6, 4))
      plt.scatter(X_train, y_train)


 



  • 머신러닝 모델 만들기

       
        # 직선의 방정식 y = wx + b

        model = nn.Linear(1, 1) # 데이터를 하나 넣으면 하나 출력
        print(model)


Linear(in_features=1, out_features=1, bias=True)

 

 

 

  • 예측선 긋기

       
      # 예측선 긋기
      y_pred = model(X_train)
      print(y_pred)

 
tensor([[0.7260],
        [0.7894],
        [0.8528]], grad_fn=<AddmmBackward0>)

 

 

  • 예측한 기울기와 절편 확인

       
      # 기울기와 바이어스
      # 학습전이라 임의의 값으로 설정됨
      list(model.parameters())

      # W: 0.0634, b: 0.6625
      # y = 0.0634 + 6625
      # x=1, 0.0634 + 0.6625 = 0.7259
      # x=2, (0.0634*2) + 0.6625 = 0.7893


[Parameter containing:
 tensor([[0.0634]], requires_grad=True),
 Parameter containing:
 tensor([0.6625], requires_grad=True)]

 

 

  • MSE(Mean Squared Error, 평균 제곱 오차)를 계산
    신경망의 예측값 실제 타겟 값 간의 차이를 제곱한 후 평균

       
        # MSE 값
        ((y_pred - y_train) ** 2).mean()
        # 예측값 - 실제값, 제곱하기, 평균내기


tensor(12.8082, grad_fn=<MeanBackward0>)

 

 

 

  • 손실 함수: 예측값과 실제값이 얼마나 차이가 나는지를 측정

      

        loss = nn.MSELoss()(y_pred, y_train)
        loss


tensor(12.8082, grad_fn=<MseLossBackward0>)

 

 

2. 경사하강법

* 비용 함수의 값을 최소로 하는 w 와 b를 찾는 알고리즘을 옵티마이저 알고리즘이라고 함 (최적화 알고리즘)
* "옵티마이저 알고리즘" 중 가장 기본적인 기술이 경사하강법
* 옵티마이저 알고리즘을 통해 w와 b를 찾아내는 과정을 "학습"이라고 부름
* 학습률(Learning rate) : 한번 W를 움직이는 거리 (increment strp)

 

  • 객체 생성

       
      # SGD(Stochasitc Gradient Desert)
      # 랜덤하게 데이터를 하나씩 뽑아서 loss를 만듦
      # 데이터를 뽑고 다시 데이터에 넣고를 반복
      # 빠르게 방향을 결정
      # 학습률(Learning rate): 한 번 움직이는 거리(increment step)
      optimizer = optim.SGD(model.parameters(), lr=0.01)


 

 

 

  • 선형 회귀

       

        # 손실 함수를 계산
        loss = nn.MSELoss()(y_pred, y_train)

        # gradient를 초기화
        optimizer.zero_grad()

        # 역전파 : 비용함수를 미분하여 gradient(기울기) 재계산
        loss.backward() # 미분을 취해서 기울기와 절편을 새롭게 찾아냄

        # W와 b를 업데이트
        optimizer.step()

        print(list(model.parameters()))
        # W: [[-0.2177]] b:[0.7267]



[Parameter containing:
tensor([[0.2177]], requires_grad=True), Parameter containing:
tensor([0.7267], requires_grad=True)]

 

 

  • 모델을 학습시키기

       
        # 반복학습을 통해 오차가 있는 W, b를 수정하면서 오차를 계속 줄여나감
        # epochs: 반복학습횟수(에포크)

        epochs = 1000

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

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

 
Epoch 0/1000 Loss: 0.000000
Epoch 100/1000 Loss: 0.000000
Epoch 200/1000 Loss: 0.000000
Epoch 300/1000 Loss: 0.000000
Epoch 400/1000 Loss: 0.000000
Epoch 500/1000 Loss: 0.000000
Epoch 600/1000 Loss: 0.000000
Epoch 700/1000 Loss: 0.000000
Epoch 800/1000 Loss: 0.000000
Epoch 900/1000 Loss: 0.000000
Epoch 1000/1000 Loss: 0.000000
  • 주석
더보기

       

          # 에포크 수 설정
          epochs = 1000

          # 에포크 반복문 시작
          for epoch in range(epochs + 1):
              # 모델을 사용하여 훈련 데이터(X_train)에 대한 예측 값(y_pred) 계산
              y_pred = model(X_train)
             
              # 예측 값(y_pred)과 실제 값(y_train) 간의 평균 제곱 오차(MSE) 손실 계산
              loss = nn.MSELoss()(y_pred, y_train)
             
              # 옵티마이저의 기울기(gradient) 초기화
              optimizer.zero_grad()
             
              # 손실에 대한 그래디언트 계산(역전파)
              loss.backward()
             
              # 옵티마이저를 사용하여 모델 파라미터 업데이트
              optimizer.step()
             
              # 100번째 에포크마다 현재 에포크와 손실 값을 출력
              if epoch % 100 == 0:
                  print(f'Epoch {epoch}/{epochs} Loss: {loss:.6f}')



 

 

 

  • 예측한 기울기와 절편 확인

       

          # parameter은 nn.module 클래스 방법( 모델이 가능한 확률을 반환하는 기여를 함)
          print(list(model.parameters()))

          # W :1.9499  b: 0.1138



[Parameter containing:
tensor([[1.9499]], requires_grad=True), Parameter containing:
tensor([0.1138], requires_grad=True)]

 

  • 입력 데이터 x_test에 대한 예측값 y_pred를 출력

     
      x_test = torch.FloatTensor([[5]])
      y_pred = model(x_test)
      print(y_pred)


tensor([[9.8635]], grad_fn=<AddmmBackward0>)



 

 

3. 다중 선형 회귀 

여러 개의 입력이 들어가서 한 개의 출력이 나오는 구조

 

 

  • X_train과 y_train이라는 두 개의 텐서를 정의하고, 이들의 값을 출력

       
          X_train = torch.FloatTensor([[73, 80, 75],
                                                       [93, 88, 93],
                                                       [89, 91, 90],
                                                       [96, 98, 100],
                                                       [73, 66, 70],])
                  
          y_train = torch.FloatTensor([[150], [190], [180], [200], [130]])

          print(X_train, X_train.shape)
          print(y_train, y_train.shape)

 
tensor([[ 73.,  80.,  75.],
        [ 93.,  88.,  93.],
        [ 89.,  91.,  90.],
        [ 96.,  98., 100.],
        [ 73.,  66.,  70.]]) torch.Size([5, 3])
tensor([[150.],
        [190.],
        [180.],
        [200.],
        [130.]]) torch.Size([5, 1])
  • X_train 정의:
    • X_train은 입력 데이터(features)입니다.
    • 5개의 샘플(sample)로 구성되어 있으며, 각 샘플은 3개의 특성(feature)을 가지고 있습니다.
  • y_train 정의:
    • y_train은 타겟 값(labels) 또는 출력 값입니다.
    • 각 샘플에 대해 하나의 타겟 값을 가지고 있습니다.

 

  • 선형 회귀 모델 정의
    입력 변수가 3개인 경우에 대해 각 변수에 대한 가중치를 학습하여 예측값을 계산

       
        # y = W1x1 + W2x2 + W3x3 + b
        model = nn.Linear(3,1)
        print(model)


Linear(in_features=3, out_features=1, bias=True)
입력 차원이 3이고 출력 차원이 1인 선형 회귀 모델을 정의 합니다.

 

 

  • 최적화 함수 정의

       

        # 확률적 경사 하강법
        optimizer = optim.SGD(model.parameters(),lr=0.00001)


  • optim.SGD는 확률적 경사 하강법(SGD, Stochastic Gradient Descent) 최적화 알고리즘을 사용하겠다는 뜻입니다.
  • model.parameters()는 모델의 학습 가능한 매개변수들(가중치와 편향)을 반환합니다.
  • lr=0.00001은 학습률(learning rate)을 0.00001로 설정합니다.
    학습률은 모델이 얼마나 빠르게 또는 천천히 최적화되는지를 결정하는 중요한 하이퍼파라미터입니다.

 

 

 

  • 선형 회귀 모델을 학습하는 과정

       
        #학습
        epochs = 10000

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

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



Epoch 0/0 Loss: 38561.125000
Epoch 100/100 Loss: 43.880661
Epoch 200/200 Loss: 43.343727
Epoch 300/300 Loss: 42.829872
Epoch 400/400 Loss: 42.337685

.........


Epoch 9500/9500 Loss: 27.417210
Epoch 9600/9600 Loss: 27.343838
Epoch 9700/9700 Loss: 27.270786
Epoch 9800/9800 Loss: 27.198359
Epoch 9900/9900 Loss: 27.126339
Epoch 10000/10000 Loss: 27.054819

* Epoch 높아질수록 Loss 낮아짐!!
  • 주석
더보기

       

          # 학습
          epochs = 10000  # 총 학습 에포크 수를 10000으로 설정

          for epoch in range(epochs + 1):  # 0부터 10000까지 반복
              y_pred = model(X_train)  # 모델에 학습 데이터셋을 입력하여 예측값 계산
              loss = nn.MSELoss()(y_pred, y_train)  # 예측값과 실제 값 사이의 손실(평균 제곱 오차) 계산
              optimizer.zero_grad()  # 역전파 이전에 기울기 초기화
              loss.backward()  # 손실 값에 대해 역전파를 수행하여 기울기 계산
              optimizer.step()  # 기울기를 사용하여 모델의 매개변수 업데이트

              if epoch % 100 == 0:  # 에포크가 100의 배수일 때마다 손실 값 출력
                  print(f'Epoch {epoch}/{epochs} Loss: {loss:.6f}')


  1. 학습 반복 횟수 설정:
    • 모델을 학습할 총 에포크(epoch) 수를 10000으로 설정합니다. 에포크는 전체 데이터셋을 한 번 학습하는 단위를 의미합니다.
  2. 학습 루프:
    • for epoch in range(epochs + 1)는 0부터 10000까지의 숫자(총 10001번)를 반복합니다.
  3. 예측값 계산:
    • X_train을 모델에 입력하여 예측값(y_pred)을 계산합니다. X_train은 학습 데이터셋의 입력입니다.
  4. 손실 계산:
    • nn.MSELoss()는 평균 제곱 오차(MSE, Mean Squared Error) 손실 함수를 정의합니다.
    • y_pred(모델의 예측값)와 y_train(실제 값)을 비교하여 손실 값을 계산합니다.
  5. 기울기 초기화:
    • 역전파(backpropagation)를 통해 가중치를 업데이트하기 전에, 기존의 기울기를 초기화합니다. 이는 이전 배치(batch)의 기울기가 현재 배치에 누적되지 않도록 하기 위함입니다.
  6. 역전파 수행:
    • 손실 값에 대해 역전파를 수행하여 모델의 매개변수들에 대한 기울기를 계산합니다.
  7. 가중치 업데이트:
    • 계산된 기울기를 사용하여 모델의 가중치를 업데이트합니다.
  8. 손실 출력:
    • 에포크가 100의 배수일 때마다 현재 에포크 번호와 손실 값을 출력합니다. 이를 통해 학습 과정을 모니터링할 수 있습니다.
전체 코드는 선형 회귀 모델을 10000번 반복 학습하며, 각 반복마다 손실을 계산하고, 기울기를 통해 모델의 매개변수를 업데이트합니다. 100번마다 현재 학습 상태(에포크 번호와 손실 값)를 출력하여 학습이 제대로 진행되고 있는지 확인할 수 있습니다.

 

 

  •  모델의 가중치와 편향을 출력

       

          print(list(model.parameters())) # W : [0.3478, 0.6414, 1.0172]


[Parameter containing:
tensor([[0.3478, 0.6414, 1.0172]], requires_grad=True), Parameter containing:
tensor([-0.2856], requires_grad=True)]
model의 학습 가능한 모든 매개변수들을 리스트로 변환하고 출력합니다.
nn.Linear(3, 1) 모델은 3개의 입력과 1개의 출력을 가지므로, 가중치 행렬 W는 (1, 3) 형태이고, 편향 b는 (1,) 형태입니다.
  • 입력 변수(x1, x2, x3)에 해당하는 가중치(W1, W2, W3)를 나타냅니다.
    여기서 0.3478, 0.6414, 1.0172는 각각 W1, W2, W3에 해당합니다.
  • 결과(쌤)

 

 

  • 선형 회귀 모델을 사용하여 새로운 입력 데이터 x_test에 대한 예측값을 계산

       
        # 93,93,93 일때 185 나오면 맞음

        x_test = torch.FloatTensor([[93, 93, 93]])
        y_pred=model(x_test)
        print(y_pred)


tensor([[186.3026]], grad_fn=<AddmmBackward0>)
  • 새로운 입력 데이터 x_test를 정의합니다. torch.FloatTensor는 실수형 텐서를 생성하는 PyTorch 함수입니다.
  • 이 예제에서는 세 개의 입력값이 모두 93인 하나의 샘플을 입력 데이터로 사용하고 있습니다.
  • x_test의 형태는 (1, 3)입니다. 즉, 하나의 샘플이 3개의 특성값(93, 93, 93)을 가지고 있습니다.
  • 결과(쌤)

 

 



4. temp 데이터 활용하기

기온 데이터

 

  • 과제 (단항 선형 회귀)

 

temps.csv
0.30MB

 

 

  • import

      
        import pandas as pd

 
 

 

 

  • 데이터 인코딩하면서 가져오기

       
          df = pd.read_csv('/content/drive/MyDrive/1. KDT/6. 머신러닝 딥러닝/데이터/temps.csv', encoding='ms949' )
          df.head()


 

 

 

 

  • null 값 삭제

       
        df.isnull().mean()

        df = df.dropna()

        df.isnull().mean()


 

 




  • [ '기온(°C)'  ]과 [ '지면온도(°C)' ]을 추출하여 PyTorch 텐서로 변환

       
        x_data = df[['기온(°C)']]
        y_data = df[['지면온도(°C)']]

        x_data = torch.FloatTensor(x_data.values)
        y_data = torch.FloatTensor(y_data.values)
        print(x_data.shape)
        print(y_data.shape)


 
torch.Size([8779, 1])
torch.Size([8779, 1])

 

 

  • 텐서의 내용 출력

       
        x_data

        y_data


tensor([[-8.7000],
        [-7.3000],
        [-6.7000],
        ...,
        [-7.3000],
        [-9.0000],
        [-9.2000]])


-----------------------------

tensor([[-2.9000],
        [-2.4000],
        [-2.2000],
        ...,
        [-1.2000],
        [-1.5000],
        [-1.2000]])

 

 

  • 산점도(Scatter plot)를 그리기

       
        plt.figure(figsize=(8, 6))
        plt.scatter(x_data, y_data)

 

 

 

 

  • 1차원 입력과 1차원 출력을 가지는 선형 회귀 모델을 정의
    확률적 경사 하강법(SGD) 옵티마이저를 설정
    모델의 초기 가중치와 편향을 출력

       
        model = nn.Linear(1, 1)
        optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
        print(list(model.parameters())) # W: -0.5700, b: 0.2403


[Parameter containing:
tensor([[-0.5700]], requires_grad=True), Parameter containing:
tensor([0.2403], requires_grad=True)]

 

 

  • 선형 회귀 모델 학습

       
        epochs = 10000

        for epoch in range(epochs + 1):
            y_pred = model(x_data)
            loss = nn.MSELoss()(y_pred, y_data)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

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

 
Epoch: 0/10000 Loss: 727.285767
Epoch: 100/10000 Loss: 13.042105
Epoch: 200/10000 Loss: 13.029263
Epoch: 300/10000 Loss: 13.018347
Epoch: 400/10000 Loss: 13.009065
Epoch: 500/10000 Loss: 13.001172
Epoch: 600/10000 Loss: 12.994462
Epoch: 700/10000 Loss: 12.988756
Epoch: 800/10000 Loss: 12.983907
Epoch: 900/10000 Loss: 12.979782
Epoch: 1000/10000 Loss: 12.976276
Epoch: 1100/10000 Loss: 12.973297
Epoch: 1200/10000 Loss: 12.970764

...............

Epoch: 9300/10000 Loss: 12.956378
Epoch: 9400/10000 Loss: 12.956378
Epoch: 9500/10000 Loss: 12.956379
Epoch: 9600/10000 Loss: 12.956379
Epoch: 9700/10000 Loss: 12.956379
Epoch: 9800/10000 Loss: 12.956379
Epoch: 9900/10000 Loss: 12.956379
Epoch: 10000/10000 Loss: 12.956379

 

 

 

  • 학습이 진행된 후의 선형 회귀 모델의 파라미터(가중치 W와 편향 b) 값을 출력

       
      list(model.parameters()) # W: 1.0854, b: 0.8199

 
[Parameter containing:
 tensor([[1.0854]], requires_grad=True),
 Parameter containing:
 tensor([0.8198], requires_grad=True)]

 

 

  • 입력 데이터 x_data에 대한 예측값을 계산하고, 이 값을 NumPy 배열로 변환하여 출력

       
      y_pred = model(x_data).detach().numpy()
      y_pred

 
array([[-8.623071],
       [-7.103529],
       [-6.452296],
       ...,
       [-7.103529],
       [-8.948688],
       [-9.165765]], dtype=float32)



  • 데이터 포인트와 학습된 모델에 의한 예측 포인트를 포함하는 산점도 그리기

       

        plt.figure(figsize=(8, 6))
        plt.scatter(x_data, y_data)
        plt.scatter(x_data, y_pred)


 

 

  • 새로운 입력 데이터에 대한 예측값을 계산

       
        result = model(torch.FloatTensor([[26]]))
        result


tensor([[29.0399]], grad_fn=<AddmmBackward0>)
  • torch.FloatTensor([[26]])는 입력 데이터를 텐서 형식으로 정의합니다. 여기서는 입력값 26을 가진 1차원 텐서입니다.
  • model()은 이 입력 데이터를 사용하여 모델에 전달합니다.
  • model은 이미 학습된 선형 회귀 모델로 가정합니다.
  • 따라서 result는 모델이 입력 26에 대해 예측한 결과값을 포함하는 텐서입니다.
이 예측값은 해당 모델이 기온이 26°C일 때 지면온도가 29 °C 로 예측했습니다.

 

 

'AI > 딥러닝' 카테고리의 다른 글

06. 비선형 활성화 함수  (0) 2024.06.20
05. 딥러닝  (0) 2024.06.20
04. 데이터로더(Data Loader)  (0) 2024.06.20
03. 논리회귀 (단항, 다중) | 시그모이드(sigmoid) 함수  (0) 2024.06.19
01. 파이토치(Pytorch)  (0) 2024.06.18