如何在STM32上部署卷积神经网络(纯C语言搭建)

2023-05-16

0、前言


本文是什么

假如你已经使用PyTorch或者TensorFlow训练了一个卷积神经网络,得到了各层参数,却希望用C语言把这个部署到STM32等单片机上,那么就可以看看这篇文章啦。

本文虽然主要介绍怎么搭建lenet-5这个网络,但卷积神经网络的卷积、池化、拉直、全连接、激活等基本操作是独立给出的,没有高耦合,完全可以用这些操作自行搭建其他网络。

本文不是什么
加入你尚没有训练得到网络的参数,甚至还不知道什么是卷积神经网络,那么本文可能对你没有太多帮助。不过,这些兄弟也可以从文中的简介中对神经网络有个初步的了解。


1、研究对象

顾名思义,可以把卷积神经网络理解为加了“卷积”操作的深度学习网络。
在这里插入图片描述


上面这张图是论文

LeCun Y, Bottou L, Bengio Y, et al. Gradient-based learning applied to document recognition[J]. Proceedings of the IEEE, 1998, 86(11): 2278-2324.

中的网络的结构图。这个网络名为lenet-5,是卷积神经网络的经典之作。虽然比起现在的深度学习网络来说过于简陋,但它几乎包含了现代卷积神经网络中的所有要素。这篇文章将拆解这个网络,一步步用C语言实现一个类似的网络。


2、卷积神经网络的组成

再复杂的对象都有组成元素,论文里的那张图就至少可以分成两部分——数据和操作。下图中我用黑色箭头标出来灰色方块就是数据,而连接灰色方块的那些线则代表某种操作。

这样,lenet-5等卷积神经网络就可以看作对输入数据的一些列处理的组合。
在这里插入图片描述
那么具体有那些处理方法呢?还是看这张图,红色箭头标注的是卷积处理,蓝色箭头标注的是池化处理,绿色箭头标注的是全连接处理。习惯上,我们把每次处理都看作一层,所以又可以说这个网络是由两个卷积层、两个池化层和三个全连接层组成的。

注意哈,原文的输出是高斯连接(Gaussian connections),本文则把它视作普通的全连接层,这个没啥影响的。


3、确定任务

我们已经知道,神经网络里面有卷积、池化、全连接等处理方法。但并不是只有这些操作的。

拉直
在这里插入图片描述


看上面这张图,红线圈中的部分有些特殊。16个矩阵形的数据经过这一层处理以后变成了长度为120的向量,这显然是和后面的两个全连接层不同的。

事实上,这一层在做全连接之前,是把输入的矩阵“拉直”成向量了的。
在这里插入图片描述
“拉直”处理如上图所示。全连接处理则是将拉直结果与一个等长的向量叉乘,得到一个数,就全连接层输出向量的一个元素。这样,每个输入都拉直、做叉乘得到一个数,组成了一个向量,就是这个特殊的全连接层的输出。

那么,后面的那两个全连接层怎么办呢?答案当然是不用再做拉直处理了呀,直接跟向量叉乘,跟有多少个向量叉乘,输出的那个向量的长度就有多长。

而那些向量的值,就是通过训练得到的参数。


激活函数
除了拉直,咱还不能忘了激活函数,对本文将要搭建的网络来说,每一层处理之后都要加上一个激活函数。激活函数有好几种可供选择,我们选用的是relu函数,它的函数图像如下,实现起来也很简单。

在这里插入图片描述


这样,我们就明确任务了,至少要编写这么几个处理函数:

  • 卷积处理
    输入可能是多个多维矩阵的形式
  • 池化处理
    与卷积层类似
  • 全连接
    第一层全连接之前先做平化处理
  • 平化处理(拉直处理)
    把矩阵变为向量
  • 激活函数
    对输入矩阵/向量中的每一个元素做映射

4、组件介绍

要用C语言实现上述的那些处理方法,需要做哪些准备呢?我们直接看看头文件吧。


4.1 矩阵操作(matoperation)
首先是输入的尺寸结构体imageSize,考虑到通用性,咱把给它设置了数量、维度、行数、列数四个参数,可以支持对四维数据的描述。

然后是两个二维矩阵相关的操作,矩阵最大值坐标matOperationMaxIt()和矩阵扩大matOperationEdgeExpand()


//矩阵尺寸
typedef struct IS{
	int numsc;//数量
	int dimsc;//维度
	int rowsc;//行数
	int colsc;//列数
}imageSize;
void matOperationMaxIt(float** mat,imageSize matSize,int* it);
float** matOperationEdgeExpand(float** mat, int r,int c, int addc, int addr);

4.2 CNN算子(cnnoperation)
这部分是卷积神经网络的基本处理方法,包括卷积处理cnnOperationConvolution()、池化处理cnnOperationPooling()、扁平化操作cnnOperationLinear()和激活函数cnnOperationActivation()


//卷积处理
void cnnOperationConvolution(float*** inputmat,imageSize inputSize,
	float*** outputmat,imageSize outputSize,float**** kernel,imageSize kernelSize,
	int paddding,int step);
//池化处理
void cnnOperationPooling(float*** inputmat, imageSize inputSize,
	float*** outputmat, imageSize outputSize,
	imageSize kernelSize, int padding,int step);
//全连接处理 一维化然后进行全连接运算
void cnnOperationLinear(float*** inputmat, imageSize inputSize,
		float*** outputmat, imageSize outputSize,float** weight,float* bias);
//扁平化
void cnnOperationFlatten(float*** input,imageSize inputsize, float*** output, 
	imageSize outputsize);
//激活函数
void cnnOperationActivation(float*** inputmat, imageSize inputSize, float bias);

4.3 网络搭建
为了方便兄弟们理解怎么用这些组件,我用前面那些组件搭了一个类似于lenet5的分类网络,暂且称之为lenet5Improved,可以使用lenet5Improved()这个函数调用。


int lenet5Improved(float*** input,imageSize inputSize);

这个网络使用PyTorch训练,它的结构如下。
Conv2d是卷积层,参数按顺序分别是卷积核的维度、卷积核的数量、卷积核的边长、padding数。比如,第一层卷积层有6个卷积核,每个卷积核都是三维的,卷积核大小是5×5


/*
	各层参数说明
	net=torch.nn.Sequential
	nn.Conv2d(3,6,kernel_size=5,padding=2),nn.ReLU(),
	nn.MaxPool2d(kernel_size=2,stride=2),
	nn.Conv2d(6,16,kernel_size=5),nn.ReLU(),
	nn.MaxPool2d(kernel_size=2,stride=2),nn.Flatten(),
	nn.Linear(576,120),nn.ReLU(),
	nn.Linear(120,84),nn.ReLU(),
	nn.Linear(84,2)
*/

下图为lenet5Improved()的实现,红色箭头标出卷积层的位置,蓝色箭头标出池化层的位置,绿色箭头标出全连接层的位置,黑色箭头标出扁平化处理的位置。每一层处理后面都跟上激活函数。

在这里插入图片描述


不要看着图片这么长就觉得很复杂,其实主要是做了动态分配的代码比较占位置,咱们可以拿第一层卷积层来看看。

在这里插入图片描述


就这几行

  • OutSize是第一层输出的大小,初始化为1个、6维、32×32的矩阵。
  • Out1用来存储第一层的输出,mallocForppptr()给它分配动态内存。
  • kernelSize是这层卷积核的大小,初始化为6个、3维、5×5的矩阵。
  • 卷积处理以后,卷积层的输出存在Out1中,用激活函数对每个数据做激活处理

其他层的处理都是类似的。


5、训练参数的使用

搭建网络是为了部署训练好的网络,那么怎么把训练得到的参数导入这个C语言搭起来的网络里呢?


前面不是为kernel等变量分配了动态内存嘛,就是用来存这些参数的。

训练得到的参数也就两种,一种是卷积层的卷积核里面的值,另一种是全连接层的那些和拉直处理后的输入做叉乘的向量的值(权重),以及偏差(bias)。把这些参数写成常量数组,就可以烧进单片机里面,运行的时候放到动态内存里面用传进处理函数就行啦。就像下面这样。在这里插入图片描述


6、源代码

为了方便大伙参考,我把源代码放到Gitee上啦,需要的点这个就行。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在STM32上部署卷积神经网络(纯C语言搭建) 的相关文章

  • System entropy source not available 答疑

    在制作生成LMDB格式的时候 会出现这种情况 xff08 在训练开始的时候也会显示这个 xff09 System entropy source not available 挖掘了很久才知道这个秘密 System entropy source
  • 用cmd命令查看连接过的wifi密码

    简单的说 xff1a 点击运行 xff0c 输入cmd xff0c 回车打开了我们熟悉的命令提示符 xff0c 输入for f 34 skip 61 9 tokens 61 1 2 delims 61 34 i in 39 netsh wl
  • 【Ubuntu】使用x11vnc进行远程桌面连接

    1 安装x11vnc sudo apt get update sudo apt get install x11vnc 2 生成密码 x11vnc storepasswd 3 开启服务 x11vnc auth guess once loop
  • 在linux下创建一个可运行shell脚本

    1 touch hello sh 2 vim hello sh 键入i 插入 bin sh echo hello world 键入 esc wq 3 chmod 700 hello sh 4 执行 hello sh
  • Linux 网络唤醒

    网络唤醒流程 1 BIOS下使能wakeup on online 2 配置ip为同一网段 S ip 61 192 168 1 11 记录对应网卡的MAC地址 假设是00 01 02 03 04 05 3 检查网卡是否启动wakeonline
  • 如何学习算法?

    今天在群里刚好看到有人在讨论算法的问题 xff0c 刚好自己曾经也有一个算法大神的梦 xff0c 来说说自己对算法的理解 算法怎么学 xff1f 什么样程度才算把算法学透 xff1f 算法学会了有什么用 xff1f 算法的学习是非常重要的
  • Flask框架搭建

    Flask框架搭建 创建一个Flask框架 1 打开pycharm专业版 xff0c 创建一个flask框架项目 xff0c 如图 xff1a 这里的虚拟环境是创建项目之前已经创建好的虚拟环境 2 点击创建按钮 xff0c 跳转到项目主界面
  • VS2017 C++error "cout": 不是"std"的成员,或者cout”: 未声明的标识符

    include pch h include iostream 原因是两个顺序写反了
  • STM32f103***烧写程序后使用STLINK V2无法连接芯片

    STM32f103 烧写程序后使用STLINK V2无法连接芯片 解决办法 xff1a 可以采用先按住RESET键点击下载后迅速松开RESET键就能下载程序了
  • VNCview的复制粘贴剪贴板共享

    autocutsel命令可以实现在CTRL 43 C和CTRL 43 V的复制粘贴 鼠标copy和paste也是可以的 autocutsel f 可以放入后台 更方便 安装 apt install autocutsel
  • 学习笔记tasksel(失败)-- 换用VNC完成

    开始学习时在云上申请了个服务器 xff0c 创建docker后 使用了一个docker pull ubuntu后准备装个图形界面 xff0c 作为代码阅读的环境 xff0c 因此使用tasksel来进行图形化界面安装 学习总结 xff1a
  • Centos7 k8s v1.5.2二进制部署安装-网络插件Flannel的安装

    一 安装部署网络插件 1 概念 kubeenetes设计了网络模型 xff0c 但是却将她得实现交给了网络插件 xff0c CNI网络插件最主要得功能就是实现POD资源能够跨宿主机进行通信 常见得CNI网络插件 xff1a Flannel
  • linux系统中重启网卡后网络不通(NetworkManager篇)

    个人博客 xff1a https 5mr xyz 一 故障现象 RHEL7 6系统 xff0c 使用nmcli绑定双网卡后 xff0c 再使用以下命令重启network服务后主机网络异常 xff0c 导致无法通过ssh远程登录系统 syst
  • Windows系统设置多用户同时远程登录

    个人博客 xff1a https 5mr xyz 一 在键盘上按Win 43 R键 也可以在开始菜单右键然后选择运行 xff0c 在运行的输入框里面输入 34 gpedit msc 34 命令 然后点击确定 二 在 计算机组策略 中依次展开
  • 在shell中把ls的输出存进一个数组变量中

    将ls的输出存到filelist数组中 xff1a c 61 0 for file in 96 ls 96 do filelist c 61 file c 43 43 done 或者 set a myfiles index 61 0 for
  • linux系统操作系统网卡漂移解决方案及问题原因

    个人博客 xff1a https 5mr xyz 一 问题描述 公司有100 150台服务器安装RHEL7 4 amp 中标麒麟7 4系统 xff0c 为方便编辑配置网卡 xff0c 使用脚本方式配置为biosname 61 0 xff0c
  • 内核报错kernel:NMI watchdog: BUG: soft lockup - CPU#1

    个人博客 xff1a https 5mr xyz 1 现象描述 系统管理员电话通知 xff0c 描述为一台服务器突然无法ssh连接 xff0c 登录服务器带外IP地址并进入远程控制台界面后 xff0c 提示Authentication er
  • Linux ls 命令提示 Input/output error

    个人博客 xff1a https 5mr xyz 一 问题描述 某一台跑批服务器硬盘无法正常读写 xff0c 提示input output error xff0c 服务器每天均需使用 xff0c 询问情况后发现服务器首先为硬盘故障 xff0
  • storcli工具的使用方法

    个人博客 xff1a https 5mr xyz 常用命令 xff1a xff08 c代表Controller xff0c e代表Enclosure xff0c s代表Slot或PD xff0c v代表ld xff09 opt MegaRA
  • xshell 连接报错 Disconnected from remote host

    个人博客 xff1a https 5mr xyz xshell连接报错 解决方法 1 登陆带外管理口远程控制台 2 查看 Var empty的属主属组和权限 xff0c empty权限需为755 3 Chmod 777 R var后导致ss

随机推荐

  • IPMI管理工具使用方法

    个人博客 xff1a https 5mr xyz 前言 最近需要对多台服务进行控制 xff0c 通过服务器的 BMC 控制台去控制太麻烦 xff0c 服务器刚好支持 IPMI 协议 xff0c 这里记录下常用的几条命令备忘 什么是 IPMI
  • k8s-cka考试题库

    个人博客 xff1a https 5mr xyz 本次测试的所有问题都必须在指定的cluster配置环境中完成 为尽量减少切换 xff0c 系统已对问题进行分组 xff0c 同一cluster内的所有问题将连续显示 开启TAB补全 做题前先
  • Segment Routing—BGP-LS

    BGP LS概况 BGP LS是学习多个IGP区域和区域拓扑的首选机制 BGP LS使用BGP xff0c 以可扩展的方式分发网络信息 重要的是 xff0c BGP LS还承载了IGP没有分发的信息 xff08 例如BGP对等体互联链路 x
  • OVN实验----L3互通

    概述 在L2互通基础上 xff0c 完成跨网段互访 物理拓扑 如上一个实验OVN实验 L2互通 逻辑拓扑 按照上个实验OVN实验 L2互通 的操作方式 xff0c 再配置一组容器blue xff0c 网段192 168 2 0 24 配置完
  • OVN实验----NAT

    概述 在L2互通 L3互通实验基础上通过NAT实现访问公网 架构图如下 xff0c 这里两台逻辑路由器LR1和GLR是通过一台逻辑交换机LSjoin互连的 xff0c GLR和物理网络设备通过LSlocal相连 物理拓扑 如上一个实验OVN
  • java环境变量配置好之后,cmd命令行javac为什么还是无效

    把cmd命令行关闭重启一下就好了 备注 xff1a jdk5 0之后 xff0c classpath不需要配置
  • Linux编程中的文件锁之flock

    1 场景概述 在多线程开发中 xff0c 互斥锁可以用于对临界资源的保护 xff0c 防止数据的不一致 xff0c 这是最为普遍的使用方法 那在多进程中如何处理文件之间的同步呢 xff1f 我们看看下面的图 xff1a 图中所示的是两个进程
  • 《现代医学成像科学丛书——CT原理与技术》——X射线管的基本作用

    Imaging System 医学影像 64 EnzoReventon 现代医学成像科学丛书 CT原理与技术 X射线管 xff08 球管 xff09 是CT中的重要部件 xff0c 它是设备的信号源 一 球管的基本作用 球管产生X射线的基本
  • curl -sSL https://get.rvm.io | bash -s stable curl: (7) Failed connect to api.github.com:443; 拒绝连接

    curl L get rvm io bash s stable curl sSL https get rvm io bash s stable curl 7 Failed connect to api github com 443 拒绝连接
  • Linux学习十一

    Linux学习十一 iptables服务把用于处理或过滤流量的策略条目称之为规则 xff0c 多条规则可以组成一个规则链 xff0c 而规则链则依据数据包处理位置的不同进行分类 xff0c 具体如下 xff1a 在进行路由选择前处理数据包
  • Docker - 解决容器内获取的时间和主机的时间不一样的问题

    问题背景 分别在容器和主机下执行 date 命令 可以看到 xff0c 时间是完全不一样的 解决方案 在运行容器时 xff0c 挂载 etc localtime 目录 docker run d v etc localtime etc loc
  • vscode中使用pip安装依赖包

    在vscode顶部菜单栏点击 终端 xff0c 软件下方出现终端输入框 第二步 xff1a 点击页面左下角查看python解释器路径 xff1a 在终端中进入到python解释器所在的路径 xff0c 例如输入 cd 39 C Users
  • ROS的2D仿真stdr安装

    ROS中仿真是很重要的一环 xff0c 一般3D仿真使用gazebo居多 xff0c 也可以使用Webots xff0c V rep xff0c stage 2D仿真有stdr xff0c turtlesim 图形显示可以用RVIZ std
  • 华为机试6 公因数集合

    题目描述 功能 输入一个正整数 xff0c 按照从小到大的顺序输出它的所有质因子 xff08 重复的也要列举 xff09 xff08 如180的质因子为2 2 3 3 5 xff09 最后一个数后面也要有空格 输入描述 输入一个long型整
  • Can't find file /root/.vnc/6be8fb894e4a:1.pid You'll have to kill the Xvnc4 process manually

    解决方法 xff1a 分别运行一下代码 xff1a rm tmp X rm tmp X11 unix X1 重新开启VNC服务 xff1a vncserver 1 geometry 1920x1080 depth 24
  • SONiC系统架构

    SONiC系统由两部分组成 xff1a 1 彼此交互的模块 2 用于交互的基础设施 xff08 集中式 xff0c 可扩展 xff09 其中用于交互的基础设施主要是一个非关系型数据库Redis引擎 xff1a 1 提供了一个无视语言的接口
  • 安卓studio jni调用第三方静态库CMakeLists配置

    通过CMakeLists调用第三方静态库需要加入以下CMake配置 xff1a add library mytaglib 这是我即将调用第三方静态库 xff0c 不需要写完整的静态库名 STATIC IMPORTED set target
  • 关于ping一下才可以连接的问题

    关于ping一下才可以连接的问题 其他地方可以ping通 xff0c telnet端口也是通的 xff0c 但是使用ssh连接 xff0c 连接不上 使用xshell工具连接一直无反应 xff0c 在xshell中ping一下对端ip就可以
  • Numpy库中的np.max与np.maximum,两者最大值求解函数有何区别?

    Numpy库中的np max与np maximum 两者最大值求解函数有何区别 在数据分析和处理中 我们经常需要求取一组数据中的最大值 在Python中 Numpy库提供了很多方便易用的数学函数 其中最大值求解函数包括np max和np m
  • 如何在STM32上部署卷积神经网络(纯C语言搭建)

    0 前言 本文是什么 假如你已经使用PyTorch或者TensorFlow训练了一个卷积神经网络 xff0c 得到了各层参数 xff0c 却希望用C语言把这个部署到STM32等单片机上 xff0c 那么就可以看看这篇文章啦 本文虽然主要介绍