신경망은 가중치 매개변수의 적절한 값을 데이터로부터 자동으로 학습하는 성질이 있다.
3.1 퍼셉트론에서 신경망으로
✔️ 신경망의 예
은닉층 : 입력층, 출력층과 달리 사람 눈에 보이지 않기 때문에 은닉층
✔️ 퍼셉트론 복습
앞 장에서 배웠던 퍼셉트론을 위와 같이 표현할 수 있다.
식 3-1을 h(x)를 이용하여 식 3-5로 표현할 수 있다.
✔️ 활성화 함수의 등장
활성화함수 h(x) : 입력신호의 총합을 출력신호로 변환하는 함수
신호의 총합이 활성화를 일으키는지를 정하는 역할
3.2. 활성화 함수
✔️ 계단 함수
계단함수 : 위와 같이 임계값을 경계로 출력이 바뀌는 활성화 함수
그래서 퍼셉트론에서는 활성화 함수로 계단함수를 이용한다고 할 수 있다.
def step_function(x):
return np.array(x > 0, dtype=np.int)
✔️ 시그모이드 함수
시그모이드함수 : 신경망에서 활성화 함수로 사용하는 함수
def sigmoid(x):
return 1 / (1 + np.exp(-x))
✔️ 시그모이드 함수와 계단함수의 비교
계단함수 | 시그모이드 함수 | |
연속성 | 연속적 X (0을 기준으로 출력이 급격히 변함) |
연속적 |
출력 | 0 or 1 | 실수(입력에 비례) |
공통점 | 1. 입력이 작으면 출력이 0에 가깝고 입력이 커지면 출력이 1에 가까워진다. (즉 입력이 중요하면 큰 값 출력, 입력이 중요하지 않으면 작은 값 출력) 2. 입력이 아무리 작거나 커도 출력은 0과 1 사이다. |
✔️ 비선형 함수
계단함수와 시그모이드 함수 모두 비선형 함수이다.
신경망에서는 활성화 함수로 비선형 함수를 사용해야 한다. (선형함수를 이용하면 신경망의 층을 깊게 하는 의미가 없어지기 때문)
✔️ ReLU 함수
ReLU함수 : 입력이 0을 넘으면 그 입력을 그대로 출력하고, 0 이하이면 0을 출력하는 함수
def relu(x):
return np.maximum(0, x)
3.4. 3층 신경망 구현하기
위와 같은 3층 신경망 1층의 1번째 뉴런으로 가는 신호를 계산해보자.
✔️ 각 층의 신호 전달 구현하기
1층의 1번째 뉴런으로 가는 신호를 식 3-8과 같이 계산할 수 있다.
여기서 행렬의 내적을 이용해 1층의 가중치 부분을 간소화하면 식 3-9와 같이 표현할 수 있다.
이를 활성화함수의 처리가 된 그림으로 표현하면 그림 3-18과 같다.
이 때, 활성화 함수로 시그모이드 함수를 사용하기로 하자.
A1 = np.dot(X, W1) + B1
Z1 = sigmoid(A1)
이와 같이 1층에서 2층, 2층에서 출력층도 계산하자.
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
def identity_function(x):
return x
A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3)
이 때 항등 함수인 identity_function()을 정의하고 이를 출력층의 활성화 함수로 이용하였다.
(항듬함수는 입력을 그대로 출력하는 함수로 굳이 정의할 필요는 없으나 그동안의 흐름과 통일하기 위해 구현함)
출력층의 활성화함수는 σ()로 표시하여 은닉층의 활성화함수는 다름을 명시했다.
forward : 신호가 순방향(입력에서 출력방향)으로 전달되는 순전파
이 때까지 구현한 함수는 forward 이며, 뒷 장에서 역방향(backward)도 구현해볼 것이다.
3.5. 출력층 설계하기
신경망은 분류와 회귀 모두 이용할 수 있는데 출력층에서 사용하는 활성화 함수에 따라 달라진다.
일반적으로 회귀에는 항등함수를, 분류에는 소프트맥스함수를 사용한다.
✔️ 항등 함수
항등함수 : 입력을 그대로 출력
✔️ 소프트맥스 함수
소프트맥스(softmax) 함수 : 분자는 입력 신호의 지수함수, 분모는 모든 입력 신호의 지수함수의 합
n은 출력층의 뉴런수, y_k는 k번째 출력
분모와 같이 출력층의 각 뉴런이 모든 입력 신호에 영향을 받기 때문에 그림 3-22와 같이 모든 입력신호로부터 화살표를 받는다.
def softmax(a):
exp_a = np.exp(a)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
✔️ 소프트맥스함수 구현 시 주의할 점
여기서 소프트맥스함수를 컴퓨터로 계산할 시 오버플로 문제가 생길 수 있다.
지수함수는 쉽게 큰 값을 출력하는데 e10은 20,000이 넘고 e1000은 무한대를 뜻하는 inf가 되어 돌아온다.
이런 큰 값끼리 나눗셈을 하면 결과수치가 불안정해지기 때문에 소프트맥스함수를 개선하여 구현할 수 있다.
아래와 같이 구현할 수 있는데 이때 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 사이의 실수이다.
또한, 소프트맥스 함수 출력의 총합은 1이다.
이러한 성질 덕분에 소프트맥스 함수의 출력을 확률로 해석할 수 있다.
(아래의 출력값을 예시로 하면 74%의 확률로 2번째 클래스, 25%의 확률로 1번째 클래스)
a = np.array([0.3, 2.9, 4.0])
y = softmax(a)
print(y) # [0.01821127 0.24519181 0.73659691]
np.sum(y) # 1
소프트 맥스 함수를 적용해도 각 원소의 대소 관계는 변하지 않는다.
또한, 신경망을 이용한 분류에서는 일반적으로 가장 큰 출력을 내는 뉴런에 해당하는 클래스로만 인식한다.
따라서 신경망으로 분류할 때는 출력층의 소프트맥스 함수를 생략해도 되며, 현업에서는 지수 함수 계산에 드는 자원 낭비를 줄이기 위해 생략하는 것이 일반적이다.
✔️ 출력층의 뉴런 수 정하기
분류에서는 분류하고 싶은 클래스로 설정하는 것이 일반적이다.
예를 들어 이미지를 숫자 0부터 9 중 하나로 분류하는 문제라면 출력층의 뉴런은 10개로 설정한다.
3.6. 손글씨 숫자 인식
책에서는 MNIST 데이터셋을 활용하여 손글씨 숫자 예측을 하는 과정을 설명하였으나 이는 생략하도록 하겠다.
✔️ 배치(batch) 처리
그림 3-26은 원소 784개로 구성된 1차원 배열(원래는 28*28인 2차원 배열)이 입력되어 마지막에 원소가 10개인(숫자 0~9)인 1차원 배열로 출력되는 흐름이다.
이는 이미지 데이터를 1장만 입력했을 때의 흐름인데 이미지 여러 장을 한꺼번에 입력하는 경우를 생각해보자.
x의 형상을 100*784로 바꿔 이미지 100개를 묶어 하나의 입력데이터로 표현하면 될 것이다.
출력 데이터는 100*10이 되며, 이미지 100개의 결과가 한 번에 출력됨을 나타낸다.
x[0], y[0]은 0번째 이미지와 추론 결과, x[1], y[1]은 1번째 이미지와 추론 결과이다.
이처럼 하나로 묶은 입력 데이터를 배치(batch)라고 한다.
배치처리를 할 경우 이미지 1장당 처리 시간을 대폭 줄일 수 있다.
데이터를 읽는 횟수가 줄어 빠른 CPU나 GPU로 순수 계산을 수행하는 비율이 높아지기 때문에 버스에 주는 부하를 줄일 수 있다.
즉, 배치처리를 수행함으로써 큰 배열로 이뤄지는 계산을 하게 되는데, 수치계산 라이브러리 대부분은 큰 배열을 효율적으로 처리할 수 있도록 최적화 되어있기 때문에 컴퓨터는 큰 배열을 한꺼번에 계산하는 것이 작은 배열을 여러번 계산하는 것보다 빠르다.
# batch 처리 전
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
# batch 처리 후
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])
3.7. 정리
- 신경망에서는 활성화 함수로 시그모이드 함수와 ReLU함수 같은 매끄럽게 변화하는 함수를 이용한다.
- 넘파이의 다차원 배열을 잘 사용하면 신경망을 효율적으로 구현할 수 있다.
- 기계학습 문제는 크게 회귀와 분류로 나눌 수 있다.
- 출력층의 활성화 함수로는 회귀에서는 주로 항등함수를, 분류에서는 주로 소프트맥스 함수를 이용한다.
- 분류에서는 출력층의 뉴런 수를 분류하려는 클래스 수와 같게 설정한다.
- 입력 데이터를 묶은 것을 배치라 하며, 추론 처리를 이 배치 단위로 진행하면 결과를 훨씬 빠르게 얻을 수 있다.
참고 git : https://github.com/geonsangyoo/DeepLearning/tree/master
'Deep Learning' 카테고리의 다른 글
[밑바닥부터시작하는딥러닝1] Chapter 7. 합성곱 신경망(CNN) (0) | 2024.04.13 |
---|---|
[밑바닥부터시작하는딥러닝1] Chapter 6. 학습관련기술들 (0) | 2024.04.12 |
[밑바닥부터시작하는딥러닝1] Chapter 5. 오차역전파법 (0) | 2024.04.05 |
[밑바닥부터시작하는딥러닝1] Chapter 4. 신경망 학습 (0) | 2024.04.04 |
[밑바닥부터시작하는딥러닝1] Chapter 2. 퍼셉트론 (0) | 2024.04.02 |