import numpy as npsigmoid and softmax
Sigmoid
def sigmoid(x): return 1/(1+np.exp(-x))import matplotlib.pyplot as pltdef plot_function(f, tx=None, ty=None, title=None, min=-2, max=2, figsize=(6,4)):
x = torch.linspace(min,max, 100)
fig,ax = plt.subplots(figsize=figsize)
ax.plot(x,f(x))
if tx is not None: ax.set_xlabel(tx)
if ty is not None: ax.set_ylabel(ty)
if title is not None: ax.set_title(title)import torchplot_function(torch.sigmoid, min=-4, max=4)
Softmax
범주가 3개 이상인 타깃에 대해 손실을 계산하기 위해서는 어떡해야 할까요?
우선은 이진 분류에서 사용할 수 있었던 출력층 함수 시그모이드를 다른 함수로 대체해야 합니다.
가상의 이미지 여섯장에 대한 활성 두 개가 존재한다고 가정하겠습니다.
사실, 두 범주 중 하나를 선택하는 일에는 하나의 활성만 존재해도 괜찮습니다. 특정 threshold(주로 0.5)를 기준으로 보다 낮은 값은 0, 높은 값은 1로 치환할 수 있습니다.
다만 여기서는 설명을 위해 2개의 활성으로 나타냈습니다.
acts = torch.rand((6,2))*2actstensor([[0.1107, 1.0475],
[1.9075, 1.7639],
[0.8810, 0.9155],
[0.0714, 0.4593],
[1.1286, 0.0719],
[1.0509, 1.0387]])
위에서 알아본 torch.sigmoid 함수를 통해 0에서 1사이의 값으로 만들 수 있습니다.
acts.sigmoid()tensor([[0.5276, 0.7403],
[0.8707, 0.8537],
[0.7070, 0.7141],
[0.5178, 0.6129],
[0.7556, 0.5180],
[0.7409, 0.7386]])
다만 두 활성의 합이 1이 아니기 때문에, 함수는 작동하나 의미적으로 무용한 변환이 되었습니다.
실제적으로 시그모이드 함수를 사용하기 위해서는, 두 활성 간의 차이를 시그모이드 변환 하는 것이 합리적입니다.
(acts[:,0]-acts[:,1]).sigmoid()tensor([0.2815, 0.5358, 0.4914, 0.4042, 0.7421, 0.5031])
위 변환의 의미는 0번 째 열의 레이블임을 확신하는 정도와 1번 째 열의 레이블임을 확신하는 정도의 차이라고 말할 수 있습니다.
소프트맥스 함수는 다중 레이블에서 정확히 위와 같은 작업을 수행합니다.
def softmax(x): return exp(x) /exp(x).sum(dim=1, keepdim=True)plot_function(np.exp, min=-4, max=4)
지수함수(exp, np.exp)는 모든 x값에 대응하는 양수 y값을 가집니다.
지수변환된 값 중에서 가장 큰 변환값을 가지는 레이블로 선택합니다.
sm_acts = torch.softmax(acts, dim=1) # 열 기준 torch.softmax레이블이 3개인 경우를 가정하고, 이때 손실은 어떻게 계산하는지 알아보겠습니다.
acts = torch.rand((6,3))*2actstensor([[1.9065, 0.6177, 1.7182],
[0.8220, 1.4084, 0.5280],
[0.6282, 0.6837, 1.5685],
[1.3450, 0.9478, 0.8547],
[1.2426, 0.9204, 1.4648],
[1.1413, 1.3553, 1.3754]])
실제 타겟값은 아래와 같다고 해보겠습니다.
targ = torch.tensor([2,1,2,0,0,1])sm_acts = torch.softmax(acts, dim=1)sm_actstensor([[0.4753, 0.1310, 0.3937],
[0.2823, 0.5074, 0.2104],
[0.2165, 0.2289, 0.5545],
[0.4377, 0.2942, 0.2681],
[0.3363, 0.2437, 0.4200],
[0.2855, 0.3536, 0.3608]])
idx = range(6)sm_acts[idx, targ]tensor([0.3937, 0.5074, 0.5545, 0.4377, 0.3363, 0.3536])
-sm_acts[idx, targ]tensor([-0.3937, -0.5074, -0.5545, -0.4377, -0.3363, -0.3536])
import torch.nn.functional as FF.nll_loss(sm_acts, targ, reduction='none')tensor([-0.3937, -0.5074, -0.5545, -0.4377, -0.3363, -0.3536])
F.nll_loss(sm_acts, targ, reduction='sum')tensor(-2.5833)
만약 예측이 targ과 반대 방향으로 많이 빗나간다면 어떤 값이 나올까요?
targ = torch.tensor([1,2,0,2,1,0])F.nll_loss(sm_acts, targ, reduction='none')tensor([-0.1310, -0.2104, -0.2165, -0.2681, -0.2437, -0.2855])
F.nll_loss(sm_acts, targ, reduction='sum')tensor(-1.3551)
예측이 타겟과 잘 맞는 경우 -2.58 정도였으나, 빗겨나간 경우 -1.35 정도로 손실값이 커졌습니다.