7주 차 학습
Deep Learning
인공지능(AI; Artificial Intelligence)
- 사람의 지능을 만들기 위한 시스템이나 프로그램
- 머신러닝에 포함되는 기술
인공뉴런(Artificial Neuron)
- $a = b + w_1x_1 + w_2x_2 + \cdots + w_mx_m$
인공신경망(Artificial Neural Network)
- 다수의 인공뉴런이 연결되어 구성된 네트워크
- 입력층(Input Layer), 은닉층(Hidden Layer), 출력층(Output Layer)으로 구성
딥러닝(Deep Learning)
- 인공신경망의 한 종류로, 은닉층이 많은 신경망
- 머신러닝이 처리하기 어려운 비정형 데이터 처리
손실 함수(Loss Function)
- Regression
경사하강법(Gradient Descent)
- 기울기를 통해 모델의 파라미터 조정
- 예측과 실제값을 비교하여 손실을 구함
- 손실이 작아지는 방향으로 파라미터 조정
최적화 알고리즘(Optimizer)
- 손실 함수를 최소화하기 위해 가중치와 바이어스를 조정
- SGD
- 임의로 추출한 일부 데이터를 사용
- 데이터셋이 크고 연산 속도가 중요한 경우에 사용
- Momentum
- 이전 기울기(gradient) 정보를 반영하여 가중치(weight) 업데이트
- RMSProp
- 이전 업데이트 맥락을 통해 학습률(learning rate) 업데이트
- Adam
- Momentum과 RMSProp 결합
- 데이터셋이 작거나 노이즈가 많은 경우에 사용
- SGD
역전파(Back-Propagation)
- 손실값을 구해 해당 손실에 관여하는 가중치들을 손실이 작아지는 방향으로 수정
Deep Learning - PyTorch
Tensor 생성
- torch.tensor()
Tensor 속성
- tensor.shape: tensor의 크기
- tensor.dtype: tensor의 데이터 타입
- tensor.device: tensor가 위치한 장치 (CPU - cpu / GPU - cuda)
Deep Learning - PyTorch(Dataset)
DataLoader
- 데이터셋을 미니배치(batch) 단위로 로드하고, 반복(iteration)할 수 있도록 도와주는 클래스
from torch.utils.data import DataLoader
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)
test_features, test_labels = next(iter(test_dataloader))
Dataset Class
# 이미지 데이터
import os
from torch.utils.data import Dataset
from torchvision.transforms import ToTensor
from pathlib import Path
from PIL import Image
class CustomDataset(Dataset): # Dataset 상속
def __init__(self, data_path:str, transform=None) -> None:
self.paths = list(Path(data_path).glob('*/*.jpg'))
self.index_to_class = self.__get_classes(data_path)
self.class_to_index = { class_name: i for i, class_name in enumerate(self.index_to_class) }
self.transform = transform
def __get_classes(self, data_path):
return sorted(entry.name for entry in os.scandir(data_path) if entry.is_dir())
def __len__(self) -> int:
return len(self.paths)
def __getitem__(self, index:int):
feature_path = self.paths[index]
img = Image.open(feature_path)
target_name = feature_path.parent.stem
if self.transform:
img = self.transform(img)
return img, self.class_to_index[target_name]
train_path = ("./data/Image Folder")
train_custom_dataset = CustomDataset(data_path=train_path, transform=ToTensor())
len(train_custom_dataset) # CustomDataset의 magic method - len
feature, target = train_custom_dataset[0] # CustomDataset의 magic method - getitem
# 타이타닉 데이터
import pandas as pd
import seaborn as sns
from torch.utils.data import Dataset
class CustomDataset(Dataset): # Dataset 상속
def __init__(self, df:pd.DataFrame, target:str, transform=None) -> None:
self.features = df.drop(columns=target)
self.target = df[target]
self.transform = transform
def __len__(self) -> int:
return self.features.shape[0]
def __getitem__(self, index:int):
feature = self.features.iloc[index]
target = self.target.iloc[index]
if self.transform:
feature = self.transform(feature)
return feature, target
df_train = sns.load_dataset('titanic')
train_custom_dataset = CustomDataset(df=df_train, target='survived')
len(train_custom_dataset) # CustomDataset의 magic method - len 호출
feature, target = train_custom_dataset[0] # CustomDataset의 magic method - getitem 호출
Deep Learning - PyTorch(Model)
Regression
import torch
from torch import nn
# Data
weight = 0.7
bias = 0.3
start = 0
end = 1
step = 0.02
X = torch.arange(start, end, step).unsqueeze(dim=1)
y = weight * X + bias
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:]
# Model
class LinearRegressionModel(nn.Module):
def __init__(self) -> None:
super().__init__()
self.weights = nn.Parameter(
torch.randn(1, dtype=torch.float),
requires_grad=True
)
self.bias = nn.Parameter(
torch.randn(1, dtype=torch.float),
requires_grad=True
)
def forward(self, x):
pred = self.weights * x + self.bias
return pred
device = 'cuda' if torch.cuda.is_available() else 'cpu'
torch.manual_seed(42)
model = LinearRegressionModel().to(device)
# Training
loss_fn = nn.L1Loss()
optimizer = torch.optim.SGD(
params=model.parameters(),
lr=0.01
)
epochs = 100
for epoch in range(epochs):
model.train()
y_pred = model(X_train.to(device))
loss = loss_fn(y_pred, y_train.to(device))
optimizer.zero_grad()
loss.backward()
optimizer.step()
model.eval()
with torch.inference_mode():
test_pred = model(X_test.to(device))
test_loss = loss_fn(test_pred, y_test.type(torch.float).to(device))
if epoch % 10 == 0:
print(f"Epoch: {epoch} | MAE Train Loss: {loss} | MAE Test Loss: {test_loss}")
Binary Classification
import pandas
import torch
from sklearn.datasets import make_circles
from sklearn.model_selection import train_test_split
# Data
n_samples = 1000
X, y = make_circles(n_samples, noise=0.03, random_state=42)
X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.float)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
# Model
class ClassificationModel(nn.Module):
def __init__(self, input_size=2, output_size=1, hidden_size=512) -> None:
super().__init__()
self.linear_relu_stack=nn.Sequential(
nn.Linear(input_size, hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, output_size)
)
def forward(self, x):
out = self.linear_relu_stack(x)
return out
device = 'cuda' if torch.cuda.is_available() else 'cpu'
torch.manual_seed(42)
model = ClassificationModel().to(device)
# Training
loss_fn = nn.BCEWithLogitsLoss()
optimizer = torch.optim.SGD(
params=model.parameters(),
lr=0.01
)
def accuracy_fn(y_true, y_pred):
correct = torch.eq(y_true, y_pred).sum().item()
acc = (correct / len(y_true)) * 100
return acc
epochs = 500
for epoch in range(epochs):
model.train()
y_pred = model(X_train.to(device)).squeeze()
loss = loss_fn(y_pred, y_train.to(device))
optimizer.zero_grad()
loss.backward()
optimizer.step()
y_pred_prob = torch.round(torch.sigmoid(y_pred))
acc = accuracy_fn(y_true=y_train, y_pred=y_pred_prob.cpu())
model.eval()
with torch.inference_mode():
y_pred = model(X_test.to(device)).squeeze()
test_loss = loss_fn(y_pred, y_test.to(device))
y_pred_prob = torch.round(torch.sigmoid(y_pred))
test_acc = accuracy_fn(y_true=y_test, y_pred=y_pred_prob.cpu())
if epoch % 100 == 0:
print(f"Epoch: {epoch} | Loss: {loss:.5f}, Accuracy: {acc:.2f} | "\
f"Test Loss: {test_loss:.5f}, Test Accuracy: {test_acc:.2f}")
Multiclass Classification
# Random Seed 고정
import os
import random
import numpy as np
import torch
def reset_seeds(seed=42):
random.seed(seed)
os.environ['PYTHONHASHSEED']
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.backends.cudnn.deterministic=True
# Dataset
from torchvision import datasets
from torchvision.transforms import ToTensor
train_dataset = datasets.FashionMNIST(
root='download',
train=True,
download=True,
transform=ToTensor()
)
test_dataset = datasets.FashionMNIST(
root='download',
train=False,
download=True,
transform=ToTensor()
)
# DataLoader
from torch.utils.data import DataLoader
reset_seed()
batch_size=64
train_dataloader = DataLoader(
train_dataset,
batch_size,
shuffle=True
)
test_dataloader = DataLoader(
test_dataset,
batch_size, shuffle=True
)
features, targets = next(iter(train_dataloader))
# Model
from torch import nn
class MulticlassModel(nn.Module):
def __init__(self, input_size, output_size, hidden_size=32) -> None:
super().__init__()
self.linear_relu_stack = nn.Sequential(
nn.Flatten(),
nn.Linear(input_size, hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, hidden_size*2),
nn.ReLU(),
nn.Linear(hidden_size*2, output_size)
)
def forward(self, x):
return self.linear_relu_stack(x)
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = MulticlassModel(1*28*28, len(train_dataset.classes)).to(device)
# Training
from tqdm.auto import tqdm
from torch.optim import SGD
from helper_functions import accuracy_fn
def model_train(model, dataloader, device, loss_fn, optimizer):
model.train()
train_loss = 0
for feature, target in tqdm(dataloader, desc='Train Loop', leave=False):
feature = feature.to(device)
target = target.to(device)
pred = model(feature)
loss = loss_fn(pred, target)
train_loss += loss.cpu().item()
optimizer.zero_grad()
loss.backward()
optimizer.step()
return train_loss / len(dataloader)
def model_test(model, dataloader, device, loss_fn, accuracy_fn):
model.eval()
test_loss, test_accuracy = 0, 0
with torch.inference_mode():
for feature, target in tqdm(dataloader, desc='Test Loop', leave=False):
feature = feature.to(device)
target = target.to(device)
pred = model(feature)
loss = loss_fn(pred, target)
test_loss += loss.cpu().item()
pred_prob = nn.Softmax(dim=1)(pred).argmax(dim=1)
test_accuracy += accuracy_fn(pred_prob.cpu(), target.cpu())
return test_loss / len(dataloader), test_accuracy / len(dataloader)
def loss_plot(train_loss, test_loss):
plt.plot(train_loss, label='Train Loss')
plt.plot(test_loss, label='Test Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.show()
class EarlyStopper(object):
def __init__(self, trial_num, best_model_path) -> None:
self.trial_num = trial_num
self.now_trial = 0
self.best_loss = np.inf
self.best_model_path = best_model_path
def get_best_model(self, device):
return torch.load(self.best_model_path).to(device)
def is_continuable(self, loss, model):
if loss < self.best_loss:
self.best_loss = loss
self.now_trial = 0
torch.save(model, self.best_model_path)
return True
elif self.now_trial < self.trial_num:
self.now_trial += 1
return True
else:
return False
def training(model, early_stopper:EarlyStopper, train_dataloader, test_dataloader, \
loss_fn, accuracy_fn, device='cpu', optimizer=None, lr=0.01, epochs=100):
model = model.to(device)
if optimizer is None:
optimizer = SGD(params=model.parameters(), lr=lr)
train_losses, test_losses = [], []
for epoch in tqdm(range(epochs), desc='Epoch Loop', leave=True):
train_loss = model_train(model, train_dataloader, device, loss_fn, optimizer)
train_losses.append(train_loss)
test_loss, test_accuracy = model_test(model, test_dataloader, device, loss_fn, accuracy_fn)
test_losses.append(test_loss)
if not early_stopper.is_continuable(test_loss, model):
break
loss_plot(train_losses, test_losses)
reset_seeds()
model = MulticlassModel(1*28*28, len(train_dataset.classes))
early_stopper = EarlyStopper(trial_num=5, best_model_path='models/best_model.pth')
loss_fn = nn.CrossEntropyLoss()
training(model, early_stopper, train_dataloader, test_dataloader, loss_fn, accuracy_fn, device)
7주 차 회고
Keep
매일 / 매주 블로그 및 회고 작성
매일 / 매주 꾸준히 배운 내용을 정리하고 회고를 작성하며 지나간 시간을 되돌아볼 수 있어서 좋았다. 부족한 부분이 무엇인지 알 수 있어서 블로그 작성하는 것이 나에게 도움이 되는 것 같다.
Problem
수면 부족
매일 꾸준히 6시에 일어나는 것은 동일하지만 자는 시간이 불규칙하고 나에게 6시간 수면은 짧은 것 같다는 생각을 하게 되었다. 하지만 집에서 해야 할 일들도 있기 때문에 이에 대해서 고민을 해봐야 할 것 같다.
Try
SQLD 시험 준비
ADsP 시험은 끝났지만 SQLD 시험도 신청했기 때문에 2주 동안 열심히 공부해봐야 할 것 같다. 이왕 열심히 해보고 싶어서 이것저것 일을 많이 벌이긴 해서 하나씩 해결해 나가야 한다.
단위 프로젝트
이번 단위가 끝나가서 단위 프로젝트를 시작하게 되었다. 열심히 하고는 싶지만 이번 단위에 대해서 내가 많이 부족한 것 같아서 더 노력을 해야 할 것 같다.
'SK네트웍스 Family AI캠프 10기 > Weekly 회고' 카테고리의 다른 글
| [플레이데이터 SK네트웍스 Family AI 캠프 10기] 9주차 회고 (1) | 2025.03.09 |
|---|---|
| [플레이데이터 SK네트웍스 Family AI 캠프 10기] 8주차 회고 (0) | 2025.03.03 |
| [플레이데이터 SK네트웍스 Family AI 캠프 10기] 6주차 회고 (0) | 2025.02.17 |
| [플레이데이터 SK네트웍스 Family AI 캠프 10기] 5주차 회고 (0) | 2025.02.09 |
| [플레이데이터 SK네트웍스 Family AI 캠프 10기] 4주차 회고 (0) | 2025.02.02 |