神经网络在1980年代复兴归功于物理学家约翰·霍普菲尔德(Hopfield)。1982年,霍普菲尔德提出了一种新的神经网络,可以解决一大类模式识别问题,还可以给出一类组合优化问题的近似解。这种神经网络模型后被称为Hopfield神经网络。Hopfield神经网络是一种递归神经网络,由约翰.霍普菲德在1982年发明。Hopfield网络是一种结合存储系统和二元系统的神经网络。它保证了向局部极小的收敛,但收敛到错误的局部极小值(local minimum),而非全局极小(global minimum)的情况也可能发生。Hopfield网络也提供了模拟人类记忆的模型。Hopfield网络原理基于Lyapunov稳定性定理和LaSalle不变性定理。对于初次接触Hopfield网络的非控制领域的人来说,Hopfield网络的核心理论晦涩难懂。本文忽略艰深的理论,取而代之的利用应用例子来介绍Hopfield神经网络的工作原理。一旦建立了Hopfield神经网络的总体认识后,再去细究其理论基础(书上及网上博客)就会有高瞻远瞩的感觉,最终完全掌握Hopfield神经网络及其思想。
1. Hopfield网络原理
Hopfield网络最典型的应用是实现一个联想存储器:在网络中存储一个或多个模式,并能够利用不完全(缺失)的输入回忆起完整的模式。
考虑下图字符识别的例子:任务是从输入文本中提取字符,并转成对应的ASCII码形式。现在,假设你不小心弄脏了输入文本(如下右图所示),尽管它与原文本的相似度仍比其它字符对应的文本与该字符原本的相似度要高(至少我们人肉眼还是能从缺失的文本中一眼识别出这是一个“T”),但是毁掉的文本与原文本已经有很大差别了。
简单说说Hopfield网络的原理:Hopfield网络相当于一个具有多个吸引子的系统。(对于吸引子的大致定义:落入吸引子附近的状态都会被吸引到该吸引子所在的状态。)我们把每个吸引子所在的状态作为一个记忆原型,被毁坏的输入假定在记忆原型的附近,通过Hopfield网络,最终能够通过毁坏的输入回忆起它所对应的完整原型。
2. Hopfield网络结构
一个具有三个神经元的Hopfield网络结构如下图所示。网络中的每个神经元i与所有其他神经元j=i之间都存在连接,权值为ωij,神经元到它自身的权值为0。一个具有N个神经元的Hopfield网络的权值个数为N2。因此,Hopfield网络的计算成本相对其他同等大小的人工神经元来说要高很多。
上图所示的Hopfield网络的权值可规范成矩阵W:
\begin{matrix}
0 & 1 & -2 \\
1 & 0 & 1 \\
-2 &1 & 0
\end{matrix}
\right]$$
可知为一个对称矩阵,并且对角元素都等于0。虽是一个例子,**Hopfield网络的权值矩阵的确为一个对角元素等于0的对称矩阵。**
假定当前网络神经元的状态为$[1, 1, 1]$,我们计算神经元1的输出:
$$y_1=\left[\begin{matrix}1 & 1& 1\end{matrix}\right]\left[\begin{matrix}0 \\ 1&\\-2\end{matrix}\right]=-1$$
第一个神经元的下一时刻的状态由当前的输出确定:
$$n = \{\begin{matrix} 0 & y<0 \\ 1 & y >= 0 \end{matrix}$$
因此,下一时刻第一个神经元的状态变为$0$,Hopfield网络的状态变为$[0, 1, 1]$。
**注意:对于递归神经网络,一般将外部输入向量作为初始的网络状态。**
> 根据以上对Hopfield网络结构的介绍,我们知道要使其正常工作需要回答以下两个问题:
1)怎样“训练”这个网络?
2)怎样更新网络各神经元的状态?
下面,我们分别回答以上三个问题。
## 3. 怎样“训练”一个Hopfield网络
《神经网络设计》系统的介绍了Hopfield网络,并明确指出:Hopfield网络没有与之相关的学习规则,它不被训练,也不会自己学习。网络的权值是基于Lyapunov函数的设计过程确定的。本文给出两种得到Hopfield网络权值的方式,它们背后的原理不在本文范围内。
### 3.1 直接计算
假定我们需要在Hopfield网络中记忆存储一列模式的状态集$V^s,s=1,...,n$,每个状态的维数相同都为$m$。我们可以按如下公式计算网络的权值:
$$\omega_{ij}=\sum_{s=1}^n (2V_i^s-1)(2V_j^s-1), i\neq j$$
当$i=j$时,$\omega_{ij}=0$.
> 注意: 分析以上计算公式,知道,我们可以先对每个要记忆的模式单独计算权值矩阵,然后将所有矩阵相加,便得到最终的Hopfield网络权值矩阵。这种计算的好处,**使得`网络能够增量式记忆增量式到来的模式。`**
如果我们只有一个模式需要记忆,则计算公式变为:
$$\omega_{ij}= (2V_i-1)(2V_j-1), i\neq j$$
假定我们对一个具有5个神经元的Hopfield网络计算权值。它所需要记忆的模式为$V^1=[0, 1, 1, 0, 1]$。因为具有5个神经元,我们需要一个$5 \times 5$的矩阵来存储网络的权值。该权值矩阵应该长成下面这样:
$$W^1=\left[\begin{matrix}
0 & \omega_{12} & \omega_{13} & \omega_{14} & \omega_{15} \\
\omega_{21} & 0 & \omega_{23} & \omega_{24} & \omega_{25} \\
\omega_{31} & \omega_{32} & 0 & \omega_{34} & \omega_{35} \\
\omega_{41} & \omega_{42} & \omega_{43} & 0 & \omega_{45} \\
\omega_{51} & \omega_{52} & \omega_{53} & \omega_{54} & 0
\end{matrix}\right]$$
矩阵为对角元素等于0的对角阵,因此我们只需要计算斜对角一半的权值即可。
$\omega_{12}=\left(2 V_{1}-1\right)\left(2 V_{2}-1\right)=(0-1)(2-1)=(-1)(1)=-1$
$\omega_{13}=\left(2 V_{1}-1\right)\left(2 V_{3}-1\right)=(0-1)(2-1)=(-1)(1)=-1$
$\omega_{14}=\left(2 V_{1}-1\right)\left(2 V_{4}-1\right)=(0-1)(0-1)=(-1)(-1)=1$
$\omega_{15}=\left(2 V_{1}-1\right)\left(2 V_{5}-1\right)=(0-1)(2-1)=(-1)(1)=-1$
$\omega_{23}=\left(2 V_{2}-1\right)\left(2 V_{3}-1\right)=(2-1)(2-1)=(1)(1)=1$
$\omega_{24}=\left(2 V_{2}-1\right)\left(2 V_{4}-1\right)=(2-1)(0-1)=(1)(-1)=-1$
$\omega_{25}=\left(2 V_{2}-1\right)\left(2 V_{5}-1\right)=(2-1)(2-1)=(1)(1)=1$
$\omega_{34}=\left(2 V_{3}-1\right)\left(2 V_{4}-1\right)=(2-1)(0-1)=(1)(-1)=-1$
$\omega_{35}=\left(2 V_{3}-1\right)\left(2 V_{5}-1\right)=(2-1)(2-1)=(1)(1)=1$
$\omega_{45}=\left(2 V_{4}-1\right)\left(2 V_{5}-1\right)=(0-1)(2-1)=(-1)(1)=-1$
可得权值矩阵为:
$$W^1=\left[\begin{matrix}
0 & -1 & -1 &1 & -1 \\
-1 & 0 & 1 & -1 & 1 \\
-1 & 1 & 0 & -1& 1 \\
1 & -1 & -1 & 0 & -1 \\
-1 & 1 & 1 & -1 & 0
\end{matrix}\right]$$
此时,如果网络新增一个需要记忆的模式$V^2=[1, 0, 1, 0, 1]$,按照以上公式与步骤,可得关于该模式的权值:
$$W^2=\left[\begin{matrix}
0 & -1 & 1 &-1 & 1 \\
-1 & 0 & -1 & 1 & -1 \\
1 & -1 & 0 & -1& 1 \\
-1 & 1 & -1 & 0 & -1 \\
1 & -1 & 1 & -1 & 0
\end{matrix}\right]$$
我们只需要将新计算的权值矩阵与旧权值矩阵按各元素相加,便得到记忆两种模式的Hopfield网络参数。
$$W=\left[\begin{matrix}
0 & -2 & 0 &0 & 0 \\
-2 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & -2& 2 \\
0 & 0 & -2 & 0 & -2 \\
0 & 0 & 2 & -2 & 0
\end{matrix}\right]$$
### 3.2 Hebb规则
算法描述如下:
选择一个Hopfield网络要记忆的模式,由该模式可以知道网络各神经元收敛到该模式状态时的期望状态。如果第$i$个神经元的状态与第$j$个神经元的状态同号(同为1,或同为0)时,增加这两个神经元的强度$\omega_{ij} + \alpha$。如果异号(有一个为1,有一个为0)时,则减小这两个神经元的连接强度$\omega_{ij} - \alpha$。权值矩阵$W$初始化为0,且$0< \alpha <1$。
以上过程迭代数次,每次选择不同的记忆模式。也可以对每个记忆模式单独学习,学习完成后将权值相加即可。
> 个人认为,Hebb规则应用在Hopfield网络的学习中非常勉强。没有直接计算法来得直接。并且,Hebb规则法并没有在理论上去推导Hopfield网络的学习算法,只是一种对直接计算法的近似。个人见解,欢迎拍砖。
## 4. 如何更新Hopfield网络的状态
到此,我们能够根据要记忆的模式设计网络的结构与参数。接下来,我们需要知道怎么更新网络的状态,使网络的状态最终收敛到记忆的模式,实现回忆功能。
仍以以上例子,假定5个神经元的Hopfield网络需要存储两个模式$V^1=[0, 1, 1, 0, 1]$与$V^2=[1, 0, 1, 0 ,1]$。
网络的权值矩阵由上节可知为:
$$W=\left[\begin{matrix}
0 & -2 & 0 &0 & 0 \\
-2 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & -2& 2 \\
0 & 0 & -2 & 0 & -2 \\
0 & 0 & 2 & -2 & 0
\end{matrix}\right]$$
现在假定有一个被污染的输入$x = [1, 1, 1, 1, 1]$,我们将它输入到上面设计的Hopfield网络。我们利用这个例子来说明网络的更新过程。
首先,我们需要一个更新顺序。每次只更新一个神经元的状态,对哪一个进行更新?一般有两种方式:1)按顺序;2)随机选择。
更新顺序:我们采用固定顺序,例如按照3,1, 5,2, 4, 3, 1, 5,2,4,....的顺序不断迭代更新网络各神经元的状态。
我们会把外部输入作为网络的初始状态,此例中网络的初始状态为$\mathbf{n} = [1, 1, 1, 1, 1]$。
我们计算第一个要更新的神经元输出
$$y_3=\sum_{j\neq 3} \omega_{j3} n_j=0$$
根据以下公式更新神经元的状态:
$$n = \{\begin{matrix} 0 & y<0 \\ 1 & y >= 0 \end{matrix}$$
因此,$n_3=1$,网络的状态变为$\mathbf{n}=[1, 1, 1, 1, 1]$
每二个要更新的神经元为第1个神经元:
$$y_1=\sum_{j \neq 1} \omega_{j1} n_j=-2$$
因此,$n_2=0$,网络的状态变为$\mathbf{n}=[0, 1, 1, 1, 1]$
按以上顺序,不断更新网络的状态。
最终收敛到状态$[0, 1, 1, 0, 1]$,也即回忆起第1个模式。
**终止准则:如果网络神经元的状态不再变化,则说明网络已经收敛,此刻网络的状态就是该输入唤起的记忆。**
如果将神经元的更新顺序改为:2,4,3,5,1,2,4,3,5,...,最终收敛的到第二个模式$[1, 0, 1, 0, 1]$。这个过程,大家感兴趣可以动手算以下,或者编程序实现,对比结果。说明,**对神经元更新的顺序是影响最终的收敛结果的**。
## 5. 一个简单的例子
假定我们需要利用Hopfield网络记忆存储以下两种模式,简称“$+$”与“$\times$”。
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0bcc3f884cc94580aa54d599b333b426~tplv-k3u1fbpfcp-zoom-1.image)![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8d84df9d461e4eb1bfc88b9c3313daba~tplv-k3u1fbpfcp-zoom-1.image)
### 5.1 数据准备
以上两种模式的数据表示为$5\times 5$的矩阵,分别为:
$$+=\left[\begin{matrix}
0 & 0 & 1 & 0 & 0\\
0 & 0 & 1 & 0 & 0\\
1 & 1 & 1 & 1 & 1\\
0 & 0 & 1 & 0 & 0\\
0 & 0 & 1 & 0 & 0
\end{matrix}\right]$$
$$\times=\left[\begin{matrix}
1 & 0 & 0 & 0 & 1\\
0 & 1 & 0 & 1 & 0\\
0 & 0 & 1 & 0 & 0\\
0 & 1 & 0 & 1 & 0\\
1 & 0 & 0 & 0 & 1
\end{matrix}\right]$$
为了能够作为网络输入,进一步将以上矩阵形式向量化为:
$$+=\left[\begin{matrix}
0 & 0 & 1 & 0 & 0&
0 & 0 & 1 & 0 & 0&
1 & 1 & 1 & 1 & 1&
0 & 0 & 1 & 0 & 0&
0 & 0 & 1 & 0 & 0
\end{matrix}\right]$$
$$\times=\left[\begin{matrix}
1 & 0 & 0 & 0 & 1&
0 & 1 & 0 & 1 & 0&
0 & 0 & 1 & 0 & 0&
0 & 1 & 0 & 1 & 0&
1 & 0 & 0 & 0 & 1
\end{matrix}\right]$$
### 5.2 网络结构与参数
可知该Hopfield网络具有25个神经元,参数的个数为$25\times 25$个。可以由$25\times 25$的权值矩阵表示。经计算,权值矩阵如下图所示,其中,黄色为+2, 深蓝色为-2,其他值为0。
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/63a5b82270f54f6fa4d3041be0c19518~tplv-k3u1fbpfcp-zoom-1.image)
### 5.3 回忆
我们拿以下两个输入,分别来测试Hopfield网络的回忆效果。最终左图的输入回忆起了$+$,右图的输入回忆起了$\times$。
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0ca08a6381f24ec683b39cc05ac30100~tplv-k3u1fbpfcp-zoom-1.image)![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b0a29eeffb2d444999c420da87fd9ff0~tplv-k3u1fbpfcp-zoom-1.image)
### 5.4 程序
程序实现了Hopfield网络。并利用本节的例子作为测试。其中,程序包括两种参数获取的方式:1)直接计算;2)Hebb规则。在本例中,最终的效果是一样的。大家可以用该程序测试更复杂的模式。
```python
import numpy as np
import copy
class HopfieldNet:
def __init__(self, node_nums, Vs):
self.node_nums = node_nums
self.W = np.zeros((node_nums, node_nums))
# self.learnW(Vs) # method 2: learn weights by Hebb rule
# method 1: calculate the weights directly
for i in range(node_nums):
for j in range(node_nums):
if i == j:
self.W[i,j] = 0
else:
self.W[i,j] = sum([(2*Vs[a][i]-1)*(2*Vs[a][j]-1) for a in range(len(Vs))])
print(self.W)
def learnW(self, Vs):
for i in range(100):
for j in range(len(Vs)):
for c in range(len(Vs[j])):
for r in range(len(Vs[j])):
if c != r:
if Vs[j][c] == Vs[j][r]:
self.W[c, r] += 0.1
else:
self.W[c, r] -= 0.1
print(self.W)
def fit(self, v):
new_v = np.zeros(len(v))
# indexs = [2, 1, 0, 4, 3]
indexs = range(len(v))
while np.sum(np.abs(new_v-v)) != 0:
new_v = copy.deepcopy(v)
for i in indexs:
temp = np.dot(v, self.W[:,i])
if temp >= 0:
v[i] = 1
else: v[i] = 0
return v
Vmat1 = np.zeros((5,5))
Vmat1[2,:] = 1
Vmat1[:,2] = 1
Vmat2 = np.zeros((5,5))
for i in range(5):
Vmat2[i,i] = 1
Vmat2[i, 4-i] = 1
import matplotlib.pyplot as plt
%matplotlib inline
plt.imshow(Vmat1)
plt.show()
plt.imshow(Vmat2)
plt.show()
node_nums = 25
Vs = [Vmat1.reshape(-1), Vmat2.reshape(-1)]
# Vs = [np.array([0, 1, 1, 0, 1]), np.array([1, 0, 1, 0, 1])]
hopnet = HopfieldNet(node_nums, Vs)
testmat = np.zeros((5,5))
testmat[2,:] = 0
testmat[:,2] = 0
testmat[2,2] = 1
testmat[0,0] = 1
plt.imshow(testmat)
plt.show()
v = testmat.reshape(-1)
# v = np.array([1, 1, 1, 1, 1])
newv = hopnet.fit(v)
print(newv)
plt.imshow(newv.reshape(5,5))
plt.show()
```
## 6. 结语
本文通过对Hopfield网络的工作原理进行解绍,规避了艰深理论的推导,让大家比较轻松的熟悉网络的结构、参数以及工作原理。为之后进一步的深度制造一种良好的信心。
> 1. Hopfield网络类似一个具有多个吸引子的系统,能将在吸引子附近的状态吸引到吸引子所在的状态。因此,Hopfield网络能够用来存储模式,并利用具有噪声的外部输入回忆起它原本的模式。
> 2. Hopfield网络的参数采用直接计算法,直接计算的公式应该是由Lyapunov稳定性定理推导出来的,具体我也不是很清楚,反正好使。
> 3. 此处,Hebb规则的应用是一种趋近直接计算法的学习方法(在Hopfield网络中),不如直接计算来的直接。
---
[1] MartinT.Hagan. 神经网络设计[M]. 2002.
[2] http://web.cs.ucla.edu/~rosen/161/notes/hopfield.html