by museonghwang

Linear Regression 학습을 위한 pytorch 기본

|

1.선형 회귀(Linear Regression)

1.1 가설(Hypothesis) 수립

선형 회귀란 학습 데이터와 가장 잘 맞는 하나의 직선을 찾는 방법으로, 이때 선형 회귀의 가설(직선의 방정식)은 아래와 같은 형식을 가집니다.

[y=Wx+b]

머신 러닝에서 식을 세울때 이 식을 가설(Hypothesis)라고 합니다. 보통 머신 러닝에서 가설은 임의로 추측해서 세워보는 식일수도 있고, 경험적으로 알고 있는 식일 수도 있고, 또는 맞는 가설이 아니라고 판단되면 계속 수정해나가게 되는 식이기도 합니다. 가설의 H를 따서 y 대신 다음과 같이 식을 표현하기도 합니다.

[H(x)=Wx+b]

이때 $x$와 곱해지는 $W$를 가중치(Weight)라고 하며, $b$를 편향(bias)이라고 합니다.

1.2 비용 함수(Cost function)에 대한 이해

비용 함수(cost function) = 손실 함수(loss function) = 오차 함수(error function) = 목적 함수(objective function)

손실 함수에 대해 이해하기 위해서 다음과 같은 예가 있다고 가정하겠습니다. 어떤 4개의 훈련 데이터가 있고, 이를 2차원 그래프에 4개의 점으로 표현한 상태라고 하겠습니다.

image

지금 목표는 4개의 점을 가장 잘 표현하는 직선을 그리는 일입니다. 임의로 3개의 직선을 그립니다.

image

위의 그림은 서로 다른 $W$와 $b$의 값에 따라서 천차만별로 그려진 3개의 직선의 모습을 보여줍니다. 이 3개의 직선 중에서 4개의 점을 가장 잘 반영한 직선은 4개의 점에 가깝게 지나가는 느낌의 검은색 직선 같습니다. 하지만 수학에서 어떤 직선이 가장 적절한 직선인지를 수학적인 근거를 대서 표현할 수 있어야 합니다. 그래서 오차(error)라는 개념을 도입합니다.

image

위 그림은 임의로 그려진 주황색 선에 대해서 각 실제값(4개의 점)과 직선의 예측값(동일한 $x$값에서의 직선의 $y$값)에 대한 값의 차이를 빨간색 화살표 ↕로 표현한 것입니다. 각 실제값과 각 예측값과의 차이고, 이를 각 실제값에서의 오차라고 말할 수 있습니다. 이 직선의 예측값들과 실제값들과의 총 오차(total error)는 직관적으로 생각하기에 모든 오차를 다 더하면 될 것 같습니다. 위 주황색 직선의 식은 $y=13x+1$이며, 각 오차는 다음과 같습니다.

$hours(x)$ 2 3 4 5
실제값 25 50 42 61
예측값 27 40 53 66
오차 -2 10 -11 -5

각 오차를 계산해봤습니다. 그런데 수식적으로 단순히 ‘오차 = 실제값 - 예측값’으로 정의하면 오차값이 음수가 나오는 경우가 생깁니다. 예를 들어 위의 표에서만 봐도 오차가 음수인 경우가 3번이나 됩니다. 이 경우, 오차를 모두 더하면 덧셈 과정에서 오차값이 +가 되었다가 -되었다가 하므로 제대로 된 오차의 크기를 측정할 수 없습니다. 그래서 오차를 그냥 전부 더하는 것이 아니라, 각 오차들을 제곱해준 뒤에 전부 더하겠습니다.

이를 수식으로 표현하면 아래와 같습니다. 단, 여기서 n은 갖고 있는 데이터의 개수를 의미합니다.

[\sum_{i=1}^{n}[y^{(i)} - H(x^{(i)})]^{2} = (-2)^{2}+(10)^{2}+(-11)^{2}+(-5)^{2} = 250]

이때 데이터의 개수인 n으로 나누면, 오차의 제곱합에 대한 평균을 구할 수 있는데 이를 평균 제곱 오차(Mean Squered Error, MSE)라고 합니다. 수식은 아래와 같습니다.

[\frac{1}{n}\sum_{i=1}^{n}[y^{(i)} - H(x^{(i)})]^{2} = 250/4 = 62.5]

이를 실제로 계산하면 44.5가 됩니다. 이는 $y=13x+1$의 예측값과 실제값의 평균 제곱 오차의 값이 62.5임을 의미합니다. 평균 제곱 오차는 이번 회귀 문제에서 적절한 $W$와 $b$를 찾기위해서 최적화된 식입니다. 그 이유는 평균 제곱 오차의 값을 최소값으로 만드는 $W$와 $b$를 찾아내는 것이 가장 훈련 데이터를 잘 반영한 직선을 찾아내는 일이기 때문입니다.

평균 제곱 오차를 $W$와 $b$에 의한 비용 함수(Cost function)로 재정의해보면 다음과 같습니다.

$cost(W,b) = \frac{1}{n}\sum_{i=1}^{n}[y^{(i)} - H(x^{(i)})]^{2}$

즉 $Cost(W,b)$를 최소가 되게 만드는 $W$와 $b$를 구하면 훈련 데이터를 가장 잘 나타내는 직선을 구할 수 있습니다.

1.3 옵티마이저 - 경사 하강법(Gradient Descent)

앞서 정의한 비용 함수(Cost Function)의 값을 최소로 하는 W와 b를 찾는 방법으로 사용되는 것이 옵티마이저(Optimizer) 알고리즘 또는 최적화 알고리즘이라고도 부릅니다. 그리고 이 옵티마이저 알고리즘을 통해 적절한 $W$와 $b$를 찾아내는 과정을 머신 러닝에서 학습(training)이라고 부릅니다. 여기서는 가장 기본적인 옵티마이저 알고리즘인 경사 하강법(Gradient Descent)에 대해서 살펴보겠습니다.

설명에서 편향 $b$는 고려하지 않겠습니다. 즉, $b$가 0이라고 가정한 $y=Wx$라고 가정합니다.

image

위의 그림에서 주황색선은 기울기 $W$가 20일 때, 초록색선은 기울기 $W$가 1일 때를 보여줍니다. 다시 말하면 각각 $y=20x, y=x$에 해당되는 직선입니다. ↕는 각 점에서의 실제값과 두 직선의 예측값과의 오차를 보여줍니다. 이는 앞서 예측에 사용했던 $y=13x+1$ 직선보다 확연히 큰 오차값들입니다. 즉, 기울기가 지나치게 크면 실제값과 예측값의 오차가 커지고, 기울기가 지나치게 작아도 실제값과 예측값의 오차가 커집니다. 사실 $b$ 또한 마찬가지인데 $b$가 지나치게 크거나 작으면 오차가 커집니다.

$W$와 cost의 관계를 그래프로 표현하면 다음과 같습니다.

image

기울기 $W$가 무한대로 커지면 커질 수록 cost의 값 또한 무한대로 커지고, 반대로 기울기 $W$가 무한대로 작아져도 cost의 값은 무한대로 커집니다. 위의 그래프에서 cost가 가장 작을 때는 맨 아래의 볼록한 부분입니다. 기계가 해야할 일은 cost가 가장 최소값을 가지게 하는 $W$를 찾는 일이므로, 맨 아래의 볼록한 부분의 $W$의 값을 찾아야 합니다.

image

기계는 임의의 초기값 $W$값을 정한 뒤에, 맨 아래의 볼록한 부분을 향해 점차 $W$의 값을 수정해나갑니다. 위의 그림은 $W$값이 점차 수정되는 과정을 보여줍니다. 그리고 이를 가능하게 하는 것이 경사 하강법(Gradient Descent)입니다.

image

위의 그림에서 초록색 선은 $W$가 임의의 값을 가지게 되는 네 가지의 경우에 대해서 그래프 상으로 접선의 기울기를 보여주며, 맨 아래의 볼록한 부분으로 갈수록 접선의 기울기가 점차 작아진다는 점입니다. 그리고 맨 아래의 볼록한 부분에서는 결국 접선의 기울기가 0이 됩니다. 그래프 상으로는 초록색 화살표가 수평이 되는 지점입니다.

즉, cost가 최소화가 되는 지점은 접선의 기울기가 0이 되는 지점이며, 또한 미분값이 0이 되는 지점입니다. 경사 하강법의 아이디어는 비용 함수(Cost function)를 미분하여 현재 $W$에서의 접선의 기울기를 구하고, 접선의 기울기가 낮은 방향으로 $W$의 값을 변경하는 작업을 반복하는 것에 있습니다. 이 반복 작업에는 현재 $W$에 접선의 기울기를 구해 특정 숫자 $\alpha$를 곱한 값을 빼서 새로운 $W$로 사용하는 식이 사용됩니다.

여기서의 $\alpha$는 학습률(learning rate)입니다. 학습률 $\alpha$는 $W$의 값을 변경할 때, 얼마나 크게 변경할지를 결정합니다. 또는 $W$를 그래프의 한 점으로보고 접선의 기울기가 0일 때까지 경사를 따라 내려간다는 관점에서는 얼마나 큰 폭으로 이동할지를 결정합니다.

[기울기 = \frac{\partial cost(W)}{\partial W}]

기울기가 음수일 때와 양수일 때 어떻게 $W$값이 조정되는지 보겠습니다.

  • 기울기가 음수일 때 : $W$의 값이 증가

[W:=W−α×(음수기울기)=W+α×(양수기울기)]

기울기가 음수면 $W$의 값이 증가하는데 이는 결과적으로 접선의 기울기가 0인 방향으로 $W$의 값이 조정됩니다.

  • 기울기가 양수일 때 : W의 값이 감소 \(W:=W−α×(양수기울기)\)

기울기가 양수면 $W$의 값이 감소하게 되는데 이는 결과적으로 기울기가 0인 방향으로 $W$의 값이 조정됩니다. 즉, 아래의 수식은 접선의 기울기가 음수거나, 양수일 때 모두 접선의 기울기가 0인 방향으로 W의 값을 조정합니다.

[W:=W−α\frac{\partial }{\partial W}cost(W)]

지금까지는 $b$는 배제시키고 최적의 $W$를 찾아내는 것에만 초점을 맞추어 경사 하강법의 원리에 대해서 배웠는데, 실제 경사 하강법은 $W$와 $b$에 대해서 동시에 경사 하강법을 수행하면서 최적의 $W$와 $b$의 값을 찾아갑니다.

2. 파이토치로 단순 선형 회귀 구현하기

2.2 기본 셋팅

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
# 랜덤 시드(random seed)
torch.manual_seed(1)

2.2 변수 선언

훈련 데이터인 x_train과 y_train을 선언합니다.

x_train = torch.FloatTensor([[1], [2], [3]])
y_train = torch.FloatTensor([[2], [4], [6]])

x_train과 y_train의 값과 크기(shape)를 출력해보겠습니다.

print(x_train)
print(x_train.shape)
tensor([[1.],
        [2.],
        [3.]])
torch.Size([3, 1])
print(y_train)
print(y_train.shape)
tensor([[2.],
        [4.],
        [6.]])
torch.Size([3, 1])

2.3 가중치와 편향의 초기화

선형 회귀의 목표는 가장 잘 맞는 직선을 정의하는 $W$와 $b$의 값을 찾는 것입니다. 우선 가중치 $W$를 0으로 초기화하고, 이 값을 출력해보겠습니다.

# 가중치 W를 0으로 초기화하고 학습을 통해 값이 변경되는 변수임을 명시함.
W = torch.zeros(1, requires_grad=True) 
# 가중치 W를 출력
print(W) 
tensor([0.], requires_grad=True)

가중치 $W$가 0으로 초기화되어있으므로 0이 출력된 것을 확인할 수 있습니다. 위에서 requires_grad=True가 인자로 주어진 것을 확인할 수 있습니다. 이는 이 변수는 학습을 통해 계속 값이 변경되는 변수임을 의미합니다. 즉 이것을 True로 설정하면 자동 미분 기능이 적용됩니다. 선형 회귀부터 신경망과 같은 복잡한 구조에서 파라미터들이 모두 이 기능이 적용됩니다. requires_grad = True가 적용된 텐서에 연산을 하면, 계산 그래프가 생성되며 backward 함수를 호출하면 그래프로부터 자동으로 미분이 계산됩니다.

마찬가지로 편향 $b$도 0으로 초기화하고, 학습을 통해 값이 변경되는 변수임을 명시합니다.

b = torch.zeros(1, requires_grad=True)
print(b)
tensor([0.], requires_grad=True)

현재 가중치 $W$와 $b$ 둘 다 0이므로 현 직선의 방정식은 다음과 같습니다.

[y=0*x+0]

지금 상태에선 x에 어떤 값이 들어가도 가설은 0을 예측하게 됩니다. 즉, 아직 적절한 $W$와 $b$의 값이 아닙니다.

2.4 가설 세우기

파이토치 코드 상으로 직선의 방정식에 해당되는 가설을 선언합니다.

[H(x) = Wx+b]

hypothesis = x_train * W + b
print(hypothesis)
tensor([[0.],
        [0.],
        [0.]], grad_fn=<AddBackward0>)

2.5 비용 함수 선언하기

파이토치 코드 상으로 선형 회귀의 비용 함수에 해당되는 평균 제곱 오차를 선언합니다.

[cost(W,b) = \frac{1}{n}\sum_{i=1}^{n}[y^{(i)} - H(x^{(i)})]^{2}]

# 앞서 배운 torch.mean으로 평균을 구한다.
cost = torch.mean((hypothesis - y_train) ** 2) 
print(cost)
tensor(18.6667, grad_fn=<MeanBackward0>)

2.6 경사 하강법 구현하기

이제 경사 하강법을 구현합니다. 아래의 ‘SGD’는 경사 하강법의 일종입니다. lr은 학습률(learning rate)를 의미합니다. 학습 대상인 $W$와 $b$가 SGD의 입력이 됩니다.

optimizer = optim.SGD([W, b], lr=0.01)

optimizer.zero_grad()를 실행하므로서 미분을 통해 얻은 기울기를 0으로 초기화합니다. 기울기를 초기화해야만 새로운 가중치 편향에 대해서 새로운 기울기를 구할 수 있습니다. 그 다음 cost.backward() 함수를 호출하면 가중치 W와 편향 b에 대한 기울기가 계산됩니다. 그 다음 경사 하강법 최적화 함수 opimizer의 optimizer.step() 함수를 호출하여 인수로 들어갔던 W와 b에서 리턴되는 변수들의 기울기에 학습률(learining rate) 0.01을 곱하여 빼줌으로서 업데이트합니다.

# gradient를 0으로 초기화
optimizer.zero_grad() 
# 비용 함수를 미분하여 gradient 계산
cost.backward() 
# W와 b를 업데이트
optimizer.step()

optimizer.zero_grad()가 필요한 이유

파이토치는 미분을 통해 얻은 기울기를 이전에 계산된 기울기 값에 누적시키는 특징이 있습니다.

import torch
w = torch.tensor(2.0, requires_grad=True)

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

    z = 2*w

    z.backward()
    print(f'수식을 w로 미분한 값 : {w.grad}')
수식을 w로 미분한 값 : 2.0
수식을 w로 미분한 값 : 4.0
수식을 w로 미분한 값 : 6.0
수식을 w로 미분한 값 : 8.0
수식을 w로 미분한 값 : 10.0
수식을 w로 미분한 값 : 12.0
수식을 w로 미분한 값 : 14.0
수식을 w로 미분한 값 : 16.0
수식을 w로 미분한 값 : 18.0
수식을 w로 미분한 값 : 20.0
수식을 w로 미분한 값 : 22.0
수식을 w로 미분한 값 : 24.0
수식을 w로 미분한 값 : 26.0
수식을 w로 미분한 값 : 28.0
수식을 w로 미분한 값 : 30.0
수식을 w로 미분한 값 : 32.0
수식을 w로 미분한 값 : 34.0
수식을 w로 미분한 값 : 36.0
수식을 w로 미분한 값 : 38.0
수식을 w로 미분한 값 : 40.0
수식을 w로 미분한 값 : 42.0

계속해서 미분값인 2가 누적되는 것을 볼 수 있습니다. 그렇기 때문에 optimizer.zero_grad()를 통해 미분값을 계속 0으로 초기화시켜줘야 합니다.

2.7 전체 코드

결과적으로 훈련 과정에서 Wb는 훈련 데이터와 잘 맞는 직선을 표현하기 위한 적절한 값으로 변화해갑니다.

# 데이터
x_train = torch.FloatTensor([[1], [2], [3]])
y_train = torch.FloatTensor([[2], [4], [6]])
# 모델 초기화
W = torch.zeros(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)
# optimizer 설정
optimizer = optim.SGD([W, b], lr=0.01)

nb_epochs = 1999 # 원하는만큼 경사 하강법을 반복
for epoch in range(nb_epochs + 1):

    # H(x) 계산
    hypothesis = x_train * W + b

    # cost 계산
    cost = torch.mean((hypothesis - y_train) ** 2)

    # cost로 H(x) 개선
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 100번마다 로그 출력
    if epoch % 100 == 0:
        print('Epoch {:4d}/{} W: {:.3f}, b: {:.3f} Cost: {:.6f}'.format(
            epoch, nb_epochs, W.item(), b.item(), cost.item()
        ))
Epoch    0/2000 W: 0.187, b: 0.080 Cost: 18.666666
Epoch  100/2000 W: 1.746, b: 0.578 Cost: 0.048171
Epoch  200/2000 W: 1.800, b: 0.454 Cost: 0.029767
Epoch  300/2000 W: 1.843, b: 0.357 Cost: 0.018394
Epoch  400/2000 W: 1.876, b: 0.281 Cost: 0.011366
Epoch  500/2000 W: 1.903, b: 0.221 Cost: 0.007024
Epoch  600/2000 W: 1.924, b: 0.174 Cost: 0.004340
Epoch  700/2000 W: 1.940, b: 0.136 Cost: 0.002682
Epoch  800/2000 W: 1.953, b: 0.107 Cost: 0.001657
Epoch  900/2000 W: 1.963, b: 0.084 Cost: 0.001024
Epoch 1000/2000 W: 1.971, b: 0.066 Cost: 0.000633
Epoch 1100/2000 W: 1.977, b: 0.052 Cost: 0.000391
Epoch 1200/2000 W: 1.982, b: 0.041 Cost: 0.000242
Epoch 1300/2000 W: 1.986, b: 0.032 Cost: 0.000149
Epoch 1400/2000 W: 1.989, b: 0.025 Cost: 0.000092
Epoch 1500/2000 W: 1.991, b: 0.020 Cost: 0.000057
Epoch 1600/2000 W: 1.993, b: 0.016 Cost: 0.000035
Epoch 1700/2000 W: 1.995, b: 0.012 Cost: 0.000022
Epoch 1800/2000 W: 1.996, b: 0.010 Cost: 0.000013
Epoch 1900/2000 W: 1.997, b: 0.008 Cost: 0.000008
Epoch 2000/2000 W: 1.997, b: 0.006 Cost: 0.000005

에포크(Epoch)는 전체 훈련 데이터가 학습에 한 번 사용된 주기를 말합니다. 현재의 경우 2,000번을 수행했습니다.

최종 훈련 결과를 보면 최적의 기울기 $W$는 2에 가깝고, $b$는 0에 가까운 것을 볼 수 있습니다. 현재 훈련 데이터가 x_train은 [[1], [2], [3]]이고 y_train은 [[2], [4], [6]]인 것을 감안하면 실제 정답은 $W$가 2이고, $b$가 0인 H(x)=2x이므로 거의 정답을 찾은 셈입니다.

3. 자동 미분(Autograd)

경사 하강법 코드를 보고있으면 requires_grad=True, backward() 등이 나옵니다. 이는 파이토치에서 제공하고 있는 자동 미분(Autograd) 기능을 수행하고 있는 것입니다. 모델이 복잡해질수록 경사 하강법을 넘파이 등으로 직접 코딩하는 것은 까다로운 일이지만, 파이토치에서는 이런 수고를 하지 않도록 자동 미분(Autograd)을 지원합니다. 자동 미분을 사용하면 미분 계산을 자동화하여 경사 하강법을 손쉽게 사용할 수 있게 해줍니다.

자동 미분(Autograd) 실습

자동 미분에 대해서 실습을 통해 이해해봅시다. 임의로 $2w^{2} + 5$라는 식을 세워보고, $w$에 대해 미분해보겠습니다.

값이 2인 임의의 스칼라 텐서 w를 선언합니다. 이때 required_gradTrue로 설정합니다. 이는 이 텐서에 대한 기울기를 저장하겠다는 의미입니다. 이렇게 하면 w.grad에 w에 대한 미분값이 저장됩니다.

w = torch.tensor(2.0, requires_grad=True)

이제 수식을 정의합니다.

y = w**2
z = 2*y + 5

이제 해당 수식을 w에 대해서 미분해야합니다. .backward()를 호출하면 해당 수식의 w에 대한 기울기를 계산합니다.

z.backward()

이제 w.grad를 출력하면 w가 속한 수식을 w로 미분한 값이 저장된 것을 확인할 수 있습니다.

print(f'수식을 w로 미분한 값 : {w.grad}')
수식을 w로 미분한 값 : 8.0

4. 다중 선형 회귀(Multivariable Linear regression)

앞서 다룬 $x$가 1개인 선형 회귀를 단순 선형 회귀(Simple Linear Regression)이라고 하며, 다수의 $x$로부터 $y$를 예측하는 것을 다중 선형 회귀(Multivariable Linear Regression)라고 합니다.

단순 선형 회귀와 다른 점은 독립 변수 x의 개수가 이제 1개가 아니라는 점입니다. 3개의 퀴즈 점수로부터 최종 점수를 예측하는 모델을 만들어보겠습니다. 독립 변수 $x$의 개수가 3라 가정했을때 이를 수식으로 표현하면 아래와 같습니다.

[H(x)=w_1x_1+w_2x_2+w_3x_3+b]

4.1 파이토치로 다중 선형 회귀 구현하기

위의 식을 보면 이번에는 단순 선형 회귀와 다르게 $x$의 개수가 3개입니다. 그러니까 $x$를 3개 선언합니다.

# 훈련 데이터
x1_train = torch.FloatTensor([[73], [93], [89], [96], [73]])
x2_train = torch.FloatTensor([[80], [88], [91], [98], [66]])
x3_train = torch.FloatTensor([[75], [93], [90], [100], [70]])
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])

이제 가중치 $w$와 편향 $b$를 선언합니다. 가중치 $w$도 3개 선언해주어야 합니다.

# 가중치 w와 편향 b 초기화
w1 = torch.zeros(1, requires_grad=True)
w2 = torch.zeros(1, requires_grad=True)
w3 = torch.zeros(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)

이제 가설, 비용 함수, 옵티마이저를 선언한 후에 경사 하강법을 1,000회 반복합니다.

# optimizer 설정
optimizer = optim.SGD([w1, w2, w3, b], lr=1e-5)

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

    # H(x) 계산
    hypothesis = x1_train * w1 + x2_train * w2 + x3_train * w3 + b

    # cost 계산
    cost = torch.mean((hypothesis - y_train) ** 2)

    # cost로 H(x) 개선
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 100번마다 로그 출력
    if epoch % 100 == 0:
        print('Epoch {:4d}/{} w1: {:.3f} w2: {:.3f} w3: {:.3f} b: {:.3f} Cost: {:.6f}'.format(
            epoch, nb_epochs, w1.item(), w2.item(), w3.item(), b.item(), cost.item()
        ))
Epoch    0/1000 w1: 0.294 w2: 0.294 w3: 0.297 b: 0.003 Cost: 29661.800781
Epoch  100/1000 w1: 0.674 w2: 0.661 w3: 0.676 b: 0.008 Cost: 1.563628
Epoch  200/1000 w1: 0.679 w2: 0.655 w3: 0.677 b: 0.008 Cost: 1.497595
Epoch  300/1000 w1: 0.684 w2: 0.649 w3: 0.677 b: 0.008 Cost: 1.435044
Epoch  400/1000 w1: 0.689 w2: 0.643 w3: 0.678 b: 0.008 Cost: 1.375726
Epoch  500/1000 w1: 0.694 w2: 0.638 w3: 0.678 b: 0.009 Cost: 1.319507
Epoch  600/1000 w1: 0.699 w2: 0.633 w3: 0.679 b: 0.009 Cost: 1.266222
Epoch  700/1000 w1: 0.704 w2: 0.627 w3: 0.679 b: 0.009 Cost: 1.215703
Epoch  800/1000 w1: 0.709 w2: 0.622 w3: 0.679 b: 0.009 Cost: 1.167810
Epoch  900/1000 w1: 0.713 w2: 0.617 w3: 0.680 b: 0.009 Cost: 1.122429
Epoch 1000/1000 w1: 0.718 w2: 0.613 w3: 0.680 b: 0.009 Cost: 1.079390

위의 경우 가설을 선언하는 부분인 hypothesis = x1_train * w1 + x2_train * w2 + x3_train * w3 + b에서도 x_train의 개수만큼 w와 곱해주도록 작성해준 것을 확인할 수 있습니다.

4.2 행렬 연산을 고려하여 파이토치로 구현하기

$x$의 개수가 3개였으니까 x1_train, x2_train, x3_train와 w1, w2, w3를 일일히 선언해주었습니다. 그런데 $x$의 개수가 1,000개라고 가정한다면, 위와 같은 방식을 고수할때 x_train1 ~ x_train1000을 전부 선언하고, w1 ~ w1000을 전부 선언해야 합니다. 다시 말해 $x$와 $w$ 변수 선언만 총 합 2,000개를 해야합니다. 또한 가설을 선언하는 부분에서도 마찬가지로 x_train과 w의 곱셈이 이루어지는 항을 1,000개를 작성해야 합니다. 이는 굉장히 비효율적입니다.

이를 해결하기 위해 행렬 곱셈 연산(또는 벡터의 내적)을 사용합니다. 즉 행렬 연산을 고려하여 파이토치로 재구현해보겠습니다. 이번에는 훈련 데이터 또한 행렬로 선언해야 합니다.

x_train  =  torch.FloatTensor([[73,  80,  75], 
                               [93,  88,  93], 
                               [89,  91,  90], 
                               [96,  98,  100],   
                               [73,  66,  70]])  
y_train  =  torch.FloatTensor([[152],  [185],  [180],  [196],  [142]])

이전에 x_train을 3개나 구현했던 것과 다르게 이번에는 x_train 하나에 모든 샘플을 전부 선언하였습니다. 다시 말해 (5 x 3) 행렬 $X$을 선언한 것입니다.

x_train과 y_train의 크기(shape)를 출력해보겠습니다.

print(x_train.shape)
print(y_train.shape)
torch.Size([5, 3])
torch.Size([5, 1])

각각 (5 × 3) 행렬과 (5 × 1) 행렬(또는 벡터)의 크기를 가집니다. 이제 가중치 $W$와 편향 $b$를 선언합니다.

# 가중치와 편향 선언
W = torch.zeros((3, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

여기서 주목할 점은 가중치 $W$의 크기가 (3 × 1) 벡터라는 점입니다. 행렬의 곱셈이 성립되려면 곱셈의 좌측에 있는 행렬의 열의 크기와 우측에 있는 행렬의 행의 크기가 일치해야 합니다. 현재 X_train의 행렬의 크기는 (5 × 3)이며, $W$ 벡터의 크기는 (3 × 1)이므로 두 행렬과 벡터는 행렬곱이 가능합니다. 행렬곱으로 가설을 선언하면 아래와 같습니다.

hypothesis = x_train.matmul(W) + b

가설을 행렬곱으로 간단히 정의하였습니다. 이는 앞서 x_train과 w의 곱셈이 이루어지는 각 항을 전부 기재하여 가설을 선언했던 것과 대비됩니다. 이 경우, 사용자가 독립 변수 x의 수를 후에 추가적으로 늘리거나 줄이더라도 위의 가설 선언 코드를 수정할 필요가 없습니다. 이제 해야할 일은 비용 함수와 옵티마이저를 정의하고, 정해진 에포크만큼 훈련을 진행하는 일입니다. 이를 반영한 전체 코드는 다음과 같습니다.

x_train  =  torch.FloatTensor([[73,  80,  75], 
                               [93,  88,  93], 
                               [89,  91,  90], 
                               [96,  98,  100],   
                               [73,  66,  70]])  
y_train  =  torch.FloatTensor([[152],  [185],  [180],  [196],  [142]])

# 모델 초기화
W = torch.zeros((3, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
# optimizer 설정
optimizer = optim.SGD([W, b], lr=1e-5)

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

    # H(x) 계산
    # 편향 b는 브로드 캐스팅되어 각 샘플에 더해집니다.
    hypothesis = x_train.matmul(W) + b

    # cost 계산
    cost = torch.mean((hypothesis - y_train) ** 2)

    # cost로 H(x) 개선
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 100번마다 로그 출력
    print('Epoch {:4d}/{} hypothesis: {} Cost: {:.6f}'.format(
        epoch, nb_epochs, hypothesis.squeeze().detach(), cost.item()
    ))

Read more

Visualizing and Understanding Convolutional Networks

|

image

Abstract

Large Convolutional Network model은 ImageNet 벤치마크에서 인상적인 분류 성능을 보여주었습니다. 하지만 model이 왜 잘 작동하는지, 또는 어떻게 개선될 수 있는지에 대한 명확한 이해가 없습니다.

  • 본 논문에서 두 가지 문제를 다룹니다.
    • 중간 feature layers의 기능과 classifier의 작동에 대한 insight를 제공하는 새로운 시각화 기법을 소개합니다.
    • 또한 다양한 model layers에서 성능 기여를 발견하기 위해 ablation study를 수행합니다. ZFNet은 다른 datasets에 잘 일반화되었음을 보여줍니다: softmax classifier가 retrained될 때, Caltech-101 및 Caltech-256 datasets에 대한 최신 SOTA 결과를 설득력 있게 능가합니다.

Introduction

1990년대 초 LeCun에 의해 소개된 이후, Convolutional Networks는 hand-written digit classification과 face detection와 같은 작업에서 우수한 성능을 보여주었습니다. 가장 주목할 만한 것은 Alex Krizhevsky에 의해 ImageNet 2012 classification benchmark에서 기록적인 성능을 보여, 16.4%의 error rate을 달성했다는 것입니다.

ConvNet model에 대한 관심에는 몇 가지 요인이 있습니다.

  1. 수백만 개의 라벨링이 된 dataset과 함께, 훨씬 더 큰 training sets의 가용성
  2. 매우 큰 model training을 실용적으로 만드는 강력한 GPU 구현
  3. Dropout과 같은 더 나은 model regularization 전략

엄청난 발전에도 불구하고, 이런 복잡한 model의 내부 operation 및 behavior, 또는 어떻게 우수한 성능을 달성하는지에 대한 insight는 여전히 거의 없습니다. 과학적 관점에서 이것은 매우 불만족스러우며, 이러한 model이 어떻게 작동하는지와 이유를 명확하게 이해하지 못한다면, 더 나은 모델의 개발은 시행착오에 그치게 됩니다.

본 논문의 핵심 사항은 다음과 같습니다.

  • 모델의 모든 layer에서 개별 feature maps을 활성화시키는 입력 자극(input stimuli)을 나타내는 시각화 기술을 소개합니다.
  • Zeiler가 제안한 시각화 기술인 multi-layered Deconvolutional Network (deconvnet)를 사용하여 feature activations을 입력 pixel 공간으로 다시 투영하는 방법입니다.
  • 이를 통해 훈련중에 features의 발전(evolution)을 관찰하고 모델의 잠재적인 문제를 진단할 수 있습니다.
  • 또한 입력 이미지의 일부를 가려서 classifier output의 민감도 분석을 수행하여, scene의 어떤 부분이 분류에 중요한지 나타냅니다.
  • 위와 같은 방법으로 다양한 architecture를 탐색하고, ImageNet에서 AlexNet의 결과를 능가하는 architecture를 찾습니다. 이후 softmax classifier를 retraining하여, 다른 dataset에 대한 모델의 일반화 능력을 탐색합니다.
  • network에 대한 직관을 얻기 위해 feature를 시각화하는 것은 일반적이지만, 대부분 pixel 공간에 대한 투영이 가능한 첫 번째 layer로 제한된 연구였습니다. 즉 higher layers에서는 그렇지 않으며, activity을 해석하는 방법이 제한적입니다.
    • layer를 시각화 하는 방법 중 하나는 unit의 activation를 maximize하기 위해 이미지 공간에서 gradient descent를 수행하여 각 unit에 대한 최적의 stimuli을 찾는 방법이 있지만, 이것은 careful initialization가 필요하며 unit의 invariances에 대한 정보를 제공받지 못하는 단점이 있습니다.
    • layer를 시각화 하는 또다른 방법으로 주어진 unit의 헤시안(Hesian)이 어떻게 optimal response을 중심으로 수치적으로 계산될 수 있는지 보여줌으로써 invariances에 대한 insight를 제공합니다. 하지만 higher layers의 경우 invariances이 매우 복잡하여 간단한 2차 근사에 의해 잘 포착되지 않는다는 것입니다.
  • 이와 대조적으로 본 논문의 접근 방식은 training set에 대해 어떤 패턴이 feature map을 활성시키는지 보기위해, invariance를 non-parametric한 관점에서 제공한 기법을 연구했습니다.
  • 또한 우리의 시각화는 input images의 크롭이 아니라, 특정 feature map을 자극하는 각 patch 내의 구조를 드러내는 하향식 투영을 진행합니다.

Unit’s Invariance

패턴인식의 관점에서 Ideal한 feature란 robust하고 selective한 feature를 말합니다. Hidden layer의 Unit들은 feature detector로 해석될 수 있으며, 이는 hidden unit이 표현하는 feature가 현재 입력에 존재하는 경우 strongly respond하고 현재 입력에 부재하는 경우 weakly respond하는 경향을 보이는 것을 의미합니다.

Invariant 한 뉴런이라는 것은 입력이 특정 변환들을 거치게 되더라도 해당 feature로의 high response를 유지하는 것을 의미합니다. (예를 들면, 어떤 뉴런이 얼굴의 특징을 탐지하는 뉴런이라고 할때, 얼굴이 Rotate되더라도 response를 잘 해내는 것이라고 할 수 있습니다.)

Approach

본 논문 전반에걸쳐 standard fully supervised convnet models인 AlexNet을 사용합니다. 해당 모델은 일련의 layers를 통해 color 2D input image $x_i$를, $C$개의 다른 클래스에 대한 확률 벡터 $\hat{y}_i$에 매핑(map)합니다.

Visualization with a Deconvnet

convnet의 작동을 이해하려면 중간 layers의 feature activity을 해석해야 합니다. 이러한 activities을 input pixel space에 다시 매핑(mapping)하는 새로운 방법을 제시하여, feature maps에서 주어진 activation을 원래 어떤 input pattern이 일으켰는지 보여줍니다.

이러한 mapping을 Deconvolutional Network(deconvnet)로 수행합니다. deconvnet은 같은 components(filtering, pooling)을 사용하는 convnet model로 생각할 수 있지만, pixels이 features로 mapping되는 과정의 반대과정을 수행합니다.

image

Figure 1. Unpooling을 통해 feature map을 image로 reconstruction하는 과정

Convnet을 조사하기 위해, deconvnet은 Figure 1과 같이 각 layers에 부착되어, image pixels로 되돌아오는 연속적인 경로를 제공합니다.

  • input image가 convnet과 layers 전체에 걸쳐 계산된 features에 제시됩니다.
  • 주어진 convnet activation를 조사하기 위해, layer의 다른 모든 activations를 0으로 설정하고 feature maps을 연결된 deconvnet layer에 대한 입력으로 전달합니다.
  • 그런 다음 우리는 연속적으로 (i) unpool, (ii) rectify, (iii) 선택된 activation를 일으킨 아래 layer의 activity을 재구성하기 위해 필터링합니다. 그런 다음 input pixel space에 도달할 때까지 반복됩니다.

Training Details

Figure 3은 본 논문의 실험에서 많이 사용된 모델을 보여줍니다.

image

Figure 3. 8-layer convnet model architecture.

Convnet Visualization

Architecture Selection

Occlusion Sensitivity

Correspondence Analysis

Experiments

ImageNet 2012

Feature Generalization

Feature Analysis

Discussion

Read more

ImageNet Classification with Deep Convolutional Neural Networks

|

image

image

Abstract

ImageNet LSVRC-2010 대회에서 120만 개의 high-resolution images를 1000개의 다른 클래스로 분류하기 위해 크고 깊은 convolutional network을 훈련했으며, test data에서 top-1 error rates 37.5% 및 top-5 error rates 17.0%를 달성하여 이전의 SOTA보다 상당히 개선되었습니다.

6천만개의 parameters와 65만개의 neurons이 있는 신경망은 5개의 convolutional layers로 구성되며, 그 중 일부는 max-pooling layers가 뒤따르고, 최종 1000-way softmax가 있는 3개의 fully-connected layers가 뒤따릅니다. 훈련을 더 빠르게 하기 위해 non-saturating neurons과 합성곱 연산에 매우 효율적인 GPU 구현을 사용했고, 특히 fully-connected layers에서 overfitting을 줄이기 위해 “Dropout”이라는 최근에 개발된 regularization 방법을 사용했습니다. 또한 ILSVRC-2012 대회에서 이 모델의 변형을 입력했고, 2위를 차지한 26.2%와 비교하여 top-5 test error rate 15.3%로 우승했습니다.

Introduction

객체 인식(object recognition)에 대한 현재 접근 방식은 기계 학습 방법을 필수적으로 사용하는데, 성능을 개선하기 위해 더 큰 datasets를 수집하고, 더 강력한 models을 학습하며, overfitting을 방지하기 위한 더 나은 기술을 사용할 수 있습니다. 최근까지의 라벨이 된 datasets는 이미지 수만 개 정도로 비교적 작았는데, Simple recognition tasks는 이정도 size의 datasets으로 꽤 잘 해결될 수 있었습니다. 그러나 실제환경에서의 objects들은 상당한 변동성을 보이기 때문에, 객체를 인식하는 방법을 배우려면 훨씬 더 많은 training set를 사용하는것이 필수적입니다. 그리고 실제로 small image datasets의 단점은 지금까지 널리 인지되어왔지만, 최근에 들어서야 수백만 장의 라벨이 된 이미지를 포함하는 데이터 세트를 수집하는 것이 가능해졌습니다.

또한 수백만 개의 이미지에서 수천 개의 objects에 대해 모델이 학습하기 위해서는 모델의 학습 수용력(learning capacity)이 높아야합니다. CNN(Convolutional Neural Networks)은 학습 수용력(learning capacity)이 큰 종류의 모델 중 하나입니다. CNN의 수용력(capacity)은 깊이와 너비를 달리하여 제어할 수 있으며, 이미지의 nature(특성, 성질)(즉, stationarity of statistics and locality of pixel dependencies)에 대해 강력하고 대부분 정확한 추정을 합니다. 따라서 비슷한 크기의 layer가 있는 standard feedforward neural networks과 비교할 때 CNN은 훨씬 적은 connections과 parameters를 가지고 있기 때문에 훈련하기가 더 쉽고 빠르지만, 이론적으로 가장 좋은 성능은 약간 떨어질 수 있습니다.

CNN의 매력적인 특성과 local architecture의 상대적 효율성에도 불구하고, high-resolution images에 대규모로 적용하는 데는 여전히 엄청난 비용이 듭니다. 다행히도, 2D 합성곱을 효율적으로 처리하는 최근의 GPU는 큰 규모의 합성곱 신경망을 학습시킬만큼 강력하며, 또한 ImageNet과 같은 대형 데이터셋은 overfitting을 방지할 정도로 많은 수의 라벨이 된 이미지를 제공합니다.

이 논문의 기여는 다음과 같습니다.

  • ILSVRC-2010 및 ILSVRC-2012 대회에서 사용된 ImageNet의 subset에 대해 현재까지 가장 큰 CNN 중 하나를 훈련했으며, SOTA의 결과를 달성
  • 2D 합성곱과 CNN 훈련에 내재된 다른 모든 작업에 고도로 최적화된 GPU 구현을 하였으며 이를 공개
  • 본 network는 성능을 향상시키고 학습시간을 줄이는 여러 가지의 새롭고 특이한 특징(feature)들을 포함
  • 본 network의 크기는 120만 개의 라벨이 된 training dataset을 가지고도 overfitting문제를 일으켰기 때문에, overfitting을 방지하기 위한 몇 가지 효과적인 기술을 사용
  • 최종 network에는 5개의 convolutional layers과 3개의 fully-connected layers가 포함되어 있으며, 이 depth가 중요함
  • convolutional layers(각각은 모델 매개변수의 1% 이하를 포함)를 제거하면 성능이 저하된다는 것을 발견
  • network의 크기는 주로 현재 GPU에서 사용할 수 있는 메모리 양과 우리가 기꺼이 허용할 수 있는 training time에 의해 제한됨
  • 2개의 GTX 580 3GB GPU에 대해 training하는 데 5~6일 소요

The Dataset

  • ImageNet은 대략 22000개의 카테고리에 속하는 1500만 개 이상의 라벨링이 된 고해상도 이미지의 dataset.
  • 약 120만 개의 training image, 50,000개의 validation image, 150,000개의 test image 사용.
  • ImageNet에서는 2가지의 error rates(top-1 및 top-5)을 사용하는 것이 일반적.
  • Test set은 ILSVRC-2010 버전을 주로 사용
  • 이미지를 256 × 256의 고정 해상도(resolution)로 다운 샘플링(down-sampled)적용.
  • 직사각형 이미지는 짧은 변의 길이가 256이 되도록 rescale 후, 가운데 부분을 256 x 256 크기로 patch를 잘라냄.
  • 각 픽셀에서 training set에 대한 mean activity을 빼는 것을 외에는, 다른 방식으로 이미지 전처리를 하지 않았고, 픽셀의 raw RGB값에 대해 네트워크를 train을 진행
  • 본 논문에서는 네트워크 입력이 224×224라고 언급했지만 이는 실수이며 입력은 227×227입니다.

image

이미지 출처 : learnopencv</a>

The Architecture

ReLU Nonlinearity

image

4-layer convolutional neural network에서 ReLU(실선)가 tanh 뉴런(점선)보다 CIFAR-10에서 6배 더 빠르게 25% training error rate에 도달합니다. 각 네트워크에 대한 learning rates은 가능한 한 빨리 훈련할 수 있도록 독립적으로 선택되었습니다. 어떤 종류의 regularization도 사용되지 않았습니다. 여기에서 설명하는 효과의 크기는 네트워크 아키텍처에 따라 다르지만 ReLU가 있는 네트워크가 saturating 뉴런이 있는 네트워크보다 일관되게 몇 배 더 빠르게 학습합니다.

AlexNet의 중요한 기능은 ReLU(Rectified Linear Unit) 비선형성을 사용한다는 것입니다. Tanh 또는 Sigmoid 활성화 함수는 신경망 모델을 훈련하는 일반적인 방법이었습니다. AlexNet은 ReLU 비포화(non-saturating) 활성화함수를 사용하면 tanh 또는 sigmoid와 같은 포화(saturating) 활성화 함수를 사용하는 것보다 깊은 CNN을 훨씬 빠르게 훈련할 수 있음을 보여주었습니다. 논문의 그림은 ReLUs(실선 곡선)를 사용하여 AlexNet이 tanh(점선 곡선)를 사용하는 동등한 네트워크보다 6배 빠른 25% 훈련 오류율을 달성할 수 있음을 보여줍니다. 이것은 CIFAR-10 test set에서 테스트되었습니다.

물론 이런 새로운 활성함수를 고려한게 AlexNet이 처음은 아니지만, AlexNet에서는 오버피팅 방지가 아니라 빠른 학습을 요구하기 때문에 ReLU를 사용하였습니다. 핵심은 더 빠른 학습은 대규모 데이터 세트에 대해 훈련된 대규모 모델의 성능에 큰 영향을 미친다는 것 입니다.

ReLU를 사용하여 더 빨리 훈련하는 이유를 살펴보겠습니다. Tanh와 ReLU 함수는 다음과 같이 주어집니다.

image

이미지 출처 : learnopencv

tanh 함수는 z가 조금만 커지거나 작아지면 매우 높거나 매우 낮은 값에서 포화(saturating)됩니다. 이 영역에서 함수의 기울기는 0에 매우 가까운데, 이것은 경사하강법을 늦출 수 있습니다. 반면에 ReLU 함수에서 z가 커져도 기울기가 0으로 가지 않는, 포화상태가 되지 않습니다(non-saturating). 이렇게 하면 최적화가 더 빨리 수렴되는 데 도움이 됩니다. z의 음수 값의 경우 기울기는 여전히 0이지만 신경망의 대부분의 뉴런은 일반적으로 양수 값을 갖게 됩니다. 같은 이유로 ReLU도 시그모이드 함수보다 우위에 있습니다.

Training on Multiple GPUs

image

  • Intra GPU Connection : 1,2,4,5 번째 Conv layer에서는 같은 GPU 내에서의 kernel만 사용할 수 있음
  • Inter GPU Connection : 3번째 Conv layer와 3개의 FC layer에서는 모든 kernel을 사용할 수 있음
  • 두 개의 GPU를 사용했을때 top-1 및 top-5 error rate를 각각 1.7%, 1.2%가량 줄였으며, 속도도 GPU 하나만 사용하는 것보다 조금 더 빨랐습니다.

단일 GTX 580 GPU에는 3GB의 메모리만 있으므로 훈련할 수 있는 네트워크의 최대 크기가 제한됩니다. 1.2백만개의 training 데이터를 네트워크에 훈련시키기에 너무 커서 1개의 GPU로는 충분치 않다라고 판단했고, 두 개의 GPU에 network를 분산시켰습니다. 병렬화 기법은 기본적으로 kernel(또는 뉴런)의 절반을 각각의 GPU에 배치하는데, 여기서 추가적인 trick은 GPU는 특정 layer에서만 connection 하게끔 합니다. 그에 따른 architecture는 열이 독립적이지 않다는 점을 제외하고, Cires가 작성한 “기둥형” CNN과 다소 유사합니다.

image

High-Performance Neural Networks for Visual Object Classification(Cires an et al.)

Local Response Normalization

ReLU는 saturating되지 않도록 input normalization가 필요하지 않은 특성을 가지고 있습니다. 하지만 ReLU의 출력은 입력에 비례하여 그대로 증가가 됩니다. 그렇게 되면 convolution 또는 pooling시 매우 높은 하나의 픽셀값이 주변의 픽셀에 영향을 미치게 됩니다. 이런 상황을 방지하기 위해 다른 activation map의 같은 위치에 있는 픽셀끼리 정규화시켜줍니다. 여러 feature map에서의 결과를 (local)normalization을 시키면, 생물학적 뉴런에서의 lateral inhibition(측면 억제: 강한 자극이 주변의 약한 자극이 전달되는 것을 막는 효과)과 같은 효과를 얻을 수 있기 때문에 generalization 관점에서는 훨씬 좋아지게 됩니다.

특정 layer에 normalization를 적용한 후 ReLU nonlinearity를 적용했으며, Response normalization는 top-1 및 top-5 error rates을 각각 1.4% 및 1.2% 감소시켰습니다. 또한 CIFAR-10 데이터 세트에서 이 체계의 효율성을 확인했는데, 4-layer CNN은 정규화 없이 13%의 test error rate을 달성하고 정규화를 통해 11%를 달성했습니다.

$(x, y)$ position에 있는 $i$번째 kernel에 적용한 다음 ReLU nonlinearity을 적용하여 계산된 뉴런의 activity을 $a^i_{x,y}$로 표시하면, response-normalized activity $b^i_{x,y}$는 다음 식으로 주어집니다.

image

  • $a$ : activity of a neuron, kernsl의 i번째 channel에 있는 (x, y)점에서 값
  • $b$ : normalized activity, LRN을 적용한 결과 값
  • $i$ : i번째 kernel, 현재 Filter
  • $(x, y)$ : position
  • $n$ : adjacent kernel maps at the same spatial position
  • $N$ : total number of kernels in the layer
  • $k=2$, $n=5$, $\alpha=1e-4$, $beta=0.75$ : hyper-parameters

Local Response Normalization은 아래 그림의 예를 통해 이해할 수 있습니다. 각각의 다른 색상은 다른 채널을 나타내므로 $N=4$이며, 하이퍼파라미터를 $(k,α,β,n)=(0,1,1,2)$라고 정의하겠습니다. $n=2$라는 의미는 위치 $(i,x,y)$에서 정규화된 값을 계산하는 동안, 이전 및 다음 필터인 $(i-1, x, y)$ and $(i+1, x, y)$에 대해 동일한 위치의 값을 고려한다는 의미입니다. $(i,x,y)=(0,0,0)$의 경우 $normalized\ value(i,x,y) = 1/(1^2+1^2) = 0.5$ 입니다. 나머지 정규화된 값도 비슷한 방식으로 계산됩니다.

image

이미지 출처 : medium

Overlapping Pooling

image

Max Pooling 레이어는 일반적으로 깊이를 동일하게 유지하면서 텐서의 너비와 높이를 다운샘플링하는 데 사용됩니다. Overlapping Max Pooling layer는 일반적인 Max Pooling layer와 유사하지만 최대값이 계산되는 인접한 windows은 서로 겹칩니다.

논문의 저자는 인접한 windows 사이에 stride=2, pooling size=3x3으로 설정하여 겹치는 뉴런을 발생시켰고, 그 결과로 top-1 error rate와 top-5 error rate가 각각 0.4%, 0.3% 감소했습니다. 저자들은 overlapping pooling이 있는 모델이 overfit(과적합)하기가 약간 더 어렵다는 것을 학습하는 동안 관찰했습니다.

Overall Architecture

Figure 2: 두 GPU 간의 책임 묘사를 명시적으로 보여주는 CNN architecture의 그림. 하나의 GPU는 그림 상단에서 레이어 부분을 실행하고 다른 GPU는 하단에서 레이어 부분을 실행합니다. GPU는 특정 계층에서만 통신합니다. 네트워크의 입력은 150, 528차원이고 네트워크의 나머지 레이어의 뉴런 수는 253,440 – 186,624 – 64,896 – 64,896 – 43,264 – 4096 – 4096 – 1000입니다.

network에는 가중치가 있는 8개의 layer가 있는데, 처음 5개는 convolutional layer이고 나머지 3개는 fully-connected layer 입니다. 그리고 마지막 fully-connected layer의 출력은 1000개의 클래스에 대한 분포를 생성하는 1000-way softmax에 전달됩니다. network는 multinomial logistic regression objective를 최대화 하는데, 이는 예측 분포에서 올바른 레이블의 log-probability의 training cases의 전반에 걸쳐 평균을 최대화하는 것과 같습니다.

  • 두 번째, 네 번째, 다섯 번째 convolutional layers의 kernel은 동일한 GPU에 있는 이전 layer의 kernel map에서만 연결됩니다.
  • 세 번째 convolutional layer의 kernel은 두 번째 layer의 모든 kernel map에 연결됩니다.
  • fully-connected layers의 뉴런은 이전 layer의 모든 뉴런에 연결됩니다.
  • Response-normalization layers은 첫 번째 및 두 번째 convolutional layer을 따릅니다.
  • Max-pooling layers은 다섯 번째 convolutional layer뿐만 아니라 Response-normalization layers을 뒤따릅니다.
  • ReLU non-linearity은 모든 convolutional 및 fully-connected layers의 출력에 적용됩니다.

조금 더 자세한 그림을 보겠습니다.

image

이미지 출처 : learnopencv</a>

  • 첫 번째 convolutional layers는 4픽셀의 stride(이것은 커널 맵에서 인접한 뉴런의 receptive field(수용장) 중심 사이의 거리입니다)로 11 x 11 x 3 크기의 96개 kernel로 227 x 227 x 3 입력 이미지를 필터링합니다.
  • 두 번째 convolutional layer는 첫 번째 convolutional layer의(response-normalized and pooled) 출력을 입력으로 받아 5 × 5 × 96 크기의 kernel 256개로 필터링합니다.
  • 세 번째 convolutional layer에는 두 번째 convolutional layer의 (normalized, pooled) 출력에 연결된 3 × 3 × 256 크기의 384개의 kernel이 있습니다.
  • 네 번째 convolutional layer에는 3 × 3 × 384 크기의 커널이 384개 있습니다.
  • 다섯 번째 convolutional layer에는 3 × 3 × 384 크기의 커널이 256개 있습니다.
  • fully-connected layers에는 각각 4096개의 뉴런이 있습니다.

이와 관련된 또다른 이미지 입니다.

image

정리하면 다음과 같습니다.

  • Layer 0: Input image
    • Size: 227 x 227 x 3
  • Layer 1: Convolution with 96 filters, size 11×11, stride 4, padding 0
    • Size: 55 x 55 x 96
    • (227-11)/4 + 1 = 55 는 결과 사이즈
  • Layer 2: Max-Pooling with 3×3 filter, stride 2
    • Size: 27 x 27 x 96
    • (55 – 3)/2 + 1 = 27 는 결과 사이즈
  • Layer 3: Convolution with 256 filters, size 5×5, stride 1, padding 2
    • Size: 27 x 27 x 256
    • (5-1)/2=2, 패딩으로 인해 원래 크기로 복원
  • Layer 4: Max-Pooling with 3×3 filter, stride 2
    • Size: 13 x 13 x 256
    • (27 – 3)/2 + 1 = 13 는 결과 사이즈
  • Layer 5: Convolution with 384 filters, size 3×3, stride 1, padding 1
    • Size: 13 x 13 x 384
    • (3-1)/2=1, 패딩으로 인해 원래 크기로 복원
  • Layer 6: Convolution with 384 filters, size 3×3, stride 1, padding 1
    • Size: 13 x 13 x 384
    • (3-1)/2=1, 패딩으로 인해 원래 크기로 복원
  • Layer 7: Convolution with 256 filters, size 3×3, stride 1, padding 1
    • Size: 13 x 13 x 256
    • (3-1)/2=1, 패딩으로 인해 원래 크기로 복원
  • Layer 8: Max-Pooling with 3×3 filter, stride 2
    • Size: 6 x 6 x 256
    • (13 – 3)/2 + 1 = 6 는 결과 사이즈
  • Layer 9: Fully Connected with 4096 neuron
  • Layer 10: Fully Connected with 4096 neuron
  • Layer 11: Fully Connected with 1000 neurons

Reducing Overfitting

Data Augmentation

논문의 저자는 Augmentation이 없었다면 상당한 overfitting에 빠졌을 것이라고 말합니다.

image horizontal reflections image translation

  • 좌우반전(horizontal reflections)을 이용하여 패치를 추출하고, 이미지의 양을 2배로 증가

image

이미지 출처 : learnopencv

image translation

  • 256×256 이미지에서 랜덤하게 227×227 패치를 추출하여 1024배 증가, 총 2048배 증가

image

이미지 출처 : learnopencv

Test

  • 5개의 224 × 224 patches(4개의 corner patches 및 1개의 center patch)와 horizontal reflections(따라서 모두 10개의 patches)를 생성
  • 10개의 patches에 대해 network의 softmax layer에 의해 만들어진 예측을 평균화함으로써 예측

jittering

  • the top-1 error rate을 1% 이상 감소시킵니다.
  • overfitting을 감소시켰습니다.
  • training 이미지에서 RGB 채널의 강도를 변경합니다.
  • 이미지의 각 RGB 픽셀에 PCA를 적용하여 평균=0, 표준편차=0.1을 갖는 랜덤 변수를 곱한 뒤 기존 픽셀에 더해줍니다.

다음과 같은 값을 모든 픽셀에 더해줍니다.

[I_{xy} = [I^R_{xy}, I^G_{xy}, I^B_{xy}]^T +[p_1, p_2, p_3][\alpha_1\lambda_1, \alpha_2\lambda_2, \alpha_3\lambda_3]^T \ \alpha_i \sim N(0, 0.1)]

  • $I_{xy}$는 RGB 이미지 픽셀
  • $p_i$ 및 $λ_i$는 각각 RGB 픽셀 값의 3 × 3 공분산 행렬의 $i$번째 고유벡터 및 고유값
  • $α_i$는 앞서 언급한 랜덤 변수

각 $α_i$는 해당 이미지가 다시 훈련에 사용될 때까지 특정 training 이미지의 모든 픽셀에 대해 한 번만 그려지고, 그 시점에서 다시 그려집니다. 이 체계는 대략적으로 natural images의 중요한 특성을 포착합니다. 즉, object의 정체성은 조명의 강도와 색상의 변화에 따라 변하지 않는다는 것입니다.

Dropout

이미지 출처 : medium

다양한 모델의 예측을 결합하는 것은 test errors를 줄이는 nice한 방법이지만, 훈련하는 데 며칠이 걸리는 대규모 신경망 네트워크는 깊고 훈련하는데 오래걸리기 때문에 이 앙상블 기법을 사용하기 어려웠습니다. 그러나 훈련하는 동안 비용이 약 2배에 불과한 매우 효율적인 모델인 Dropout을 사용하면 됩니다.

“dropped out”된 뉴런은 순방향 전달에 기여하지 않고 역전파에 참여하지 않기 때문에 입력이 제공될 때마다 신경망은 다른 아키텍처를 샘플링하지만, 이러한 모든 아키텍처는 가중치를 공유합니다. 즉 뉴런들 사이의 의존성을 낮추며, co-adaptations을 감소시킵니다. 따라서 다른 뉴런의 다양한 무작위 하위 집합의 연결이 유용한 보다 더 강건한 feature를 학습하는데 집중하게합니다.

  • 0.5의 확률로 각 hidden neuron의 값을 0으로 바꿔줍니다.
  • 3개 중 처음 2개의 fully-connected layers에서 dropout을 사용합니다.
  • dropout이 없으면 네트워크는 상당한 overfitting을 나타냅니다.
  • Test시 dropout 적용 x, 대신 출력에 0.5를 곱해준다.

Details of learning

stochastic gradient descent

  • batch size : 128
  • momentum : 0.9
  • weight decay : 0.0005
    • 소량의 가중치 감소가 모델이 학습하는 데 중요하다는 것을 발견했는데, 여기서 가중치 감소는 단순한 정규화가 아니라 모델의 training error를 줄입니다.
  • learning rate : 0.01
    • validation error rate가 현재 learning rate로 개선되지 않을 때 learning rate을 10으로 나눔
    • 실험 중 총 3번

가중치 w에 대한 업데이트 규칙은 다음과 같습니다.

image

  • $i$ : iteration index
  • $v$ : momentum variable
  • $ε$ : learning rate,
  • $\left\langle \frac{∂L}{∂w} {w_i} \right\rangle{D_i}$ : $w_i$에서 평가된, $w$에 대한 목적 도함수의 $i$번째 배치 $D_i$에 대한 평균입니다.

weight initialization

  • mean=0, std=0.01 Gaussian distribution 초기화
  • 첫 번째, 세 번째 convolutional layers의 biases : 상수 0으로 초기화
  • 나머지 layer : 상수 1로 초기화
    • 이 초기화는 ReLU에 positive인 inputs을 제공하여 학습의 초기 단계를 가속화시킵니다.

train

  • dropout : 0.5
  • epoch : 90
  • 2개의 NVIDIA GTX 580 3GB GPU에서 5~6일 소요

Results

ILSVRC-2010에 대한 결과는 Table 1에 요약되어 있습니다.

image

본 네트워크는 top-1 및 top-5 test set error rates를 각각 37.5%와 17.0%의 달성하였습니다. 당시 발표된 방법 중 47.1%, 28.2%를 기록한 팀은 6개의 sparse-coding된 모델의 예측을 평균하여 기록을 달성하였고, 45.7%, 25.7%의 모델은 2가지 종류의 밀접한 특성을 이용한 Fisher Vectors를 계산하여 2개의 분류기의 예측을 평균하여 기록을 내었는데, 당시의 방법론 보다 훨씬 좋은 성능을 보여주었습니다.

또한 ILSVRC-2012에도 참가하였는데 그에 대한 기록은 Table 2에 나와있습니다.

image

ILSVRC-2012 test set labels은 라벨링이 되어있지 않아서 우리가 시도한 모든 모델들의 test error rates을 기록하지는 못했습니다. 특히 val 과 test의 error rates이 0.1%의 이상 차이가 나지 않기 때문에 둘을 같은 결과로 사용했습니다.

  • 본 논문에서의 CNN은 18.2%의 top-5 error rate을 기록했습니다.
  • 비슷한 CNN 5개의 예측을 평균하면 16.4%의 error rate가 나타납니다.
  • 마지막 pooling layer 위에 여섯 번째 convolutional layer가 추가된 하나의 CNN을 training하여, 전체 ImageNet Fall 2011 release를 분류한 다음, ILSVRC-2012에서 “fine-tuning”하면 error rate가 16.6%에 달합니다.
  • 앞서 언급한 fine-tuning 모댈 2개와 5개의 CNN을 예측을 평균하면 15.3%의 error rate을 얻을 수 있습니다.

Qualitative Evaluations

image

Figure 3: 224x224x3 입력 이미지에서 첫 번째 convolutional layer에서 학습한 11x11x3 크기의 96개 convolutional kernel. 상위 48개 kernel은 GPU 1에서 학습되고 하위 48개 kernel은 GPU 2에서 학습되었습니다.

이 network에서는 다양한 주파수(frequency), 방향(orientation-selective), 색상(blobs)들을 학습했습니다. GPU1의 kernels은 주로 색깔정보가 없지만 GPU2의 kernels은 다양한 색상을 담고있습니다. 이런 특성은 랜덤한 가중치 초기화와는 무관하게 매 실행마다 발생합니다.

image

(Left) 8개의 ILSVRC-2010 테스트 이미지와 우리 모델에서 가장 가능성이 높은 것으로 간주되는 5개의 레이블. 올바른 레이블이 각 이미지 아래에 기록되고 올바른 레이블에 할당된 확률도 빨간색 막대로 표시됩니다(상위 5개에 있는 경우). (Right) 첫 번째 열에 있는 5개의 ILSVRC-2010 테스트 이미지. 나머지 열은 테스트 이미지에 대한 특징 벡터로부터 유클리드 거리가 가장 작은 마지막 은닉층에서 특징 벡터를 생성하는 6개의 훈련 이미지를 보여줍니다.

Figure 4의 왼쪽 panel에서 network가 8개의 test images에 대한 top-5 예측을 계산하여 학습한 내용을 정성적으로 평가합니다. 또한 왼쪽 상단의 진드기와 같이 중심에서 벗어난 objects도 network에 의해 인식될 수 있으며, top-5 레이블의 대부분은 합리적으로 보입니다. 예를들어 고양이종에 속하는 다른 것들이 표범의 하위 라벨들로 예측되었으며, 아래의 첫 번째와 세 번째 이미지인 cherry나 grille의 경우 초점을 어디에 맞추느냐에 따라 충분히 나올 수 있는 답이기 때문에 완전한 오류라고 볼 수는 없습니다.

신경망의 시각적인 지식(visual knowledge)을 확인하는 또다른 방법은 마지막 4096개의 은닉층에서 이미지에 의해 유도된 특성 활성화(feature activations)입니다. 만약 두 이미지가 작은 Euclidean separation으로 특성이 활성화 되었다면, 우리는 신경망이 매우 높은 수준(high levels)으로 그 둘이 비슷하다고 생각합니다. Figure4의 오른쪽 panel에서 이 방법에 따르면 테스트셋의 5개의 이미지와 6개의 훈련이미지가 매우 비슷하다는 것을 보여줍니다. 픽셀 수준에서 생각하면, 검색된 훈련 이미지는 첫번째 열의 이미지와 L2에서 비슷하지 않습니다.(색이나 포즈 등) 그럼에도 불구하고 같은 부류라고 판단하는 것을 볼 수 있습니다. 예를 들어, 개와 코끼리 사진은 다양한 포즈를 취합니다.

이를 통해 단순히 픽셀이 아닌, 더 고차원적인 근거로 분류한다는 것을 알 수 있습니다.

Discussion

본 논문의 결과는 크고 깊은 convolutional neural network이 순수 supervised learning을 사용하여 매우 까다로운 dataset에서 기록적인 결과를 달성할 수 있음을 보여줍니다. 그리고 convolutional layer 중 하나라도 없앨 경우 성능이 크게 떨어지므로 것을 이유로 모델의 깊이가 그만큼 중요합니다. 또한 학습 이전에 비지도학습으로 미리 학습을 했더라면(unsupervised pre-training) 성능이 더 좋았을 것이라고 가정하고 있습니다.

최종적으로 지금까지의 결과는 네트워크를 더 크게 만들고 더 오래 훈련했기 때문에 개선되었지만, human visual system의 infero-temporal pathway와 일치시키기 위해서는 아직 많은 노력이 필요합니다. 궁극적으로 우리는 정적이거나 일시적인 형태에서 매우 많은 정보를 주는 비디오 시퀀스에서 크고 넓은 CNN을 적용하고 싶다고 합니다.

Read more

활성화 함수의 역할과 종류

|

활성화 함수의 필요성

activation f

동물의 대뇌피질에 있는 신경세포들은 서로 화학물질을 전달함으로써 신경세포 또는 뉴런(neuron)간 정보를 교환합니다. 각 신경세포들은 이렇게 전달받은 정보들을 취합한 후 신경세포의 세포체(cell body, soma)에서는 화학적으로 전달받은 정보를 활성화(activation)라는 과정을 통해 전기신호로 전환한 후 신경세포 말단으로 전달하고, 전기신호로 신경세포 말단으로 전달된 정보는 다시 화학물질로 전환되어 다음 신경세포로 전달됩니다. 이때 신경세포의 세포체는 여러가지 복잡한 생물학적 규칙에 따라 신호를 보내거나 또는 보내지 않거나 하며 신호의 강도를 조절하고 신경망 연결을 강화하거나 악화시킵니다. 이처럼 생물학적 신경망에서 활성화는 학습과정에서 매우 중요한 역할을 합니다.

activation f

Heaviside step function</a>

생물학적 신경망을 모방한 인공신경망은 생물학적 신경망처럼 신호가 전달되는 어떤 규칙을 설명하는 수학적인 모델이 필요합니다. 이러한 신호전달 역할을 하는 수학적인 모델이 바로 활성화 함수(activation function) 입니다. 인공신경망의 원조인 TLU(Threshold Logic Unit)나 퍼셉트론(Perceptron) 에서는 그림과 같이 0과 1 두가지 강도를 가지는 Heaviside step function을 사용하였는데 신호전달이 같은 강도로 두가지(binary) 형태로 발생되는 것 보다는 여러가지 강도로 연속적으로 보내는 것이 타당하다고 판단되어 시그모이드(sigmoid)나 tanh 같은 연속적이고 미분 가능한 함수가 활성화 함수로 사용되기 시작되었습니다.

인공신경망은 최초 SLP(Single Layered Perceptron) 형태에서 보다 복잡한 문제를 풀 수 있는 MLP(Multi Layered Perceptron) 구조로 진화하면서 MLP 모델을 학습시킬 수 있는 에러의 역전파(Propagation of Error) 알고리즘이 개발되었고 역전파에 적합한 활성화 함수가 도입되었습니다. 역전파 과정은 사실 생물학적 신경망에서는 발생되는 않는 인공신경망에서 필요한 수학적인 학습 방식이라고 할 수 있습니다.

경사법(Gradient Method)을 이용하여 역전파를 통해 인공신경망 모델을 학습시키는 과정을 한번 살펴보겠습니다. 데이터가 입력되면 학습변수 텐서에 곱해져서 활성화 함수에 적용됩니다. 이런 과정이 여러 단계의 신경층을 통해 순전파하면서 예측값을 만들고, 예측값을 기반으로 목적함수를 계산하고, 이 목적함수를 각 신경층 단계별로 연쇄법칙(Chain rule) 적용하여 역전파 하면서 원하는 학습변수에 대한 기울기(gradient)를 구합니다. 그리고 이 기울기에 학습률을 곱해 각 학습변수를 업데이트 합니다. 이때 활성화 함수가 포함된 목적함수의 기울기가 0이 되면 학습이 되지 않습니다. 따라서 순전파를 통해 목적함수에 포함될 활성화 함수는 학습 변수가 존재할 대부분의 범위에서 그 미분값이 0이 아닌 것이 좋습니다. 이러한 사항들을 정리하면 인공신경망에서의 활성화 함수는 다음과 같은 기능을 수행해야 합니다.

정보의 희소성(sparsity) 강화

인공신경망에서 순전파 할 때 활성화 함수는 의미 있는 정보는 증폭하고 의미 없는 정보는 소멸시킵니다. 즉 이러한 정보의 양극화희소성(sparsity) 라고 하는데 수학모델을 기반으로 하는 인공신경망은 이러한 희소한 데이터로 분석하는 것이 정확도나 수렴속도 향상에 도움이 됩니다. 예를 들면 다음 그림과 같이 각 신경망에서 정보가 전달될 때 활성화 함수를 통해 정보가 희소해지면 어떤 노드는 1을 가지고 어떤 노드는 0을 갖는 좀 더 변별력 있는 결과값을 찾을 수 있고 수렴속도도 빠릅니다.

image

Deep Sparse Rectifier Neural Networks, 2011</a>

경사소멸(gradient vanishing)의 최소화

인공신경망에서 학습과정은 목적함수의 역전파를 통해 각 학습변수를 갱신하는 것입니다. 학습변수를 갱신하는 방법 중 가장 보편적인 경사법을 사용한다면 각 학습변수는 경사도 또는 기울기를 통해 구해집니다. 따라서 목적함수에 포함될 활성화 함수의 미분인 도함수 또는 미분함수가 각 학습변수의 모든 영역에서 0이 아닌 것이 좋습니다. 활성화 함수가 포함된 목적함수를 학습변수로 미분한 값이 0일 때 이런 상황을 경사소멸이라고 하며 갱신할 값이 0이기 때문에 학습이 이루어지지 않습니다.

활성화 함수의 종류

Heaviside Step Function

Heaviside step function 라는 이름이 붙은 이유는 간단합니다. 이 함수로 들어온 입력이 특정 임계점을 넘으면 $1$(혹은 True)를 출력하고 그렇지 않을 때는 $0$을 출력하기 때문입니다.

함수 그래프

activation f

함수 수식

[f(x)= \begin{cases} 1\; for\ x\ ≥ 0
0 \; for\ x < 0 \end{cases}]

특징

  • 단순한 구조
  • 계단 함수는 0을 경계로 출력이 갑자기 바뀐다. 즉 0과 1 중 하나의 값만 돌려준다.
  • 입력이 아무리 작거나 커도 출력은 0 또는 1
  • 큰 관점에서 입력이 작을 때의 출력은 0이고, 입력이 커지면 출력이 1이되는 구조로, 입력이 중요하면 큰 값을 출력하고 입력이 중요하지 않으면 작은 값을 출력한다.
  • 비선형 함수

단점

  • 계단 함수는 그래프에서 보이는 것 처럼, 굉장히 극적으로 모양이 변하기 때문에 데이터의 손실이 발생할 가능성이 굉장히 높아진다.
  • 불연속 함수이기 때문에 미분이 불가능하다.
  • 다중 출력이 불가능하다.
  • 합산된 값이 0.1이든 1.0이든 모두 무시하고 1로 전달하므로 출력되는 결과값이 너무 희석된다.

Linear Activation Function

선형 활성화 함수(linear activation function)은 말 그대로 ‘선형’인 활성화 함수입니다.

그래프

activation f

함수 수식

\(f(x) = x\)

특징

  • 이 함수는 입력의 가중치 합에 대해 아무 것도 하지 않고 단순히 주어진 값을 내보낸다.
  • 선형 활성화 함수를 사용한 모델은 이진 계단 함수를 사용한 모델과 다르게 다중 출력이 가능하다.
  • 때문에 이진 분류는 물론이고 간단한 다중 분류 문제까지도 해결할 수 있습니다.
  • 또한 미분이 가능해서 역전파 알고리즘 또한 사용할 수 있다.

단점

  • 함수의 도함수가 상수이고 입력 x와 관련이 없기 때문에 역전파를 사용은 가능할뿐 실제로 사용할 수 없다.
  • 모델에 선형 활성화 함수를 사용한다면 비선형적 특성을 지닌 데이터를 예측하지 못한다.
  • 선형 활성화 함수를 사용하면 신경망의 모든 레이어가 하나로 축소된다. 신경망의 레이어 수에 관계없이 마지막 레이어는 여전히 첫 번째 레이어의 선형 함수다. 따라서 본질적으로 선형 활성화 함수는 신경망을 단 하나의 계층으로 바꾼다.

Sigmoid / Logistic Activation Function

시그모이드 함수는 계단함수를 부드럽게 만든 함수라고 볼 수 있다. 여기서 부드럽다는 의미는 모든 영역에서 미분 가능하다는 뜻입니다. 시그모이드 함수는 다음 그래프와 같이 (-∞, +∞)의 값을 입력하면 [0, 1] 의 실수값으로 압축해줍니다. 시그모이드 함수는 계단함수 이후 가장 많이 사용되었던 활성화 함수였으나 경사소멸 문제나 수렴속도의 저하로 최근에는 출력값을 [0, 1]로 맞추는 것이 필요한 경우가 아니라면 잘 사용되지 않습니다.

그래프

activation f

함수 수식

[\sigma(x) = \frac{1}{1+e^{-x}}]

특징

  • 비선형 함수이다.
  • 결과값을 [0, 1] 범위로 압축하므로 이 범위 밖의 값으로 확대되는 경우는 없다.
  • 입력이 중요하면 큰 값을 출력하고 입력이 중요하지 않으면 작은 값을 출력한다.
  • 부드러운 활성화 함수로 1차 미분 가능 함수이다.
  • 시그모이드 함수를 쓰는 가장 주된 이유가 바로 치역이 $0$과 $1$사이이므로, 특히 확률을 예측해야 하는 모델에서 자주 사용된다.
  • 시그모이드 함수는 부드러운 곡선이며 입력에 따라 출력이 연속적으로 변화한다. 시그모이드 함수의 이 매끈함이 신경망 학습에서 아주 중요한 역할을 하게 됩니다.

단점

  • 0을 중심으로 x값이 시그모이드 양 끝으로 멀어지게 되면 0과 1로 수렴하게 되어 변별력이 없어짐.
  • x값이 0에서 멀어지면서 경사소멸 현상이 발생한다.
  • 결과값이 [0, 1]이므로 중간값이 0이 아니기 때문에 수렴속도가 느리다.

Tanh Function (Hyperbolic Tangent)

그래프

activation f

함수 수식

[\tanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}}]

특징

단점

ReLU Function

그래프

activation f

함수 수식

[f(x) = \max(0,x)]

특징

단점

Leaky ReLU Function

그래프

activation f

함수 수식

[f(x) = \max(0.1x,x)]

특징

단점

Parametric ReLU Function

그래프

activation f

a=2

함수 수식

[f(x) = \max(ax,x)]

특징

단점

Exponential Linear Units (ELUs) Function

그래프

activation f

a=1

함수 수식

[f(x)= \begin{cases} x \;\;\;\;\;\;\;\;\;\;\;\;\; for\ x ≥ 0
a(e^x-1)\; for\ x\ < 0 \end{cases}]

특징

단점

Swish

그래프

activation f

함수 수식

[f(x) = \frac{x}{1+e^{-x}}]

특징

단점

Gaussian Error Linear Unit (GELU)

그래프

activation f

함수 수식

[f(x) = 0.5x(1 + tanh[\sqrt(2/\pi)(x+0.044715x^3)])]

특징

단점

Scaled Exponential Linear Unit (SELU)

그래프

activation f

λ=1, a=2

함수 수식

[f(x)= \lambda \begin{cases} x \;\;\;\;\;\;\;\;\;\;\;\;\; for\ x ≥ 0
a(e^x-1)\; for\ x\ < 0 \end{cases}]

특징

단점

Read more

활성화 함수(Activation)와 비선형 함수(Non-linear function)

|

Activation function

오늘은 수학 분야에서도 딥러닝과 아주아주 밀접하고 직접적인 주제를 다루어보겠습니다. 바로 softmax나 ReLU 등 이미 익숙히 들어보셨을 활성화 함수(activation function) 입니다. 활성화 함수란 무엇일까요? “어떤 것이 활성화(activated)되었다” 라는 것을 들으면 어떤 것이 떠오르시나요? 활성화(activated) or 비활성화(deactivated) 라는 것은 ‘어떤 조건을 만족 or 불만족했다’라는 것과 긴밀한 연관이 있습니다.

activation f

이미지 출처 : v7labs

즉 신경망 속의 퍼셉트론(perceptron) 혹은 노드(node)는 ‘특정 조건’이 만족하면 ‘활성화’ 되도록 디자인되어 있으며, 노드에 입력으로 들어오는 값이 어떤 ‘임계치’를 넘어가면 “활성화(activated)”되고, 넘어가지 않으면 “비활성화(deactivated)”되게끔 설계되어 있습니다. 즉 계단 함수(Step function)를 통해 출력값이 0이 될지, 1이 될지를 결정했습니다. 이러한 매커니즘은 실제 뇌를 구성하는 신경 세포 뉴런이 전위가 일정치 이상이 되면 시냅스가 서로 화학적으로 연결되는 모습을 모방한 것입니다. 이렇게 은닉층과 출력층의 뉴런에서 출력값을 결정하는 함수활성화 함수(Activation function) 라고 합니다.

활성화 함수의 기본적 정의는 위와 같지만, 실제로 딥러닝에서 활성화 함수를 쓰는 결정적 이유는 따로 있습니다. 바로 신경망에 비선형성을 추가하여 딥러닝 모델의 표현력을 향상시켜주기 위해서인데요, 전문적인 용어로는 모델의 representation capacity 또는 expressivity 를 향상시킨다라고도 말합니다.

improve expressivity

활성화 함수는 모델의 표현력을 왜 향상시켜줄까요? 답은 간단합니다. 만일 어떤 모델이 $w_1, b_1$이라는 2개의 parameter로 이루어진 다음과 같은 모델이라고 해보겠습니다.

[f(x)=w_1x+b_1]

그런데 이 모델로 $x^2, x^5, sin(x)$등으로 표현되는 데이터를 학습할 수 있을까요? 답은 “그럴 수 없다” 입니다. 왜냐하면 $w_1, b_1$값을 아무리 바꿔도 $x^2, x^5, sin(x)$와 같은 함수는 절대 표현할 수 없기 때문이죠. 이를 수학적으로 말하면, '”선형” 함수(직선)로는 “비선형”함수(사인곡선 or $x^5$와 같은 고차항)를 표현할 수 없다’라고 말합니다.

그런데 잘 생각해 보시면 딥러닝 모델의 parameter($w,b$)들은 입력값 $x$와 선형 관계입니다. 왜냐하면, $wx+b$의 표현되는, 즉 곱하고 더하는 연산만 하면서 그다음 layer로 전달하기 때문이죠. 그리고 아무리 많은 layer들을 겹쳐도 역시 그 결과는 선형 관계입니다. 따라서 사인 곡선처럼 직선으로는 근사 시킬 수 없는 (혹은 고양이나 강아지 사진처럼 무수히 많고 복잡한 특징들을 가진) 비선형 데이터를 표현하려면 딥러닝 모델도 비선형성을 지니고 있어야 합니다. 이때 쓰인 것이 바로 활성화 함수이고, 이 활성화 함수를 layer 사이사이에 넣어줌으로써 모델이 비선형 데이터도 표현할 수 있게 되었습니다.


Linear and Non-linear

딥러닝에서는 일반적으로 비선형 활성화 함수를 사용한다고 합니다. 그럼 선형 활성화 함수는 왜 딥러닝에서 사용되지 않는 걸까요? 이를 알아보기 위해 먼저 선형(Linear)에 대해 알아보겠습니다.

선형(Linear)

선형 변환이란 ‘선형’이라는 규칙을 지키며 $V$, 공간상의 벡터를 $W$ 공간상의 벡터로 바꿔주는 역할을 합니다.

activation f

그럼 자세하게 들어가서 먼저 선형 변환(linear transformation)이 어떤 것인지 정의하고 가겠습니다.

선형 변환(linear transformation) 정의

$V$와 $W$가 어떤 $(1)$벡터 공간이고 둘 모두 $(2)$실수 집합 $(3)$상에 있다고 가정하겠습니다. 이때 함수 $(4) \mathcal{T}: V \rightarrow W$가 다음 두 조건을 만족할 때,

  • 가산성(Additivity) : 모든 $x, y \in V$에 대해, $\mathcal{T}(x+y) = \mathcal{T}(x)+ \mathcal{T}(y)$
  • 동차성(Homogeneity) : 모든 $x \in V, c \in \Bbb{R}$에 대해, $\mathcal{T}(cx) = c\mathcal{T}(x)$

위 2가지 성질을 만족한다면, 함수 $\mathcal{T}$를 선형 변환(linear transformation) 이라고 부릅니다.

(1) : 간단하게 말해서 벡터를 그릴 수 있는 공간입니다. 영상에서의 좌표 평면이라고 생각하시면 됩니다.

(2) : 정확히 표현하면 같은 체(field)에 속해 있다고 해야 하나, 이 글에선 실수만 다루기 때문에 실수 집합 상에 있다고 표현했습니다. 체의 예로는 실수 집합 $\Bbb{R}$, 유리수 집합 $\Bbb{Q}$, 복소수 집합 $\Bbb{C}$ 등이 있습니다.

(3) : 실수 집합 상에 있다는 말은 $V$를 이루는 원소들이 실수라는 의미입니다. 예를 들어 실수 집합 상의 $V$가 어떤 벡터들의 집합이라고 했을 때, 그 벡터는 실수 벡터(벡터의 각 원소가 실수)가 됩니다.

(4): 정의역(domain)이 $V$ 이고 공역(codomain)이 $W$ 인 함수 $\mathcal{T}$라는 의미입니다.

activation f

간단히 ’$\mathcal{T}$ 는 선형(linear) 이다.’ 라고 하기도 합니다. $\mathcal{T}$가 선형이라면 다음과 같은 성질을 가집니다.

$\mathcal{T}(0)=0$

모든 $x,y \in V$ 와 $c \in \Bbb{R}$ 에 대해 다음 식과 동치입니다. $\mathcal{T}(cx+y)=c\mathcal{T}(x)+\mathcal{T}(y)$

모든 $x,y \in V$ 에 대해 $\mathcal{T}(x-y)=\mathcal{T}(x)-\mathcal{T}(y)$ 는 $x_1, x_2, \dots, x_n \in V$ 과 $a_1, a_2, \dots, a_n \in \Bbb{R} $ 에 대해 다음의 식과 동치입니다.

\[\mathcal{T} \biggl(\displaystyle\sum_{i=1}^n a_ix_i \biggl) = \displaystyle\sum_{i=1}^n a_i\mathcal{T}(x_i)\]

예를 하나 들어보죠. 다음과 같이 정의된 함수 $\mathcal{T} : R^2 \rightarrow R^2$ 는 선형일까요?

$\mathcal{T}(a_1,a_2) = (a_1+2a_2, a_2)$ 라고 정의를 하고, $c \in \Bbb{R}$이고 $(x_1, x_2), (y_1, y_2) \in \Bbb{R}^2$라고 하겠습니다. 그럼, $c(x_1,x_2)+(y_1,y_2)=(cx_1+y_1, cx_2+y_2)$ 이므로, 이를 이용해서 $\mathcal{T}(c(x_1,x_2)+(y_1,y_2))$ 를 구하면 다음과 같습니다.

\[\begin{aligned} \mathcal{T}(c(x_1,x_2)+(y_1,y_2)) & = \mathcal{T}(cx_1+y_1, cx_2+y_2) \\ & = (cx_1+y_1 + 2(cx_2+y_2), cx_2+y_2) \end{aligned}\]

또한,

\[\begin{aligned} c\mathcal{T}(x_1,x_2)+\mathcal{T}(y_1,y_2) & = c(x_1+2x_2,x_2)+(y_1+2y_2,y_2)\\ & = (cx_1+2cx_2+y_1+2y_2, cx_2+y_2)\\ & = (cx_1+y_1 + 2(cx_2+y_2),cx_2+y_2) \end{aligned}\]

이므로, $\mathcal{T}(c(x_1,x_2)+(y_1,y_2))=c\mathcal{T}(x_1,x_2)+\mathcal{T}(y_1,y_2)$ 입니다. 따라서 2번째 성질에 의해 $\mathcal{T}$ 는 선형 입니다.

비선형(Non-linear)

그렇다면 비선형은 뭘까요? 간단합니다. 선형이 아닌 함수를 비선형(Non-linear) 함수라고 합니다. 아래 함수 $f(x)$들을 살펴보고, 다음 질문에 답해 봅시다.

$1) f(x)=3x$

어떤 실수 $x,y,c$가 있다고 할 때, $f(cx+y)=3(cx+y)$이고, $cf(x)+f(y)=3cx+3y=3(cx+y)$이므로 $f$는 선형입니다.


$2) f(x)=x2$

어떤 실수 $x,y,c$가 있다고 할 때, $f(cx+y) = (cx+y)^2$이고, $cf(x)+f(y)=cx^2+y^2$이므로 $f$는 선형이 아닙니다.


$3) f(x)=\theta_0x_0 + \theta_1x_1(x=[x_0, x_1]은 벡터)$

주어진 식을 벡터의 형태로 다음과 같이 표현할 수 있습니다.

[f(x)=θ_0x_0+θ_1x_1=[θ_0\ θ_1]⋅[x_0 \ x_1]=θx]

어떤 벡터 $x, y \in \Bbb{R}^2$와 어떤 실수 $c$가 있다고 할 때,

[\begin{aligned} f(cx+y)&=f([cx_0+y_0\ cx_1+y_1])\ & =[θ_0\ θ_1]⋅[cx_0+y_0\ cx_1+y_1]\&=θ_0(cx_0+y_0)+θ_1(cx_1+y_1) \end{aligned}]

이고,

[\begin{aligned} cf(x)+f(y)&=cθx+θy\&=c(θ_0x_0+θ_1x_1)+θ_0y_0+θ_1y_1\&= θ_0(cx_0+y_0)+θ_1(cx_1+y_1) \end{aligned}]

이므로 $f$는 선형입니다.


비선형 함수를 쓰는 이유

그렇다면 왜 딥러닝에서는 비선형 활성화 함수를 주로 사용할까요? 한 문장으로 요약하자면, “딥러닝 모델의 표현력을 향상시키기 위해서” 입니다.

  • 그럼 선형 활성화 함수를 사용하면 왜 표현력이 떨어지게 되는 걸까요?
  • 레이어를 충분히 쌓는다면 선형 활성화 함수를 사용한 모델의 표현력을 향상시킬 수 있지 않을까요?

간단한 예시를 통해 알아가보도록 하겠습니다.

activation f

위 그림과 같이 퍼셉트론 3개로 구성된 모델이 있다고 가정하겠습니다. 입력값 $x$가 모델을 거치면 출력값 $y$가 됩니다. (여기서 입력값 $x$와 출력값 $y$는 스칼라값이고 $f$는 활성화 함수입니다.) 수식으로 표현하면 다음과 같습니다.

[y = f(w_3f(w_2f(w_1x)))]

여기서 $w_i$는 각 입력에 곱해지는 가중치이며, 편향값은 편의를 위해 $0$으로 두겠습니다. 이때 만약 $f$가 선형이라고 한다면 무슨 일이 일어날까요? $f$가 선형이기 때문에 선형 함수의 정의에 의해 $f(w_1x) = w_1f(x)$로 쓸 수 있기 때문에 이를 적용시키면 $w_1, w_2, w_3$을 아래의 식과 같이 합칠 수 있습니다.

[\begin{aligned} y = f(w_3f(w_2f(w_1x))) & = f(w_3f(f(w_1w_2x)))\ & = f(f(f(w_1w_2w_3x)))\ & = f(f(f(Wx)))\ \end{aligned}]

여기서 $W = w_1w_2w_3$입니다.

activation f

위 그림과 같이 $w_i$가 서로 자리를 바꿀 수 있는 것은 $w_i$가 스칼라이기 때문입니다. 편의를 위해 순서대로 나열했습니다 (즉, $w_1w_2 = w_2w_1$). 이것의 의미는 가중치의 업데이트가 $w_1, w_2, w_3$셋 전부에서 일어날 필요가 없다는 것입니다. 간단하게 예를 들어 보겠습니다.

$w_1, w_2, w_3$의 가중치를 모두 $1$로 초기화하고 모델을 훈련시켰을 때, 최종적으로 훈련된 모델의 가중치들이 $w_1’, w_2’, w_3’$라고 하겠습니다. 이것을 식으로 하면 다음과 같습니다.

[y = f(w_3’f(w_2’f(w_1’x)))]

함수 $f$가 선형인 것을 이용해 식을 다음과 같이 바꾸어 보겠습니다.

[y = f(f(f(W x)))]

여기서 $W = w_1’ w_2’ w_3’$입니다. 이 식은, 사실상, $w_1, w_2, w_3$의 가중치를 모두 $1$로 초기화하고 모델을 훈련시켰을 때, $w_2$와 $w_3$은 업데이트되지 않게 고정시키고 $w_1$만 업데이트한 것과 같습니다. 즉, $w_2$나 $w_3$의 가중치가 어떻게 변하는지와 상관없이  $w_1$만 잘 업데이트되면 결과는 같다는 것이죠. 그럼 나가아서 $f(f(f(W x)))$를 $f^\star(W x)$로 표현할 수도 있을까요? 이렇게 하기 위해선 그냥 $f$함수 3개를 하나의 합성함수로 만들어 주면 됩니다. 그런데 선형 함수들의 합성함수도 선형일까요?

activation f

네, 선형입니다. 그럼 어떻게 해서 선형이 되는지 증명해 보고 넘어가도록 할까요?

선형 변환의 합성함수에 관한 정리

$V, W$ 그리고 $Z$ 가 실수 공간상의 벡터 공간이고, 함수 $\mathcal{T} : V \rightarrow W$ 와 함수 $\mathcal{U} : W \rightarrow Z$ 가 선형이라고 하면, 합성함수 $\mathcal{UT} : V \rightarrow Z$ 도 선형입니다.

$x, y \in V$이고 $a \in \Bbb{R}$이라고 하겠습니다. 그럼,

[\begin{aligned} \mathcal{UT}(ax+y) & = \mathcal{U}(\mathcal{T}(ax+y)) \ & = \mathcal{U}(a\mathcal{T}(x)+\mathcal{T}(y)) \ & = a\mathcal{U}(\mathcal{T}(x)) + \mathcal{U}(\mathcal{T}(y)) \ & = a\mathcal{U}\mathcal{T}(x) + \mathcal{U}\mathcal{T}(y) \end{aligned}]

이므로, 선형의 성질에 의해 $\mathcal{UT}$도 선형입니다. 우리는 이제 선형함수의 합성함수 또한 선형이라는 것을 알았습니다. 이 정리에 의해 우리는 이제 $f(f(f(W x)))$를 $f^\star(W x)$ 로 표현할 수 있습니다.

이것의 의미는 무엇일까요? 바로 3개의 노드를 1개로 줄여서 표현을 해도 결과가 달라지지 않는다는 것입니다.

activation f

결론적으로, 선형 활성화 함수를 사용한다면, 노드의 개수를 아무리 많이 붙여도 결국 하나의 노드를 사용하는 것과 차이가 없습니다. 그럼 위에서 노드 3개를 사용한 모델은 결국 다음과 같이 단순한 식으로 표현이 됩니다.

\[y=model(x)=f(wx)=awx\]

여기서, 활성화 함수 $f$는 일반적인 선형 함수 $f(x) = ax$라고 하겠습니다. ($a$는 어떤 실수입니다.)

위 식으로부터 알 수 있듯이, 이러한 모델은 선형적 특성을 띠는 데이터만 예측할 수 있고, 비선형적 특성을 띠는 데이터는 예측할 수 없습니다. 이러한 모델로 비선형 특성을 띠는 데이터를 예측하라는 것은 $ax$에서 $a$값을 바꾸어 $x^2$을 만들라는 것과 다름없죠.

다시 말해, 선형 활성화 함수를 사용한다면, 모델의 표현력이 떨어지게 됩니다. 자, 그럼 단일 노드가 아닌 layer들로 구성되어 있는 모델에서도 위와 같을까요?

지금부터는 Layer들을 쌓아도 활성화 함수가 선형이라면 모델의 표현력은 증가하지 않는다는 것을 증명해 보겠습니다. 아래 그림은 input layer가 각각 1개, hidden layer는 2개(왼쪽 그림) or 1개(오른쪽)로 구성된 임의의 모델입니다. 빨간색으로 표현된 부분은 활성화 함수이며, 두 모델 모두 선형 활성화 함수라고 보겠습니다.

activation f

먼저, 각 노드와 연결된 weight와 노드에서 연산된 값(=activation value)을 다음과 같이 표현하겠습니다.

activation f

위와 같이 하나의 weight에는 양옆에 있는 layer와 연결이 되어있으므로, 3개의 index가 필요합니다.

[w_n^{l,m}]

$l : layer\ index,\ m:l번째\ layer의 \ node\ index,\ n:(l−1)번째 layer의 node\ index$

그리고, 노드에서 연산된 activation값은 2개의 index가 필요합니다.

[a_j^l\ or\ a_j^{l-1}]

$l : layer\ index,\ j:k번째\ layer의\ node\ index(그림에선\ m\ or\ n)$

그러면 지금부터 모델에서 임의의 노드를 선택하여 연산을 비교해 보겠습니다. 먼저, 왼쪽 모델에서 수행되는 연산은 다음과 같습니다.

[2번째\ layer의\ 3번째\ node 값 : a_3^2=f(\Sigma_ix_iw_i^{2,3}) - (1)]

[3번째\ layer의\ 1번째\ node 값 : a_1^3=f(\Sigma_ja_j^2w_j^{3,1}) - (2)]

(2)번 식의 $a_j^2$의 의미는 무엇인가요?? 네, 2번째 layer의 $j$번째 node의 연산값입니다. 이제 $a_j^2$를 (1)번 식을 이용하면 다음과 같이 (2)식을 표현할 수 있습니다.

[a_1^3=f(\Sigma_ja_j^2w_j^{3,1}) - (2)]

[a_j^2=f(\Sigma_ix_iw_i^{2,j})]

를 대입하면 다음과 같고,

[a_1^3=f(\Sigma_jf(\Sigma_ix_iw_i^{2,j})w_j^{3,1}) - (3)]

여기서, 이전에 다루었던 “선형 함수의 성질을 이용”하면 (3)식은 다음과 같이 정리됩니다.

[a_1^3=f(f(x_1))(\Sigma_jw_1^{2,j}w_j^{3,1})+f(f(x_2))(\Sigma_jw_2^{2,j}w_j^{3,1})+… - (3)]

너무 조그마한 notation이 많아 어지러우신가요? 조금만 참아주세요, 오른쪽 모델은 1줄이면 끝납니다! 오른쪽은 1개의 hidden layer이므로 다음과 같이 표현됩니다.

[\begin{aligned} a_2^2&=f(\Sigma_ix_iw_I^{2,3}) \ &=f(x_1)w_1^{2,2}+f(x_2)w_2^{2,2}+…-(4) \end{aligned}]

식 (3)과 (4)의 공통점이 있다면 무엇이 있을까요?? 바로 input data의 각 $x_1,x_2,x_3,..$ 에 대해 항들이 독립적으로 분리 가 되었음을 알 수 있습니다. 식 (3)과 (4)에서 $x_1$ 이 들어간 항을 볼까요?

(3)에 있는 $f(f(x_1))$는 선형함수를 2번 거친 것이므로 결국 선형 함수이겠죠? 따라서 식 (4)의 $f(x_1)$처럼 선형함수를 1번만 통과한 것으로도 표현이 가능합니다.

한편, 식 (3)의 $f(f(x_1))$과 곱해진 $\Sigma_jw_1^{2,j}w_j^{3,1}$부분은 여러 weight들의 덧셈과 합으로 이루어졌습니다. 그럼 결국 실수 하나가 나오겠네요? 그렇다면 식 (4)의 $f(x_1)$과 곱해진 $w_1^{2,2}$하나로도 표현이 가능합니다. 결국, 왼쪽 모델의 weight 개수가 아무리 많더라도 실수 하나의 값에 대응되므로 오른쪽 모델의 weight 한 개로도 표현할 수 있습니다.

activation f

위에 설명한 것을 간단하게 함축해서 표현하면 위와 같습니다. 결국 1번 $(w_1^{2,2})$ 은 2번 $(\Sigma_jw_1^{2,j}w_j^{3,1})$ 을 대체할 수 있고, $f’(x_1)(=f(f(x_1)))$ 은 $f(x_1)$ 으로 대체할 수 있으므로, 왼쪽 모델이 표현하는 모든 함수는, 오른쪽 모델이 항상 표현할 수 있습니다.

이러한 결과는 “선형 함수의 성질”로 식 (3)의 각 항들을 풀면서 나타난 성질입니다. 이제 우리는 앞서 던졌던 질문에 대한 답을 할 수 있게 되었습니다. 반면에 다음과 같이 각 layer 마다 비선형 함수가 있다면 어떻게 될까요?

activation f

기본적인 연산은 위에서 했던 것과 같으므로, 선형 변환하기 전의 과정은 생략하고 다음 그림과 함께 살펴만보고 마치겠습니다.

activation f

Read more