본문 바로가기
딥러닝/모두를 위한 딥러닝 2

07 인공지능 뉴런 artificial neural network

by 혜 림 2021. 4. 1.

 아래의 링크를 참고하여 작성하였습니다wikidocs.net/book/2788

 

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net

 

 

개요

 

1. 퍼셉트론

2. 단층 퍼셉트론

3. 다층 퍼셉트론

4. 역전파

5. 비선형 활성화 함수

6. 과적합 방지, 기울기 소실/폭발 

 

 

 

0. 인공지능 뉴런

 

우리의 뇌는 신경 세포 뉴런으로 이루어져있다.

컴퓨터가 이러한 뉴런의 원리를 모방하는 것을 인공지능 뉴런이라고 한다. 

 

 

우리 몸의 뉴런 구조는 아래와 같다.

수상돌기(가지돌기)에서 받은 신호를 축삭돌기를 통해 축삭말단으로 보낸다.

하지만 모든 신호가 전달되는 건 아니다.

예컨대, 어느 정도의 수준을 만족해야 그 신호가 전달된다.

그 수준을 우리는 '역치'라고 한다.

 

즉 신호가 역치를 넘는 강도여야 축삭돌기를 통해서 신호가 전달된다.

 

 

 

https://ko.wikipedia.org/wiki/%EC%8B%A0%EA%B2%BD_%EC%84%B8%ED%8F%AC

 

 

위를 흉내낸 인공지능 뉴런이다

 

 

https://clickai.ai/resource/blog/blog_post_3.html

 

 

여기서 입력값이 신호, 가중치는 입력값을 전달하는 축삭돌기다.

즉 가중치가 충분히 크지 않으면, 입력값은 결과값에 큰 영향을 끼치지 않을 것이다.

 

예를 들어 변수1의 가중치는 0.8인데 변수2의 가중치가 0.2라면 우리는 변수2가 더 중요한 변수임을 알게 될 것이다. 

 

이렇게 입력값과 가중치를 곱한 값을 더한다. 즉 가중치의 합을 구한다.

활성함수를 거쳐서 최종적인 출력값을 계산해 낸다. 

 

활성화함수는 앞서 봤던 Sigmoid, softmax와 같은 역할의 함수라고 생각하면 된다.

점이 찍혀있는 건 어떻게 글로 이걸 설명할 수 있을까 많이 고심했기 때문이다...

 

 

 

차분히 생각해보자

먼저 로지스틱 회귀다

우리가 어떻게 구했는가? 

 

변수가 여러개 있으면 그거를 토대로 0일 확률 p, 1일 확률 1-p를 구했다.

이때 확률을 크게 하는 클래스 값을 택하기로 했다.  

즉 p>1-p이면 클래스 0을, p<1-p이면 클래스 1을 택한다.

 

위 등식을 풀면 $p>0.5$ 인지를 판단하는 문제가 된다.

 

자, 이게 나아가서 소프트맥스 회귀로 이어졌다.

 

여러개의 변수를 토대로 확률 $p_{a}, p_{b},p_{c}$를 구했다. (이때 a,b,c가 클래스다)

이때 확률을 가장 크게 하는 클래스를 하나 택하기로 했다.

 

그렇다면 우리는 총 결과값을 세개를 얻는 것이다: $p_{a}, p_{b},p_{c}$

 

하지만 잘 생각해보자, 우리에게 변수는 세 개뿐인가?

아마 아닐 것이다.

 

이전에 했던 iris를 생각해보자. 변수가 $x_{0},x_{1},x_{2},x_{3}$ 이렇게 4개가 있었다.

그런데 우리가 원하는 결과값은 각 클래스에 속할 확률인 $p_{a}, p_{b},p_{c}$다.

 

그래서 우리는 가중치의 합을 통해서 3개의 값으로 줄여준다.

그리고 이 가중치의 합을 통해서 구한 3개의 값을 이용해서 원하는 결과값인 $p_{a}, p_{b},p_{c}$ 을 구한다.

 

이때 두번째 과정, 그러니까 

"이 가중치의 합을 통해서 구한 3개의 값을 이용해서 원하는 결과값인 $p_{a}, p_{b},p_{c}$ "

이 역할을 하는 것이 활성화함수인 셈이다.

 

부디 잘 이해가 되길 바란다. 미래의 나에게... 

 

 

 

1. 퍼셉트론 

 

퍼셉트론은 인공지능 뉴런의 한 형태로, 매우 초기의 형태다. 

각각의 입력값과 그에 해당하는 가중치들의 곱이 임계값보다 크면 1을 출력한다. 아니라면 0을 출력한다.

도식화하면 아래와 같다. 

 

 

 

 

 

 

 

 

수식으로는 다음과 같다. 여기에서 세타는 임계값을 의미한다. 

가중치와 값의 곱이 임계값을 넘어가면 1, 그렇지 않으면 0을 출력한다.

 

 

 

 

여기에 편향도 추가하면 아래와 같이 도식화 할 수 있다

이때 입력벡터에는 x 대신에 1이 들어간다. 1 * Bias가 곧 Bias 이기 때문이다

 

 

 

 

 

위의 과정을 그림으로 나타내면 아래와 같다.

 

 

 

 

 

 

 

위의 과정도 결국은 함수다. 이러한 함수는 step function이다.

어떤 구간에서 갑자기 튀어오르는 형태다. 

Sigmoid, softmax와 같은 역할의 함수라고 생각하면 된다.

 

 

퍼셉트론은 인공 뉴런의 초기단계라고 했다.

그렇다면 다른 인공 뉴런과 어떤 점이 다른가? 

사용하는 활성화 함수에 차이가 생긴다. 

 

퍼셉트론은 step 함수를, 앞에서 봤던 로지스틱 회귀는 sigmoid, 소프트맥스 회귀는 softmax 회귀를.

 

 

 

 

2. 단층 퍼셉트론

 

기본적인 퍼셉트론부터 보자.

단층 퍼셉트론은 은닉층hidden layer가 없기 때문에단층이라고 부른다.

입력층과 출력층으로 이루어진다. 

 

하지만 단층 퍼셉트론에는 엄연한 한계가 존재한다.

이를 알기 위해서 게이트 연산을 살펴보자. 

 

게이트 연산이란 두 개의 입력값과 하나의 출력값으로 이루어진 연산을 의미한다. 

 

 

 

 

게이트 연산의 종류는 다음과 같다

 

- AND 게이트: 입력값이 모두 1이면  1을 출력한다

- NAND 게이트: 입력값이 모두 1이면  0을 출력한다

- OR 게이트: 입력값이 모두 0이면 0을 출력한다

 

 

 

 

 

                    입력벡터를 좌표평면에 나타냈다                        ★은 output 이 1임을 의미한다

 

 

XOR 게이트: 입력값이 서로 다르면(0,1) (1,0) 1을 출력한다

 

그렇지만 XOR 게이트의 경우 실현이 불가능하다.

아무리 가중치와 편향을 고쳐도 불가능하다. 

이때 XOR 게이트를 단층 퍼셉트론으로 구현하지 못하는 이유는 무엇인가?

 

직선(선형 함수) 하나로 두 영역을 구분하려고 하기 때문이다! 

 

 

 

 

그러면 이번엔 선형에 얽매이지 말고 생각해보자

어떻게 하면 한번의 획으로 저 별 두개와 초록 색 점을 구분할 수 있을까?

 

 

 

 

 

위처럼 획을 구부리면 된다! 즉 비선형 함수를 이용하는 것이다

이렇듯 XOR 게이트가 구현이 불가능하다는 단층 퍼셉트론의 문제점을 극복한 것이 다층 퍼셉트론이다 

비선형 함수를 이용한다는 것이 핵심이다! 

 

 

실제로 단층 퍼셉트론을 돌려봐도 그러한 결과가 나온다

 

X=torch.FloatTensor([[0,0],[0,1],[1,0],[1,1]]).to(device)
Y=torch.FloatTensor([[0],[1],[1],[0]]).to(device)

Y 가 우리의 target이다 [0,0] 처럼 입력값이 같은 경우에는 0, [0,1]처럼 입력값이 다른 경우에는 1을 출력해야 한다

 

그 후엔 우리가 원하는 모델을 만들자

모델은  시그모이드(가중합)) 의 형태이다

 

 

linear=nn.Linear(2,1,bias=True)
sigmoid=nn.Sigmoid()
model=nn.Sequential(linear,sigmoid).to(device)

그 후에 비용함수와 경사 하강법에 대한 설정을 한다 

criterion=torch.nn.BCELoss().to(device)
optimizer=torch.optim.SGD(model.parameters(),lr=1)

실행해보자! 

for epoch in range(10001):
    optimizer.zero_grad()
    hypothesis=model(X)
    
    cost=criterion(hypothesis,Y)
    cost.backward()
    optimizer.step()
    
    if epoch%100==0:
        print(epoch, cost.item())

 

 

어떤가? 10,000 번을 시행했음에도 불구하고 코스트가 무려 0.69나 된다

좀더 거슬러 올라가면 

 

 

100번째 즈음부터 cost가 하나도 변하지 않았다는 것이다

 

그렇다면 우리가 만든 모델로 예측을 해서 실제로 어쩌고 있는지 좀 봐보자  

with torch.no_grad():
    hypothesis=model(X)
    predicted=(hypothesis>0.5).float()
    accuracy=(predicted==Y).float().mean()
    
    print("모델의 출력값: ",hypothesis.detach().cpu().numpy())
    print("모델의 예측값: ",predicted.detach().cpu().numpy())
    print("실제값: ",Y.cpu().numpy())
    print("정학eh: ",accuracy.item())
    print(type(accuracy))

 

 

아이구머니나! 굉장히 예측을 잘 못하고 있음을 확인할 수 있다

그래서 단층 퍼셉트론으로는 XOR게이트 연산을 못함을 확인할 수 있다

3. 다층 퍼셉트론

 

다층 퍼셉트론은 아래에 보이는 것처럼 입력층과 출력층 사이에 은닉층이 끼어있다

단층 퍼셉트론에서 구현이 불가능했던 XOR은 다른 게이트 연산을 다시 연산하여 만들어낼 수 있다

 

 

 

 

NAD와 OR을 combine해서 XOR을 만들어낸 것은 단순 예시일뿐

 

 

 

좀 더 자세하게 보자

 

 

여기에서 z값들은 단순히 가중합을 의미한다(WX+b) 

그렇지만 앞에서 softmax 함수에서 했듯이 우리는 이 가중합을 입력값으로 두고 다시 함수에 넣는다

이때 이게 활성화 함수라고 했다

 

f(XW+b) 의 값을 h라고 두었다 활성화 함수의 결과값이다

h와 o를 따로 둔 것은 서로 다른 활성화 함수를 이용했기 때문이다

 

 

그렇다면 정말로 은닉층을 쓰면 XOR 게이트 연산이 가능해질까? 

아까와 동일한 데이터다 

X=torch.FloatTensor([[0,0],[0,1],[1,0],[1,1]]).to(device)
Y=torch.FloatTensor([[0],[1],[1],[0]]).to(device)

대신 모델을 복잡하게 설정해준다

시그모이드(가중합(시그모이드(가중합(시그모이드(가중합)))))) 의 형태다 

model=nn.Sequential(
        nn.Linear(2,10,bias=True),
nn.Sigmoid(),
nn.Linear(10,10,bias=True),
nn.Sigmoid(),
nn.Linear(10,1,bias=True),
nn.Sigmoid()).to(device)
criterion=torch.nn.BCELoss().to(device)
optimizer=torch.optim.SGD(model.parameters(),lr=1)
for epoch in range(10001):
    optimizer.zero_grad()
    hypothesis=model(X)
    
    cost=criterion(hypothesis,Y)
    cost.backward()
    optimizer.step()
    
    if epoch%100==0:
        print(epoch, cost.item())

 

 

어떤가 이번에는 줄어들고 있지 않은가?

초록빛이 들어온 것 같다, 희망적이다!

 

그렇다면 한번 모델로 예측한 값을 직접 봐보자

with torch.no_grad():
    hypothesis=model(X)
    predicted=(hypothesis>0.5).float()
    accuracy=(predicted==Y).float().mean()
    
    print('모델의 출력값(Hypothesis): ', hypothesis.detach().cpu().numpy())
    print('모델의 예측값(Predicted): ', predicted.detach().cpu().numpy())
    print('실제값(Y): ', Y.cpu().numpy())
    print('정확도(Accuracy): ', accuracy.item())

 

 

와우! 이번엔 해냈다

 

그러면 이번엔 다셉트론으로 조금 더 복잡한 것을 해보자

앞서서 softmax로 필기체를 인식하는 모델을 만들어봤는데, 실은 단층 퍼셉트론이었다

그렇다면 다셉트론으로 돌리면 어떻게 될 것인가?

 

저번과 동일하게 데이터를 불러오고, 배치를 설정해주자

 

모델은 아래와 같다

가중합(렐루(가중합(렐루(가중합))))

model=nn.Sequential(nn.Linear(784,512),
                   nn.ReLU(),
                   nn.Linear(512,256),
                   nn.ReLU(),
                   nn.Linear(256,10))
loss_fn=nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(model.parameters())
for epoch in range(15+1):
    avg_cost=0
    total_batch=len(data_loader)
    
    for X,Y in data_loader:
        X=X.view(-1,28*28).to(device)
        Y=Y.to(device)
        
        optimizer.zero_grad()
        hypothesis=model(X)
        cost=loss_fn(hypothesis,Y)
        cost.backward()
        optimizer.step()
        
        avg_cost+=cost/total_batch
        
    print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.9f}'.format(avg_cost))
    
print('Learning finished')

 

 

 

실은 줄었는지 잘 모를것이다

그래서 저번 결과도 같이 불러와보자

어떤가 15번째 cost를 비교하면 훨씬 줄지 않았는가??

 

 

 

 

만들 모델로 예측을 해보자

 

with torch.no_grad(): # torch.no_grad()를 하면 gradient 계산을 수행하지 않는다.
    X_test = mnist_test.test_data.view(-1, 28 * 28).float().to(device)
    Y_test = mnist_test.test_labels.to(device)

    prediction = model(X_test)
    correct_prediction = torch.argmax(prediction, 1) == Y_test
    accuracy = correct_prediction.float().mean()
    print('Accuracy:', accuracy.item())

    # MNIST 테스트 데이터에서 무작위로 하나를 뽑아서 예측을 해본다
    r = random.randint(0, len(mnist_test) - 1)
    X_single_data = mnist_test.test_data[r+1:r + 2].view(-1, 28 * 28).float().to(device)
    Y_single_data = mnist_test.test_labels[r+1:r + 2].to(device)
    
    print('Label: ', Y_single_data.item())
    single_prediction = model(X_single_data)
    print('Prediction: ', torch.argmax(single_prediction, 1).item())
    
    plt.imshow(mnist_test.test_data[r+1:r + 2].view(28, 28),
    cmap="Greys", interpolation="nearest")
    plt.show

 

 

 

 

label과 prediction 이 정확하게 일치한다

그리고 softmax를 썼을 때에 비해서 정확도 accuracy도 올라갔다

 

 

 

4. 역전파

 

역전파란  반대로 출력층에서 입력층 방향으로 계산하면서 가중치를 업데이트해가는 것을 의미한다.

쉽게 생각해서 경사하강법은 역전파의 방법이다.

 

위의 그림에서 마지막 부분만 가져오자.

그러면 여기가 역전파 1단계가 된다.

w1~w4까지 있는 곳은 역전파 2단계가 될 것이다.

 

 

 

 

가중치를 비용 함수를 최소화 하는 방향으로 이동시키기 위해서 우리는 앞서 gradient를 계산했다

여기서 우리는 W5의 경우만 한번 보자

비용 함수를 W5에 대해서 미분한다

이때 우리는 chain rule을 이용해서 아래와 같이 계산할 수 있다. 

 

 

 

 

이렇게 여러번 미분해서 곱하는 이유는, 좌변을 곧장 구할 수 없기 때문이다

 

 

비용함수는 아래와 같이 써질 것이다

실제값인 target에서 우리가 계산해 낸 output 값을 빼고 제곱한 후, 평균 낸다

 

 

 

자, 위의 식에서 우변의 첫번째 항을 보자

위의 E_total을 o1에 대해서 미분한 값이다

간단하게 계산할 수 있을 것이다

 

 

 

그 후 우리는 output1을 z3에 대해서 미분해야 한다

sigmoid(z3)=output1 이다

 

그렇다면 우리는 sigmoid의 미분함수만 알면된다

하여 아래와 같이 계산된다

 

 

 

마지막으로 w5에 대해서 z3를 미분한다

z3는 입력값인 h1에 가중치를 곱한 값으로 계산하므로, 미분의 결과값은 다음과 같이 h1이다

 

 

 

 

 

그래서 앞서서 따로 계산했던 항들을 모두 곱하면, 그게 바로 W5의 gradient 값이다

기존의 W5에서 learning rate * gradient (w5)를 빼서, 가중치를 업데이트 해준다

 

반대로 순전파는 우리가 input에서 output을 도출해가는 과정이다.

즉 순전파를 통해서  output을 구하고,

output과 실제값 사이의 오차를 구해서 

역전파를 통해서 w들을 업데이트 해주는 것이다.

 

그럼 이 업데이트된 w들을 가지고 다시 순전파, 오차 계산, 역전파의 과정을 겪는 셈이다.  

 

5. 비선형 활성화 함수

 

앞서서 강조를 했듯이, 다층 퍼셉트론에서는 비선형 활성화 함수를 써야한다.

 

 

 

 

 

 

여태껏 sigmoid 함수를 예로 들었지만, 사실 이는 바람직하지 않다. 

 

 

 

 

 

왜냐하면 output이 0과 1일 때 그 기울기가 0에 가깝기 때문이다

 

 

위의 그래프를 보면 쉽게 이해할 수 있다. 

위 그래프는 나름 sigmoid 함수를 미분한 그래프를 그린 것이다. 

sigmoid의 값은 0~1 사이의 값을 가지므로, 계속 곱해주면 그 값이 점점 작아지게 된다.

따라서 위 그림처럼  sigmoid의 도함수는 점점 낮아질 것이다. 

이게 무엇을 의미하는가? 바로 기울기 소실이다. 

 

즉 역전파로 거슬러 가기 어려워짐을 의미한다

https://wikidocs.net/60683

 

이를 막기 위해서 우리는 다른 비선형 함수를 사용한다. 

 

- 하이퍼볼릭탄젠트 함수

- 렐루 ReLU 함수

- 리키 렐루leaky ReLU 함수

- 소프트맥스 함수 

 

 

 

 

각각의 함수에 대해서 알고 싶다면 아래의 코드를 참고하자

 

 

# 시그모이드 함수 
def sigmoid(x):
    return 1/(1+np.exp(-x))
    
# 하이퍼볼릭 탄젠트 함수는 np.tanh(x) 함수를 이용

# 렐루 함수 
def relu(x):
    return np.maximum(0,x)
    
# 리키 렐루 함수 여기서 0.1은 사용자가 지정하는 값
def leaky_relu(x):
    return np.maximum(0.1*x,x)

# 소프트맥스 함수
def softmax(x):
	retrun np.exp(x)/np.sum(np.exp(x))

6. 과적합 방지, 기울기 소실/폭발 

 

폭발이라니.. 말만 들어도 신난다

하지만 실제로 신나는 일은 아니다....

 

- 1) 과적합 방지 

 

딥러닝에서 가장 주의해야 하는 건 과적합 overfitting이다

지금 주어진 train set을 너무 잘 예측하는 나머지, 새로 들어오는 test set은 잘 예측하지 못한다는 것이다

유연성이 떨어진다

 

 

 

 

그러면 이를 어떻게 해결할 것인가?

 

 

1. 더 많은 데이터 셋을 확보한다

가장 이상적이지만, 가장 어렵다

 

 

2. 모델의 복잡도 줄이기

 

인공 신경망의 복잡도는 은닉층(hidden layer)의 수나 매개변수의 수 등으로 결정된다.

 

모델이 복잡하다는 것은, 유연하지 못하다는 것이다.

즉 이미 주어진 데이터에 지나치게 맞추어져 있기 때문에 유연하게 반응하지 못한다는 것인데, 

이러한 과적합 현상은 인공 신경망의 복잡도를 줄임으로써 해소할 수 있다. 

 

왼쪽의 경우는 은닉층이 2개 있는 경우고, 오른쪽의 경우는 은닉층이 1개 있는 경우다.

 

 

이를 통해 모델의 복잡도를 줄일 수 있고, 나아가 과적합 문제를 어느 정도 방지할 수 있다. 

 

 

 

3. 가중체 규제 적용하기

 

앞서 말했듯이, 모델의 은닉층 뿐 아니라 매게변수가 많아도 모델은 복잡해진다.

즉 간결한 모델이 좋은 것인데, 이를테면 이런 것이다. 

 

아이스크림 가격을 왜 올해는 올리셨나요? 라고 물었을 때

수요가 많아서요, 라는 답변과

수요가 많고, 재고 관리하는데 비용이 너무 많이 들고, 수송 수단을 구하기 어려워졌고, 공급이 줄어들었고, 작년에 동일하게 운영했는데 마진이 별로여서요, 라는 답변 중에서

 

첫번째 답변이 더 간결하고 두 번째 답변이 보다 복잡하다

즉 첫 번째 답변이 이해하기 쉽기 때문이다. 물론 둘 다 이해하기 쉬운 문장이긴 하다

 

 

그래서 우리는 비용함수를 고려할 때 매게 변수의 수도 같이 고려해보면 어떨까? 하는 아이디어를 내게 된다.

 

이를테면 라그랑지 함수다. 

 

penalty term을 도입하게 된다.

즉 매게변수가 많으면 비용을 높여 선택에 부담이 가게 하는 것이다.

 

이때 얼만큼 매게 변수의 수에 예민하게 반응할 것인가를 람다를 통해서 정하게 된다. 

 

크게 두 가지 방식을 소개한다. 

가중치 절대값의  합과 람다를 곱한 L1,

가중치 제곱의 합과 람다를 곱한 L2

 

***아까 매게 변수의 수를 줄인다고 했지만 실제로 비용함수에 더하는 penalty term은 가중치에 대한 것이다

가중치의 절대값, 제곱을 합했으므로 penalty term은 무조건 0보다 커질 수 밖에 없다

 

그러므로 이를 줄인다면 0에 가까워지는 것인데,

가중치가 0에 가까워진다? 이 말이 곧 변수의 영향력을 고려하지 않겠다는 말이 된다. ***

 

 

 

 

 

 

 

하지만 주로 L2를 선호하는데,

그 이유는 단순하다.

계산하기 편해서다.

 

앞에서도 우리는 잔차의 절대값을 더하지 않고 제곱해서 더하지 않았는가?

절대값을 더하게 되면 미분이 불가능한 지점이 생기기 때문에 계산이 어렵다.

그래서 우리는 대부분 절대값보다는 제곱해서 더하게 된다. 

 

 

 4. Dropout

 
뉴런을 모두 사용하자 않고, 일정 비율만큼만 랜덤으로 골라 사용한다. 
그러나 이 방식은 신경만 학습 시에만 사용하고, 예측 시에는 사용하지 않는다. 

 

이를 통해서 얻는 효과는

 

 1. 특정 뉴런, 조합에만 의존적인 것 방지

 2. 매번 랜덤적으로 선택하기에, 매번 다른 신경망들이 형성된다 그러나 예측 시에는 모두를 사용하기 때문에 결과적으로 앙상블한 효과가 나타난다 

 

 

 

- 2) 기울기 소실, 기울기 폭발

 

 

 

0. 기울기 소실, 기울기 폭발

 

기울기 소실이란 역전파 과정으로 가중치를 업데이트 하지 못하게 된 경우를 의미한다.

 

즉 우리는 gradient를 계산해서 하강하게 되는데 이 gradient가 기울기라고 했다.

따라서 이 기울기가 0에 가까워진다면, 우리는 움직이는동 마는동 하게 될 것이다.

이가 기울기 소실이다. 

 

기울기 발산이란 기울기가 수렴하지 않고 발산하는 경우다. 

앞에서 말했듯이 오목한 convex한 함수가 아니면 발산하게 된다. 

 

 

그렇다면 어떻게 해결할 것인가?

 

 

1. 비선형 함수의 선택 

 

기울기 소설을 단점으로 갖는 것이 앞서 보았던 sigmoid 함수이다. 

따라서 우리는 활성화 함수를 다른 것을 택함으로써 이를 해결할 수 있다. 

 

ReLU나 leaky ReLU가 그것이다. 

 

 

2. 가중치 초기화 

 

 

제일 처음 잡는 가중치의 값을 신중하게 하는 것이다. 

 

 

처음 지정하는 값이 왜 중요한가?

 

만약 우리가 시작점 initial point를 A라고 잡으면 경사 하강법gradient descent을 이용하면 A*에서 epoch를 멈출 것이다.

만약 우리가 시작점 initial point를 B라고 잡으면 경사 하강법gradient descent을 이용하면 B*에서 epoch를 멈출 것이다.

 

즉 어디서 시작하느냐에 따라 우리가 얻는 가중치 weight이 달라진다. 

그렇기 때문에 시작점은 중요하다.

 

 

여기서는 신중하게 가중치를 정하는 두 가지 방안을 소개한다. 

 

 ① 세이비어 초기화

 

Unif라는 건 균등분폰데, (a,b)사이의 값이 뽑힐 확률이 균등하다는 것이다.

혹은 정규분포N에 따라서 뽑을 수도 있다.

 

이때의 parameter에 주목하자

 

 

 

 

n_in은 input node 의 갯수, n_out은 output node의 갯수이다

 

 

이는 앞서 보았던 sigmoid, step function과 이용할수록 좋다

 

 

② He  초기화

 

이는 ReLU와 leaky ReLU와 잘 어울린다

 

 

 

이때 주목할만한 점은, 세이비어 초기화는 input node와 output node 모두를 고려하는 반면에,

He 초기화는 input node의 갯수만 주목한다는 점이다 

 

 

3. 배치 정규화

 

매번 들어가는 input node가 다르면 가중치들은 심히 혼란스러워 할 것이다.

그래서 일정한 분포를 가지는 input node를 넣어주고자 하는 게 배치 정규화다.

 

배치 정규화(Batch Normalization)는 한 번에 들어오는 배치 단위로 정규화하는 것으로,

배치 정규화는 각 층에서 활성화 함수를 통과하기 전에 수행한다.

가중치와 마찬가지로 학습하면서 변화하는 변수이다. 

 

 

 

아래와 같은 순서를 따른다

 

하나의 미니 배치와 파라미터 감마와 베타를 입력하면(감마와 베타가 필요한 이유는 밑에서) 

$\text{Input: } \mathrm{B}=\{x_{1},x_{2}, \dots ,x_{i} \}$

 

배치의 scalar들을 정규화한 값을 구한다 

 

순서는 아래와 같다

 

먼저 배치의 평균과 분산을 구한다

$\mu_{B}\leftarrow\frac{1}{m}\sum_{i=1}^m x_{i}$

$\sigma_{B}^{2}\leftarrow\frac{1}{m}\sum_{i=1}^{m} (x_{i}-\mu_{B})^{2}$

 

정규화한 값을 구한다(고등학교 때 배운 Z 점수와 유사하다)

$\hat{x_{i}}\leftarrow\frac{x_{i}-\mu_{B}}{\sqrt{\sigma_{B}^{2}+\epsilon}}$

 

스케일과 시프트를 통해 조정한 BN의 최종 결과

$\hat{y_{i}}\leftarrow\gamma\hat{x_{i}}+\beta =BN_{\gamma,\beta }(x_{i})$

 

 

스케일과 시프트를 하는 이유는 무엇일까?

 

만약 정규화한 값에서 그친다면 우리가 얻는 배치의 값은 0~1이다

예를 들어 활성화 함수가 시그모이드 함수라고 한다면 아래와 같은 형태인데, 

 

 

 

만약에 정규화를 한다면 위 함수의 중간지대의 값들을 가지게 된다.

즉, 선형 함수가 된다는 것이다.

 

우리는 XOR을 구현하지 못한다는 한계가 있는 선형함수를 극복하기 위해

위와 같은 비선형 활성화 함수를 썼는데,

정규화를 통해 다시 선형함수로 돌아가버리는 것이다

 

그래서 대신, 다른 값들을 가지게 하기 위해서 감마와 베타를 이용한다. 

 

- +) 층 정규화 

 

아래 그림을 통해서 차이를 보는 것이 빠를 듯 하다

위가 배치 정규화고 아래가 층 정규화이다. 

 

https://wikidocs.net/61271

 

 

배치 정규화 참고 자료

light-tree.tistory.com/139

kratzert.github.io/2016/02/12/understanding-the-gradient-flow-through-the-batch-normalization-layer.htm

blog.naver.com/PostView.nhn?blogId=laonple&logNo=220808903260

 

댓글