y= h(b+w1x1+w2x2)
가중치곱에 편향을 더한후 활성화 함수를 거쳐 output으로 출력됨.
활성화 함수는 말 그대로 입력신호의 총합이 활성화를 일으키는지를 정하는 역할을 함.
활성화 함수는 비선형함수로 분류됨
활성화 함수
1. 시그모이드 함수
신경망에서 자주이용되는 함수이다
def sigmoid(x):
return 1/ (1+np.exp(-x))
2. 계단함수
0이하는 0, 양수는 1로 나타나는 함수다.
넘파이 배열에 관하여 다음과 같이 구현함
def step_function(x):
y = x>0
return y.astype(np.int)
return y.astype(np.int)는 boolean 형태로 true false가 나올때, 이것을 1,0으로 변환함
시각화 하면 다음과 같이 나온다
import numpy as np
import matplotlib.pylab as plt
x= np.arange(-5.0,5.0,0.1)
y= step_function(x)
plt.plot(x,y)
plt.ylim(-0.1,1.1)
plt.show()
시그모이드와 계단함수의 차이점이 있다면, 매끄러움의 차이다
계단함수는 0또는 1의값만 돌려주는 반면, 시그모이드는 0.nn의 실수를 return 한다.
3. ReLU 함수
입력이 0을 넘으면 그 입력 그대로 출력하고, 0이하면 0을 출력
def relu(x):
return np.maximum(0,x)
출력층 설계하기
일반적으로 회귀에는 항등함수, 분류에는 소프트맥스 함수 사용
항등함수는 입력신호 그대로 출력신호가 됨.
지수 함수/ 지수함수의 k번째 출력합 으로 나타낸다
구현시 지수함수로 인한 overflow 문제가 종종 일어난다. 예를들어 e^100은 0이 40개가 넘는 값이 되고 1000승이 되면 inf로 출력된다. 이를 해결하기 위해 각 실수를 배열에 있는 수 중 가장 큰값을 빼준다
본래 softmax 함수를 계산하면 다음과 같이 출력된다
a = np.array([1010,1000,990])
np.exp(a)/ np.sum(np.exp(a))
array([nan, nan, nan])
overflow 해결을 위한 코드는 다음과 같다
c = np.max(a)
print(a-c)
np.exp(a-c)/ np.sum(np.exp(a-c))
[ 0 -10 -20]
array([9.99954600e-01, 4.53978686e-05, 2.06106005e-09])
softmax 함수의 출력은 0과 1사이의 실수로 계산되고, 출력의 총합이 1이된다는 특징이 있다. 여기서 softmax 를 적용해도 각 원소의 대소관계는 변하지 않는다. exp(x)가 단조 증가 함수이기 때문이다. 또한 출력이 가장 큰 뉴런의 위치 또한 변하지 않는다. 결과적으로 신경망으로 분류할 땐 softmax 함수를 생략해도 된다.
MNIST 데이터셋으로 신경망 구현하기
import sys,os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
def img_show(img):
pil_img = Image.fromarray(np.uint8(img)) #넘파이로 저장된 이미지 데이터를 PIL 용 데이터 객체로 변환
pil_img.show()
(x_train,t_train),(x_test,t_test)= load_mnist(flatten= True, normalize=False) #flatten 은 이미지를 1차원 배열로 변환, normalize는 정규화
img = x_train[0]
label = t_train[0]
print(label) #5
print(img.shape) #(784, )
img = img.reshape(28,28) #원래의 이미지 모양으로 변형
print(img.shape) # (28,28)
img_show(img)
이미지를 불러오는데 다음과 같이 코드를 구현한다
입력층 뉴런을 784개(28*28), 출력층 뉴런을 10(mnist class 갯수 0~9)개로 설정함.
은닉층은 총 두개, 첫번째 은닉층에는 50개, 두번째 은닉층에는 100개의 뉴런을 배치함.
def get_data():
(x_train,t_train),(x_test,t_test)= load_mnist(flatten= True, normalize=False,one_hot_label=False)
return x_test,t_test
def init_network():
with open("sample_weight.pkl",'rb') as f:
network = pickle.load(f)
return network
def predict(network,x):
W1,W2,W3 = network['W1'],network['W2'], network['W3']
b1,b2,b3 = network['b1'],network['b2'], network['b3']
a1 = np.dot(x,W1)+b1
z1= sigmoid(a1)
a2= np.dot(z1,W2)+b2
z2= sigmoid(a2)
a3= np.dot(z2,w3)+b3
y= softmax(a3)
return y
pickle 파일은 학습된 가중치 매개변수를 읽어준다. 가중치와 편향 매개변수가 딕셔너리 변수로 저장되어 있음
x,t = get_data()
network = init_network()
accuracy_int = 0
for i in range(len(x)):
y= predict(network,x[i])
p = np.argmax(y) # 확률이 가장 높은 원소의 인덱스를 얻음
if p ==t[i]:
accuracy_cnt +=1
print("Accuracy:" + str(float(accuracy_cnt)/len(x)))
predict 함수는 각 레이블의 확률을 numpy array로 반환함. argmax로 가장 큰 원소의 인덱스를 구함. 예측과 정답이 맞으면하나씩 count 해줌. 맞는 갯수가 몇개인지 acc 구함.
배치처리 구현: 배치란 하나로 묶은 입력 데이터를 배치라고함
이미지가 다발로 묶여있다고 생각하면 됨.
x,t = get_data()
network = init_network()
batch_size=100 # 배치 크기
accuracy_int = 0
for i in range(0,len(x),batch_size):
x_batch = x[i:i+batch_size]
y_batch = predict(network,x_batch)
p = np.argmax(y_batch, axis=1)
accuracy_cnt += np.sum(p == t[i:i+batch_size])
print("Accuracy:" + str(float(accuracy_cnt)/len(x)))
배치사이즈가 100이므로 x[0:100], x[100:200]..과 같이 100개씩 묶어줌. axis=1을 추가하여 100*10의 배열 중 첫번째 차원을 축으로 하는 최댓값의 인덱스를 찾도록함.
'Deep Learning > from scratch I' 카테고리의 다른 글
[밑바닥부터 시작하는 딥러닝 - 5장 오차역전파법 II] (1) | 2024.02.08 |
---|---|
[밑바닥부터 시작하는 딥러닝 - 5장 오차역전파법 I] (0) | 2024.02.08 |
밑바닥부터 시작하는 딥러닝 - 4장 신경망 학습 II] (0) | 2024.02.07 |
밑바닥부터 시작하는 딥러닝 - 4장 신경망 학습 I] (1) | 2024.02.07 |
[밑바닥부터 시작하는 딥러닝 - 2장 퍼셉트론] (0) | 2024.02.05 |