Q1
Q. Multi-Class Classification의 경우 위와 같이 코드를 작성하면 되지만, Binary Classification의 경우는 어떻게 다르게 작성해야 되는가?
https://stackoverflow.com/questions/65916356/image-classification-using-pytorch
실제로 Binary Classification에 torch.argmax(outputs, dim=1)을 적용하면 accuracy가 100을 넘어버린다..
A. Multi-Class Classification의 경우 다음과 같이 코드가 작성된다:
loss_function = nn.CrossEntropyLoss() # nn.Softmax()을 이미 포함하고 있음
# case 1
predicted = torch.argmax(outputs, dim=1)
# case 2
_, predicted = torch.max(outputs, dim=1)
correct = (batch_y == predicted).sum().item()
Binary Classification의 경우 다음과 같이 코드가 작성된다:
loss_function = nn.BCEWithLogitsLoss() # nn.Sigmoid()를 이미 포함하고 있음
predicted = torch.sigmoid(outputs) >= 0.5 # 시그모이드 함수를 적용하고 0.5 기준으로 예측 생성
correct += (batch_y == predicted).sum().item()
torch.argmax는 다중 클래스 분류 문제에서 각 클래스에 대한 확률이 가장 높은 인덱스를 찾는 데 사용된다.
Binary Classification의 경우, 모델이 출력하는 값은 로짓(logit) 값이며, 이를 시그모이드 함수를 통해 확률로 변환한 후 특정 임계값(보통 0.5)을 기준으로 예측을 생성해야 한다.
여기서 torch.argmax(outputs, dim=1) 는 다중 클래스 분류를 위한 것이며, 바이너리 분류에는 적합하지 않다.
Binary Classification에서는 torch.sigmoid(outputs) >= 0.5 을 통해 Class를 예측한다.
Q2
Q. nn.BCEWithLogitsLoss( )는 nn.BCELoss() + nn.Sigmoid()를 결합한 것인데, predicted를 구하는 과정에서 또 torch.sigmoid() 를 가해주면 결국 Sigmoid를 두 번 가해주는 것이 아닌가?
A. 아니다.
손실 계산과 예측 클래스 결정은 별개의 과정이며, 각각에 적합한 처리가 필요하다.
Binary Classification의 outputs 값은 logit 값이라는 것을 기억하자.
그래서, Loss Function이 logit에 대해 내부적으로 Sigmoid를 적용한다 하더라도,
모델의 출력을 해석할 때는 별도로 시그모이드 함수를 적용하여 확률로 변환하고, 해당 확률을 기준으로 최종 클래스를 결정해야 한다.
Loss 계산: Output Activation으로 nn.Sigmoid( ) + Loss Function으로 nn.BCELoss( ) = nn.BCEWithLogitsLoss( )
Predicted Class 결정: outputs에 torch.sigmoid( ) >= 0.5 을 가해 0.5보다 높으면 1, 낮으면 0으로 Class값 결정
Q3
Q. 그럼 Binary Classification이나 Multi-Class Classification 모두 outputs이 logit값으로 나오는데,
Predicted Class를 구하는데 있어서 원래는 각자 Model의 outputs에 output Layer Activation을 가해줘야 실제 output이 되지.
Binary Classification: Loss Function을 nn.BCEWithLogitLoss( )를 사용해서 마지막 Layer에 nn.Sigmoid( )를 넣어주지 않음
Multi-Class Classification: Loss Function을 nn.CrossEntropyLoss( )를 사용해서 마지막 Layer에 nn.Softmax( )를 넣어주지 않음
Binary Classification은 Sigmoid를 적용해서 0.5보다 크면 1, 작으면 0으로 Labeling 했어.
predicted = torch.sigmoid(outputs) >= 0.5 # 시그모이드 함수를 적용하고 0.5 기준으로 예측 생성
Multi-Class Classification도 그럼 마찬가지로 Softmax를 적용해서 최대값이 나오는 인덱스로 LabelIng 해야 되는데, 그냥 바로 logit 값을 기준으로 최댓값의 인덱스로 Labeling 하는 이유가 뭐야?
predicted = torch.argmax(outputs, dim=1)
A. Softmax Function은 입력 벡터의 각 요소에 대해 지수 함수를 적용하고, 그 결과를 모두 더한 값으로 각 요소를 나누어 확률 분포를 생성한다. 이 과정은 출력 벡터의 대소 관계를 변경하지 않는다.
즉, Softmax Function 적용 전후로 가장 큰 값을 가진 요소의 인덱스는 동일하다.
따라서, Class를 예측하기 위해 모델의 출력 Logit에 Softmax를 적용한 후 가장 큰 확률 값을 가진 인덱스를 찾는 것과 직접 logit에서 가장 큰 값을 가진 인덱스를 찾는 것은 동일한 결과를 준다. 이러한 이유로 모델의 예측을 결정할 때 굳이 소프트맥스 함수를 적용할 필요 없이, 바로 `torch.argmax`를 사용할 수 있다.
요약하면, 소프트맥스는 확률 분포를 얻기 위해 사용되지만, 단순히 가장 높은 확률을 가진 클래스를 찾는 데에는 소프트맥스 함수를 적용할 필요가 없다. 예측 클래스를 결정하는 데 있어서는 로짓의 대소 관계만 중요하기 때문이다.
Q4
Q. 'Logit' 값이라는게 정확히 무엇이니?
A. 로짓(logit) 값은 실수 값으로, 특히 신경망 분류 문제에서는 클래스에 대한 예측 확률을 나타내기 전의 원시 출력 값을 의미한다. 신경망의 마지막 층에서 활성화 함수를 거치기 전의 값을 말하며, 이 값들은 실제로 실수 범위 내에서 어떤 값이든 가질 수 있다.
신경망에서는 종종 이러한 로짓을 통해 각 클래스에 대한 모델의 "확신도" 또는 "선호도"를 나타낸다.
로짓이 높을수록 모델이 해당 클래스를 예측할 확률이 높다고 해석할 수 있다.
하지만 로짓 자체는 확률 값이 아니므로, 이를 확률로 변환하기 위해서는 소프트맥스(멀티 클래스 분류) 또는 시그모이드(이진 분류)와 같은 활성화 함수를 적용해야 한다.
요약하자면, "Logit"은 Model의 Output Layer에서 Activation Function를 적용하기 전의 원시 실수 값이다. 이 값들은 활성화 함수를 통해 각 클래스에 대한 예측 확률로 변환된다.