import torch.nn as nnnn.Lineartorch.optim as optimoptim.SGD(model.parameters(), lr=0.00001)import torch.nn.functional as FF.mse_loss(y_pred, y_optimizer.zero_grad로 초기화optimizer.step()# 결과를 시각화할 때 텐서 연산의 결과를 초기화 후 넘파이 배열로 변경하여 시각화 하는 것이 안전
# 텐서를 끊고(.detach()) 넘파이로 바꿈(.numpy())
# 예측값(y_pred) 결과의 텐서를 해제하고 넘파이로 변환
np_pred = y_pred.detach().numpy()
# 시각화 → 산점도 그래프
plt.scatter(x=np_pred, y=y)
plt.show()





# 라이브러리 불러오기
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tqdm import tqdm
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# 데이터 불러오기
from sklearn.datasets import fetch_california_housing
# 데이터프레임에 담기
data=fetch_california_housing()
h_data=pd.DataFrame(data.data, columns=data.feature_names)
h_data["price"]=data.target
h_data.shape
(20640, 9)
🏠 California Housing Dataset 컬럼 설명
| 컬럼명 | 설명 |
|---|---|
MedInc | 지역의 중간 소득 (단위: 10,000달러) |
HouseAge | 주택 연식 (해당 지역 내 평균 주택 연수) |
AveRooms | 가구당 평균 방 수 |
AveBedrms | 가구당 평균 침실 수 |
Population | 지역 내 인구 수 |
AveOccup | 가구당 평균 거주 인원 |
Latitude | 위도 |
Longitude | 경도 |
Price | 주택의 중간 가격 (단위: 100,000달러) → MedHouseVal 컬럼이 Price 역할을 함 |
h_data.hist(figsize=(10,10))
plt.tight_layout()
plt.show()

# 객체 생성
st_scaler = StandardScaler()
# 입력특성 데이터 스케일링 → 정답 데이터 제외하고!
h_data.values[:,:-1] = st_scaler.fit_transform(h_data.values[:,:-1])
# 문제와 정답으로 분리
# numpy 형태의 데이터를 tensor 형태로 변경
t_data = torch.from_numpy(h_data.values).float()
# 문제, 정답 분리
X = t_data[:,:-1]
y = t_data[:,-1:] # 정답 데이터를 2차원으로 출력해 주기 위해 (unsqeeze 안 하려고)
print(X.shape, y.shape)
torch.Size([20640, 8]) torch.Size([20640, 1])

# nn.Module: PyTorch에서 제공하는 기본 모델 클래스 → 상속하여 새 모델 정의
# 상속: 기본 뼈대는 "부모"로 삼고 새로운 클래스를 정의하여 다양한 기능을 만들어 사용할 수 있음
class MyModel(nn.Module): # PyTorch에서 제공하는 기본 모듈 클래스를 상속받겠다는 뜻
# 모델의 구조(레이어)를 정의하는 함수를 정의
def __init__(self, input_dim, out_dim): # input_dim, out_dim: 입력 특성의 수, 출력 수를 외부에서 받기
super().__init__() # 부모 클래스 생성자 호출
self.input_dim = input_dim # 외부에서 전달받은 argument를 내부에서 사용하기 위해 self로 넣어 주어야 함
self.out_dim = out_dim
# 입력층 → 모델의 입력 layer를 정의
self.linear1 = nn.Linear(self.input_dim, 3)
# 중간층(은닉층)
self.linear2 = nn.Linear(3,3) # 3의 퍼셉트론을 한 개의 층에서 사용하겠다는 뜻
self.linear3 = nn.Linear(3,3) # 3의 퍼셉트론을 한 개의 층에서 사용하겠다는 뜻
# 출력층
self.linear4 = nn.Linear(3, self.out_dim)
# 활성화함수
self.act = nn.ReLU()
# 데이터를 입력 받아 연산을 진행하는 함수를 정의
def forward(self, X):
h = self.act(self.linear1(X))
h = self.act(self.linear2(h))
h = self.act(self.linear3(h))
y = self.linear4(h) # 회귀 문제 → 출력층 활성화 함수: 항등함수 → 따로 입력할 필요 없음
return y
# 모델 생성
# MyModel(입력, 출력)
model1 = MyModel(X.size(-1), y.size(-1))
print(model1)
MyModel(
(linear1): Linear(in_features=8, out_features=3, bias=True)
(linear2): Linear(in_features=3, out_features=3, bias=True)
(linear3): Linear(in_features=3, out_features=3, bias=True)
(linear4): Linear(in_features=3, out_features=1, bias=True)
(act): ReLU()
)
# 학습 횟수 및 출력 횟수, 학습률 지정
n_epochs = 4000
print_interval = 200
learning_rate = 0.001
# 최적화 함수 정의
optimizer = optim.Adam(model1.parameters(), lr=learning_rate)
# 학습 반복문 작성
for i in tqdm(range(n_epochs)):
# 예측 결과
y_pred = model1(X)
# 손실 함수를 통한 loss
loss = F.mse_loss(y_pred, y)
# 최적화 함수 초기화
optimizer.zero_grad()
# 오차역전파
loss.backward()
# 결과 담기
optimizer.step()
# 결과 출력
if (i+1)%print_interval==0:
print(f"epoch: {i+1}, loss: {loss:.4e}")

반복문에서
.forward()를 직접 호출하지 않았는데 왜 학습이 되나요? 자동 실행된 건가요?
네, 맞아요! 반복문 안에서 명시적으로.forward()를 호출하지 않아도y_pred=model1(X)를 실행하면 내부적으로forward()를 자동 실행합니다.
이는 해당 모델 객체가 PyTorch에서nn.Module을 상속 받아__call__메서드가 재정의되어 있기 때문입니다.
model1(X)는 사실model1.__call__(X)이고 이__call__메서드 안에서 내부적으로forward(X)를 호출하도록 되어 있습니다.
- 요약:
- 반복문에서 model1(X) 한 줄이면 자동으로 forward(X)가 실행되는 것과 같습니다.
- 그래서
.forward(X)를 직접 호출하지 않아도 모델이 작동해요.
torch.nn.Module(*args, **kwargs) 클래스forward(*input)nn.Sequential()을 사용하여 모델 구현model2 = nn.Sequential(
nn.Linear(X.size(-1), 3) # (입력 특성의 수, 퍼셉트론의 수)
, nn.ReLU() # 활성화 함수
, nn.Linear(3,3) # (입력 수, 퍼셉트론의 수)
, nn.ReLU()
, nn.Linear(3,3)
, nn.ReLU()
, nn.Linear(3,y.size(-1))
)
print(model2)
# 학습 횟수 및 출력 횟수, 학습률 지정
n_epochs = 4000
print_interval = 200
learning_rate = 0.001
# 최적화 함수 정의
optimizer = optim.Adam(model2.parameters(), lr=learning_rate)
# 학습 반복문 작성
for i in tqdm(range(n_epochs)):
# 예측 결과
y_pred = model2(X)
# 손실 함수를 통한 loss
loss = F.mse_loss(y_pred, y)
# 최적화 함수 초기화
optimizer.zero_grad()
# 오차역전파
loss.backward()
# 결과 담기
optimizer.step()
# 결과 출력
if (i+1)%print_interval==0:
print(f"epoch: {i+1}, loss: {loss:.4e}")
Sequential(
(0): Linear(in_features=8, out_features=3, bias=True)
(1): ReLU()
(2): Linear(in_features=3, out_features=3, bias=True)
(3): ReLU()
(4): Linear(in_features=3, out_features=3, bias=True)
(5): ReLU()
(6): Linear(in_features=3, out_features=1, bias=True)
)

-∞ ~ ∞) → 확률 값 1개(0 ~ 1 사이 한 개의 확률 값): sigmoid