Fundamental 26
Fundamental 26 활성화 함수의 이해
활성화 함수
우리가 지금까지 써왔던 신경망 속의 퍼셉트론 혹은 노드도 특정 조건이 만족하면 활성화 되도록 디자인 되어 있다. 노드에 입역으로 들어오는 값이 어떤 임계치를 넘어가면 활성화되고 넘어가지 않으면 비활성화 되게끔코딩되어있다.
ReLU는 입력 값이 음수라면, 즉 0 미만이라는 조건을 만족한다면 0을 출력하고, 입력값이 0이상이면 입력값 그대로 출력한다. 따라서 ReLU함수한 0 미만인 경우는 비활성화가 되고 0 이상인 경우는 활성화되는 함수라고 말할 수 있다.
시그모이드는 ReLU처럼 명확하고 간단하게 글로 표현하긴 힘들지만, 입려값이 -inf로 갈수록 0을 출력하고 +inf로 갈수록 1을 출력하며, 0일때는 1/2을 출력하는 함수이다.

딥러닝에서 활서화 함수를 쓰는 결정적인 이유는 딥러닝 모델의 표현력을 향상시켜주기 위해서이다. 전문적인 용어로는 모델의 representation capacity또는 expressicity를 향상시킨다라고도 말한다.
퍼셉트론
퍼셉트론의 정의
퍼셉트론이란?
학습시킬 머신 자체를 동물의 신경세포와 유사하게 설계해 나오게 된 것
퍼셉트론의 구조


활성화 함수
활성화함수는 들어온 신호가 특정 입게점을 넘으면 출력을 하고, 넘지 못하면 무시한다. 또한 신호를 전달해주기 때문에 Transfer function으로도 알려져 있다.
종류
- 선형 활성화 함수 (Linear activation function)
- 비선형 활성화 함수 (Non-linear activation function)
선형과 비선형
선형(Linear)
선형 변환이란?
선형이라는 규칙을 지키며 V공간상의 벡터를 W공간상의 벡터로 바꿔주는 역할

비선형(Non-linear)
비선형 함수를 쓰는 이유: 딥러닝 모델의 표현력을 향상시키기위해



비선형 함수를 쓰는 이유
- 선형 활성화 함수흫 사용한다면, 노드의 개수를 아무리 많이 붙여도 결국 하나의 노드를 사용하는 것돠 차이가 없다.
- 다시말해 선형 활성화함수를 사용한다면, 모델의 표현력이 떨어지게 된다.
선형변환

비선형변환

활성화 함수의 종류
활성화 함수는 크게 3가지 종류의 함수로 나눌 수 있다.
- 이진 계단 함수(Binary step function)
- 선형 활성화 함수 (Linear activation fuction)
- 비선형 활성화 함수 (Non-linear activation function)
이진 계단 함수
- 입력이 특정 임계점을 넘으면 1를 출력하고 그렇지 않을 때는 0을 출력한다.

def binary_step(x, threshold=0):
# threshold가 있는 함수를 쓰면 꼭 defualt 값을 설정해주세요
return 0 if x<threshold else 1
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
def plot_and_visulize(image_url, function, derivative=False):
X = [-10 + x/100 for x in range(2000)]
y = [function(y) for y in X]
plt.figure(figsize=(12,12))
# 함수 그래프
plt.subplot(3,2,1)
plt.title('function')
plt.plot(X,y)
# 함수의 미분 그래프
plt.subplot(3,2,2)
plt.title('derivative')
if derivative:
dev_y = [derivative(y) for y in X]
plt.plot(X,dev_y)
# 무작위 샘플들 분포
samples = np.random.rand(1000)
samples -= np.mean(samples)
plt.subplot(3,2,3)
plt.title('samples')
plt.hist(samples,100)
# 활성화 함수를 통과한 샘플들 분포
act_values = [function(y) for y in samples]
plt.subplot(3,2,4)
plt.title('activation values')
plt.hist(act_values,100)
# 원본 이미지
image = np.array(Image.open(image_url), dtype=np.float64)[:,:,0]/255. # 구분을 위해 gray-scale해서 확인
image -= np.median(image)
plt.subplot(3,2,5)
plt.title('origin image')
plt.imshow(image, cmap='gray')
# 활성화 함수를 통과한 이미지
activation_image = np.zeros(image.shape)
h, w = image.shape
for i in range(w):
for j in range(h):
activation_image[j][i] += function(image[j][i])
plt.subplot(3,2,6)
plt.title('activation results')
plt.imshow(activation_image, cmap='gray')
return plt
import os
img_path = os.getenv('HOME')+'/aiffel/activation/jindo_dog.jpg'
ax = plot_and_visulize(img_path, binary_step)
ax.show()

퍼셉트론
# 퍼셉트론
class Perceptron(object):
def __init__(self, input_size, activation_ftn, threshold=0, learning_rate=0.01):
self.weights = np.random.randn(input_size)
self.bias = np.random.randn(1)
self.activation_ftn = np.vectorize(activation_ftn)
self.learning_rate = learning_rate
self.threshold = threshold
def train(self, training_inputs, labels, epochs=100, verbose=1):
'''
verbose : 1-매 에포크 결과 출력,
0-마지막 결과만 출력
'''
for epoch in range(epochs):
for inputs, label in zip(training_inputs, labels):
prediction = self.__call__(inputs)
self.weights += self.learning_rate * (label - prediction) * inputs
self.bias += self.learning_rate * (label - prediction)
if verbose == 1:
pred = self.__call__(training_inputs)
accuracy = np.sum(pred==labels)/len(pred)
print(f'{epoch}th epoch, accuracy : {accuracy}')
if verbose == 0:
pred = self.__call__(training_inputs)
accuracy = np.sum(pred==labels)/len(pred)
print(f'{epoch}th epoch, accuracy : {accuracy}')
def get_weights(self):
return self.weights, self.bias
def __call__(self, inputs):
summation = np.dot(inputs, self.weights) + self.bias
return self.activation_ftn(summation, self.threshold)
def scatter_plot(plt, X, y, threshold = 0, three_d=False):
ax = plt
if not three_d:
area1 = np.ma.masked_where(y <= threshold, y)
area2 = np.ma.masked_where(y > threshold, y+1)
ax.scatter(X[:,0], X[:,1], s = area1*10, label='True')
ax.scatter(X[:,0], X[:,1], s = area2*10, label='False')
ax.legend()
else:
area1 = np.ma.masked_where(y <= threshold, y)
area2 = np.ma.masked_where(y > threshold, y+1)
ax.scatter(X[:,0], X[:,1], y-threshold, s = area1, label='True')
ax.scatter(X[:,0], X[:,1], y-threshold, s = area2, label='False')
ax.scatter(X[:,0], X[:,1], 0, s = 0.05, label='zero', c='gray')
ax.legend()
return ax
# AND gate, OR gate
X = np.array([[0,0], [1,0], [0,1], [1,1]])
plt.figure(figsize=(10,5))
# OR gate
or_y = np.array([x1 | x2 for x1,x2 in X])
ax1 = plt.subplot(1,2,1)
ax1.set_title('OR gate ' + str(or_y))
ax1 = scatter_plot(ax1, X, or_y)
# AND gate
and_y = np.array([x1 & x2 for x1,x2 in X])
ax2 = plt.subplot(1,2,2)
ax2.set_title('AND gate ' + str(and_y))
ax2 = scatter_plot(ax2, X, and_y)
plt.show()

AND, OR gate
# OR gate
or_p = Perceptron(input_size=2, activation_ftn=binary_step)
or_p.train(X, or_y, epochs=1000, verbose=0)
print(or_p.get_weights()) # 가중치와 편향값은 훈련마다 달라질 수 있습니다.
# AND gate
and_p = Perceptron(input_size=2, activation_ftn=binary_step)
and_p.train(X, and_y, epochs=1000, verbose=0)
print(and_p.get_weights()) # 가중치와 편향값은 훈련마다 달라질 수 있습니다.
'''
999th epoch, accuracy : 1.0
(array([0.58153805, 0.38941101]), array([-0.0018244]))
999th epoch, accuracy : 1.0
(array([0.10201569, 0.02235862]), array([-0.11932287]))
'''
from itertools import product
# 그래프로 그려보기
test_X = np.array([[x/100,y/100] for (x,y) in product(range(101),range(101))])
pred_or_y = or_p(test_X)
pred_and_y = and_p(test_X)
plt.figure(figsize=(10,10))
ax1 = plt.subplot(2,2,1)
ax1.set_title('predict OR gate')
ax1 = scatter_plot(ax1, test_X, pred_or_y)
ax2 = plt.subplot(2,2,2, projection='3d')
ax2.set_title('predict OR gate 3D')
ax2 = scatter_plot(ax2, test_X, pred_or_y, three_d=True)
ax3 = plt.subplot(2,2,3)
ax3.set_title('predict AND gate')
ax3 = scatter_plot(ax3, test_X, pred_and_y)
ax4 = plt.subplot(2,2,4, projection='3d')
ax4.set_title('predict AND gate 3D')
ax4 = scatter_plot(ax4, test_X, pred_and_y, three_d=True)
plt.show()

이진 계단 함수의 한계
- 단층 퍼셉트론은 XOR gate를 구현할 수 없다.
- 역전파 알고리즘을 사용하지 못한다.
시그모이드

import os
img_path = os.getenv('HOME')+'/aiffel/activation/jindo_dog.jpg'
# 시그모이드 함수
def sigmoid(x):
return 1/(1+np.exp(-x).astype(np.float64))
def dev_sigmoid(x):
return sigmoid(x)*(1-sigmoid(x))
# 시각화
ax = plot_and_visulize(img_path, sigmoid, dev_sigmoid)
ax.show()

시그모이드 함수의 단점
- 0 또는 1에서 포화가 된다.
- Non-zero-centered
하이퍼볼릭 탄젠트

import os
img_path = os.getenv('HOME')+'/aiffel/activation/jindo_dog.jpg'
# 하이퍼볼릭 탄젠트 함수
def tanh(x):
return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))
def dev_tanh(x):
return 1-tanh(x)**2
# 시각화
ax = plot_and_visulize(img_path, tanh, dev_tanh)
ax.show()

하이퍼볼릭 탄젠트 함수의 단점
- -1, 1에서 포화된다.
ReLU


'AIFFEL > fundametal' 카테고리의 다른 글
| Fundamental 28 (0) | 2022.02.18 |
|---|---|
| Fundamental 27 (0) | 2022.02.16 |
| Fundamental 25 (0) | 2022.02.11 |
| Fundamental 24 (0) | 2022.02.09 |
| Fundamental 23 (0) | 2022.02.07 |



