본문 바로가기

Deep Learning Study

Paper 구현하고 싶다. #1-5 Optimization & Loss Modules & Training

728x90

# Intro

센서 기반 IOT 스마트 팩토리 중 설비 쪽에 부서가 배치됐다. 

학부시절에 하던 내용들이랑 많이 겹쳐서, 앞으로의 행보가 기대되지만,

굉 장 히 많은 지식들이 요구돼서 긴장도 된다.

 

기계과라면 가져야 하는 낭만 일반기계기사를 3월 12일 날짜로 홧김에 신청하게 돼서, 

지금 여러모로 할일이 많아져 버렸다.

 

일단 개인적인 목표에서, Tutorial 5까지는 마친 상태지만, 리뷰가 너무 늦춰져서

좀 성실해질 필요가 있다.

 

아무튼 이어서 쓰면,

1. Optimization

Data를 정리하고, Model을 만들었다면, 궁극적인 목표인 Optimization을 할 차례이다.

 

optimization은 Parameter를 Loss Function을 활용하여 최적화시키는 역할을 한다.

 

간략하게 Flow를 설명하면,

1) Batch를 DataLoader에서 불러오기
2) Prediction(preds) 구하기
3) loss기반 label과 preds 차이 계산하기
4) 역전파 (Gradient구하기)
5) Gradient 토대로, Model Update 하기

1,2,4번은 PyTorch에서 간단하게 구현된다.

3,5번은 조금 설명이 필요한데,

 

3) Loss Modules [loss기반 label과 preds 차이 계산하기]

Loss는 optimizer를 위한 도구의 일종이다. 내가 가진 Data와 Test 할 데이터 사이의 격차를 알려준다.

 

다양한 Loss Module이 존재하는데, 일단 첫 단계인만큼 가볍게 수식으로 이해시킨다.

2진법의 경우에 사용되는 Binary Cross Entropy (BCE)를 예시로 보여준다.

그림 1. Loss

좌측에 L은 Loss 기호

y는 label값

x는 Input-Data라는 것

이 3개만 알고 있으면 된다.

 

현재 주어진 예제가 XOR 알고리즘 (0과 1을 구별하는 알고리즘) 이기 때문에,

Binary(이진법)에 관련된 Cross Entropy(Data를 Label로 맞추는 과정)

Binary Cross Entropy라는 '전략'을 사용하게 된 거다.

 

즉 Loss를 설정할 땐, 내가 구하고자 하는 Algorithm에 맞추어 선정하는 것이 옳다.

이걸 하이퍼 파라미터(HyperParameter)라고 한다. 

 

사실 여기서 딥러닝이 PID와 수학적 표현법이 다를 뿐 전체적인 맥락이 비슷하단 걸

알 수 있다. 자유도 높은 튜닝을 가진 툴이라는 생각이 든다.

 

아무튼 저런 식은 사실 PyTorch에서 다 제공한다. (Tensor Flow도 마찬가지)

loss_module = nn.BCEWithLogitsLoss()

이 짧은 코드 한 줄로 전부 해결된다.

 

4) Stochastic Gradient Descent [역전파 (Gradient 구하기)]

이제 loss를 설정했으니까 어떤 방법으로 Optimization을 update 시켜줄지 정하는 과정이 필요하다.

이것 또한 PyTorch에서 이미 다 해놨다.

# Input to the optimizer are the parameters of the model: model.parameters()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

직관적으로 

Optimize를 위한 Optimizer(옵티마이저 해주는 사람)을 선정한다.

model.parameters() : 모델의 파라미터들 (wx + b... )를 최적화시킬 거예요

lr=0.1 : 사용자가 update의 정도를 조절하고자 계수 Learning Rate를 설정한다. 

 

Optimizer는 2가지 유용한 기능을 제공한다.

1. optimizer.step() : 위에서 언급한 것과 같이 Parameter를 Gradient에 따라 Update 하는 간단한 함수이다.

2. optimizer.zero_grad() : 모든 Gradient를 0으로 세팅한다. 

  - 이 기능은 조금 중요한데, loss의 backward를 zero_grad 없이 계산하게 된다면, 점점 값이 불려져 나가게 되므로 

 갚을 덮어씌워 초기화시키기 위해서 zero_grad()를 해주는 것이 좋다.

  (요약 : loss.backward 전에 optimizer.zero_grad() 하기)

 

추후에 Tutorial에서 Active Function과 더불어서 Optimization을 더 설명하므로, 그냥 Flow만 눈에 익히면 된다.

 

2. Training

이렇게 Optimization을 마치고 나면, Training을 할 단계이다.

일전에 열심히 만들어 놓은 Dataset을 가지고 실험해 보자. 

 

Training에서는 위에서 언급한 5가지의 Step이 존재한다는 걸 잊지 말자 

1) Batch를 DataLoader에서 불러오기
2) Prediction(preds) 구하기
3) loss기반 label과 preds 차이 계산하기
4) 역전파 (Gradient 구하기)
5) Gradient 토대로, Model Update 하기

1) Batch기반 DataLoader 불러오기

train_dataset = XORDataset(size=2500)
train_data_loader = data.DataLoader(train_dataset, batch_size=128, shuffle=True)

 

1-1) 여기서 추가적으로 GPU를 사용하는 사람이라면, gpu Device에 Data들을 Push 해주면 된다.

# Push model to device. Has to be only done once
model.to(device)

단순하게 Train 시키는 모듈을 불러오는 건 model.train() 한 개로 끝이 난다.

여기서 training이나 testing에 적용되는 forward step(순전파, 여기서는 학습 방향정도로 이해) 방식을 

model.train() or model.eval()로 변경 가능하다.

 

이제 Training 함수를 만들어 보자.

 

2~5) Training 단계

 

def train_model(model, optimizer, data_loader, loss_module, num_epochs=100):
    # Set model to train mode
    model.train() 
    
    # Training loop -> tqdm은 그냥 그래프 막대기 보여주는 모듈 (간지용)
    for epoch in tqdm(range(num_epochs)):
        for data_inputs, data_labels in data_loader: # -> DataLoader의 Data와 label을 구별한다.
            
            ## Step 1: Move input data to device (only strictly necessary if we use GPU)
            data_inputs = data_inputs.to(device)
            data_labels = data_labels.to(device)
            
            ## Step 2: Run the model on the input data [2) Prediction(preds) 구하기]
            preds = model(data_inputs)
            preds = preds.squeeze(dim=1) # Output is [Batch size, 1], but we want [Batch size] : 1 같은 의미가 불명확한 차원 삭제
            
            ## Step 3: Calculate the loss[3) loss기반 label과 preds 차이 계산하기]
            # 모델에 통과해서 얻은 preds를 label과 비교하여 차이를 얻어냄
            loss = loss_module(preds, data_labels.float())
            
            ## Step 4: Perform backpropagation [4) 역전파 (Gradient구하기)]
            # Before calculating the gradients, we need to ensure that they are all zero. 
            # The gradients would not be overwritten, but actually added to the existing ones.
            optimizer.zero_grad() 
            # Perform backpropagation
            loss.backward()
            
            ## Step 5: Update the parameters [5) Gradient 토대로, Model Update하기]
            optimizer.step()

 

위처럼 만들고 난 뒤에 함수를 실행시켜 보면,

 

train_model(model, optimizer, train_data_loader, loss_module)

 

그림 2. Traininig 하는 모습

이렇게 tqdm의 바(bar) 그래프가 나오면서 training 하는 모습을 볼 수 있다.

 

끊어가기

다음엔 Save & Load를 소개하면서 Tutorial 1이 끝이 나게 된다.

이후로는 Activation, Initializer, Opimizer들이 나오게 되면서, 딥러닝의 기초 중 살짝 수준 있는 내용을

다루게 된다.