입력층(0층), 은닉층(1층), 두번째 은닉층(2층), 출력층(3층)
활성화 함수
a = b + w1x1 + w2x2
y = h(a)
1단계. 가중치가 곱해진 입력 신호의 총합 계산
2단계. 합을 활성화 함수에 입력해 결과 도출
b - 편향
계단함수
입력이 0 넘으면 1 출력
그 외에는 0 출력
import numpy as np
import matplotlib.pylab as plt
def step_function(x):
return np.array(x>0, dtype=int)
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()
시그모이드 함수
연속적인 실수
def sigmoid(x):
return 1/(1+np.exp(-x))
<공통점>
입력이 중요하면 큰 값을 출력, 입력이 중요하지 않으면 작은 값 출력
출력 0~1 사이
비선형 함수
직선 1개로는 그릴 수 없는 함수
층을 쌓고 싶다면 활성화 함수로 '비선형 함수' 사용
선형함수)
f(x)=ax + b
층을 깊게 해도 '은닉층이 없는 네트워크'와 똑같은 기능
ReLu 함수
입력이 0을 넘으면 입력 그대로 출력
0 이하면 0 출력
def relu(x):
return np.maximum(0,x)
<다차원 배열의 계산>
배열의 차원수 - np.dim() 함수 사용
배열의 형상 - 인스턴스 변수(클래스에 정의된 변수) shape
행렬의 곱 - 대응하는 차원의 원수 수를 일치시켜야함
3층 신경망
가중치 오른쪽 아래 인덱스 번호 - 다음층 번호, 앞 층 번호 순서
<각층의 신호 전달 구현>
A = (a1,a2,a3)
B=(x1,x2)
W=((w11,w21,w31),(w12,w22,w32))
X = np.array([1.0, 0.5])
W1 = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
B1 = np.array([0.1,0.2,0.3])
A1 = np.dot(X,W1)+B1
Z1=sigmoid(A1)
W2 = np.array([[0.1, 0.4],[0.2, 0.5],[0.3, 0.6]])
B2 = np.array([0.1, 0.2
A2 = np.dot(Z1, W2)+B2
Z2 = sigmoid(A2)
def identity_function(x):
return x
W3 = np.array([[0.1, 0.3],[0.2,0.4]])
B3 = np.array([0.1, 0.2])
A3 = np.dot(Z2, W3)+B3
Y = identity_function(A3) #Y=A3
<구현 정리>
import numpy as np
def sigmoid(x):
return 1/(1+np.exp(-x))
def identity_function(x):
return x
def init_network():
network={}
network['W1']=np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
network['b1']=np.array([0.1,0.2,0.3])
network['W2']=np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
network['b2']=np.array([0.1,0.2])
network['W3']=np.array([[0.1,0.3],[0.2,0.4]])
network['b3']=np.array([0.1,0.2])
return network
def forward(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=identity_function(a3)
return y
network=init_network()
x=np.array([1.0,0.5])
y=forward(network, x)
print(y) #[0.31682708 0.69627909]
init_network() - 가중치와 편향을 초기화 → 딕셔너리 변수인 network 에 저장
network - 각 층에 필요한 매개변수 (가중치와 편향)를 저장
forward() - 입력 신호를 출력으로 변환하는 처리 과정을 구현
<출력층 설계>
회귀 - 항등 함수
분류 - 소프트 맥스 함수
a=np.array([0.3,2.9,4.0])
exp_a=np.exp(a)
sum_exp_a=np.sum(exp_a)
y=exp_a/sum_exp_a
def softmax(a):
exp_a=np.exp(a)
sum_exp_a=np.sum(exp_a)
y=exp_a/sum_exp_a
return y
#주의점
소프트맥스 함수 - 지수 함수 사용
→ 오버플로 문제, 큰 값끼리 나눗셈을 해서 결과 수치 '불안정'해짐
오버플로 막을 목적 - 입력 신호 중 최대값을 이용
a=np.array([1010,1000,990])
print(np.exp(a)/np.sum(np.exp(a))) #너무 큰 숫자 nan 출력 [ 1.34985881 18.17414537 54.59815003]
c=np.max(a)
print(a-c) #74.1221542101633
print(np.exp(a-c)/np.sum(np.exp(a-c))) #[0.01821127 0.24519181 0.73659691]
def softmax(a):
c=np.max(a)
exp_a=np.exp(a-c)
sum_exp_a=np.sum(exp_a)
y=exp_a/sum_exp_a
return y
소프트맥스 함수 출력의 총합 1
→ 출력을 '확률'로 해석 가능
ex) y[0] 확률 0.018 (1.8%), y[1] 확률 0.245 (24.5%) y[2] 확률 0.737 (73.7%)
"2번째 원소의 확률이 높으니 답은 2번째 클래스다"
"74% 확률로 두번째 클래스, 25% 확률로 1번째 클래스, 1% 확률로 0번째 클래스다"
각 원소의 대소 관계는 변하지 않음
→ y=exp(x) 가 단조 증가 함수
뉴런의 회색 농도 - 해당 뉴런의 출력값의 크기
<손글씨 숫자 인식>
추론 과정 - 신경망의 순전파
MNIST 데이터셋
손글씨 숫자 이미지 집합
28x28 픽셀 사이즈의 손글씨 사진, 훈련 이미지 60,000장 시험 이미지 10,000장
각 픽셀은 0~255까지의 값
import sys, os
sys.path.append(os.pardir) #부모 디렉터리로의 접근을 허락
import numpy as np
from dataset.mnist import load_mnist #dataset 폴더의 mnist라는 파일에서 load_mnist라는 문장을 제약 없이씀
from PIL import Image
def img_show(img):
pil_img = Image.fromarray(np.uint8(img))
pil_img.show()
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
img = x_train[0]
label = t_train[0]
print(label)
print(img.shape)
img = img.reshape(28, 28)
print(img.shape)
img_show(img)
sys - 파이썬 인터프리터가 제공하는 변수들과 함수들을 직접 제어할 수 있게 해주는 모듈
os - 환경 변수나 디렉터리, 파일 등의 OS 자원을 제어할 수 있게 해주는 모듈
mnist_show.py
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
load_mnist 함수
normalize - 입력 이미지의 픽셀값을 0.0~1.0 사이의 값으로 정규화할지를 정함
False 설정 - 입력 이미지의 픽셀은 원래 값인 0~255 사이의 값 유지
flatten - 입력 이미지를 평탄하게 (1차원 배열)로 만들지를 정함
False 설정 - 입력 이미지 1 x 28 x 28 의 3차원 배열
True 설정 - 784개의 원소로 이뤄진 1차원 배열 저장
one_hot_label - 원-핫 인코딩 형태로 저장할지를 정함
[0,0,1,0,0,0] 정답을 뜻하는 원소만 1 (hot), 나머지는 0
False 설정 - '7'이나 '2' 같은 숫자 형태의 레이블 저장
True 설정 - 레이블을 원-핫 인코딩하여 저장
<신경망의 추론 처리>
입력층 뉴런을 784(28x28)개, 출력층 뉴런을 10(0~9)개로 구성
첫번째 은닉층 50개의 뉴런
두번째 은닉층 100개의 뉴런
# coding: utf-8
import sys, os
sys.path.append(os.pardir)
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax
import numpy as np
import pickle
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, 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 파일인 sample_weight.pkl에 저장된 '학습된 가중치 매개변수' 읽음
→ 가중치와 매개변수가 딕셔너리 변수로 저장되어 있음
<정확도 평가>
x, t = get_data()
network = init_network()
accuracy_cnt = 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)))
for 문을 돌며 x에 저장된 이미지 데이터 1장씩 꺼냄. → predict() 함수로 분류
predict() - 각 레이블의 확률을 넘파이 배열로 반환
ex) [0.1,0.3] → '0'일 확률 0.1, '1'일 확률 0.3
신경망이 예측한 답변과 정답 레이블을 비교하며 맞힌 숫자를 셈 (accuracy_cnt +1)
→ 전체 이미지 숫자로 나눠 정확도 구함
정규화 - 데이터를 특정 범위로 변환하는 처리
전처리 - 신경망의 입력 데이터에 특정 변환을 가함
가중치 형상 출력
print(x.shape) =>(10000, 784)
print(x[0].shape) =>(784,)
print(W1.shape) =>(784, 50)
print(W2.shape) =>(50, 100)
print(W3.shape) =>(100, 10)
다차원 배열의 대응하는 차원의 원소 수가 일치함을 확인
x[0]과 y[0] 에는 0번째 이미지 추론 결과, x[1]과 y[1]에는 1번째 이미지와 결과 저장
배치 - 하나로 묶은 입력 데이터 (묶음)
<데이터를 배치 처리로 구현>
x, y = get_data()
network = init_network()
batch_size=100 # 배치 크기
accuracy_cnt = 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 == y[i:i+batch_size])
print("Accuracy: " + str(float(accuracy_cnt)/ len(x)))
range() - x[i:i+batch_size] 에서 입력 데이터를 묵음 (i번째부터 i+batch_size 번째까지의 데이터를 묶음)
batch_size가 100 - x[0:100], x[100:200]'
효율적이고 빠르게 처리 가능
'AI > 딥러닝' 카테고리의 다른 글
[밑바닥부터 시작하는 딥러닝] 7장 합성곱 신경망(CNN) (0) | 2023.04.15 |
---|---|
[밑바닥부터 시작하는 딥러닝] 6장 학습 관련 기술들 (1) | 2023.04.08 |
[밑바닥부터 시작하는 딥러닝] 5장 오차역전파법 (0) | 2023.04.01 |
[밑바닥부터 시작하는 딥러닝] 4장 신경망 학습 (0) | 2023.03.25 |
[밑바닥부터 시작하는 딥러닝] 2장 퍼셉트론 (0) | 2023.03.18 |