> ADALINE のアルゴリズムが特に興味深いのは、連続値の[[コスト関数]] の定義とその最小化に関する重要な概念を具体的に示すからである。コスト関数は、この後の章で説明する[[ロジスティック回帰]]、[[サポートベクターマシン]]、[[回帰]]モデルなど、分類向けのより高度な機械学習アルゴリズムにつ いて理解するための土台を築くものである。
※ B. Widrow and others, An Adaptive "Adaline" Neuron Using Chemical "Memistors", Technical Report Number 1553-2, Stanford Electron Labs, Stanford, CA, October 1960
> ADALINE の学習規則と Rosenblatt のパーセプトロンの主な違いは、重みの更新方法にある。ADALINEの学習規則では、パーセプトロンのような単位[[ステップ関数]]ではなく、**線形活性化関数**に基づいて重みが更新される。ADALINEでは、この線形活性化関数 𝜙(z) は単に総入力の[[恒等関数]]であり、次の式で表される。なお、ADALINE の学習規則は [[Widrow-Hoff則]]とも呼ばれる。
$\newcommand{\bm}[1]{\boldsymbol{#1}}$
$\phi(\bm{w}^{T}\bm{x}) = \bm{w}^{T}\bm{x}$
> 線形活性化関数は重みの学習に使用されるが、最終的な予測にはやはりしきい値関数を使用する。
![[ADALINE/ScreenShot_2020-10-15_at_5.07.57_PM.png]]
> ADALINE の場合は、重みの学習に用いるコスト関数 J を定義できる 。 それらの重みは、計算された成果指標と真のクラスラベルとの誤差平方和(Sum of Squared Error: SSE)として学習される。
$J(\bm{w}) = \frac{1}{2} \sum_{i}(y^{(i)}-\phi(z^{(i)}))^2$
1/2 は勾配を得やすくするために便宜上追加したもの。微分したときに平方の係数と相殺される。
連続値の線形活性化関数の利点: 単位ステップ関数とは対照的に、コスト関数が微分可能になること。
コスト関数のもう一つの特徴は、凸関数であること。
[[勾配降下法(gradient [[descent)]]]] を用いて、コスト関数を最小化する重みを発見できる。
**勾配降下法による重みの更新**
コスト関数 *J* (***w***) の勾配 **∇***J*(***w***) に沿って逆方向に1 ステップ進む
$\bm{w} = \bm{w} + \Delta \bm{w}$
$\Delta \bm{w} = - \eta \nabla J(\bm{w})$
コスト関数の勾配を計算するには、重み $w_{j}$ ごとにコスト関数の偏微分係数を計算する必要がある。
$\displaystyle \cfrac{\partial J}{\partial w_{j}} = - \sum_{i}(y^{(i)} - \phi(z^{(i)}))x^{(i)}_{j}$
以上より、重み $w_{j}$ の更新を次のように記述できる。
$\displaystyle \Delta w_{j} = - \eta \sum_{i}(y^{(i)} - \phi(z^{(i)}))x^{(i)}_{j}$
> ... 重みの更新は(サンプルごとに重みを小刻みに更新するのではなく)トレーニングデータセットのすべてのサンプルに基づいて計算される。このアプローチが「バッチ」勾配降下法とも呼ばれるのは、そのためである。
### ADALINEの分類器のPython実装
```python
class AdalineGD(object):
"""ADALINE分類器
eta: float
n_iter: int
random_state: int
w_: 一次元配列
cost_: リスト
各エポックでの誤差平方和のコスト関数
"""
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):
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)
output = self.activation(net_input) # ロジスティック回帰の場合は、シグモイド関数に変更できる
# 誤差の計算
errors = (y - output)
# 重みの更新
self.w_[1:] += self.eta * X.T.dot(errors) # X.T.dotは特徴行列と誤差ベクトルの行列ベクトル積
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):
""" 1ステップ後のクラスラベルを返す"""
return np.where(self.activation(self.net_input(X)) >= 0.0, 1, -1)
```
### 収束に最も適した学習率 𝜂 を見つける
ある程度の実験が必要。
- 左グラフ: 選択した学習率が大きすぎると大局的最小値を「超えて」しまうため、コスト関数を最小化するどころか、エポックごとに誤差平方和が増えている。
- 右グラフ: コストが減少していることがわかる。ただし、選択された学習率 𝜂 = 0.0001 は非常に小さいため、アルゴリズムをコストの大局的最小値に収束させるには、相当な数のエポックが必要になる。
![[ScreenShot_2020-10-17_at_9.04.29_AM.png]]
**特定の重みパラメータの値を変更することで、コスト関数 J を最小化する方法**
左図: 学習率がうまく選択された様子。 ($\eta=0.0001$)
右図: 学習率が大きすぎて、大局的最小値を超えてしまっている様子。($\eta = 0.01$)
![[ScreenShot_2020-10-17_at_9.05.57_AM.png]]
[[特徴量のスケーリング]] (標準化)により勾配降下法を改善できる。
標準化が勾配降下法による学習に役立つ理由: コストの大局的最小値を見つけ出すために実行しなければならないステップの数が少なくなること。
![[ScreenShot_2020-10-17_at_9.21.28_AM.png]]
勾配降下法では、すべてのサンプルにわたって蓄積された誤分類の合計を用いて重みを更新する。計算量が大きいので、トレーニングサンプルごとに段階的に重みを更新する。
以上、[[📖Python機械学習プログラミング 達人データサイエンティストによる理論と実践]] 2.2節より引用
---