【自制C++深度学习推理框架】卷积层的设计思路

news2024/11/26 9:30:12

卷积层的设计思路

使用Im2Col来实现高性能卷积

在深度学习中实现高性能卷积有以下几个方法:

  • 并行计算:在网络或硬件层面上,利用并行计算的优势对卷积过程进行加速,例如使用GPU。

  • 转换卷积算法:卷积操作可由矩阵相乘代替,使用Im2Col来实现高性能卷积。

  • 减少内存带宽:通过修改计算顺序、优化缓存管理或手动调整内存布局等方法来减少内存访问量,从而提高卷积性能。

  • 降低精度:使用低精度数据类型(如半精度浮点数)进行计算可以提高卷积性能,因为这些数据类型在内存和计算方面都需要较少的资源。

Im2Col(图像到列)是一种将卷积层输入的多维图像数据转换为二维列状数据的算法。该算法被广泛应用于深度学习框架中,以加速卷积计算,提高图像处理的效率和准确性。下面是 Im2Col 算法的基本原理:

  1. 输入数据:一个形状为 [ N , C , H , W ] [N, C, H, W] [N,C,H,W] 的四维张量,其中 N 表示样本数,C 表示通道数,H 和 W 分别表示图像高度和宽度。

  2. 设定卷积核大小和步幅:卷积层通常包含若干个卷积核,每个卷积核大小为 K h ∗ K w K_h * K_w KhKw,步幅为 S h ∗ S w S_h * S_w ShSw

  3. 对输入图像进行填充:在输入图像的周围填充 P h P_h Ph 行和 P w P_w Pw 列的零值,使得输出特征图大小为 [ ( H − K h + 2 ∗ P h ) / S h + 1 , ( W − K w + 2 ∗ P w ) / S w + 1 ] [(H - K_h + 2*P_h)/S_h+1, (W - K_w + 2*P_w)/S_w+1] [(HKh+2Ph)/Sh+1,(WKw+2Pw)/Sw+1]

  4. 将卷积核拉成一维向量:将每个卷积核从形状为 [ K h , K w , C ] [K_h, K_w, C] [Kh,Kw,C] 的三维张量转换为形状为 [ K h ∗ K w ∗ C ] [K_h * K_w * C] [KhKwC] 的一维向量。

  5. Im2Col 转换:将输入图像的每个大小为 K h ∗ K w K_h * K_w KhKw 的图块按行将像素展开成一列,生成一个形状为 [ K h ∗ K w ∗ C , H o u t ∗ W o u t ] [K_h * K_w * C, H_{out} * W_{out}] [KhKwC,HoutWout] 的二维张量。

  6. 矩阵乘法计算:将一维卷积核向量与 Im2Col 转换得到的列向量进行矩阵乘法运算,得到一个形状为 [ N ∗ n u m f i l t e r s , H o u t ∗ W o u t ] [N * num_filters, H_{out} * W_{out}] [Nnumfilters,HoutWout] 的矩阵,其中 num_filters 表示卷积核数量。

  7. 将结果转换为输出特征图:将结果矩阵重组成形状 [ N , n u m f i l t e r s , H o u t , W o u t ] [N, num_filters, H_{out}, W_{out}] [N,numfilters,Hout,Wout] 的四维张量,即为卷积层输出的特征图。

Im2Col

总之,Im2Col 算法是通过将输入图像转换为列状数据,并利用矩阵乘法计算来提高卷积运算效率和准确性。在实际应用中,使用 Im2Col 算法可以加速卷积操作,提升深度学习模型的训练和推理速度。

详细可以查看:

  • High Performance Convolutional Neural Networks for Document Processing
  • https://blog.csdn.net/qq_32901731/article/details/128822803

ConvolutionLayer的定义

由于ConvolutionLayer是带参数的,因此可通过继承ParamLayer类,定义ConvolutionLayer类来实现卷积层。具体来说:

  • 构造函数:定义了卷积层的一些基本参数,包括输出通道数 output_channel、输入通道数 in_channel、卷积核大小 kernel_h 和 kernel_w、padding_h 和 padding_w、stride_h 和 stride_w、group数 groups 和是否使用偏置 use_bias。通过该函数初始化了类成员变量。

  • 静态函数 GetInstance:给定运行时操作符 op,该函数返回一个 conv_layer 实例的指针。在卷积层中,该函数主要解析和验证输入张量的形状和参数,以及计算输出张量的形状。

  • 前向传播函数 Forward:根据输入张量 inputs 和已经初始化的卷积层参数,执行卷积操作,并将结果写入输出张量 outputs 中。具体实现涉及到 Im2Col 转换、矩阵乘法等计算过程。

此外,该类定义了一些私有成员变量,包括是否使用偏置 use_bias_、groups 数量 groups_、padding 和 stride 的高度和宽度等参数。这些变量在构造函数中进行初始化,并在前向传播函数中使用。

ConvolutionLayer的实例化

通过LayerRegistererWrapper kConvGetInstance("nn.Conv2d", ConvolutionLayer::GetInstance);来定义

一个 LayerRegistererWrapper 类型的变量 kConvGetInstance,用来注册一个名为 “nn.Conv2d” 的卷积层的 GetInstance 函数 ConvolutionLayer::GetInstance。

这样在使用该卷积层时只需要指定名称 “nn.Conv2d”,就可以自动调用对应的 GetInstance 函数了。

卷积层的 GetInstance 函数,用于对传入的运行时操作符 op 进行解析和验证,并返回一个卷积层实例的指针。具体来说:

  • 首先检查输入参数 op 是否为空,如果为空则报错并返回对应的错误码。

  • 从 op 中获取卷积层的 dilation(膨胀率)、in_channels(输入通道数)和 out_channels(输出通道数)等参数,进行解析和验证。如果这些参数不存在或格式不正确,则报错并返回对应的错误码。

  • 检查卷积核的 dilation 值是否为 1,因为目前只支持 dilation 值为 1。

  • 对于 padding 参数,首先检查该参数是否存在,不存在则报错并返回 kParameterMissingPadding 的错误码;接着尝试从运行时参数 op 中获取 padding 值,如果获取不到或者格式不正确,则同样报错返回对应的错误码。

  • 对于 bias、stride、kernel_size 参数,也采用类似的方法进行判断和提取,如果某个参数不存在或格式有误,则报错返回相应的错误码。

  • 如果 padding_mode 参数存在,则检查该参数是否满足规定的格式(字符串类型),如果格式有误,则报错返回相应的错误码。

  • 对 groups 参数进行检查,如果该参数不存在或者其值无效,则报错并返回相应的错误码。

  • 接着根据 kernel、padding、stride 参数的值,构造一个 ConvolutionLayer 类的实例 conv_layer,并对其参数进行相应的初始化。

  • 如果使用偏置,则从运行时参数 op 中获取 bias 属性的值,并进行一些检查和处理,以确保该属性的形状和值符合要求。如果 bias 属性不存在或数据有误,则报错并返回相应的错误码。

  • 最后如果存在权重属性 weight,则从运行时参数 op 中获取该属性的值,检查其形状是否正确。如果 weight 数据有误,则报错并返回相应的错误码。否则,将 weight 值设置给卷积层实例(即 conv_layer),并返回 kParameterAttrParseSuccess 表示解析和构造过程成功完成。

ConvolutionLayer的前向传播

在前向传播中,我们不仅使用Im2Col来实现高性能卷积,还使用了 Armadillo 库来进行矩阵乘法,也使用了OpenMP library线程并行处理。具体如下:

  • 首先进行参数和数据的检查,确保输入输出数据正确且合法。

  • 接着从权重参数 weights_ 中提取卷积核的数量、大小、通道数等相关信息,并对一些参数进行检查和校验。

  • 对 groups_ 参数进行一些校验和检查,确保卷积核数量和输入通道数是组数的整数倍。

  • 接着根据输出特征图的大小(即 output_h 和 output_w 值)计算输入矩阵的列长 col_len,并对其进行校验。

  • 然后,根据Im2Col原理,对每个分组内的卷积核参数提取并预处理成矩阵形式kernel_matrix_arr。

  • 接着,根据Im2Col原理,对每个分组内的输入数据input提前并预处理成矩阵形式input_matrix。

  • 获取或创建输出特征图的 output_tensor ,如果该 output_tensor 不存在,则创建一个新的空 tensor,并更新输出数组 output_tensor。

  • 接着对 output_tensor 的形状进行检查和校验,确保其形状与预期的输出特征图大小相符合。

  • 然后针对每个分组执行以下:将 kernel_matrix_arr 与输入变量 input_matrix 进行矩阵乘法操作得到中间结果 outputs_matrix。

  • 对于每个分组,改变张量的形状,根据是否使用偏置进行指定 bias 值的计算,最终将输出结果保存在 output_tensor 中的相应通道。

  • 最后返回成功标志 InferStatus::kInferSuccess,结束前向传播计算过程。

此外,在对每个batch_size进行卷积时利用 OpenMP 循环并行处理。其中:

  • #pragma omp 表示这是 OpenMP 库中的预处理指令。

  • parallel for 表示对循环进行并行处理,即多个线程之间分配迭代次数并并行执行循环内部的逻辑。

  • num_threads(batch_size) 指定了同时运行的线程数目,这里将其设置为输入数据的 batch_size。

  • for 循环将输入数据拆分成多个子任务(每个任务处理一个 batch 中的一组数据)。在执行时,不同的线程会负责处理不同的子任务,从而实现并行计算。

这样可以加速并行处理,使得程序可以充分利用系统资源,提高计算效率。

阅读的代码

  • source
    • layer
      • details
        • convolution.hpp
        • convolution.cpp

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

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

相关文章

【生成数据】随机漫步

使用python来生成随机漫步数据,再使用matplotlib将这些数据呈现出来。 随机漫步:每次行走都是完全随机的,没有明确的方向,结果是由一系列随机决策决定的。也可以这么认为,随机漫步就是蚂蚁在晕头转向的情况下&#xff…

DNS详解

2.4 DNS:因特网的目录服务 我们首先要了解域名和IP地址的区别。IP地址是互联网上计算机唯一的逻辑地址,通过IP地址实现不同计算机之间的相互通信,每台联网计算机都需要通过IP地址来互相联系和分别。 但由于IP地址是由一串容易混淆的数字串构成…

Java String ,StringBuffer 和 StringBuilder 类

文章目录 一、Java String 类二、Java StringBuffer 和 StringBuilder 类总结 一、Java String 类 字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。 创建字符串 创建字符串最简单的方式如下: St…

SiLu激活函数解释

SiLu激活函数 在yolo v5中,我们使用了SiLu激活函数 首先,了解一下激活函数的作用: 激活函数在神经网络中起到了非常重要的作用。以下是激活函数的一些主要功能: 引入非线性:激活函数的主要目标是在模型中引入非线性…

STM32F7xx Keil5 RTX RL-TCPnet DP83822移植

使用之前RTX工程模板 RTE中RL-TCPnet配置 暂时全部默认配置,DHCP已打开 修改RTE_Device.h ETH配置 修改DP83822驱动 去掉文件只读属性,之后需要修改,添加到工程 修改DP83822 ID RTE创建tcp server例程,参考该例程,进…

2023.6.4 第五十六次周报

目录 前言 文献阅读:一种预测中国东海岸非平稳和不规则波的VMD-LSTM/GRU混合模型 背景 研究区域和数据 VMD LSTM/GRU预测模型 VMD-LSTM/GRU 方法的数值算法 序列的非平稳分析 神经网络设计 结论 代码:lstm预测污染物浓度 总结 前言 I read …

ChatGPT结合Excel公式办公 —— ChatGPT统计富豪信息

💧 C h a t G P T 统计富豪信息 \color{#FF1493}{ChatGPT统计富豪信息} ChatGPT统计富豪信息💧 🌷 仰望天空,妳我亦是行人.✨ 🦄 个人主页——微风撞见云的博客🎐 🐳 《数据结构与算法…

设计原则-里氏替换原则

凡事皆有利弊,面向对象设计语言通过提供继承、多态等机制使得项目代码更具有复用性、可扩展性等优点,但是这些机制也存在一定的使用风险,比如继承的滥用、多态实现的不确定性等问题都有可能会引起重大线上事故。 一、里氏替换原则概念 里氏…

智能计算补充(从第四章p44往后)

智能计算补充(从第四章p44往后) 本文内容大部分来自于任振兴老师的讲课PPT,主要是对老师PPT内容的总结和提炼,侵权请联系我删除。 文章目录 智能计算补充(从第四章p44往后)适应度尺度变换1、适应度尺度变换…

DicomObjects.Core 3.0.17 Crack

DicomObjects.NET 核心版简介 DicomObjects.Core Assembly DicomObjects.NET 核心版简介 DicomObjects.Core 由一组相互关联但独立的 .核心兼容的“对象”,使开发人员能够快速轻松地将DICOM功能添加到其产品中,而无需了解或编程DICOM标准的复杂性。此帮助…

Golang 协程/线程/进程 区别以及 GMP 详解

Golang 协程/线程/进程 区别详解 转载请注明来源:https://janrs.com/mffp 概念 进程 每个进程都有自己的独立内存空间,拥有自己独立的地址空间、独立的堆和栈,既不共享堆,亦不共享栈。一个程序至少有一个进程,一个进程…

数据库多表设计

说明:在项目的数据库设计时,表与表之间是有联系的,如学生管理系统中,有部门表,教师表、学生表、课程表等等 一位教师隶属于一个部门,一个部门有多位教师,因此部门表和教师表,是一对…

【c++修行之路】c++11特性--上

文章目录 前言列表初始化用法介绍原理:std::initializer_list 简化声明的方式autodecltype 右值引用移动构造万能引用和完美转发万能引用完美转发 类的新增功能可变参数模板lambda表达式深入探究lambda表达式lambda表达式带来的便利结语 前言 大家好久不见&#xf…

bmp文件格式与保存

BMP文件由三部分组成,分辨是文件头,DIM头和像素数据。具体格式如下: 基本介绍 1. 文件头 14个字节 signature: 为文件标志位,恒为0X42 FileSize:是指整个文件的大小 REservedx:保留位恒为0 …

leetcode700. 二叉搜索树中的搜索(java)

二叉搜索树中的搜索 leetcode700 二叉搜索树中的搜索题目描述 解题思路代码演示二叉树专题 leetcode700 二叉搜索树中的搜索 leetcode 700 二叉搜索树中的搜索。 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/search-i…

chatgpt赋能python:Python去掉GIL:提升Python多线程编程性能的突破口

Python去掉GIL:提升Python多线程编程性能的突破口 Python 是世界上最受欢迎的编程语言之一,其中一大原因是其简单易用、优雅简洁的语法。Python 也是一个卓越的多用途编程语言,广泛应用于 Web 开发、科学计算、人工智能等领域。但是&#xf…

javaScript蓝桥杯-----宝贵的一票

目录 一、介绍二、准备三、目标四、代码五、检测踩坑!!六、完成 一、介绍 公司经常举办各种活动,但一到投票环节就犯了难,于是公司决定安排小蓝开发一个投票系统,更好的收集大家的投票信息。为了赶在下一次活动开始前…

k8s亲和性和反亲和性

1.前言 k8s的亲和性和反亲和性都是通过标签来影响pod的调度,在此基础上亲和性又分为硬亲和性和软亲和性,required为硬亲和性即标签内容必须要符合才能调度,preferred为软亲和性即标签内容不一定要符合也能调度,除此之外还有node亲…

Unsupported major.minor version 51.0解决办法

先看看我的报错截图 [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 08:51 min [INFO] Finished at: 2023-0…

[2.0快速体验]Apache Doris 2.0 日志分析快速体验

1. 概述 应用程序、服务器、云基础设施、IoT 和移动设备、DevOps、微服务架构—最重要的业务和 IT 发展趋势帮助我们以前所未有的方式优化运维和客户体验。但这些趋势也导致由机器生成的数据出现爆炸式成长,其中包括日志和指标等,例如,用户交…