神经网络|(十三)|SOM神经网络
【1】引言
前序已经对神经网络有了基础认识,今天先学习SOM神经网络。
前序学习文章链接包括且不限于:
神经网络|(十一)|神经元和神经网络-CSDN博客
神经网络|(十二)|常见激活函数-CSDN博客
【2】SOM神经网络
SOM神经网络是一种结构比较简单、但是理解起来稍微复杂的神经网络。
结构简单是因为它只有两层,第一层是输入层,第二层是输出层。
和之前学习文章中提及到的一样:输入层的每一个元素都会直接作用到输出层的每一个元素。
【3】代码测试
这里逐步给出代码,通过代码的学习,大家对SOM算法的理解会相对深入。
【3.1】准备工作
首先引入必要的模块:
import numpy as np #引入numpy模块
import matplotlib.pyplot as plt #引入matplotlib模块
然后定义数据集:
# 生成 100行2列的位于[0,1)区间内,符合均匀分布的随机数
data = np.random.rand(100, 2)
之后为SOM算法准备一些初始数据:
# SOM 参数设置
# 输出层网格的大小(行数和列数)
# grid_size是存储数据的元组,不是矩阵
grid_size = (10, 10)
# 输入数据的维度
# input_dim取到的是data数组的列数
input_dim = data.shape[1]
# 最大迭代次数
max_iterations = 100
# 初始学习率
initial_learning_rate = 0.5
# 初始邻域半径
# 内置函数max()在元组grid_size中遍历每个元素,然后取出最大值
initial_radius = max(grid_size) / 2
# 时间常数,用于控制学习率和邻域半径的衰减速度
# 时间常数有多种定义方式,这是其中的一种
time_constant = max_iterations / np.log(initial_radius)# 初始化 SOM 权重
# 权重矩阵的形状为 (行数, 列数, 输入维度)
# weights是一个grid_size[0]层,每一层的行列为(grid_size[1], input_dim)形式的矩阵
weights = np.random.rand(grid_size[0], grid_size[1], input_dim)
【3.2】子函数
【3.2.1】decay_function()函数
# 定义学习率和邻域半径的衰减函数
def decay_function(initial_value, iteration, time_constant):return initial_value * np.exp(-iteration / time_constant)
【3.2.2】calculate_distances()函数
# 计算输入向量与所有神经元权重之间的欧氏距离
# 使用 for 循环代替 np.linalg.norm()
def calculate_distances(input_vector, weights):# 提取weights数组的结构属性:深度、行数、列数rows, cols, _ = weights.shape# 定义一个纯0矩阵distances = np.zeros((rows, cols))for i in range(rows):for j in range(cols):# diff=第i层第j行的weights数据-input_vector# input_dim取到的是data数组的列数,所以第i层第j行的weights数据有input_dim数据# input_vector是从data的所有行里面随机提取的一行,列数=input_dim# diff=每一行的weights数据-input_vector# squared_diff=(weights数据-input_vector)的平方# sum_squared_diff=(weights数据-input_vector)的平方和# distances[i, j]是(weights数据-input_vector)的平方和再开方# 随着i和j的增加,diff会增加,distances[i, j]也会增加diff = weights[i, j] - input_vectorsquared_diff = diff ** 2sum_squared_diff = np.sum(squared_diff)distances[i, j] = np.sqrt(sum_squared_diff)return distances
【3.2.3】find_bmu()函数
# 找到最佳匹配单元(BMU)
def find_bmu(distances):# np.argmin(distances)求出distance的最小值# np.unravel_index返回distance的最小值在distance中的索引位置return np.unravel_index(np.argmin(distances), distances.shape)
【3.2.4】update_weights()函数
# 更新 BMU 及其邻域内神经元的权重
def update_weights(input_vector, bmu, weights, radius, learning_rate):# 提取weights数组的结构属性:深度、行数、列数rows, cols, _ = weights.shapefor i in range(rows):for j in range(cols):# 计算当前神经元与 BMU 之间的距离dist_to_bmu = np.sqrt((i - bmu[0]) ** 2 + (j - bmu[1]) ** 2)if dist_to_bmu <= radius:# 计算邻域函数值influence = np.exp(-(dist_to_bmu ** 2) / (2 * radius ** 2))# 更新权重weights[i, j] += learning_rate * influence * (input_vector - weights[i, j])return weights
【3.2.5】SOM训练函数
# 训练 SOM
for iteration in range(max_iterations):# 随机选择一个输入向量# input_vector是从data的所有行里面随机提取的一行input_vector = data[np.random.randint(0, data.shape[0])]# 计算当前的学习率和邻域半径current_learning_rate = decay_function(initial_learning_rate, iteration, time_constant)current_radius = decay_function(initial_radius, iteration, time_constant)# 计算输入向量与所有神经元权重之间的距离distances = calculate_distances(input_vector, weights)# 找到 BMUbmu = find_bmu(distances)# 更新权重weights = update_weights(input_vector, bmu, weights, current_radius, current_learning_rate)
【3.3】SOM可视化
# 可视化 SOM 结果
plt.figure(figsize=(10, 10))
# 绘制数据点
plt.scatter(data[:, 0], data[:, 1], c='b', label='Data Points')
# 绘制 SOM 网格
for i in range(grid_size[0]):for j in range(grid_size[1]):# 绘制神经元的位置plt.scatter(weights[i, j, 0], weights[i, j, 1], c='r', s=100)# 绘制水平连接if j < grid_size[1] - 1:plt.plot([weights[i, j, 0], weights[i, j + 1, 0]],[weights[i, j, 1], weights[i, j + 1, 1]], 'k-')# 绘制垂直连接if i < grid_size[0] - 1:plt.plot([weights[i, j, 0], weights[i + 1, j, 0]],[weights[i, j, 1], weights[i + 1, j, 1]], 'k-')plt.title('Self - Organizing Map')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.show()
此时获得的完整代码为:
import numpy as np
import matplotlib.pyplot as plt# 生成示例数据
# 这里我们生成 100行2列的位于[0,1)区间内,符合均匀分布的随机数
data = np.random.rand(100, 2)
#print(data)
# SOM 参数设置
# 输出层网格的大小(行数和列数)
# grid_size是存储数据的元组,不是矩阵
grid_size = (10, 10)
# 输入数据的维度
# input_dim取到的是data数组的列数
input_dim = data.shape[1]
# 最大迭代次数
max_iterations = 100
# 初始学习率
initial_learning_rate = 0.5
# 初始邻域半径
# 内置函数max()在元组grid_size中遍历每个元素,然后取出最大值
initial_radius = max(grid_size) / 2
# 时间常数,用于控制学习率和邻域半径的衰减速度
# 时间常数有多种定义方式,这是其中的一种
time_constant = max_iterations / np.log(initial_radius)# 初始化 SOM 权重
# 权重矩阵的形状为 (行数, 列数, 输入维度)
# weights是一个grid_size[0]层,每一层的行列为(grid_size[1], input_dim)形式的矩阵
weights = np.random.rand(grid_size[0], grid_size[1], input_dim)
print('weights =',weights)
# 定义学习率和邻域半径的衰减函数
def decay_function(initial_value, iteration, time_constant):return initial_value * np.exp(-iteration / time_constant)# 计算输入向量与所有神经元权重之间的欧氏距离
# 使用 for 循环代替 np.linalg.norm()
def calculate_distances(input_vector, weights):# 提取weights数组的结构属性:深度、行数、列数rows, cols, _ = weights.shape# 定义一个纯0矩阵distances = np.zeros((rows, cols))for i in range(rows):for j in range(cols):# diff=第i层第j行的weights数据-input_vector# input_dim取到的是data数组的列数,所以第i层第j行的weights数据有input_dim数据# input_vector是从data的所有行里面随机提取的一行,列数=input_dim# diff=每一行的weights数据-input_vector# squared_diff=(weights数据-input_vector)的平方# sum_squared_diff=(weights数据-input_vector)的平方和# distances[i, j]是(weights数据-input_vector)的平方和再开方# 随着i和j的增加,diff会增加,distances[i, j]也会增加diff = weights[i, j] - input_vectorsquared_diff = diff ** 2sum_squared_diff = np.sum(squared_diff)distances[i, j] = np.sqrt(sum_squared_diff)return distances# 找到最佳匹配单元(BMU)
def find_bmu(distances):# np.argmin(distances)求出distance的最小值# np.unravel_index返回distance的最小值在distance中的索引位置return np.unravel_index(np.argmin(distances), distances.shape)# 更新 BMU 及其邻域内神经元的权重
def update_weights(input_vector, bmu, weights, radius, learning_rate):# 提取weights数组的结构属性:深度、行数、列数rows, cols, _ = weights.shapefor i in range(rows):for j in range(cols):# 计算当前神经元与 BMU 之间的距离dist_to_bmu = np.sqrt((i - bmu[0]) ** 2 + (j - bmu[1]) ** 2)if dist_to_bmu <= radius:# 计算邻域函数值influence = np.exp(-(dist_to_bmu ** 2) / (2 * radius ** 2))# 更新权重weights[i, j] += learning_rate * influence * (input_vector - weights[i, j])return weights# 训练 SOM
for iteration in range(max_iterations):# 随机选择一个输入向量# input_vector是从data的所有行里面随机提取的一行input_vector = data[np.random.randint(0, data.shape[0])]# 计算当前的学习率和邻域半径current_learning_rate = decay_function(initial_learning_rate, iteration, time_constant)current_radius = decay_function(initial_radius, iteration, time_constant)# 计算输入向量与所有神经元权重之间的距离distances = calculate_distances(input_vector, weights)# 找到 BMUbmu = find_bmu(distances)# 更新权重weights = update_weights(input_vector, bmu, weights, current_radius, current_learning_rate)# 可视化 SOM 结果
plt.figure(figsize=(10, 10))
# 绘制数据点
plt.scatter(data[:, 0], data[:, 1], c='b', label='Data Points')
# 绘制 SOM 网格
for i in range(grid_size[0]):for j in range(grid_size[1]):# 绘制神经元的位置plt.scatter(weights[i, j, 0], weights[i, j, 1], c='r', s=100)# 绘制水平连接if j < grid_size[1] - 1:plt.plot([weights[i, j, 0], weights[i, j + 1, 0]],[weights[i, j, 1], weights[i, j + 1, 1]], 'k-')# 绘制垂直连接if i < grid_size[0] - 1:plt.plot([weights[i, j, 0], weights[i + 1, j, 0]],[weights[i, j, 1], weights[i + 1, j, 1]], 'k-')plt.title('Self - Organizing Map')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.show()
代码运行获得的图像为:

图1 SOM算法运行效果
【4】算法分析
实际上,SOM 算法本身因为涉及索引操作,所以理解起来比较复杂。
在最初的理解层面:输入层的每一个元素都会直接作用到输出层的每一个元素。
需要再叠加一层:输入层和输出层的每一个位置索引都相关。
为便于理解,直接看核心的SOM 算法执行过程:
# 训练 SOM
# 这是实质的SOM 主函数
for iteration in range(max_iterations):# 随机选择一个输入向量# input_vector是从data的所有行里面随机提取的一行# 第一维度代表矩阵的行数,data.shape[0]获得data二维数组的行数# 由于每一次挑选input_vector都是随机的,所以存在全部data行都被选中的可能input_vector = data[np.random.randint(0, data.shape[0])]# 计算当前的学习率和邻域半径current_learning_rate = decay_function(initial_learning_rate, iteration, time_constant)current_radius = decay_function(initial_radius, iteration, time_constant)# 计算输入向量与所有神经元权重之间的距离distances = calculate_distances(input_vector, weights)# 找到 BMU# find_bmu函数是取出distances矩阵数组中最小的distances所在的位置索引# bmu只是位置函数bmu = find_bmu(distances)# 更新权重weights = update_weights(input_vector, bmu, weights, current_radius, current_learning_rate)
先取了input_vector数组,它是一个一维数组,是SOM算法的输入;
然后定义了学习率和领域半径,这两个参数的作用是用于调整权重向量weights;
在调整权重向量weights之前,需要计算输入和各个weights之间的距离;
距离计算完之后,需要获得最小距离对应的位置索引;
更新权重向量时,需要以最小距离所在的位置为参考,在一定的领域半径范围内才会对权重向量更新,否则就保持原值。
总结下来,先获得一个最小的输入量和weights量的差,然后在差最小,也就是最接近输入量的位置处,往周围拓展赋值。
按照这个思路理解,再回头去看各个子函数,对算法的理解会更深入。
文章里的代码使用了常规的for循环,而非已经成型的内置函数,读懂代码对理解SOM算法的本质意义有很大帮助。
【5】总结
学习了SOM算法的基本原理,使用python代码实现了SOM算法。
相关文章:
神经网络|(十三)|SOM神经网络
【1】引言 前序已经对神经网络有了基础认识,今天先学习SOM神经网络。 前序学习文章链接包括且不限于: 神经网络|(十一)|神经元和神经网络-CSDN博客 神经网络|(十二)|常见激活函数-CSDN博客 【2】SOM神经网络 SOM神经网络是一种结构比较简单、但是理…...
IP协议、DNS协议、DHCP协议、Telent协议的记忆总结
首先记忆一下几个协议的端口号 HTTP:超文本传输协议 80 HTTPS:安全传输协议 443 DHCP:动态主机配置协议 67/68 DNS:域名解析协议 53 FTP:文件传输协议 20/21 TFTP:简单文件传输协议 69 TELENT:远…...
Pico 4 Enterprise(企业版)与Unity的交互-有线串流调试篇
入手了Pico 4 E做VR开发,谁知入了天坑...根据官方文档,尝试了串流助手、企业串流、PICO Developer Center,陷入了各种版本问题、环境问题的陷阱。而且Pico4E的OS自24年12开始就不再更新,头盔中预装的企业串流版本也较低࿰…...
DeepSeek-R1:使用KTransformers实现高效部署指南
KTransformers作为一个开源框架,专门为优化大规模语言模型的推理过程而设计。它支持GPU/CPU异构计算,并针对MoE架构的稀疏性进行了特别优化,可以有效降低硬件要求,允许用户在有限的资源下运行像DeepSeek-R1这样庞大的模型。 硬件…...
企业日常工作中常用的 Linux 操作系统命令整理
Linux 操作系统命令整理 在企业级运维、开发和日常工作中,Linux 命令是绕不开的核心技能。不论是日志排查、进程管理,还是高效运维优化,掌握这些命令都能让你事半功倍!本篇文章整理了自己在日常工作中积累最常用的 Linux 命令&am…...
任务9:交换机基础及配置
CSDN 原创主页:不羁https://blog.csdn.net/2303_76492156?typeblog 一、交换机基础 交换机的概念:交换机是一种网络设备,用于连接多台计算机或网络设备,实现数据包在局域网内的快速交换。交换机基于MAC地址来转发数据包&#x…...
Notepad++ 8.6.7 安装与配置全攻略(Windows平台)
一、软件定位与核心优势 Notepad 是开源免费的代码/文本编辑器,支持超过80种编程语言的高亮显示,相比系统自带记事本具有以下优势: 轻量高效:启动速度比同类软件快30%插件扩展:支持NppExec、JSON Viewer等200插件跨文…...
SpringMVC请求处理流程:DispatcherServlet工作原理
文章目录 引言一、DispatcherServlet概述二、DispatcherServlet初始化过程三、请求接收与处理器匹配四、请求参数绑定与处理器执行五、视图解析与渲染六、异常处理机制总结 引言 SpringMVC框架是Java Web开发中最流行的MVC框架之一,其核心组件DispatcherServlet作为…...
YOLOv8目标检测推理流程及C++代码
这部分主要是使用c++对Onnx模型进行推理,边先贴代码,过段时间再详细补充下代码说明。 代码主要分成三部分,1.main_det.cpp推理函数主入口;2.inference_det.h 头文件及inference_det.cpp具体函数实现;3.CMakeList.txt. 1.main_det 推理配置信息全部写在config.txt中,执行…...
解锁数据潜能,永洪科技以数据之力简化中粮可口可乐决策之路
企业数字化转型是指企业利用数字技术和信息通信技术来改变自身的商业模式、流程和增值服务,以提高企业的竞争力和创新能力。数字化转型已经成为企业发展的重要战略,尤其在当前信息技术高速发展的时代。数字化转型还涉及到企业与消费者之间的互动和沟通。…...
Redis3 Hash 类型命令详解
1. 什么是 Redis Hash? Redis Hash 是一种 键值对集合,类似于 Java 里的 HashMap,可以用来存储对象的数据。例如,你可以将用户信息存储在 Redis 的 Hash 结构中,每个字段代表用户的一个属性。 示例: HSE…...
双链路提升网络传输的可靠性扩展可用带宽
为了提升网络传输的可靠性或增加网络可用带宽, 通常使用双链路冗余备份或者双链路聚合的方式。 本文介绍几种双链路网络通信的案例。 5GWiFi冗余传输 双Socket绑定不同网络接口:通过Android的ConnectivityManager绑定5G蜂窝网络和WiFi的Socket连接&…...
深入浅出:UniApp 从入门到精通全指南
https://juejin.cn/post/7440119937644101684 uni-app官网 uniapp安卓离线打包流程_uniapp离线打包-CSDN博客 本文是关于 UniApp 从入门到精通的全指南,涵盖基础入门(环境搭建、创建项目、项目结构、编写运行)、核心概念与进阶知识&#x…...
MDM 如何彻底改变医疗设备的远程管理
在现代医疗行业迅速发展的格局中,医院和诊所越来越依赖诸如医疗平板和移动工作站等移动设备。这些设备在提高工作效率和提供卓越的患者护理方面发挥着关键作用。然而,随着它们的广泛使用,也带来了一系列挑战,例如在不同地点确保数…...
前端性能优化之同时插入100000个元素页面不卡顿
面试官:同时插入100000个元素怎么让页面不卡顿 优化前写法 首先我们来看下面的一段,点击按钮后,循环100000次,每次都插入一个元素,并且插入区域上方还有一个小球在滚动,在插入的过程中我们可以观察小球的…...
PHP之Cookie和Session
在你有别的编程语言的基础下,你想学习PHP,可能要了解的一些关于cookie和session的信息。 Cookie 参数信息 setcookie(name,value,expire, path, domain); name : Cookie的名称。 value : Cookie的值。 expire : Cookie的过期时间,可以是一…...
vscode 配置debug的环境
vscode配置debug的环境 配置好python解释器, ctrl shift P 就可以指定python了。 当前环境下建立 .vscode 文件夹新建 .vscode/launch.json 文件文件的配置如下 {"version": "0.2.0","configurations": [{"name": &qu…...
socket基础学习以及java搭建
在 Java 中,Socket 编程用于实现网络通信。Java 提供了丰富的网络 API,使得通过 Socket 进行通信变得简单和高效。Java 的 Socket 编程常见于客户端-服务器应用中,比如聊天程序、文件传输工具等。 1. Socket 基本概念 Socket 编程的基本概念…...
Exoplayer2源码编译FFmpeg拓展模块实现音频软解码
在前面文章最新版本Exoplayer扩展FFmpeg音频软解码保姆级教程中介绍了最新版本的Exoplayer(androidx.Media3)编译FFmpeg模块的流程,有就是media3版本的explayer最低支持的sdk版本是21也就是Android5.x,但是市面上还是有很多IOT设备是很老的android4.4(sdk19)的&…...
Docker安装嵌入框架Text Embeddings Inference (TEI)
Docker安装Text Embeddings Inference (TEI) 1 简单介绍 文本嵌入推理(TEI,Text Embeddings Inference )是HuggingFace研发的一个用于部署和服务开源文本嵌入和序列分类模型的工具包。TEI兼容OpenAI的嵌入模型的规范。 # 官网地址 https:/…...
使用easyocr、PyPDF2对图像及PDF文档进行识别
一、概述 本 Python 脚本的主要功能是对当前目录及其子目录下的图片和 PDF 文件进行光学字符识别(OCR)处理。它使用 easyocr 库处理图片中的文字,使用 PyPDF2 库提取 PDF 文件中的文本,并将处理结果保存为文本文件。同时ÿ…...
MAUI(C#)安卓开发起步
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
oracle decode
1. 基本语法 DECODE(expression, search1, result1, search2, result2, ..., default_result) expression :需要比较的表达式或列。search1, search2, ... :要匹配的值。result1, result2, ... :当 expression 等于 search 时返回的结果。def…...
826考研
初试总分第一的hh佬小红书:https://www.xiaohongshu.com/user/profile/64e106aa000000000100fe33 深研院巨佬经验贴:https://zhuanlan.zhihu.com/p/690464528 本部羊神经验贴:https://zhuanlan.zhihu.com/p/689494655 本部学硕佬经验贴&#…...
PPT小黑第26套
对应大猫28 层次级别是错的,看着是十页,导入ppt之后四十多页 选中所有 红色蓝色黑色 文本选择标题:选择 -格式相似文本(检查有没有漏选 漏选的话 按住ctrl 点下一个) 要求新建幻灯片中不包含原素材中的任何格式&…...
【Linux-网络】HTTP的清风与HTTPS的密语
🎬 个人主页:谁在夜里看海. 📖 个人专栏:《C系列》《Linux系列》《算法系列》 ⛰️ 道阻且长,行则将至 目录 📚 引言 📚 一、HTTP 📖 1.概述 📖 2.URL ǵ…...
Vue 与 Nuxt 的区别
Nuxt 实现服务端渲染SSR Nuxt.js 是基于 Vue.js 的一个框架,它为构建 Vue.js 应用提供了更高级的功能和更便捷的开发体验。 一、定位与功能 Vue.js 是一个前端 JavaScript 框架,专注于构建用户界面和单页应用(SPA)。 核心功能…...
华为OD机试-最长的密码(Java 2024 E卷 100分)
题目描述 小王正在进行游戏大闯关,有一个关卡需要输入一个密码才能通过。密码获得的条件如下: 在一个密码本中,每一页都有一个由26个小写字母组成的密码,每一页的密码不同。需要从这个密码本中寻找这样一个最长的密码,从它的末尾开始依次去掉一位得到的新密码也在密码本…...
利用golang embed特性嵌入前端资源问题解决
embed嵌入前端资源,配置前端路由的代码如下 func StartHttpService(port string, assetsFs embed.FS) error {//r : gin.Default()gin.SetMode(gin.ReleaseMode)r : gin.New()r.Use(CORSMiddleware())// 静态文件服务dist, err : fs.Sub(assetsFs, "assets/di…...
解决docker认证问题 failed to authorize: failed to fetch oauth token
报错信息[bash1]解决方案 全局代理打开“buildkit”: false ,见[图1] [bash1] >docker build -t ffpg . [] Building 71.8s (3/3) FINISHED docker:desktop-linux> [internal] load bui…...
