Loss function_BASE

TEMP·2021년 9월 18일
0

Torch_LOSS

목록 보기
2/5

다른 post에서 자세하게 말했지만 다시 말하면 torch.nn.functional은 함수고 torch.nn은 클래스이다. 따라서 trainer에 들어가는 모양이 다르다.

내가 만들어 놓은 trainer를 예로 들자면 class로 사용하는 경우 loss=class()라고 설정한 뒤 trainer 의 params부분에 넣어주면 되고, function으로 사용 할 경우
trainer에서 loss를 input으로 받지 않고 직접 안에서 설정해주어야 한다.

또한 주의할점이 있는데 내가 만들어 놓은 trainer에서는 loss과 metric을 1 iter 즉, 한번의 minibatch학습 후 이를 loss_batch 이러한 iterator를 반복하는 1 epoch후를 train_loss라고 해놨다.

그리고 마지막 train_loss를 나눠주게끔 해놨는데 이는 두가지 경우가 있다.
1. 설정한 loss function이 batch의 mean을 구하는 경우
2. 설정한 loss function이 batch의 sum을 구하는 경우

CROSSENTROPYLOSS

https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html#torch.nn.CrossEntropyLoss

torch.nn.CrossEntropyLoss(weight=None, size_average=None, 
ignore_index=-100, reduce=None, reduction='mean')

공식문서에도 나와있지만 target은 0부터 시작해야 한다.
아마 F.one_hot(targets, num_classes=10)때문일거 같다.

이제 이를 직접 custom 해보자.
CEECEE == (target)log(softmax(output))-(target)\mathrm{log}(softmax(output))이다.
softamxsoftamx == eoutputeoutput\dfrac{e^{output}}{\displaystyle\sum{}e^{output}}
이때 target은 onehot이므로 target이 1 즉 정답에 대한 oputput의 확률인 sorfmax값만 계산하면 된다.

참고로 여기서 .item()찍어주면 큰일난다.(사실 안해봤는데 autograd를 이해했다면 바로 알거다.)
.item()을 찍어주면 tensor type이 풀리면서 grad도 같이 사라짐.

Custom Code

import torch.nn.functional as F
    
def myCEE(outputs,targets):
    exp=torch.exp(outputs)
    A=torch.log(torch.sum(exp,dim=1))
    
    hadamard=F.one_hot(targets, num_classes=10).float()*outputs
    B=torch.sum(hadamard, dim=1)
    return torch.sum(A-B)

이렇게 해서 train해보니 loss가 4 epoch정도 부터 nan을 뽑아낸다.....
찾아보니 not a number인데 뭐 여러가지 이유가 있다.
일단 역전파는 잘 되니까 이것만 해결하면 될거 같다.

loss_func = nn.CrossEntropyLoss(reduction='sum')  
loss_func(outputs,targets)
-------------------------------------------------------
tensor(147.5397, grad_fn=<NllLossBackward>)


myCEE(outputs,targets)
-------------------------------------------------------
tensor(147.5397, grad_fn=<SumBackward0>)

와 이게 값은 같다. 즉 잘만들었다는 건데 grad_fn이 다르네 자세히 살펴보면 Nll저거 custom loss function 찾아보면서 엄청 많이 봤던거다. custom할때 다 저걸 넣던데 뭐야 왜넣어 굳이 하고 넘겼는데 이래서 인가 보다.

저게 뭔지 찾아보자.
위에서 언급한 것과 마찬가지로 torch.nn.functional.nll_loss는 함수, orch.nn.NLLLoss은 클래스이다.
찾아 보니 이것도 loss function인데 nn.CrossEntropyLoss에서 softmax가 없는거다.

즉, 저건 그냥 하나의 loss function이고 아마 nn.CrossEntropyLoss가 nn.NLLLoss을 상속받아서 그런거 같다.

nan problem에 대한 글은 google에 생각 보다 많다.
직접 찾아보지는 않았지만, 0때문일 거라 추측했고, 단순 실험을 위해 너무 적은 parameter를 가진 model을 만들어서 그런거라 생각했다.

따라서 model에서 convolution을 더 쌓아보니 학습은 당연히 더 잘되고 심지어 39 epoch까지 nan이 안나왔다.

그래도 여전히 의문점이 남아있는데 그건 내가 만든거 하고 torch내장하고 어느부분이 다른가이다.
분명 내장 loss는 나처럼 저렇게 간단하게 만들지는 않았을 거고 장치가 마련되어 있을텐데 잘 모르겠다.

stackoverflow에 올려두었다.
https://stackoverflow.com/questions/69235383/pytorch-custom-loss-function-nn-crossentropyloss

추가적으로 nan에 대한것은 아마 나중에 엄청 많이 마추칠거 같으므로 정확히 어느부분에서 nan이 나오는지 추적하는 방법을 찾아서 정리하도록 하자.

0개의 댓글

관련 채용 정보