当前位置: 首页 > news >正文

用 C 写一个卷积神经网络

用 C 写一个卷积神经网络

深度学习领域最近发展很快,前一段时间读transformer论文《Attention Is All You Need》时,被一些神经网络和深度学习的概念搞得云里雾里,其实也根本没读懂。发现深度学习和传统的软件开发工程领域的差别挺大,光读论文可能不是一条很好了解深度学习的路径。所以我换了一个思路,从开源的项目入手,当时我研究了一段时间ggml项目代码(https://github.com/ggerganov/ggml) , 但实际的难度还是太过陡峭,主要的困难来源于数学推导和神经网络本身的特殊性。为了更全面的了解深度学习领域,最后我选择从基础的系统知识和书籍入手, 在阅读《Neural Networks and Deep Learning》这本书时,正好书中是通过设计一个手写识别程序来讲解神经网络,书中的例子是用python实现的,其中用了不少机器学习库,屏蔽了很多细节。于是萌生了自己用C写一个手写识别程序想法。

要用C不依赖第三方库写一个神经网络,需要从数学推导、网络模型和工程实现三个方面着手。项目本身没有什么价值,只是个人学习神经网络一个小玩具。
代码地址:https://github.com/yuanrongxi/simple-neural-network.git

神经网络涉及到的数学主要是线性代数和微积分求导,神经网络中的计算大部分是通过矩阵来完成的,首先需要弄明白标量、向量、张量等概念,掌握基本的矩阵运算,例如:空间转置、加减乘除、点积、reshape等,线性代数推荐看《Linear Algebra an Its Applications》,了解基本的向量空间和运算即可,如果想更直观可以看https://github.com/kf-liu/The-Art-of-Linear-Algebra-zh-CN/blob/main/The-Art-of-Linear-Algebra-zh-CN.pdf。积分求导主要是针对神经网络的反向传播,因为在神经网络推导时会用各种激活函数、softmax、卷积、pooling max、norm、flatten等数据操作,反向传播的过程的梯度下降算法需要对这些操作进行反向求导,所以需要清楚各个函数求导过程和代价函数概念,求导更详细的可以看B站上的《跟着李沐学AI》。

网络模型涉及到神经元和感知机的概念,通过编排神经元和激活函数构建网络分层,这个《Neural Networks and Deep Learning》中讲的比较清楚。网络模型可以理解成一堆weight(权重)/bais(偏置)加一堆的y = w.x+b的函数,但它分为正向传播(feedforward)和反向传播(backprop),正向传播就是推理,反向传播就是求权重和偏置参数。因为反向传播过程是一个利用梯度下降求导的过程,理解起来会有些困难,https://builtin.com/machine-learning/backpropagation-neural-network 对反向传播总结的非常好,通俗易懂。最后CNN模型选择参照了YanLeCun的LeNet(图-1),保留第一个卷积层,去掉了中间的卷积层。

LeNet

工程实现方面参照了NumPy的思路,将涉及到矩阵运算、激活函数、反向求导等做成一个独立的矩阵运算模块,这样做的好处是可以对专门的运算做优化,后面也方便加入GPU和CUDA做尝试。其次设计了一个run state机制,因为神经网络在推理和训练时,会有很多的中间数据,这些数据有些是临时的,有些是反向传播依赖的。为了避免频繁内存分配,在创建NN时将所有用到的对象统一分配,中间数据的矩阵flatten也是零拷贝。关于CPU并行计算上,采用了openmp进行简单的矩阵并行处理,加快训练速度,所以在矩阵运算代码中用了大量的数组下标寻址,没有使用更快的指针,后面CPU上可以尝试SSSE3/simd128采用多线程分任务优化。最后神经网络是难于调试的,往往逻辑流程运行正确,但训练出来的结果不达预期,和传统的系统工程差别大。在实现中采用了对所有数学代码进行单元测试,并逐一对照相对应的pytorch运行结果,确保数学上正确,这样做大大减轻了神经网络的调试难度。值得一提的是程序设计后期借助了cursor AI代码工具,效率是前期的4~5倍左右。

来看一下程序的效果,采用的是MNIST的数据集,6万张训练图片和1万张测试图片,训练和测试30轮,多层感知机网络的识别准确度在95%左右,CNN网络的准确度在98%左右。执行时间CNN是多层感知机的20倍左右。
在这里插入图片描述
整个程序的开发设计断断续续用了4个周末的时间,实现难度一般,过程有些简单的认识:

  1. 之所以Python成为深度学习界的标准开发语言,是因为它有很多强大的库和平台,像NumPy、Pytorch、Keras等,写一个神经网络可能只需几十行代码,简单高效,其他语言无可匹及。业界正在研究基于Python语言的编译技术,这可能是未来重要的方向之一。

  2. 深度学习与传统软件工程差别大,传统软件工程是建立的逻辑学层面的工程体系,只要逻辑性强从事软件开发不是难事,所以行业内人员参差不齐。AI和深度学习领域有自己独立的知识体系,而且更多是要依靠数学推导和模型设计,工程实现也更偏CPU/GPU相关的编程,逻辑在其中起的作用有限,AI这个领域不太可能出现从培训机构出来就业的人员。传统软降工程也走到一个阶段了,软件工程的需求正在从传统的工程领域快速迁移到深度学习领域。

  3. 深度学习的计算分为推理和训练,随着网络模型的发展计算将越来越重。训练的计算量会因为成本越来越高会出现更高效的芯片和分布式计算网络。而推理计算由于安全和场景需要,可能会越来越终端化,而且推理的计算量未来是训练计算量的万倍甚至更多,会催生出新的工程领域,例如ggml。

  4. AI发展很快,很多面向程序员的工具,像github copilot、cursor等,生成的代码未必可直接使用,但能够加快从概念到代码的过程,合理使用AI工具可以更快的进入陌生领域。

科技正在大力向前,它已不再朝我而来,我唯一能做的是调整自己的位置来跟上它的步伐。

相关文章:

用 C 写一个卷积神经网络

用 C 写一个卷积神经网络 深度学习领域最近发展很快,前一段时间读transformer论文《Attention Is All You Need》时,被一些神经网络和深度学习的概念搞得云里雾里,其实也根本没读懂。发现深度学习和传统的软件开发工程领域的差别挺大&#xf…...

直面双碳目标,优维科技携手奥意建筑打造绿色低碳建筑数智云平台

优维“双碳”战略合作建筑 为落实创新驱动发展战略,增强深圳工程建设领域科技创新能力,促进技术进步、科技成果转化和推广应用,根据《深圳市工程建设领域科技计划项目管理办法》《深圳市住房和建设局关于组织申报2022年深圳市工程建设领域科…...

docker 基础入门

docker 基础入门 引言 在当今快速演进的软件开发领域,Docker 已经成为一个革命性的工具,它极大地改变了我们构建、部署和管理应用程序的方式。作为一种开源容器化平台,Docker 提供了一个轻量级且一致的环境,使得软件能够在几乎任…...

HarmonyOS:NativeWindow 开发指导

场景介绍 NativeWindow 是 HarmonyOS 本地平台化窗口,表示图形队列的生产者端。开发者可以通过 NativeWindow 接口进行申请和提交 Buffer,配置 Buffer 属性信息。 针对 NativeWindow,常见的开发场景如下: ● 通过 NativeWindow…...

汉威科技传感器为农业加点“智慧”

农业是国家之根本,历来受到高度重视,在央视《传感中国》系列节目中,智慧农业独占一期,重要性不言而喻。 随着传感器、物联网、GIS、大数据、5G、人工智能、区块链等技术的快速发展,智慧农业成为种植、养殖行业的新趋势…...

springboot listener、filter登录实战

转载自&#xff1a; www.javaman.cn 博客系统访问&#xff1a; http://175.24.198.63:9090/front/index 登录功能 1、前端页面 采用的是layui-admin框架&#xff0c;文中的验证码内容&#xff0c;请参考作者之前的验证码功能 <!DOCTYPE html> <html lang"zh…...

【数据结构—栈的实现(数组栈)】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、栈 1.1栈的概念及结构 二、栈的实现 2.1头文件的实现—Stack.h 2.2源文件的实现—Stack.c 2.3源文件的测试—test.c 三、栈的实际测试数据展示 3.1正常的出…...

Linux安装Halo(个人网站)

项目简介 1.代码开源:Halo 的项目代码开源在 GitHub 上且处于积极维护状态&#xff0c;截止目前已经发布了 109 个版本。你也可以在上面提交你的问题或者参与代码贡献。2.易于部署:推荐使用 Docker 的方式部署 Halo&#xff0c;便于升级&#xff0c;同时避免了各种环境依赖的问…...

Java - Spring中Bean的循环依赖问题

什么是Bean的循环依赖 A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你&#xff0c;你也依赖我。 比如&#xff1a;丈夫类Husband&#xff0c;妻子类Wife。Husband中有Wife的引用。Wife中有Husband的引用。 Spring解决循环依赖的机理 Spring为什么可以解决set s…...

使用 Python 实现简单的爬虫框架

爬虫是一种自动获取网页内容的程序&#xff0c;它可以帮助我们从网络上快速收集大量信息。在本文中&#xff0c;我们将学习如何使用 Python 编写一个简单的爬虫框架。 一、请求网页 首先&#xff0c;我们需要请求网页内容。我们可以使用 Python 的 requests 库来发送 HTTP 请…...

Activiti七大接口,28张表详解

Activiti七大接口&#xff0c;28张表详解 7大接口 RepositoryService&#xff1a;提供管理流程部署和流程定义API。 RuntimeService&#xff1a;提供运行时流程实例进行管理与控制API。 TaskService&#xff1a;提供流程任务管理API。 IdentityService&#xff1a;提供对流程…...

解决msvcr120.dll文件丢失问题

项目场景&#xff1a; 在VMware虚拟机中安装win7家庭版系统&#xff0c;安装MySQL数据库&#xff0c;部署项目文件。 问题描述 安装MySQL数据库过程中提示“msvcr120.dll文件丢失”。 原因分析&#xff1a; 提示丢失msvcr120.dll文件&#xff0c;我们首先要到C:\Windows\Sys…...

AI日报:人工智能与新材料的发现

文章目录 总览人工智能正在革命性地发现新的或更强的材料&#xff0c;这将改变制造业。更坚韧的合金问题研究解决方案 新材料人工智能存在的挑战方法探索 日本的研究人员正在使用人工智能制造更强的金属合金或发现新材料&#xff0c;并彻底改变制造过程 总览 日本的研究人员开…...

鱼fish数据集VOC+yolo-1400张(labelImg标注)

鱼类&#xff0c;是最古老的脊椎动物。易蓄积重金属。 部分不同染色体数目的杂交的后代依然有生育能力。它们几乎栖居于地球上所有的水生环境&#xff0c;从淡水的湖泊、河流到咸水的大海和大洋。 今天要介绍鱼的数据集。 数据集名称&#xff1a;鱼 fish 数据集格式&#xf…...

爬虫解析-BeautifulSoup-bs4(七)

目录 1.bs4的安装 2.bs4的语法 &#xff08;1&#xff09;查找节点 &#xff08;2&#xff09;查找结点信息 3.bs4的操作 &#xff08;1&#xff09;对本地文件进行操作 &#xff08;2&#xff09;对服务器响应文件进行操作 4.实战 beautifulsoup&#xff1a;和lxml一样…...

分类预测 | Matlab实现OOA-SVM鱼鹰算法优化支持向量机的多变量输入数据分类预测

分类预测 | Matlab实现OOA-SVM鱼鹰算法优化支持向量机的多变量输入数据分类预测 目录 分类预测 | Matlab实现OOA-SVM鱼鹰算法优化支持向量机的多变量输入数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现OOA-SVM鱼鹰算法优化支持向量机的多变量输…...

2.vue学习笔记(目录结构+模板语法+属性绑定)

文章目录 1.目录结构2.模板语法2.1.文本插值2.2.使用JavaScript表达式2.3.原始HTML 3.属性绑定3.1.简写3.2.布尔型Attribute3.3.动态绑定多个值 1.目录结构 1.vscode ——VSCode工具的配置文件夹 2.node_modules ——Vue项目的运行依赖文件夹 3.public ——资源文件夹&am…...

Python基本语法及高级特性总结

1. Python基本语法 1.1 变量和数据类型 在Python中&#xff0c;变量不需要预先声明&#xff0c;可以直接赋值。Python是一种动态类型语言&#xff0c;变量的类型会根据赋值的对象自动确定。例如&#xff1a; a 10 # a是整数类型变量 b 3.14 # b是浮点数类型变量 c …...

03-详解网关的过滤器工厂和常见的网关过滤器路由过滤器,默认过滤器,全局过滤器的执行顺序

过滤器工厂 过滤器种类 GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务响应的结果做加工处理 Spring提供了31中不同的路由过滤器工厂 AddResponseHeader表示给请求添加响应头 default-filters: # 默认过滤器 - AddResponseHeaderX-Response-Default-R…...

基于SSM的小儿肺炎知识管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...