卷积神经网络(CNN)处理流程(简化版)

前言

是看了这个大佬的视频后想进行一下自己的整理(流程只到了扁平化),如果有问题希望各位大佬能够给予指正。卷积神经网络(CNN)到底卷了啥?8分钟带你快速了解!_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1MsrmY4Edi/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=7c3bfbf39d037fe80c97234396acc524

输入层

由于自己也不知道设置什么矩阵,就干脆让deepseek生成0~9的矩阵,每次随机使用一个数字来进行测试。

  • 从预定义的digit_templates中随机选择一个数字(0-9)

  • 将数字的6x6二进制矩阵转换为NumPy数组
    关键变量

  • digit: 原始数字矩阵(6x6),值为0(黑)或1(白)

# 数字模板(6x6矩阵)
digit_templates = {0: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0]],1: [[0, 0, 1, 1, 0, 0],[0, 1, 1, 1, 0, 0],[0, 0, 1, 1, 0, 0],[0, 0, 1, 1, 0, 0],[0, 0, 1, 1, 0, 0],[0, 1, 1, 1, 1, 0]],2: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[0, 0, 0, 1, 1, 0],[0, 1, 1, 0, 0, 0],[1, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 1]],3: [[1, 1, 1, 1, 1, 0],[0, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0],[0, 0, 0, 0, 0, 1],[0, 0, 0, 0, 0, 1],[1, 1, 1, 1, 1, 0]],4: [[1, 0, 0, 0, 1, 0],[1, 0, 0, 0, 1, 0],[1, 0, 0, 0, 1, 0],[1, 1, 1, 1, 1, 1],[0, 0, 0, 0, 1, 0],[0, 0, 0, 0, 1, 0]],5: [[1, 1, 1, 1, 1, 1],[1, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 0],[0, 0, 0, 0, 0, 1],[0, 0, 0, 0, 0, 1],[1, 1, 1, 1, 1, 0]],6: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0]],7: [[1, 1, 1, 1, 1, 1],[0, 0, 0, 0, 1, 0],[0, 0, 0, 1, 0, 0],[0, 0, 1, 0, 0, 0],[0, 1, 0, 0, 0, 0],[1, 0, 0, 0, 0, 0]],8: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0]],9: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 1],[0, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0]]
}# 随机选择数字
random_digit = randint(0, 9)
digit = np.array(digit_templates[random_digit])

Padding

将6*6的矩阵边界填充0扩展为8x8矩阵,防止丢失边缘信息。

numpy.pad()函数详解_numpy pad-CSDN博客https://blog.csdn.net/weixin_41862755/article/details/128336141

  • 在原始矩阵周围添加一圈0(pad_width=1
  • 将6x6矩阵扩展为8x8,防止卷积时边缘信息丢失
    输出

  • padded: 填充后的矩阵(8x8)

padded = np.pad(digit, pad_width=1, mode='constant')  # 边界填充

卷积

局部加权求和(对应相乘再相加),提取输入数据的局部特征,形成特征映射。

  • conv2d函数实现滑动窗口卷积运算

  • 使用垂直核(kernel_v)检测垂直边缘特征

  • 使用水平核(kernel_h)检测水平边缘特征
    关键参数

  • kernel_v[[0,1,0], [0,1,0], [0,1,0]](强化垂直线条)

  • kernel_h[[0,0,0], [1,1,1], [0,0,0]](强化水平线条)
    输出

  • conv_v: 垂直卷积结果(6x6矩阵)

  • conv_h: 水平卷积结果(6x6矩阵)

# 定义卷积核
kernel_v = np.array([[0, 1, 0], [0, 1, 0], [0, 1, 0]])  # 垂直特征
kernel_h = np.array([[0, 0, 0], [1, 1, 1], [0, 0, 0]])  # 水平特征def conv2d(image, kernel):# 手动实现卷积运算h, w = image.shapek_h, k_w = kernel.shapeoutput = np.zeros((h - k_h + 1, w - k_w + 1))for y in range(h - k_h + 1):for x in range(w - k_w + 1):output[y, x] = np.sum(image[y:y + k_h, x:x + k_w] * kernel)return output.astype(int)conv_v = conv2d(padded, kernel_v)  # 垂直卷积
conv_h = conv2d(padded, kernel_h)  # 水平卷积

激活

这个视频中没有,然后代码中也没起作用,因为没有出现值为负数出现。激活函数可以进行非线性变换,使网络能够学习复杂模式,可以进行特征过滤,保留有用特征,抑制噪声,可以优化训练,控制梯度流动,提高模型收敛速度。

  • 对卷积结果应用ReLU(Rectified Linear Unit)激活函数

  • 保留正值,负值置为0(非线性变换)
    输出

  • relu_v: 垂直特征激活结果(6x6)

  • relu_h: 水平特征激活结果(6x6)

relu_v = np.maximum(0, conv_v)  # ReLU激活
relu_h = np.maximum(0, conv_h)

池化

池化能够进行信息压缩,用更少的参数表达关键特征,可以不变性增强,使模型对输入的小变化更鲁棒,可以计算效率,加速训练和推理过程。

  • maxpool2d函数实现2x2最大池化(步长=2)

  • 降低特征图维度,保留显著特征(保留2*2中的最大值)
    输出

  • pool_v: 垂直特征池化结果(3x3)

  • pool_h: 水平特征池化结果(3x3)

扁平化

扁平化可以结构转换,让多维特征转换成一维向量,可以信息整合,合并不同特征提取路径的结果,起到桥梁作用,连接特征提取层与分类决策层。

  • 将池化后的3x3矩阵展平为一维向量(flatten()

  • 合并垂直和水平特征向量(最终18维向量)
    输出

  • flattened: 合并后的特征向量(形状:(18,))

flattened = np.concatenate([pool_v.flatten(), pool_h.flatten()])

可视化

  • 使用Matplotlib绘制处理流程各阶段的结果

  • 关键可视化内容:

    • 原始数字矩阵(标注0/1值)

    • 卷积/激活/池化结果(热力图+数值标注)

    • 扁平化向量(条形图,红色标记激活特征)

完整代码

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patheffects as path_effects
from random import randint# 数字模板(6x6矩阵)
digit_templates = {0: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0]],1: [[0, 0, 1, 1, 0, 0],[0, 1, 1, 1, 0, 0],[0, 0, 1, 1, 0, 0],[0, 0, 1, 1, 0, 0],[0, 0, 1, 1, 0, 0],[0, 1, 1, 1, 1, 0]],2: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[0, 0, 0, 1, 1, 0],[0, 1, 1, 0, 0, 0],[1, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 1]],3: [[1, 1, 1, 1, 1, 0],[0, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0],[0, 0, 0, 0, 0, 1],[0, 0, 0, 0, 0, 1],[1, 1, 1, 1, 1, 0]],4: [[1, 0, 0, 0, 1, 0],[1, 0, 0, 0, 1, 0],[1, 0, 0, 0, 1, 0],[1, 1, 1, 1, 1, 1],[0, 0, 0, 0, 1, 0],[0, 0, 0, 0, 1, 0]],5: [[1, 1, 1, 1, 1, 1],[1, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 0],[0, 0, 0, 0, 0, 1],[0, 0, 0, 0, 0, 1],[1, 1, 1, 1, 1, 0]],6: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0]],7: [[1, 1, 1, 1, 1, 1],[0, 0, 0, 0, 1, 0],[0, 0, 0, 1, 0, 0],[0, 0, 1, 0, 0, 0],[0, 1, 0, 0, 0, 0],[1, 0, 0, 0, 0, 0]],8: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0]],9: [[0, 1, 1, 1, 1, 0],[1, 0, 0, 0, 0, 1],[1, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 1],[0, 0, 0, 0, 0, 1],[0, 1, 1, 1, 1, 0]]
}# 随机选择数字
random_digit = randint(0, 9)
digit = np.array(digit_templates[random_digit])# 定义卷积核
kernel_v = np.array([[0, 1, 0], [0, 1, 0], [0, 1, 0]])  # 垂直特征
kernel_h = np.array([[0, 0, 0], [1, 1, 1], [0, 0, 0]])  # 水平特征def process_digit(digit):# Paddingpadded = np.pad(digit, pad_width=1, mode='constant')# 卷积计算def conv2d(image, kernel):h, w = image.shapek_h, k_w = kernel.shapeoutput = np.zeros((h - k_h + 1, w - k_w + 1))for y in range(h - k_h + 1):for x in range(w - k_w + 1):output[y, x] = np.sum(image[y:y + k_h, x:x + k_w] * kernel)return output.astype(int)  # 转换为整型conv_v = conv2d(padded, kernel_v)conv_h = conv2d(padded, kernel_h)# ReLU激活relu_v = np.maximum(0, conv_v).astype(int)  # 转换为整型relu_h = np.maximum(0, conv_h).astype(int)  # 转换为整型# 最大池化def maxpool2d(image, size=2):h, w = image.shapereturn np.array([[np.max(image[i:i + size, j:j + size])for j in range(0, w, size)]for i in range(0, h, size)]).astype(int)  # 转换为整型pool_v = maxpool2d(relu_v)pool_h = maxpool2d(relu_h)# 扁平化flattened = np.concatenate([pool_v.flatten(), pool_h.flatten()]).astype(int)  # 转换为整型return {'original': digit,'padded': padded,'conv_v': conv_v,'conv_h': conv_h,'relu_v': relu_v,'relu_h': relu_h,'pool_v': pool_v,'pool_h': pool_h,'flattened': flattened}def visualize_flow(results):fig = plt.figure(figsize=(20, 12))plt.suptitle(f'CNN Processing Flow for Digit {random_digit}', fontsize=18, y=0.97)grid = plt.GridSpec(4, 6, hspace=0.4, wspace=0.3)# 创建文本描边效果text_effect = [path_effects.withStroke(linewidth=2, foreground='black')]# 原始图像 - 显示阿拉伯数字ax1 = fig.add_subplot(grid[0:2, 0:2])img1 = ax1.imshow(results['original'], cmap='binary')plt.colorbar(img1, ax=ax1, fraction=0.046, pad=0.04)ax1.set_title("Original Digit (6x6)", pad=12)ax1.text(3, 3, str(random_digit),ha='center', va='center',color='red', fontsize=48, alpha=0.5)for y in range(results['original'].shape[0]):for x in range(results['original'].shape[1]):display_val = '1' if results['original'][y, x] > 0.5 else '0'ax1.text(x, y, display_val,ha='center', va='center',color='white' if results['original'][y, x] > 0.5 else 'black',fontsize=14, weight='bold')# Padding后的图像 - 显示阿拉伯数字ax2 = fig.add_subplot(grid[0:2, 2:4])img2 = ax2.imshow(results['padded'], cmap='binary')plt.colorbar(img2, ax=ax2, fraction=0.046, pad=0.04)ax2.set_title("After Padding (8x8)", pad=12)ax2.text(4, 4, str(random_digit),ha='center', va='center',color='red', fontsize=48, alpha=0.5)for y in range(results['padded'].shape[0]):for x in range(results['padded'].shape[1]):display_val = '1' if results['padded'][y, x] > 0.5 else '0'ax2.text(x, y, display_val,ha='center', va='center',color='white' if results['padded'][y, x] > 0.5 else 'black',fontsize=12, weight='bold')# 右侧图像的统一设置right_plots = {'conv_v': ('Vertical Conv', grid[0, 4]),'conv_h': ('Horizontal Conv', grid[0, 5]),'relu_v': ('ReLU(V)', grid[1, 4]),'relu_h': ('ReLU(H)', grid[1, 5]),'pool_v': ('Pool(V)', grid[2, 4]),'pool_h': ('Pool(H)', grid[2, 5])}for key, (title, pos) in right_plots.items():ax = fig.add_subplot(pos)img = ax.imshow(results[key], cmap='viridis')plt.colorbar(img, ax=ax, fraction=0.046, pad=0.04)ax.set_title(title, pad=7)for y in range(results[key].shape[0]):for x in range(results[key].shape[1]):ax.text(x, y, f"{results[key][y, x]:d}",  # 使用整型格式ha='center', va='center',color='white',fontsize=10, weight='bold',path_effects=text_effect)# 扁平化ax9 = fig.add_subplot(grid[3, :])bars = ax9.bar(range(len(results['flattened'])), results['flattened'])for j, val in enumerate(results['flattened']):if val > 0:bars[j].set_color('red')ax9.text(j, val / 2, f"{val:d}",  # 使用整型格式ha='center', va='center',color='white',weight='bold',path_effects=text_effect)ax9.set_xticks(range(len(results['flattened'])))ax9.set_title("Flattened Vector (Red = Activated Features)", pad=12)plt.tight_layout()plt.show()# 执行流程
results = process_digit(digit)
print(f"Processing digit: {random_digit}")
print("Flattened vector:", results['flattened'])
visualize_flow(results)

Processing digit: 1
Flattened vector: [1 3 0 1 3 0 1 3 1 2 3 1 1 2 1 2 3 2] 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/90989.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/90989.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DBSyncer:开源免费的全能数据同步工具,多数据源无缝支持!

DBSyncer(英[dbsɪŋkɜː],美[dbsɪŋkɜː 简称dbs)是一款开源的数据同步中间件,提供MySQL、Oracle、SqlServer、PostgreSQL、Elasticsearch(ES)、Kafka、File、SQL等同步场景。支持上传插件自定义同步转换业务,提供…

kafka开启Kerberos使用方式

kafka SASL_PLAINTEXT serviceName 配置: /etc/security/keytabs/kafka.service.keytab 对应的用户名 $ cat /home/sunxy/kafka/jaas25.conf KafkaClient { com.sun.security.auth.module.Krb5LoginModule required useKeyTabtrue renewTickettrue serviceName“ocd…

Unity教程(二十四)技能系统 投剑技能(中)技能变种实现

Unity开发2D类银河恶魔城游戏学习笔记 Unity开发2D类银河恶魔城游戏学习笔记目录 技能系统 Unity教程(二十一)技能系统 基础部分 Unity教程(二十二)技能系统 分身技能 Unity教程(二十三)技能系统 掷剑技能…

局域网TCP通过组播放地址rtp推流和拉流实现实时喊话

应用场景,安卓端局域网不用ip通过组播放地址实现实时对讲功能发送端: ffmpeg -f alsa -i hw:1 -acodec aac -ab 64k -ac 2 -ar 16000 -frtp -sdp file stream.sdp rtp://224.0.0.1:14556接收端: ffmpeg -protocol whitelist file,udp,rtp -i stream.sdp -acodec pcm…

基于深度学习的医学图像分析:使用YOLOv5实现细胞检测

最近研学过程中发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击链接跳转到网站人工智能及编程语言学习教程。读者们可以通过里面的文章详细了解一下人工智能及其编程等教程和学习方法。下面开始对正文内容的…

32.768KHZ 3215晶振CM315D与NX3215SA应用全场景

在现代电子设备中,一粒米大小的晶振,却是掌控时间精度的“心脏”。CITIZEN的CM315D系列与NDK的NX3215SA系列晶振便是其中的佼佼者,它们以 3.2 1.5 mm 的小尺寸”(厚度不足1mm),成为智能设备中隐形的节奏大师。精准计时的奥秘这两…

嵌软面试——ARM Cortex-M寄存器组

Cortex-M内存架构包含16个通用寄存器,其中R0-R12是13个32位的通用寄存器,另外三个寄存器是特殊用途,分别是R13(栈指针),R14(链接寄存器),R15(程序计数器)。对于处理器来说…

7.DRF 过滤、排序、分页

过滤Filtering 对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。 pip install django-filter在配置文件中增加过滤器类的全局设置: """drf配置信息必须全部写在REST_FRAMEWORK配置项中""…

二、CUDA、Pytorch与依赖的工具包

CUDA Compute Unified Device Architecture(统一计算架构)。专门用于 GPU 通用计算 的平台 编程接口。CUDA可以使你的程序(比如矩阵、神经网络)由 GPU 执行,这比CPU能快几十甚至上百倍。 PyTorch 是一个深度学习框架…

SpringCloude快速入门

近期简单了解一下SpringCloude微服务,本文主要就是我学习中所记录的笔记,然后具体原理可能等以后再来深究,本文可能有些地方用词不专业还望包容一下,感兴趣可以参考官方文档来深入学习一下微服务,然后我的下一步学习就是docker和linux了。 nacos: Nacos 快速开始 | Nacos 官网…

GPT Agent与Comet AI Aent浏览器对比横评

1. 架构设计差异GPT Agent的双浏览器架构:文本浏览器:专门用于高效处理大量文本内容,适合深度信息检索和文献追踪,相当于Deep Research的延续可视化浏览器:具备界面识别与交互能力,可以点击网页按钮、识别图…

应用信息更新至1.18.0

增加DO权限 增加权限管理(需DO支持) 增加应用冻结隐藏(需DO支持) 增加权限委托(需DO支持) 增加特殊组件 ...

常用git命令集锦

git init 初始化 将当前目录初始化为 git 本地仓库,此时会在本地创建一个 .git 的文件夹 git init -q 静默执行,就是在后台执行 git init --bare –bare 参数,一般用来初始化一个空的目录,作为远程存储仓库 git init --template dir –templa…

skywalking安装

一、简介 SkyWalking是一款用于分布式系统跟踪和性能监控的开源工具。它可以帮助开发人员了解分布式系统中不同组件之间的调用关系和性能指标,从而进行故障排查和性能优化。 它支持多种语言和框架,包括Java、.NET、Node.js等。它通过在应用程序中插入代…

利用DataStream和TrafficPeak实现大数据可观察性

可观察性工作流对于深入了解应用程序的健康状况、客户流量和整体性能至关重要。然而,要实现真正的可观察性还面临一些挑战,包括海量的流量数据、数据保留、实施时间以及各项成本等。TrafficPeak是一款为Akamai云平台打造,简单易用、可快速部署…

jQuery 最新语法大全详解(2025版)

引言 jQuery 作为轻量级 JavaScript 库,核心价值在于 简化 DOM 操作、跨浏览器兼容性和高效开发。尽管现代框架崛起,jQuery 仍在遗留系统维护、快速原型开发中广泛应用。本文涵盖 jQuery 3.6 核心语法,重点解析高效用法与最佳实践。 一、jQu…

Android 15 修改截图默认音量大小

概述 在 Android 15 中,截图音效的默认音量可能过大,影响用户体验。本文将介绍如何通过修改系统源码来调整截图音效的默认音量大小。 修改位置 需要修改的文件路径: frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundProvider.kt…

Python爬虫实战:快速采集教育政策数据(附官网工具库API)

解锁教育政策研究的数据金矿,用技术提升学术效率 在教育政策研究领域,获取最新、最全面的政策文本是学术工作的基础。传统手动收集方式效率低下且容易遗漏关键政策,而Python爬虫技术为教育研究者提供了高效的数据采集解决方案。本文将系统介…

验证回文串-leetcode

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s,如果它是 回文串 ,返回 true ;否则&#xf…

嵌入式学习日志(十)

10 学习指针1 指针核心定义与本质1.1 指针与指针变量1、指针即地址,指针变量是存放地址的变量,其大小与操作系统位数相关:64 位系统中占 8 字节,32 位系统中占 4 字节。2、指针的核心功能是通过地址间接访问目标变量&#xff0…