Hopfield网络的基本

频道:行业资讯 日期: 浏览:806

霍普菲尔德于1982年发明了Hopfield网络,从那时开始,人们就将多种不同的神经网络模型组合在一起,互相比较,得到了较好的性能与鲁棒性。据我所知,由于Hopfield网络是Boltzmann机器和深度信念网络(DBN)的基础,因此在介绍Boltzmann机器和Deep Belief 网络的教材中,都会介绍Hopfield网络。

与当前热门的深度网络相比,Hopfield网络从不同的视角观察了人类的学习系统,值得我们一探究竟。让我们看看Hopfield网络得基本运作机理。

Hopfield网络基础及其运作方式

Hopfield网络的核心是,输入残缺的数据后,可以重建完整数据的一个模型。

我们可以将网络描述为使用链接连接节点(或称单元、神经元)的网络。每个节点在任何时间点为-1或1中的某个状态,我们可以使用向量V表示给定时间点,各个节点的状态。

Hopfield网络是个全连接网络(即是个全连接的无向图),如图1所示,即每个节点都与其他节点连接,我们使用链接表示这种连接,因此这种链接是对称的,换句话说,节点i和节点j之间的链接是一样的,没有方向的区别,我们使用权重来表示各个节点之间连接的强度,因此,我们使用矩阵W来表示节点之间连接的强度(权重),我们可以很容易的知道这是对称矩阵。

Hopfield网络的基本

图1:具有4个节点的Hopfield网络

我们可以使用以下V和W来表示这个网络。

Hopfield网络的基本

我们如何才能得到权重矩阵W呢?首先,我们可以注意到节点不链接到自身,因此我们可以将权重矩阵的对角置为0。正如我们前面所知道,这是一个对称矩阵,即Wab=Wba, 我们可以将权重矩阵与节点的状态结合起来,即Wab=Va*Vb,这样我们就可以得到一个权重矩阵W, 如下式所示。这其实就是等一下我们要讨论的Hebbian学习规则。

Hopfield网络的基本

现在,构建了权重矩阵之后,我们需要定义规则,确定每个节点的状态。由于节点的状态为(-1,1),因此我们制定了以下规则:

Hopfield网络的基本

现在,让我们来看看Hopfield网络实际上如何工作。比如说,我们有残缺的V’=[1, -1, -1, -1],也就是最后一位反转了。我们可以使用V’初始化网络状态。

Figure 2: 残缺输入的Hopfield网络

我们可以使用先前制定的规则,更新网络状态,对于Va,我们有:

Va = f(wab · Vb + wac · Vc + wad · Vd) = +1

注意:尽管Vb和Vc都是-1,但是Wab*Vb 和Wac*Vc 对x的贡献为正值,反转的节点贡献为负值,这样所得到的Va为+1。换句话说,使用向前所构建的W,如果节点的状态与原本的状态相反,我们将迫使其转变到相反的状态,如果节点的状态与原本的状态一致,则停留在原来的状态。不同的状态互相排斥,相同的状态互相吸引。这是Hebbian学习规则的一种表述。

类似得:

Vb = f(wba ·Va + wbc · Vc + wbd · Vd) = -1

Vc = f(wca · Va + wcb · Vb + wcd · Vd) = -1

现在,对于反转的位,我们可以得到:

Vd = f(wda · Va + wdc · Vc + wdb · Vb) = +1

Va=+1吸引节点d,因此Wda*Va>0, 而Vc=Vd=-1,排斥节点d,因此总体上贡献了正值wdc · Vc + wdb · Vd >0。

原来相同的节点趋向于相同的状态,原来相反状态的节点排斥对方到相反的状态。这样我们修复了原始的V。

但是,是什么原理使得Hopfield网络可以运行呢?

到目前为止,我们发现,一旦网络完全确定了,也就是W和状态向量V确定了,这样我们恢复残缺的V,我们根据规则,更新网络状态即可。

换句话说,在使用V’初始化网络状态后,我们可以让网络使用以上规则进行演化,这样网络就可以收敛到先前的状态。不仅如此,当网络到达先前状态后,无论网络迭代多少次,网络的状态依然保持不变。

让我们来看看为什么吧?

我们可以定义一个函数,这个函数使用状态V和矩阵W作为自变量。我们将这个方程称为与网络状态相关的能量方程,将其表示为:

Hopfield网络的基本

见证奇迹的时刻到来了。

结论1

如果节点Vi的状态从+1变为-1,我们将会得到:

Hopfield网络的基本

现在,如果将Vi的状态从-1变为原来的+1,那么dVi=2, 这意味着xi为正数,也就是Delta能量为负,这样能量就是单调递减,直至到达最低点。

结论2

但是,是否存在最低点,或者能量将一直减小直到负无穷?

换句话说,我们要弄清楚,Delta能量是否可用为0。为了使Delta E =0,我们需要使dVi=0,也就是要Vi(k-1)’ = Vi(k)’,也就是前一状态的的Vi和后一状态的Vi相同。

让我们假设,Vi(k-1)’ = +1,我们要Vi(k)’ = +1,或者说 xi(k) > 0。

Hopfield网络的基本

由于Vj(k-1)’ = Vj ,因此xi(k) 一直为正。

总之,我们证明了当状态恢复为原值时,能量方程不会再改变了。换句话说,dVi=0,节点不会更新到不同的值---系统到达了稳定的配置状态。

以下是Hopfield Network的源代码。

import numpy as np from matplotlib import pyplot as plt from random import randint, shuffle class InvalidWeightsException(Exception): pass class InvalidNetworkInputException(Exception): pass class HopfieldNetwork(object): def __init__(self, num_inputs): self._num_inputs = num_inputs self._weights = np.random.uniform(-1.0, 1.0, (num_inputs, num_inputs)) def set_weights(self, weights): """Update the weights array""" if weights.shape != (self._num_inputs, self._num_inputs): raise InvalidWeightsException() self._weights = weights def get_weights(self): """Return the weights array""" return self._weights def calculate_neuron_output(self, neuron, input_pattern): """Calculate the output of the given neuron""" num_neurons = len(input_pattern) s = 0.0 for j in range(num_neurons): s += self._weights[neuron][j] * input_pattern[j] return 1.0 if s > 0.0 else -1.0 def run_once(self, update_list, input_pattern): """Iterate over every neuron and update its output""" result = input_pattern.copy() changed = False for neuron in update_list: neuron_output = self.calculate_neuron_output(neuron, result) if neuron_output != result[neuron]: result[neuron] = neuron_output changed = True return changed, result def run(self, input_pattern, max_iterations=10): """Run the network using the input data until the output state doesnt change or a maximum number of iteration has been reached.""" iteration_count = 0 result = input_pattern.copy() update_list=[] for i in range(self._num_inputs): update_list.append(i) while True: #update_list = range(self._num_inputs) shuffle(update_list) changed, result = self.run_once(update_list, result) if not changed or iteration_count == max_iterations: return result

额外的函数

def calculate_weight(i, j, patterns): """Calculate the weight between the given neurons""" num_patterns = len(patterns) s = 0.0 for mu in range(num_patterns): s += patterns[mu][i] * patterns[mu][j] w = (1.0 / float(num_patterns)) * s return w def calculate_neuron_weights(neuron_index, input_patterns): """Calculate the weights for the givven neuron""" num_patterns = len(input_patterns) num_neurons = len(input_patterns[0]) weights = np.zeros(num_neurons) for j in range(num_neurons): if neuron_index == j: continue weights[j] = calculate_weight(neuron_index, j, input_patterns) return weights def hebbian_training(network, input_patterns): """Train a network using the Hebbian learning rule""" n = len(input_patterns) num_neurons = len(input_patterns[0]) weights = np.zeros((num_neurons, num_neurons)) for i in range(num_neurons): weights[i] = calculate_neuron_weights(i, input_patterns) network.set_weights(weights)

0 留言

评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。
验证码