3장까지의 전체 코드:
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
import pickle
import numpy as np
# 신경망 함수들
def sigmoid(num):
rst = (1 / (1 + np.exp(-num)))
return (rst)
def identity_function(x):
return x
def softmax(a):
c = np.max(a)
minus = a - c
exp_a = np.exp(minus)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
def init_network():
with open("C:\\Users\itwill\sample_weight\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
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
##############################################################
x, t = get_data()
network = init_network()
batch_size = 100
result = 0
for i in range(0,len(x),batch_size):
x_batch = x[i:i+batch_size]
y = predict(network, x_batch)
p = np.argmax(y,axis=1) #예상값
#print(p)
t_batch = t[i:i+batch_size] #실제값 (t 라벨. 이미 최대값 뽑아서 나온 실제답임)
result += np.sum( p==t_batch )
print("정확도:",result/len(x))
정확도: 0.9352
■ 4장. 신경망 학습
앞장에서는 저자가 만들어온 가중치값을 가지고 신경망을 구성했기 때문에
신경망을 학습 시킬 필요가 없었다.
필기체 7 ----------------> 신경망 --------------------> 예측값 == 실제값
↑ ↑
저자가 만들어 온 가중치값 세팅 정확도
4장에서는 우리가 직접 신경망을 학습을 시킬 것 인데
학습을 시키기 위해서 알아야 하는 내용?
1. 오차함수
2. 가중치를 갱신하는 방법(수치 미분)
"경사법에서는 기울기(경사)값을 기준으로 나아갈 방향 결정."
"함수 f(x)의 x에 대한 미분값을 수치해석으로 구하기"
"x의 차수를 끌어내려와 연산시켜줌"
3. 미니배치 (mini batch)
■ 오차함수
" 예상값과 실제값과의 오차를 신경망에 역전파 시켜주기 위해서
필요한 함수 "
오차가 최소화 될 때까지 신경망을 학습시키기 위해서 필요한 함수
1. 평균제곱 오차함수 : 회귀분석을 할 때 일반적으로 사용
2. 교차 엔트로피 오차함수 : 분류문제를 풀 때 사용
출력층 함수 오차 함수
회귀문제를 해결할 때 ------> 항등 함수 평균제곱 오차함수
분류문제를 해결할 때 ------> 소프트맥스 함수 교차 엔트로피 함수
p.112
■ 평균제곱 오차함수
y는 예상값
t는 실제값(라벨값)
k는 차원 수
1/2곱해주는 이유는 미분시키면 2값이 나오는데, 그 군더더기를 없애주려고
1/2를 곱하는 것이다.
아직 저 식에서는 평균낸거 아님.
문제141.
위의 식을 가지고 평균제곱 오차함수를 파이썬으로 구현하시오
import numpy as np
def mean_squared_error(y,t):
return 0.5 * np.sum( ( y-t)**2 )
t = [0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0]
y = [0.1 , 0.05 , 0.6 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0]
# t가 (원-핫코딩 시킨)실제값, y가 예상값 인데, mnist 의 숫자 2에서
# y가 가장 큰값을, t는 1을 나타내는 걸 볼 수 있다.
print( mean_squared_error( np.array( y ) , np.array( t ) ) )
0.0975
0.0975 의 오차를 신경망으로 역전파 시켜서 가중치(w)를 갱신한다.
문제142.
아래의 확률벡터를 평균제곱오차 함수를 이용해서
target(실제값) 과 예측값의 오차율이 어떻게 되는지
for loop 문으로 한번에 알아내시오
import numpy as np
def mean_squared_error(y,t):
for i in y:
print (0.5 * np.sum( ( i-t )**2))
t = [0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0]
y = [
[0.1,0.05,0.1,0.0,0.05,0.1,0.0,0.1,0.0,0.0],
[0.1,0.05,0.2,0.0,0.05,0.1,0.0,0.6,0.0,0.0],
[0.0,0.05,0.3,0.0,0.05,0.1,0.0,0.6,0.0,0.0],
[0.0,0.05,0.4,0.0,0.05,0.0,0.0,0.5,0.0,0.0],
[0.0,0.05,0.5,0.0,0.05,0.0,0.0,0.4,0.0,0.0],
[0.0,0.05,0.6,0.0,0.05,0.0,0.0,0.3,0.0,0.0],
[0.0,0.05,0.7,0.0,0.05,0.0,0.0,0.2,0.0,0.0],
[0.0,0.1,0.8,0.0,0.1,0.0,0.0,0.2,0.0,0.0],
[0.0,0.05,0.9,0.0,0.05,0.0,0.0,0.0,0.0,0.0]
]
# t가 (원-핫코딩 시킨)실제값, y가 예상값 인데, mnist 의 숫자 2에서
# y가 가장 큰값을, t는 1을 나타내는 걸 볼 수 있다.
mean_squared_error( np.array( y ) , np.array( t ) )
==========================================
import numpy as np
def mean_squared_error(y,t):
return 0.5 * np.sum( ( y-t )**2)
#print(mean_squared_error( np.array( y ) , np.array( t ) ) )
t = [0,0,1,0,0,0,0,0,0,0] # 숫자2
y1 = [0.1,0.05,0.1,0.0,0.05,0.1,0.0,0.1,0.0,0.0]
y2 = [0.1,0.05,0.2,0.0,0.05,0.1,0.0,0.6,0.0,0.0]
y3 = [0.0,0.05,0.3,0.0,0.05,0.1,0.0,0.6,0.0,0.0]
y4 = [0.0,0.05,0.4,0.0,0.05,0.0,0.0,0.5,0.0,0.0]
y5 = [0.0,0.05,0.5,0.0,0.05,0.0,0.0,0.4,0.0,0.0]
y6 = [0.0,0.05,0.6,0.0,0.05,0.0,0.0,0.3,0.0,0.0]
y7 = [0.0,0.05,0.7,0.0,0.05,0.0,0.0,0.2,0.0,0.0]
y8 = [0.0,0.1,0.8,0.0,0.1,0.0,0.0,0.2,0.0,0.0]
y9 = [0.0,0.05,0.9,0.0,0.05,0.0,0.0,0.0,0.0,0.0]
y=np.array([y1,y2,y3,y4,y5,y6,y7,y8,y9])
#print(y)
for i in range(len(y)):
print ( "y"+str(i+1)+"의 오차율:" , ( mean_squared_error( y[i] , np.array(t) ))*100, "%" )
y1의 오차율: 42.25 %
y2의 오차율: 51.25 %
y3의 오차율: 43.25 %
y4의 오차율: 30.75 %
y5의 오차율: 20.75 %
y6의 오차율: 12.75 %
y7의 오차율: 6.75 %
y8의 오차율: 5.0 %
y9의 오차율: 0.75 %
■ 2. 교차 엔트로피 오차 함수
수식 : 4.2
t = 실제값
y = 예상값 에 log 를 씌움 (log를 안씌우면 순식간에 큰값이 되버림)
t의 1값이
y의 가장 큰 값이랑 매칭된다.
문제143.
확률0.1 과 확률 0.9 를 교차 엔트로피 공식에 대입한 결과가
각각 어떻게 되는지 확인하시오 !
import numpy as np
print(-np.log( 0.1), -np.log( 0.9))
#0.9는 90%의 확률로 오차를 알려주는 것이고
0.1 은 10%의 확률로 오차를 알려주는 것이다.
2.30258509299 0.105360515658
확률 : 0.1 확률 : 0.9
오차 : 2.3 오차 : 0.1
결과를 보면
0.9로 돌린 값이 훨씬 작다.
※ 설명: 책 p.114 자연로그 y = logx 의 그래프
x 축이 확률
y 축이 오차
***-log 그래프
화면 캡처: 2019-01-16 오후 5:28
문제144.
교차 엔트로피 함수를 생성하시오 (p.115)
def cross_entropy_error(y,t):
import numpy as np
delta = 1e-7 #log=0 은 에러나서 y에 델타를 더해주기 위함이다.
return -np.sum( t * np.log(y + delta ) )
※ 설명:
delta 를 더하는 이유는 np.log() 함수에 0을 입력하면
마이너스 무한대를 뜻하는 -inf 가 되어
더 이상 계산을 진행할 수 없기 때문에
아주 작은값인 0.0000001(=1e-7) 을 더해주는 것이다.
import numpy as np
t = [0,0,1,0,0,0,0,0,0,0] # 숫자2
y = [0.1 , 0.05 , 0.6 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0]
print( cross_entropy_error( np.array( y ) , np.array( t ) ) )
0.510825457099
문제145.
아래의 예측값(=y)으로 오차를 구했을 때 오차는 어떻게 되는가?
t = [0,0,1,0,0,0,0,0,0,0]
y = [0.1 , 0.05 , 0.1 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0]
*** t 자리 y 값을 0.1 로 바꿨다(위에는 0.6)
import numpy as np
t = [0,0,1,0,0,0,0,0,0,0] # 숫자2
y = [0.1 , 0.05 , 0.1 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0]
print( cross_entropy_error( np.array( y ) , np.array( t ) ) )
2.30258409299
문제144번의 답과 다르게 큰 오차를 리턴해주고 있다.
문제146.(오늘의 마지막 문제)
평균제곱 오차함수와 교차엔트로피 오차함수중에
어떤것이 더 큰 오차를 신경망에 역전파 시켜주겠는지
테스트 해보시오
t = [0,0,1,0,0,0,0,0,0,0] # 실제값, mnist 숫자2
y1 = [0.1 , 0.05 , 0.6 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0] #예상값
y2 = [0.1 , 0.05 , 0.1 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0] #예상값
---교차엔트로피 오차함수:
확률: 0.6 오차: 0.51083
확률: 0.1 오차: 2.30258
def cross_entropy_error(y,t):
import numpy as np
delta = 1e-7 #log=0 은 에러나서 y에 델타를 더해주기 위함이다.
return -np.sum( t * np.log(y + delta ) )
import numpy as np
t = [0,0,1,0,0,0,0,0,0,0] # 숫자2
y1 = [0.1 , 0.05 , 0.6 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0]
y2 = [0.1 , 0.05 , 0.1 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0]
y = np.array([y1,y2])
for i in y:
print( "확률:",i[np.argmax(i)], \
" 오차:", cross_entropy_error( np.array(i) , np.array(t) ).round(5) )
---평균제곱 오차함수:
확률: 0.6 오차: 0.0975
확률: 0.1 오차: 0.5975
import numpy as np
def mean_squared_error(y,t):
return 0.5 * np.sum( ( y-t )**2)
import numpy as np
t = [0,0,1,0,0,0,0,0,0,0] # 숫자2
t_index = t.index(1)
y1 = [0.1 , 0.05 , 0.6 , 0.0 , 0.05 , 0.1 , 0.0 , 0.1 , 0.0 , 0.0]
y2 = [0.1 , 0.05 , 0.1 , 0.0 , 0.05 , 0.1 , 0.0 , 0.6 , 0.0 , 0.0]
y=np.array([y1,y2])
for i in y:
print("확률:" ,i[t_index], \
" 오차:" ,mean_squared_error( np.array(i), np.array(t) ).round(5) )
※설명:
y2 = [0.1 , 0.05 , 0.1 , 0.0 , 0.05 , 0.1 , 0.0 , 0.6 , 0.0 , 0.0]
#평균제곱 오차함수는 다 더해서 평균내는 오차함수법이라서
y2의 세번째 숫자와 8번째 숫자 자리를 서로 바꿔준다.
■ 미니배치 (minibatch)학습 p.115
"훈련 데이터 중에 일부만 골라서 학습하는 방법"
"표본을 뽑아서 학습 시킨다"
↓
예: 된장찌개의 맛을 확인하기 위해서 한 수저(=표본)만 간을 본다
복원추출 이든 비복원추출 이든 mnist의 경우 100장씩 배치처리 한다면
100장씩 600번을 훈련시키면 그게 1 epoch 다.
여러번 에폭이 반복되면서 비용함수(오차함수)의 global minima 로
찾아가게 된다.
※설명:
복원 추출? 한 번 추출한 것을 다시 뽑을 수 있는 추출
비복원 추출? 한 번 추출한 것을 다시 뽑을 수 없는 추출
화면 캡처: 2019-01-17 오후 1:59
에폭?epoch
총 60000장을 100장씩 600번 시키는게 1 에폭이다
그렇게 Global cost minimum 지점까지 가기위한 에폭을 찾는거다.
**600장씩 100번으로 안 돌리는 이유는 컴퓨터안전을 위해서.
1에폭 돌면 빨간화살표이 저렇게 이동한다.(=오차를 줄여나간다)
이렇게 n번의 에폭이 돌면 global minimum 값(최적의 가중치)를
찾아낸다.
문제152.
1~60000개의 숫자중에 무작위로 10개를 출력하시오
import numpy as np
print( np.random.choice( np.arange(60000), 10 ) )
[11882 59774 18864 22356 16868 18575 50014 53451 44508 58383]
***코드실행할 때마다 값이 다르게 나온다.
[51835 20726 8898 42379 29605 49912 29791 19515 9947 38958]
[ 5119 26806 53424 27060 5161 4245 55450 47885 35941 49317]
[ 2154 49402 55745 31473 5705 14930 1449 4533 12439 58915]
[ 9058 57518 56537 27119 11089 3010 54576 31172 34541 53821]
[27876 27607 5783 9982 13193 25979 791 57308 29670 56173]
문제153.
mnist의 테스트 데이터 10000장 중에 랜덤으로 100장을 추출하는
코드를 작성하시오
(랜덤 추출이 + 복원추출: 출력랜덤값 제거 안했으니까)
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
import pickle
import numpy as np
# 신경망 함수들
def sigmoid(num):
rst = (1 / (1 + np.exp(-num)))
return (rst)
def identity_function(x):
return x
def softmax(a):
c = np.max(a)
minus = a - c
exp_a = np.exp(minus)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
def init_network():
with open("C:\\Users\itwill\sample_weight\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
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
x,t = get_data()
for i in range(0,10000,100):
batch_mask = np.random.choice(10000,100)
print( batch_mask ) #0~10000랜덤하게 100개
x_batch = x[batch_mask]
print( len( x_batch ) )
문제154.
위의 코드는 복원추출인데
비복원 추출이 되게끔 코드를 수정하시오
x,t = get_data()
for i in range(0,10000,100):
#batch_mask = np.random.choice(10000,100) # 차례대로 뽑아야 하니까.
#print( batch_mask )
#x_batch = x[batch_mask] # 랜덤값 넣을 필요 없음
x_batch = x[i:i+100] # 순차적으로 갖고오기
print( len( x_batch ) )
문제155.
위의 코드를 5epoch 이 돌게 코드를 수정하시오
batch_size=100
for j in range(1,5+1):
print('--------------------------------------', j,'에폭')
for i in range(0,len(x),batch_size): #비복원추출
x_batch = x[i:i+batch_size]
t_batch = t[i:i+batch_size]
print(len(x_batch))
print('--------------------------------------', j,'에폭')
■ 미니배치 처리에 맞게끔 교차 엔트로피 함수를 구성하는 방법
-미니배치 처리하기 전 교차 엔트로피 함수(한장씩 출력)
y = np.array([0,0,0.9,0,0,0,0,0,0,0.1]) #확률벡터 예상값
t = np.array([0,0,1,0,0,0,0,0,0,0])
def cross_entropy_error(y,t):
delta = 1e-7
return -np.sum(t * np.log(y+delta))
print(cross_entropy_error(y,t))
문제156.
미니배치 (100장)에 맞게끔 교차엔트로피 함수를 수정하시오
#- 100장씩 미니배치한후의 교차 엔트로피 함수
y = np.array([ [0, 0, 0.9, 0, 0, 0, 0, 0, 0, 0.1],
[0.9, 0, 0.1, 0, 0, 0, 0, 0, 0, 0.1],
[0, 0, 0.1, 0, 0.8, 0, 0, 0, 0, 0.1],
:
: 100개
:
[0, 0, 0.9, 0, 0, 0, 0, 0, 0, 0.1] )
*** t값도 100개 있음(여기에 기재하지 않겠음)
y의 shape 을 찍어보면 ( 100 , 10 ) 나온다. (행,열)
y.shape[0] 하면 행값이므로 100 이 나온다.
batch_size = y.shape[0]
def cross_entropy_error(y,t):
delta = 1e-7
return -np.sum(t * np.log(y+delta)) / batch_size
print(cross_entropy_error(y,t))
※ 랜덤으로 추출한 100개를 가지고 배치로 오차함수 역전파 시키는 이유는
한장씩 한장씩 하는 것보다
100장씩 하는게 더 빠르게 최적의 가중치값으로 회귀하기 때문이다.
■ 수치 미분(p.121)
신경망 학습 시킬 때 왜 미분을 알아야 하는가?
가중치를 갱신해주기 위해서 미분이 필요하다
가중치 = 기울기 - 기울기
할선= 나누는 선
접선= 닿는 선
한 점에서의 속도를 구하려면 접선의 방정식을 구해야 하는데
구하는 방법이 바로 미분(기울기)
f(x+h) - f(x)
lim --------------------------------
h->0 h
책 121p
위의 미분 공식을 파이썬 함수로 구현해서 실행을 해본다.
def numerical_diff(f,x):
h = 10e-50 #0에 가까운 숫자(0이 50개)
return ( f(x+h) -f(x)) / h
그런데
import numpy as np
print(np.float32(1e-50))
0.0
1e-50 을 출력해보면 너무 작은값이라서 0.0 이라고 출력된다.
즉, h로 사용하기에 적절치 못하다.
저자가 테스트를 해보니 최적의 미세값으로
h = 1e-4 라는 것을 알아냈다.
h를 10의 -4승의 값을 사용하면 좋은 결과가 나온다고 알려져 있다.
미분계산을 위한 함수를 만들고 다듬어 가자.
1. 미분함수의 첫 번째 개선
def numerical_diff(f,x):
h = 10e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x)) / h
↓ 컴퓨터로는 미분을 하지 못하니 도함수를 구현해야 한다.
2. 두 번째 개선
접선공식 할선공식
f(x+h) - f(x) f(x+h) - f(x-h)
lim ---------------------- lim-------------------------
h->0 h h->0 (x+h) - (x-h)
↓
f(x+h) - f(x)
lim ----------------------
h->0 2h
접선공식을 이용해서
h값을 구하면 좋겠지만, 컴퓨터가 h값을 구현 못한다.
(꽤나 작은값들은 모두 그냥 0으로 표시해버린다)
가중치에서 기울기를 빼주는 이유는
기울기가 0 이 되는 지점이 왔을 때
가중치에서 그 기울기 0을 빼주면
가중치에 변화가 없으니까
그것을 최적의 가중치라 생각하고 출력하면 된다.
문제157.
y = 2x^2 + 2 의 함수를 loss2 라는 이름으로 생성하시오
(2차함수)
def loss2(x):
return 2*x**2+2
print(loss2(4))
문제158.
y = 2x^2 + 2의 함수의 x = 7 인 곳의 기울기를 손으로 구하시오
답: 28
※ 기울기를 구하려면 도함수를 구해야 한다.
도함수?
함수를 미분해서 얻은 함수
순간변화율. 유도함수.라고도 한다.
문제159.
y = 2x^2 + 2의 함수의 x = 7 인 곳의 기울기를 컴퓨터로 구현하시오
(책 123p_ 할선공식을 이용한 기울기 구하기)
def numerical_diff(f,x): #할선공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x-h) ) / (2*h)
def loss2(x):
return 2*x**2+2
print(numerical_diff( loss2, 7) )
27.999999999934744
문제160.(오늘의 마지막 문제)
문자 159번의 함수를 접선의 미분 공식으로 만든 함수로
미분했을 때의 x=7 에서의 기울기를 구하시오
(책 121p_ 접선공식을 이용한 기울기 구하기)
def numerical_diff2(f,x): #접선의 공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x) ) / h
def loss2(x):
return 2*x**2+2
print(numerical_diff2( loss2, 7) )
28.000199999951292
----------------할선과 접선을 통해서 나온 값들을
기울기 28에서 빼서
그 차가 더 작은것을 알아보자!
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
def numerical_diff(f,x): #할선의 공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x-h) ) / (2*h)
def loss2(x):
return 2*x**2+2
print(28-numerical_diff( loss2, 7) )
6.52562448522076e-11
def numerical_diff2(f,x): #접선의 공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x) ) / h
def loss2(x):
return 2*x**2+2
print(28-numerical_diff2( loss2, 7) )
-0.00019999995129182935
위 2개 값을
a=6.52562448522076e-11
b=0.00019999995129182935 (음수 지우고)
print(min(a,b))
6.52562448522076e-11
※ 설명:
더 적은값이 할선인 것을 확인할 수 있다.
그래서 파이썬으로 할선의 공식을 이용하여 실제 기울기와 가장 근접한
값을 구하는 것이다.
- 손실 함수의 목적
머신러닝 모델의 최종적인 목적은 높은 정확도를 끌어내는
매개변수(가중치, 편향)를 찾는 것이다.
신경망 학습에서는 최적의 매개변수를 탐색할 때
손실함수의 값을 가능한 한 작게 하는 매개변수 값을 찾는다.
이 때, 매개변수의 미분(기울기)을 계산하고, 그 미분 값을 토대로 매개변수 값을 갱신하는 과정을 반복한다.
- 주요한 점은,
정확도와는 달리 손실 함수는
매개변수의 변화에 따라 연속적으로 변화한다는 점이다.
손실 함수와는 달리 정확도는 매개변수의 변화에 둔감하고,
또한 변화가 있다하여도
불연속적으로 변화하기 때문에 미분을 할 수 없다.
미분이 되지 않으면 최적화를 할 수 없으므로 정확도가 아닌
손실 함수를 지표로 삼아 학습을 해나가는 것이다.
■ 4장의 목차
1. 오차함수 : 예상값과 실제값의 오차를 구하기 위해 필요한 함수
2. 미니배치 : 신경망 학습시 한장 씩 처리하는 것보다 배치로 처리하는 게
학습이 더 빠르기 때문이다.
3. 수치미분 : 신경망을 학습 시킬 때
"가중치 = 가중치 - 기울기" 의 공식으로 가중치를
갱신해 나가는데 이때 기울기를 구할려면
미분을 해야 한다.
"아주 작은 차분으로 미분하는 것"
P.123 NOTE
이 3가지를 통해서 3층 신경망을 학습을 시키는 챕터가 4장의 내용
문제162.
아래의 비용함수를 시각화 하시오
구글 검색창에
x**2 + 4**2
넣으면 함수위치가 실시간으로 나온다.
문제163.
아래의 그래프를 구글에서 시각화 하시오
f(x0, x1) = x0**2 + x1**2
↓
z= x^2 + y^2
화면 캡처: 2019-01-18 오전 11:44
3차원 그래프
문제164.
아래의 비용함수를 만들고 이 비용함수의 x=6 인 지점에서의
미분계수(기울기)를 손으로 구하시오
y = 4x^2 + 7^2
답: 48
문제165.
위의 식을 loss3 라는 비용함수로 만들고
loss3 함수를 파이썬으로 미분해서 x=6 인 지점의 미분계수(기울기)를
구하시오
def loss3(x):
return 4*x**2 + 7**2
def numerical_diff(f,x): #할선의 공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x-h) ) / (2*h)
print(numerical_diff( loss3, 6 ))
47.99999999988813
※설명:
컴퓨터로는 진정한 미분을 구현할 수 없기 때문에 오차가 발생한다
왜?
1. 극한값을 구현하기가 어렵다.
2. 접선의 방정식이 아니라 할선의 방정식의 기울기로 미분함수를
만들어야하기 때문이다.
지금까지 구현한 비용함수는 2차원에 해당하는 비용함수 였다.
즉 w(가중치)를 하나만 두고 만든 함수였다.
그런데
신경망에 들어가는 가중치는 w(가중치)가 w1 하나만이 아니라
w0 도 있고
w2 도 있고
여러개의 w가 있을 수 있기 때문에 2차원을 넘어설 수 있다.
2차원 그래프가 아니라 3차원 그래프를 미분할 때 사용한 미분방법이?
편미분! p.125
■ 편미분
"변수가 2개 이상인 함수를 미분할 때 미분 대상 변수외에
나머지 변수를 상수처럼 고정시켜 미분하는 것을 편미분이라고 한다"
f(x0,x1) = x0**2 + x1**2
f(w0,w1) = w0**2 + w1**2
문제166. 손으로 먼저 편미분을 수행하시오
f(x0,x1) = x0^2 + x1^2
위 함수를 편미분 하는데
x0 = 3
x1 = 4 일때 x0 에 대해서 편미분 하시오
"변수가 2개 이상인 함수를 미분할 때 미분 대상 변수외에
나머지 변수를 상수처럼 고정시켜 미분하는 것을 편미분이라고 한다"
f(x0,x1) = x0^2 + x1^2
y = 3^2 + 4^2
답: 6
문제167.
f(x0,x1) = x0^2 + x1^2 함수를 편미분 하는데
x0=3, x1=4 일 때 x0 에 대해서 편미분한 미분계수(기울기)를
파이썬으로 구현하시오
def loss5(x):
return x**2 + 4**2
# 구하고자 하는 자리에만 x 남겨놓고
다른 x는 상수로 대체시켜줌.
def numerical_diff(f,x): #할선의 공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x-h) ) / (2*h)
print(numerical_diff( loss5, 3 ))
6.00000000000378 ##기울기 6
문제168.
위 문제에서 x1=4 에 대해서 편미분 하시오
def loss5(x):
return 3**2 + x**2
##########################################################
def numerical_diff(f,x): #할선의 공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x-h) ) / (2*h)
print(numerical_diff( loss5, 4 ))
7.999999999999119 ###기울기 8
f(x0,x1) = x0^2 + x1^2
x=np.array([3.0 , 4.0])
기울기 = [6,8]
문제169.
위에서는 f(x0,x2) = x0^2 +x1^2 함수를 편미분 하는 것을
각각 수행했는데
이제 편미분이 한 번에 수행하게 코드를 작성하시오
import numpy as np
def loss_func(x):
return x[0]**2 + x[1]**2
def numerical_diff(f,x): #할선의 공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x-h) ) / (2*h)
print(numerical_diff( loss_func, np.array([3,4]) ))
문제169-1.
아래와 같이 결과를 출력하시오
[0 0]
import numpy as np
x = np.array([3.0 , 4.0])
print(np.zeros_like(x))
[ 0. 0.]
#이 작업을 하는 이유는 6.0 과 8.0을 그 자리에 넣으려고 !
문제169-2.
x 넘파이 배열의 원소중에서 3을 받아서
아래의 식을 아래와 같이 구현하시오
f(x+h) - f(x-h)
↓ ↓
f(3.0 + 0.0001) - f(3.0 - 0.0001)
↓ ↓
(3.0001^2 + 4^2) - (2.9999^2 + 4^2) = 0.0012
import numpy as np
def loss_func(x):
return x[0]**2 + x[1]**2
##########################################################
def numerical_diff(f,x): #할선의 공식
h = 1e-4 #컴퓨터로 극한값을 구하기 어려우므로 이렇게 미세값지정해준다.
return ( f(x+h) -f(x-h) )
x=np.array([3.0 , 4.0])
print(numerical_diff( loss_func, x))
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
import numpy as np
def loss_func(x):
return x[0] ** 2 + x[1] ** 2
x = np.array([3.0, 4.0])
def numerical_gradient(f, x):
h = 0.0001
grad = np.zeros_like(x) # [0 0]
for idx in range(x.size): # 0, 1
tmp_val = x[idx] # x[0] =3.0
x[idx] = tmp_val + h # x[idx] = 3.0 + 0.0001
fxh1 = f(x) # f(x+h) 를 계산, 3.0001^2 + 4^2 = 25.00
x[idx] = tmp_val - h # 3- 0.0001 =2.9999
fxh2 = f(x) # f(x-h) 를 계산 # 2.9999^2 + 4^2 =24.999
grad[idx] = (fxh1 - fxh2)
return grad
x = np.array([ 3.0 , 4.0 ])
print(numerical_gradient(loss_func, x))
[ 0.0012 0.0016]
문제169-3.
아래의 식으로 numerical_gradient 함수 코드를 완성 시키시오
**위 코드에서 몇 가지 수정
import numpy as np
def loss_func(x):
return x[0] ** 2 + x[1] ** 2
x = np.array([3.0, 4.0])
def numerical_gradient(f, x):
h = 0.0001
grad = np.zeros_like(x) # [0 0]
for idx in range(x.size): # 0, 1
tmp_val = x[idx] # x[0] =3.0
x[idx] = tmp_val + h # x[idx] = 3.0 + 0.0001
fxh1 = f(x) # f(x+h) 를 계산, 3.0001^2 + 4^2 = 25.00
x[idx] = tmp_val - h # 3- 0.0001 =2.9999
fxh2 = f(x) # f(x-h) 를 계산 # 2.9999^2 + 4^2 =24.999
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val #x[idx] 가 2.9999 로 되어있어서 3.0으로 바꿔줘야함
#다음 for문 돌면 3.9999 를 4.0으로 바꿔주고.
return grad
x = np.array([ 3.0 , 4.0 ])
print(numerical_gradient(loss_func, x))
[ 6. 8.] # <<-----기울기
문제170.
아래의 x0, x1 지점에서의 기울기를 각각 구하시오
f(x0,x1) = x0^2 + x1^2
x0 , x1 ----------------------------------> grad1 , grad2
[3.0 4.0] --------------------------------> [6.0 8.0]
[0.0 2.0] --------------------------------> [0.0 4.0]
[3.0 0.0] --------------------------------> [6.0 0.0]
위 공식에서 x값 대입시킴.
x들은 가중치고 grad들은 기울기다.
p.129
첫번째 3차원 함수를 윗방향에서 바라보면 아래 그림같은 모습이다.
기울기 그림은 마이너스 방향을 가진 벡터(화살표)로 그려집니다.
이 그림을 보면 기울기는 함수의 '가장 낮은 장소(최솟값)'를 가리키는
것 같습니다.
마치 나침반처럼 화살표들은 한 점을 향하고 있지요.
또 '가장 낮은 곳'에서 멀어질 수록 화살표의 크기가 커짐을 알 수 있습니다.
기울기가 가리키는 쪽은 각 장소에서 함수의 출력값을 가장 크게
줄이는 방향 입니다.중요!!
■ 경사하강법
p.131
"특정 가중치의 위치에서 기울기를 빼서 점차 global minima로
진행하는 학습 방법"
기계학습은 최적의 매개변수를 찾아내는 과정입니다.
최적값 = 손실 함수 최솟값----> 매개변수 값
최적을 찾기 위해 :
기울기를 이용.
가중치에서 기울기를 빼서 가중치값을 갱신시키는데,
기울기가 0이 되는 지점에 오면
가중치값도 더 이상 갱신이 안된다. (최솟값을 얻음)
그 지점을 바로 최적값 이라 부른다.
최솟값 ===> 최적값
※경사하강법 공식
가중치 = 가중치 - 러닝레이트 * 기울기
∂ 비용함수
w0 = w0 - 학습률*--------------------
∂ W0
∂ 비용함수
w1 = w1 - 학습률* --------------------
∂ W1
*∂ : 편미분
※ 왜 학습률을 곱해주는가?
학습률을 곱해주지 않으면 너무 촘촘히 내려가서 학습이 안 될수도 있다.
*학습률이란?
"한 번의 학습으로 얼마만큼 학습행 할지, 즉 매개변수 값을 얼마나
갱신하느냐를 정하는 것이 학습률 입니다"
"학습률 값은 0.01 이나 0.001 등 미리 특정값으로 정해두어야 하는데,
일반적으로 이 값이 너무 크거나 작으면 '좋은장소'를 찾아갈 수 없습니다.
신경망 학습에서는 보통 이 학습률값을 변경하면서 올바르게 학습하고
있는지를 확인하면서 진행합니다"
문제171.
책 131페이지에 나오는 경사 하강 함수(gradient_descent)함수를 생성하시오
문제172.
위에서 만든 gradient_descent 함수를 가지고
x[0] = 3.0
x[1] = 4.0
인 지점에서 학습을 100번 수행했을 때 global minima 에 도착하는지
확인하시오
러닝레이트: 0.01
학습 횟수: 100
import numpy as np
def loss_func(x): # 할선공식
return x[0] ** 2 + x[1] ** 2
#기울기는 나아갈 방향을 정해줌
# 기울기가 0이 되는 지점을 찾아내어
# 가중치 - 기울기 = 가중치 (즉 가중치 갱신 안됨)
# 위 내용이 성립되는 기울기를 찾아내고
# 오차(손실함수)의 최솟값도 찾아내어
# (손실함수가 최솟값을 가질 때 => 최적의 매개변수)
# 학습률을 끌어올리는 함수
def gradient_descent(f, init_x, lr=0.01, step_num=100): # 디폴트값
# 프린트에 함수조건 안주면 디폴트로 돌아간다.
x = init_x
for i in range(step_num):
grad = numerical_gradient(f,x) # 기울기 구하는 함수
x -= lr * grad
return x
x = np.array([3.0, 4.0])
print( gradient_descent( loss_func, init_x=x, lr=0.1, step_num=100 ) )
*lr = 러닝레이트
lr이 0.01 일 때: [ 0.39785867 0.53047822]
lr이 0.1 일 때: [ 6.11110793e-10 8.14814391e-10]
문제173. 학습율을 0.1로 변경해서 수행해보시오
러닝레이트: 0.1
lr이 0.1 일 때: [ 6.11110793e-10 8.14814391e-10]
return x.round() 시켜보면 0 이 출력된다.
0에 가까운 값이라는 걸 알 수 있다.
문제174.
러닝레이트(학습률)를 크게 주고 학습을 하면 결과가 어떻게 나오는지
확인하고 러닝레이트(학습률)를 작게 주고 학습을 하면
결과가 어떻게 나오는지 확인하시오
1. 학습률: 10 [ 2.58983747e+13 -1.29524862e+12]
2. 학습률:1e-10 [ 2.99999994 3.99999992]
너무 크거나, 너무 작은값으로 주면
1번같은 경우 global minima 에 도달하지 못하고 발산을 한다.
■ 위에서 배운 3가지 방법으로 3층 신경망을 학습 시키는 방법 구현
1. 오차함수
2. 미니배치
3. 수치미분(편미분)
■ 학습이 스스로 되는 3층 신경망 구현
문제175.
2x3 행렬을 생성하는데 값은 랜덤값으로 생성되게 하시오
import numpy as np
w = np.random.randn(2,3)
print(w)
[[ 0.63731947 -0.32702381 -0.48764098]
[-1.56229829 0.88644744 0.89773323]]
프린트 할 때 마다 값이 변한다.
문제176.
위에서 구한 w값으로 아래의 입력값 과의 행렬 내적을 출력하시오
import numpy as np
w = np.random.randn(2,3)
x = np.array([0.6,0.9])
print(np.dot(x,w))
[ 1.1661284 -0.51610649 -1.48958246]
문제177.
175번문제의 코드를 __init__ 라는 함수로 생성하시오
import numpy as np
w = np.random.randn(2,3)
print(w)
실행문: __init__()
def __init__():
import numpy as np
w = np.random.randn(2,3)
return w
print(__init__() )
문제178.
위에서 만든 가중치와 아래의 입력값을 받아
행렬을 내적하는 predict 라는 함수를 만드시오
import numpy as np
def __init__():
w = np.random.randn(2,3)
return w
def predict(x,w):
return np.dot(x, w )
x=np.array([0.6,0.9])
w=__init__()
print( predict( x,w ) )
[ 0.69548293 0.71253162 -1.03456288]
문제179.
위의 predict 함수에 나온 결과를 softmax 출력층 함수에 통과시킨
결과를 출력하시오
import numpy as np
def __init__():
w = np.random.randn(2,3)
return w
def predict(x,w):
return np.dot(x, w )
def softmax(x):
c = np.max(x)
return np.exp(x-c) / np.sum( np.exp(x - c) )
x=np.array([0.6,0.9])
w=__init__()
print(softmax(predict(x,w)))
[ 0.43801051 0.44629298 0.11569652]
문제180.
위에서 출력된 소프트맥스 함수의 결과와 아래의 target값과의 오차를
출력하기 위해 cross_entropy_error 함수를 통과한 결과를 출력하시오
import numpy as np
def __init__():
w = np.random.randn(2,3) # 평균이 0 이고 분산이 1인 여러개의
#숫자가 랜덤으로 출력됨
return w
def predict(x,w):
return np.dot(x, w )
def softmax(x):
c = np.max(x)
return np.exp(x-c) / np.sum( np.exp(x - c) )
def cross_entropy_error(y,t):
import numpy as np
delta = 1e-7 #log=0 은 에러나서 y에 델타를 더해주기 위함이다.
return -np.sum( t * np.log(y + delta ) )
t=np.array([0,0,1])
x=np.array([0.6,0.9])
w=__init__()
print(cross_entropy_error( softmax( predict(x,w) ),t ) )
문제181.(오늘의 마지막 문제)
위의 3가지 함수를 다 사용한 simpleNet 이라는 클래스를
책 134페이지를 보고 생성하고
잘 생성되었는지 확인하시오
import numpy as np
class simpleNet:
#import numpy as np #클래스안에서 넘파이 부르면 작동 안됨. 그래서 맨 위에 둠.
def __init__(self): # 랜덤의 w값을 생성한다.
self.w = np.random.randn(2,3)
#return w
def predict(self,x): # 2행3열 랜덤 w값과 x를 내적시킨다.
return np.dot(x, self.w ) #내적결과 출력
def softmax(self,x): # 출력층 함수 (확률출력)
c = np.max(x)
return np.exp(x-c) / np.sum( np.exp(x - c) )
def cross_entropy_error(self,y,t): # 분류를 위한 오차함수
import numpy as np
delta = 1e-7 #log=0 은 에러나서 y에 델타를 더해주기 위함이다.
return -np.sum( t * np.log(y + delta ) )
def loss(self, x, t): # 소프트맥스를 통과시킨 확률과, 실제 t값을
#크로스_엔트로피_오차함수에 통과시킨다.
z = self.predict(x)
y = self.softmax(z)
loss = self.cross_entropy_error(y,t)
return loss
net = simpleNet()
print(net.w)
t=np.array([0,0,1])
x=np.array([0.6,0.9])
# x를 1행2열로 주고
# __init__ 함수에서 임의로 만드는 w값은 2행3열로 제작하여
#내적시켜줌.
[[ 1.0920435 -0.5548598 1.10784619]
[ 0.91498452 0.47295498 0.87371092]]
문제191.
위의 simpleNet 클래스의 loss 함수를 실행시켜보시오
net = simpleNet()
t=np.array([0,0,1])
x=np.array([0.6,0.9])
print(net.loss(x,t))
문제192.
simpleNet 클래스의 가중치W가 몇행몇열인지 출력하시오
net = simpleNet()
print(net.w.shape)
(2, 3)
문제193.
simpleNet 클래스의 __init__함수를 가중치 w1은 784*50 으로
생성되게 하고
가중치 w2는 50*10으로 가중치가 랜덤으로 생성되게
코드를 수정하시오
def __init__(self): # 랜덤의 w값을 생성한다.
self.params = {} #가중치 초기화
self.params['w1'] = 0.01*np.random.randn(784,50)
self.params['b1'] = np.zeros(50) #numpy array로 0을 50개 채우겠다.
self.params['w2'] = 0.01*np.random.randn(50,10)
self.params['b2'] = np.zeros(10)
#은닉층 1층이 50개, 은닉층2층이 10개라서 바이어스값도 50, 10 .
※ 0.01 곱하는건 가중치 초기화에 대한 값으로 6장에서 학습함
문제194.
simpleNet 클래스의 가중치 w1과 w2의 shape을 출력하시오
print('w1',net.params['w1'].shape)
print('w1',net.params.get('w1').shape) #위 밸류갖고 오는것과 같다.
print('w2',net.params['w2'].shape)
print('b1',net.params['b1'].shape)
print('b2',net.params['b2'].shape)
w1 (784, 50)
w2 (50, 10)
b1 (50,)
b2 (10,)
문제195.
simpleNet 클래스를 객체화 시킬 때 아래와 같이 실행되게 하시오
***매번 클래스 함수값을 바꿔쓰는것보다
__init__ 함수에서 인자지정 해주면 된다.
def __init__(self , input_size = 784, hidden_size = 50, output_size = 10 ):
# 랜덤의 w값을 생성한다.
self.params = {} #가중치 초기화
self.params['w1'] = 0.01*np.random.randn(input_size,hidden_size)
self.params['b1'] = np.zeros(hidden_size) #numpy array로 0을 50개 채우겠다.
self.params['w2'] = 0.01*np.random.randn(hidden_size,output_size)
self.params['b2'] = np.zeros(output_size)
#은닉층 1층이 50개, 은닉층2층이 10개라서 바이어스값도 50, 10
# 0.01 곱하는건 가중치 초기화에 대한 값으로 6장에서 학습함
net = simpleNet()
print('w1',net.params['w1'].shape)
#print('w1',net.params.get('w1').shape) #위 밸류갖고 오는것과 같다.
print('w2',net.params['w2'].shape)
print('b1',net.params['b1'].shape)
print('b2',net.params['b2'].shape)
w1 (784, 50)
w2 (50, 10)
b1 (50,)
b2 (10,)
문제196.
predict 함수를 위의 가중치에 맞게 변경하시오
def predict(self,x): # 2행3열 랜덤 w값과 x를 내적시킨다.
w1, w2 = self.params['w1'], self.params['w2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, w1) + b1
z1 = self.sigmoid(a1)
a2 = np.dot(z1, w2) + b2
y = self.softmax(a2)
return y
문제197.
mnist 데이터 100장만 입력해서 predict 함수를 통과한 결과가
어떻게 되는지 확인하시오
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
import pickle
import numpy as np
import numpy as np
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
x, t = get_data()
net = simpleNet()#( input_size = 784, hidden_size = 50, output_size = 10 )
#net = simpleNet()
y = net.predict(x[:100])
print(y)
print(y.shape)
*소프트맥스값 10개 확률이 100개 출력됨.
(100, 10) #shape 으로 형태확인
■ accurace (정확도) 구하는 함수의 이해
"예상한 숫자와 실제숫자를 비교해서 정확도를 출력하는 함수"
예제:
def accuracy(self, x, t):
y = self.predict(x) # 10개짜리 확률벡터 100개 출력
# 100 * 10 행
- y 값의 행렬
[ [ 0.1 0.1 0.05 0.4 0.05 0.1 0.05 0.05 0.05 0.05 0.00], # 3
[ 0.4 0.1 0.05 0.1 0.05 0.1 0.05 0.05 0.05 0.05 0.00], # 0
: 100개 : 100개
: :
[ 0.1 0.1 0.05 0.4 0.05 0.1 0.05 0.05 0.05 0.05 0.00] ]
- target 의 행렬 (one hot encoding)
[ [ 0 0 1 0 0 0 0 0 0 0 ], # 2
[ 1 0 0 0 0 0 0 0 0 0 ], # 0
:
: 100개
[ 0 0 1 0 0 0 0 0 0 0 ] ]
y = np.argmax(y, axis=1) # [ 3 0 1 5 6 .......... 3 ] # 100개
t = np.argmax(t, axis=1) # [ 2 0 2 1 3 ...........3 ] # 100개
accuracy = np.sum(y == t) / float(x.shape[0])
# y랑 t 같은것만 골라서 sum 시키고
# shape[0] 으로 나눈다. (100개)
return accuracy
문제198.(위 예시 참고)
정확도를 구하는 accuracy 함수를 simpleNet 클래스에 추가하고
100장을 입력해서 정확도를 출력해보시오.
def accuracy(self, x, t):
y = self.predict(x) # 10개짜리 확률벡터 100개 출력
# 100 * 10 행
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
accuracy = np.sum(y==t) / float(x.shape[0])
return accuracy
def get_data():
(x_train, t_train) , (x_test, t_test) = \
load_mnist(normalize=True, flatten=True, one_hot_label=True)
return x_test, t_test
x, t = get_data()
net = simpleNet()#( input_size = 784, hidden_size = 50, output_size = 10 )
#net = simpleNet()
y = net.accuracy(x[:100],t[:100])
print(y)
0.15
■ numerical_gradient 함수 생성
"비용함수와 가중치 또는 바이어스를 입력받아 기울기를 출력하는 함수"
예제:
def numerical_gradient(self, x, t):
loss_W = lambda K: self.loss(x, t)
grads = {}
#
# grads['W1'] = numerical_gradient(self.loss(x,t), self.params['W1']) self.loss 바로 쓰면
# grads['b1'] = numerical_gradient(self.loss(x,t), self.params['b1']) 안나온다.
# grads['W2'] = numerical_gradient(self.loss(x,t), self.params['W2'])
# grads['b2'] = numerical_gradient(self.loss(x,t), self.params['b2'])
#
grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
■ 비용함수 생성방법
net=simpleNet(input_size = 784,hidden_size = 50, output_size =10)
def f(w):
return network.loss(x,t)
※ 설명: 135 p
여기서 정의한 f(w) 함수의 w의 의미는 더미로 만든 것입니다.
numerical_gradient(f,x) 내부에서 f(x)를 실행하는데
그와의 일관성을 위해서 f(w) 를 정의한 것입니다.
lambda 표현식으로 한 줄로 표현하면 아래와 같습니다.
f = lambda W: network.loss(x,t)
dW = numerical_gradient(f, net.W)
↑
W의 기울기
문제199.
x[0] 과 t[0] 을 입력해서 얻은 기울기 grads['W1'], grads['W2'],
grads['b1'], grads['b12] 행렬의 shape 은 각각
어떻게 되겠는가?
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from common.gradient import numerical_gradient
from PIL import Image
import pickle
import numpy as np
import numpy as np
class simpleNet:
def __init__(self, input_size, hidden_size, output_size ):
self.params = {}
self.params['W1'] =0.01 * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] =0.01 * np.random.randn(hidden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def softmax(self,a):
minus = a - np.max(a)
return np.exp(minus) / np.sum(np.exp(minus))
def sigmoid(self,num):
rst = (1 / (1 + np.exp(-num)))
return (rst)
def predict(self, x):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1
z1 = self.sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = self.softmax(a2)
return y
def cross_entropy_error(self,y,t):
delta = 1e-7
if y.ndim ==1:
t=t.reshape(1,t.size)
y=y.reshape(1,y.size)
batch_size=y.shape[0]
return -np.sum(t*np.log(y+delta)) / batch_size
def loss(self,x,t):
z = self.predict(x)
y = self.softmax(z)
return self.cross_entropy_error(y,t)
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
accuracy = np.sum(y == t) / float(x.shape[0])
return accuracy
def numerical_gradient(self, x, t):
loss_W = lambda K: self.loss(x, t)
grads = {}
#
# grads['W1'] = numerical_gradient(self.loss(x,t), self.params['W1']) self.loss 바로 쓰면
# grads['b1'] = numerical_gradient(self.loss(x,t), self.params['b1']) 안나온다.
# grads['W2'] = numerical_gradient(self.loss(x,t), self.params['W2'])
# grads['b2'] = numerical_gradient(self.loss(x,t), self.params['b2'])
#
grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
def get_data():
(x_train, t_train) , (x_test, t_test) = \
load_mnist(normalize=True, flatten=True, one_hot_label=True)
return x_test, t_test
x, t = get_data()
net=simpleNet(input_size = 784,hidden_size = 50, output_size =10)
y = net.numerical_gradient(x[0],t[0])
print(y['W1'].shape)
print(y['W2'].shape)
print(y['b1'].shape)
print(y['b2'].shape)
(784, 50)
(50, 10)
(50,)
(10,)
문제200.
지금까지 완성한 simpleNet 클래스를 가지고 만든 신경망에
훈련data 100장씩 미니배치해서 학습시키는 코드를 구현하시오
(p. 141~142)
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from common.gradient import numerical_gradient
from PIL import Image
import pickle
import numpy as np
import numpy as np
class simpleNet:
def __init__(self, input_size, hidden_size, output_size ):
self.params = {}
self.params['W1'] =0.01 * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] =0.01 * np.random.randn(hidden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def softmax(self,a):
minus = a - np.max(a)
return np.exp(minus) / np.sum(np.exp(minus))
def sigmoid(self,num):
rst = (1 / (1 + np.exp(-num)))
return (rst)
def predict(self, x):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1
z1 = self.sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = self.softmax(a2)
return y
def cross_entropy_error(self,y,t):
delta = 1e-7
if y.ndim ==1:
t=t.reshape(1,t.size)
y=y.reshape(1,y.size)
batch_size=y.shape[0]
return -np.sum(t*np.log(y+delta)) / batch_size
def loss(self,x,t):
z = self.predict(x)
y = self.softmax(z)
return self.cross_entropy_error(y,t)
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
accuracy = np.sum(y == t) / float(x.shape[0])
return accuracy
def numerical_gradient(self, x, t):
loss_W = lambda K: self.loss(x, t)
grads = {}
#
# grads['W1'] = numerical_gradient(self.loss(x,t), self.params['W1']) self.loss 바로 쓰면
# grads['b1'] = numerical_gradient(self.loss(x,t), self.params['b1']) 안나온다.
# grads['W2'] = numerical_gradient(self.loss(x,t), self.params['W2'])
# grads['b2'] = numerical_gradient(self.loss(x,t), self.params['b2'])
#
grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
def get_data():
(x_train, t_train) , (x_test, t_test) = \
load_mnist(normalize=True, flatten=True, one_hot_label=True)
return x_test, t_test
x, t = get_data()
#net=simpleNet(input_size = 784,hidden_size = 50, output_size =10)
###############################################
train_loss_list = []
iters_num = 1 #반복횟수
train_size = x.shape[0] # 60000
batch_size = 100 #미니배치
learning_rate = 0.1
network = simpleNet(input_size = 784, hidden_size = 50, output_size = 10)
for i in range(iters_num):
#미니배치 획득
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x[batch_mask]
t_batch = t[batch_mask]
grad = network.numerical_gradient(x_batch, t_batch)
# grad = network.gradient(x_batch, t_batch) #성능 개선판 !
#매개변수 갱신
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
#학습 경과 기록
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
print(train_loss_list)
■ 수치 미분을 이용한 2층 신경망 구현 코드
*신경망에 들어간 함수들
1. softmax 함수-------------------->입력값,가중치 총합을 받아
0~1 사이의 확률벡터를 출력하는 함수
2. sigmoid 함수-------------------->입력과,가중치 총합을 받아
0~1사이의 확률값을 출력하는 함수
3. predict 함수--------------------->입력층->은닉층->출력층을 구현한 함수
4. cross_entropy_error 함수--->예측값과 라벨(target)을 입력받아 오차를
출력하는 함수
5. loss 함수-------------------------->출력층->오차함수를 구현한 함수
6. accuracy 함수------------------->예측값과 라벨(target)값을 받아 정확도를 출력하는
함수
7. numerical_gradient 함수---->비용함수와 가중치를 입력받아
해당 가중치의 기울기를 출력하는 함수
8. simpleNet 클래스를 객체화 시켜서 훈련 데이터를 100장씩 입려해서
학습시키는 코드
■ 문제200번 코드설명
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
↓ ↓
6만장 6만개
(훈련 (훈련
데이터 데이터
이미지) 라벨)
# x_train = 60000 * 784 (28*28을 일렬로 죽 늘어놔서)
# t_train = 60000 * 10
train_loss_list = [] # [6.9, 6.7, 6.5,.....] 오차를 에폭마다 입력
# 하이퍼 파라미터 (신경망 학습을 최적화 하기 위해 사람이 조절해야 하는 값)
iters_num = 10000 # 반복횟수
train_size = x_train.shape[0] # x_train.shape = 60000 * 784
batch_size = 100 # 미니배치 크기
learning_rate = 0.1 # 학습률( 학습발자국 )
network = simpleNet(input_size=784, hidden_size=50, output_size=10)
for i in range(iters_num): # 10000 만약1에폭 하고 싶으면 600, 2에폭은 1200
batch_mask = np.random.choice(train_size, batch_size) # 60000, 100
#batch_mask는 0~60000 랜덤뽑은거 100개
x_batch = x_train[batch_mask] # 100 * 784
t_batch = t_train[batch_mask] # 100 * 10
grad = network.numerical_gradient(x_batch, t_batch) #오차역전파 구현 함수
#grad = network.gradient(x_batch,t_batch) #수치미분 구현 함수
#수치미분으로 돌리면 오래걸려서
#주석처리 하고, 위 grad = 오차역전파법 로 코드수행한다.
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
# 가중치, 바이어스의 기울기들을 for 문 돌리는데
# running rate 곱한 grad를 빼줌으로서
#0에 가깝게 갱신시켜준다.
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
# loss 값(오차값)이 점점 줄어드는걸 볼 수 있다. p142 그래프
# train_loss_list 에 append 시킨 이유가 그래프 그릴려고.
# 145p 보면 정확도 올라가는 걸 볼 수 있다.
문제201.
위의 train_loss_list 에 들어간 오차들을 그래프로 시각화 하면
어떻게 되겠는가?
문제202.
위의 신경망의 정확도를 시각화 하면 어떻게 되겠는가?
문제203.
위의 정확도 그래프를 실제로 파이썬 코드로 시각화 하시오
(수치미분법 말고, 오차역전파로 구현했다.
문제 200번은 수치미분으로 구현시켰는데
사진1개에 1분 걸릴만큼 오래 걸렸다.
하지만 오차역전파법은 바로바로 출력된다.)
░ 출력값:
train acc, test acc | 0.1292, 0.1342
train acc, test acc | 0.902566666667, 0.9082
train acc, test acc | 0.922083333333, 0.9238
train acc, test acc | 0.935516666667, 0.9344
train acc, test acc | 0.943633333333, 0.9451
train acc, test acc | 0.950516666667, 0.9504
train acc, test acc | 0.956283333333, 0.9537
train acc, test acc | 0.96035, 0.959
train acc, test acc | 0.964266666667, 0.9599
train acc, test acc | 0.966283333333, 0.9624
train acc, test acc | 0.9686, 0.9644
train acc, test acc | 0.970383333333, 0.9647
train acc, test acc | 0.9728, 0.9666
train acc, test acc | 0.973416666667, 0.9674
train acc, test acc | 0.97675, 0.9687
train acc, test acc | 0.976266666667, 0.9676
train acc, test acc | 0.97855, 0.9701
점점 정확도가 올라가는걸 볼 수 있다.
░ 코드:
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
from common.layers import *
from common.gradient import numerical_gradient
from collections import OrderedDict
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
# 가중치 초기화
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b2'] = np.zeros(output_size)
# 계층 생성
self.layers = OrderedDict()
self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
self.layers['Relu1'] = Relu()
self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])
self.lastLayer = SoftmaxWithLoss()
def predict(self, x):
for layer in self.layers.values():
x = layer.forward(x)
return x
# x : 입력 데이터, t : 정답 레이블
def loss(self, x, t):
y = self.predict(x)
return self.lastLayer.forward(y, t)
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
if t.ndim != 1: t = np.argmax(t, axis=1)
accuracy = np.sum(y == t) / float(x.shape[0])
return accuracy
# x : 입력 데이터, t : 정답 레이블
def numerical_gradient(self, x, t):
loss_W = lambda W: self.loss(x, t)
grads = {}
grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
def gradient(self, x, t):
# forward
self.loss(x, t)
# backward
dout = 1
dout = self.lastLayer.backward(dout)
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
# 결과 저장
grads = {}
grads['W1'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
grads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].db
return grads
# 데이터 읽기
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
# 하이퍼파라미터
iters_num = 10000 # 반복 횟수를 적절히 설정한다.
train_size = x_train.shape[0] # 60000 개
batch_size = 100 # 미니배치 크기
learning_rate = 0.1
# 그래프 그리기 위해 필요한 리스트
train_loss_list = [] # 오차를 에폭마다 담기 위한 리스트
train_acc_list = [] # 훈련데이터의 정확도를 에폭마다 담기 위한 리스트
test_acc_list = [] # 테스트 데이터의 정확도를 에폭마다 담기 위한 리스트
# 1에폭당 반복 수
iter_per_epoch = max(train_size / batch_size, 1)
#60000 / 100 , 1
#max ( 600 , 1)
# iter_per_epoch = 600
for i in range(iters_num): # 10000 , 1에폭 : 600/// 2에폭 : 1200
batch_mask = np.random.choice(train_size, batch_size)
#숫자 100개를 랜덤으로 선택해서 x_batch 와 t_batch를 구성
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 기울기 계산
#grad = network.numerical_gradient(x_batch, t_batch) #수치미분
grad = network.gradient(x_batch, t_batch) #오차 역전파
# 매개변수 갱신 (2층 신경망)
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
# 학습 경과 기록
loss = network.loss(x_batch, t_batch) # 100개 학습할 때 마다 오차를 출력
train_loss_list.append(loss) # cost 가 점점 줄어드는것을 보려고
# 1에폭당 정확도 계산
# 여기는 훈련이 아니라 1에폭 되었을때 정확도만 체크
if i % iter_per_epoch == 0: # 600%600 , 1200%600 # 600 번마다 정확도 쌓는다.
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc) # 10000/600 개 16개 # 정확도가 점점 올라감
test_acc_list.append(test_acc) # 10000/600 개 16개 # 정확도가 점점 올라감
print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))
# 그래프 그리기
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc') #정확도 plot 그래프 그림
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
문제204.
위의 코드를 수정해서 그림4-11에 해당하는 오차 그래프를 그리시오
(오차가 점점 줄어드는 그래프)
# 그래프 그리기
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_loss_list))
plt.plot(x, train_loss_list, label='train loss') #정확도 plot 그래프 그림
#plt.plot(x, train_loss_list, label='test loss', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("loss")
plt.ylim(0, 2.0) # 정확도와 다르게 범위 좀더 넓게 보려고
plt.legend(loc='upper right') #아래에 있으면 자료 가려서
plt.show()
■ 힘들게 학습시켜 만들어 놓은 가중치를 파일로 생성하는 방법
" pickle 을 이용하면 된다"
*pickle 모듈을 이용하는 예제
---리스트 데이터를 pickle 파일로 생성하는 예제
import pickle
list = ['a', 'b', 'c']
with open('d:\\list.pkl', 'wb') as f:
pickle.dump(list, f)
---pickle 파일을 파이썬으로 로드하는 예제
with open('d:\\list.pkl','rb') as f:
data = pickle.load(f)
print(data)
['a', 'b', 'c']
---이미 저자가 만들어놓은 가중치와 바이어스로 신경망을 구현하는 코드
# 가중치와 bias 값을 가져오는 함수
def init_network():
with open("sample_weight.pkl", 'rb') as f:
network = pickle.load(f)
return network
3층 신경망의 가중치와 바이어스의 pickle 파일
(w1, w2, w3, b1, b2, b3)
문제205.
방금 학습시킨 2층 신경망의 가중치와 바이어스를 two_layer_w.pkl 이라는
피클파일을 생성하시오
답:
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
import pickle
with open('d:\\two_layer_w.pkl', 'wb') as f:
pickle.dump(network.params, f)
※ 설명: 지금 생성한 pickle 파일은 2층 신경망의 가중치와 바이어스
(w1, w2, b1, b2) 의 값을 저장한 파일이다
문제206.
지난번 저자가 만들어온 가중치와 바이엇의 pickle 파일을 로드해서
만든 3층 신경망에 mnist 숫자 데이터 한장을 넣어서
인공지능이 잘 맞추는지 확인하는 코드를 다시 돌려보시오 !
#■ 저자가 이미 최적화 해놓은 W1,W2,W3,b1,b2,b3 를 가지고 만든
# 3층 신경망 코드
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
import pickle
import numpy as np
# 신경망 함수들
def sigmoid(num):
rst = (1 / (1 + np.exp(-num)))
return (rst)
def identity_function(x):
return x
def softmax(a):
c = np.max(a)
minus = a - c
exp_a = np.exp(minus)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
def init_network():
with open("C:\\Users\itwill\sample_weight\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
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
x, t = get_data()
network = init_network()
y = predict(network,x[0])
print(np.argmax(y))
print(t[0])
7
7
문제207.
위의 코드를 수정해서 지금 방금 만든 two_layer_w.pkl 파일을 로드해서
x[0] 숫자를 잘 맞추는지 확인하시오
저자가 만든 신경망 vs 우리가 만든 신경망
3층 신경망 2층 신경망
(w1,w2,w3, (w1,w2,b1,b2)
b1,b2,b3)
문제208.(점심시간 문제)
지금 pickle파일 로드해서 만든 2층 신경망에 선혜가 만든 필기체 그림을
입력해서 숫자 2 잘 맞추는지 확인하시오
#1. 흑백으로 변경
j = 'd:\\num2.png' #역슬래시 2개씩 안쓰면 에러뜸
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def rgb2gray(rgb):
return np.dot(rgb[...,:3], [0.299, 0.587, 0.114])
img = mpimg.imread(j)
gray = rgb2gray(img)
plt.imshow(gray, cmap = plt.get_cmap('gray'))
plt.show()
print(gray.shape)
#2. 입력값으로 쓰이기 위해 (784,) 로 변경해줌
a = np.array(gray)
x= a.flatten()
print(x.shape)
#3. 신경망에 넣어줌
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
import pickle
import numpy as np
# 신경망 함수들
def sigmoid(num):
rst = (1 / (1 + np.exp(-num)))
return (rst)
#def identity_function(x):
# return x
def softmax(a):
c = np.max(a)
minus = a - c
exp_a = np.exp(minus)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
def init_network():
with open("d:\\two_layer_w.pkl",'rb') as f:
#지금 이 코드는 2층 신경망
#저자가 만든 피클샘플은 3층 신경망
#그래서 내꺼 2층 신경망 피클 가져온 것.
network = pickle.load(f)
return network
def predict(network, x):
W1, W2 = network['W1'], network['W2']
b1, b2 = network['b1'], network['b2']
a1 = np.dot(x,W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1,W2) + b2
y = softmax(a2)
return y
"""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"""
#x, t = get_data() #우리가 손으로 그린 그림 넣어야 되니까
#위 get_data 함수도 안 씀. mnist 안쓰고
#우리가 만든 그림으로 학습시키니까.
network = init_network()
y = predict(network,x)
y1 = np.argmax(y)
print(y1)
#print(t[0])
(28, 28)
(784,)
5
'deeplearning' 카테고리의 다른 글
6장. 신경망을 학습시키는 여러 기술들 소개(경사하강법의 종류, 배치 정규화, 드롭아웃) (0) | 2019.03.27 |
---|---|
5장. 오차 역전파 ( 계산 그래프, 연쇄법칙, 역전파 ) (0) | 2019.03.27 |
3장. 인공 신경망 ( 신경망의 활성화 함수, 3층 신경망 구현 ) (0) | 2019.03.27 |
2장. 퍼셉트론Perceptron (0) | 2019.03.27 |
1장. deeplearning에 필요한 파이썬 기본문법 (0) | 2019.03.27 |