1 . Neural Network
앞에서 다루어왔던 퍼셉트론의 장점과 단점을 살펴보자. 우선 장점이라면 엄청 복잡한 함수도 쉽게 표현할 수 있다는 것이다.(예를 들면 앞에서 말했듯이 퍼셉트론으로만으로도 컴퓨터를 구현할 수 있다.). 하지만 반대로 단점이라면 우리가 앞에서 AND, NAND, OR, XOR게이트를 봤듯이 진리표를 보면서 가중치와 임계값에 대한 매개변수를 사람이 수동적으로 넣어주어야 한다는 한계점이 있다.
이러한 퍼셉트론의 단점은 신경망, 흔히 말하는 Neural Network를 사용하면 해결할 수 있다. 신경망을 이용하면 가중치에 대한 매개변수의 적정값을 입력데이터를 통해 자동으로 학습하게 할 수 있기 때문이다. 우선적으로 이번 포스팅에서는 입력데이터의 식별 처리과정을 다뤄볼 것이다.
신경망의 구조를 살펴보면 다음과 같다.
왼쪽부터 Input은 입력층, Hidden은 은닉층, Output은 출력층이다. 여기서 은닉층은 말그대로 은닉, 비가시적인 부분이다. 해당 그림을 보면 알겠지만 이러한 신경망은 기본적으로 3층신경망 구조를 띄우고 있다.(가중치를 갖는것이 Input -> Hidden, Hidden -> Output 총 두개뿐이라 2층 신경망이라고 정의하기도 한다.)
그렇다면 신경망에서 신호를 전달할때는 어떻게 전달할까? 앞의 퍼셉트론을 살펴보자. 퍼셉트론의 구조는 다음과 같았다.
이 퍼셉트론을 기준으로 보면 x1, x2, x3라는 입력이 각각의 해당 신호의 중요성을 나타내는 가중치 w1,w2,w3을 만나 곱해지고, 뉴련이 얼마나 쉽게 활성화 되는지를 판단하는 편향값 b 와 더해져 그 값이 0보다 크면 1을, 0보다 작거나 같으면 0을 출력하는 원리였다. 하지만 위의 신경망 같은 경우 편향값 b가 보이지 않는다. 이 b를 추가해서 구조를 그려보면 다음과 같이 그려진다.
해당 퍼셉트론에서 입력값이 1이고 가중치가 편향에 해당하는 b값인 뉴런 하나가 추가되었다. 이러한 퍼셉트론이 우리가 지금까지 흔히 봐왔던 x1w1 +x2w1+b의 기본적인 구조이다. 하나 명심해야할것은 편향값 b의 입력값은 고정적으로 1이다. 이 퍼셉트론도 마찬가지로 모든 뉴런의 가중치와 입력값의 곱의 합이 0을 넘으면 1을, 0보다 작거나 같으면 0을 출력한다.
우리가 앞에서 이러한 퍼셉트론의 식을 다음과 같이 작성하였다.
만약 여기서 출력이 0 혹은 1이 되는거의 판단을 하나의 함수로 나타낸다고 하면 어떻게 할까? 일반적으로 우리가 흔히 y = f(x)라는 식을 많이 쓴다. 만약 사진의 수식을 y = f(x)식으로 정리하면 어떻게 표현 할 수 있을까?
y = f(x)와 같은 형식으로 정리한다면 다음과 같이 정리할 수 있을것이다. x1w1 + x2w2 + b라는 기본적인 출력 판별식을 x로 두고 x가 0보다 작거나 같으면 0을, 0보다 크면 1을 출력하는 식이 된다. 여기서 보았던 f(x)와 같이 입력 신호 총합을 출력신호로 바꿔주는 함수를 활성화 함수라고 한다(Activation Function). 활성화 함수의 활성화의 의미는 입력신호의 총합이 해당 뉴런의 활성화를 일으키는지를 판별한다는 의미와 동일하다. 만약 이게 무슨말인지 이해가 안된다면 다음과 같이 생각하자. 0이 출력되게 되면 해당 신호가 흐르지 않고 해당 뉴런이 활성화 되지 않는거나 마찬가지이다. 반면 1이 출력되면 해당 신호가 흐르고 활성화 되는것과 같다. 즉 결과값이 0이 나올지, 1이 나올지에 따라 해당 뉴런의 활성화 여부가 나뉘는데 이러한 점을 판별해 주는 함수라 생각하면 된다.
활성화 함수가 사용된 흐름을 살펴보면 다음과 같다. 위에서 봤듯이 y = f(x)에서 입력값에 해당하는 x는 x1w1+x2w2+b, 즉 입력값에 해당하는 값이고 이 입력값 x는 활성화함수 f()를 만나 활성화 여부가 판별된 뒤 해당 결과값을 y에 전달하는것과 동일하다. 일반적으로 결과층에다 그냥 결과에 해당하는 y를 써놓지만 좀 더 자세한 흐름을 알려주기 위해서는 활성화 함수의 흐름까지 그려주기도 한다.
2 . Activation Function
활성화 함수는 임계값을 기준으로 출력값이 바뀌게 된다. 이렇게 임계값을 기준으로 값을 바꿔주는 함수를 계단함수(step function)이라고 한다.
이말은 즉슨 일반적인 퍼셉트론은 다양한 종류의 활성화 함수중 계단함수를 활성화 함수로서 선택해 사용하고 있다고 할 수 있고 결론적으로 퍼셉트론은 계단함수를 이용한다고 보면 된다.
여기서 말했듯 '다양한 종류의 활성화 함수' 라고 하였다. 즉 활성화 함수에는 계단 함수 외에도 다양한 종류가 존재한다는 것이다. 앞으로는 그 다양한 종류의 활성화 함수들을 살펴보려 한다.
2 - 1 . Sigmoid Function
우선적으로 가장 많은 사용빈도수를 지닌 시그모이드 함수(sigmoid function)부터 살펴보자. 시그모이드 함수의 기본 식은 다음과 같다.
여기서 e는 수학에서의 e, 자연상수와 동일한 의미이다. 여기서 sigmoid함수 또한 입력값을 받아 신호를 변환하여 변환 신호를 다음 뉴런으로 전달하는 역할을 한다. 즉 퍼셉트론과 동일한 역할을 하지만 활성화 함수 부분만 다른것이다. 차이점을 코드와 그래프로 한번 살펴보자. 우선적으로 기본적인 퍼셉트론에서 사용하는 임계값에 따른 결과값을 출력하는 계단함수부터 살펴보자.
(1) 계단함수
다음과 같이 계단 함수를 나타내었다 하자. 해당 함수는 일반적인 계단함수와 동일히 임계값을 0으로 해주고 0보다 크면 1을, 작으면 0을 반환하는 구조이다. 하지만 여기서 문제점이 있다. 함수의 인자로서는 np.array형식을 넣지 못한다는 것이다.
다음과 같이 일반적인 부동소수점을 넣는것은 가능하지만 np.array()형태의 자료형은 넣어줄 수 없다. 우리가 np.array를 고려하는 이유는 그래프를 그릴때 앞에서 보았지만 y 값에 대한 연산을 위해 x값을 np.arange를 통해 일정범위의 넘파이 배열을 값으로 넣어주어야 하므로 이 점까지 고려해 주어야 하는 것이다.
그렇다면 np.array()형태의값이 들어갈 수 있도록 고쳐주자.
함수를 다음과 같이 고쳐주면 된다. 해당 함수의 유도과정을 살펴보자.
우선적으로 값을 위의 사진대로 np.array([1.0,2.0,-5.0])을 넣어주었다 하자. y = x > 0이라는 식에서 우선적으로 y에는 array([True,True,False])라는 값이 저장이 될것이다.
그 후 return 전에 y.astype(np.int)를 살펴보자. astype()메서드는 넘파이 배열의 자료형을 바꿔줄 때 사용한다. .astype메서드의 인자로는 자신이 바꿔주고자 하는 자료형을 작성해 주면 된다(np.(자료형)). 그 후 자료형을 변환한 값을 반환하면 array([1,1,0])을 반환하는것을 볼 수 있다. 그 이유는 파이썬에서는 기본적으로 Boolean자료형에 대해 True의 값일때는 1을, False일때는 0을 출력하기 때문이다.
해당 함수를 가지고 그래프를 그려보자.
위에서 작성해 보았던 함수를 이용하여 계단함수의 그래프를 그려보았다.
우선적으로 numpy모듈과 그래프를 작성하므로 matplotlib라이브러리를 import해준다. 그 후 np.array()자료형을 통해 임계값 0을 기준으로 출력값을 판별해주는 함수(func2)를 선언해준다.
우선 x부터 보자. x는 -6부터 6전까지의 범위 안에서 0.1 간격으로 넘파이 배열을 생성한다. 즉 [-6.0,-4.9~~~5.9]라는 값을 가진 배열이 생성되는것이다. 그 후 y는 해당 값에 대해 위에 선언한 계단함수 func2에 해당 x값을 넣어 연산된 값을 받은 후 .plot 메서드를 이용해 그래프를 구현하고 기본적으로 범위를 생성하지 않게되면 y축의 범위는 0~1이다. 하지만 우리가 결론적으로 계단함수를 통해 얻는 값 또한 1, 0이기 때문에 겹쳐서 보이므로 겹쳐 보이는 부분을 없애주기위해 y축 범위를 .ylim메서드를 통해서 지정해주고 .show메서드로 그래프를 출력한다.
그래프를 보면 모양이 계단형식이므로 우리가 흔히 계단함수라고 부르는 것이다.
(2) Sigmoid함수
앞에서 시그모이드 함수의 기본적인 수식을 다음과 같이 표현하였다.
이 식에서 e를 다른 수식기호로 표현하면 exp라는 기호로 표현할 수 있다. 넘파이에는 이 자연상수에 대한 값을 np.exp라는 넘파이 메서드로 출력할 수 있도록 해준다. 그렇다면 앞에서 응용했던것과 동일하게 sigmoid함수의 코드를 작성해 보자.
해당 코드에서도 동일히 numpy, matplotlib 모듈을 impot 해준다. 그 후 sigmoid함수를 구현해 보자. 우선적으로 sigmoid의 기본적인 수식은 1/(1+e의 -x승) 이었다. 앞서 말했듯이 자연상수 e는 넘파이의 메서드 중 자연상수 연산자인 exp로 np.exp()와 같이 코드를 통해 연산해 줄 수 있다. 그렇기에 이를 그대로 코드로 작성해 주면 x라는 매개변수가 들어왔을때 그 값을 수식 그대로 반환해주면 된다. 즉 return 1/(1+np.exp(-x)) 로 작성해 줄 수 있는것이다.
x값을 np.arange(-6,6,0.1) 를 통해 x값을 [-6~5.9] 범위의 넘파이 배열을 생성해주고 y에서는 넘파이 배열 x를 앞에서 선언한 sigmoid()라는 함수의 인자로 넣어주어서 값을 저장한다. 자 여기서 np.exp()함수를 한번 더 살펴보자. 인자로서 들어오는것은 [-6~5.9] 하나의 배열형태로 값을 받는다. 여기서 자연상수 연산을 해준다는것은 배열 안의 모든 값들 각각에 대한 연산을 해준다는 의미인데, 이는 즉 앞에서 보았던 브로드캐스트 기능이 사용되었음을 알 수 있다(복습).
그 후 과정은 앞에서 보았던 계단함수와 가능하게 .plot()메서드 안에 x, y축 값들을 인자로 넣어 그래프화를 시키고, .show를 통해 출력하면 된다.
(3) sigmoid와 계단함수 비교
그렇다면 sigmoid함수와 계단 함수의 큰 차이점과 공통점은 무엇일까? 우선 앞의 matplotlib에 대한 연습에서 보았던것처럼 두 함수를 비교하는 코드를 작성해 보자.
우선적으로 공통점부터 살펴보자. 공통점은 우선 입력이 작으면 출력이 거의 0에 가까워지고 커지면 거의 1에 가까워지는 구조이다. 또한 두 함수 모두 중요한 입력값이면 큰값을, 중요하지 않은 값이라면 작은값을 출력하는것 또한 비슷하며, 이 두 함수 모두 아무리 입력값이 크더라도 출력은 0~1사이에서만 출력된다.
반대로 차이점을 보자면, 우선적으로 결과값에 대한 유동성이다. sigmoid함수의 출력값은 곡선모양의 그래프에, 입력값에 따른 출력값이 연속적으로 변화한다. 반면 계단함수는 결론적인 값은 0 혹은 1밖에 없는 다소 결과값이 유동성이 떨어진다.
이러한 차이점을 통해 하나 짚고 넘어갈 것은, 일반적인 퍼셉트론에서는 임계점을 기준으로 출력값을 0 혹은 1로 두기 떄문에 결론적으로 계단함수를 활성화 함수로서 채택해서 사용한다. 그와 반대로 신경망은 중요한것은 입력값으로 가장 적절한 가중치 매개변수의 값을 학습해 주어야 하기에 입력해준 값마다 최적화된 값이 모두 다를 수 밖에 없다. 그렇기에 값의 유동성에 좋은 sigmoid함수같은 함수를 활성화 함수로 많이 사용하는 것이다.
결론적으로 퍼셉트론에서는 0 혹은 1 이 두가지의 신호만 뉴런 사이에 흘렀다면 신경망에서는 연속적인 값이 흐른다는것이다.
2 - 2 . 비선형 함수
앞에서 계단함수와 sigmoid함수에대한 공통점을 살펴보았다. 중요도에 따라 중요하면 큰값을 중요도가 적으면 작은 값을 출력하고 결론적으로 0과 1 사이의 값에서 출력값이 나오는것을 알 수 있었다. 하지만 하나의 공통점이 더 있다. 두 함수 모두 비선형 함수라는 것이다. 비선형 함수는 앞에서도 다루었지만 XOR게이트와 같이 직선 하나로만 그릴 수 없는 함수를 의미한다. 선형함수를 일컫는것은 간단히 말하면 출력값이 입력값의 상수배만큼 변하는 함수를 의미한다. 예를들면 y = ax 와 같은 함수가 될 수 있다. 반대로 비선형 함수란 선 한개로 나타낼 수 없는 함수를 의미한다.
신경망에서는 활성화함수가 꼭 비선형 함수어야 하는데 그 이유는 은닉층을 쓰는것과 같이 네트워크 자체의 깊이를 늘리는것에 대해 의미를 찾기 위해서이다. 앞서 예시로 든 선형함수 y = ax를 보자. y = ax라는 활성화함수를 층이 4개인 네트워크(여기서 활성화 함수는 당연히 3개가 존재하겠죠?)에 사용하게 되면 y = a*a*a*x 가 되게 되는데 이는 은닉층 없이도 나타낼 수 있는 값이다. 즉 이러한 선형함수는 층의 깊이에 대한 이점을 살리는것이 불가능하다.
3 . ReLU Fuction
sigmoid함수 외 ReLU라는 활성화 함수 한가지를 더 보자. ReLU함수 또한 sigmoid함수와 마찬가지로 많이 쓰이는 활성화 함수 중 하나이다.
ReLU함수의 특징은 입력값이 0보다 크면 입력값 그대로 내보내고, 0보다 작으면 0을 출력하는 함수이다.
ReLU활성화 함수를 코드로 작성하면 다음과 같다.
ReLU함수를 구현할 때는 np.maximum()이라는 함수를 이용했는데 해당 넘파이의 maximum함수는 두개의 인자중 더 큰값을 출력하는 역할을 한다. 밑의 출력값을 보면 0보다 큰 4를 넣으면 그대로 4를, 0보다 작은 -3을 넣으면 0을 출력하는것을 볼 수 있다.
ReLU활성화 함수를 그래프로 나타내면 다음과 같다.
'Machine Learning &DeepLearning > Machine Learning Base Theory' 카테고리의 다른 글
Machine Learning with Python #2 (0) | 2019.01.14 |
---|---|
Machine Learning with Python #1 (0) | 2019.01.13 |