2022.07.18 책 구매 ~ 2022.07.28 책 완독
기억했으면 하는 것들을 위주로 기록
1장 헬로파이썬
기본적인 파이썬 문법을 설명한다. python3 을 기준으로 작성된 소스코드들.
넘파이: 넘파이는 배열이나 행렬 계산에 용이한 메서드들이 준비되어있는 외부 라이브러리
원소별: element-wise
원소별 곱셈: element-wise product
* 논문에 종종 나오는 것 봤던 기억이 있습니다. 이제야 뜻을 정확히 알게 된 것 같아 속이 시원하네요
브로드캐스트: 형상이 다른 배열끼리도 계산할 수 있도록 지원하는 기능
ex) 2 x 2 행렬에 스칼라 값 10 을 곱할 수 있게 합니다. 스칼라 값 10이 2x2 행렬로 확대됩니다.
1 2 * 10 = 1 2 * 10 10 = 10 20
3 4 3 4 10 10 30 40
1 2 * 10 20 = 1 2 * 10 20 = 10 40
3 4 3 4 10 20 30 80
bool 배열: 넘파이 배열에 부등호 연산을 수행 시, 배열의 원소 각각에 부등호 연산을 수행한 bool 배열이 생성됩니다.
X = X.flatten()
print(X)
# [51 55 14 19 0 4]
X[np.array([0, 2, 4])]
# array([51, 14, 0])
X > 15
# array([True, True, False, True, False, False], dtype=bool)
X[X>15]
# array([51, 55, 19])
matplotlib: 그래프를 그려주는 라이브러리
pyplot: 그래프를 그려주는 matplotlib의 모듈
2장 퍼셉트론
신경망의 기원이 되는 알고리즘
(단순) 퍼셉트론(혹은 인공 뉴런): 다수의 신호를 입력으로 받아 하나의 신호를 출력합니다. 흐름을 만들고 정보를 앞으로 전달합니다. 앞으로는 1을 신호가 흐른다, 0을 신호가 흐르지 않는다는 의미로 사용.
퍼셉트론 알고리즘:
x1 --w1-->
y
x2 --w2-->
^ ^
입력신호 가중치: 복수의 입력 신호 각각에 고유한 가중치 부여, 각 신호가 결과에 주는 영향력을 조절하는 요소, 클수록 중요함!
뉴런, 노드
뉴런에서 보내온 신호의 총합이 정해진 한계(임계값, theta, 세타)을 넘어설 때만 1을 출력
진리표: 입력 신호와 출력 신호의 대응 표
퍼셉트론으로 표현하고 싶을 때는 진리표대로 작동하도록 하는 w1, w2, theta 의 값을 정하면 된다.
AND 게이트 진리표
x1 x2 y
0 0 0
1 0 0
0 1 0
1 1 1
(w1, w2, theta) = (0.5, 0.5, 0.7), (1.0, 1.0, 1.0)
NAND 게이트: Not AND, AND 게이트의 출력을 뒤집은 것
NAND 게이트 진리표
x1 x2 y
0 0 1
1 0 1
0 1 1
1 1 0
(w1, w2, theta) = (-0.5, -0.5, -0.7)
OR 게이트 진리표
x1 x2 y
0 0 0
1 0 1
0 1 1
1 1 1
(w1, w2, theta) = (0.5, 0.5, 0.2)
퍼셉트론의 구조는 AND, NAND, OR 게이트 모두에서 똑같다. 다른 것은 매개변수(가중치와 임계값) 뿐.
퍼셉트론 구현
def AND(x1, x2):
w1, w2, theta = 0.5, 0.5, 0.7
tmp = x1*w1 + x2*w2
if tmp <= theta:
return 0
elif tmp > theta:
return 1
가중치와 편향 도입
theta를 -b로 치환. b는 편향.
퍼셉트론은 입력 신호에 가중치를 곱한 값과 편향을 합하여, 그 값이 0을 넘으면 1을 출력, 그렇지 않으면 0을 출력
가중치와 편향 구현
def AND(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
def NAND(x1, x2):
x = np.array([x1, x2])
w = np.array([-0.5, -0.5])
b = 0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
def OR(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.2
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
퍼셉트론의 한계
XOR 게이트: 배타적 논리합. 한쪽이 1일 때만 1을 출력
퍼셉트론은 직선 하나로 나눈 영역만 표현할 수 있다는 한계가 있음
비선형 영역: 곡선 영역
선형 영역: 직선 영역
다층 퍼셉트론: 층이 여러 개인 퍼셉트론
층을 쌓아 퍼셉트론으로 XOR 게이트를 표현할 수 있습니다. 단층 퍼셉트론으로는 표현하지 못한 것을 층을 하나 늘려 구현 할 수 있었습니다.
기존 게이트를 조합하여 XOR 게이트를 표현할 수 있다. 입력은 NAND, OR 게이트로, 이들의 출력이 AND 게이트의 입력으로 이어지면 가능합니다.
XOR 게이트의 진리표
x1 x2 s1 s2 y
0 0 1 0 0
1 0 1 1 1
0 1 1 1 1
1 1 0 1 0
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
y = AND(s1, s2)
return y
3장 신경망
퍼셉트론으로는 복잡한 함수도 표현 가능, 그러나 가중치를 설정하는 값은 여전히 사람이 수동으로 해야 함
신경망은 이러한 것을 해결하는, 가중치 매개변수의 적절한 값을 데이터로부터 자동으로 학습하는 능력이 있다.
입력층, 은닉층: 사람 눈에 보이지 않음, 출력층: 0층, 1층, 2층. 여기서는 층의 개수 = 입력+은닉+출력층의 합계 - 1
b: 편향, 뉴러닝 얼마나 쉽게 활성화되느냐를 제어
w1, w2: 가중치, 각 신호의 영향력을 제어
y = h(b + w1x1 + w2x1)
h(x) = 0 (x <= 0)
1 (x > 0)
활성화 함수
a = b + w1x1 + w2x2
y = h(a)
활성화 함수의 처리 과정
1 --b--> h()
x1 --w1--> a -> y
x2 --w2-->
계단 함수: 임계값을 경계로 출력이 바뀌는 함수
신경망에서 이용하는 활성화 함수
시그모이드 함수
def step_function(x):
if x > 0:
return 1
else:
return 0
def step_function(x):
y = x > 0
return y.astype(np.int)
def sigmoid(x):
return 1 / (1 + np.exp(-x))
계단함수와 시그모이드 함수의 공통점으로는
큰 관점에서 보면 둘은 같은 모양, 둘 다 입력이 작을 때의 출력은 0에 가깝고 혹은 0이고, 입력이 커지면 출력이 1에 가까워지는 혹은 1이 되는 구조. 출력은 0에서 1사이라는 것. 둘 모두 비선형 함수
비선형 함수는 선형이 아닌 함수, 직선 1개로는 그릴 수 없는 함수
신경망에서는 선형 함수를 사용하지 못하는 이유 ? 신경망의 층을 깊게 하는 의미가 없어지기 때문에.
층을 아무리 깊게 해도 '은닉층이 없는 네트워크'로도 똑같은 기능을 할 수 있다는 데에 문제가 있다.
Example). H(x) = cx, y(x) = h(h(h(x))), y(x) = c^3 = ax
ReLU 함수 : 입력이 0을 넘으면 그 입력을 그대로 출력하고, 0이하이면 0을 출력하는 함수
def relu(x):
return np.maximum(0, x)
다차원배열
2차원 배열: 행렬, 가로방향을 행, 세로방향을 열
행렬곱: np,dot(A, B)
행렬 곱에서는 대응하는 차원의 원소 수를 일치시켜야 한다.
3층 신경망 구현
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
def identity_function(x):
return x
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y) # [0.31682708, 0.69627909]
출력층 설계하기
항등 함수: identity function: 입력을 그대로 출력합니다. 입력과 출력이 항상 같다는 뜻의 항등
소프트맥스 함수: softmax function: 모든 입력 신호로부터 화살표를 받음. 출력층의 각 뉴런이 모든 입력 신호에서 영향을 받기 때문.
오버 플로 문제가 있어서 지수함수를 사용할 때 쉽게 아주 큰 값을 내뱉게 되어 무한대로 돌아오게 되어 수치가 불안정해집니다.
개선한 수식은 입력 신호 중 최댓값을 이용하여 C에 대입하여 오버플로를 막는 것이 일반적입니다.
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
출력은 0에서 1.0 사이의 실수. 출력의 총합은 1.
출력의 총합이 1인 덕분에 소프트맥스 함수의 출력을 확률로 해석할 수 있습니다. 문제를 확률적(통계적)으로 대응 할 수 있게 됩니다.
분류에서는 일반적으로 가장 큰 출력을 내는 뉴런에 해당하는 클래스로만 인식하기에 현업에서는 지수 함수 계산에 드는 낭비를 줄이고자 출력층의 소프트매긋 함수는 생략하는 것이 일반적.
출력층의 뉴런 수를 분류에서는 분류하고 싶은 클래스 수로 설정하는 것이 일반적.
MNIST 데이터셋으로 손글씨 숫자 인식해보기
def get_data():
(x_train, t_train), (x_test, y_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
x, t = 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 == t[i:i+batch_size])
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
배치: Batch: 하나로 묶은 입력 데이터
정규화: Normalization: 데이터를 특정 범위로 변환하는 처리
전처리: pre-processing: 신경망의 입력 데이터에 특정 변환을 가하는 것
4장 신경망 학습
데이터가 이끄는 접근 방식 덕에 사람 중심 접근에서 벗어날 수 있다.
입력 데이터에서 본질적인 데이터를 정확하게 추출할 수 있도록 설계된 변환기: 특징, 이미지에서 특징 feature 를 추출하다
이미지의 특징은 보통 벡터로 기술.
컴퓨터 비전 분야에서는 SIFT, SURF, HOG 등의 특징을 사용하여 이미지를 벡터 데이터로 변환하고, 지도학습 방식의 대표 분류 기법은 SVN, KNN 등으로 학습합니다.
첫번째 : 사람이 생각한 알고리즘 -> 결과
두번째 : 사람이 생각한 특징(SIFT, HOG) -> 기계학습(SVN, KNN) -> 결과
세번째 : 신경망(딥러닝) -> 결과
딥러닝을 end-to-end machine learning 이라고도 합니다.
훈련 데이터 training data, 시험 데이터 test data : 범용 능력을 평가하기 위해 분리
한 데이터셋에만 지나치게 최적화된 상태: overfitting 오버피팅
신경망 학습에서 사용하는 지표: 손실함수 loss function
손실함수 두 가지 - 오차제곱합, 교차 엔트로피 오차
오차제곱합 sum of squares for error, SSE
한 원소만 1로 하고 그 외는 0으로 나타내는 표기법: 원-핫 인코딩
def sum_squares_error(y, t):
return 0.5 * np.sum((y-t)**2)
오차제곱합은 각 원소의 출력(추정 값)과 정답 레이블(참 값)의 차를 제곱한 후, 그 총합을 구합니다.
교차 엔트로피 오차 cross entropy error, CEE
실질적으로 정답일 때의 추정의 자연로그를 계산하는 식.
정답일 때의 출력이 전체 값을 정하게 됩니다
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
Delta 는 np.log() 함수에 0을 입력 시 -inf 가 되는 것이 발생하지 않도록 하기 위한 것.
훈련 데이터로부터 일부만 골라 학습을 하는 것: 미니배치 mini-batch 학습
손실함수를 사용하는 이유?
'공부 > 단행본' 카테고리의 다른 글
[컴퓨터 비전] Chapter 03 에지 검출 (0) | 2022.02.11 |
---|---|
[컴퓨터 비전] Chapter 02 영상 처리 (0) | 2022.02.11 |
[컴퓨터 비전] Chapter 01 소개 (0) | 2022.02.11 |
데이터중심의 어플리케이션 설계 2장 (0) | 2022.01.02 |
데이터중심의 어플리케이션 설계 1장 (0) | 2021.12.30 |