딥러닝 / 다차원 배열, 3층신경망 구현, 소프트맥스 함수
6 다차원 배열의 계산 - p.77
신경망에 들어가는 데이터는 다차원 배열입니다. 다차원 배열이 신경망에 들어가서 행렬 계산을 하기 때문에 다차원 배열에 대한 이해가 있어야합니다. 사진, 동영상 모두 다차원 배열입니다.
ex. 이미지는 다차원 배열로 이루어짐(28x28 784개의 숫자로 이루어진 필기체 5의 이미지 데이터)
mnist 필기체 데이터중에 하나로 하나의 픽셀이 0~255사이의 숫자로 되어 있고 숫자값이 클 수록 밝은색, 0에 가까울수록 어두운 색입니다.
예제1. 1차원 배열 만들기
import numpy as np
a = np.array([1,2,3,4])
print(np.ndim(a)) # np.ndim() 차원확인 == 1차원이라 1 나옴
예제2. 위의 1차원 배열에서 숫자 4를 출력하시오.
import numpy as np
a = np.array([1,2,3,4])
a[3] #4
예제3. 2차원 배열을 생성하고 차원을 확인하시오.
b = np.array([1,2,3,4,5,6]).reshape(3,2)
np.ndim(b) #2
예제4. 3차원 배열을 생성하고 차원을 확인하시오.
# c = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
c = np.array([1,2,3,4,5,6,7,8]).reshape(2,2,2)
np.ndim(c) #3
c
예제5. 위의 3차원 배열에서 숫자5를 출력하시오.
c = np.array([1,2,3,4,5,6,7,8]).reshape(2,2,2)
c[1,0,0] #5
문제27. 행렬의 내적을 구현하시오.
a = np.array([1,2,3,4]).reshape(2,2)
b = np.array([5,6,7,8]).reshape(2,2)
np.dot(a,b)
# array([[19, 22],
# [43, 50]])
7 행렬의 내적
다차원 배열을 곱하려면 두 행렬의 대응하는 차원의 원소를 일치시켜야 합니다.
a = np.array([2,4,3,3,3,2]).reshape(3,2)
b = np.array([3,1,9,2,1,4,7,3]).reshape(2,4)
print(np.dot(a,b))
# [[10 18 46 16]
# [12 15 48 15]
# [11 11 41 12]]
문제28. 두 행렬의 대응하는 차원의 원소를 틀리게 해서 내적하는 실험을 하시오.
ValueError: shapes (3,2) and (4,2) not aligned: 2 (dim 1) != 4 (dim 0)
=> 내적하는 두 행렬의 차원이 일치하지 않아 에러발생.
문제29. 신경망 내적을 구현해서 y행렬을 출력하시오.
x = np.array([1,2]).reshape(1,2)
y = np.array([1,3,5,2,4,6]).reshape(2,3)
print(np.dot(x,y)) #[[ 5 11 17]]
8 3층신경망 구현하기
예제1. 3층 신경망에서 입력 -> 은닉1층까지만 코드로 구현하시오.
import numpy as np
# 시그모이드 함수 생성
def sigmoid(x):
return 1 / (1+np.exp(-x))
# 입력층
x = np.array([1,2]).reshape(1,2)
# 은닉1층
w1 = np.array([1,3,5,2,4,6]).reshape(2,3)
y = np.dot(x,w1) #입력값과 가중치를 내적
y_hat = sigmoid(y)
print(y_hat) #[[0.99330715 0.9999833 0.99999996]]
예제2. 입력층 -> 은닉1층 -> 은닉2층까지 구현하시오.
import numpy as np
# 시그모이드 함수 생성
def sigmoid(x):
return 1 / (1+np.exp(-x))
# 입력층
x = np.array([1,2]).reshape(1,2)
# 은닉1층
w1 = np.array([1,3,5,2,4,6]).reshape(2,3)
y = np.dot(x,w1) #입력값과 가중치를 내적
y_hat = sigmoid(y)
#은닉2층
w2 = np.array([3,4,5,6,7,8]).reshape(3,2)
z = np.dot(y_hat,w2)
z_hat = sigmoid(z)
print(z_hat) #[[0.99999969 0.99999998]]
예제3. 입력층 -> 은닉1층 -> 은닉2층 -> 출력층까지 구현하시오.
import numpy as np
# 시그모이드 함수 생성
def sigmoid(x):
return 1 / (1+np.exp(-x))
# 입력층
x = np.array([1,2]).reshape(1,2)
# 은닉1층
w1 = np.array([1,3,5,2,4,6]).reshape(2,3)
y = np.dot(x,w1) #입력값과 가중치를 내적
y_hat = sigmoid(y)
#은닉2층
w2 = np.array([3,4,5,6,7,8]).reshape(3,2)
z = np.dot(y_hat,w2)
z_hat = sigmoid(z)
#출력층
w3 = np.array([4,5,6,7]).reshape(2,2)
k = np.dot(z_hat,w3)
print(k) #[[ 9.99999866 11.99999833]]
문제30. 은닉1층과 은닉2층의 활성화 함수를 sigmoid함수가 아닌 relu함수로 변경하고 전체코드를 실행하시오.
import numpy as np
# relu함수
def relu(x):
return np.maximum(0,x) # 0과 x값 중에서 큰 값을 반환
# 입력층
x = np.array([1,2]).reshape(1,2)
# 은닉1층
w1 = np.array([1,3,5,2,4,6]).reshape(2,3)
y = np.dot(x,w1) #입력값과 가중치를 내적
y_hat = relu(y)
#은닉2층
w2 = np.array([3,4,5,6,7,8]).reshape(3,2)
z = np.dot(y_hat,w2)
z_hat = relu(z)
#출력층
w3 = np.array([4,5,6,7]).reshape(2,2)
k = np.dot(z_hat,w3)
print(k) #[[2088 2499]]
9 출력층 설계하기 - p.90
출력층의 함수는 그동안 흘러왔던 확률들의 숫자를 취합해서 결론을 내주는 함수
기계학습 문제는 "분류"와 "회귀"로 나뉩니다. 분류는 데이터가 어느 클래스에 속하느냐는 문제. 사진 속 인물의 성별을 분류하는 문제가 여기에 속합니다. 한편 회귀는 입력 데이터에서 수치를 예측하는 문제. 사진 속 인물의 몸무게가 57.4kg일것이다라고 예측하는 문제가 바로 회귀.
1. 분류 예측 신경망 : 출력층의 함수를 소프트 맥스 함수 사용
소프트맥스 : 입력값을 받아서 확률벡터를 출력하는 함수
ex. [0.8,0.2] <- [개일 확률, 고양이일 확률]
2. 수치 예측 신경망 : 출력층의 함수를 항등함수 사용
항등함수? 입력값을 받아서 그대로 출력하는 함수
def identity_func(x):
return x
10 출력층 함수 소프트 맥스 함수 구현하기
소프트 맥스 함수는 분류를 하기 위해 확률 벡터를 출력하는 함수.
위의 식을 파이썬으로 구현해볼텐데 위의 식을 그대로 파이썬 코드로 구현하면 에러가 나서 구현이 안됨. 왜냐하면 자연상수 e의 지수함수는 쉽게 아주 큰 값을 출력하기 때문에 컴퓨터는 큰 값을 출력하게 되면 overflos가 출력되면서 에러남.
ex. 에러 나는지 실험해보기
print(np.exp(10)) #22026.465794806718
print('%f'%np.exp(100)) #26881171418161356094253400435962903554686976.000000
print(np.exp(1000)) #inf 무한대라고 뜸
자연상수 e의 1000승은 무한대를 뜻하는 inf가 출력됨.
그래서 컴퓨터로 계산할 수 없음.
# 개, 고양이, 말을 분류하는 신경망이라고 가정하고 다음과 같이 k값을 출력한다면
import numpy as np
k = np.array([1010,1000,990])
print(np.exp(k)) #[inf inf inf]
위와 같이 에러가 나므로 에러가 안나게 하기 위해서는 위개 3개 값중에 가장 큰 값으로 이 3개의 숫자들을 각각 뺍니다.
k = np.array([1010,1000,990])
k - max(k) #array([ 0, -10, -20])
# 예제
k = np.array([100,90,80])
k_max = k - max(k) #array([ 0, -10, -20])
print(np.exp(k)/sum(np.exp(k))) #[9.99954600e-01 4.53978686e-05 2.06106005e-09]
print(np.exp(k_max) /sum(np.exp(k_max)))
가장큰 값으로 빼서 계산하면 확률값이 동일하게 나옴.
위의 코드를 softmax함수로 구현합니다.
def softmax(k):
C = np.max(k)
minus = k - C
np_exp = np.exp(minus)
sum_exp_k = np.sum(np_exp)
y = np_exp / sum_exp_k
return y
k = np.array([1010,1000,990])
print(softmax(k)) #[9.99954600e-01 4.53978686e-05 2.06106005e-09]
문제31. 위에서 출력된 값들을 다 더하면 1이 맞는지 확인하시오.
def softmax(k):
C = np.max(k)
minus = k - C
np_exp = np.exp(minus)
sum_exp_k = np.sum(np_exp)
y = np_exp / sum_exp_k
return y
k = np.array([1010,1000,990])
result = softmax(k)
print(np.sum(result)) #1.0
문제32. 문제30번에서 만든 3층 신경망 전체 코드에 출력층 쪽에 지금 만든 softmax함수를 넣어서 확률이 출력되게 하시오.
import numpy as np
# relu함수
def relu(x):
return np.maximum(0,x) # 0과 x값 중에서 큰 값을 반환
# softmax함수
def softmax(k):
C = np.max(k)
minus = k - C
np_exp = np.exp(minus)
sum_exp_k = np.sum(np_exp)
y = np_exp / sum_exp_k
return y
# 입력층
x = np.array([1,2]).reshape(1,2)
# 은닉1층
w1 = np.array([1,3,5,2,4,6]).reshape(2,3)
y = np.dot(x,w1) #입력값과 가중치를 내적
y_hat = relu(y)
#은닉2층
w2 = np.array([3,4,5,6,7,8]).reshape(3,2)
z = np.dot(y_hat,w2)
z_hat = relu(z)
#출력층
w3 = np.array([4,5,6,7]).reshape(2,2)
k = np.dot(z_hat,w3)
k_hat = softmax(k)
print(k_hat) #[[3.19865896e-179 1.00000000e+000]]
문제33. 위의 출력된 k_hat의 확률중에서 어떤값이 더 큰지 그 큰 요소의 인덱스 번호를 출력하시오.
#출력층
w3 = np.array([4,5,6,7]).reshape(2,2)
k = np.dot(z_hat,w3)
k_hat = softmax(k)
print(np.argmax(k_max)) #k_hat 중 가장 큰 값을 갖는 인덱스 번호 출력
np.argmax함수는 numpy 리스트의 요소중 가장 큰 값의 인덱스 번호를 출력하는 함수
문제34. 오늘 배운 내용으로 아래의 신경망을 구현하시오.
import numpy as np
# 시그모이드 함수
def sigmoid(x):
return 1 / (1+np.exp(-x))
# softmax함수
def softmax(k):
C = np.max(k)
minus = k - C
np_exp = np.exp(minus)
sum_exp_k = np.sum(np_exp)
y = np_exp / sum_exp_k
return y
# 입력층
x = np.array([7,12]).reshape(1,2)
# 은닉1층
w1 = np.array([3,6,9,2,4,8]).reshape(2,3)
y = np.dot(x,w1) #입력값과 가중치를 내적
y_hat = sigmoid(y)
#출력층
w2 = np.array([7,6,5,4,3,2]).reshape(3,2)
k = np.dot(y_hat,w2)
k_hat = softmax(k)
print(k_hat) #[[0.95257413 0.04742587]]