์ด์ ์ธ์ ๋ ๊ฐ์์ ์ฐ๋ฆฌ๋ ํผ์ ํธ๋ก ํจ์๋ฅผ ํ์ตํ๊ณ ์์ต๋๋ค. ๊ธฐ์ตํ์๋์? ๊ธฐ์ต์ด ์ ๋์ ๋ค๋ฉด ์ ๋ ๊ฐ ๊ธ์ ๋ณด๊ณ ์ค์๋ ๊ฒ์ ์ถ์ฒ๋๋ฆฝ๋๋ค. ์ ๊ฐ ๊ณต๋ถํ๋๋งํผ ์ ๊ธ๋ค์ด ์ฃผ๊ธฐ์ ์ผ๋ก ์์ ๋ ์ ์์์ ์์์ฃผ์๊ธธ ๋ฐ๋๋๋คใ ใ
https://dnai-deny.tistory.com/5 https://dnai-deny.tistory.com/6
์ด๋ฒ ์ธ์ ์์๋ ํผ์ ํธ๋ก ์๊ณ ๋ฆฌ์ฆ์ ์งํ๋ฒ์ ์ธ ์๋ฌ๋ฆฐ๊ณผ ๋จธ์ ๋ฌ๋์ ์์ด์ ๋งค์ฐ ์ค์ํ ๊ฐ๋ ์ธ ๊ฒฝ์ฌํ๊ฐ๋ฒ์ ๋ํด ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
1. ์ ์ํ ์ ํ ๋ด๋ฐ, ์๋ฌ๋ฆฐ
์๋ฌ๋ฆฐ์ ๋จ์ผ ์ธต ์ ๊ฒฝ๋ง์ ๋ ๋ค๋ฅธ ์ข ๋ฅ์ ๋๋ค. ๋ฒ๋๋ ์๋๋ก์ฐ์ ํ ๋ ํธํ๊ฐ ๊ฐ๋ฐํ ์๊ณ ๋ฆฌ์ฆ์ด์ฃ . ์ ๋ชฉ์์ ๋ณด์ด๋ฏ ํผ์ ํธ๋ก ์ด ์งํํ ํํ๋ผ๊ณ ํ ์ ์์ต๋๋ค. ์๋ํ๋ฉด, ์๋ฌ๋ฆฐ์์๋ ๋น์ฉ ํจ์(cost function)์ด๋ผ๋ ์ฃผ์ ๊ฐ๋ ์ด ์ ์๋์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์๋ฌ๋ฆฐ๊ณผ ํผ์ ํธ๋ก ์ ์ฐจ์ด์ ์ ๊ฐ์ค์น ์ ๋ฐ์ดํธ ๋ฐฉ์์ ์์ต๋๋ค. ์๋ฌ๋ฆฐ์ ๋จ์ ๊ณ๋จ ํจ์ ๋์ ์ ํ ํ์ฑํ ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด ํจ์์์๋ ์ต์ข ์ ๋ ฅ๊ณผ ๋์ผํ ํจ์๋ฅผ ์ ํ ํ์ฑํ ํจ์๋ก ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ก ์๋ ์์์ด์ฃ .
๊ฐ์ค์น ํ์ต์๋ ์ ํ ํ์ฑํ ํจ์๊ฐ ์ฌ์ฉ๋์ง๋ง ์ต์ข ์์ธก์ ๋ง๋๋ ๋ฐ์๋ ์ฌ์ ํ ์๊ณํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ฃผ์ํ ์ฐจ์ด์ ์ ์๋ ๊ทธ๋ฆผ์์ ํ์ธํ ์ ์์ต๋๋ค. ์๋ฌ๋ฆฐ์ ์ ๋ต ํด๋์ค ๋ ์ด๋ธ๊ณผ ์ ํ ํ์ฑํ ํจ์์ ์ค์ ์ถ๋ ฅ ๊ฐ์ ๋น๊ตํด ๊ฐ์ค์น๋ฅผ ์ ๋ฐ์ดํธํ์ง๋ง ํผ์ ํธ๋ก ์ ์ ๋ต ํด๋์ค ๋ ์ด๋ธ๊ณผ ์์ธก ํด๋์ค ๋ ์ด๋ธ์ ๋น๊ตํ๋ค๋ ์ ์ด ๋ค๋ฆ ๋๋ค.
2. ๊ฒฝ์ฌํ๊ฐ๋ฒ์ผ๋ก ๋น์ฉํจ์ ์ต์ํํ๊ธฐ
์ง๋ํ์ต์ ํต์ฌ ๊ตฌ์ฑ ์์ ์ค ํ๋๋ ์ต์ ํ๋ฅผ ์ํด ์ ์๋ ๋ชฉ์ ํจ์์ ๋๋ค. ์ต์ํ๊ฐ ๋ชฉ์ ์ธ ๋น์ฉํจ์๊ฐ ์ข ์ข ๋ชฉ์ ํจ์๊ฐ ๋๊ธฐ๋ ํ๋ค๊ณ ํฉ๋๋ค. ์๋ฌ๋ฆฐ์ ๊ณ์ฐ๊ดธ ์ถ๋ ฅ๊ณผ ์ง์ง ํด๋์ค ๋ ์ด๋ธ ์ฌ์ด์ ์ค์ฐจ์ ์ ๊ณฑ์ ํฉํ ๊ฐ์ผ๋ก ๋น์ฉํจ์ J๋ฅผ ์ ์ํฉ๋๋ค.
์ด ํจ์์ ์ฅ์ ์ ๋ฐ๋ก ๋ณผ๋กํจ์๋ผ๋ ์ ์ ๋๋ค. ๋น์ฐํ ๋ณผ๋กํจ์์ด๊ธฐ ๋๋ฌธ์ ๋ฏธ๋ถ์ด ๊ฐ๋ฅํ๊ณ , ๋ฏธ๋ถํด์ ๊ตฌํด์ง ๊ทธ ๊ธฐ์ธ๊ธฐ๋ฅผ ๊ฒฝ์ฌ๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ์ด๊ฒ์ ์ด์ฉํ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ(gradient descent)๋ฅผ ์ ์ฉํ์ฌ ๋น์ฉํจ์๋ฅผ ์ต์ํํ๋ ๊ฐ์ค์น๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
๊ทธ๋ฆผ 4์์๋ ๊ฐ์ค์น์ ๋ฐ๋ฅธ ๊ฒฝ์ฌ๊ฐ ์ง์ญ ํน์ ์ ์ญ ์ต์๊ฐ์ ๋๋ฌํ ๋๊น์ง ์ธ๋์ ๋ด๋ ค์ค๋ ๊ฒ์ผ๋ก ๋ณด์ฌ์ฃผ๊ณ ์์ต๋๋ค. ํ์ต์ ๋ฐ๋ณตํ๋ฉด์ ๊ฒฝ์ฌ๊ฐ ์๋งํด์ง๋ ์ชฝ์ผ๋ก ์งํํ๊ฒ ๋๊ณ , ์งํ ํฌ๊ธฐ๋ ๊ธฐ์ธ๊ธฐ์ ํ์ต๋ฅ (learning rate)๋ก ๊ฒฐ์ ํฉ๋๋ค.
์ด๋ w := w + โณw ๋ ๋์ผํ๋ฐ, โณw = -nโฝJ(w) ๋ก ๊ฐ์ค์น ๋ณํ๋์ด ์ ์๋ฉ๋๋ค. ํ์ต๋ฅ n์ ์์์ ๊ทธ๋๋์ธํธ์ ๊ณฑํ ๊ฒ์ด์ฃ . ๋น์ฉ ํจ์์ ๊ทธ๋๋์ธํธ๋ฅผ ๊ณ์ฐํ๋ ค๋ฉด ๊ฐ ๊ฐ์ค์น wj์ ๋ํ ํธ๋ ํจ์๋ฅผ ๊ณ์ฐํด์ผํฉ๋๋ค.
๋ฐ๋ผ์ ๊ฐ์ค์น์ ์ฝ๋ฐ์ดํธ ๊ณต์์ ์๋์ ๊ฐ์ด ์ธ ์ ์์ต๋๋ค.
์ฌ๊ธฐ๊น์ง ๋ณด๋ฉด ํผ์ ํธ๋ก ๊ณผ ๊ฑฐ์ ๋์ผํ๊ฒ ๋ณด์ด์ง๋ง, โฎ(z(i)) ๋ ์ ์ ํด๋์ค ๋ ์ด๋ธ์ด ์๋๊ณ ์ค์๋ผ๋ ์ ์ด ๋ค๋ฆ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ฐ๊ฐ ์ํ๋ง๋ค ๊ฐ์ค์น๋ฅผ ์ ๋ฐ์ดํธ ํ๋ ๊ฒ์ด ์๋ ๋ชจ๋ ์ํ์ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ์ค์น ์ ๋ฐ์ดํธ๋ฅผ ๊ณ์ฐํฉ๋๋ค. ์ด ๋ฐฉ์์ ๋ฐฐ์น ๊ฒฝ์ฌ ํ๊ฐ๋ฒ(batch gradient descent)์ด๋ผ๊ณ ํฉ๋๋ค.
3. ํ์ด์ฌ์ผ๋ก ์๋ฌ๋ฆฐ ๊ตฌํํ๊ธฐ
class AdalineGD(object):
"""์ ์ํ ์ ํ ๋ด๋ฐ ๋ถ๋ฅ๊ธฐ
๋งค๊ฐ๋ณ์
------------
eta : float
ํ์ต๋ฅ (0.0๊ณผ 1.0 ์ฌ์ด)
n_iter : int
ํ๋ จ ๋ฐ์ดํฐ์
๋ฐ๋ณต ํ์
random_state : int
๊ฐ์ค์น ๋ฌด์์ ์ด๊ธฐํ๋ฅผ ์ํ ๋์ ์์ฑ๊ธฐ ์๋
์์ฑ
-----------
w_ : 1d-array
ํ์ต๋ ๊ฐ์ค์น
cost_ : list
์ํฌํฌ๋ง๋ค ๋์ ๋ ๋น์ฉ ํจ์์ ์ ๊ณฑํฉ
"""
def __init__(self, eta=0.01, n_iter=50, random_state=1):
self.eta = eta
self.n_iter = n_iter
self.random_state = random_state
def fit(self, X, y):
"""ํ๋ จ ๋ฐ์ดํฐ ํ์ต
๋งค๊ฐ๋ณ์
----------
X : {array-like}, shape = [n_samples, n_features]
n_samples ๊ฐ์ ์ํ๊ณผ n_features ๊ฐ์ ํน์ฑ์ผ๋ก ์ด๋ฃจ์ด์ง ํ๋ จ ๋ฐ์ดํฐ
y : array-like, shape = [n_samples]
ํ๊น๊ฐ
๋ฐํ๊ฐ
-------
self : object
"""
rgen = np.random.RandomState(self.random_state)
self.w_ = rgen.normal(loc=0.0, scale=0.01, size=1 + X.shape[1])
self.cost_ = []
for i in range(self.n_iter):
net_input = self.net_input(X)
# Please note that the "activation" method has no effect
# in the code since it is simply an identity function. We
# could write `output = self.net_input(X)` directly instead.
# The purpose of the activation is more conceptual, i.e.,
# in the case of logistic regression (as we will see later),
# we could change it to
# a sigmoid function to implement a logistic regression classifier.
output = self.activation(net_input)
errors = (y - output)
self.w_[1:] += self.eta * X.T.dot(errors)
self.w_[0] += self.eta * errors.sum()
cost = (errors**2).sum() / 2.0
self.cost_.append(cost)
return self
def net_input(self, X):
"""์ต์ข
์
๋ ฅ ๊ณ์ฐ"""
return np.dot(X, self.w_[1:]) + self.w_[0]
def activation(self, X):
"""์ ํ ํ์ฑํ ๊ณ์ฐ"""
return X
def predict(self, X):
"""๋จ์ ๊ณ๋จ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํด๋์ค ๋ ์ด๋ธ์ ๋ฐํํฉ๋๋ค"""
return np.where(self.activation(self.net_input(X)) >= 0.0, 1, -1)
ํผ์ ํธ๋ก ๊ณผ ๋ค๋ฅธ ์ ์ด ๋ณด์ด์๋์? fit ๋ฉ์๋ ์ ๋ฐ๋ณต๋ฌธ์ self.w_[1:] += self.eta * X.T.dot(errors)์ self.w_[0] * errors.sum()์ด ๋ค๋ฅด์ฃ . 0๋ฒ์งธ ๊ฐ์ค์น์ธ ์ ํธ์ด ์ค์ฐจํฉ๊ณผ ํ์ต๋ฅ ์ ๊ณฑ์ด๊ณ , ๊ทธ ์ด์ธ์ ๋ถ๋ถ์์๋ X.T.dot(errors)๋ ํน์ฑ ์ค์ฐจ ๋ฒกํฐ ๊ฐ์ ํ๋ ฌ๊ณผ ๋ฒกํฐ์ ๊ณฑ์ ํ์ต๋ฅ ์ ๊ณฑํ ๊ฐ์ ๋๋ค.
๋ ๋ค๋ฅธ ์ ์ activation ๋ฉ์๋์ธ๋ฐ, ์ด๊ฒ์ ๊ทธ์ ๋จ์ํ ํญ๋ฑ ํจ์์ด๊ธฐ ๋๋ฌธ์ ๋ณ๋ค๋ฅธ ์ํฅ์ ๋ฏธ์น์ง ์์ต๋๋ค.
์ค์ ๋ชจ๋ธ์์๋ ์ต์ ์ผ๋ก ์๋ ดํ๋ ์ข์ ํ์ต๋ฅ (learning rate)๋ฅผ ์ฐพ๊ธฐ ์ํด ์ฌ๋ฌ ๋ฒ ์คํ์ ๊ฑฐ์ณ์ผํฉ๋๋ค. ํ์ต๋ฅ 0.01๊ณผ 0.0001์ ๋น๊ตํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 4))
ada1 = AdalineGD(n_iter=10, eta=0.01).fit(X, y)
ax[0].plot(range(1, len(ada1.cost_) + 1), np.log10(ada1.cost_), marker='o')
ax[0].set_xlabel('Epochs')
ax[0].set_ylabel('log(Sum-squared-error)')
ax[0].set_title('Adaline - Learning rate 0.01')
ada2 = AdalineGD(n_iter=10, eta=0.0001).fit(X, y)
ax[1].plot(range(1, len(ada2.cost_) + 1), ada2.cost_, marker='o')
ax[1].set_xlabel('Epochs')
ax[1].set_ylabel('Sum-squared-error')
ax[1].set_title('Adaline - Learning rate 0.0001')
plt.show()
์ผ์ชฝ๊ณผ ์ค๋ฅธ์ชฝ์ ๋น๊ตํด๋ณด๋ฉด, ํ์ต๋ฅ ์ด 0.01์ธ ๊ฒฝ์ฐ์ epoch์ด ๋์ด๋จ์๋ ๋ถ๊ตฌํ๊ณ ์คํ๋ ค ์ค์ฐจ๊ฐ ๊ณ์ ๋์ด๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ ๊ฐ์ค์น๋ฅผ ์ ๋ฐ์ดํธํ ๋ ํ์ต๋ฅ ์ด ๋๋ฌด ์ปค์ ๊ฒฝ์ฌํ๊ฐ์ ํ๋ ์ค์ ๊ธฐ์ธ๊ธฐ๊ฐ ์ต์๊ฐ ๋๋ ๊ฐ์ ์ฐพ์ง ๋ชปํ๊ณ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ค๋ฅธ์ชฝ์ ๊ฒฝ์ฐ๋ ์คํ๋ ค ํ์ต๋ฅ ์ด ๋๋ฌด ์์์ ์ต์๊ฐ์ ์๋ ดํ๊ธฐ ์ํด์๋ ์์ฃผ ๋ง์ epoch์ด ํ์ํฉ๋๋ค. ์๋ ๊ทธ๋ฆผ 8์ด ๊ธ๋ก ์ค๋ช ํ ๋ด์ฉ์ ๊ทธ๋ฆผ์ผ๋ก ์ค๋ช ํด์ฃผ๊ณ ์์ต๋๋ค.
4. ๊ฒฝ์ฌ ํ๊ฐ๋ฒ ์ฑ๋ฅ ๊ฐํํ๊ธฐ
๋ชจ๋ธ์์ ์ต์ ์ ์ฑ๋ฅ์ ์ํด ํ์ํ ๊ฒ์ ์ข์ ๋ชจ๋ธ๋ง์ด ์๋๋๋ค. ๋ ๋ฒ์งธ ์ธ์ ์ ๋์๋ ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ๋ฅผ ๊ธฐ์ตํ์๋์? (https://dnai-deny.tistory.com/3) ์ง๊ธ ๋ณผ ๋ด์ฉ์ ์ต์ ์ ์ฑ๋ฅ์ ์ํด ํน์ฑ ์ค์ผ์ผ, ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ์ ๋ฐ๋์ ๋ด๊ฐ๋ณผ ์ ์๋ ํ์คํ(standardization) ์ ๋๋ค. ์ด ๊ธฐ์ ์ ๋ฐ์ดํฐ์ ์ ๊ท๋ถํฌ์ ์ฑ์ง์ ๋ถ์ฌํด ๊ฒฝ์ฌ ํ๊ฐ๋ฒ ํ์ต์ด ๋น ๋ฅด๊ฒ ์๋ ดํ ์ ์๋๋ก ๋ง๋ค์ด์ค๋๋ค. ์ด ๊ณผ์ ์ ์ ๊ท๋ถํฌ์ ๊ฐ์ด ํ์ค์ 0์ ๋ง์ถ๊ณ ํ์คํธ์ฐจ๋ฅผ 1๋ก ๋ง๋ญ๋๋ค. j๋ฒ์งธ ํน์ฑ์ ํ์คํํ๋ ๋ฐฉ๋ฒ์ ์๋ ์์์์ ํ์ธํ ์ ์์ต๋๋ค.
๋ชจ๋ ์ํ์์ ํ๊ท ์ ๋บ ๊ฒ์ ํ์คํธ์ฐจ๋ก ๋๋๋ฉด ๋ฉ๋๋ค. xj๋ ๋ชจ๋ ์ํ์ j๋ฒ์งธ ํน์ฑ์ ํฌํจํ ๋ฐฑํฐ๋ฅผ ์๋ฏธํฉ๋๋ค. ์ฒ๋ฆฌ๋ฅผ ๊ฑฐ์น๊ฒ ๋๋ฉด ์๋ ๊ทธ๋ฆผ 10์์ ๋ณด์ด๋ ๊ฒ์ฒ๋ผ ๋ ์ ์ ๊ณผ์ ์ผ๋ก ๋น ๋ฅด๊ฒ ์ต์ ์ ํด๊ฒฐ๋ฐฉ๋ฒ์ ์ฐพ์ ์ ์์ฃ .
์๋ ์ฝ๋๋ฅผ ์ด์ฉํด์ ๊ฐ๋จํ๊ฒ ํ์คํ๋ฅผ ํ ์ ์์ต๋๋ค. numpy ๋ด์ฅ ํจ์ mean๊ณผ std๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ ๋๋ถ์ด์ฃ .
# ํน์ฑ์ ํ์คํํฉ๋๋ค.
X_std = np.copy(X)
X_std[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std()
X_std[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std()
ada = AdalineGD(n_iter=15, eta=0.01)
ada.fit(X_std, y)
plot_decision_regions(X_std, y, classifier=ada)
plt.title('Adaline - Gradient Descent')
plt.xlabel('sepal length [standardized]')
plt.ylabel('petal length [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Sum-squared-error')
plt.tight_layout()
plt.show()
ํ์คํ๊ฐ ๋๋๋ฉด ๊ฒฐ์ ๊ฒฝ๊ณ ๊ทธ๋ํ์ ๋น์ฉ์ด ๊ฐ์๋๋ cost function ๊ทธ๋ํ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ํ์ต๋ฅ ์ 0.01๋ก ์ฌ์ฉํ๊ณ , ํน์ฑ์ ํ์คํํ๋ ํ์คํ ๋ชจ๋ธ์ด ์๋ ดํ๋ ๊ฒ์ ๋ณผ ์ ์์ฃ . ํ์ง๋ง ๋ชจ๋ ์ํ์ด ์๋ฒฝํ๊ฒ ๋ถ๋ฅ๋๋๋ผ๋ Sum-Squared error์ ๊ฐ์ด 0์ด ๋์ง๋ ์์ต๋๋ค.
5. ๋๊ท๋ชจ ๋จธ์ ๋ฌ๋๊ณผ ํ๋ฅ ์ ์ธ ๊ฒฝ์ฌํ๊ฐ๋ฒ
4์ ๊ฐ์ ๋ฐฉ๋ฒ์ ๋ค๋ฅธ ๋ง๋ก ๋ฐฐ์น ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ด๋ผ๊ณ ํฉ๋๋ค. ํ์ง๋ง ๋งค์ฐ ๋ง์ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ค์ผํ๋ ๊ฒฝ์ฐ์๋ ๋ฐฐ์น ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ ์ด์ฉํ๋ฉด ๊ณ์ฐ ๋น์ฉ์ด ์๋นํ ๋์์ง๋๋ค. ๊ณ์ฐํด์ผํ ๊ฑฐ๋ฆฌ๊ฐ ๋ง์์ง๊ธฐ ๋๋ฌธ์ด์ฃ . ๊ฐ์ค์น๊ฐ ์ ๋ฐ์ดํธ ๋ ๋๋ง๋ค ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋ค์ ํ์ตํด์ผํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํจ์จ์ ์ผ๋ก ํด๊ฒฐํ๊ธฐ ์ํด์ ํ๋ฅ ์ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ(stochastic gradient descent)๊ฐ ๋ฑ์ฅํฉ๋๋ค. ์๋ ์์ ๋ ๊ฐ๋ฅผ ๋น๊ตํด๋ณด๋ฉด์ ์ด์ผ๊ธฐํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ ์์์ ์๊ทธ๋ง ๊ธฐํธ๊ฐ ๋ณด์ด์๋์? ์ฒซ ๋ฒ์งธ ์์์ ๋ฐฐ์น ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ ๋ณด์ฌ์ฃผ๊ณ ์๋๋ฐ, ์๊ทธ๋ง ๊ธฐํธ๋ฅผ ํตํด์ ์ ์ฒด ๋ฐ์ดํฐ ์ x์ ๋ํด์ ๋์ ๋ ์ค์ฐจ ํฉ์ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ์ค์น๋ฅผ ์ ๋ฐ์ดํธ ํฉ๋๋ค. ๋ฐ๋ฉด์ ๋ ๋ฒ์งธ ์์, ํ๋ฅ ์ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์์๋ ๊ฐ ํ๋ จ ์ํ์ ๋ํด์ ์กฐ๊ธ์ฉ ๊ฐ์ค์น๋ฅผ ์ ๋ฐ์ดํธ ํฉ๋๋ค.
ํ๋ฅ ์ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ ์ผ๋ฐ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ๋ณด๋ค ํจ์ฌ ์์ฃผ ๊ฐ์ค์น๋ฅผ ์ ๋ฐ์ดํธ ํด์ฃผ๊ธฐ ๋๋ฌธ์ ์๋ ด ์๋๊ฐ ํจ์ฌ ๋น ๋ฆ ๋๋ค. ๋ค๋ง ์ค์ฐจ์ ๊ถค์ (๊ทธ๋ํ)๋ ํจ์ฌ ์ด์ง๋ฌ์ด ํํ๊ฐ ๋์ฃ . ํ๋ฅ ์ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์์ ์ข์ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ ์ํด์๋ ํ๋ จ ์ํ์ ์์๋ฅผ ๋๋คํ๊ฒ, ๊ทธ๋ฆฌ๊ณ ์ํญ๋ง๋ค ํ๋ จ์ธํธ๋ฅผ ์๋ ๊ฒ์ด ์ข์ต๋๋ค.
ํ๋ฅ ์ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ ๋ ์จ๋ผ์ธ ํ์ต์ผ๋ก ์ฌ์ฉํ ์ ์๋ค๋ ์ฅ์ ์ด ์์ต๋๋ค. ์จ๋ผ์ธ ํ์ต์์ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ์๋ก์ด ๋ฐ์ดํฐ๊ฐ ๋์ฐฉํ๋ฉด ๊ณ์ํด์ ํ๋ จ๋ฉ๋๋ค. ํนํ ์จ๋ผ์ธ ํ์ต์ ๋ง์ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ค์ผํ ๋ ์ ์ฉํฉ๋๋ค. ์ ์ฅ ๊ณต๊ฐ์ ์ ์ฝ์ด ์๋ค๋ฉด ๋ชจ๋ธ์ ์ ๋ฐ์ดํธํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ฒ๋ฆฌ๋ ๊ฒ๋ ๊ฐ๋ฅํ๊ณ , ์ค์๊ฐ์ผ๋ก ์ ๋ฐ์ดํธ๋๋ ๋ณํ์ ์ฆ์ ์ ์ํ ์ ์์ต๋๋ค.
์ด๋ฏธ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ ๊ตฌํํ๊ธฐ ๋๋ฌธ์ ์ฝ๊ฐ์ ์์ ์ ํตํด ํ๋ฅ ์ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ ๋ง๋ค ์ ์์ต๋๋ค.
class AdalineSGD(object):
"""ADAptive LInear NEuron ๋ถ๋ฅ๊ธฐ
Parameters
------------
eta : float
ํ์ต๋ฅ (0.0๊ณผ 1.0 ์ฌ์ด)
n_iter : int
ํ๋ จ ๋ฐ์ดํฐ์
๋ฐ๋ณต ํ์
shuffle : bool (default: True)
True๋ก ์ค์ ํ๋ฉด ๊ฐ์ ๋ฐ๋ณต์ด ๋์ง ์๋๋ก ์ํฌํฌ๋ง๋ค ํ๋ จ ๋ฐ์ดํฐ๋ฅผ ์์ต๋๋ค
random_state : int
๊ฐ์ค์น ๋ฌด์์ ์ด๊ธฐํ๋ฅผ ์ํ ๋์ ์์ฑ๊ธฐ ์๋
Attributes
-----------
w_ : 1d-array
ํ์ต๋ ๊ฐ์ค์น
cost_ : list
๋ชจ๋ ํ๋ จ ์ํ์ ๋ํด ์ํฌํฌ๋ง๋ค ๋์ ๋ ํ๊ท ๋น์ฉ ํจ์์ ์ ๊ณฑํฉ
"""
def __init__(self, eta=0.01, n_iter=10, shuffle=True, random_state=None):
self.eta = eta
self.n_iter = n_iter
self.w_initialized = False
self.shuffle = shuffle
self.random_state = random_state
def fit(self, X, y):
"""ํ๋ จ ๋ฐ์ดํฐ ํ์ต
Parameters
----------
X : {array-like}, shape = [n_samples, n_features]
n_samples ๊ฐ์ ์ํ๊ณผ n_features ๊ฐ์ ํน์ฑ์ผ๋ก ์ด๋ฃจ์ด์ง ํ๋ จ ๋ฐ์ดํฐ
y : array-like, shape = [n_samples]
ํ๊น ๋ฒกํฐ
๋ฐํ๊ฐ
-------
self : object
"""
self._initialize_weights(X.shape[1])
self.cost_ = []
for i in range(self.n_iter):
if self.shuffle:
X, y = self._shuffle(X, y)
cost = []
for xi, target in zip(X, y):
cost.append(self._update_weights(xi, target))
avg_cost = sum(cost) / len(y)
self.cost_.append(avg_cost)
return self
def partial_fit(self, X, y):
"""๊ฐ์ค์น๋ฅผ ๋ค์ ์ด๊ธฐํํ์ง ์๊ณ ํ๋ จ ๋ฐ์ดํฐ๋ฅผ ํ์ตํฉ๋๋ค"""
if not self.w_initialized:
self._initialize_weights(X.shape[1])
if y.ravel().shape[0] > 1:
for xi, target in zip(X, y):
self._update_weights(xi, target)
else:
self._update_weights(X, y)
return self
def _shuffle(self, X, y):
"""ํ๋ จ ๋ฐ์ดํฐ๋ฅผ ์์ต๋๋ค"""
r = self.rgen.permutation(len(y))
return X[r], y[r]
def _initialize_weights(self, m):
"""๋๋คํ ์์ ์๋ก ๊ฐ์ค์น๋ฅผ ์ด๊ธฐํํฉ๋๋ค"""
self.rgen = np.random.RandomState(self.random_state)
self.w_ = self.rgen.normal(loc=0.0, scale=0.01, size=1 + m)
self.w_initialized = True
def _update_weights(self, xi, target):
"""์๋ฌ๋ฆฐ ํ์ต ๊ท์น์ ์ ์ฉํ์ฌ ๊ฐ์ค์น๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค"""
output = self.activation(self.net_input(xi))
error = (target - output)
self.w_[1:] += self.eta * xi.dot(error)
self.w_[0] += self.eta * error
cost = 0.5 * error**2
return cost
def net_input(self, X):
"""์ต์ข
์
๋ ฅ ๊ณ์ฐ"""
return np.dot(X, self.w_[1:]) + self.w_[0]
def activation(self, X):
"""์ ํ ํ์ฑํ ๊ณ์ฐ"""
return X
def predict(self, X):
"""๋จ์ ๊ณ๋จ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํด๋์ค ๋ ์ด๋ธ์ ๋ฐํํฉ๋๋ค"""
return np.where(self.activation(self.net_input(X)) >= 0.0, 1, -1)
ada = AdalineSGD(n_iter=15, eta=0.01, random_state=1)
ada.fit(X_std, y)
plot_decision_regions(X_std, y, classifier=ada)
plt.title('Adaline - Stochastic Gradient Descent')
plt.xlabel('sepal length [standardized]')
plt.ylabel('petal length [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Average Cost')
plt.tight_layout()
plt.show()
์ ์ฝ๋์์ fit ๋ฉ์๋ ์์์ ๊ฐ ํ๋ จ ์ํ๋ง๋ค ๊ฐ์ค์น๋ฅผ ์ ๋ฐ์ดํธ ํ ๊ฒ๋๋ค. ๊ทธ๋ฆฌ๊ณ partial_fit ๋ฉ์๋๋ฅผ ๊ตฌํํด์ ๊ฐ์ค์น๋ฅผ ์ด๊ธฐํํ์ง ์๋๋ก ํด์ ์จ๋ผ์ธ ํ์ต์์ ์ฌ์ฉํ๋๋ก ํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก ๊ฐ ์ํญ๋ง๋ค ํ๊ท ๋น์ฉ์ ๊ณ์ฐํ๊ณ ์ํฌํฌ๊ฐ ๋ณํ๊ธฐ ์ ์ ํ๋ จ์ํ์ ์์ต๋๋ค.
์๋ฌ๋ฆฐ ๋ถ๋ฅ๊ฐ์์ ์ฌ์ฉํ๋ _shuffle ๋ฉ์๋๋ np.random ๋ชจ๋์ permutation ํจ์๋ก 0๋ถํฐ 100์ฌ์ด์ ๋๋ค ์ซ์ ์ํ์ค๋ฅผ ์์ฑํด ์ํ์ ์๋ ์ธ๋ฑ์ค๋ก ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ fit ๋ฉ์๋๋ก ํ๋ จํ๊ณ , plot_decision_regions๋ก ๊ทธ๋ํ๋ฅผ ๊ทธ๋ฆฝ๋๋ค.
ํ์ต๊ณก์ ๊ทธ๋ํ์์ ํ์คํ ํ๊ท ๋น์ฉ(cost)๊ฐ ๋น ๋ฅด๊ฒ ๊ฐ์ํฉ๋๋ค. ์ํฌํฌ๊ฐ ์ด๋์ ๋ ์ง๋๋ฉด ์ต์ข ๊ฒฐ์ ๊ฒฝ๊ณ๋ ๋ฐฐ์น ํ๊ฐ๋ฒ๊ณผ ๊ฑฐ์ ๋น์ทํฉ๋๋ค. ์ฌ๊ธฐ์ ์จ๋ผ์ธ ํ์ต ๋ฐฉ์์ผ๋ก ํ๋ จํ๊ธฐ ์ํด์๋ ๊ฐ๊ฐ์ ์ํ์ ์๋์ ๊ฐ์ด partial_fit ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
ada.partial_fit(X_std[0,:], y[0])
์ด๋ฒ 3, 4, 5์ธ์ ์์๋ ๊ธฐ์ด์ ์ ํ ๋ถ๋ฅ๊ธฐ์ธ ํผ์ ํธ๋ก ๊ณผ ์๋ฌ๋ฆฐ ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํํด๋ณด์์ต๋๋ค. ๋, ์์ฃผ ์ค์ํ ๊ฒฝ์ฌํ๊ฐ๋ฒ๋ ๋ฐฐ์ ์ฃ . ์ด๋ฅผ ํตํด ์ฌ๋ฌ๋ถ์ ๊ฐ๋จํ ๋ถ๋ฅ๊ธฐ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์๊ฒ ๋์ จ์ต๋๋ค. ์ถํ๋๋ ค์! ์ด๋ฒ ๊ตฌํ์ ์ฌ์ฉํ ๊ฐ์ฒด ์งํฅ ๋ฐฉ์์ด ์ดํ ์ฌ์ดํท๋ฐ์ ์ดํดํ๋๋ฐ์๋ ๋์์ด ๋์ค ๊ฒ๋๋ค.
๋ค์ ์ธ์ ๋ถํฐ๋ ๋ก์ง์คํฑ ํ๊ท๋ฅผ ๋ค๋ฃจ๊ฒ ๋ฉ๋๋ค. ์ฌ์ดํท๋ฐ์ ํตํด์ ํผ์ ํธ๋ก ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ๋ ์ดํด๋ณผ ๊ฑฐ๊ณ , ์ค์ํ ํจ์์ธ ์๊ทธ๋ชจ์ด๋ ํจ์๋ ๋ฐฐ์ฐ๊ฒ ๋ ๊ฒ๋๋ค. ๋ชจ๋๋ค ์๊ณ ํ์ จ๊ณ , ํญ์ ๋ง์๋๋ฆฌ๋ค์ํผ ๋ชจ๋ ์ฝ๋๋ฅผ ์ดํดํ์ค ํ์๋ ์์ง๋ง ์ฃผ์ํ ํจ์๋ค์ ๊ผญ ์์๋์ธ์! ๋ค์ ์๊ฐ์ ๋ต๊ฒ ์ต๋๋ค!