본문 바로가기

NLP(자연어처리)

[파이썬으로 배우는 자연어 처리 인 액션] Chapter5. 신경망 첫걸음: 퍼셉트론과 역전파 Review

이 포스트는 '파이썬으로 배우는 자연어 처리 인 액션' 책의 Chapter 5 내용에 기반하여, 신경망, 퍼셉트론과 역전파에 대한 정리와 공부 기록을 담고 있습니다.
http://www.yes24.com/Product/Goods/89232661

파이썬으로 배우는 자연어 처리 인 액션 - YES24

파이썬과 다양한 AI 패키지로 만드는 수준 높은 예제최신 NLP 제품과 서비스 개발을 위한 실용주의적 안내서최근 심층 학습(딥러닝) 기술이 발전하면서 응용 프로그램들이 대단히 정확하게 텍스

www.yes24.com

🔻Chapter 5에서 다루는 내용

  • 신경망의 역사
  • 뉴런과 퍼셉트론
  • 역전파
  • 신경망을 제어하는 매개변수들
  • 케라스를 이용한 기본적인 신경망 구현

Chapter 5에서는 신경망(neural network), 좀 더 정확히는 인공신경망을 전혀 모르는 독자를 위해 기초적인 신경망에 대한 내용을 담고 있습니다.

목차

5.1 신경망의 구성요소
5.1.1 퍼셉트론
5.1.2 디지털 퍼셉트론
5.1.3 치우침 단위
5.1.4 오차 곡면을 누비며
5.1.5 경사로를 따라 활강
5.1.6 흔들어서 탈출
5.1.7 케라스: 신경망 파이썬 구현

5.1 신경망의 구성요소

퍼셉트론은 생명체의 뉴런세포가 작동하는 방식을 컴퓨터로 흉내내는 것입니다. 퍼셉트론은 두 개의 노드가 있을 경우, 그 두 개의 노드가 각각 들어가야 하는 위치인 입력치와 그를 가중하는 가중치, 이를 통해 계산하여 나온 결과인 출력 값으로 구성되어 있습니다. 가중치와 입력치를 곱한 것을 모두 합한 값이 활성함수에 의해 판단되는데, 그 값이 임계치(threshold)보다 크면 뉴런(혹은 내부 함수)이 활성화되고 결과값으로 1을 출력한다. 이를 통해 값이 0 또는 1로 결정된다. 이렇게 나온 값을 출력 값이라고 하며, 이 과정을 통틀어 퍼셉트론이라고 부릅니다.
출처: https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%85%89%ED%8A%B8%EB%A1%A0

퍼셉트론 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 퍼셉트론(perceptron)은 인공신경망의 한 종류로서, 1957년에 코넬 항공 연구소(Cornell Aeronautical Lab)의 프랑크 로젠블라트 (Frank Rosenblatt)에 의해 고안되었다. 이것은

ko.wikipedia.org

전기 신호가 수상돌기(dendrite)들을 통해서 뉴런 세포에 전달되면서 세포핵에 전하가 축적됩니다. 전하가 특정 수준 이상이 되면, 뉴런세포가 발화(firing)하며, 그러면 전기신호가 축삭돌기(axon)를 통해서 이웃 뉴런 세포에 전달된다고 합니다. 중요한 것은, 뉴런 세포의 발화 여부가 뉴런 세포에 들어온 전기신호의 총량에 의존하며, 각 수상돌기를 통해 들어오는 전기신호의 세기는 그 수상돌기에 부여된 가중치에 비례한다는 가정입니다.


5.1.1 퍼셉트론

퍼셉트론은 주어진 이미지가 특정 부류의 이미지인지 아닌지를 아래와 같이 판단합니다.(로젠블랫의 실험)
이미지에서 특징들(이미지의 작은 영역) 각각에 일종의 중요도로서의 가중치를 부여되어 있고, 모든 가변 저항이 전달한 신호들의 세기가 특정 임계치(threshold)를 넘기면 퍼셉트론 자체가 '발화'해서 축삭도릭를 통해 전기 신호를 외부로 전달합니다.

발화 : 주어진 이미지가 퍼셉트론이 기대하던 이미지에 부합함
발화 x: 주어진 이미지가 기대하던 이미지에 부합하지 않음

5.1.2 디지털 퍼셉트론

신경망을 사용한다는 것은 어떤 자료 집합의 한 견본(example)을 신경말 알고리즘에 입력해서 알고리즘이 그 견본에 관해 어떤 값을 산출하는지 보는 것입니다. 신경망을 활용하려면, 하나의 견본(example)이 어떠 특징(feature)들로 구성되는지를 사람이 결정해야 합니다.
각 특징($x_{i}$)과 해당 가중치($w_{i}$)의 곱을 모두 합한 것이 퍼셉트론에 들어오는 입력값으로, 곧 견본 벡터와 가중치 벡터들의 일차결합입니다.

견본은 특징들의 벡터

뉴런이 발화(1 출력)하는 것을 결정하는 함수를 활성화 함수(activation function)라고 부르고, 문턱값에 기초한 활성화 함수로는 계단함수(step function)이 있습니다.


5.1.3 bias unit (치우침 단위)

bias unit 을 두는 이유는 모든 특징(성분)이 0인 입력(영벡터)에 대해 뉴런이 안정적으로 작동하게 하기 위한 것입니다. 입력 영벡터에 대해 0을 출력하도록 신경망을 훈련해야 하는 경우도 있겠지만, 그렇지 않을 경우, bias unit이 없으면 출력값을 0을 출력하게 될 것입니다.(0 x 가중치 = 0) bias unit은 이 문제를 해결해주고, 실제로 0을 출력해야 하는 경우에도, 적절한 자료로 훈련시키면, bias unit에 대한 가중치가 감소해서, 내적이 threshold보 다 작게 하여 0이 출력되게끔 만들 수 있다고 합니다. 이렇게 가중치를 훈련시킴으로써 제대로 설정하는 과정을 신경망의 학습이라고 부릅니다.

파이썬의 뉴런
Numpy dot 함수를 이용해서 두 벡터(input, wieght)의 내적을 구한 후, bias를 더하는 과정입니다.

import numpy as np
example_input = [1, .2, .1, .05, .2]
example_weights = [.2, .12, .4, .6, .9]

input_vector = np.array(example_input)
weights = np.array(example_weights)
bias_weight = .2

activation_level = np.dot(input_vector, weights)+bias_weight*1
activation_level
0.6740000000000002

뉴런 출력 결과 값으로 약 0.674가 나왔고, 아래는 threshold(임계치)를 0.5로 설정하여 문턱값 활성화함수를 표현한 것입니다.

threshold = 0.5
if activation_level >=threshold:
  perceptron_output = 1
else:
  perceptron_output = 0
perceptron_output
1

0.674>0.5이므로 결과값은 1이 나온 것을 확인할 수 있습니다.

퍼셉트론의 훈련
신경망의 핵심은 가중치들을 신경망이 스스로 학습하게 하는 것입니다. 즉, 주어진 sample의 예측 결과에 기초해서 가중치들을 바람직한 값 (true value) 쪽으로 슬쩍 밀어옮기는 수단이 필요합니다. 퍼셉트론은 주어진 입력에 대한 추측이 맞았는지 틀렸는지에 대한 함수에 기초해서 가중치들을 증가하거나 감소함으로써 학습합니다. 출력의 오차가 점차 0으로 수렴하게 되면 시스템은 학습을 마칩니다. (학습을 마치는 오차의 임계치를 설정할 수 O)

example_output sample에 대해 뉴런이 0을 출력해야 한다고 가정할 때, 다음은 0(true value)에 가깝게 가중치들을 갱신하는 코드입니다.

expected_output = 0
new_weights = []
for i, x in enumerate(example_input):
  new_weights.append(weights[i]+(expected_output-perceptron_output)*x)
weights = np.array(new_weights)
example_weights
[0.2, 0.12, 0.4, 0.6, 0.9]
weights
array([-0.8 , -0.08,  0.3 ,  0.55,  0.7 ])


컴퓨터에게 논리 가르치기
아례 예시는 간단한 장난감 문제로, label이 붙은 sample들만으로 컴퓨터에게 어떤 개념을 가르친다는 것인지를 잘 보여주는 예제 입니다.

sample_data = [[0,0], #거짓, 거짓
               [0,1], #거짓, 참
               [1,0], #참, 거짓
               [1,1]] #참, 참
expected_results = [0,#거짓
                    1,#참
                    1,#참
                    1]#참
activation_threshold = 0.5
#무작위 가중치 초기화값 설정
from random import random
weights = np.random.random(2)/1000 #0보다 크고, 0.001보다 작은 무작위 부동소수점
weights
array([0.00016068, 0.0009587 ])
#무작위 bias 가중치 설정
bias_weight = np.random.random()/1000
bias_weight
6.8364485814401685e-06
#퍼셉트론 무작위 추측
for idx, sample in enumerate(sample_data):
  input_vector = np.array(sample)
  activation_level = np.dot(input_vector, weights)+bias_weight
  if activation_level>activation_threshold:
    perceptron_output = 1
  else:
    perceptron_output = 0
  print('Predicted: {}'.format(perceptron_output))
  print('Exepected: {}'.format(expected_results[idx]))
  print()

결과

Predicted: 0
Exepected: 0

Predicted: 0
Exepected: 1

Predicted: 0
Exepected: 1

Predicted: 0
Exepected: 1
#퍼셉트론 학습
for iteration_num in range(5):
  correct_answers = 0
  for idx, sample in enumerate(sample_data):
    input_vector = np.array(sample)
    weights = np.array(weights)
    activation_level = np.dot(input_vector, weights)+ (bias_weight*1)
    if activation_level>activation_threshold:
      perceptron_output = 1
    else:
      perceptron_output = 0
    if perceptron_output == expected_results[idx]:
      correct_answers +=1
    new_weights = []
    for i, x in enumerate(sample):
      new_weights.append(weights[i]+(expected_results[idx]-perceptron_output)*x)
    bias_weight = bias_weight + ((expected_results[idx]-perceptron_output)*1)
    weights = np.array(new_weights)
  print('{} correct answers out of 4, for iteration {}'.format(correct_answers, iteration_num))

결과

3 correct answers out of 4, for iteration 0
2 correct answers out of 4, for iteration 1
3 correct answers out of 4, for iteration 2
4 correct answers out of 4, for iteration 3
4 correct answers out of 4, for iteration 4

4번째 반복만에 컴퓨터가 논리합을 완전히 터득했고 sample에 대한 오차가 0이므로(수렴), 갱신과정을 반복해도 가중치들이 더 개선되지는 않습니다.

업데이트 된 가중치

weights
array([1.00016068, 1.0009587 ])


퍼셉트론의 본질적인 결함(선형성 만족)

기본적인 퍼셉트론에는 본질적인 결함이 있습니다. 만약, 서로 다른 부류의 자료점들을 직선(선형)으로 분리할 수 없으면, 모형은 절대로 수렴하지 않습니다. 즉, 모형은 최적의 가중치들을 배우지 못하게 되고, 목표변수를 정확하게 예측할 수 없습니다. 이처럼 직선으로 부류를 가르지 못하면, 단일뉴런 퍼셉트론은 최적의 해에 도달하지 못하고, 가중치 공간을 계속 방황하게 되고, 결과적으로 동전을 던지는 것과 같은 무작위 추측보다 나은 성과를 낼 수 없습니다.

최솟값과 극솟값
퍼셉트론 모형이 수렴했다는 것은 잘와 목표변수 사이의 관계를 서술하는 하나의 직선 방정식을 찾았다는 뜻입니다. 그런데 퍼셉트론이 수렴했다고 해서, 그 직선 방정식이 반드시 최선의 분리 직선이라는, 다른 말로 하면 비용이 '최소'라는 보장은 없습니다. 초기 가중치들에서 출발해서 찾아낸 최선의 해는 최솟값이 아닌 하나의 극솟값에 해당합니다.

Backpropagation(역전파)
다수의 퍼셉트론을 함께 사용한다면 선형 부리 가능이 아닌 문제도 풀 수 있음을, 즉, 비선형 함수들도 선형 함수들처럼 퍼셉트론들로 근사할 수 있다고 합니다. 그런데 하나가 아니라 여러 개의 퍼셉트론의 가중치들을 어떻게 갱신해야 할지, 오차를 가중치들에 배분한다는 것은 무슨 뜻인지 의문이 생길 것 입니다.

두 퍼셉트론을 직렬로 연결해서 한 퍼셉트론의 출력이 다른 퍼셉트론에 입력되게 하면 흥미로운 일이 생깁니다. 역전파는 단일 퍼셉트론의 한계를 극복하는 데 도움을 주지만, 역전파를 활용하려면 퍼셉트론의 구조를 좀 더 조율해야 합니다. 다중 퍼셉트론에서 가중치들은 그것이 전체 오차에 얼마나 기여하느냐에 기초해서 갱신됩니다. 그런데 한 퍼셉트론의 출력이 다른 퍼셉트론의 입력이 되면, 둘째 퍼셉트론의 관점에서 보는 오차의 정의가 명확하지 않습니다.
이 문제를 해결하려면, 한 층의 한 가중치가 오차에 기여하는 정도를 그 다음층에 있는 다른 가중치들에 근거해서 계산하는 방법이 필요합니다. 그리고 그것이 바로 역전파입니다.

Backpropagation은 신경망의 입력과 출력(예측값), 그리고 목푯값(true value)이 주어졌을 때 특정 가중치의 적절한 변화량(갱신량)을 구하는 알고리즘입니다. 이에 반해, Forwardpropagation(순전파)은 입력이 신경망을 따라 '앞으로', 즉 순방향으로 나아가서 결국에는 신경망의 출력이 계산되는 것니다.

Backpropgation을 수행하기 위해서는 비선형 연속 미분가능(continuously differentiable)함수를 활성화 함수로 사용해야 합니다.

활성화 함수가 비선형이어야 하는 이유는?, S자형 함수

활성화 함수가 비선형이어야만, 신경망이 특징벡터와 목표변수 사이의 비선형관계를 배울 수 있기 때문입니다. 비선형 함수를 사용하면 신경망이 비선형관계를 모형화할 수 있겠지만, 그렇다고 아무 비선형 함수나 사용해도 좋은 것은 아닙니다. S자형 함수 같은 연속 미분가능 비선형 함수를 사용하면 여러 층의 뉴런들을 통해서 오차가 매끄럽게 역전파되므로 훈련과정이 좀 더 빨라진다고 합니다.


Backpropagation 주의점

  • 가중치(weight) 갱신 시기

Backpropagation을 할때, 각 가중치의 변화량을 계산하되, 그것으로 가중치를 실제로 갱신하면 안 됩니다. Backpropagation을 함으로써 신경망의 시작 부분까지 도달한 후에야 갱신해야 합니다. 그렇게 하지 않고, 그때그때 가중치를 갱신하면 신경망 앞쪽으로 갈수록 미분들이 부정확해져서 가중치 변화량도 틀리게 나옵니다.

  • Learning rate(학습 속도)

Learning rate가 너무 크면 가중치가 너무 크게 변해서 최적해를 건너뛰고, Learning rate가 너무 작으면 수렴에 도달하는 시간이 비현실적으로 길어질 수 있습니다. 그보다도 심각한 일은 오차곡면의 극소점을 벗어나지 못하는 것입니다.

5.1.4 오차 곡면을 누비며

신경망 훈련의 목표는 비용함수가 최소가 되는 최적의 매개변수(가중치)들을 구하는 것입니다.

두 가중치를 두 차원으로 두고, 그에 해당하는 오차를 세번째 차원(높이)으로 두어서 하나의 3차원 곡면을 표현한 것입니다.

5.1.5 경사로를 따라 활강

오차곡면과 다르게 비볼록 오차곡면의 경우, 활강을 어디서 시작하느냐에 따라서 구덩이에 빠져서 진짜 최소점에 도달하지 못하고 극소점에서 활강을 마치게 될 수 있습니다.(훈련 업데이트를 마치게 됩니다.)

5.1.6 흔들어서 탈출

다수의 훈련 견본에 대해 오차를 측정해서 가중치를 갱신하는 방식을 배치 훈련 방식이라고 부릅니다. 배치(batch)는 한 번의 훈련 주기에 사용하는 자료점들의 집합으로, 많은 경우 전체 훈련 자료의 한 부분집합입니다 .하나의 배치에 대한 오차 곡면은 일정하며, 배치가 달라지면 오차곡면도 달라집니다. 무작위로 초기화한 가중치들은 그 오차 곡면의 한 지점을 정의하는데, 그 지점에서 기울기를 따라 아래쪽으로 하강하다 보면 극소점에 해당하는 구덩이에 빠질 수 있습니다. 그러면 비용함수를 최소화할 수 없게 되는 것으로 최적의 weight를 찾을 수 없게 됩니다. 이러한 문제를 해결하는 방법은 크게 두 가지가 있습니다.

1. 확률적 경사 하강법(Stochastic Gradient Decent, SGD)
확률적 경사하강법은 모든 훈련 견본을 처리한 후 기울기들을 갱신하는 대신 각각의 훈련 견본에 대해 가중치들을 갱신합니다. 또한, 훈련 견본들의 순서를 매번 무작위로(확률적으로) 뒤섞습니다. 주어진 견본(sample)하나에 대해 그런 갱신을 수행합니다. 즉, 한 훈련 주기 끝에서 모든 오차를 취합한 후 일괄적으로 가중치들을 갱신하는 것이 아니라, 개별 견본의 출력과 오차를 구할 때 마다 가중치들을 갱신하는 것입니다. 하지만 이방식의 단점은 느리다는 것입니다.(견본마다 순전파와 역전파를 반복하기 때문)

2. 미니배치(mini-batch)
미니배치 훈련 방식에서는 훈련 집합 전체 또는 앞에서 말한 배치를 더 작은 부분집합들로 나눕니다. 이 방법은 배치 훈련의 장점인 속도와 확률적 경사 하강법의 장점인 안정성(극소점 극복)을 모두 갖추었습니다.

요약

  • 학습은 비용함수를 최소화하는 방향으로 일어난다.
  • 신경망 학습의 비결은 역전파 알고리즘이다.
  • 가중치가 모형의 오차에 기여하는 정도는 학습을 위해 가중치를 변화하는 정도와 직접 연관된다.
  • 신경망은 본질적으로 하나의 최적화 엔진이다.
  • 훈련 시에는 오차 곡면상의 구덩이(극소점)를 조심해야 한다. 오차가 꾸준히 줄어들지 않는다면 뭔가 문제가 있는 것이다.
  • 케라스는 신경망을 위한 수학 연산을 좀 더 손쉽게 사용할 수 있게 해주는 편리한 라이브러리이다.