• 임계치(threshold): 어떠한 값이 활성화되기 위한 최소값을 임계치라고 한다.
  • 가중치(weight): 퍼셉트론의 학습 목표는 학습 벡터를 두 부류로 선형 분류하기 위한 선형 경계를 찾는 것이다. 가중치는 이러한 선형 경계의 방향성 또는 형태를 나타내는 값이다.
  • 바이어스(bias): 선형 경계의 절편을 나타내는 값으로써, 직선의 경우는 y절편을 나타낸다.
  • net값: 입력값과 가중치의 곱을 모두 합한 값으로써, 기하학적으로 해석하면 선형 경계의 방정식과 같다.
  • 활성함수(activation function): 뉴런에서 계산된 net값이 임계치보다 크면 1을 출력하고, 임계치보다 작은 경우에는 0을 출력하는 함수. 이 정의는 단층 퍼셉트론에서만 유효하며, 다층 퍼셉트론에서는 다른 형태의 활성함수를 이용한다.
  • 뉴런(neuron): 인공신경망을 구성하는 가장 작은 요소로서, net값이 임계치보다 크면 활성화되면서 1을 출력하고, 반대의 경우에는 비활성화되면서 0을 출력한다. http://untitledtblog.tistory.com/27

퍼셉트론

퍼셉트론(perceptron)은 가장 오래되고 단순한 형태의 판별 함수 기반 예측 모형(discriminant function based predition model) 중 하나이다.

1962년 Rosenblatt은 동물의 신경(neuron) 구조에 기반한 퍼셉트론의 아이디어를 고안했다.

퍼셉트론은 입력 $x = (1, x_1, \cdots, x_m)$에 대해 1 또는 -1의 값을 가지는 $y$를 출력하는 비선형 함수이다. 1을 포함하는 입력 요소 $x_i$에 대해 가중치 $w_i$를 곱한 후 이 값이 활성화 함수 (activation function) $f(z)$를 지나면 출력 $y$가 생성된다.

$$ y = f(w^Tx) $$

퍼셉트론은 활성화 함수로 다음과 같은 Heaviside step function 을 가진다.

$$ y = f(z) = \begin{cases} -1, & z < 0, \\ 1, & z \ge 0 \end{cases} $$

따라서 퍼셉트론은 $w^Tx$라는 판별함수를 가지는 판별 기반 모형이다.

퍼셉트론 손실 함수

퍼셉트론은 독립 변수 $x$로부터 종속 변수 $y$를 예측하는 예측 모형이므로 예측 오차 즉 손실(loss)을 최소화하는 가중치를 계산해야 한다.

일반적으로 예측 오차는 다음과 같이 손실 함수(loss function)의 합으로 나타난다.

$$ E(w) = \sum_i L(\hat{y}, y) $$

손실 함수(loss function) 는 실제 $y$ 값과 예측 $\hat{y}$ 값의 차이를 나타내는 함수이다.

보통은 $L(\hat{y}, y) = -(\hat{y} - y)^2 $과 같은 손실함수를 많이 사용하지만 퍼셉트론의 경우에는 다음과 같은 손실 함수를 사용한다.

$$ L(\hat{y}, y) = \max(0,-\hat{y}y) $$$$ E(w) = \sum_i \max(0,-\hat{y}y) = \sum_i \max(0,-w^Tx_i y_i) $$

이를 퍼셉트론 손실 함수(perceptron loss function)이라고 한다.

  • 양수가 되면 1, 음수가 되면 -1로, 가중치는 m+1개
  • 기계 하나에 여러 개의 모델이 들어가는 것이 NN. 그 기반이 퍼셉트론이다.
  • 원래 모델 하나는 시신경이 하나 있을 때 가중치를 이용해서 구하면 개라는 모델을 만드는 것이고 또 눈알을 훈련 시켜서 고양이를 인식하기 위한 모델을 만드는 것
  • 가중치랑 x는 모두 변수인가요?
    • 멀티 인풋, 멀티 아웃풋이 NN이다.
    • 여러 단계를 거치는 것이 무슨 의미인가? 인풋이 3개가 있다면 3개의 라벨을 구하는 문제에서 모든 경우의 수로 그어 나간다.
    • x1, x2는 시신경 하나하나. 가중치는 내가 조정해서 구하는 값이 되기 때문에 변수(X)
    • 트레이닝을 한 다음에 이미 트레이닝이 된 정보를 활용하기 때문에. w는 상수다.
  • 원샷으로 되는것은 리니어리그레션만 된다. 로지스틱은 안 된다. 분류에서는 반드시 이것을 쓸 필요가 없다. 에러를 그럼 뭘 쓰느냐? 곱하기
  • 분류에서는 부호만 같으면 된다. 뭐가 부호가 같으면 되? y랑y햇이
  • 다르면 +값, 같으면 0이 나오게끔

가중치 계산

$E(w)$를 최소화하는 $w$를 찾기 위해 $E(w)$를 $w$로 미분하여 gradient를 구하면 다음과 같다.

$$ \dfrac{dE}{dw} = - \sum_i x_i y_i $$

gradient descent 방법을 사용하면 다음과 같이 $w$를 구할 수 있다.

$$ \begin{eqnarray} w_{k+1} &=& w_{k} + \eta_k \sum_{i=1}^N x_i y_i \\ \end{eqnarray} $$

여기에서 $eta$는 step size 또는 learning rate 이라고 부른다.

  • i는 샘플
  • yi는 1과 -1
  • 개면 1이고 아니면 -1이고
  • 샘플을 먼저 돌려보고 나서 가중치가 1인지 -1인지 결정해야 한다.
  • 누구를 믿고 누구를 믿지 않을 지를 알 수 있다. 이 과정을 계속 반복하면 정확한 w가 나온다.

SGD (Stochastic Gradient Descent)

퍼셉트론은 일반적인 gradient descent 방법이 아닌 SGD(Stochastic Gradient Descent) 최적화 방법을 사용한다.

SGD 최적화 방법은 정확한 gradient 인 $\dfrac{dE}{dw} = - \sum_i x_i y_i$ 대신 일부 표본 데이터만 사용한 gradient의 추정치를 이용하는 방법이다. gradient 추정에 사용하는 표본 데이터의 갯수를 minibatch size 라고 하는데 퍼셉트론은 가장 극단적인 경우로 minibatch size = 1 을 사용한다. 즉, 한번에 하나의 표본 데이터만을 이용하여 가중치를 조정한다.

$$ \begin{eqnarray} w_{k+1} &=& w_{k} + \eta_k x_i y_i \\ \end{eqnarray} $$

이 식에서 $i$는 매 회 임의의 표본을 선택한다.

  • 1000장 너무 많아. 100장씩만 합시다.
  • 그런 다음에 또 할 때는 새로 100장을 뽑는다.
  • 대신 좋은 점은 무엇이냐? 계산이 빠르다.
  • 얼마나 틀리는가? 많이 틀릴 수 있지만 틀려도 상관은 없다. 많이 시도하면 된다.
  • 그런데 가장 극단적인 경우는 1인데 실제로 이렇게 하더라도 대체적으로 맞는다. SGD를 일반화 했기 때문에 더 많이 쓰인다.
  • SGD는 NN에서 많이 쓰인다.
  • 이미지 인식에서 많이 쓰인다.
  • 실제로 라벨을 6천개나 만개를 만들고 그만큼 샘플을 필요로 한다? 데이터 수가 많거나 모델이 복잡할 경우에 쓰인다.

Scikit-Learn 의 퍼셉트론 구현

Scikit-Learn 에서는 두 가지의 퍼셉트론 클래스를 제공한다. 단순한 퍼셉트론 모형인 Perceptron 클래스와 좀 더 다양한 옵션 인수를 제공하는 SGDClassifier 클래스이다.

SGDClassifier 클래스에서 제공하는 인수 중 일부를 소개하면 다음과 같다.

  • loss : ‘hinge’, ‘log’, ‘modified_huber’, ‘squared_hinge’, ‘perceptron’, ‘squared_loss’, ‘huber’, ‘epsilon_insensitive’, ‘squared_epsilon_insensitive’

    • 손실 함수
  • penalty : ‘none’, ‘l2’, ‘l1’, or ‘elasticnet’

    • 정규화 조건
  • alpha, l1_ratio

    • 정규화 가중치
  • n_iter :

    • 최적화를 위한 반복 횟수
  • eta0 :

    • learning rate $\eta$
    • eta는 기울기다. 너무 작으면 튕겨 나간다. 크면?

Perceptron 실행 예


In [1]:
from sklearn.datasets import load_iris
iris = load_iris()

idx = np.in1d(iris.target, [0, 2])
X = iris.data[idx, 0:2]
y = iris.target[idx]

plt.scatter(X[:, 0], X[:, 1], c=y, s=100)
plt.show()



In [5]:
from sklearn.linear_model import Perceptron

def plot_perceptron(n):
    model = Perceptron(n_iter=n, eta0=0.1, random_state=1).fit(X, y)   #eta 값이 0.1이면 크다. 이게 줄어들면 밑에 n값 조절 움직임 폭이 작다.
    XX_min = X[:, 0].min() - 1; XX_max = X[:, 0].max() + 1;            #eta는 xy의 곱의 합. 위에 식에서...
    YY_min = X[:, 1].min() - 1; YY_max = X[:, 1].max() + 1;
    XX, YY = np.meshgrid(np.linspace(XX_min, XX_max, 1000), np.linspace(YY_min, YY_max, 1000))
    ZZ = model.predict(np.c_[XX.ravel(), YY.ravel()]).reshape(XX.shape)
    cmap = mpl.colors.ListedColormap(sns.color_palette("Set2"))
    plt.contourf(XX, YY, ZZ, cmap=cmap)
    plt.scatter(X[:, 0], X[:, 1], s=50, linewidth=2, c=y, cmap=cmap)
    plt.xlim(XX_min, XX_max)
    plt.ylim(YY_min, YY_max)
    plt.grid(False)

In [6]:
plot_perceptron(1)



In [8]:
from ipywidgets import widgets
widgets.interact(plot_perceptron, n=widgets.IntSlider(min=1, max=100, step=1, value=1));



In [9]:
plot_perceptron(500)   #웨이트 바꿔주는 작업을 500번 한 것이다.



In [10]:
from sklearn.metrics import confusion_matrix, classification_report

model = Perceptron(n_iter=500, eta0=0.1, random_state=1).fit(X, y)

In [11]:
confusion_matrix(y, model.predict(X))


Out[11]:
array([[50,  0],
       [ 0, 50]])

SGDClassifier 실행 예


In [18]:
from sklearn.linear_model import SGDClassifier

def plot_sgd(n):
    model = SGDClassifier(loss='hinge', n_iter=n, random_state=1).fit(X, y)   #n이 적으면 iteration이 잘 안 되고 크면 잘 된다.
    XX_min = X[:, 0].min() - 1; XX_max = X[:, 0].max() + 1;
    YY_min = X[:, 1].min() - 1; YY_max = X[:, 1].max() + 1;
    XX, YY = np.meshgrid(np.linspace(XX_min, XX_max, 1000), np.linspace(YY_min, YY_max, 1000))
    ZZ = model.predict(np.c_[XX.ravel(), YY.ravel()]).reshape(XX.shape)
    cmap = mpl.colors.ListedColormap(sns.color_palette("Set2"))
    plt.contourf(XX, YY, ZZ, cmap=cmap)
    plt.scatter(X[:, 0], X[:, 1], c=y, s=50, linewidth=2, cmap=cmap)
    plt.xlim(XX_min, XX_max)
    plt.ylim(YY_min, YY_max)
    plt.grid(False)

In [19]:
plot_sgd(1)



In [20]:
widgets.interact(plot_sgd, n=widgets.IntSlider(min=1, max=100, step=1, value=1));



In [21]:
plot_sgd(1000)