网络组成
DHNN网络由n个神经元组成,每个神经元取值为1或-1。
每个神经元既是输入,也是输出,如果采用异步更新的策略,每次只更新一个神经元,更新顺序可以任意。激活函数为符号函数,大于等于零激活为1,反之为-1,每个神经元没有自反馈,即权重矩阵对角线为零。
DHNN输入一个值后,神经元状态不断更新后最终会收敛于某个“吸引子”。“吸引子”就是网络存储的记忆,是通过网络权重存储的。网络权重的计算方法一般有下面两种:联立方程求解法和外积和法。一般后面的方法用得较多。
DHNN网络是批学习网络,一次性输入样本一次性学习。输入的样本即“吸引子”,若样本值两两正交,则网络最稳定,理论上样本数上限为n。但一般很难做到两两正交,减少样本数(p<0.14n)可以提高抗畸变性,否则会出现“伪吸引子”。
DHNN网络可以靠下面的能量函数判断收敛状态,随着网络更新,能量函数处于递减趋势。
程序实现
下面是一个简单的python实现程序,可以输入简单样本和预测目标后进行不断更新。
# -*- coding: utf-8 -*-
import numpy as np
import time
def sgn(x):
"""激活函数"""
y = 1 if x >= 0 else -1
return y
class DHNN:
def __init__(self, v0, tra):
"""初始化"""
self.n = np.size(v0) # 神经元个数
self.W = np.diag(np.zeros(self.n)) # 权矩阵 对角线元素为零的对称矩阵
self.V = v0 # 神经元状态 取值:{-1,1}
self.Ip = np.zeros(self.n) # 偏置矢量
self.T = np.zeros(self.n) # 阈值矢量
self.train(tra)
def update(self, i):
"""网络更新"""
net = np.dot(self.V, self.W[:, i]) + self.Ip[i] - self.T[i]
self.V[i] = sgn(net)
E = -1 / 2 * np.dot(np.dot(self.V.T, self.W), self.V) - np.dot(self.Ip.T, self.V) + np.dot(self.T.T, self.V)
# print('能量', E)
# print('状态', self.V)
return E, sgn(net)
def train(self, sample):
"""网络权重计算(记忆存储)"""
S = sample
for i in range(self.n):
for j in range(self.n):
delta = 1 if i == j else 0
a = []
for m in S:
a_ = m[i] * m[j]
a.append(a_)
self.W[i, j] = (1 - delta) * np.sum(a)
print('权重\n', self.W)
if __name__ == '__main__':
St = np.array([[-1, -1, 1, 1],
[-1, 1, 1, -1]])
test = DHNN(np.array([1, 1, -1, 1]), St)
while True:
time.sleep(1)
test.update(3)
上面这个程序我还做了一个gui界面用于上课演示。
当我将上面的程序用于手写数字识别时,图片采用16*16共256个神经元,当样本数量小于4个时,还有点效果,当样本数多了之后,某些“伪吸引子”和样本的吸引力实在太强导致网络效果极差。想必用于实际用途需要更多的改进算法。
参考
https://zhuanlan.zhihu.com/p/144624580
https://blog.csdn.net/qq_41185868/article/details/80789989
https://blog.csdn.net/weixin_42398658/article/details/84027012
https://space.bilibili.com/529985682/video
2 条评论
大佬,能否讲下mnist的手写分类的设计,网上的讲解有点看不太懂,
我不是专门研究深度学习的哈,做这个也只是恰好上课需要|´・ω・)ノ