Softmax Classification도 Logistic Regression의 연장선이다.
max 값을 얻고 싶은데, soft하게 얻고 깊은게 softmax이다.
Softmax 값들의 총 합은 1이다.
ex) (1, 2, 3)의 max 값을 (0.09, 0.24, 0.66)의 확률 값으로 찾는다!
2. Discrete Probability Distribution
Discrete Probability Distribution은 이산적인 확률 분포를 뜻한다.
우리는 이산 확률 분포를 바탕으로 머신러닝을 수행하게 된다. 상대방이 '가위, 바위, 보'를 낼 확률을 예측한다고 하면, 이전의 패턴을 참고하게 된다. 확률 분포에 근사하기 위해 머신러닝을 이용한다.
import torch
import torch .nn as nn
import torch .nn .functional as F
import torch .optim as optim
torch .manual_seed (1 ) # 재현을 위함
z = torch .FloatTensor ([1 , 2 , 3 ]) # 1, 2, 3
hypothesis = F .softmax (z , dim = 0 ) # 1, 2, 3 중 max를 soft하게 얻자.
print (hypothesis ) # 0.09, 0.24, 0.66
hypothesis .sum () # 1. Softmax들의 총 합은 1
두 개의 확률 분포가 주어졌을 때, 두 개가 얼마나 다른지 나타내는 수치.
Cross Entropy 손실함수를 minimize 하는 것이 중요하다!
5. Cross Entropy Loss : Low-level Implementation
z = torch .rand (3 , 5 , requires_grad = True ) # 3 * 5의 크기로 z를 만든다.
hypothesis = F .softmaz (z , dim = 1 ) # 3 * 5의 3개의 행 중 2번째 행, 즉 2번째 dimension에 대해 softmax를 실행한다.
print (hypothesis ) # 예측값
y = torch .randint (5 , (3 ,)).long () # 정답 값 (실습이라 정답 값을 랜덤하게 생성함)
print (y ) # 0 2 1. 각 행 별로 0번째 2번째 1번째 인덱스가 정답
y_one_hot = torch .zeros_like (hypothesis ) # hypothesis와 같은 3 * 5의 벡터를 만들어 준다.
y_one_hot .scatter_ (1 , y .unsqueeze (1 ), 1 ) # dim = 1에 대해서, y.unsqueeze(1)을 통해 y가 (3,) 이었던 것을 (3,1)로 만들어 [0, 2, 1] => [[0], [2], [1]]로 만든 후 그 자리에 1을 뿌린다.
cost = (y_one_hot * - torch .log (hypothesis )).sum (dim = 1 ).mean () # 3 * 5의 크기인 y_one_hot과 hypothesis를 dim = 1에 대해서 sum 해 준다. dimension 1이 없어지므로 (3, 5)가 (3,)이 되어 mean() 되면 scalar 값이 나온다.
print (cost ) # 1.4689
6. Cross Entropy Loss : High-level Implementation
위는 Cross-entropy를 직접 수작업으로 구현한 것이다. 하지만 PyTorch에서는 편한 함수를 제공하고 있다.
# 소프트맥스 Low / High
torch .log (F .softmax (z , dim = 1 )) # Low-level 소프트맥스
F .log_softmax (z , dim = 1 ) # High-level 소프트맥스이다. torch.log 안 취해도 됨!
# Cross entropy Low / High
(y_one_hot * - torch .log (F .softmax (z , dim = 1 ))).sum (dim = 1 ).mean () # Low-level cross entropy 방법 1
F .nll_loss (F .log_softmax (z , dim = 1 ), y ) # Low-level cross entropy 방법 2
F .cross_entropy (z , y ) # High-level cross entropy
7. Training Example : Low-level Cross Entropy Loss
x_train = [[1 , 2 , 1 , 1 ], # m * 4차원
[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 ] # m개. one-hot encoding을 했을 때의 인덱스의 위치를 나타내는 것임.
x_train = torch .FloatTensor (x_train )
y_train = torch .LongTensor (y_train )
# 모델 초기화
W = torch .zeros ((4 , 3 ), requires_grad = True ) # 학습 파라미터 W. samples = 3, classes = 3, dim = 4
b = torch .zeros (1 , requires_grad = True ) # 학습 파라미터 b
# optimizer
optimizer = optim .SGD ((W , b ), lr = 0.1 )
nb_epochs = 1000
for epoch in range (nb_epochs + 1 ):
# Cost 계산
hypothesis = F .softmax (x_train .matmul (W ) + b , dim = 1 ) # 모델
y_one_hot = torch .zeros_like (hypothesis ) # One-hot
y_one_hot .scatter_ (1 , y_train .unsqueeze (1 ), 1 )
cost = (y_one_hot * - torch .log (F .softmax (hypothesis , dim = 1 ))).sum (dim = 1 ) # loss
# Cost로 Gradient 개선
optimizer .zero_grad ()
cost .backward ()
optimizer .step ()
# 100번마다 로그 출력
if epoch % 100 == 0 :
print ('Epoch {:4d}/{} Cost : {1.6f}' .format (epoch , nb_epochs , cost .item ()))
8. Training Example : High-level Cross Entropy Loss
x_train = [[1 , 2 , 1 , 1 ],
[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 )
W = torch .zeros ((4 , 3 ), requires_grad = True )
b = torch .zeros (1 , requires_grad = True )
optimizer = optim .SGD ((W , b ), lr = 0.1 )
nb_epochs = 1000
for epoch in range (nb_epochs + 1 ):
# 변형된 부분!
z = x_train .matmul (W ) + b
cost = F .cross_entropy (z , y_train ) # cross entropy에는 softmax도 들어있음. one-hot encoding도 생략됨.
optimizer .zero_grad ()
cost .backward ()
optimizer .step ()
if epoch % 100 == 0 :
print ('Epoch {:4d}/{} Cost : {1.6f}' .format (epoch , nb_epochs , cost .item ()))
9. Training Example : High-level Implementation (위 보다 더 쉽게 구현!)
# 모델 정의
class SoftmaxClassifierModel (nn .Module ): #nn.Module 상속받아 모델 정의
def __init_ (self ):
super ().__init__ ()
self .linear = nn .Linear (4 , 3 ) # 4차원의 인풋을 받아 Output이 3!
def forward (self , w ):
return self .linear (x ) #linear를 통과시키는 모델을 만들어라. x는 m * 4이고 return 값은 m * 3이 됨.
model = SoftmaxClassifierModel ()
optimizer = optim .SGD (model .parameters (), lr = 0.1 )
nb_epochs = 1000
for epoch in range (nb_epochs + 1 ):
# 변형된 부분!
prediction = model (x_train ) # prediction size는 m * 3
cost = F .cross_entropy (prediction , y_train )
optimizer .zero_grad ()
cost .backward ()
optimizer .step ()
if epoch % 100 == 0 :
print ('Epoch {:4d}/{} Cost : {1.6f}' .format (epoch , nb_epochs , cost .item ()))