ホップフィールドネットワークの記憶容量を改善する一つの試み:ロジスティック回帰に基づく学習アルゴリズムの実装

はじめに

総ニューロン数に対して約14%を超える記憶パタンを学習させると、Hopfieldモデルはパタンを正確に記憶できなくなり、想起性能が低下する現象が知られている。このニューロン数に対する記憶パタン数の上限は「記憶容量」(あるいは単に容量)と呼ばれ、その理論値は  0.138  n n はニューロン数)と計算されている [1]。記憶容量を改善する研究は数多く存在し、より多くの情報を効率的に記憶するための様々な手法が提案されている。

Hopfieldモデルの代表的な学習則は、生物学的な妥当性を重視したHebb則である。しかし、これはシナプス結合の局所的な情報のみを用いるため、学習能力に限界がある。容量の改善を第一に考えるならば、必ずしもHebb則に固執する必要はない。記憶パタンを、ネットワーク全体として最適な形で記憶するように学習する立場もある。例えば、記憶パタンから計算される擬似逆行列を用いる手法 [2] はよく知られている。

本記事では、記憶パタンを「教師データ」に対応させ、それらに対する一種の教師あり学習の問題としてモデルの学習を捉える。損失関数を適切に定義できれば、あとは勾配法を用いてモデルのパラメタを最適化することができる。David Mackayの名著 『Information Theory, Inference, and Learning Algorithms』[3] の第42章(42.8節)では、ロジスティック回帰の枠組みに基づいてHopfieldモデルの容量を改善できることが示唆されている。

今回、上記Mackayの本を参考に、ロジスティック回帰に基づく学習アルゴリズムを実装した。想起過程のダイナミクスを調べる実験を通じて、古典的なHebb則と比較して、想起性能(特にノイズに対するロバスト性)と容量が改善される結果を得た。本記事では、その詳細な内容について紹介する。

ロジスティック回帰に基づく学習

準備

ネットワークにおけるニューロンの総数を  n とする。 モデルに記憶させる  m 個のパタンを  \{ \mathbf{x}^{(1)},  \mathbf{x}^{(2)}, \ldots,  \mathbf{x}^{(m)} \} により与える。  \mathbf{x}^{(p)} = [ x^{(p)}_1, x^{(p)}_2, \ldots, x^{(p)}_n ]^\top であり、各要素  x_i^{(p)} \pm 1 の値をとる。

記憶行列を  \mathbf{W} = [ w_{ij}] と書く。 \mathbf{W} n \times n 行列であり、 w_{ij} はニューロン  i からニューロン  j への結合の強さを表す。制約として、対称性  w_{ij} = w_{ji} および自己結合の禁止  w_{ii} = 0 を課す。

ロジスティック回帰の枠組みに乗せるため、記憶パタンを0/1の形式に変換する:   \mathbf{x}^{(p)} = [ x^{(p)}_1, x^{(p)}_2, \ldots, x^{(p)}_n ]^\top の各要素を下記の規則に従って変換し、  \mathbf{t}^{(p)} = [t_1^{(p)}, t_2^{(p)}, ..., t_n^{(p)}]^\top を定義する。


t_i^{(p)}=
\begin{cases}
1  \;\;\;\;( x^{(p)}_i = 1)\\
0 \;\;\;\;( x^{(p)}_i = -1)
\end{cases}

この変換ルールは簡潔に  t_i^{(p)} = (x_i^{(p)} + 1) / 2 とも書ける。  \mathbf{t}^{(p)}  \mathbf{x}^{(p)} に対する目標出力(教師データ)の役割を果たす。

尤度と対数尤度

モデルの学習に際して


\begin{align*}
\mathcal{D} = \left\{(\mathbf{x}^{(1)}, \mathbf{t}^{(1)}), (\mathbf{x}^{(2)}, \mathbf{t}^{(2)}), ..., (\mathbf{x}^{(m)}, \mathbf{t}^{(m)})\right\}
\end{align*}

というデータセットが与えられたと考える。各パタン  (\mathbf{x}^{(p)}, \mathbf{t}^{(p)}) は互いに独立に生成されたと仮定する。するとまず、データセット  \mathcal{D} 全体が得られる確率(尤度)は、各パタンが得られる確率の積として表すことができる。


\begin{align*}
L_{\mathcal{D}}(\mathbf{W}) \triangleq  P(  \mathcal{D} \mid \mathbf{W}) = \prod_{p=1}^{m} P(\mathbf{x}^{(p)}, \mathbf{t}^{(p)} \mid \mathbf{W} )
\end{align*}

ニューロン間の条件付き独立性の仮定を用いると、各パタンが得られる確率は、各ニューロンの目標出力が得られる確率の積として表すことができる。


\begin{align*}
P( \mathbf{x}^{(p)}, \mathbf{t}^{(p)} \mid \mathbf{W} ) =  P(\mathbf{x}^{(p)} \mid  \mathbf{W}) \prod_{i=1}^{n} P( t_i^{(p)} \mid \mathbf{x}^{(p)}, \mathbf{W} )
\end{align*}

入力パタン   \mathbf{x}^{(p)} における各ニューロン  x_i^{(p)} は、他のニューロンの状態  x_j^{(p)} から自身の状態  t_i^{(p)}\in \{0, 1\} を予測する(二値分類する)ロジスティック回帰モデルとして機能すると考える。ニューロン  x_i^{(p)} への総入力(活性化、アクティベーション)を  a_i^{(p)} と書き、出力を  y_i^{(p)} と書く。なお  \sigma (\cdot) はシグモイド関数である。


\begin{align*}
a_i^{(p)} &\triangleq \sum_{j\neq i} w_{ij} x_{j}^{(p)} = \sum_{j\neq i} w_{ij} (2\: t_j^{(p)} - 1)\\
y_i^{(p)} &\triangleq \frac{1}{1 + \exp(-a_i^{(p)})} = \sigma (a_i^{(p)})
\end{align*}

各ニューロン  x_i^{(p)} における出力  y_i^{(p)} t_i^{(p)} = 1 の確率として解釈できることから、目標出力  t_i^{(p)} が得られる条件付き確率はベルヌイ分布に従うと仮定できる。


\begin{align*}
P(t_i^{(p)} \mid\mathbf{x}^{(p)}, \mathbf{W}) &= P( t_i^{(p)} = 1 \mid \mathbf{x}^{(p)}, \mathbf{W} )^{t_i^{(p)}} P( t_i^{(p)} = 0 \mid \mathbf{x}^{(p)}, \mathbf{W} )^{1 - t_i^{(p)}} \\
&= \left(y_i^{(p)}\right)^{t_i^{(p)}} \left(1 - y_i^{(p)}\right)^{1 - t_i^{(p)}}
\end{align*}

さらに入力パタン  \mathbf{x}^{(p)} \mathbf{W} に依存しないと仮定する。


\begin{align*}
P( \mathbf{x}^{(p)} \mid \mathbf{W} ) = P( \mathbf{x}^{(p)} ) 
\end{align*}

つまり、入力パタン  \mathbf{x}^{(p)} \mathbf{W} とは無関係に生成される、ということを意味する。記憶対象パタンはあらかじめ外部から与えられており、モデルの学習プロセスに影響を与えない、という状況を反映している。

以上より、尤度は次式の積の形で表され、対数尤度はまた和の形で表される。


\begin{align*}
L_{\mathcal{D}}(\mathbf{W})  &= \prod_{p=1}^{m} P( \mathbf{x}^{(p)} ) \prod_{i=1}^{n}  \left(y_i^{(p)}\right)^{t_i^{(p)}} \left(1 - y_i^{(p)}\right)^{1 - t_i^{(p)}} \\
\log L_{\mathcal{D}}(\mathbf{W}) &=  \sum_{p=1}^{m} \log P( \mathbf{x}^{(p)} ) + \sum_{p=1}^{m} \sum_{i=1}^{n}  \{t_i^{(p)} \log (y_i^{(p)}) + (1 - t_i^{(p)}) \log (1 - y_i^{(p)})\}
\end{align*}

学習の目標は、全てのパタンとニューロンに対して尤度を最大化することであり、パラメタ  \mathbf{W} が最適化の対象となる。

オリジナルのHopfieldモデルでは、アクティベーションに対して符号関数を適用しており、各ニューロンの出力は  \{-1, 1\} という有限集合を値域に持つ。ここではシグモイド関数を適用しており、出力の値域が  [0,1] という区間(無限集合)へと変わる。出力に関するこれらの変更は、ロジスティック回帰の導入のためにはやむを得ない。ただし、このような変更は学習時にのみ一時的に行われるのであり、想起時には元の出力形式に戻る。

損失関数

尤度を最大化する代わりに、損失関数を最小化することを考える。損失関数は、負の対数尤度からモデルパラメタに関係のない項を引き去ることで得られる。


\begin{align*}
\mathcal{L} &\triangleq - \left(\log L_{\mathcal{D}}(\mathbf{W}) - \sum_{p=1}^{m} \log P( \mathbf{x}^{(p)} ) \right) \\
&= -\sum_{p=1}^{m}\sum_{i=1}^{n} \{t_{i}^{(p)} \log y_{i}^{(p)} + (1 - t_{i}^{(p)}) \log (1 - y_{i}^{(p)})\}
\end{align*}

これは二値交差エントロピーとしても知られている。一方でまた、負号を取りつつ、記憶パタン数  m で割ったもので損失関数を与えてもよい。


\begin{align*}
\mathcal{L}_{\text{ave}} &\triangleq  -\frac{1}{m} \left(\log L_{\mathcal{D}}(\mathbf{W}) - \sum_{p=1}^{m} \log P( \mathbf{x}^{(p)} ) \right) \\
&= -\frac{1}{m}\sum_{p=1}^{m}\sum_{i=1}^{n} \{t_{i}^{(p)} \log y_{i}^{(p)} + (1 - t_{i}^{(p)}) \log (1 - y_{i}^{(p)}) \} \\
&= \frac{1} {m} \mathcal{L} 
\end{align*}

この損失関数は「平均損失」を表す。平均損失を使用すると、データセットのサイズに依存せずに学習率を調整することが可能となる。今回は記憶パタン数を色々と変えて実験を行うので、平均損失のほうが都合が良い。 さらに、以下に示すメリットもある。データセット  \mathcal{D} 上の標本分布を次式で定義する。


\begin{align*}
q_{\mathcal{D}} (\mathbf{x}, \mathbf{t}) \triangleq \frac{1}{m} \sum_{p=1}^{m} \delta (\mathbf{x}, \mathbf{x}^{(p)}) \delta (\mathbf{t}, \mathbf{t}^{(p)}) = \frac{1}{m} \sum_{p=1}^{m} \prod_{i=1}^{n}  \delta (x_i, x_i^{(p)}) \delta (t_i, t_i^{(p)}) 
\end{align*}

すると、平均損失を明示的に期待値の形で書くことができる。


\begin{align*}
\mathcal{L}_{\text{ave}} &= \mathbb{E}_{q_{\mathcal{D}} (\mathbf{x}, \mathbf{t}) } [ -\log P(\mathbf{t} \mid \mathbf{x}, \mathbf{W}) ]
\end{align*}

ただし  \mathbb{E}_{q_{\mathcal{D}} (\mathbf{x}, \mathbf{t}) } [ \cdot] は標本分布による期待値を取る操作を表す。平均損失は、1つのパタンあたりの平均的な誤りを表しており、損失値を解釈しやすくなる。

勾配計算と対称化

勾配降下法に先立ち、パラメタ w_{ij} に関する損失関数の勾配を計算しておく。まずは損失関数を少し整理する。


\begin{align*}
\mathcal{L} &=  -\sum_{p=1}^{m}\sum_{i=1}^{n} \{t_{i}^{(p)} \log y_{i}^{(p)} + (1 - t_{i}^{(p)}) \log (1 - y_{i}^{(p)})\} \\
&=  -\sum_{p=1}^{m}\sum_{i=1}^{n} \left\{ t_{i}^{(p)} a_{i}^{(p)} - \log \left( 1 + \exp (a_{i}^{(p)}) \right)  \right\}
\end{align*}

そこで勾配を計算すれば、


\begin{align*}
\frac{\partial \mathcal{L}} { \partial w_{ij}} &= -\sum_{p=1}^{m} \left\{t_{i}^{(p)} \frac{\partial a_{i}^{(p)} }{ \partial w_{ij}}  - \frac{ \exp (a_{i}^{(p)}) }{1 + \exp (a_{i}^{(p)})  }\frac{\partial a_{i}^{(p)} }{ \partial w_{ij}}   \right\} \\
&= -\sum_{p=1}^{m} \left\{ t_{i}^{(p)}x_j^{(p)}  - y_{i}^{(p)} x_j^{(p)}  \right\} \\
&= -\sum_{p=1}^{m} (t_i^{(p)} - y_i^{(p)}) x_j^{(p)}
\end{align*}

となる。さらに行列記法に移れば、


\begin{align*}
\frac{\partial \mathcal{L}} { \partial \mathbf{W}} = \left[ \frac{\partial \mathcal{L}} { \partial w_{ij}} \right] = - (\mathbf{T} - \mathbf{Y})^{\top} \mathbf{X}
\end{align*}

となる。ここで、 \mathbf{X} = [\mathbf{x}^{(1)}, \mathbf{x}^{(2)}, \ldots, \mathbf{x}^{(m)}]^{\top} \mathbf{Y} = [\mathbf{y}^{(1)}, \mathbf{y}^{(2)}, \ldots, \mathbf{y}^{(m)}]^{\top}  \mathbf{T} = [\mathbf{t}^{(1)}, \mathbf{t}^{(2)}, \ldots, \mathbf{t}^{(m)}]^{\top} と置いた。いずれも  m \times n 行列である。

しかし、上記の勾配のままだと、更新後の記憶行列における対称性が保証されない。そこで、あらかじめ 勾配の対称化 を行う。対称化された勾配を次式で定義する。


\begin{align*}
\mathcal{S}\left( \frac{\partial \mathcal{L}} { \partial \mathbf{W}}\right) \triangleq \frac{1}{2} \left \{ \left(\frac{\partial \mathcal{L}} { \partial \mathbf{W}}\right) + \left( \frac{\partial \mathcal{L}} { \partial \mathbf{W}} \right)^{\top} \right\}
\end{align*}

成分ごとに書けば


\begin{align*}
\left[ \mathcal{S}\left( \frac{\partial \mathcal{L}} { \partial \mathbf{W}}\right) \right]_{i, j} = \frac{1}{2} \left( \frac{\partial \mathcal{L}} { \partial w_{ij}} + \frac{\partial \mathcal{L}} { \partial w_{ji}} \right)
\end{align*}

である。

損失関数が平均損失の場合は


\begin{align*}
\frac{\partial \mathcal{L}_{\text{ave}}} { \partial w_{ij}} &= -\frac{1}{m}\sum_{p=1}^{m} (t_i^{(p)} - y_i^{(p)}) x_j^{(p)} \\
\frac{\partial \mathcal{L}_{\text{ave}}} { \partial \mathbf{W}} &= - \frac{1}{m}(\mathbf{T} - \mathbf{Y})^{\top} \mathbf{X} \\
\mathcal{S}\left( \frac{\partial \mathcal{L}_{\text{ave}}} { \partial \mathbf{W}}\right) &= \frac{1}{2} \left \{ \left(\frac{\partial \mathcal{L}_{\text{ave}}} { \partial \mathbf{W}}\right) + \left( \frac{\partial \mathcal{L}_{\text{ave}}} { \partial \mathbf{W}} \right)^{\top} \right\}
\end{align*}

となる。

勾配降下法

対称化された勾配を用いて、勾配降下法のパラメタ更新則を書くことができる。


\begin{align*}
\mathbf{W}_{\text{new}}  = \mathbf{W}_{\text{old}} - \eta \: \mathcal{S} \left.\left(\frac{\partial \mathcal{L}} { \partial \mathbf{W}}\right) \right|_{ \mathbf{W} =  \mathbf{W}_{\text{old}}}
\end{align*}

本記事では正則化のために重み減衰を採用する。以下に示すように、勾配降下法の場合は重み減衰とL2正則化は等価である。まず損失関数に対してフロベニウスノルムの2乗による正則化項を加えたものを新たな損失関数とする。


\begin{align*}
\mathcal{L}  + \frac{\lambda}{2} \| \mathbf{W}\|_{F}^{2} = \mathcal{L}  + \frac{\lambda}{2} \sum_{i=1}^{n} \sum_{j=1}^{n} w_{ij}^{2}
\end{align*}

ここで   \| \cdot \|_{F} はフロベニウスノルムを表し、  \lambda は正則化の強さを制御するハイパパラメタである。上式より、フロベニウスノルムの2乗による正則化は  \mathbf{W}の各成分に対するL2正則化と等価である。そしてL2正則化を導入した場合の更新則は次式で与えられる。


\begin{align*}
\mathbf{W}_{\text{new}}  &= \mathbf{W}_{\text{old}} - \eta  \left.\left\{ \mathcal{S}\left( \frac{\partial \mathcal{L}} { \partial \mathbf{W}}\right) \right|_{ \mathbf{W} =  \mathbf{W}_{\text{old}}}  + \lambda  \mathbf{W}_{\text{old}} \right\} \\
&= ( 1 - \eta \lambda) \mathbf{W}_{\text{old}} -  \eta \: \mathcal{S} \left.\left(\frac{\partial \mathcal{L}} { \partial \mathbf{W}}\right) \right|_{ \mathbf{W} =  \mathbf{W}_{\text{old}}}
\end{align*}

重み減衰の効果は   ( 1 - \eta \lambda) \mathbf{W}_{\text{old}} に表れており、減衰のスケールは   ( 1 - \eta \lambda) となる。 最後に、 \mathbf{W}_{\text{new}} の対角成分を0にする操作によって、ニューロンの自己結合を禁止する制約を満たすようにする。


\begin{align*}
\mathbf{W}_{\text{new}}^{\prime}  = \mathbf{W}_{\text{new}} - \text{diag} (\mathbf{W}_{\text{new}})
\end{align*}

ここで   \text{diag} ( \cdot ) は行列の対角成分を残し、他の成分を全て0にする演算子を表す。以上が勾配降下法によるパラメタ更新の1ステップに相当する。ここまで述べた定式化は、損失関数が平均損失の場合も全く同様に当てはまる。

実装

以下に置いた。Enjoy!

実験の例を確認したいひとはこちらから(Google Colab):

先日公開した記事のPython実装からの差分を中心に説明する。まず、コマンドラインオプションについては、勾配降下法に関するものが増えている。重み減衰の強さは、本実装ではL2正則化の強さと等しい。

オプション名 説明 デフォルト値
--num_updates パラメタ更新回数 10
--learning_rate 学習率 1.0
--weight_decay 重み減衰(L2正則化)の強さ 0.0

学習のための learn 関数について、勾配降下法の該当箇所を抜粋する。

num_patterns = patterns.shape[0]
targets = np.copy(patterns)
targets[targets == -1] = 0
for _ in range(num_updates):
    activation = expit(patterns @ weights)
    _grad = -(targets - activation).T @ patterns / num_patterns
    grad = (_grad + _grad.T) / 2
    weights = weights - lr * (grad + weight_decay * weights)
    np.fill_diagonal(weights, 0.0)

規定回数だけパラメタ更新のループを回す形であり、かつ勾配計算に学習データ全体を用いるバッチ学習である。なおパラメタはHebb則を用いて初期化する。

以下は記憶パタンから目標出力への変換処理である。ニューロン値が-1の箇所を見つけて0に置き換える処理も、Numpyの力によって簡潔に書くことができる(ブールインデックス)。

targets[targets == -1] = 0

本実装では損失関数に平均損失を採用した。勾配を num_patterns で割っているのはそのためである。続く勾配の対称化処理は明白だろう。

_grad = -(targets - activation).T @ patterns / num_patterns
grad = (_grad + _grad.T) / 2

更新則は説明した通りである。weight_decay が重み減衰(L2正則化)に関するハイパパラメタである。パラメタ更新後に対角成分を0にする処理が必要だが、fill_diagonal 関数が便利に使える。

weights = weights - lr * (grad + weight_decay * weights)
np.fill_diagonal(weights, 0.0)

シェルスクリプトの例は以下の通りである。

#!/bin/bash

CURDIR=$(cd $(dirname $0);pwd)
LOGDIR=${CURDIR}/log

mkdir -p ${LOGDIR}

HOPNET=hopnet_dynamics_logistic.py
PYTHON=$(which python)

N_NEURONS=1000   # The number of neurons
N_PATTERNS=200   # The maximum number of patterns
N_STEPS=25       # The number of steps for recall process
N_UPDATES=10       # The number of updates in learning weights
LEARNING_RATE=1.0  # The learning rate in gradient decent
WEIGHT_DECAY=0.1   # The scale of weight decay

for i in 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.6 0.7 0.8 0.9; do
    LOG_FILE=log_${i}.txt
    echo -n "Initial similarity ${i} ... "
    ${PYTHON} ${CURDIR}/${HOPNET} --num_neurons ${N_NEURONS} \
              --num_patterns ${N_PATTERNS} \
              --num_steps ${N_STEPS} \
              --similarity ${i} \
              --num_updates ${N_UPDATES} \
              --learning_rate ${LEARNING_RATE} \
              --weight_decay ${WEIGHT_DECAY} \
              --log_file ${LOGDIR}/${LOG_FILE}
    echo "done"
done

今回のPython実装では、学習と想起過程のシミュレーションについて、スクリプトを分離せずに1つにまとめている。それゆえ、上記のシェルスクリプトでは同じデータを用いた学習を何度も繰り返すことになり、無駄が多い(時間がかかる)。効率を重視するならば、学習を一度だけ行って記憶行列のデータをファイルに書き出し、後にそれを読み出して想起過程のシミュレーションを行うのがよい。

実験

これまでの記事と同様に、方向余弦の初期値(0.05〜1.0)を指定して想起対象パタンから初期パタンを生成し、状態更新と共に変化する方向余弦の値を観察する。これらの初期値は、記憶パタンに加わる様々なノイズレベルをシミュレートしていると見なせる。最終的に方向余弦が1.0に収束すれば、想起成功と判定できる。

実験条件

主な実験条件を表に示す。

項目 設定値
ニューロン数 1000(固定)
記憶対象パタン数 80、200、300、400、500
方向余弦の初期値 0.05、0.1、0.15、0.2、0.25、0.3、0.35、
0.4、0.45、0.5、0.6、0.7、0.8、0.9
学習率 1.0
パラメタ更新回数 10
重み減衰(L2正則化)の強さ 0.1

実験を通して、総ニューロン数は 1000 で固定する。記憶対象パタン数を表のように変えたとき、記憶率はそれぞれ0.08、0.2、0.4、0.5である。記憶対象パタン数が80と200のときについては、C言語実装の記事で紹介した実験結果を踏まえて、Hebb則の結果と比較する。記憶パタン数をそれ以上増やした場合については、Hebb則では想起失敗の傾向は変わらないので、ロジスティック回帰の結果のみを示す。

実験結果

まず記憶対象パタン数80の場合について、Hebb則とロジスティック回帰の結果を図1に示す。この場合はどちらも傾向は同じであり、問題なく収束している。

図1 想起過程(ニューロン数1000、記憶パタン数80):左 Hebb則,右 ロジスティック回帰

記憶対象パタン数200の場合の結果を図2に示す。記憶率は 200/1000 = 0.2 で0.15を超えており、Hebb則ではパタンを記憶できず、どの初期値から開始しても別の平衡状態に収束している。ロジスティック回帰では、多くの初期値で想起に成功しており、ノイズに対するロバスト性も高まっている。実際、臨界方向余弦が依然として0.35付近に留まっていることが見て取れる。これらの結果より、想起性能ひいては容量の改善を達成できたといえる。

図2 想起過程(ニューロン数1000、記憶パタン数200):左 Hebb則,右 ロジスティック回帰

最後に、ロジスティック回帰について、記憶対象パタン数を300、400、500に増やした場合の結果を図3に示す。パタン数が増えるにつれて,臨界方向余弦は1にどんどん近づくが、パタン数500でも0.8付近であった。これらの結果から、ロジスティック回帰によって容量は2〜3倍程度(約  0.5\;n)にまで増大したのではないかと推測する。あくまで実験的な推測であり、理論的な保証はない。

図3 想起過程(ロジスティック回帰):
左 記憶パタン数300,中 記憶パタン数400,右 記憶パタン数500

おわりに

本記事では、ホップフィールドネットワークの容量を改善する一つの試みとして、ロジスティック回帰に基づく学習アルゴリズムを実装した。実験の結果、古典的なHebb則と比較して、想起性能と容量の向上が確認できた。

近年の研究では、Krotov らはエネルギー関数におけるニューロン間の相互作用関数を、従来の二次関数から指数2以上のべき乗関数に変更することで、容量がニューロン数に対してべき乗関数的にスケールすることを示した [4]。状態更新則も併せて変更することで、ネットワーク全体の安定性も確保した。さらに、Demircigil らは相互作用関数を指数関数に変更し、容量がニューロン数に対して指数関数的にスケールするという、飛躍的な増大を実現した [5]。論文 "Hopfield Networks is All You Need" [6] では、状態変数を連続値に拡張したモデルも検討されており、最終的には Transformer の self-attention と類似した構造が現れる。これらのモデルは、古典的な Hopfield モデルとは一線を画しており、"Modern" Hopfield モデルと呼ぶのが適切だろう。詳細は、それぞれの論文や "Hopfield Networks is All You Need" の解説ブログ [7]、日本語による紹介記事・スライド [8, 9]、および解説動画 [10-13] を参照してほしい。特に最後の [12, 13] は D. Krotov 氏本人による貴重な解説である。

今回実装したロジスティック回帰は、各ニューロンの分類能力を高めるための手法であり、エネルギー関数自体の構造(相互作用関数)を変更するものではない。相互作用関数は依然として二次関数のままである。結果として、容量はニューロン数に対して線形的にしかスケールせず、比較的早い段階で限界に達してしまった。今後は、先行研究で提案された相互作用関数を実装に組み込み、さらなる容量改善を目指したい。

最後に、ロジスティック回帰ベースの学習でやり残したことを書いておこう。

  • 今回実装したのはバッチ型の勾配降下法であるが、ミニバッチを導入した確率的勾配降下法の適用も可能である。

  • 学習率のチューニングや重み減衰のチューニングはほとんど行っていない。パラメタ更新のループ回数も決め打ちである。チューニング次第では、容量はもう少し改善するかもしれない。

  • L1ノルム正則化や慣性項も導入していないので、これらの簡単な改善策を色々と試してみてもよい。特にL1正則化はスパース学習・スパースエンコーディングとも関連して興味深い。

  • 最適化アルゴリズムについて、ニュートン法は計算量の観点から適用を見送ったが、代わりに準ニュートン法を適用してもよいだろう。

  • 単純に勾配降下法の初期値をHebb則によって与えるのではなく、初期値を擬似逆行列によって与えてもよいだろう。

参考文献・参考記事

[1] D.J. Amit, H. Gutfreund, H. Sompolinsky, "Storing Infinite Numbers of Patterns in a Spin-Glass Model of Neural Networks," Phys. Rev. Lett., vol.55, issue 14, pp.1530--1533, 1985.

[2] T. Kohonen, "Self-Organization and Associative Memory," Springer Berlin, Heidelberg, 1989.

[3] David J. C. MacKay. 2002. Information Theory, Inference and Learning Algorithms. Cambridge University Press, USA.

[4] D. Krotov, J. Hopfield, "Dense Associative Memory for Pattern Recognition," Advances in Neural Information Processing Systems (NIPS), vol.29, 2016. Link

[5] M. Demircigil, J. Heusel, M. Löwe, et al., "On a Model of Associative Memory with Huge Storage Capacity," J Stat Phys 168, 288–299 (2017). Link, Link (arXiv)

[6] H. Ramsauer, et al., "Hopfield Networks is All You Need," Paper presented at the meeting of the ICLR, 2021. Link

[7] Hopfield Networks is All You Need (同名論文の解説記事)

[8]【DL輪読会】Hopfield network 関連研究について(論文『Hopfield Networks is All You Need』の解説スライド)

[9] Modern Hopfield NetworkとTransformer attentionの関係(日本語による解説記事)

[10] 【DL輪読会 #379 3/3】Hopfield network 関連研究について ([8]の動画版)

[11] Hopfield Networks is All You Need (Paper Explained)(同名論文の解説動画)

[12] Modern Hopfield Networks for Novel Transformer Architectures (D. Krotov氏による解説動画)

[13] Recent Developments in Modern Hopfield Networks (Dense Associative Memories) (D. Krotov氏による解説動画)