본문 바로가기
인공신경망(DL)/Neural Networks

역전파( Back Propagation ), 최적화(Optimizer)

by kiimy 2021. 8. 14.
728x90
  • 경사하강법과 역전파 알고리즘에 대해 이해하고 설명할 수 있다.
  • 경사하강법과 역전파 알고리즘을 사용하여 신경망을 구현할 수 있다.
  • 케라스 프레임워크를 이용하여 모델을 구축할 수 있다.

인공신경망 학습

MLP의 파라미터 개수가 점점 많아지면서 각각의 weight와 bias를 학습시키는 것이 매우 어려워

so, 

순방향 신경망(FP)과 같은 다층퍼셉트론(MLP, Multi-layer Perceptron) 구조의 신경망은

경사하강법(Gradient descent, GD)으로 학습을 할 수 있는데 역전파(Backpropagationm, BP) 알고리즘에

의해 필요한 기울기(gradient)계산이 가능

신경망 학습 알고리즘 요약:

  1. 학습할 신경망 구조를 선택합니다.
    • 입력층 유닛의 수 = 특징 수
    • 출력층 유닛의 수 = 타겟 클래스 수
    • 은닉층 수, 각 은닉층의 노드 수
  2. 가중치 랜덤 초기화
  3. 순방향 전파를 통해 (출력층 y값) 을 모든 입력 에 대해 계산합니다.
  4. 비용함수를 계산합니다. == MSE
  5. 역방향 전파를 통해 편미분 값들을 계산합니다.
  6. 경사하강법 (or 다른 최적화 알고리즘)을 역전파와 함께 사용하여 비용함수를 최소화 합니다.
  7. 어떤 기준을 충족하거나 비용함수를 최소화 할 때까지 단계 2-5를 반복합니다. 2-5를 한 번 진행하는 것을 epoch 또는 iteration이라 말합니다.

batch, epoch, iteration

epoch

인공 신경망에서 전체 데이터에 대해서 순전파와 역전파가 끝난 상태

ex) 전체 데이터를 하나의 문제지에 비유한다면 문제지의 모든 문제를 끝까지 다 풀고,

     정답지로 채점을 하여 문제지에 대한 공부를 한 번 끝낸 상태

에포크 횟수가 지나치거나 너무 적으면 앞서 배운 과적합과 과소적합이 발생

batch_size

사용 이유:

데이터가 많을 경우 전체 데이터를 메모리에 올리기 힘들 뿐만 아니라,

너무 큰 데이터를 한번에 학습시키면 가장 작은 cost값으로 수렴하기 힘들다는 문제

 

문제지에서 몇 개씩 문제를 풀고나서 정답지를 확인하느냐의 문제

ex) 실제값과 예측값으로부터 오차를 계산하고 옵티마이저가 매개변수를 업데이트

    업데이트가 시작되는 시점이 정답지/실제값을 확인하는 시점

전체 데이터가 2,000일때 batch_size를 200으로 준다면 n는 10

n = iteration

iteration

한 번의 에포크를 끝내기 위해서 필요한 배치의 수 or

한 번의 에포크 내에서 이루어지는 매개변수의 업데이트 횟수

 

SGD를 이 개념을 가지고 다시 설명하면, SGD는 배치 크기가 1이므로 모든 이터레이션마다

하나의 데이터를 선택하여 경사 하강법을 수행

 

비용(cost), 손실(loss), 에러(error)

Objective Function >= Cost Function >= Loss function 이라 생각할 수 있다.
Objective Function가 가장 상위 개념이고 Cost Function과 Loss Function은 Object Function의 한 예라 볼 수 있다.

 

한 데이터 샘플을 Forward Propagation를 시키고 마지막 출력층을 통과한 값과

이 데이터의 타겟값을 비교하여 loss or error를 계산

* loss = 한 데이터 포인트에서의 손실

* cost = 전체 데이터 셋의 loss를 합한 개념

 

신경망을 훈련시키기 위해서는 다른 머신러닝 알고리즘들 보다 훨씬 많은 훈련 데이터가 필요하고

그에 따라 훈련 시간도 오래 걸리며 더 많은 하이퍼파라미터를 튜닝 == 역전파 알고리즘을 사용

역전파 Backpropagation (BP)

신경망에 존재하는 가중치들을 어떻게 업데이트 해야할지 결정하기 위해 epoch/batch 마다

출력층에서 입력층 방향(역방향)으로 미분값을 계산하고 가중치를 업데이트 하여 신경망을 학습하는 알고리즘

 

==> 왜 역전파??

(수치미분 학습의 과정)

1. 순전파 계산(지금 있는 노드들에 입력데이터와 정답값을 지닌 학습 데이터를 넣어주고, 계산 시킴)

2. 손실함수 계산(정답값과, 인공신경망 계산 결과에 대한 오차값 구하기)

3. 각 노드들의 w와 b값들의 기울기를 구하기 위한 미분을 실행(이때, 미분 연산은 편미분 시행

어마어마한 연산량과 과정이 필요. 각 w와 b에 미세한 delta값을 적용하여, 다시 순전파를 실행하여

손실함수까지 구하고, 그 차이의 기울기값을 구하는 것을 그 무수한 w와 b에 시행해줘야한다.

4. 그렇게 구한 기울기에 학습률을 곱한 후, 기존 값에 - 빼준다.(손실함수 기울기의 반대 방향으로

갱신해야 결과가 0에 가까워질테니...)

=====> 수치미분을 통하여 신경망을 갱신하려면, 미분 과정에서 delta값을 더한 순전파를

             몇번이고 다시 시행해야하므로 연산량이 많아진다.

수치 미분 오차역전파법을 정확히 구현했는지 확인하기 위해 필요하다. (기울기 확인 = Gradient Check)

 

오차역전파를 이용하여 미리 해당 노드에서 역전파되는 기울기의 변화에 대한 설정을 해두면,

따로 계산할 것도 없이 기울기를 알아낼수 있다

 

https://wiserloner.tistory.com/789

 

딥러닝 학습시 오차 역전파를 사용하는 이유

- 제목을 다르게 쓰면, 최종 손실 함수를 미분하는 방식으로 학습을 하지 않는 이유가 되겠네요. - 이 글은, 기본적인 딥러닝 구조와 딥러닝에 사용되는 수학적 지식이 있는 것을 가정하고 씁니

wiserloner.tistory.com

# 가중치를 업데이트 해주는 이유

가중치(weight)의 초기값은 랜덤으로 지정된다. 이러한 이유로 에러값(error)이 높게 나올 수도 있고

낮게 나올 수도 있으며 이는 예측값(output)이 낮거나 높게 나올 수도 있다는 말이다.

 

결국은 이 오차(에러값)을 줄일려면 가중치와 편향을 증가시켜주거나 or 감소시켜야한다.(업데이트)

== 입력값과 출력값은 고정이 되어 있기 때문에 

 

*오차를 구하는 이유? 인공신경망이 더 나은 결과를 도출하기 위해서

 

손실 함수(Loss function)

실제값과 예측값의 차이 = 오차

회귀 - MSE

분류 - crossentropy

 

 

 

 

 

손실 함수의 값을 최소화하는 두 개의 매개변수인 가중치 W와 편향 b를 찾아가는 것이 딥 러닝의 학습 과정

* 역전파로 가중치와 편향 업데이트

 

* Cross-Entropy

# 이진분류
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc'])

# 구하고자하는 타겟값이 onehot 형태일때
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])

# 구하고자하는 타겟값이 정수 형태일때
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['acc'])

옵티마이저(optimizer 최적화)

 

여러가지 경사하강법을 적용시킬 수 있다.

 

 

 

 

 

 

 

배치(Batch)

전체 데이터를 가지고 매개 변수의 값을 조정할수도 있고, 정해준 양의 데이터만 가지고도

매개 변수의 값을 조정할 수 있다.

 

batch_size - 한번의 배치마다 전체 데이터에서일부를 불러온다( 전체 데이터를 학습 X -> 조각조각)

ex) batch_size= default 32

전체 데이터수 = 100

전체 데이터수 / 32 , batch= 4 ==> 나머지 2도 하나의 batch로 본다.

한 batch당 들어가 있는 데이터 수 = 전체 데이터수 / batch 수 

즉, 데이터 샘플에서 얼마만큼의 데이터를 불러올거냐~

Error를 줄이기 위해서는?

  • 경사(Gradient)를 계산해서 경사가 작아지도록 가중치를 업데이트!

왜 경사하강법(Gradient Descent, GD)인가?

일단 미분의 의미부터 알아본다

미분은 변수의 움직임에 따른 함수값의 변화를 측정하기 위한 도구로,

최적화에서 가장 많이 사용되는 기법이다.

 

한 점에서 접선의 기울기를 알면, 어느 방향으로 움직여야 함수값이 증가 / 감소하는지 알 수 있다.

W에 대한 가중치 없데이트 공식이다.

랜덤으로 지정해준 가중치에서 오차를 해당 가중치로 미분한 값을 빼준다.

알파 = learning_rate

 

빼주는 이유? - 접선의 기울기가 양수면 함수값이 증가, 음수면 감소하는 것을 알 수 있다.

결국엔

  • 함수값이 증가하고 있다면 해당 값을 빼줘야 최저점으로 갈 수 있고
  • 함수값이 감소하고 있다면 해당 값을 ( - ) *( - ) = + 이므로 더해줘야 최저점으로 가는 것

 

https://www.jeremyjordan.me/nn-learning-rate/

Learning rate(알파) 는 하이퍼파라미터로 사람이 주관적으로 정해주어야하는 값 (0~1 사이)

 

1. 이 때 너무 낮은 값을 선택하면, 위 그림과 같이 최소점까지 아주 조금씩 업데이트

    되므로 수렴속도가 매우 오래걸린다.

 

2. 너무 큰 값을 선택하면, 업데이트가 너무 많이 되서 최소점으로 수렴을 하지 못하고 왔다갔다 하는 발산

결국엔 작지도 크지도 않은 적절한 Learning rate를 찾는것이 매우 중요하다.

 

하지만, GD마다 단점이 있다. 

* BGD( Batch Gridient Descent ) 배치 경사하강법

예를 들어서 데이터가 1000개 있을 때 모든 데이터에 대하여 각각 Loss function을 계산하고,

==> 모든 관측치를 가지고 기울기를 계산하고 업데이트 한다는 것( 계산이 많아짐 )

그들의 기댓값을 오차(ε)로 하고, 그 오차를 최소화시키는 방향으로 weight들을 업데이트

==한 번의 에포크에 모든 매개변수 업데이트를 단 한 번 수행

따라서 BGD 학습은 초기 W 값에 매우 큰 영향을 받는다. 즉, 신경망의 손실 함수는

매우 고차원임을 고려하면 Local mimimun (지역적 극소)에 빠질 수 있다.

단점

데이터가 100만개가 넘어가게 되면 BGD는 전체 데이터를 고려하므로 연산에 대한 Cost가 매우 커지게 된다.

전체 데이터를 고려해서 학습하므로 에포크당 시간이 오래 걸리며, 메모리를 크게 요구

https://www.researchgate.net/figure/Schematic-of-the-local-minima-problem-in-FWI-The-data-misfit-has-spurious-local-minima_fig1_267820876

W가 1지점에서 시작하면 Local minimum으로 수렴하지만,

2지점에서 시작하면 Global minimum으로 수렴하게 되는 것을 알 수 있다 

== 시간이 오래걸려도 global minimuu을 찾을 수 있다는 장점이 있다.

* SGD( Stochastic Gradient Descent ) 확률적 경사하강법 == BSD 보완

데이터가 1000개가 있을 때 각 데이터에 대하여 Loss function을 계산하고

==> 무작위로 뽑은 하나의 관측값 마다 기울기를 계산하고 바로 가중치 업데이트

BGD는 1000개의 데이터 모두를 고려한다고 하면, SGD는 1개의 데이터만 고려하는 것

매개변수 값을 조정 시 전체 데이터가 아니라 랜덤으로 선택한 하나의 데이터에 대해서만 계산 - 빠름

 

SGD 또한 초기 W에 민감하지만, 각각 데이터의 오차가 반영되기 때문에 global minimum 으로

갈 가능성이 BGD 보다 높다고 할 수 있다. 

단점

1개의 데이터를 이용하여 그라디언트를 계산하기 때문에,

계산 과정을 복잡해지지 않지만 Iteration 이 매우 커지게된다.

매개변수의 변경폭이 불안정

https://wikidocs.net/36033

GD vs SGD (출처 : https://seamless.tistory.com/38)

따라서 SGD는 수렴하지 못하고 이상한데서 왔다갔다 하는 문제가 발생할 수 있고,

수렴속도가 매우 느리다. (= 정확도가 낮을 수도 있다 )

* MGD( mini-batch Gradient Descent ) - SGD 보완

예를 들어서 10000개의 데이터가 존재하면 100개씩 미니 배치를 만들어서 ( batch_size )

각 100개씩 BGD 방식으로 가중치 업데이트

==정해진 양에 대해서만 계산하여 매개 변수의 값을 조정

전체 데이터를 계산하는 것보다 빠르며, SGD보다 안정적( 많이 사용함 )

단점

무작정 기울어진 방향으로 이동하는 방식이기 때문에 탐색 경로가 비효율적이다.


이제 여기서 더 효율적인 방법을 찾기 위해 두 가지를 생각해 볼 수 있다.

어느방향으로 갈지( Momentum )와 얼마나 큰 보폭(learning_rate)으로 갈지 설정 해줘야한다.

* Momentum

경사하강법 (Gradient Descent Method)의 문제점인 local minimum, plateau (평탄한 지점)에 빠지거나

수렴속도가 느리다는 단점을 해결하고자 나온 것이 모멘텀 (Momentum)

가중치가 이동하는 과정에서 일종의 '관성을 부여' = 가중치 업뎃 시 이전 단계의 업데이트 방향을 반영

http://www.yaldex.com  ​

Local Minimum 을 피할 수 있게 해주며, 이전 속도가 더 반영되므로 수렴속도도 빨라지게 된다.

(=  마치 언덕에서 공이 내려올 때, 중간에 작은 웅덩이에 빠지더라도 관성의 힘으로 넘어서는 효과 )

다시 말해 로컬 미니멈에 도달하였을 때, 기울기가 0이라서 기존의 경사 하강법이라면
이를 글로벌 미니멈으로 잘못 인식하여 계산이 끝났을 상황이라도 모멘텀.
즉, 관성의 힘을 빌리면 값이 조절되면서 로컬 미니멈에서 탈출하는 효과

단점

가중치 업뎃할때마다 과거에 이동했던 양을 변수별로 저장해야하므로

변수에 대한 메모리가 2배로 소모된다는 것

* Adagrad ( Adaptive Gradient ) learning_rate

매개변수들은 각자 의미하는 바가 다른데변수들을 업데이트할 때 각각의 변수마다

보폭을(learning_rate)를 다르게 설정해서 이동하는 방식

== 자주 등장했거나 변화를 많이 한 변수들은 그만큼 목적지에 가까이 있을 확률이 높기 때문에

     세세하게 조정을 하는 것이고, 그렇지 않은 변수들은 도달하기 위해 많이 변해야하므로 크게 조정하는 것

단점

학습을 너무 진행하면 학습의 정도가 낮아짐

(= 과거 기울기 값을 제곱해서 계속해서 더해가는 것이기 때문에)

== 점점 제곱값이 작아질 것이기 때문

* RMSProp = Adagrad 보완

상대적인 크기 차이를 유지하면서 이동하기 때문에 보폭이 너무 작아서 멈추는 것을 막는다.

즉 , 새로운 기울기의 정보만 반영 == 학습률이 0에 가까워지는 것을 방지

참조 https://dsbook.tistory.com/68

 

최적화, Optimizer

(JY) Loss function, 손실함수 (JY) Keras 사용해보기 1. What is keras? 케라스(Keras)는 텐서플로우 라이버러리 중 하나로, 딥러닝 모델 설계와 훈련을 위한 고수준 API이다. 사용자 친화적이고 모델의 구성이.

dsbook.tistory.com

* Adam ( Momentum + RMSProp ) 

제일 좋다고한다. 어찌 설명을 해야할지.. 간단하게 두 개를 합친 것이다.

그만큼 하이퍼파리미터도 많다. momentum에서 사용하는 계수와 학습률에 대한 계수가 사용된다.

기본적인 Network

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.utils import plot_model

model = Sequential()

model.add(Flatten(input_shape=(28, 28)))
# 28*28 = 784 특성 벡터로 펼쳐 변환해 Dense 층으로 들어갑니다
model.add(Dense(10, activation='softmax'))

model.compile(optimizer='adam' , loss='sparse_categorical_crossentropy' , metrics=['accuracy'])

model.summary()

# 가시화
plot_model(model, show_shapes=True)

# 모델 학습
model.fit(X_train, y_train, epochs=10, validation_data=(X_test,y_test))

# 예측
model.predict(X_test[0:1])

# 테스트 데이터 예측 정확도
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=2)

 

728x90

댓글