[프로젝트 1 - 이미지 처리] 4. 학습

Jade·2021년 4월 1일
0

부스트캠프 AI Tech

목록 보기
34/54

프로젝트 1 - 학습

  • Loss
  • Optimizer
  • Metric
  • 학습!
  • 추론

[Loss]

파라미터를 업데이트하는 방향을 정하는 척도로, 사용하는 loss가 달라지면 파라미터를 업데이트하는 방법도 달라진다.

loss.backward()는 오차 역전파에 해당하는 메소드로, 이걸 실행하면 모델 파라미터가 업데이트된다. (required_grad=False 설정된 경우 업데이트하지 않음)

loss도 nn.Module을 상속받은 패밀리라서 안을 뜯어보면 forward 메소드를 가지고 있다. backward가 실행되면 모델이 forward를 실행해서 연쇄적으로 레이어의 forward가 실행되는 것과 반대로, loss에서부터 거꾸로 연쇄가 일어나서 모델 파라미터가 업데이트된다.

  • 특별한 경우에 쓰이는 loss
    Focal loss : 클래스별 데이터셋 분포가 불균형할 때 사용한다. 많이 맞춘 클래스는 loss를 조금 부여하고 적게 맞춘 클래스는 loss를 많이 부여해서 적게 맞춘 클래스를 더 많이 맞춰갈 수 있게 하는 방법이다.

    Label smoothing loss : 일반화 성능을 높이기 위해 사용한다. 클래스 레이블을 ont-hot 형태로 쓰지 않고 smoothing된 상태에서 쓰는 loss다.

[Optimizer]

옵티마이저에 추가로 설정할 수 있는 팁들

  • LR scheduler
    LR(학습율)을 동적으로 조절할 수 있다! LR을 조절하면 수렴 속도가 훨씬 빨라질 수 있다.
    • StepLR
      특정 step마다 LR을 감소시킨다.
    • CosineAnnealingLR
      코사인함수처럼 LR을 급격히, 그리고 주기적으로 변경한다. 말이 안 되는 것 같지만 의외로 local minima에서 잘 탈출할 수 있다.
    • ReduceLROnPlateau
      더 이상 성능이 향상되지 않을 때 LR을 감소시킨다.

[Metric]

학습이 잘 되었는지 평가하는 지표다. 보통은 accuracy를 쓰지만 클래스별 데이터 분포가 균일하지 않은 경우에는 accuracy가 객관적 지표가 될 수 없다. 데이터 분포가 불균형할 때는 적은 데이터를 가진 클래스의 예측 성능이 떨어지는데, 데이터가 많은 클래스가 accuracy에 주는 영향이 커서 데이터가 적은 클래스 예측이 틀려도 accuracy에 별 영향을 주지 못한다. 그럴 때는 F1 score를 지표로 사용하는 것이 더 좋다.


[학습!]

  • model.train()
    모델을 학습시키기 전에 model.train()을 써서 모델을 학습 모드로 설정해야 한다.

  • optimizer.zero_grad()
    학습할 때는 배치 단위로 데이터를 보게 된다.(forward, grdient 계산, 역전파, loss) zero_grad()를 설정하지 않으면 이전 배치의 grdient 정보가 누적되어 남아 있게 된다. 이전 배치의 정보가 남아 있으면 새 배치의 loss 계산, 나아가 학습에 영향을 줄 수 있다. 한번에 하나의 배치에 대한 loss만 계산하기 위해서 이전 배치의 정보를 날려버리는 것이다.

  • loss 함수 설정
    nn.Module 안에 있는 다양한 손실 함수 중 하나를 골라서 criterion이라고 이름을 붙인 다음 해당 클래스의 객체를 만들어 loss라고 이름붙여서 많이들 쓰는 것 같다.

criterion = torch.nn.CrossEntropyLoss()
loss = criterion(outputs, labels)
  • loss.backward()optimizer.step()
    backward를 하면 loss에서부터 연결된 레이어를 거꾸로 타고 올라가서 모델의 파라미터가 업데이트된다. (오차 역전파)
    step을 하면 업데이트된 파라미터를 실제 데이터데 적용시키고 다음 배치로 넘어간다.

  • Gradient accumulation
    배치 사이즈를 크게 잡고 데이터를 한번에 많이 보고 싶은데 GPU 한계 등으로 그렇게 할 수 없을 때 쓰는 방법이다. zero_grad()를 따로 써 주지 않으면 이전 배치의 gradient 정보가 남아 있다는 것을 이용하여 배치 사이즈를 크게 한 것 같은 효과를 얻을 수 있다.

    예를 들어 배치 사이즈가 1인데 한번에 5개씩 보는 효과를 내고 싶다면 매번 zero_grad()로 이전 배치의 정보를 날려버리는 대신 배치 5개를 볼 동안 graient를 유지한다. 이 때 gradient를 초기화시키지 않았기 때문에 loss가 누적되어 커지는데, loss가 커지는 것은 의도하지 않았기 때문에 loss를 accumulation number(예시에서는 5)로 나눠 준다. 한번에 5개 데이터를 묶어서 가상의 배치로 만들었기 때문에 optimizer.step()도 5개 배치마다 해야 한다.

num_accum = 5
optimizer.zero_grad() # 시작하기 전에는 한번 날려주자
for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(trainLoader, 0):
        inputs, labels = data
        outputs = net(inputs) # 이건 신경망 모델인듯?
        
        loss = criterion(outputs, labels)/num_accum
        loss.backward()
        
        if i % num_accum == 0:
        optimizer.step()
        optimizer.zero_grad()

[추론]

  • model.eval()
    모델을 evaluation 모드로 설정한다. 학습 중간에 evaluation할 경우 evaluation이 끝나고 나서 다시 model.train()을 써서 학습 모드로 돌려 놔야 한다.

  • with torch.no_grad():
    torch.no_grad()는 evaluation할 때 쓰느데, gradient를 업데이트하지 않겠다고 설정하는 것이다. 이걸 with 구문과 함께 쓰면 그 안에 있는 모든 작업이 grdient를 업데이트하지 않는 상태에서 실행된다.


[피어 세션]

  • fine tuning과 featrue extraction
    fine tuning을 하려면 사전 훈련된 모델의 가중치와 바이어스 정보(pretrained=True)를 다 가져온 상태에서 모델의 CNN도 같이 학습시켜야 한다. feature extraction을 하려면 모델의 CNN 부분을 따로 동결시켜 놔야 한다. 코드 어떻게 해야 하더라?

  • augmentation 할 때 데이터가 불어나는 것은 아닌 듯
    데이터 양을 늘리려면 데이터로더에 똑같은 데이터를 여러 번 집어넣되 적용할 transformation을 다르게 해야 할 것 같다.

  • 데이터의 밸런스를 맞추려고 마스크 쓴 데이터 일부를 안 갖고 와서 모델을 학습시켰더니 검증 정확도가 올랐다고 한다. 이 부분은 각자 고민해 봐야 할 문제인 듯

  • optimizer는 adamp가 엄청 좋다고 한다! 성능도 속도도 굿

profile
반가워용

0개의 댓글