Let's explore an example PyTorch end-to-end workflow
Resources :
머신러닝에서의 데이터는 거의 모든것이 될 수있다.
Machine learning is a game of two parts :

import torch
# 1. 가중치와 편향 설정
weight = 0.7 # b
bias = 0.3 # a
# 2. 데이터 생성 (입력값 X)
start = 0
end = 1
step = 0.02
X = torch.arange(start, end, step).unsqueeze(dim=1)
y= weight * X + bias
# 3. 출력값 Y 계산
y = weight * X + bias # 선형 회귀 공식 적용
# 4. 데이터 확인
print("X:", X[:10]) # X의 처음 10개 값
print("y:", y[:10]) # y의 처음 10개 값
print("X 길이:", len(X))
print("y 길이:", len(y))

데이터를 훈련 세트와 테스트 세트로 분할하는 것은 가장 중요한 개념 중 하나이다.
# Create a train/test split
train_split = int(0.8 * len(X))
X_train, y_train = X[:train_split], y[:train_split] # 훈련 세트로 분할
X_test, y_test = X[train_split:], y[train_split:] # 테스트 세트로 분할
len(X_train), len(y_train), len(X_test), len(y_test) # 훈련 세트와 테스트 세트의 길이 출력

데이터를 어떻게 하면 더 잘 시각화할 수있을까?
Visualize !
import matplotlib.pyplot as plt
def plot_predictions(train_data=X_train,
train_labels = y_train,
test_data = X_test,
test_labels = y_test,
predictions = None):
"데이터를 테스트하고 예측하고, 비교"
plt.figure(figsize=(10,7))
# plot training data in blue
plt.scatter(train_data, train_labels, c="b", s = 4, label="Training data")
# plot test data in green
plt.scatter(test_data, test_labels, c="g", s = 4, label="Testing data")
# Are there predictions?
if predictions is not None:
# plot the predictions in red if they exist
plt.scatter(test_data, predictions, c="r", s = 4, label="Predictions")
# Show the legend
plt.legend(prop={"size": 14})
plot_predictions()


My first PyTorch model !
following resource from Real Python : https://realpython.com/python3-object-oriented-programming/
from torch import nn
# Create linear regression model class
class LinearRegressionModel(nn.Module): # PyTorch의 거의 모든 것은 nn 모듈에서 상속되므로 nn.Module을 상속해야 한다.
def __init__(self):
super().__init__()
self.weights = nn.Parameter(torch.randn(1,
requires_grad=True,
dtype=torch.float))
self.bias = nn.Parameter(torch.randn(1,
requires_grad=True,
dtype=torch.float))
# Forward method to define the computation in the model : 모델에서 메소드를 정의하는 방법
def forward(self, x: torch.Tensor) -> torch.Tensor: # <- "x"는 입력 데이터를 나타내는 텐서
return self.weights * x + self.bias # 선형회귀 공식 적용

torch.nn의 PyTorch 레이어가 이를 설정한다.forward()을 써야한다.nn.Module 하위 클래스는 forward()를 덮어쓰도록 요구. 이 메서드는 forward 계산에서 발생하는 일을 정의합니다
model.parameters()를 사용하여 모델 매개변수 또는 모델 내부의 내용을 확인할 수 있다.
# Create a random seed
torch.manual_seed(42) # 랜덤 시드 고정
# Create an instance of the model (this is a subclass of nn.Module)
model_0 = LinearRegressionModel()
# 모델의 내부 매개변수를 확인
list(model_0.parameters())

# 매개변수 이름과 값을 딕셔너리 형태로 확인
model_0.state_dict()

랜덤 시드 설정 전후 비교
모델 초기 상태 예측
모델 초기 상태에서 예측하기
torch.no_grad() 또는 torch.inference_mode()를 사용하여 예측을 수행:# Make predictions with the model
with torch.inference_mode():
y_preds = model_0(X_test)
# torch.no _grad(),으로 비슷한 작업을 수행할 수도 있지만, inference_mode()을 선호한다.
with torch.no_grad():
y_preds = model_0(X_test)
y_preds

Visualize with prediction
plot_predictions(predictions=y_preds)

추론 모드란?
왜 추론 모드를 사용하는가?
훈련의 전체 개념은 모델이 어떤 알 수 없는 매개변수(이들은 무작위일 수 있음)에서 어떤 알 수 있는 매개변수로 이동하는 것이다. 데이터의 잘못된 표현에서 좋은 표현으로 이어지는 다른 최악의 상황에서도 마찬가지이다.
모델 예측이 얼마나 부실하거나 얼마나 잘못된지 측정하는 한 가지 방법은 loss function(손실 함수)를 사용하는 것이다.
Thins we need to train:
PyTorch에 특정하게, 우리는 다음을 필요로 한다:
nn.L1Loss() torch.optim.SGD()# Setup a loss function
loss_fn = nn.L1Loss()
# Set up an optimizer(stochastic gradient descent)
optimizer = torch.optim.SGD(params = model_0.parameters(),
lr = 0.01) # lr = learning rate(학습률) = 설정할 수 있는 가장 중요한 하이퍼파라미터

PyTorch의 훈련 루프는 머신 러닝 모델의 성능을 점진적으로 개선하는 핵심 과정이며, 손실 함수와 최적화를 활용하여 모델의 매개변수를 조정한다. 경사 하강법과 학습률 스케줄링을 통해 더 나은 결과를 도출한다.

0. training loop : 데이터를 반복문으로 처리
1. forward pass : 데이터를 모델의 forward() 함수를 통해 전달하여 예측을 수행하는 전방 전달 과정 - 전방 전파라고도 함
2. calculate loss(손실함수 계산) : 전방 전달 예측과 실제 라벨을 비교
3. optimizer zero grad(최적화 함수 초기화) : 매 에포마다 누적되므로, 각 전방 전달마다 새로 시작하도록 0으로 설정.
4. loss backward(손실 역전파) : 손실에 대한 모델의 각 매개변수에 대한 기울기를 계산하기 위해 네트워크를 역방향으로 이동(역전파(backpropagation))
5. optimizer step(최적화 함수 단계) : 최적화 함수를 사용하여 손실을 개선하려고 모델의 매개변수를 조정(경사 하강(gradient descent))
# epochs : 데이터를 반복하는 것 (이것은 우리가 직접 설정했기 때문에 하이퍼파라미터라고 한다.)
epochs = 1
# 0. 데이터를 반복문으로 처리
# 데이터를 모델을 통해 일정 횟수(예: 100회의 데이터 통과)의 에포크를 수행
for epoch in range(epochs):
# 모델을 훈련 모드로 설정
model_0.train()# PyTorch의 훈련 모드는 모든 기울기를 필요로 하는 매개변수를 훈련으로 설정.
# 1. forward pass
# 모델의 `forward()` 메서드를 수행하여 데이터를 모델을 통해 전달.
y_preds = model_0(X_test)
# 2. Calculate the loss
# 모델의 예측이 얼마나 잘못되었는지에 대한 손실 값을 계산.
loss= loss_fn(y_preds, y_test)
print(f"Loss: {loss}") # 손실 값 출력
# 3. optimizer zero grad (최적화 함수 초기화) : 매 에포마다 누적되므로, 각 전방 전달마다 새로 시작하도록 0으로 설정.
optimizer.zero_grad()
# 4. loss backward
# 손실 함수에 대한 역전파를 수행합니다( `requires_grad=True`인 모든 매개변수의 기울기를 계산합니다)
loss.backward()
# 5. optimizer step
# `loss.backward()`로 계산된 기울기에 따라 모델의 매개변수를 업데이트하는 최적화 함수를 단계를 진행
optimizer.step() # 루프를 통해 최적화가 누적되므로 다음 루프 반복을 위해 3단계에서 이를 초기화.
model_0.eval() # 기울기 추적 종료.
# 모델의 매개변수 출력
print(model_0.state_dict())


# 새로운 예측 생성
with torch.inference_mode():
y_preds_new = model_0(X_test)
# 새로운 예측 시각화
plot_predictions(predictions=y_preds_new)


torch.manual_seed(42) # 랜덤시드 설정(재현성을 위해)
# epochs : 데이터를 반복하는 것 (이것은 우리가 직접 설정했기 때문에 하이퍼파라미터라고 한다.)
epochs = 200
# Track different values
# 모델 진행 상황을 추적하는 데 도움이 되는 유용한 값을 저장하는 빈 리스트를 생성
epoch_count = []
loss_values = []
test_loss_values = []
# 0. 데이터를 반복문으로 처리
# 데이터를 모델을 통해 일정 횟수(예: 100회의 데이터 통과)의 에포크를 수행
for epoch in range(epochs):
# 모델을 훈련 모드로 설정
model_0.train()# PyTorch의 훈련 모드는 모든 기울기를 필요로 하는 매개변수를 훈련으로 설정.
# 1. forward pass
# 모델의 `forward()` 메서드를 수행하여 데이터를 모델을 통해 전달.
y_preds = model_0(X_test)
# 2. Calculate the loss
# 모델의 예측이 얼마나 잘못되었는지에 대한 손실 값을 계산.
loss= loss_fn(y_preds, y_test)
# 3. optimizer zero grad (최적화 함수 초기화) : 매 에포마다 누적되므로, 각 전방 전달마다 새로 시작하도록 0으로 설정.
optimizer.zero_grad()
# 4. loss backward
# 손실 함수에 대한 역전파를 수행합니다( `requires_grad=True`인 모든 매개변수의 기울기를 계산합니다)
loss.backward()
# 5. optimizer step
# `loss.backward()`로 계산된 기울기에 따라 모델의 매개변수를 업데이트하는 최적화 함수를 단계를 진행
optimizer.step() # 루프를 통해 최적화가 누적되므로 다음 루프 반복을 위해 3단계에서 이를 초기화.
# 모델을 평가 모드로 설정
# 훈련이 아닌 평가를 원한다고 모델에게 알려준다. (훈련에 사용되지만 평가에는 사용되지 않는 기능을 비활성화)
model_0.eval()
# 더 빠른 성능을 위한 추론 : `torch.inference_mode()` 컨텍스트 관리자를 활성화하여 경사 추적과 같은 기능을 비활성화(추론에는 경사 추적이 필요하지 않다.)
with torch.inference_mode():
# 1. forward 전달
# 모델을 통해 테스트 데이터를 전달합니다(이는 모델의 구현된 `forward()` 메서드를 호출합니다)
test_pred = model_0(X_test)
# 2. 손실 계산
# 테스트 손실 값 계산(모델의 예측이 테스트 데이터셋에서 얼마나 잘못되었는지, 낮을수록 더 좋음)
test_loss = loss_fn(test_pred, y_test)
# 3. 10번째 epoch마다 상태 출력
# 훈련/테스트 중 모델의 진행 상황을 ~10 에포크마다 출력 (참고: 여기에 출력되는 것은 특정 문제에 맞게 조정할 수 있다.)
if epoch % 10 == 0:
epoch_count.append(epoch)
loss_values.append(loss)
test_loss_values.append(test_loss)
print(f"Epoch : {epoch} | Loss : {loss} | Test loss : {test_loss}")
# 모델의 매개변수 출력
print(model_0.state_dict())


# 시각화
plot_predictions(predictions=test_pred)

1. 경사 추적 비활성화
torch.inference_mode()는 기울기 추적을 비활성화하여 아래의 이점을 제공:
훈련 단계에서는 역전파(backpropagation)를 위해 기울기 추적이 필수적이지만, 평가 및 추론 단계에서는 모델의 성능을 측정하는 것이 목적이므로 기울기 추적이 필요 없다.
2. 계산 그래프 구성 방지
훈련 시에는 PyTorch가 내부적으로 계산 그래프(Computation Graph) 를 구성하여 역전파를 수행할 수 있도록 설정한다. 하지만 추론 시에는 이 그래프가 필요하지 않으므로 torch.inference_mode()를 통해 이를 방지:
3. 성능 최적화
torch.inference_mode()는 추론 및 평가 작업을 위해 추론 전용 모드를 제공:
4. 왜 평가 후에 사용하는가?
model.eval()) 는 드롭아웃(dropout), 배치 정규화(batch normalization) 등의 레이어를 비활성화하여 모델이 평가에 적합한 상태로 동작하도록 설정.torch.inference_mode()) 는 모델의 매개변수 업데이트를 필요로 하지 않는 순방향 전달(forward pass) 에 최적화된 상태로 실행.결론적으로, model.eval()과 torch.inference_mode()는 목적이 다르다:
• model.eval(): 평가 모드로 전환 (모델의 상태 설정)
• torch.inference_mode(): 추론 전용 모드로 전환 (경사 추적 및 계산 그래프 비활성화)
이 두 가지를 조합함으로써 모델의 정확한 평가와 추론 작업의 효율성을 동시에 얻을 수 있다.
# plot the loss curves
plt.plot(epoch_count, np.array(torch.tensor(loss_values).numpy()), label="Train loss")
plt.plot(epoch_count, np.array(torch.tensor(test_loss_values).numpy()), label="Test loss")
plt.title("Training and test loss culves")
plt.ylabel("Loss")
plt.xlabel("Epochs")
plt.legend()

PyTorch에서 모델을 저장하고 로드하는 데 사용하는 세 가지 주요 메서드가 있다.
torch.save() - Python의 pickle 형식으로 PyTorch 객체를 저장torch.load() - 저장된 PyTorch 객체를 로드torch.nn.Module.load_state_dict() - 이 메서드를 사용하여 모델의 저장된 상태 사전을 로드.# Saving our PyTorch model
from pathlib import Path
# 1. Create models directory
MODEL_PATH = Path("models")
MODEL_PATH.mkdir(parents=True, exist_ok=True)
# 2. Create model save path
MODEL_NAME = "01_pytorch_workflow_model_0.pth"
MODEL_SAVE_PATH = MODEL_PATH / MODEL_NAME
print(f" Saving model to : {MODEL_SAVE_PATH}")
torch.save(obj=model_0.state_dict(),
f=MODEL_SAVE_PATH)
# 3. Saving the model state dict
print((model_0.state_dict))


모델의 state_dict()를 저장했기 때문에, 모델 클래스의 새로운 인스턴스를 생성하고 저장된 state_dict() 정보를 로드한다.
# 저장된 state_dict()를 로드하려면 모델 클래스의 새 인스턴스를 생성해야 합니다.
loaded_model_0 = LinearRegressionModel()
# 저장된 model_0의 state_dict를 로드합니다 (이렇게 하면 새로운 인스턴스가 업데이트된 매개변수로 업데이트됩니다)
loaded_model_0.load_state_dict(torch.load(f=MODEL_SAVE_PATH))