PyTorch : Numpy + AutoGrad + Function
Tensor handling
Tensor operations
행렬곱셈 연산은 함수는 dot이 아닌 mm 사용
Tensor operations for ML/DL formula
nn.functional 모듈을 통해 다양한 수식 변환을 지원함
import torch
import torch.nn.functional as F
tensor = torch.FloatTensor([0.5,0.7,0.1])
h_tensor = F.softmax(tensor,dim=0)
h_tensor
# tensor([0.3458,0.4224,0.2318])
AutoGrad
PyTorch의 핵심은 자동 미분의 지원 : backward 함수 사용
w = torch.tensor(2.0,requires_grad = True)
y = w**2
z = 10*y+25
z.backward()
w.grad
torch.nn.Module
nn.Parameter
Backward
for epoch in range(epochs):
...
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs,labels)
loss.backward()
optimizer.step()
...
Dataset 클래스
import torch
import torch.utils.data import Dataset
class CustomDataset(Dataset):
def __init__(self,text,labels): #초기 데이터 생성 방법을 지정
self.labels = labels
self.data = text
def __len__(self): # 데이터의 전체 길이
return len(self.labels)
def __getitem__(self,idx): # index 값을 주었을 때 반환되는 데이터의 형태
label = self.labels[idx]
text = self.data[idx]
sample = {"Text":text, "Class":label}
return sample
DataLoader 클래스
from torch.utils.data import Dataset, DataLoader
MyDataLoader = DataLoader(MyDataset, batch_size = 2, shuffle = True)
next(iter(dataset_loader)) # 데이터가 나옴
torchsummary
모델의 구조를 Keras 형태로 볼 수 있다.
checkpoints
학습의 중간 결과를 저장하여 최선의 결과를 선택
earlystopping 기법 사용시 이전 학습의 결과물을 저장
loss와 metric 값을 지속적으로 확인 및 저장
일반적으로 epoch,loss,metric을 함께 저장하여 확인
# exmaple
torch.save({
'epoch' : e,
'model_state_dict' : model.state_dict(),
'potimizer_state_dict' : optimizer.state_dict(),
'loss' : epoch_loss,},
f"saved/checkpoint_model_{e}_{epoch_loss/len(dataloader)}_{epoch_acc/len(dataloader)}.pt")
checkpoint = torch.load(PATH)
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
loss = checkpoint['loss']
전이 학습
#example
def binary_acc(y_pred, y_test):
y_pred_tag = torch.round(torch.sigmoid(y_pred))
correct_results_sum = (y_pred_tag == y_test).sum().float()
acc = correct_results_sum/y_test.shape[0]
acc = torch.round(acc * 100)
return acc
my_model = MyNewNet()
my_model = my_model.to(device)
for param in my_model.parameters():
param.requires_grad = False
for param in my_model.linear_layers.parameters():
param.requires_grad = True
criterion = nn.BCEWithLogitsLoss()
optimizer = optim.Adam(my_model.parameters(), lr=LEARNING_RATE)
for e in range(1, EPOCHS+1):
epoch_loss = 0
epoch_acc = 0
for X_batch, y_batch in dataloader:
X_batch, y_batch = X_batch.to(device), y_batch.to(device).type(torch.cuda.FloatTensor)
optimizer.zero_grad()
y_pred = my_model(X_batch)
loss = criterion(y_pred, y_batch.unsqueeze(1))
acc = binary_acc(y_pred, y_batch.unsqueeze(1))
loss.backward()
optimizer.step()
epoch_loss += loss.item()
epoch_acc += acc.item()
print(f'Epoch {e+0:03}: | Loss: {epoch_loss/len(dataloader):.5f} | Acc: {epoch_acc/len(dataloader):.3f}')
Monitoring tools for PyTorch
Tensorboard
#example
import os
logs_base_dir = "logs"
os.makedirs(logs_base_dir, exist_ok=True)
from torch.utils.tensorboard import SummaryWriter
import numpy as np
writer = SummaryWriter(logs_base_dir)
for n_iter in range(100):
writer.add_scalar("Loss/train",np.random.random(),n_iter)
writer.add_scalar("Loss/test",np.random.random(),n_iter)
writer.add_scalar("Accuracy/train",np.random.random(),n_iter)
writer.add_scalar("Accuracy/test",np.random.random(),n_iter)
writer.flush()
%load_ext tensorboard
%tensorboard --logdir {logs_base_dir}
weight & biases
# example
EPOCHS = 100
BATCH_SIZE = 32
LEARNING_RATE = 0.001
config={"epochs": EPOCHS, "batch_size": BATCH_SIZE, "learning_rate" : LEARNING_RATE}
wandb.init(project="my-test-project", config=config)
# wandb.config.batch_size = BATCH_SIZE
# wandb.config.learning_rate = LEARNING_RATE
# config={"epochs": EPOCHS, "batch_size": BATCH_SIZE, "learning_rate" : LEARNING_RATE}
for e in range(1, EPOCHS+1):
epoch_loss = 0
epoch_acc = 0
for X_batch, y_batch in train_dataset:
X_batch, y_batch = X_batch.to(device), y_batch.to(device).type(torch.cuda.FloatTensor)
optimizer.zero_grad()
y_pred = model(X_batch)
loss = criterion(y_pred, y_batch.unsqueeze(1))
acc = binary_acc(y_pred, y_batch.unsqueeze(1))
loss.backward()
optimizer.step()
epoch_loss += loss.item()
epoch_acc += acc.item()
train_loss = epoch_loss/len(train_dataset)
train_acc = epoch_acc/len(train_dataset)
print(f'Epoch {e+0:03}: | Loss: {train_loss:.5f} | Acc: {train_acc:.3f}')
wandb.log({'accuracy': train_acc, 'loss': train_loss})
Multi-GPU
# example
parallel_model = torch.nn.DataParallel(model)
...
loss.mean().backward()
...
Hyperparameter Tuning
# config에 serach space 지정, 학습 스케줄링 알고리즘 지정
config = {
"l1" : tune.sample_from(lambda _ : 2 ** np.random.randint(2,9)),
"l2" : tune.sample_from(lambda _ : 2 ** np.random.randint(2,9)),
"lr" : tune.loguniform(1e-4, 1e-1),
"batch_size" : tune.choice([2,4,8,16])
}
scheduler = ASHAScheduler(
metric = "loss", mode = "min", max_t = max_num_epochs, grace_period = 1, reduction_factor = 2)
reporter = CLIReporter(
metric_columns = ["loss","accuracy","training_iteration"])
result = turn.run(
partial(train_cifar, data_dir = data_dir),
resources_per_tial = {"cpu":2,"gpu":gpus_per_trial},
config = config, num_samples = num_samples, scheduler = scheduler,
progress_report = report)
PyTorch Troubleshooting
Out Of Memory
GPUtil 사용하기
# example
import GPUtil
GPUtil.showUtilization()
torch.cuda.empty_cache()
torch.no_grad()
벡터나 행렬의 norm을 계산하기 위해서 torch.linalg.norm을 사용한다.
torch.tensor VS torch.Tensor
Set random seed
# Set random seed
SEED = 2021
random.seed(SEED)
np.random.seed(SEED)
os.environ["PYTHONHASHSEED"] = str(SEED)
torch.manual_seed(SEED)
torch.cuda.manual_seed(SEED) # type: ignore
torch.backends.cudnn.deterministic = True # type: ignore
torch.backends.cudnn.benchmark = True # type: ignore
# 중요하지 않은 에러 무시
warnings.filterwarnings(action='ignore')
# 유니코드 깨짐현상 해결
mpl.rcParams['axes.unicode_minus'] = False
Dataset의 기본 구성 요소
# 기본 요소
from torch.utils.data import Dataset
class CustomDataset(Dataset):
def __init__(self,):
pass
def __len__(self):
pass
def __getitem__(self,idx):
pass
init
getitem
len
PyTorch의 DataLoader
DataLoader(dataset, batch_size=1,shuffle=False,sampler=None,batch_sampler=None,
num_workers=0, collate_fn = None, pin_memory = False,
drop+last = False, timeout = 0, worker_init-fn = None)
dataset
: Dataset 인스턴스가 들어감batch_size
: batch_sizeshuffle
: 데이터를 DataLoader에서 섞어서 사용하는지sampler, batch_sampler
: index를 컨트롤 하는 방법, index를 원하는 방식대로 조정함. 그렇기에 shuffle 파라미터는 False(기본값)여야 함num_workers
: 데이터를 불러올 때 사용하는 서브 프로세스 개수collate_fn
: zero-padding이나 Variable Size 데이터 등 데이터 사이즈를 맞추기 위해 많이 사용