Pytorch 시작하기¶
학습 내용¶
- 파이토치는 무엇일까요?
파이토치(pytorch)는 무엇일까요?¶
- (1) Facebook에서 개발한 오픈 소스 머신 러닝 라이브러리.
- (2) PyTorch는 파이썬을 기반으로 한다.
- (3) 주요 특징
- 동적 계산 그래프 : PyTorch는 실행 시점에 계산 그래프를 생성한다.
- 강력한 GPU 지원
- 파이썬과 친숙한 문법과 사용성 제공
- PyTorch는 자동으로 기울기(gradient)를 계산하는 기능을 제공한다.
- 연구자와 실무자 모두에게 인기가 있다.
기본 예제 - 기본적인 텐서 연산과 자동미분(autograd)을 사용하는 코드¶
# PyTorch 라이브러리 설치 (구글 코랩에서는 일반적으로 설치가 되어 있지만, 없을 경우 설치)
!pip install torch
Requirement already satisfied: torch in /usr/local/lib/python3.10/dist-packages (2.4.0+cu121) Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch) (3.15.4) Requirement already satisfied: typing-extensions>=4.8.0 in /usr/local/lib/python3.10/dist-packages (from torch) (4.12.2) Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch) (1.13.2) Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch) (3.3) Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch) (3.1.4) Requirement already satisfied: fsspec in /usr/local/lib/python3.10/dist-packages (from torch) (2024.6.1) Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch) (2.1.5) Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from sympy->torch) (1.3.0)
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
# torch: PyTorch 라이브러리의 기본 모듈로, 텐서 연산과 딥러닝을 위한 다양한 기능을 제공
# torch.nn: 신경망을 구성하는 다양한 클래스와 기능을 제공하는 모듈
# torch.optim: 다양한 최적화 알고리즘(예: SGD, Adam 등)을 제공하는 모듈
# matplotlib.pyplot: 데이터를 시각화하기 위한 파이썬 라이브러리
print(torch.__version__)
2.4.0+cu121
# SimpleNet 클래스는 PyTorch의 nn.Module을 상속받아 정의한 간단한 신경망 모델
# __init__ 메서드: 신경망의 구조를 정의
# forward 메서드: 신경망의 순전파(forward pass)를 정의
# 간단한 신경망 모델 정의
class SimpleNet(nn.Module):
# __init__ 메서드: 신경망의 구조를 정의
def __init__(self):
super(SimpleNet, self).__init__()
# self.fc1 = nn.Linear(1, 10): 입력이 1차원이고 출력이 10차원인 첫 번째 선형 레이어(fully connected layer)
# self.relu = nn.ReLU(): ReLU(Rectified Linear Unit) 활성화 함수
# self.fc2 = nn.Linear(10, 1): 10차원의 입력을 받아 1차원의 출력을 내는 두 번째 선형 레이어
self.fc1 = nn.Linear(1, 10)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(10, 1)
# forward 메서드: 신경망의 순전파(forward pass)를 정의
def forward(self, x):
# 입력 x는 먼저 fc1 레이어를 통과하고, ReLU 활성화 함수를 거쳐 fc2 레이어로 전달됩니다.
x = self.relu(self.fc1(x))
x = self.fc2(x) # 출력 레이어에는 ReLU를 적용하지 않습니다
return x
# 데이터 생성
# torch.linspace(start, end, steps) 함수는 start에서 end까지의 범위에서 등간격으로 나열된 steps 개의 값을 생성하는 함수
# .view()는 PyTorch에서 텐서의 크기(shape)를 변경하는 함수. 뒤는 1로 맞추고 -1은 아무것이나 상관없다.
x = torch.linspace(-5, 5, 100).view(-1, 1)
# x**2: 입력 x의 제곱을 계산하여 비선형 관계를 생성
# torch.randn(x.size()) * 3: x와 동일한 크기의 표준 정규 분포를 따르는 랜덤 텐서를 생성하고,
# 이를 3배하여 노이즈로 사용합니다. 이는 y 값에 랜덤한 변동을 추가하여 데이터의 복잡성을 높입니다.
y = x**2 + torch.randn(x.size()) * 3
# 모델, 손실 함수, 옵티마이저 초기화
# model = SimpleNet(): 정의된 SimpleNet 신경망 모델의 인스턴스를 생성
# criterion = nn.MSELoss(): 손실 함수로 평균 제곱 오차(MSE, Mean Squared Error)를 사용합니다.
# MSE는 예측 값과 실제 값 간의 차이의 제곱의 평균을 계산합니다. 회귀 문제에서 자주 사용됩니다.
# optimizer = optim.Adam(model.parameters(), lr=0.01): Adam 옵티마이저를 사용하여 모델의 파라미터를 학습합니다.
# 학습률(learning rate)은 0.01로 설정
model = SimpleNet()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
# 학습 루프
# num_epochs = 1000: 모델 학습을 위한 에폭 수를 1000으로 설정합니다. 1 에폭은 전체 데이터셋을 한 번 학습하는 과정입니다.
#
num_epochs = 1000
for epoch in range(num_epochs):
# 순전파
# outputs = model(x): 모델에 입력 x를 통과시켜 예측 값을 얻습니다.
# loss = criterion(outputs, y): 예측 값과 실제 값 y 간의 손실을 계산합니다.
outputs = model(x)
loss = criterion(outputs, y)
# 역전파 및 최적화
# optimizer.zero_grad(): 옵티마이저의 기울기를 초기화합니다.
# PyTorch에서는 기본적으로 기울기가 누적되므로, 매 반복마다 초기화가 필요합니다.
# loss.backward(): 역전파(backpropagation)를 수행하여 기울기를 계산합니다. 모델의 각 파라미터에 대한 손실 함수의 기울기를 계산합니다.
# optimizer.step(): 옵티마이저가 기울기를 사용하여 파라미터를 업데이트합니다. 이 단계에서 모델이 학습됩니다.
optimizer.zero_grad()
loss.backward()
optimizer.step()
# (epoch+1) % 100 == 0일 때, 즉 매 100번째 에폭마다 현재 에폭 번호와 손실 값을 출력합니다.
if (epoch+1) % 100 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# 결과 시각화
# model.eval(): 모델을 평가 모드로 전환합니다. 평가 모드에서는 드롭아웃(dropout)과 배치 정규화(batch normalization)과
# 같은 레이어가 훈련 모드에서와 다르게 작동하므로, 이를 비활성화합니다.
# with torch.no_grad():: 기울기 계산을 비활성화하여 추론(inference) 모드로 전환합니다.
# 메모리 사용량을 줄이고 계산 속도를 높이기 위해 사용됩니다.
# predicted = model(x): 학습된 모델을 사용하여 x에 대한 예측 값을 계산합니다.
model.eval()
with torch.no_grad():
predicted = model(x)
# plt.scatter(x.numpy(), y.numpy(), label='Original data'): 원본 데이터를 산점도로 그립니다.
# plt.plot(x.numpy(), predicted.numpy(), color='red', label='Fitted line'): 모델이 학습한 결과를 선으로 표시하여 시각화합니다.
plt.scatter(x.numpy(), y.numpy(), label='Original data')
plt.plot(x.numpy(), predicted.numpy(), color='red', label='Fitted line')
# plt.legend() 및 plt.show(): 그래프의 범례를 추가하고, 그래프를 화면에 표시합니다.
plt.legend()
plt.show()
print("학습 완료!")
Epoch [100/1000], Loss: 22.5298 Epoch [200/1000], Loss: 14.9777 Epoch [300/1000], Loss: 11.5867 Epoch [400/1000], Loss: 10.3279 Epoch [500/1000], Loss: 9.6922 Epoch [600/1000], Loss: 9.4535 Epoch [700/1000], Loss: 9.3779 Epoch [800/1000], Loss: 9.3390 Epoch [900/1000], Loss: 9.3128 Epoch [1000/1000], Loss: 9.2779
학습 완료!
현재 모델 SimpleNet은 입력층과 출력층 사이에 하나의 은닉층만을 가지고 있습니다. 은닉층의 수와 각 은닉층의 노드 수(폭)를 늘려 모델의 깊이를 더해 보세요.
단계 1: 은닉층을 2개 이상 추가하고, 각 은닉층의 노드 수를 다양하게 설정합니다. 예를 들어, 첫 번째 은닉층에 20개의 노드, 두 번째 은닉층에 15개의 노드를 추가할 수 있습니다.
단계 2: 각 은닉층 사이에 ReLU 활성화 함수를 추가하여 비선형성을 유지합니다.
단계 3: 모델을 다시 학습시키고, 학습이 얼마나 향상되었는지 또는 더 나빠졌는지를 평가합니다. 손실 함수 값이나 시각화를 통해 모델 성능을 비교해 보세요.
실습 문제 2: 학습률과 옵티마이저 변경하기¶
Adam 옵티마이저는 잘 작동하지만, 다른 옵티마이저와 학습률을 실험하여 모델의 학습 성능을 비교해 보세요.
단계 1: optim.SGD (확률적 경사 하강법)과 같은 다른 옵티마이저로 변경하여 모델을 학습시켜 보세요. 학습률(learning rate)도 0.01, 0.001 등으로 다양하게 설정해 보세요.
단계 2: 각 옵티마이저와 학습률 조합에서의 모델 성능을 기록하고 비교해 보세요. 어떤 경우가 더 빠르게 수렴했는지, 또는 손실 함수 값이 더 낮았는지 확인하세요.
실습 문제 3: 정규화와 드롭아웃 적용하기¶
모델이 과적합(overfitting)되는 것을 방지하기 위해 드롭아웃(dropout)과 배치 정규화(batch normalization)를 추가해 보세요.
단계 1: 은닉층 사이에 드롭아웃 레이어(nn.Dropout)를 추가하여 과적합을 방지해 보세요. 드롭아웃 비율을 0.2 또는 0.5로 설정하여 다양한 비율을 실험해 보세요.
단계 2: 배치 정규화 레이어(nn.BatchNorm1d)를 은닉층 후에 추가하여 모델의 학습 안정성을 향상시켜 보세요.
단계 3: 드롭아웃과 배치 정규화를 적용한 모델과 적용하지 않은 모델의 성능을 비교해 보세요. 과적합이 얼마나 줄어들었는지, 모델의 일반화 성능이 얼마나 개선되었는지 확인해 보세요.