소프트맥스 함수를 이용하는 다중 클래스 로지스특 회귀

소프트맥스 함수(Softmax Function)

  • 신경망에서 출력이 발화한다/안한다 2가지인 경우보다는 더욱 많은 경우를 분류하거나 예측해야하는 문제가 더 많음
  • 데이터를 2가지 분류하는 문제를 이진 분류(binary classification)이라 하고 3개 이상으로 분류하는 문제를 다중클래스 분류(multiclass classification)라 한다
  • 단순 신경망 모델이나 로지스틱 회귀는 다중클래스 분류 문제를 해결할 수 없지만 활성화 함수로 계단 함수를 시그모이드 함수로 바꾸면 출력값을 확률로 만들 수 있기 때문에 시그모이드 함수를 약간 변형하면 다중클래스 분류 문제를 해결하는데 사용 가능
  • 소프트맥스 함수(softmax funcation)는 $n$차원 벡터 $\mathbb{x}=(x_1,x_2,\ldots,x_n)$에 대하여 식 (5.1)로 정의한다

\begin{eqnarray} \textrm{softmax}(\mathbb{x})_i=\frac{e^{\mathbb{x}_i}}{\sum_{j=1}^ne^{\mathbb{x}_j}}\quad(i=1, 2, \ldots, n)\tag{5.1}\end{eqnarray}

  • $y_i= \textrm{softmax}(\mathbb{x})_i$를 성분으로 갖는 벡터를 $\mathbb{y}$라고 하면 소프트맥스 함수의 정의로 부터 식 (5.2)가 성립

\begin{align} \sum_{i=1}^ny_i &= \sum_{i=1}^n \frac{e^{\mathbb{x}_i}}{\sum_{j=1}^ne^{\mathbb{x}_j}} \quad(0\leqq y_i \leqq 1\,\,(i=1,2,\ldots,n))\\ &= \frac{\sum_{i=1}^ne^{\mathbb{x}_i}}{\sum_{j=1}^ne^{\mathbb{x}_j}}\\&= 1\tag{5.2}\end{align}

  • 각각의 성분 표시를 일반화하면 식 (5.3)으로 표현 가능하기 때문에 $y_i$는 식 (5.4)가 된다

\begin{eqnarray} \mathbb{y} = \left( \begin{array}{c}y_1\\y_2\\\vdots\\y_n\end{array}\right) = \frac{1}{\sum_{j=1}^ne^{x_j}}\left( \begin{array}{c}e^{x_1}\\e^{x_2}\\\vdots\\e^{x_n}\end{array}\right)\tag{5.3}\end{eqnarray}

\begin{eqnarray} y_i = \frac{e^{x_i}}{\sum_{j=1}^n e^{x_j}}\tag{5.4}\end{eqnarray}


소프트맥스 함수의 예

  • $\mathbb{x}=\left(\begin{array}{c}2 & 1 & 1\end{array}\right)$이라면

\begin{align}\mathbb{y} &= \left(\begin{array}{c} y_1& y_2 & y_3\end{array}\right)\\ &= \frac{1}{e^2 + e^1 + e^1}\left(\begin{array}{c} e^2 & e^1 & e^1\end{array}\right) \\ &= \frac{1}{12.8256} \left(\begin{array}{c} 7.3891 & 2.7183 & 2.7183 \end{array}\right)\\ &= \left(\begin{array}{c} 0.5761 & 0.2119 & 0.2119\end{array}\right) \end{align}


소프트맥스 함수의 경사도

  • 소프트맥스 함수를 사용하면 출력 벡터의 성분이 정규화되어 '출력 확률'로 취급할 수 있기 때문에 신경망 모델에 사용이 가능
  • 소프트맥스 함수의 경사도를 구하기 위해 입력 벡터 $x_i$의 편미분 식을 구하기 위해 식 (5.3) 우변의 분모를 식 (5.5)로 정의

\begin{eqnarray} Z = \sum_{j=1}^n e^{x_j} \tag{5.5}\end{eqnarray}

  • 이제 소프트맥스 함수를 $x_i$로 편미분을 해보자
    • $i=j$일 때

\begin{align} \frac{\partial y_i}{\partial x_i} &= \frac{e^{x_i}Z - e^{x_i}e^{x_i}}{Z^2}\\ &= \frac{e^{x_i}}{Z}\bigg(\frac{Z}{Z}-\frac{e^{x_i}}{Z}\bigg)\\ &= y_i(1-y_i)\quad(\because\,\,(5.4),\,(5.5)) \tag{5.5}\end{align}

    • $i\neq j$일 때

\begin{align} \frac{\partial y_i}{\partial x_j} &= \frac{\not{e^{x_i}Z} - e^{x_i}e^{x_j}}{Z^2}\\ &= -\frac{e^{x_i}}{Z}\frac{e^{x_j}}{Z} \\ &= -y_iy_j\tag{5.6}\end{align}

  • 모든 $i$에 대해서 일반화하기 위해 식 (5.5)와 식 (5.6)을 합쳐서 정리하면 식 (5.7)이 된다

\begin{eqnarray} \frac{\partial y_i}{\partial x_j} = \left\{ \begin{array}{lc} y_i(1-y_i) & (i=j) \\ -y_iy_j & (i\neq j)\end{array}\right.\tag{5.7}\end{eqnarray}


다중클래스 신경망 모델링

  • 입력 데이터 $(x_1, \ldots,x_m,\ldots, x_M)$를 $K$개의 클래스 $(y_1, y_2, \ldots, y_K)$로 분류하는 신경망을 모델링하려면 출력이 $K$개가 되어야 하기 때문에 아래 그림과 같은 신경망을 모델링해야 한다


  • 이 때 출력 $y$는 스칼라가 아닌 $K$ 차원의 벡터가 되기 때문에 식 (5.8)로 표현된다

\begin{eqnarray} \mathbb{y} = \left( \begin{array}{c} y_i\\\vdots \\ y_k \\ \vdots\\ y_K \end{array}\right) \tag{5.8}\end{eqnarray}

  • 출력은 $K$차원의 벡터이지만 기본적인 개념은 이진 분류 모델과 동일하기 때문에 $y_k$에 대응하는 뉴런만 따로 떼서 보면 해당 뉴런의 출력은 식 (5.9)처럼 되며 이는 이진 분류때와 같은 형태가 되는 것을 알 수 있다

\begin{align} y_k &= f(w_{k1}x_1 + w_{k2}x_2 + \cdots + w_{kM}x_M + b_k)\\ &= f(\mathbb{w}\mathbb{x} + b_k)\tag{5.9}\end{align}

  • $\mathbb{w}_k=\left(\begin{array}{c} w_{k1} & w_{k2} & \cdots & w_{kM}\end{array}\right)$라고 하면 전체 웨이트 $\boldsymbol{W}$는 식 (5.10)과 되며 바이어스 $b$는 식 (5.11)과 같이 표현할 수 있다

\begin{align} \boldsymbol{W} &= \left(\begin{array}{c} \mathbb{w}_{1} \\ \vdots \\ \mathbb{w}_{k} \\ \vdots \\ \mathbb{w}_{K}\end{array}\right) \\ &= \left(\begin{array}{ccccc} w_{11} & \cdots & w_{1n} & \cdots & w_{1M} \\\vdots &\ddots & \vdots & \ddots& \vdots \\w_{k1} & \cdots & w_{kn} & \cdots & w_{kM}\\\vdots &\ddots & \vdots &\ddots & \vdots \\w_{K1} & \cdots & w_{Kn} & \cdots & w_{KM}\\\end{array}\right)\tag{5.10}\\ \mathbb{b} &= \left(\begin{array}{c} b_{1} \\ \vdots \\ b_{k} \\ \vdots \\ b_{K}\end{array}\right) \tag{5.11}\end{align}

  • 식 (5.10)과 식 (5.11)을 사용하여 다중클래스 신경망 모델의 식은 식 (5.12), 그리고 신경망 모델링 가설식은 식 (5.13)으로 나타낼 수 있다

\begin{eqnarray} y = f(\boldsymbol{W}\mathbb{x} + \mathbb{b})\tag{5.12}\end{eqnarray}

\begin{eqnarray} H(\mathbb{x}) = f(\boldsymbol{W}\mathbb{x} + \mathbb{b})\tag{5.12}\end{eqnarray}

    • $\boldsymbol{W}$를 웨이트 행렬(weight matrix)라 하고, $\mathbb{b}$를 바이어스 벡터(bias vector)라고 한다
    • 발화를 결정하는 활성화 함수 $f(\cdot)$에 소프트맥스 함수를 사용하면 $y$가 식 (5.2)를 만족하기 때문에 다중클래스 분류를 위한 함수로 사용 가능하며 이 모델을 다중클래스 회귀(multi-class logistic regression)라고 한다


입력 데이터가 각 클래스로 분류될 확률

  • 입력 $\mathbb{x}$가 어떤 클래스로 분류될 확률 변수를 $C$라고 하면
    • 이진 분류의 경우: $C\in \{0, 1\}$
    • 다중클래스 분류의 경우: $C\in\{1, 2, \ldots, K\}$
  • 어떤 뉴런의 출력 $y_k$는 $\mathbb{x}$가 클래스 $k$로 분류될 확률이기 때문에 식 (5.14)와 같이 확률식으로 표현 가능

\begin{align} y_k &= \mathrm{Pr}(C=k|\mathbb{x})\\ &=\frac{e^{\mathbb{w}_k\mathbb{x} + b_k}}{\sum_{j=1}^Ke^{\mathbb{w}_j\mathbb{x} + b_j}}\tag{5.14}\end{align}


매개변수 $\boldsymbol{W}$와 $\mathbb{b}$의 가능도 함수

  • 실제의 값과 모델의 가설식의 오차를 계산하면서 매개변수 $\boldsymbol{W}$와 $\mathbb{b}$를 업데이트하기 위한 가능도 함수를 구하기 위해 입력 데이터 $\mathbb{x}_n$ $(n=1, 2, \ldots, N)$과 그에 대응하는 정답 데이터 $\mathbb{y}_n$이 있다고 하자
  • $\mathbb{x}_n$이 클래스 $k$에 속한다면 식 (5.15)와 같이 $\mathbb{y}_n$의 $k$번째 성분 $\mathbb{y}_{n_k}$는 $1$이지만 그 외의 $j$번째 성분인 $\mathbb{y}_{n_j}$는$0$이 될 것이다

\begin{eqnarray} \mathbb{y}_{n_{j}} = \left\{\begin{array}{lc} 1 & (j = k) \\ 0 & (j\neq k)\end{array}\right.\tag{5.15}\end{eqnarray}

  • 식 (5.15)처럼 벡터의 어느 성분만 $1$이고 나머지 성분은 $0$이 되도록 표현하는 것을 $1$-of-$K$ 표현(1-of-K representation)이라고 하며, 식 (5.15)를 코드로 구현하는 것을 원-핫 인코딩(one-hot encoding)이라고 한다
  • 다중클래스 모델링 가설식인 식 (5.12)에서 $f(\cdot)=\textrm{softmax}(\cdot)$이라고 하면 $\boldsymbol{W}$와 $\mathbb{b}$의 가장 좋은 값을 찾기 위한 가능도 함수는 식 (5.16)으로 표현할 수 있다
    • 각각의 $\mathbb{x}_n$에 대하여 신경망 모델의 출력값이 $\mathbb{y}_{n_k}$가 될 확률 $\mathrm{Pr}(C=k|\mathbb{x}_n)$이 높아야 좋은 모델이다

\begin{align}L(\boldsymbol{W},\mathbb{b}) &= \prod_{n=1}^N\prod_{k=1}^K\mathrm{Pr}(C=k|\mathbb{x}_n)^{\mathbb{y}_{n_k}}\\ &= \prod_{n=1}^N\prod_{k=1}^K\big(H_{n_k}(\mathbb{x}_n)\big)^{\mathbb{y}_{n_k}}\tag{5.16}\end{align}

  • 식 (5.16)을 최대로 만드는 매개변수 $\boldsymbol{W}$와 $\mathbb{b}$를 구하기 위해 식 (5.16)에 $\log$를 취하는 변형을 하면 식 (5.17)이 된다

\begin{align} E(\boldsymbol{W}, \mathbb{b}) &= -\log L(\boldsymbol{W},\mathbb{b}) \\ &= -\sum_{n=1}^N\sum_{k=1}^K \mathbb{y}_{n_k}\log H_{n_k}(\mathbb{x}_n)\tag{5.17}\end{align}

  • 식 (5.17)을 다중클래스에서의 교차 엔트로피 오차 함수라고 하며, 우리는 이 식의 최적화 문제를 풀어야만 한다
  • 최적화 문제를 풀기 위하여 우리는 앞에서 했던 것처럼 경사하강법을 사용해 식 (5.17)의 최소값을 구할 수 있다


다중클래스 회귀 모델의 경사하강법

  • 웨이트 행렬 $\boldsymbol{W}$의 경사인 편미분 구하기
    • $\boldsymbol{W} = (\mathbb{w}_1, \mathbb{w}_2, \ldots, \mathbb{w}_K)$이기 때문에 교차 엔트로피 오차 함수를 식 (5.18)이라 할 수 있다

\begin{align} E &= E(\boldsymbol{W}, \mathbb{b})\\ &= E(\mathbb{w}_1, \mathbb{w}_2, \ldots, \mathbb{w}_K, \mathbb{b})\tag{5.18}\end{align}

    • $\boldsymbol{W}$의 $j$번째 성분인 $\mathbb{w}_j$의 편미분 구하기
      • $I$를 $K$차 단위행렬, 그리고 $\mathbb{a}_n=\boldsymbol{W}\mathbb{x}_n+\mathbb{b}$라고 하면 식 (5.19)를 구할 수 있다

\begin{align}\frac{\partial E}{\partial \mathbb{w}_j} &= - \sum_{n=1}^N\sum_{k=1}^K\frac{\partial E}{\partial H_{n_k}(\mathbb{x}_n)}\frac{\partial H_{n_k}(\mathbb{x}_n)}{\partial \mathbb{a}_{n_j}} \frac{\partial \mathbb{a}_{n_j}}{\partial \mathbb{w}_j}\\&=-\sum_{n=1}^N\sum_{k=1}^K \frac{\partial}{\partial H_{n_k}(\mathbb{x}_n)}\big(\mathbb{y}_{n_k}\log H_{n_k}(\mathbb{x}_n)\big)\frac{\partial H_{n_k}(\mathbb{x}_n)}{\partial \mathbb{a}_{n_j}} \frac{\partial \mathbb{a}_{n_j}}{\partial \mathbb{w}_j}\\&= -\sum_{n=1}^N\sum_{k=1}^K\frac{\mathbb{y}_{n_k}}{H_{n_k}(\mathbb{x}_n)} \frac{\partial H_{n_k}(\mathbb{x}_n)}{\mathbb{a}_{n_j}}\mathbb{x}_n\\ &= -\sum_{n=1}^N \sum_{k=1}^K \frac{\mathbb{y}_{n_k}}{H_{n_k}(\mathbb{x}_n)}H_{n_k}(\mathbb{x}_n) (I_{k_j}- H_{n_k}(\mathbb{x}_n))\quad(\because\,\,H_{n_k}(\mathbb{x}_n)\,\,\textrm{is softmax})\\ &= -\sum_{n=1}^N\Bigg( \sum_{k=1}^K \mathbb{y}_{n_k}I_{k_j} - \sum_{k=1}^K \mathbb{y}_{n_k}H_{n_j}(\mathbb{x}_n)\Bigg)\mathbb{x}_n\\&= -\sum_{n=1}^N\big(\mathbb{y}_{n_j} - H_{n_j}(\mathbb{x}_n)\big)\mathbb{x}_n\quad(\because\,\,(5.15))\tag{5.19}\end{align}

  • $\mathbb{b}$의 $j$번째 성분인 $b_j$의 편미분은 식 (5.20)와 같다

\begin{align}\frac{\partial E}{\partial b_j} &= \sum_{n=1}^N\sum_{k=1}^K\frac{\partial E}{\partial H_{n_k}(\mathbb{x}_n)}\frac{\partial H_{n_k}(\mathbb{x}_n)}{\partial \mathbb{a}_{n_j}} \frac{\partial \mathbb{a}_{n_j}}{\partial b_j}\\&=-\sum_{n=1}^N\sum_{k=1}^K \frac{\partial}{\partial H_{n_k}(\mathbb{x}_n)}\big(\mathbb{y}_{n_k}\log H_{n_k}(\mathbb{x}_n)\big)\frac{\partial H_{n_k}(\mathbb{x}_n)}{\partial \mathbb{a}_{n_j}} \frac{\partial \mathbb{a}_{n_j}}{\partial b_j}\\&= -\sum_{n=1}^N\sum_{k=1}^K\frac{\mathbb{y}_{n_k}}{H_{n_k}(\mathbb{x}_n)} \frac{\partial H_{n_k}(\mathbb{x}_n)}{\mathbb{a}_{n_j}}\\ &= -\sum_{n=1}^N \sum_{k=1}^K \frac{\mathbb{y}_{n_k}}{H_{n_k}(\mathbb{x}_n)}H_{n_k}(\mathbb{x}_n) (I_{k_j}- H_{n_k})\quad(\because\,\,H_{n_k}(\mathbb{x}_n))\,\,\textrm{is softmax})\\ &= -\sum_{n=1}^N\Bigg( \sum_{k=1}^K \mathbb{y}_{n_k}I_{k_j} - \sum_{k=1}^K \mathbb{y}_{n_k}H_{n_j}(\mathbb{x}_n)\Bigg)\\&= -\sum_{n=1}^N\big(\mathbb{y}_{n_j} - H_{n_j}(\mathbb{x}_n)\big)\quad(\because\,\,(5.15))\tag{5.20}\end{align}

  • 전체 웨이트 행렬 $\boldsymbol{W}$와 바이어스 벡터 $\mathbb{b}$에 대한 편미분 식은 각각의 $j$번째 성분에 대한 편미분이 식 (5.19)와 식 (5.20)이기 때문에 각각의 성분을 모아 벡터로 묶으면 식 (5.21)과 식 (5.22)로 표현할 수 있다

\begin{align} \frac{\partial E}{\partial \boldsymbol{W}} &= -\sum_{n=1}^N \big(\mathbb{y}_n - H_n(\mathbb{x}_n)\big)\mathbb{x}_n\tag{5.21}\\ \frac{\partial E}{\partial \mathbb{b}} &= -\sum_{n=1}^N \big(\mathbb{y}_n - H_n(\mathbb{x}_n)\big)\tag{5.22}\end{align}


TensorFlow로 구현

  • 2개의 입력을 받아 3개의 클래스로 분류하기
  • 각 클래스의 데이터는 평균 $\mu \neq 0$인 정규분포를 따르는 샘플 데이터를 생성해 사용
  • 전체 데이터는 300개로 3개의 클래스는 각각 100개의 데이터로 구성되어 있어, 100개를 제대로 분류해야 한다
  • 미니배치 확률 경사하강법(SGD)을 사용하려는데, SGD를 사용하기 위해서는 데이터를 무작위로 섞는 작업이 필요하다
    • sklearn 라이브러리의 sklearn.utils.shuffle 함수를 사용
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf

M = 2       # 입력 데이터의 차원
K = 3       # 출력 클래스의 수
n = 100     # 각 클래스에 속한 데이터 수
N = n * K   # 전체 데이터 수

# 샘플 데이터 생성
X1 = np.random.randn(n, M) + np.array([0, 10])  # 평균이 [0, 10]인 클래스
X2 = np.random.randn(n, M) + np.array([5, 5])   # 평균이 [5, 5]인 클래스
X3 = np.random.randn(n, M) + np.array([10, 0])  # 평균이 [10, 0]인 클래스

Y1 = np.array([[1, 0, 0] for _ in range(100)])
Y2 = np.array([[0, 1, 0] for _ in range(100)])
Y3 = np.array([[0, 0, 1] for _ in range(100)])

X = np.concatenate((X1, X2, X3), axis=0)
Y = np.concatenate((Y1, Y2, Y3), axis=0)

plt.scatter(X1[:, 0], X1[:, 1], marker='x', label='Class 1')
plt.scatter(X2[:, 0], X2[:, 1], marker='o', label='Class 2')
plt.scatter(X3[:, 0], X3[:, 1], marker='^', label='Class 3')
plt.grid(linestyle=':')
plt.legend()
plt.show()



W = tf.Variable(tf.zeros([M, K]))
b = tf.Variable(tf.zeros([K]))

x = tf.placeholder(tf.float32, shape=[None, M])
y = tf.placeholder(tf.float32, shape=[None, K])

hypothesis = tf.nn.softmax(tf.matmul(x, W) + b)

# 오차 함수는 미니배치로 계산을 하기때문에 각 미니배치의 평균값으로 오차를 계산
cost = tf.reduce_mean(-tf.reduce_sum(y * tf.log(hypothesis), reduction_indices=[1]))

train = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

# 제대로 분류되는지 확인
correct_prediction = tf.equal(tf.argmax(hypothesis, 1), tf.argmax(y, 1))

batch_size = 50
n_batches = N // batch_size

# SGD에서는 각 에포크마다 데이터를 섞는다

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    for epoch in range(20):

        X_, Y_ = shuffle(X, Y)

        for i in range(n_batches):
            start = i * batch_size
            end = start + batch_size

            sess.run(train, feed_dict={x: X_[start:end], y: Y_[start:end]})

    X_, Y_ = shuffle(X, Y)

    classified = correct_prediction.eval(session=sess, feed_dict={x: X_[0:10], y: Y_[0:10]})
    prob = hypothesis.eval(session=sess, feed_dict={x: X_[0:10]})

    print(f'분류 결과: {classified}')
    print()
    print(f'출력 결과 확률:\n{prob}')

  • 실행 결과
분류 결과: [ True  True  True  True  True  True  True  True  True  True]

출력 결과 확률:
[[9.17210460e-01 8.27893838e-02 7.92326063e-08]
 [9.02648142e-04 9.82177138e-01 1.69202797e-02]
 [2.44496441e-08 2.24424489e-02 9.77557540e-01]
 [9.97427881e-01 2.57207383e-03 3.72525255e-09]
 [9.80204523e-01 1.97954960e-02 7.34132088e-09]
 [1.45240305e-02 9.82932091e-01 2.54384498e-03]
 [9.65797622e-03 8.52199674e-01 1.38142347e-01]
 [5.00551378e-03 9.84985948e-01 1.00085456e-02]
 [9.97002780e-01 2.99719279e-03 1.52783930e-09]
 [9.28733170e-01 7.12668002e-02 4.98736341e-08]]


  • 분류 결과를 그래프로 표시
    W = sess.run(W)
    b = sess.run(b)

    print(f'weight matrix: \n{W}')
    print()
    print(f'bias vector: \n{b}')

    plt.scatter(X1[:, 0], X1[:, 1], marker='x', label='Class 1')
    plt.scatter(X2[:, 0], X2[:, 1], marker='o', label='Class 2')
    plt.scatter(X3[:, 0], X3[:, 1], marker='^', label='Class 3')
    plt.grid(linestyle=':')
    plt.legend()

    x_space = np.linspace(-3, 14, 100000)
    plt.plot(x_space, (W[0, 1] - W[0, 0]) / (W[1, 0] - W[1, 1]) * x_space + (b[1] - b[0]) / (W[1, 0] - W[1, 1]))
    plt.plot(x_space, (W[0, 2] - W[0, 1]) / (W[1, 1] - W[1, 2]) * x_space + (b[2] - b[1]) / (W[1, 1] - W[1, 2]))
    plt.show()
weight matrix: 
[[-1.0804898   0.30662853  0.7738616 ]
 [ 0.79061     0.3192574  -1.1098676 ]]

bias vector: 
[-0.05789646  0.10934979 -0.05145331]
 


  • 입력 데이터가 2차원이기 때문에 분류의 기준이 되는 직선을 그릴 수 있는데, 소프트맥스 함수의 값이 같아지는 곳이 경계가 된다

    • 클래스 1과 클래스 2를 분류하는 직선 : $w_{11}x_1 + w_{12}x_2 + b_1 = w_{21}x_1 + w_{22}x_2 + b_2$

    • 클래스 2와 클래스 3을 분류하는 직선 : $w_{21}x_1 + w_{22}x_2 + b_2 = w_{31}x_1 + w_{32}x_2 + b_3$


Keras로 구현

from sklearn.utils import shuffle
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import SGD

M = 2       # 입력 데이터의 차원
K = 3       # 출력 클래스의 수
n = 100     # 각 클래스에 속한 데이터 수
N = n * K   # 전체 데이터 수

# 샘플 데이터 생성
X1 = np.random.randn(n, M) + np.array([0, 10])  # 평균이 [0, 10]인 클래스
X2 = np.random.randn(n, M) + np.array([5, 5])   # 평균이 [5, 5]인 클래스
X3 = np.random.randn(n, M) + np.array([10, 0])  # 평균이 [10, 0]인 클래스

Y1 = np.array([[1, 0, 0] for _ in range(100)])
Y2 = np.array([[0, 1, 0] for _ in range(100)])
Y3 = np.array([[0, 0, 1] for _ in range(100)])

X = np.concatenate((X1, X2, X3), axis=0)
Y = np.concatenate((Y1, Y2, Y3), axis=0)

model = Sequential()
model.add(Dense(input_dim=M, units=K))
model.add(Activation('softmax'))

# 이진 분류는 loss='binary_crossentropy'
# one-hot encoding은 loss=categorical_crossentropy'
model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=0.1))

minibatch_size = 50

model.fit(X, Y, epochs=20, batch_size=minibatch_size)

X_, Y_ = shuffle(X, Y)
classes = model.predict_classes(X_[0:10], batch_size=minibatch_size)
prob = model.predict_proba(X_[0:10], batch_size=minibatch_size)

print()
print('예측 결과:')
print(np.argmax(model.predict(X_[0:10]), axis=1) == classes)
print()
print(f'출력 확률:\n{prob}')


  • 실행 결과
예측 결과:
[ True  True  True  True  True  True  True  True  True  True]

출력 확률:
[[9.8160446e-01 1.8395502e-02 5.8491527e-09]
 [9.9367309e-01 6.3269795e-03 1.2570837e-08]
 [2.1171716e-07 5.1151857e-02 9.4884795e-01]
 [9.9820423e-01 1.7957645e-03 1.4402781e-09]
 [5.6637567e-10 4.2483290e-03 9.9575162e-01]
 [6.7489594e-03 9.6715742e-01 2.6093608e-02]
 [1.7853441e-09 5.5074170e-03 9.9449265e-01]
 [2.2595707e-02 9.3311501e-01 4.4289291e-02]
 [6.5676443e-02 9.2871374e-01 5.6097610e-03]
 [8.7217444e-08 1.4764958e-02 9.8523498e-01]]




출처 : 정석으로 배우는 딥러닝

'신경망(Neural Network) 스터디' 카테고리의 다른 글

7. 심층 신경망  (0) 2018.01.10
6. 다층 퍼셉트론 모델링  (0) 2017.12.28
4. 로지스틱 회귀  (0) 2017.12.23
3. 단순 신경망 모델의 확장  (0) 2017.12.22
2. 논리 회로  (0) 2017.12.22

+ Recent posts