최적화 및 미분

2025. 4. 27. 20:38·Bootcamp_zerobase/Pytorch

2025.04.27

 

Part12. 파이토치

  • Chapter.02 최적화
    • 03_자동미분
    • 04_linear Regression

 

 

자동미분

 

autograd는 Pytorch에서 핵심적인 기능을 담당하는 하부 패키지

autograd는 텐서의 연산에 대해 자동으로 미분값을 구해주는 기능이다.

  • tensor 데이터를 생성할 때, requires_grad 임수를 True로 설정하거나
  • .requires_grad(True)를 실행하면

그 텐서에 행해지는 모든 연산에 대한 미분값을 계산한다.

계산을 멈추고 싶으면 .detach() 함수나 with을 이용해 torch.no_grad()를 이용한다.

 

 

 

 

tensor.grad_fn 속성을 출력해 미분 함수를 확인할 수 있다.

 

 

 

기본적으로 tensorflow 자동미분은 아래와 같이 with tf.GradientTape as tape: 구문을 이용해 적용한다.

import tensorflow as tf

# 변수 정의
x = tf.Variable(3.0)

# 테이프 켜고 연산 기록
with tf.GradientTape() as tape:
    y = x ** 2 + 2 * x + 1  # y = x^2 + 2x + 1

# x에 대해 y를 미분
dy_dx = tape.gradient(y, x)

print(dy_dx.numpy())  # 결과: 8.0
  • tape 안에 있는 모든 연산을 자동으로 기록
  • tape.gradient(target, sources) 로 미분 결과 반환

 

 

 

Pytorch에서는 아래와 같이 tensor_name.backward( ) 함수로 사용할 수 있다. backward( ) 함수는 자동으로 미분값을 계산해 requires_grad 인수가 True 설정된 변수의 grad 속성 값을 갱신한다.

 

텐서의 "미분값"은 무슨 의미냐? → "각 원소별 변화율" 을 나타내.
정확히는, 입력(텐서) 안에 있는 각 원소가 출력(스칼라, 또는 다른 텐서)에 대해 얼마나 영향을 미치는지(=변화율) 를 나타내는 거야.
즉, 입력 텐서가 100개 원소면,미분값(gradient)도 100개짜리야.

 

 

 

또한 기본적으로 y.backward()는  x.grad에 gradient 값을 누적한다. 그렇기에 해당 코드를 계속작동 시키면 x.grad 값이 누적되면서 변하게 된다.

 

 

 

 

선형회귀 (linear Regression)

 

 

 

Pytorch를 이용해서 선형회귀를 구현하는 과제를 실습해본다. TensorFlow와 마찬가지로 관련 패키지를 불러온다.

학습할 데이터는 scikit-learn에서 제공하는 boston 집값 데이터를 활용한다.

import pandas as pd
import numpy as np
import torch

import matplotlib.pyplot as plt

torch.manual_seed(777)

 

 

Boston 집값 데이터 Load

아래와 같이 데이터셋을 받아온다. 다만, 전에도 나왔지만 boston 집값에 대한 데이터는 더 이상 scikit-learn에서 제공되지 않는다.

아래의 링크에서 조금 더 확인할 수 있다.

https://velog.io/@ho3068/Regression-3

 

아래와 같이 데이터를 받아오면 조금 편집을해줘야 한다. 기본적으로 제공되는 데이터가 2줄이 1나의 row로 구성되어야 한다.

그리고 각 row의 마지막 값이 target 값이다.

 

 

 

슬라이싱을 이용해서 데이터를 feature 와 target 데이터로 전처리 진행해준다.

 

 

결과적으로는 아래와 같다. 그리고 데이터프레임으로 객체를 생성하

# hstack 사용. 두 개의 데이터를 수평으로 쌓아 결합

feature_data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target_data = raw_df.values[1::2, 2]

feature_data.shape, target_data.shape

	>> ((506, 13), (506,))
cnames = [
    "CRIM","ZN","INDUS","CHAS","NOX","RM","AGE","DIS","RAD","TAX","PTRATIO","B","LSTAT"
    ]

boston_df = pd.DataFrame(feature_data, columns=cnames)
boston_df.tail()

 

 

 

 

tensor로 변환 및 가중치 구하

## tensor

x = torch.tensor(boston_df.values)
y = torch.tensor(target_data).reshape(-1, 1)

print(x.shape, y.shape)

	>> torch.Size([506, 13]) torch.Size([506, 1])

y 값은 기존의 shape이 (506,) 의 1차원 벡터값이므로, reshape을 통해서 변경 (2차원), Feature 데이터와 차원 동일하게 설정

 

$y = wX$ 의 선형회귀 형태에서 가중치 w를 구하기 위해선...X의 역행렬을 곱해서 .. $w = (X^T X)^{-1} X^T y$ 이런 형태가 되어야 한다.

따라서 $ X $ 행렬과 $ X^T $ 전치행렬을 곱해서 정사각 행렬로 만든다. 그 다음 해당 정사각 행렬의 역행렬 $ (X^T X)^{-1} $ 을 곱해서 가중치를 구할 수 있다.

 

 

일단 X tensor의 전치행렬을 구하면 아래와 같다.

  • 전치행렬 (Transpose Matrix) : 주어진 행렬의 행과 열을 서로 교환한 새로운 행렬을 의미
# x의 0번축과 1번축 교환. (행과 열 교환)
XT = torch.transpose(x, 0, 1)
XT.shape
	>> torch.Size([13, 506])

 

 

가중치를 구해보면..

 

 

 

예측치는 기존의 특성값과 가중치(변화량)을 곱하면 예측치로 볼 수 있다. 그래서 기존의 x와 가중치 W 를 곱하면 예측치가 된다.

 

 

예측값과 결과값을 뺏을 때, 0에 가까울수록 오차가 작고 예측이 잘되었다고 볼 수 있는데.. 아래의 그래프를 통해 얼마나 잘 예측되었는지 확인할 수 있다.

 

 

 

 

 

Gradient Descent 방식

 

위에서는 단순히 가중치만을 구했다. 수학적으로.. 이제 가중치를 업데이트하면서 가장 오차를 최소화시켜 가중치를 구하는 방법을 진행해본다.

 

임의로 w와 bias를 지정한다. 단 shape은 맞춰서 지정해야 한다. 또한 dtype 역시 확인 후 맞추어야 한다.

## w와 b를 임의 지정
## x의 x.dtype 은 float64

w = torch.rand((13, 1) ,dtype=torch.float64, requires_grad=True)
b = torch.rand((1, 1), dtype=torch.float64, requires_grad=True)
z = torch.matmul(x, w) + b

 

 

 

이제 가중치를 업데이트하기 위한 loss를 구해보면.. 아래와 같다.

loss = torch.mean((z-y)**2)

 

 

이제 autograd 명령어와 loss를 이용해서 미분값을 업데이트하면..

 

 

Pytorch에서 loss 의 값만을 바로 얻기 위해서는 tf와 다르게 detach()함수 적용 후 numpy 적용하여 얻을 수 있다.

 

또는 loss.item( ) 함수를 사용하면 바로 값을 얻을 수 있다.

 

 

 

이제 실제로 Gradient Descent 를 반복문으로 실행해보면 (100번)

lr = 0.000003
loss_tracking = []

for epoch in range(300):

    z = torch.matmul(x, w) + b
    loss = torch.mean((z - y)**2)

    loss.backward()

    w.data = w.data - w.grad * lr
    b.data = b.data = b.data * lr

    #Pytorch에서 grad 값은 누적된다. 초기화 필요하다
    w.grad.zero_()
    b.grad.zero_()

    loss_tracking.append(loss.item())

    print(f"{epoch} - loss : {loss.item()}")

 

 

 

  • loss.backward()는 손실 함수에 대한 각 파라미터의 그래디언트를 계산합니다.
  • 계산된 그래디언트는 w.grad와 b.grad에 저장됩니다.
  • 이후 w.data = w.data - w.grad * lr와 같이 파라미터를 업데이트합니다

 

 

 

 

Optimizer를 사용하면 훨씬 더 간단하게 코드를 구현할 수 있다.

 

기존에  w.data = w.data - w.grad * lr 이렇게 수동으로 파라미터(가중치)를 업데이트 하였는데, optimizer 사용 시 자동으로 업데이트가 된다.

## optimizer 사용
## 위 코드는 수동으로 경사 하강법 적용
## optimizer 적용 시 자동으로 동작

import torch.optim as optim

optimizer = optim.SGD([w, b], lr=0.000003)
loss_tracking = []

for epoch in range(300):
    z = torch.matmul(x, w) + b
    loss = torch.mean((z-y)**2)

    optimizer.zero_grad()   # grad 초기화 (수동으로 .zero_() 안해도 됨)
    loss.backward()     # grad 계산
    optimizer.step()    # 파라미터 업데이트 (w.data = w.data - w.grad * lr)

    loss_tracking.append(loss.item())

    print(f"{epoch} - loss : {loss.item()}")

 

 

 

 

 

'Bootcamp_zerobase > Pytorch' 카테고리의 다른 글

Pytorch의 모델링 및 학습  (0) 2025.05.18
Pytorch 모델 학습  (0) 2025.04.28
Tensor 다루기  (1) 2025.04.27
Pytorch #4 : 식물잎 사진으로 질병분류  (0) 2025.04.26
Pytorch #3 : 파이토치 MNIST 실습  (0) 2025.04.26
'Bootcamp_zerobase/Pytorch' 카테고리의 다른 글
  • Pytorch의 모델링 및 학습
  • Pytorch 모델 학습
  • Tensor 다루기
  • Pytorch #4 : 식물잎 사진으로 질병분류
Loft_mind
Loft_mind
건축 전공자의 전공 갈아타기
  • Loft_mind
    오늘의 설계
    Loft_mind
  • 공지사항

    • 분류 전체보기 (36)
      • Bootcamp_zerobase (35)
        • Pytorch (12)
        • Image Augmentation (2)
        • YOLO & RNN (4)
        • Git & GitHub (2)
        • Tensorflow (11)
        • OpenCV (4)
      • Architecture (0)
  • 블로그 메뉴

    • 홈
    • 태그
  • 태그

    mnist
    zerobase
    tensorflow
    ComputerVision
    bash
    정규표현식
    VGGNET
    pytorch
    image augmentation
    제로베이스
    github
    opencv
    subclass
    CNN
    rnn
    autoencoders
    git
    PIL
    ResNet
    deeplearning
    컴퓨터 비전
    역전파
    RE
    YOLO
  • hELLO· Designed By정상우.v4.10.3
Loft_mind
최적화 및 미분
상단으로

티스토리툴바