Skip to content

Latest commit

 

History

History
182 lines (133 loc) · 5.61 KB

9-1. ReLU.md

File metadata and controls

182 lines (133 loc) · 5.61 KB

Part 1. 활성화 함수

1. 활성화 함수와 Sigmoid 함수

(1) 활성화 함수

  • 활성화 함수 : 입력 신호의 총합을 출력 신호로 변환하는 함수이다.
  • 활성화 함수로 Sigmoid, ReLU 등이 있다.

(2) Sigmoid 함수

  • x = torch.nn.sigmoid(x)
  • Sigmoid 함수 : S자 모양의 함수로, 넓은 범위의 숫자를 0~1 사이의 숫자로 출력값을 바꿔준다.
  • Sigmoid의 특징 : Sigmoid 함수는 S자 모양인데, 0과 1 사이는 기울기가 완만하지만, 0이나 1에 가까워 질 수록 기울기가 급격하게 0에 수렴하게 생겼다.
  • 학습 과정 : Input -> Layer -> Sigmoid -> Output -> Cost 계산(GT와 Output의 차이) -> Backpropagation


2. Sigmoid 함수의 문제점

(1) Vanishing Gradient

  • Sigmoid의 문제점은 Backpropagation 과정에서 발생한다.
  • Sigmoid의 0이나 1에 가까운 부분의 기울기는 0.xx처럼 굉장히 낮다.
  • Backpropagation을 할 때 기울기를 곱하며 계산하게 되는데, 이때 0.xx가 곱해지면 기울기가 점차 소멸되게 된다.
  • 여러 레이어들을 쌓을 때 활성화함수로 Sigmoid를 이용하면, Backpropagation 도중 마지막단 레이어들은 기울기(Gradient)가 잘 전달 되겠지만, 앞단의 레이어는 기울기를 거의 전파받지 못한다.

(2) 해결법

  • ReLU!


3. ReLU 함수

(1) ReLU

  • x = torch.nn.relu(x)
  • f(x) = max(0, x)
  • ReLU 함수는 함수에 x가 들어왔을 때, x가 0보다 크면 원래 x값 그대로 출력하고, 0보다 작으면 0으로 출력한다.
  • 음수가 들어오면 기울기(Gradient)가 0이 되고, 양수가 들어오면 기울기가 1이 된다. (원래 값 그대로 이기 때문에 기울기 1)

(2) ReLU와 Vanishing Gradient

  • 기울기가 0 또는 1이기 때문에 Vanishing Gradient 문제가 없다!

(3) ReLU의 문제점

  • 음수가 들어오면 기울기가 아예 사라진다.
  • but 대부분 잘 동작함!


4. 기타 활성화 함수

  • torch.nn.tanh(x)
  • torch.nn.leaky_relu(x, 0.01) : relu에서 0값 내보내는 걸 약간 변형



Part 2. Optimizer

1. PyTorch의 다양한 Optimizer들

(1) PyTorch의 Optimizer

  • torch.optim에는 다양한 optimization algorithms들이 있다.
  • Optimizer는 그라 디센드를 수행하는 애들임!
  • 시간이 있다면 같은 모델에 다양한 Optimizer를 적용해서 결과를 비교해보는 것도 좋겠다.

(2) 다양한 Optimizer들

  • torch.optim.SGD
  • torch.optim.Adadelta
  • torch.optim.Adagrad
  • torch.optim.Adam
  • torch.optim.SparseAdam
  • torch.optim.Adamax
  • torch.optim.ASGD
  • torch.optim.LBFGS
  • torch.optim.RMSprop
  • torch.optim.Rprop

(3) 각 Optimizer들의 전략

  • SGD : 조금만 보고 빨리 판단해서 깎아 내려가자
  • Momentum : 아까 내려 오던 관성 방향대로 깎아 내려가자
  • Adam : 방향도 스텝사이즈도 적절하게 깎아 내려가자



Part 3. MNIST 분류

1. MNIST softmax로 분류 - 기존에 배운것에서 Optimizer만 Adam으로 바꿔보기!

# 파라미터들
learning_rate = 0.001
training_epochs = 15
batch_size = 100

# Fully-connected 레이어 하나!
linear = torch.nn.Linear(784, 10, bias = True).to(device) # Linear 모델로, 784(28 * 28)개의 인풋을 받아 최종적으로 10(0 ~ 9)개의 클래스로 분류함

torch.nn.init.normal_(linear.weight) # layer의 weight 초기화!

cripterion = torch.nn.CrossEntropyLoss().to(device) # Loss

# 기존에 배운것에서 이 부분만 바뀜!!
optimizer = torch.optim.Adam(linear.parameters(), lr = learning_rate) # Optimizer를 Adam으로 설정

# 학습
total_batch = len(data_loader)
for epoch in range(training_epochs):
  avg_cost = 0
  total_batch = len(data_loader)
  
  for X, Y in data_loader:
    X = X.view(-1, 28*28).to(device)
    
    hypothesis = linear(X)
    cost = criterion(hypothesis, Y)
    
    optimizer.zero_grad()
    cost.backward()
    avg_cost += cost / total_batch
    
    print("Epoch: ", "%04d" % (epoch+1), "cost =", "{:.9f}".format(avg_cost)) # Accuracy : 89%


2. MNIST MLP로 분류 - 레이어 깊게 쌓아보고, ReLU도 이용해보기!

# parameters
learning_rate = 0.001
training_epochs = 15
batch_size = 100

# 3개의 레이어!
linear1 = torch.nn.Linear(784, 256, bias = True).to(device) # 784(28 * 28)를 입력으로 받아 256 출력!
linear2 = torch.nn.Linear(256, 256, bias = True).to(device) # 256 입력 받아 256 출력!
linear3 = torch.nn.Linear(256, 10, bias = True).to(device) # 256 입력 받아 10(0~9) 출력!
relu = torch.nn.ReLU()

# weight 초기화
torch.nn.init.normal_(linear1.weight)
torch.nn.init.normal_(linear2.weight)
torch.nn.init.normal_(linear3.weight)

# 모델
model = torch.nn.Sequential(linear1, relu, linear2, relu, linear3).to(device) # 마지막 레이어 이후 활성화 함수를 넣지 않은 이유는, 밑에서 CrossEntropyLoss()를 이용해 Loss를 계산할 때 그 함수에서 자동으로 softmax 활성화함수 처리를 해주기 때문

criterion = torch.nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

# 학습
total_batch = len(data_loader)
for epoch in range(training_epochs):
  avg_cost = 0
  total_batch = len(data_loader)
  
  for X, Y in data_loader:
    X = X.view(-1, 28*28).to(device)
    
    hypothesis = model(X)
    cost = criterion(hypothesis, Y)
    
    optimizer.zero_grad()
    cost.backward()
    avg_cost += cost / total_batch
    
    print("Epoch: ", "%04d" % (epoch+1), "cost =", "{:.9f}".format(avg_cost)) # Accuracy : 94%