[08.26 P Stage Day4] - 📝 Training & Inference
모델 훈련(Train) 과 Inference
- 요소
Loss
: Loss 함수 = Cost 함수 = Error 함수, Backpropagation을 진행할 때, Output과 Target 값을 가지고 Loss 값을 구할 때 사용하는 함수이다.
- nn.Loss 패키지에서 확인할 수 있다.Loss 함수 또한 forward 함수를 가지고 있기 때문에, Model과 연결되어 학습이 진행된다.
- loss.backward()
- 재미있는 것은 net이라는 Model에서 output이 만들어 지고, output과 label 값을 통해서 Loss 값을 구해준다. 또한 중요한 사실은, forward 함수를 통해서 Model 부터 loss 과정 전체가 Chain 으로 연결이 된다.
- : 이 함수가 실행되면 모델의 파라미터의 grad 값이 업데이트가 된다.
- Focal Loss, Label SmoothingLabel Smoothing Loss : Class Target Label을 Onehot 표현하기 보다 조금 Soft하게 표현해서 일반화 성능을 높이기 위한 것이다.
- Focal Loss : Class Imbalance 문제가 있는 경우, 맞춘 확률이 높은 Class는 조금의 loss를, 맞춘 확률이 낮은 Class는 Loss를 훨씬 높게 부여한다.
Optimizer
: Loss 를 구하는 것 까지 진행했다면, 실제로 파라미터를 Update 하는 것
각 모델 별로 W(Weight) 는 있지만, learning rate 와 방향(Weight의 변화율) 을 통해서 Update를 진행한다.
Leraning Rate Scheduler
: 학습시에 Learning rate를 동적으로 조절하기 위한 것
- StepLR, CosineAnnealingLR, ReduceLROnPlateau
#StepLR
#특정 Step 마다 LR 감소
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=2, gamma=0.1)
#CosineAnnealingLR
#Cosine 함수 형태처럼 LR을 급격히 변경
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max = 10, eta_min=0)
#ReduceLROnPlateau
#더 이상 성능 향상이 없을 때 LR 감소
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min')
Metric
: 학습에 직접적 영향(X), 단 모델이 학습이 잘 되었는가? 객관적으로 판단하게 되는 좋은 지표이다.
→ 애초에 데이터들의 Label 분포가 불균형, 너무 한 쪽으로 치우쳐져 있는 경우에 ACC 는 높은 것처럼 보이나 실제로는 정확도가 높지 않을 수 있다. 그래서 Balance 하게 데이터를 가꾸는 것도 성능에 중요한 요소이다.
(중요!)
Training Process
: 실제로 PyTorch에서 동작되는 전체적인 Training 과정을 정리한다.
model.train(mode = True)
: 이는 module을 training mode로 Setting 해준다. 이를 왜 해주냐면, training/evaluation 과정에서 Dropout이나 BatchNorm 과정이 다르게 영향을 줄 수 있기 때문이다.
for epoch in range(10): #전체 훈련을 몇번 돌 것인지?
running_loss = 0.0
for i, **data** in enumerate(trainloader, 0):
#하나의 Batch 단위로 나올 수 있도록 for문을 더 잡는다.
inputs, labels = data
#data = [inputs, labels] 이다.
optimizer.**zero_gard**()
#zero_grad()의 의미!
#얘를 먼저 하는 이유는, 매 Step 마다 이전 Step에 있는 Gradient가 남아 있기 때문에 초기화 해준다.
#Grad를 초기화 할 것인가, 아닌가에 따라서 현재 Batch 마다 각각 적용할지 말지 결정하는 역할
outputs = '나의모델'(inputs)
loss = **criterion**(outputs, labels)
loss.**backward**()
# 각각의 parameter들의 Grad가 바뀌어 있을 것이다.
# Grad 값을 변경한 것이 끝이 아니다. Update해주어야 한다.
optimizer.**step**()
# Update 해주는 함수! optimizer.
running_loss += loss.item()
if i % 2000 == 1999:
print('[%d %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
Gradient Accumulation
우리의 메모리는 한정되어 있다. 큰 배치 같은 경우에는 GPU 메모리가 감당하지 못 할 것이다. 그래서 Update하는 작용에서 Step을 건너 뛰어서 Gradient를 중첩시켜 놓고난 다음, Update를 진행시킨다. 이 방법이 Gradient Accumulation 이라고 한다.
NUM_ACC = 2
optimizer.zero_grad()
for epoch in range(1000):
running_loss = 0.0
for i, data in enumerate(train_loader, 0):
inputs, data= data
outputs = '나의모델'(inputs)
loss = criterion(outputs, labels) / NUM_ACC
loss.backward()
if i % NUM_ACC == 0:
optimizer.step()
optimizer.zero_gard()
Inference Process
model.eval()
: 이는 evaluation mode로 세팅하는 함수이다.
Inference는 파라미터를 Update하는 과정이 아니라, 우리가 만든 모델을 테스트하는 과정이다.
with torch.no_grad(): #enter함수가 호출될 것이다.
for data in testloader:
images, labels = data
outputs = '나의모델'(images)
_, predicted = torch.max(outputs.data, 1)
total += label.size(0)
correct += (predicted == labels).sum().item()
print("Acc" % (100 * correct/total))
#with torch.no_gard() 함수 내부
def __enter__(self):
self.prev = torch.is_grad_enabled()
torch.**set_grad_enabled**(False)
#안에 있는 grad enabel을 False로 바꾼다.
Appendix : PyTorch Lightning
: 물론 학습의 입장에서는 이런 Process가 모두 이해하는 것이 중요하다. 하지만 현업에서는 생산성이 굉장히 중요하다. 그래서 PyTorch Lightning은 이런 모든 과정을 간략하게 보여주는 프레임(?) 느낌이다.