πŸ“šSTUDY/πŸ”₯Pytorch ML&DL

06. softmax classification

ν•΄λŠ”μ„  2020. 2. 28. 19:08

λ³Έ 글은 'λͺ¨λ‘λ₯Ό μœ„ν•œ λ”₯λŸ¬λ‹ μ‹œμ¦Œ 2'와 'pytorch둜 μ‹œμž‘ν•˜λŠ” λ”₯ λŸ¬λ‹ μž…λ¬Έ'을 보며 κ³΅λΆ€ν•œ λ‚΄μš©μ„ μ •λ¦¬ν•œ κΈ€μž…λ‹ˆλ‹€.

ν•„μžμ˜ 의견이 μ„žμ—¬ λ“€μ–΄κ°€ λΆ€μ •ν™•ν•œ λ‚΄μš©μ΄ μ‘΄μž¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


3개 μ΄μƒμ˜ μ„ νƒμ§€μ—μ„œ 1개λ₯Ό 선택!  (softν•˜κ²Œ max값을 λ½‘μ•„μ£ΌλŠ”)

⇒ 닀쀑 클래슀 λΆ„λ₯˜ (Multi-class classification)

μ„Έ 개 μ΄μƒμ˜ λ‹΅ 쀑 ν•˜λ‚˜λ₯Ό κ³ λ₯΄λŠ” 문제.

μ‹œκ·Έλͺ¨μ΄λ“œ ν•¨μˆ˜λŠ” λ‘œμ§€μŠ€ν‹± ν•¨μˆ˜μ˜ ν•œ μΌ€μ΄μŠ€λΌ λ³Ό 수 있고, 인풋이 ν•˜λ‚˜μΌ λ•Œ μ‚¬μš©λ˜λŠ” μ‹œκ·Έλͺ¨μ΄λ“œ ν•¨μˆ˜λ₯Ό 인풋이 μ—¬λŸ¬κ°œμΌ λ•Œλ„ μ‚¬μš©ν•  수 μžˆλ„λ‘ μΌλ°˜ν™” ν•œ 것이 μ†Œν”„νŠΈλ§₯슀 ν•¨μˆ˜μž…λ‹ˆλ‹€.

 

0. 원-ν•« 인코딩(one-Hot Encoding)

  1. μ„ νƒμ§€μ˜ 개수만큼 차원을 가진닀.
  2. 선택지에 ν•΄λ‹Ήν•˜λŠ” μΈλ±μŠ€λŠ” 1, λ‚˜λ¨Έμ§€λŠ” 0으둜 ν‘œν˜„ν•œλ‹€.

ex)

강아지 = [1, 0, 0]
고양이 = [0, 1, 0]
냉μž₯κ³  = [0, 0, 1]

 

  • μ •μˆ˜ 인코딩(1, 2, 3)과의 차이점

    ⇒ μ •μˆ˜ 인코딩은 각 ν΄λž˜μŠ€κ°€ μˆœμ„œ 정보λ₯Ό ν•„μš”λ‘œ ν•  λ•Œ μœ μš©ν•˜λ‹€.

    ⇒ 원 ν•« 인코딩은 일반적인 λΆ„λ₯˜λ¬Έμ œ, 즉 μˆœμ„œκ°€ μ˜λ―Έμ—†κ³  λ¬΄μž‘μœ„μ„±μ΄ μžˆμ„ λ•Œ μœ μš©ν•˜λ‹€.

    (λͺ¨λ“  클래슀의 관계λ₯Ό κ· λ“±ν•˜κ²Œ λΆ„λ°°ν•˜κΈ° λ•Œλ¬Έ!)

1. softmax function

각 μ„ νƒμ§€λ§ˆλ‹€ μ†Œμˆ˜λ₯Ό ν• λ‹Ήν•΄μ„œ κ·Έ 합이 1이 되게 λ§Œλ“œλŠ” ν•¨μˆ˜.

 

for i = 1, 2, ..., k

 

piλŠ” i번 ν΄λž˜μŠ€κ°€ 정닡일 ν™•λ₯ μ„ λœ»ν•œλ‹€. pi(i=1~k)λ₯Ό λ‹€ λ”ν•˜λ©΄, κ·Έ 합은 1이 λœλ‹€. 즉, μ†Œν”„νŠΈ λ§₯슀 ν•¨μˆ˜λŠ” μ–΄λ ΅κ²Œ 생각할 ν•„μš” 없이 주어진 값듀에 λŒ€ν•΄ 합이 1이 λ˜λ„λ‘ κ·Έ 값듀을 λΉ„μœ¨μ— 맞좰 μ†Œμˆ˜λ‘œ μ •κ·œν™” μ‹œμΌœμ£ΌλŠ” ν•¨μˆ˜λΌκ³  μƒκ°ν•˜λ©΄ λœλ‹€.

 

Softmax( ( 1xf ) * ( fxC ) + ( Cx1 ) ) = C x 1

μ°¨λ‘€λ‘œ μž…λ ₯κ°’, κ°€μ€‘μΉ˜, 편ν–₯, μ˜ˆμΈ‘κ°’μ΄λ‹€. (fλŠ” νŠΉμ„±μ˜ 수, CλŠ” 클래슀의 개수)

λ°μ΄ν„°μ˜ κ°œμˆ˜μ— λ”°λΌμ„œ μž…λ ₯κ°’μ˜ 1이 바뀐닀.

 

2. cost function

logistic regresstionμ—μ„œλŠ” binary cross-entropyλ₯Ό μ‚¬μš©ν–ˆλ‹€. μ–˜λŠ” 2개 쀑 ν•˜λ‚˜λ₯Ό κ²°κ³Όκ°’μœΌλ‘œ λ‚΄ λ†“μ•˜μ—ˆλŠ”λ°, 이 BCE 보닀 더 근원적인? ν•¨μˆ˜κ°€ μžˆλ‹€. λ°”λ‘œ CE! cross entropy!

CEλŠ” 3개 μ΄μƒμ˜ κ°’ 쀑 ν•˜λ‚˜λ₯Ό λ‚΄μ–΄ λ†“λŠ”λ‹€.

μ—¬κΈ°μ„œ μ΅œλŒ€κ°’μΈ Kλ₯Ό 2둜 μ§€μ •ν•˜κ²Œ λœλ‹€λ©΄, BCE의 식이 λ‚˜μ˜€κ²Œ λœλ‹€!

 

3. Code κ΅¬ν˜„

softmax와 cross-entropy의 κ΅¬ν˜„ λ°©λ²•μ—λŠ” 3가지가 μžˆλ‹€.

 

#1
F.softmax() + torch.log()  # = F.log_softmax() 

#2
F.log_softmax() + F.nll_loss() # = F.cross_entropy()

#3
F.cross_entropy()

κ²°λ‘ μ μœΌλ‘œλŠ” νŽΈν•˜κ²Œ 3번만 μ‚¬μš©ν•˜λ©΄ λœλ‹€! νŠΉμ΄ν•˜κ²Œ κ°€μ„€ ν•¨μˆ˜μ™€ 손싀 ν•¨μˆ˜λ₯Ό ν•œλ²ˆμ— μ“Έ 수 μžˆλ‹€! 이럴 경우, μ‹€μ œ codeμ—μ„œλŠ” ν–‰λ ¬μ˜ 곱만 μ‹œμΌœμ£Όκ³ , μ†Œμˆ˜ 합이 1이 λ˜λ„λ‘ μ •κ·œν™” μ‹œμΌœμ£ΌλŠ” 과정은 μ†μ‹€ν•¨μˆ˜λ₯Ό μ“Έ λ•Œ 같이 ν•  수 μžˆλŠ” μ € F.cross_entropy()에 맞겨주면 λœλ‹€.

 

4. Full Code

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

x_train = [[1, 2, 1, 1], #4개의 νŠΉμ„±μ„ 가지고 μžˆλŠ” 8개의 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€
           [2, 1, 3, 2],
           [3, 1, 3, 4],
           [4, 1, 5, 5],
           [1, 7, 5, 5],
           [1, 2, 5, 6],
           [1, 6, 6, 6],
           [1, 7, 7, 7]]
y_train = [2, 2, 2, 1, 1, 1, 0, 0]

x_train = torch.FloatTensor(x_train) #ν…μ„œλ‘œ λ³€ν™˜
y_train = torch.LongTensor(y_train)

y_one_hot = torch.zeros(8, 3) 
#μ•žμ˜ 8은 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€ 개수, λ’€μ˜ 3은 닡이 2μΌλ•Œ [0 0 1] μ΄λŸ°μ‹μœΌλ‘œ λ‚˜νƒ€λ‚Ό 것(μ§€κΈˆμ€ 자리만 λ§Œλ“¦)

y_one_hot.scatter_(1, y_train.unsqueeze(1), 1) #μ‹€μ œ κ°’ yλ₯Ό 원-ν•« λ²‘ν„°λ‘œ λ°”κΏˆ
print(y_one_hot.shape)


# λͺ¨λΈ μ΄ˆκΈ°ν™”
W = torch.zeros((4, 3), requires_grad=True) #νŠΉμ„±μ€ 4개, κ²°κ³Ό κ°€μ§€μˆ˜λŠ” 3개
b = torch.zeros(1, requires_grad=True) #1둜 ν•˜λ©΄ 3κ°œμ— 같은 값이 더해짐, 3으둜 해도 μƒκ΄€μ—†μŒ!

# optimizer μ„€μ •
optimizer = optim.SGD([W, b], lr=0.1)

nb_epochs = 1000
for epoch in range(nb_epochs + 1):

    # κ°€μ„€
    hypothesis = F.softmax(x_train.matmul(W) + b, dim=1) 

    # λΉ„μš© ν•¨μˆ˜ - 직접 계산 버전
    cost = (y_one_hot * -torch.log(hypothesis)).sum(dim=1).mean()

    # cost둜 H(x) κ°œμ„ 
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 100λ²ˆλ§ˆλ‹€ 둜그 좜λ ₯
    if epoch % 100 == 0:
        print('Epoch {:4d}/{} Cost: {:.6f}'.format(
            epoch, nb_epochs, cost.item()
        ))

 

4-1. Full Code with nn,Module

class SoftmaxClassifierModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(4, 3) # 인풋은 4, Output이 3!

    def forward(self, x):
        return self.linear(x)

model = SoftmaxClassifierModel() #λͺ¨λΈ 생성

# optimizer μ„€μ •
optimizer = optim.SGD(model.parameters(), lr=0.1)

nb_epochs = 1000
for epoch in range(nb_epochs + 1):

    # H(x) 계산 - ν–‰λ ¬ 곱만 ν•΄μ€€λ‹€
    prediction = model(x_train)

    # cost 계산 - 이 ν•¨μˆ˜μ„œ softmaxμžλ™μœΌλ‘œ 적용됨
    cost = F.cross_entropy(prediction, y_train)

    # cost둜 H(x) κ°œμ„ 
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 20λ²ˆλ§ˆλ‹€ 둜그 좜λ ₯
    if epoch % 100 == 0:
        print('Epoch {:4d}/{} Cost: {:.6f}'.format(
            epoch, nb_epochs, cost.item()
        ))

 


<Reference>

https://deeplearningzerotoall.github.io/season2/lec_pytorch.html

https://wikidocs.net/59427

https://wikidocs.net/60572

https://wikidocs.net/60575