[핸즈온 머신러닝] 10장. 케라스를 사용한 인공 신경망 소개 (1)
본 글은 [핸즈온 머신러닝 2판 (Hands-On Machine Learning with Scikit-Learn, keras & TensorFlow)] - (박해선 옮김) 책을 개인공부하기 위해 요약, 정리한 내용입니다.
전체 코드는 https://github.com/ingu627/handson-ml2에 기재했습니다.(원본 코드 fork)
뿐만 아니라 책에서 설명이 부족하거나 이해가 안 되는 것들은 외부 자료들을 토대로 메꿔 놓았습니다.
오타나 오류는 알려주시길 바라며, 도움이 되길 바랍니다.
10장. 케라스를 사용한 인공 신경망 소개
- 지능적인 기계를 만드는 법에 대한 영감을 얻으려면 뇌 구조를 살펴보는 것이 합리적이다. 이는 인공 신경망(ANN; Artificial Neural Network)을 촉발시킨 근원이다.
- 인공 신경망은 뇌에 있는 생물학적 뉴런의 네트워크에서 영감을 받은 머신러닝 모델이다.
- 요즈음에는
뉴런
(neuron) 대신유닛
(unit)으로 부른다.
- 요즈음에는
- 케라스는 신경망 구축, 훈련, 평가, 실행을 목적으로 설계된 멋지고 간결한 고수준 API이다.
10.1 생물학적 뉴런에서 인공 뉴런까지
이미지 출처1
- 예전과는 다르게 인공 신경망이 우리 생활에 훨씬 커다란 영향을 줄 것이라는 믿을 만한 근거가 몇가지 있다.
- 신경망을 훈련하기 위한 데이터가 엄청나게 많아졌다. 인공 신경망은 종종 규모가 크고 복잡한 문제에서 다른 머신러닝 기법보다 좋은 성능을 낸다.
- 1990년대 이후 컴퓨터 하드웨어가 크게 발전했다. 덕분에 납득할 만한 시간 안에 대규모 신경망을 훈련할 수 있다. 또한 수백만 개의 강력한 GPU 카드를 생산해내는 게임 산업 덕분이기도 하고 클라우드 플랫폼은 이런 강력한 도구를 손쉽게 사용할 수 있는 환경을 제공한다.
10.1.2 뉴런을 사용한 논리 연산
이미지 출처2
- 이 세포는 핵을 포함하는 세포체와 복잡한 구성 요소로 이루어져 있다.
- 수상돌기라는 나뭇가지 모양의 돌기와 축삭돌기라는 아주 긴 돌기 하나가 있다. 축삭돌기의 끝은 축삭끝가지라는 여러 가지로 나뉘고, 이 가지 끝은 시냅스 말단이라는 미세한 구조이며 다른 뉴런의 수상돌기나 세포체에 연결된다.
-
다시 정리하면 각각의 뉴런은 수상돌기를 통해 다른 뉴런에서 입력 신호를 받아서 축색돌기를 통해 다른 뉴런으로 신호를 내보낸다. 시냅스는 뉴런과 뉴런을 연결하는 역할을 한다. 출력신호는 입력된 신호가 모여서 일정한 용량을 넘어설 때 일어난다.3
- Dendrite : 수상돌기, 다른 뉴런으로부터 신호를 수용하는 부분
- Axon : 축삭돌기, 신호를 내보내는 부분
- Synaptic terminals : 시냅스(synapse) 뉴런의 접합부, 다른 뉴런으로 부터 짧은 전기 자극 신호(signal)를 받음
10.1.2 뉴런을 사용한 논리 연산
- 인공 뉴런 모델은 하나 이상의 이진(on/off) 입력과 이진 출력 하나를 가진다.
- 인공 뉴런은 단순히 입력이 일정 개수만큼 활성화되었을 때 출력을 내보낸다.
- ①은 항등함수를 의미하며, 뉴런 A가 활성화 되면 뉴런 C 또한 활성화된다.
- ②는 논리곱 연산을 의미하며, 뉴런 A와 B가 모두 활성화될 때만 뉴런 C가 활성화된다.
- ③은 논리합 연산을 의미하며, 뉴런 A와 B 둘 중 하나라도 활성화되면 C가 활성화된다.
- ④는 어떤 입력이 뉴런의 활성화를 억제할 수 있다고 가정하면, 위의 그림에서 처럼 뉴런 A가 활성화 되고 B가 비활성화될 때 뉴런 C가 활성화된다.4
10.1.3 퍼셉트론
- 퍼셉트론은 가장 간단한 인공 신경망 구조 중 하나이다.
- 퍼셉트론은 TLU(Threshold Logic Unit)이라는 형태의 뉴런을 기반으로 하며, 아래의 그림과 같이 입력과 출력이 어떤 숫자고 각각의 입력에 각각 고유한 가중치($W$, weight)가 곱해진다.
- TLU는 입력의 가중치 합을 계산 ($z = w_1x_1 + w_2x_2 + … + w_nx_n = x^tw$)한 뒤 계산된 합에 계단 함수(step function)를 적용하여 결과를 출력한다. 즉, $h_w(x) = step(z)$, 여기에서 $z=x^tw$이다.
-
퍼셉트론에서 가장 널리 사용되는 계단 함수는 헤비사이드 계단 함수(Heaviside step function)이다. 부호 함수(sign function)를 대신 사용하기도 한다.
- $heaviside(z) = 0 \quad z<0일때$
$\qquad \qquad \qquad \quad 1 \quad z\ge0일때$ - $sgn(z) = -1 \quad z<0일때$
$ \qquad \qquad \quad 0 \quad z=0일때 $
$ \qquad \qquad \ +1 \quad z>0일때$
- $heaviside(z) = 0 \quad z<0일때$
- 하나의 TLU는 간단한 선형 이진 분류 문제에 사용할 수 있다. 입력의 선형 조합을 계산해서 그 결과가 임곗값을 넘으면 양성 클래스를 출력한다. 그렇지 않으면 음성 클래스를 출력한다. (로지스틱 회귀나 선형 SVM 분류기처럼)
- TLU를 훈련한다는 것은 최적의 $w_0, w_1, w_2$를 찾는다는 뜻이다.
- 퍼셉트론은 층이 하나뿐인 TLU로 구성된다. 각 TLU은 모든 입력에 연결되어 있다. 한 층에 있는 모든 뉴런이 이전 층의 모든 뉴런과 연결되어 있을 때 이를 완전 연결 층 또는 밀집 층이라고 부른다.
- 입력층 (input layer)은 모두 입력 뉴런으로 구성된다. 보통 여기에 편향 특성이 더해진다.
- 위 그림은 입력 두 개와 출력 세 개로 구성된 퍼셉트론이다. 이 퍼셉트론은 샘플을 세 개의 다른 이진 클래스로 동시에 분류할 수 있으므로 다중 레이블 분류기(multilabel classifier)이다.
- 완전 연결 층의 출력 계산 : $h_{W,b}(X) = \phi(XW + b)$
- $X$ : 입력 특성의 행렬을 나타냄
- 이 행렬의 행은 샘플, 열은 특성
- $W$ : 가중치 행렬. 편향 뉴런을 제외한 모든 연결 가중치를 포함
- 이 행렬의 행은 입력 뉴런에 해당하고 열은 출력층에 있는 인공 뉴런에 해당
- $b$ : 편향 벡터. 편향 뉴런과 인공 뉴런 사이의 모든 연결 가중치를 포함
- 인공 뉴런마다 하나의 편향 값이 있다.
- $\phi$ : 활성화 함수 (activation function)
- $X$ : 입력 특성의 행렬을 나타냄
- 두 뉴런이 동일한 출력을 낼 때마다 이 둘 사이의 연결 가중치가 증가하며 이러한 규칙을 헤브의 규칙 또는 헤브 학습(Hebbian Learning)이라고 한다. (
퍼셉트론 훈련
) - 퍼셉트론은 네트워크가 예측할 때 만드는 오차를 반영하도록 조금 변형된 규칙을 사용하여 훈련된다. 퍼셉트론 학습 규칙은 오차가 감소되도록 연결을 강화시킨다.
- 퍼셉트론은 네트워크가 만드는 에러를 반영하도록 학습되며 잘못된 출력을 만드는 연결은 올바른 출력을 만들 수 있도록 가중치를 조정한다.
- 퍼셉트론 학습 규칙(가중치 업데이트)
- $w_{\rm i,j}^{\rm next\ step} = w_{\rm i,j} + \eta(y_j - y_j)\hat x_i$
- $w_{\rm i,j}$: $i$번째 입력 뉴런과 $j$번째 출력 뉴런 사이를 연결하는 가중치
- $x_i$ : 현재 학습 데이터 샘플의 $i$번째 뉴런의 입력값
- $\hat y$ : 현재 학습 데이터 샘플의 -번째 출력 뉴런의 출력값
- $y_i$ : 현재 학습 데이터 샘플의 -번째 출력 뉴런의 실제값
- $\eta$ : 학습률, learning rate
- $w_{\rm i,j}^{\rm next\ step} = w_{\rm i,j} + \eta(y_j - y_j)\hat x_i$
- 각 출력 뉴런의 결정 경계는 선형이므로 퍼셉트론도 복잡한 패턴을 학습하지 못한다.
- 하지만 퍼셉트론 수렴 이론으로 즉, 훈련 샘플이 선형적으로 구분될 수 있다면 이 알고리즘이 정답에 수렴한다는 것을 증명
import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import Perceptron
iris = load_iris()
X = iris.data[:, (2, 3)] # 꽃잎 길이, 꽃잎 너비
y = (iris.target == 0).astype(np.int)
per_clf = Perceptron(max_iter=1000, tol=1e-3, random_state=42)
per_clf.fit(X, y)
y_pred = per_clf.predict([[2, 0.5]])
y_pred
# array([1])
a = -per_clf.coef_[0][0] / per_clf.coef_[0][1]
b = -per_clf.intercept_ / per_clf.coef_[0][1]
axes = [0, 5, 0, 2]
x0, x1 = np.meshgrid(
np.linspace(axes[0], axes[1], 500).reshape(-1, 1),
np.linspace(axes[2], axes[3], 200).reshape(-1, 1),
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = per_clf.predict(X_new)
zz = y_predict.reshape(x0.shape)
plt.figure(figsize=(10, 4))
plt.plot(X[y==0, 0], X[y==0, 1], "bs", label="Not Iris-Setosa")
plt.plot(X[y==1, 0], X[y==1, 1], "yo", label="Iris-Setosa")
plt.plot([axes[0], axes[1]], [a * axes[0] + b, a * axes[1] + b], "k-", linewidth=3)
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#9898ff', '#fafab0'])
plt.contourf(x0, x1, zz, cmap=custom_cmap)
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
plt.legend(loc="lower right", fontsize=14)
plt.axis(axes)
save_fig("perceptron_iris_plot")
plt.show()
- Perceptron 클래스는 매개변수가 loss=”perceptron”, learning_rate=”constant”, eta0=1(학습률), penalty=None(규제 없음)인 SGDClassifier와 같다.
- 로지스틱 회귀 분류기와 달리 퍼셉트론은 클래스 확률을 제공하지 않으며 고정된 임곗값을 기준으로 예측을 만든다.
- 퍼셉트론을 여러 개 쌓아올리면 일부 제약을 줄일 수 있다. 이런 인공신경망을 다층 퍼셉트론(MLP)라 한다.
- MLP는 XOR 문제를 풀 수 있다.
이미지 출처5
10.1.4 다층 퍼셉트론과 역전파
- 다층 퍼셉트론은 (통과) 입력층(input layer) 하나와 은닉층(hidden layer)이라 불리는 하나 이상의 TLU 층과 마지막 출력층(output layer)으로 구성된다. 입력층과 가까운 층을 보통 하위 층(lower layer)이라 부르고 출력에 가까운 층을 상위 층(upper layer)라고 부른다. 출력층을 제외하고 모든 층은 편향 뉴런을 포함하며 다음 층과 완전히 연결되어 있다.
신호는 (입력에서 출력으로) 한 방향으로만 흐른다. (이런 구조를 피드포워드 신경망(FNN))에 속한다.
- 은닉층을
여러 개
쌓아 올린 인공 신경망을 심층 신경망(DNN; deep neural network)라고 한다. - 딥러닝은 심층 신경망을 연구하는 분야이며 조금 더 일반적으로는 연산이 연속하여 길게 연결된 모델을 연구한다.
- 이렇게 여러층을 쌓은 MLP를 통해 XOR 문제를 해결 했지만, 층이 깊어질 수록 증가하는 가중치 매개변수의 수로 인해 다층 퍼셉트론을 학습시키기에는 오랜 시간이 걸리는 문제가 발생했다. 하지만, 1986년 역전파(backpropogation) 알고리즘이 등장하면서 계산량을 획기적으로 줄일 수 있게 되었다.6
- 역전파 알고리즘(backpropagation)은 효율적인 기법으로 그레이디언트를 자동으로 계산(== 자동 미분)하는 경사 하강법이다.
- 네트워크를 두 번(정방향 한번, 역방향 한 번) 통과하는 것만으로 이 역전파 알고리즘은 모든 모델 파라미터에 대한 네트워크 오차의 그레이디언트를 계산할 수 있다.
- 다른 말로 하면 오차를 감소시키기 위해 각 연결 가중치와 편향값이 어떻게 바뀌어야 할지 알 수 있다.
알고리즘
- 한 번에 (예를 들어, 32개의 샘플이 포함된) 하나의 미니배치씩 진행하여 전체 훈련 세트를 처리한다. 이 과정을 여러 번 반복한다. 각 반복을 에포크(epoch)라 한다.
- 각 미니배치는 네트워크의 입력층으로 전달되어 첫 번째 은닉층으로 보내진다.
- 해당 층에 있는 모든 뉴런의 출력을 계산한다. 이 결과는 다음 층으로 전달된다.
- 다시 이 층의 출력을 계산하고 결과는 다음 층으로 전달된다. (정방향 계산)
- 알고리즘이 네트워크의 출력 오차를 측정한다.(즉, 손실 함수를 사용하여 기대하는 출력과 네트워크의 실제 출력을 비교하고 오차 측정 값을 반환한다.)
- 각 출력 연결이 이 오차에 기여하는 정도를 계산한다. (연쇄법칙 적용)
- 연쇄 법칙을 계속 사용하여 이전 층의 연결 가중치가 이 오차의 기여 정도에 얼마나 기여했는지 측정한다. 이렇게 입력층에 도달할 때까지 역방향으로 계속된다.
- 알고리즘은 경사 하강법을 수행하여 방금 계산한 오차 그레이디언트를 사용해 네트워크에 있는 모든 여결 가중치를 수정한다.
- 위를 다시 요약 정리
- 각 훈련 샘플에 대해 역전파 알고리즘이 먼저 예측을 만들고(정방향 계산) 오차를 측정한다.
- 역방향으로 각 층을 거치면서 각 연결이 오차에 기여한 정도를 측정한다. (역방향 계산)
- 이 오차가 감소하도록 가중치를 조정한다. (경사 하강법 단계)
왜 활성화 함수가 필요할까?
- 선형 변환을 여러 개 연결해도 얻을 수 있는 것은 선형 변환뿐이다.
- 층 사이에 비선형성을 추가하지 않으면 아무리 층을 많이 쌓아도 하나의 층과 동일해진다. 이런 층으로는 복잡한 문제를 풀 수 없다.
- 반대로 비선형 활성화 함수가 있는 충분히 큰 심층 신경망은 이론적으로 어떤 연속 함수도 근사할 수 있다.
- 로지스틱(시그모이드) 함수 : $\sigma(z) = \frac {1}{1+exp(-z)}$
- 하이퍼볼릭 탄젠트 함수 (쌍곡 탄젠트 함수) : $\tanh(z) = 2\sigma(2z) - 1$
- ReLU 함수 : $ReLU(z)=max(0, z)$
- ReLU 함수의 값이 0보다 클 때 기울기는 항상 1이므로 오차 그레이디언트를 그대로 역전파시킨다.
- ReLU 함수 값이 0보다 작거나 같을 때는 오차 그레이디언트를 역전파하지 않는다.
로지스틱 함수나 하이퍼볼릭 탄젠트 함수는 출력 범위가 0~1 또는 -1~1 사이로 한정되어 양극단에서 기울기가 급격히 감소하므로 오차 그레이디언트를 잘 역전파하지 못한다.
10.1.5 회귀를 위한 다층 퍼셉트론
- 회귀 MLP의 전형적인 구조
하이퍼파라미터 | 일반적인 값 |
---|---|
입력 뉴런수 | 특성마다 하나 (예를 들어 MNIST의 경우 28x28=784) |
은닉층 수 | 문제에 따라 다름. 일반적으로 1에서 5 사이 |
은닉층의 뉴런 수 | 문제에 따라 다름. 일반적으로 10에서 100사이 |
출력 뉴런 수 | 예측 차원마다 하나 |
은닉층의 활성화 함수 | ReLU |
출력층의 활성화 함수 | 1. 없음 2. 출력이 양수일 때 : ReLU/sotfplus 3. 출력을 특정 범위로 제한할 때 : logisitc(0~1)/tanh(-1~1)를 사용 |
손실 함수 | MSE나 (이상치가 있다면)MAE |
- 출력 뉴런 수 : 예측해야 하는 값의 수에 따라 출력 뉴런 설정
10.1.6 분류를 위한 다층 퍼셉트론
- 다층 퍼셉트론은 분류 작업에도 사용할 수 있다.
- 이진 분류 문제에서는 로지스틱 활성화 함수를 가진 하나의 출력 뉴런만 필요하다.
- 출력은 0과 1사이의 실수이다.
- 다층 퍼셉트론은 다중 레이블 이진 분류 (multilabel binary classification) 문제를 쉽게 처리할 수 있다.
- 각 샘플이 3개 이상의 클래스 중 한 클래스에만 속할 수 있다면 (예를 들어 숫자 이미지 분류에서 클래스 0에서 9까지) 클래스마다 하나의 출력 뉴런이 필요하다. 출력층에는 소프트맥스 활성화 함수를 사용해야 한다.
- 소프트맥스 함수는 모든 예측 확률을 0과 1 사이로 만들고 더했을 때 1이 되도록 만든다. 이를 다중 분류 (multiclass classifcation)라고 부른다.
- 확률 분포를 예측해야 하므로 손실 함수에는 일반적으로 크로스 엔트로피 손실(cross-entropy loss)을 선택하는 것이 좋다.
- 분류 MLP의 전형적인 구조
하이퍼파라미터 | 이진 분류 | 다중 레이블 분류 | 다중 분류 |
---|---|---|---|
입력층과 은닉층 | 회귀와 동일 | 회귀와 동일 | 회귀와 동일 |
출력 뉴런 수 | 1개 | 레이블마다 1개 | 클래스마다 1개 |
출력층의 활성화 함수 | 로지스틱 함수 | 로지스틱 함수 | 소프트맥스 함수 |
손실 함수 | 크로스 엔트로피 | 크로스 엔트로피 | 크로스 엔트로피 |
댓글남기기