[AI 인공지능 머신러닝 딥러닝/Python | PyTorch] - 인스톨! 파이토치 강의 소개
인스톨! 파이토치 강의 소개
혁펜하임 PyTorch 강의 오리엔테이션 요약혁펜하임 채널의 '[PyTorch] 0강. 오리엔테이션' 영상은 채널 5주년 기념으로 '인스톨! 파이토치' 강의를 소개하는 내용입니다. 강의자는 최근 출간한 '이론
inner-game.tistory.com
파이토치(PyTorch)의 자동 미분(Automatic Differentiation) 기능인 autograd는 신경망 학습의 핵심이자 파이토치가 딥러닝 프레임워크로서 강력한 이유 중 하나입니다. 역전파(backpropagation) 과정에서 필요한 모든 미분 계산을 자동으로 처리해주어, 개발자는 복잡한 수학적 미분 공식을 직접 구현할 필요 없이 모델 설계에만 집중할 수 있습니다.

torch.autograd는 파이토치의 자동 미분 엔진으로, 신경망 학습에서 가장 자주 사용되는 역전파 알고리즘을 자동으로 수행합니다. 역전파 시 매개변수(모델의 가중치, 편향)는 해당 매개변수에 대한 손실 함수의 변화도(gradient)에 따라 조정되는데, 이 변화도를 계산하는 작업을 autograd가 자동으로 처리합니다.
Autograd의 동작 원리는 연산 그래프(Computational Graph) 개념에 기반합니다. 순전파(forward pass) 시 autograd는 동시에 두 가지 작업을 수행합니다. 첫째, 요청된 연산을 실행하여 결과 텐서를 계산합니다. 둘째, **DAG(Directed Acyclic Graph, 방향성 비순환 그래프)**에 연산의 기울기 함수를 기록합니다. 이후 .backward()가 호출되면, 이 그래프를 역방향으로 순회하며 각 텐서의 기울기를 계산하고 저장합니다.
경사 하강법과의 연결
경사 하강법(Gradient Descent)은 손실 함수를 최소화하기 위해 기울기의 반대 방향으로 매개변수를 조금씩 업데이트하는 최적화 알고리즘입니다. Autograd는 이 과정에서 필수적인 "현재 매개변수에서의 기울기"를 자동으로 계산해줍니다. 따라서 autograd를 이해하는 것은 딥러닝의 학습 메커니즘 전체를 이해하는 핵심 열쇠가 됩니다.
requires_grad는 텐서가 자동 미분의 대상인지를 나타내는 속성입니다. 기본적으로 사용자가 직접 생성한 텐서는 requires_grad=False로 설정되어 있으며, 이 상태에서는 연산 그래프가 구축되지 않습니다.
텐서를 생성할 때 requires_grad=True로 설정하면, 파이토치는 해당 텐서에 대한 모든 연산을 추적하기 시작합니다. 이렇게 "태그"를 달아두면, 나중에 역전파를 통해 이 텐서에 대한 기울기를 계산할 수 있습니다.
import torch
# requires_grad=True로 자동 미분 활성화
w = torch.tensor(3.0, requires_grad=True)
# 수식 정의: y = w^3 + 10
y = w**3 + 10
# 역전파 수행
y.backward()
# 기울기 확인: dy/dw = 3w^2 = 3*(3)^2 = 27
print(f'y를 w로 미분한 값: {w.grad}') # 27.0
위 예제에서 w.grad는 w에 대한 y의 기울기를 저장합니다. 수학적으로 y = w³ + 10을 w로 미분하면 3w²이므로, w=3일 때 기울기는 27이 됩니다.
연산 그래프에서 사용자가 직접 생성한 텐서는 leaf node가 되고, 연산의 결과로 생성된 텐서는 non-leaf node가 됩니다. 기본적으로 autograd는 leaf node의 기울기만 .grad 속성에 저장하며, 중간 계산 단계의 non-leaf node 기울기는 메모리 효율을 위해 자동으로 삭제합니다. 만약 중간 노드의 기울기도 보존하고 싶다면 .retain_grad()를 호출해야 합니다.
.backward() 메서드를 호출하면 역전파가 시작됩니다. Autograd는 연산 그래프를 역방향으로 순회하며 각 텐서의 기울기를 계산하고, 이를 각 텐서의 .grad 속성에 저장합니다.
import torch
import torch.nn as nn
# 입력 데이터와 가중치 설정
x = torch.randn(3, requires_grad=True)
w = torch.randn(3, requires_grad=True)
b = torch.randn(1, requires_grad=True)
y = torch.randn(3) # 정답 레이블
# 순전파
z = torch.matmul(x, w) + b
# 손실 함수 계산 (MSE)
loss_fn = nn.MSELoss()
loss = loss_fn(z, y)
# 역전파
loss.backward()
# 기울기 확인
print(f'w의 기울기: {w.grad}')
print(f'b의 기울기: {b.grad}')
위 예제에서 loss.backward()를 호출하면, loss를 각 매개변수(w, b)로 미분한 값이 자동으로 계산되어 w.grad, b.grad에 저장됩니다.
기울기 누적과 초기화
주의할 점은 .backward()를 여러 번 호출하면 기울기가 **누적(accumulate)**된다는 것입니다. 즉, 이전에 계산된 기울기에 새로운 기울기가 더해집니다. 이는 일부 특수한 경우(예: RNN의 시퀀스 학습)에는 유용하지만, 일반적인 학습 루프에서는 매 반복마다 기울기를 초기화해야 합니다.
# 매 학습 스텝마다 기울기 초기화 필요
optimizer.zero_grad() # 또는 w.grad.zero_()
loss.backward()
optimizer.step()
.zero_grad()는 기울기를 0으로 초기화하는 메서드로, 이전 반복의 기울기가 현재 반복에 영향을 주지 않도록 합니다.
no_grad()의 필요성
학습이 아닌 추론(inference) 단계에서는 기울기 계산이 필요하지 않습니다. 그런데 requires_grad=True인 텐서로 연산을 수행하면, 파이토치는 자동으로 연산 그래프를 구축하고 중간 결과를 메모리에 저장합니다. 이는 불필요한 메모리 낭비와 연산 시간 증가를 초래합니다.
torch.no_grad()는 이러한 기울기 계산을 일시적으로 비활성화하는 **컨텍스트 매니저(context manager)**입니다. 이 블록 내에서 수행되는 모든 연산은 연산 그래프에 기록되지 않으며, autograd 엔진이 꺼진 상태가 됩니다.
x = torch.tensor([1.], requires_grad=True)
# no_grad 블록 내에서는 기울기 추적 안 함
with torch.no_grad():
y = x * 2
print(y.requires_grad) # False
위 예제에서 x는 requires_grad=True이지만, torch.no_grad() 블록 내에서 생성된 y는 requires_grad=False가 됩니다.
사용 사례와 장점
torch.no_grad()는 주로 다음 상황에서 사용됩니다:
1. 모델 평가(evaluation): 테스트 데이터로 정확도를 측정할 때
2. 추론(inference): 학습된 모델로 실제 예측을 수행할 때
3. 메모리 절약: GPU 메모리가 부족한 상황에서 OOM(Out Of Memory) 에러 방지
Autograd 엔진을 끔으로써 메모리 사용량을 줄이고 연산 속도를 높일 수 있습니다. 다만 역전파를 할 수 없기 때문에 학습에는 사용할 수 없습니다.
# 데코레이터 형태로도 사용 가능
@torch.no_grad()
def evaluate(model, data_loader):
model.eval()
correct = 0
for data, target in data_loader:
output = model(data)
pred = output.argmax(dim=1)
correct += pred.eq(target).sum().item()
return correct / len(data_loader.dataset)
초보자들이 자주 혼동하는 개념으로, zero_grad()는 기존 기울기를 0으로 초기화하는 것이고, no_grad()는 기울기 추적 자체를 하지 않는 것입니다. 둘은 완전히 다른 목적으로 사용됩니다.
전이 학습(Transfer Learning)에서는 사전 학습된 모델의 일부 레이어를 고정하고, 새로운 데이터에 맞게 일부만 재학습시킵니다. 이때 고정하려는 파라미터의 requires_grad를 False로 설정합니다.
# 사전 학습된 모델 불러오기
model = torchvision.models.resnet50(pretrained=True)
# 대부분의 레이어 고정
for param in model.parameters():
param.requires_grad = False
# 마지막 분류 레이어만 재학습
model.fc = nn.Linear(2048, num_classes) # 새 레이어는 requires_grad=True
위 예제에서 고정된 레이어들은 역전파 시 기울기가 계산되지 않으므로, 메모리와 연산 시간을 크게 절약할 수 있습니다.
model.train() vs model.eval()
model.train(False) 또는 model.eval()은 Dropout, BatchNorm 등의 레이어 동작 방식을 변경하지만, requires_grad 설정과는 무관합니다. 즉, model.eval()을 호출해도 파라미터의 requires_grad는 여전히 True로 유지됩니다. 따라서 추론 시 메모리를 절약하려면 model.eval()과 함께 torch.no_grad()를 함께 사용해야 합니다.
Autograd를 효과적으로 사용하기 위한 몇 가지 실무 팁이 있습니다. 첫째, 매 학습 반복마다 반드시 optimizer.zero_grad()를 호출하여 기울기를 초기화해야 합니다. 그렇지 않으면 이전 반복의 기울기가 누적되어 잘못된 방향으로 학습이 진행됩니다.
둘째, 검증(validation)이나 테스트 단계에서는 항상 torch.no_grad()와 model.eval()을 함께 사용하여 메모리와 연산 시간을 절약해야 합니다. 셋째, 복잡한 커스텀 손실 함수나 특수한 학습 방식을 구현할 때는 torch.autograd.grad()를 사용하여 더 세밀한 제어가 가능합니다.
넷째, 중간 계산 결과의 기울기가 필요한 경우 .retain_grad()를 명시적으로 호출해야 하며, 그렇지 않으면 메모리 효율을 위해 자동으로 삭제됩니다. 마지막으로, torch.no_grad()는 thread-local이므로 멀티스레딩 환경에서 다른 스레드의 계산에는 영향을 주지 않습니다.
핵심 정리: Autograd는 파이토치의 심장이자 두뇌로, 복잡한 미분 계산을 자동화하여 개발자가 모델 설계와 실험에 집중할 수 있게 해줍니다. requires_grad, backward(), torch.no_grad()의 세 가지 핵심 개념을 정확히 이해하고 적절히 활용하면, 효율적이고 강력한 딥러닝 학습 파이프라인을 구축할 수 있습니다.
[AI 인공지능 머신러닝 딥러닝/Python | PyTorch] - 인스톨! 파이토치 3강 | 신경망의 기초부터 실전까지: nn.Linear와 선형 회귀 완전 정복 (3강)
인스톨! 파이토치 3강 | 신경망의 기초부터 실전까지: nn.Linear와 선형 회귀 완전 정복 (3강)
[AI 인공지능 머신러닝 딥러닝/Python | PyTorch] - 인스톨! 파이토치 강의 소개 인스톨! 파이토치 강의 소개혁펜하임 PyTorch 강의 오리엔테이션 요약혁펜하임 채널의 '[PyTorch] 0강. 오리엔테이션' 영상
inner-game.tistory.com