[CH05] 03. 소프트맥스 회귀의 비용함수 구현하기

SoYeong Gwon·2022년 7월 1일
0

DeepLearning Introduction

목록 보기
10/12
post-thumbnail

본 게시글은 다음 링크(https://wikidocs.net/book/2788)의 wiki docs를 참고하여 작성되었습니다.

  • 이번 챕터에서 소프트맥스 회귀의 비용함수를 구현해보자.
  • 모든 실습은 아래 초기화 과정이 진행되었다고 가정함.
import torch 
import torch.nn.functional as F

torch.manual_seed(1)

01. 파이토치로 소프트맥스의 비용 함수 구현하기(low-level)

  • 다음 3개의 원소를 가진 벡터 텐서를 정의하고, 이 텐서를 통해 소프트맥스 함수를 이해해보자.
# 텐서 선언 
z = torch.FloatTensor([1,2,3])

# softmax 함수 실행 
hypothesis = F.softmax(z, dim = 0)

print(hypothesis) # 3개의 원소 값이 0과 1사이의 값을 가지는 벡터로 변환됨.
print(hypothesis.sum()) # 이 원소들의 합은 1
<torch._C.Generator at 0x2594337a230>
tensor([0.0900, 0.2447, 0.6652])
tensor(1.)

01. 파이토치로 소프트맥스의 비용 함수 구현하기(low-level)

  • 다음 3개의 원소를 가진 벡터 텐서를 정의하고, 이 텐서를 통해 소프트맥스 함수를 이해해보자.
# 텐서 선언 
z = torch.FloatTensor([1,2,3])

# softmax 함수 실행 
hypothesis = F.softmax(z, dim = 0)

print(hypothesis) # 3개의 원소 값이 0과 1사이의 값을 가지는 벡터로 변환됨.
print(hypothesis.sum()) # 이 원소들의 합은 1
tensor([0.0900, 0.2447, 0.6652])
tensor(1.)
# 임의의 3 x 5 행렬 크기를 가진 텐서를 만들었음.
z = torch.rand(3, 5, requires_grad=True)

hypothesis = F.softmax(z, dim=1) # 두번째 차원에 대해서 softmax 함수 적용 

print(hypothesis) 
tensor([[0.2645, 0.1639, 0.1855, 0.2585, 0.1277],
        [0.2430, 0.1624, 0.2322, 0.1930, 0.1694],
        [0.2226, 0.1986, 0.2326, 0.1594, 0.1868]], grad_fn=<SoftmaxBackward0>)
# 각 샘플에 대한 임의의 테이블 생성
y = torch.randint(5,(3,)).long()
print(y)
tensor([2, 1, 0])
# 원-핫 인코딩 생성 
# 모든 원소가 0의 값을 가진 3 * 5 텐서 생성 
y_one_hot = torch.zeros_like(hypothesis)
y_one_hot.scatter_(1, y.unsqueeze(1),1)
tensor([[0., 0., 1., 0., 0.],
        [0., 1., 0., 0., 0.],
        [1., 0., 0., 0., 0.]])
  • 원-핫 인코딩 동작 원리
    • y_one_hot = torch.zero_like(hypothesis)
      • 모든 원소가 0의 값을 가진 3 x 5 텐서를 만들어 y_one_hot에 저장
    • y_one_hot.scatter_(1, y.unsqueeze(1),1)
      • y.unsqueeze(1) 를 하면 (3,)의 크기를 가졌던 y 텐서는 (3 x 1) 텐서가 됨.
      • scatter의 첫번째 인자로 dim=1에 대해서 수행하라고 알려주고, 세번째 인자에 숫자 1을 넣어 y_unsquezze(1)이 알려주는 위치에 1을 넣어주어 one-hot encoding
    • 연산 뒤에 _를 붙이는 In-Place Operation을 통해 y_one_hot에 값을 넣어줌.
print(y_one_hot)
tensor([[0., 0., 1., 0., 0.],
        [0., 1., 0., 0., 0.],
        [1., 0., 0., 0., 0.]])
  • 이제 비용함수 구현
  • 비용함수 식은 다음과 같음.
    cost(W)=1ni=1nj=1kyjilog(pji)cost(W) = -\frac{1}{n} \sum_{i=1}^n \sum_{j=1}^k y_j^i log(p_j^i)
  • 마이너스 부호를 뒤로 빼면 다음 식과 동일함.
    cost(W)=1ni=1nj=1kyji(log(pji))cost(W) = \frac{1}{n} \sum_{i=1}^n \sum_{j=1}^k y_j^i * (-log(p_j^i))
  • 이 식에서 j=1k\sum_{j=1}^{k}sum(dim=1)으로 구현하고, $ \frac{1}{n} \sum_{i=1}^{n}$ mean()으로 구현함.
cost = (y_one_hot * -torch.log(hypothesis)).sum(dim=1).mean()
print(cost)
tensor(1.6682, grad_fn=<MeanBackward0>)

2.파이토치로 소프트맥스의 비용함수 구현하기(High-Level)

  • 하이-레벨로 구현하는 방법에 대해서 알아보자.

01. F.softmax() + torch.log() = F.log_softmax()

  • 앞서 low-level에서 함수의 결과에 로그를 씌울때 다음과 같이 사용하였음. : torch.log(F.softmax())

  • 파이토치에서는 두 개의 함수를 결합한 F.log_softmax()라는 도구를 제공함.

F.log_softmax(z, dim=1)
tensor([[-1.3301, -1.8084, -1.6846, -1.3530, -2.0584],
        [-1.4147, -1.8174, -1.4602, -1.6450, -1.7758],
        [-1.5025, -1.6165, -1.4586, -1.8360, -1.6776]],
       grad_fn=<LogSoftmaxBackward0>)
torch.log(F.softmax(z, dim=1))
tensor([[-1.3301, -1.8084, -1.6846, -1.3530, -2.0584],
        [-1.4147, -1.8174, -1.4602, -1.6450, -1.7758],
        [-1.5025, -1.6165, -1.4586, -1.8360, -1.6776]], grad_fn=<LogBackward0>)

02. F.log_softmax() + F.nll_loss() = F.cross_entropy()

  • 로우-레벨로 구현한 비용함수는 다음과 같음.
# Low Level 
# 첫번째 수식
(y_one_hot * -torch.log(F.softmax(z,dim=1))).sum(dim=1).mean()
tensor(1.6682, grad_fn=<MeanBackward0>)
# 두번째 수식
(y_one_hot * -F.log_softmax(z,dim=1)).sum(dim=1).mean()
tensor(1.6682, grad_fn=<MeanBackward0>)
# 세번째 수식
F.nll_loss(F.log_softmax(z,dim=1),y)
tensor(1.6682, grad_fn=<NllLossBackward0>)
  • 여기서 nll이란 Negative Log Likelihood의 약자
  • nll_lossF.log_softmax()를 수행한 후에 남은 수식들을 수행함.
  • 이를 더 간단히 하면 F.cross_entropy()F.log_softmax()F.null_loss()를 포함하고 있음.
# 네번째 수식
F.cross_entropy(z,y)
tensor(1.6682, grad_fn=<NllLossBackward0>)
  • F.cross_entropy는 비용 함수에 소프트맥스 함수까지 포함하고 있음.

0개의 댓글