神经网络|(十四)|霍普菲尔德神经网络-Hebbian训练
【1】引言
前序学习进程中,除了对基本的神经网络知识进行了学习,还掌握了SOM神经网络原理,文章链接包括且不限于:
神经网络|(十一)|神经元和神经网络-CSDN博客
神经网络|(十二)|常见激活函数-CSDN博客
神经网络|(十三)|SOM神经网络-CSDN博客
在此基础上,本篇文章学习一个新的神经网络:霍普菲尔德神经网络。
【2】霍普菲尔德神经网络原理
霍普菲尔德神经网络和SOM神经网络一样不走寻常路,SOM神经网络着力于找出和输入最近的点,霍普菲尔德神经网络更关注两两元素之间成对的程度。
到这里可以直接进入代码学习,通过代码的设计来读懂霍普菲尔德神经网络的原理。
理解霍普菲尔德神经网络需要至少在神经网络算法和神经网络模型两个层面上完成理解。需要注意的是:神经网络算法是神经网络模型的训练手段,模型是大框架,算法是执行方法。
霍普菲尔德神经网络算法具体训练时有两种方法供选择,一种是Hebbian方法,另一种是Storkey方法。
【3】代码理解
【3.1】Hebbian方法训练霍普菲尔德神经网络
【3.1.1】准备工作
首先是完成准备工作,引入必要模块:
import numpy as np #引入numpy模块
import matplotlib.pyplot as plt #引入matplotlib模块
【3.1.2】主函数
直接阅读主函数是我们链接整改程序的关键,主函数通过把算法实施过程拆解为调用不同的子函数,直观表达了程序运行框架。
# 示例:创建一些简单的模式
patterns = [np.array([1, 1, 1, -1, -1, -1]),np.array([-1, -1, -1, 1, 1, 1])
]# 初始化权重
n_neurons = len(patterns[0])
weights = initialize_weights(n_neurons)# 训练网络
weights = train(weights, patterns)# 测试回忆功能
initial_state = np.array([1, 1, 1, -1, -1, -1])
recalled_pattern = recall(weights, initial_state)
主函数直接调用了initialize_weights()、train()和recall()三个子函数,它们分别执行权重初始化、模型训练和测试回忆功能,下一步即可对这些子函数进行学习。
【3.1.3】子函数
【3.1.3.1】initialize_weights()函数
# 定义初始化函数
def initialize_weights(n_neurons):"""初始化霍普菲尔德网络的权重矩阵:param n_neurons: 神经元的数量:return: 初始的权重矩阵"""# 返回一个(n_neurons行, n_neurons列)纯0矩阵return np.zeros((n_neurons, n_neurons))
initialize_weights()函数生成的是 (n_neurons行, n_neurons列)纯0矩阵,作为权重weights的初始值。
【3.1.3.2】train()函数
# 训练模型传入的参数有weights和patterns
def train(weights, patterns):"""使用 Hebbian 学习规则训练网络:param weights: 权重矩阵:param patterns: 训练模式的列表:return: 训练后的权重矩阵"""for pattern in patterns:# 将pattern转化为一个列向量pattern = pattern.reshape(-1, 1)# weights是在自身的基础上叠加pattern自身的平方weights += np.dot(pattern, pattern.T)# 确保对角线元素为 0# 通过内置函数,让weights处于对角线上的元素都为0np.fill_diagonal(weights, 0)# 除以总模数,进行归一化操作weights /= len(patterns)return weights
train()函数调用weights和patterns两个参数,先将patterns转置为纯列向量,然后自身和自身作矩阵点乘运算,点乘运算结果是一个 (n_neurons行, n_neurons列)矩阵,所以可以和weights矩阵按位置做加法。
由于霍普菲尔德神经网络认为元素两两之间有关系,但自己和自己不能用权重来衡量。
weights矩阵的对角线就代表了元素自己和自己的连接权重,所以需要调用一个np.fill_diagonal()函数让新获得的weights矩阵对角线上的元素为0。
然后把weights做了归一化处理。
【3.1.3.3】recall()函数
def recall(weights, initial_state, max_iterations=100):"""从初始状态回忆模式:param weights: 权重矩阵:param initial_state: 初始状态:param max_iterations: 最大迭代次数:return: 回忆出的模式"""# state是对state的复制state = initial_state.copy()for _ in range(max_iterations):# 新的state通过update函数更新new_state = update(weights, state)if np.array_equal(new_state, state):breakstate = new_statereturn state
recall()函数要求调用update()函数生成新状态,用新状态来覆盖旧状态。
【3.1.3.4】update()函数
def update(weights, state):"""更新网络状态:param weights: 权重矩阵:param state: 当前网络状态:return: 更新后的网络状态"""# state转化为列向量state = state.reshape(-1, 1)# 先用weights和state矩阵相乘,然后用np.sign()函数返回1,-1和0# np.sign()函数,参数为正返回1,参数为负返回-1,参数为0返回0new_state = np.sign(np.dot(weights, state))return new_state.flatten()
代码运行获得的图像为:

图1 hebbian训练效果
此时的完整代码为:
import numpy as np #引入numpy模块
import matplotlib.pyplot as plt #引入matplotlib模块# 定义初始化函数
def initialize_weights(n_neurons):"""初始化霍普菲尔德网络的权重矩阵:param n_neurons: 神经元的数量:return: 初始的权重矩阵"""# 返回一个(n_neurons行, n_neurons列)纯0矩阵return np.zeros((n_neurons, n_neurons))# 训练模型传入的参数有weights和patterns
def train(weights, patterns):"""使用 Hebbian 学习规则训练网络:param weights: 权重矩阵:param patterns: 训练模式的列表:return: 训练后的权重矩阵"""for pattern in patterns:# 将pattern转化为一个列向量pattern = pattern.reshape(-1, 1)# weights是在自身的基础上叠加pattern自身的平方weights += np.dot(pattern, pattern.T)# 确保对角线元素为 0# 通过内置函数,让weights处于对角线上的元素都为0np.fill_diagonal(weights, 0)# 除以总模数,进行归一化操作weights /= len(patterns)return weightsdef update(weights, state):"""更新网络状态:param weights: 权重矩阵:param state: 当前网络状态:return: 更新后的网络状态"""# state转化为列向量state = state.reshape(-1, 1)# 先用weights和state矩阵相乘,然后用np.sign()函数返回1,-1和0# np.sign()函数,参数为正返回1,参数为负返回-1,参数为0返回0new_state = np.sign(np.dot(weights, state))return new_state.flatten()def recall(weights, initial_state, max_iterations=100):"""从初始状态回忆模式:param weights: 权重矩阵:param initial_state: 初始状态:param max_iterations: 最大迭代次数:return: 回忆出的模式"""# state是对state的复制state = initial_state.copy()for _ in range(max_iterations):# 新的state通过update函数更新new_state = update(weights, state)if np.array_equal(new_state, state):breakstate = new_statereturn state# 示例:创建一些简单的模式
patterns = [np.array([1, 1, 1, -1, -1, -1]),np.array([-1, -1, -1, 1, 1, 1])
]# 初始化权重
# 获得patterns第一个元素,也就是np.array([1, 1, 1, -1, -1, -1])中数字的数量
n_neurons = len(patterns[0])
weights = initialize_weights(n_neurons)# 训练网络
weights = train(weights, patterns)# 测试回忆功能
initial_state = np.array([1, 1, 1, -1, -1, -1])
recalled_pattern = recall(weights, initial_state)# 可视化结果
plt.figure(figsize=(12, 4))plt.subplot(1, 3, 1)
plt.imshow(initial_state.reshape(1, -1), cmap='gray')
plt.title('Initial State')plt.subplot(1, 3, 2)
plt.imshow(recalled_pattern.reshape(1, -1), cmap='BuGn')
plt.title('Recalled Pattern')plt.subplot(1, 3, 3)
plt.imshow(patterns[0].reshape(1, -1), cmap='Blues')
plt.title('Original Pattern')plt.show()
update()函数根据weights和state矩阵点乘的结果,调用内置函数np.sign()函数进行判断,当矩阵点乘的结果为正返回1,为负返回-1,为0返回0。
因为weights是一个(n_neurons行, n_neurons列)矩阵,state是一个(n_neurons行, 1列)矩阵,所以计算获得的new_state是一个(n_neurons行, 1列)矩阵,update()函数返回的是(1行, n_neurons列)矩阵。
【3.1.4】综合分析
经过对主函数和子函数的阅读理解,可以发现,Hebbian方法的霍普菲尔德神经网路算法遵循原则是:
如果元素组成为:X=[X1,X2,...,Xn],就可以按照这个大小生成一个nXn的权重矩阵weights;
让所有的元素两两相乘,也获得nXn的dot(X,XT)(XT是X的转置),再让dot(X,XT)和weights同一位置的元素相加,这样就获得新的权重。新的权重实际上叠加了元素相乘的积,所以权重本身含有元素的大小。
实际上到这一步,就已经完成了训练,下一步是测试功能,所以会有recall()函数来进行检验。
recall函数会要求先更新权重,这是因为训练过程中已经计算出新权重,测试数据和原始数据已经不一样,所以要依据权重数据和测试数据的关系,对状态数据进行更新,更新后的状态数据会覆盖旧有的状态数据。
recall函数在新的状态下,成功摸索出了原有状态。
【4】细节说明
对于weights矩阵的训练过程,有一个归一化的操作。
weights /= len(patterns)
【5】总结
探索了霍普菲尔德神经网络的基本知识,基于python语言,调用hebbian方法对霍普菲尔德神经网络算法进行了初步训练和测试。
相关文章:
神经网络|(十四)|霍普菲尔德神经网络-Hebbian训练
【1】引言 前序学习进程中,除了对基本的神经网络知识进行了学习,还掌握了SOM神经网络原理,文章链接包括且不限于: 神经网络|(十一)|神经元和神经网络-CSDN博客 神经网络|(十二)|常见激活函数-CSDN博客 神经网络|(十三)|SOM神经…...
【JAVA架构师成长之路】【Redis】第13集:Redis缓存击穿原理、规避、解决方案
30分钟自学教程:Redis缓存击穿原理与解决方案 目标 理解缓存击穿的定义及核心原因。掌握互斥锁、逻辑过期时间等预防技术。能够通过代码实现高并发场景下的缓存保护。学会熔断降级、热点探测等应急方案。 教程内容 0~2分钟:缓存击穿的定义与典型场景 …...
preloaded-classes裁剪
系统预加载了哪些class类?system/etc/preloaded-classes 修改源代码? frameworks\base\config\preloaded-classes 默认位置,如果改了不生效,可能有其它模块的mk文件指定了preloaded-classes覆盖了framework模块,例如…...
爬虫案例五多进程与多线程爬取斗图网
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、多进程与多线程爬取斗图网总结 前言 提示:这里可以添加本文要记录的大概内容: 爬取斗图网 提示:以下是本篇文章正文内…...
Redis的CPU高达90%时如何处理
Redis的CPU高达90%时如何处理 1. 分析和优化2. 扩展和分片3. 缓存策略调整4. 资源提升5. 负载均衡6. 进程调整7. 代码层面改进8. 其他 当Redis的CPU使用率高达90%时,说明Redis服务器可能处于过载状态,这可能会导致响应时间变长甚至服务中断。要处理这种…...
计算机视觉之dlib人脸关键点绘制及微笑测试
dlib人脸关键点绘制及微笑测试 目录 dlib人脸关键点绘制及微笑测试1 dlib人脸关键点1.1 dlib1.2 人脸关键点检测1.3 检测模型1.4 凸包1.5 笑容检测1.6 函数 2 人脸检测代码2.1 关键点绘制2.2 关键点连线2.3 微笑检测 1 dlib人脸关键点 1.1 dlib dlib 是一个强大的机器学习库&a…...
FPGA时序约束的几种方法
一,时钟约束 时钟约束是最基本的一个约束,因为FPGA工具是不知道你要跑多高的频率的,你必要要告诉工具你要跑的时钟频率。时钟约束也就是经常看到的Fmax,因为Fmax是针对“最差劲路径”,也就是说,如果该“最差劲路径”得到好成绩,那些不是最差劲的路径的成绩当然比…...
【0013】Python数据类型-列表类型详解
如果你觉得我的文章写的不错,请关注我哟,请点赞、评论,收藏此文章,谢谢! 本文内容体系结构如下: Python列表,作为编程中的基础数据结构,扮演着至关重要的角色。它不仅能够存储一系…...
10.RabbitMQ集群
十、集群与高可用 RabbitMQ 的集群分两种模式,一种是默认集群模式,一种是镜像集群模式; 在RabbitMQ集群中所有的节点(一个节点就是一个RabbitMQ的broker服务器) 被归为两类:一类是磁盘节点,一类是内存节点; 磁盘节点会把集群的所有信息(比如交换机、绑…...
Web网页开发——水果忍者
1.介绍 复刻经典小游戏——水果忍者 2.预览 3.代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&…...
信息安全访问控制、抗攻击技术、安全体系和评估(高软42)
系列文章目录 信息安全访问控制、抗攻击技术、安全体系和评估 文章目录 系列文章目录前言一、信息安全技术1.访问控制2.抗攻击技术 二、欺骗技术1.ARP欺骗2.DNS欺骗3.IP欺骗 三、抗攻击技术1.端口扫描2.强化TCP/IP堆栈 四、保证体系和评估1.保证体系2.安全风险管理 五、真题在…...
【算法】009、单双链表反转
【算法】009、单双链表反转 文章目录 一、单链表反转1.1 实现思路1.2 多语言解法 二、双链表反转2.1 实现思路2.2 多语言解法 一、单链表反转 1.1 实现思路 维护 pre 变量。 从前向后遍历 head,首先记录 next head.next,其次反转指针使 head.next pr…...
物联网设备接入系统后如何查看硬件实时数据?
要在软件中实时查看硬件设备的信息,通常需要结合前后端技术来实现。以下是设计思路和实现步骤: 1. 系统架构设计 实时查看硬件设备信息的系统通常采用以下架构: 数据采集层: 硬件设备通过传感器采集数据,发送到InfluxDB。数据存…...
【Linux系统编程】初识系统编程
目录 一、什么是系统编程1. 系统编程的定义2. 系统编程的特点3. 系统编程的应用领域4. 系统编程的核心概念5. 系统编程的工具和技术 二、操作系统四大基本功能1. 进程管理(Process Management)2. 内存管理(Memory Management)3. 文…...
解决stylelint对deep报错
报错如图 在.stylelintrc.json的rules中配置 "selector-pseudo-class-no-unknown": [true,{"ignorePseudoClasses": ["deep"]} ]...
React基础之useInperativehandlle
通过ref调用子组件内部的focus方法来实现聚焦 与forwardRef类似,但是forwardRef是通过暴露整个Ref来实现,而useInperativehandle是通过对外暴露一个方法来实现的 import { forwardRef, useImperativeHandle, useRef, useState } from "react";…...
使用joblib 多线程/多进程
文章目录 1. Joblib 并行计算的两种模式多进程(Multiprocessing,适用于 CPU 密集型任务)多线程(Multithreading,适用于 I/O 密集型任务)2. Joblib 的基本用法3. Joblib 多进程示例(适用于 CPU 密集型任务)示例:计算平方4. Joblib 多线程示例(适用于 I/O 密集型任务)…...
⭐算法OJ⭐N-皇后问题 II【回溯剪枝】(C++实现)N-Queens II
⭐算法OJ⭐N-皇后问题【回溯剪枝】(C实现)N-Queens 问题描述 The n-queens puzzle is the problem of placing n n n queens on an n n n \times n nn chessboard such that no two queens attack each other. Given an integer n, return the num…...
【数据结构初阶】---堆的实现、堆排序以及文件中的TopK问题
1.树的概念及结构 1.1树的概念 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 有一个特殊的结点&…...
ubuntu20系统下conda虚拟环境下安装文件存储位置
在 Conda 虚拟环境中执行 pip install 安装软件后,安装的文件会存储在该虚拟环境专属的 site-packages 目录中。具体路径取决于你激活的 Conda 环境路径。以下是定位步骤: 1. 确认 Conda 虚拟环境的安装路径 查看所有环境: conda info --env…...
2003-2024年上市公司政府补助数据+stata代码
政府补助数据2003-2024 范围:2003 - 2024年,全部A股上市公司 原始数据来源于国泰安,有计算代码和原始数据,可复现出计算结果 政府补贴,政府补助,政府津贴,2024数据全 计算结果:d…...
告别Redis?在CentOS 7上快速体验国产TongRDS 2.2.x(附与SpringBoot整合对比)
国产内存数据库TongRDS技术评估与SpringBoot整合实战 在技术架构选型的关键时刻,国产基础软件的成熟度与性能表现成为越来越多企业关注的焦点。作为Redis的潜在替代方案,TongRDS凭借其纯Java架构和与Redis协议的高度兼容性,正在技术社区引发热…...
OpenClaw+GLM-4.7-Flash极客玩法:浏览器自动化与RPA任务融合
OpenClawGLM-4.7-Flash极客玩法:浏览器自动化与RPA任务融合 1. 当OpenClaw遇见GLM-4.7-Flash 去年冬天的一个深夜,我正为重复性的网页数据抓取任务头疼不已。Selenium脚本频繁因页面结构变化而崩溃,每次都需要人工介入调整。直到发现OpenCl…...
OpenClaw内存优化:Qwen3-32B-Chat在16G设备运行方案
OpenClaw内存优化:Qwen3-32B-Chat在16G设备运行方案 1. 为什么需要内存优化? 去年冬天,当我第一次尝试在16GB内存的MacBook Pro上运行Qwen3-32B-Chat模型时,系统几乎立即崩溃。这让我意识到,想要在资源有限的设备上运…...
霜儿-汉服-造相Z-Turbo实战体验:输入一句话,秒获专属汉服少女AI写真
霜儿-汉服-造相Z-Turbo实战体验:输入一句话,秒获专属汉服少女AI写真 1. 惊艳效果展示:从文字到古风美图的魔法 想象一下,你只需要输入"霜儿,古风汉服少女,月白霜花刺绣汉服,江南庭院&quo…...
Python3与pysoem实战:基于SDO的EtherCAT伺服电机多模式控制
1. 环境准备与基础配置 在开始EtherCAT伺服电机控制之前,我们需要搭建一个稳定的开发环境。我推荐使用Ubuntu 20.04 LTS作为基础系统,这个版本对Python3和网络驱动的支持都非常完善。在实际项目中,我发现普通用户权限往往无法直接操作网卡设备…...
QT加载动画卡顿?试试用QMovie+多线程优化你的等待提示框性能
QT加载动画性能优化实战:用QMovie与多线程打造流畅等待体验 当用户点击一个需要长时间处理的按钮时,那个旋转的小圆圈突然卡住不动了——这是许多QT开发者都遇到过的尴尬场景。更糟的是,整个界面随之冻结,用户只能无奈地看着无响应…...
从51单片机到STM32:我的裸机架构升级踩坑实录(附代码片段)
从51单片机到STM32:我的裸机架构升级踩坑实录 第一次用STM32F103替换掉手头的STC89C52时,我对着闪烁的LED灯陷入了沉思——这个32位的"怪兽"显然不应该继续沿用51那套超级循环的编程方式。三年前那个在延时函数里死等按键响应的菜鸟程序员&…...
Java中正确比较数组最小值的两种方法
本文旨在解决Java Stream 当API使用min()方法获得数组最小值时,返回optionalint类型导致的直接比较错误。我们将深入探讨这个问题的根源,并提供两个有效的解决方案:一是比较Optionalint的getasint()方法,二是引入apache Commons N…...
智能家居控制中心:OpenClaw+Qwen3.5-9B语音指令中转
智能家居控制中心:OpenClawQwen3.5-9B语音指令中转 1. 为什么需要语音控制的智能家居中枢? 去年装修新房时,我装了十几款不同品牌的智能设备——从米家的灯泡到涂鸦的窗帘电机,再到HomeKit的温控器。每次想调整家居状态…...
