2.Conv2d实现

news2024/7/7 17:13:22

[C++ 基于Eigen库实现CRN前向推理]

第二部分:Conv2d实现

  • 前言:(Eigen库使用记录)
  • 第一部分:WavFile.class (实现读取wav/pcm,实现STFT)
  • 第二部分:Conv2d实现
  • 第三部分:TransposedConv2d实现 (mimo,padding,stride,dilation,kernel,outpadding)
  • 第四部分:NonLinearity (Sigmoid,Tanh,ReLU,ELU,Softplus)
  • 第五部分:LSTM
  • GITHUB仓库

1. Conv2d介绍

1.1 参数介绍

这是pytorch官方源码

def __init__(
        self,
        in_channels: int,
        out_channels: int,
        kernel_size: _size_2_t,
        stride: _size_2_t = 1,
        padding: _size_2_t = 0,
        dilation: _size_2_t = 1,
        groups: int = 1,
        bias: bool = True,
        padding_mode: str = 'zeros'  # TODO: refine this type
    ):
  • in_channels:网络输入的通道数,简单理解为每个输入样本包含多个个FeatureMap。

  • out_channels:网络输出的通道数。即卷积核的个数

  • kernel_size:卷积核的大小,如果该参数是一个整数q,那么卷积核的大小是qXq。
    至此,一个简单的卷积如图
    在这里插入图片描述

  • stride:步长。是卷积过程中移动的步长。默认情况下是1。一般卷积核在输入图像上的移动是自左至右,自上至下。如果参数是一个整数那么就默认在水平和垂直方向都是该整数。如果参数是stride=(2, 1),2代表着高(h)进行步长为2,1代表着宽(w)进行步长为1。
    加入步长后,当步长为2时,卷积如图:
    在这里插入图片描述

  • padding:填充,默认是0值填充。改参数指定的是在边缘填充多少行或列的0值
    如padding为1时,卷积如图
    在这里插入图片描述

  • dilation:扩张。一般情况下,卷积核与输入图像对应的位置之间的计算是相同尺寸的,也就是说卷积核的大小是3X3,那么它在输入图像上每次作用的区域是3X3,这种情况下dilation=0。当dilation=1时,表示的是下图这种情况。
    在这里插入图片描述

1.2 python实现

2. 基于Eigen的C++实现

2.1 Layer_Conv2d.h
//
// Created by Koer on 2022/10/31.
//

#ifndef CRN_LAYER_CONV2D_H
#define CRN_LAYER_CONV2D_H


#include "vector"
#include "mat.h"
#include "Eigen"
#include "tuple"

#include "Eigen/CXX11/Tensor"

class Layer_Conv2d {
public:
    Layer_Conv2d();

    Layer_Conv2d(int64_t in_ch, int64_t out_ch, std::pair<int64_t, int64_t> kernel = std::make_pair(1, 1),
                 std::pair<int64_t, int64_t> stride = std::make_pair(1, 1),
                 std::pair<int64_t, int64_t> dilation = std::make_pair(1, 1),
                 std::pair<int64_t, int64_t> padding = std::make_pair(0, 0));

    void LoadState(MATFile *pmFile, const std::string &state_preffix);

    void LoadTestState();

    Eigen::Tensor<float_t, 4> forward(Eigen::Tensor<float_t, 4> &input);

private:
    int64_t in_channels;
    int64_t out_channels;
    std::pair<int64_t, int64_t> kernel_size;
    std::pair<int64_t, int64_t> stride;
    std::pair<int64_t, int64_t> dilation;
    std::pair<int64_t, int64_t> padding;
    Eigen::Tensor<float_t, 4> weights;
    Eigen::Tensor<float_t, 2> bias;

};


#endif //CRN_LAYER_CONV2D_H

2.2 Layer_Conv2d.cpp
//
// Created by Koer on 2022/10/31.
//

#include "iostream"
#include "../include/Layer_Conv2d.h"


Layer_Conv2d::Layer_Conv2d() {
    this->in_channels = 1;
    this->out_channels = 1;
    this->kernel_size = std::make_pair(1, 1);
    this->stride = std::make_pair(1, 1);
    this->padding = std::make_pair(0, 0);
}

Layer_Conv2d::Layer_Conv2d(int64_t in_ch, int64_t out_ch,
                           std::pair<int64_t, int64_t> kernel,
                           std::pair<int64_t, int64_t> stride,
                           std::pair<int64_t, int64_t> dilation,
                           std::pair<int64_t, int64_t> padding) {
    /* code */
    this->in_channels = in_ch;
    this->out_channels = out_ch;
    this->kernel_size = kernel;
    this->stride = stride;
    this->dilation = dilation;
    this->padding = padding;
}

void Layer_Conv2d::LoadState(MATFile *pmFile, const std::string &state_preffix) {
    std::string weight_name = state_preffix + "_weight";
    std::string bias_name = state_preffix + "_bias";

    // Read weight
    mxArray *pa = matGetVariable(pmFile, weight_name.c_str());
    auto *values = (float_t *) mxGetData(pa);
    // First Dimension  eg.(16,1,2,3)  ===> M=16
    long long dim1 = mxGetM(pa);
    // Rest Total Dimension eg.(16,1,2,3) ===>N = 1 * 2 * 3 = 6
    long long dim2 = mxGetN(pa);
    dim2 = dim2 / this->kernel_size.first / this->kernel_size.second;
    this->weights.resize(dim1, dim2, this->kernel_size.first, this->kernel_size.second);
    int idx = 0;
    for (int i = 0; i < this->kernel_size.second; i++) {
        for (int j = 0; j < this->kernel_size.first; j++) {
            for (int k = 0; k < dim2; k++) {
                for (int l = 0; l < dim1; l++) {
                    this->weights(l, k, j, i) = values[idx++];
                }
            }
        }
    }
    // std::cout << this->weights << std::endl;

    // Read bias
    pa = matGetVariable(pmFile, bias_name.c_str());
    values = (float_t *) mxGetData(pa);
    dim1 = mxGetM(pa);
    dim2 = mxGetN(pa);
    this->bias.resize(dim1, dim2);
    idx = 0;
    for (int i = 0; i < dim2; i++) {
        for (int j = 0; j < dim1; j++) {
            this->bias(j, i) = values[idx++];
        }
    }
    // std::cout << this->bias << std::endl;
    // std::cout << " Finish Loading State of " + state_preffix << std::endl;
}

void Layer_Conv2d::LoadTestState() {
    Eigen::Tensor<float_t, 4> w(this->out_channels, this->in_channels, this->kernel_size.first,
                                this->kernel_size.second);
    w.setConstant(1.0);
    this->weights = w;
    Eigen::Tensor<float_t, 2> b(1, this->out_channels);
    b.setConstant(0.0);
    this->bias = b;
}

Eigen::Tensor<float_t, 4> Layer_Conv2d::forward(Eigen::Tensor<float_t, 4> &input) {
    const Eigen::Tensor<size_t, 4>::Dimensions &dim_inp = input.dimensions();

    /* Sequence channel × T × F */
    size_t pad_size_time = this->padding.first;
    size_t pad_size_freq = this->padding.second;
    int64_t batch = dim_inp[0], C_in = dim_inp[1], H_in = dim_inp[2], W_in = dim_inp[3];
    int64_t H_pad = H_in + pad_size_time * 2;
    int64_t W_pad = W_in + pad_size_freq * 2;

    /* padding tensor */
    Eigen::Tensor<float_t, 4> padded_input = Eigen::Tensor<float_t, 4>(batch, C_in, H_pad, W_pad);
    padded_input.setZero();
    padded_input.slice(Eigen::array<size_t, 4>{0, 0, pad_size_time, pad_size_freq}, dim_inp) = input;

    /* output shape */
    int64_t H_out = (H_pad - this->dilation.first * (this->kernel_size.first - 1) - 1) / this->stride.first + 1;
    int64_t W_out = (W_pad - this->dilation.second * (this->kernel_size.second - 1) - 1) / this->stride.second + 1;
    Eigen::Tensor<float_t, 4> output = Eigen::Tensor<float_t, 4>(batch, this->out_channels, H_out, W_out);
    output.setZero();

    /* params
     * region: tmp storage of map to be convolved
     * kernel: tmp storage of kernel of the out_channels idx_outc
     * tmp_res: tmp storage of res (convolve all in_channels and sum up)
     * dim_sum: the origin tmp_res is at view of (1,ic,k1,k2), sum along the 1,2,3 axis
     * h_region: the h of convolve region - 1
     * w_region: the w of convolve region - 1
    */
    Eigen::Tensor<float_t, 4> region;
    Eigen::Tensor<float_t, 4> kernel;
    Eigen::Tensor<float_t, 1> tmp_res;
    Eigen::array<int, 3> dim_sum{1, 2, 3};
    int64_t h_region = (this->kernel_size.first - 1) * this->dilation.first;
    int64_t w_region = (this->kernel_size.second - 1) * this->dilation.second;
    for (int64_t idx_batch = 0; idx_batch < batch; idx_batch++) {
        for (int64_t idx_outc = 0; idx_outc < this->out_channels; idx_outc++) {
            kernel = this->weights.slice(Eigen::array<int64_t, 4>{idx_outc, 0, 0, 0},
                                         Eigen::array<int64_t, 4>{1, this->in_channels, this->kernel_size.first,
                                                                  this->kernel_size.second}
            );
            for (int64_t idx_h = 0; idx_h < H_pad - h_region; idx_h += stride.first) {
                for (int64_t idx_w = 0; idx_w < W_pad - w_region; idx_w += stride.second) {
                    region = padded_input.stridedSlice(
                            Eigen::array<int64_t, 4>{idx_batch, 0, idx_h, idx_w},
                            Eigen::array<int64_t, 4>{idx_batch + 1, this->in_channels, idx_h + h_region + 1,
                                                     idx_w + w_region + 1},
                            Eigen::array<int64_t, 4>{1, 1, this->dilation.first, this->dilation.second});
                    tmp_res = (region * kernel).sum(dim_sum);
                    output(idx_batch, idx_outc, idx_h / this->stride.first, idx_w / this->stride.second) =
                            tmp_res(0) + this->bias(0, idx_outc);
                }
            }
        }
    }
    return output;
}

这是基于循环写的,效率十分十分低。后面要写成unfold形式进行并行运算。

参考链接

[1] Conv2d介绍

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

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

相关文章

智工教育:注册计量师职业资格条件已改革!

第一&#xff0c;报名条件发生变化 注册计量师职业资格考试&#xff0c;取消了一级注册计量师职业资格考试报考条件中对工作年限的要求。 凡遵守中华人民共和国宪法、法律、法规&#xff0c;恪守职业道德&#xff0c;诚实守信&#xff0c;从事计量技术工作&#xff0c;符合注册…

Codeforces Round #290 (Div. 2) C. Fox And Names

翻译&#xff1a; Fox Ciel将发表一篇关于FOCS (Fox操作的计算机系统&#xff0c;发音:“Fox”)的论文。她听到一个谣言:报纸上的作者名单总是按照词典顺序排列的。 在查看了一些例子后&#xff0c;她发现有时这不是真的。在一些论文中&#xff0c;作者的名字没有按照正常意义…

【无人机】四轴无人机的轨迹进行可视化和动画处理(Matlab代码实现)

&#x1f4cb;&#x1f4cb;&#x1f4cb;本文目录如下&#xff1a;⛳️⛳️⛳️ ​ 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现 1 概述 随着传感器检测技术、智能控制技术和材料技术的快速发展,四轴无人机及其配套系统的发展越来越成熟。无人机遥感系统具有成本低、…

Java数据结构之Map与Set

文章目录一、搜索&#xff08;一&#xff09;概念及场景&#xff08;二&#xff09;模型二、Map&#xff08;一&#xff09;介绍&#xff08;二&#xff09;Map常用方法说明1.需要注意的几个点2.特别注意的几个方法(1)V getOrdefault(Object key,V defaultValue)&#xff0c;这…

【DL with Pytorch】第 5 章 :风格迁移

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

[JavaEE]计算机是如何工作的

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 1. javaEE概述 2. 计算机发展史 3. 冯诺依曼体系 …

java面试强基(15)

说明一下public static void main(String args[])这段声明里每个关键字的作用? ​ public: main方法是Java程序运行时调用的第一个方法&#xff0c;因此它必须对Java环境可见。所以可见性设置为 pulic. ​ static: Java平台调用这个方法时不会创建这个类的一个实例&#xf…

如何将带GPS的网络化的软件定义无线电接收机应用于分布式和移动频谱监测?(二)

GPS定位和测向的四种技术 知道感兴趣信号的位置对于许多应用很重要。军事用户获得了更好的态势感知能力&#xff0c;诸如机场或公用事业基础设施之类的敏感设施可以找到RF干扰源&#xff0c;电信公司可以识别恶意发射机或其他干扰其覆盖范围的设备。通过嵌入式GPS功能了解测量…

中国什么时候能办世界杯?

自从1930年在乌拉圭举办了第一届世界杯以来&#xff0c;到现在已经成功举办了22届&#xff0c;然而这22届里&#xff0c;光是欧洲就举办了11届&#xff0c;南美洲5届&#xff0c;中北美洲3届&#xff0c;亚洲2届&#xff0c;非洲1届。 说到这里不难发现&#xff0c;他们之间分布…

Azure DevOps Server 用户组加入 Azure AD Domain Service 管理用户

一&#xff0c;引言 今天我们继续讲解 Azure DevOps Server 的内容&#xff0c;对于管理用户组除了在 Azure DevOps Server 服务器上添加管理员方式外&#xff0c;还有没有其他方式&#xff0c;Azure DevOps 需要加入Azure ADDS 服务域后&#xff0c;Azure DevOps Server 的管理…

[附源码]计算机毕业设计springboot基于vue+mysql开发的考试系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

图扑软件荣获第七届“创客中国”中小企业创新创业大赛优胜奖!

2022 年 11 月 17 日&#xff0c;由工业和信息化部、财政部共同主办的第七届“创客中国”中小企业创新创业大赛全国总决赛在浙江杭州落下帷幕。 本次《第七届“创客中国”中小企业创新创业大赛》举办目的&#xff0c;意在加大优质中小企业梯度培育力度&#xff0c;进一步提升中…

ProcessDB实时/时序数据库——ODBC之连接数据库

目录 前言 一、安装ProcessDB-ODBC驱动 1.下载ProcessDB-ODBC驱动 2.安装ProcessDB-ODBC驱动 二、配置ProcessDB数据源 三、JAVA连接ProcessDB数据库 前言 ProcessDB实时/时序数据库支持ODBC连接数据库&#xff0c;接下来将和大家分享下如何使用ODBC操作ProcessDB实时/时…

Java基础之《netty(5)—NIO之Selector》

一、基本介绍 1、Java的NIO&#xff0c;用非阻塞的IO方式&#xff0c;可以用一个线程&#xff0c;处理多个的客户端连接&#xff0c;就会使用到Selector&#xff08;选择器&#xff09;。 2、Selector能够检测多个注册的通道上是否有事件发生&#xff08;注意&#xff1a;多个…

[附源码]SSM计算机毕业设计新闻发布和评论管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【冰糖Python】Python 中的 assert 语句

assert 判断一个表达式的真假&#xff0c;在表达式条件为 false 的时候触发异常&#xff0c;返回错误 具体用法&#xff1a; assert expression assert expression [, arguments] 实际用例&#xff1a; 注意以上使用&#xff1a; 1、条件为True时&#xff0c;assert不执行…

基于PHP+MySQL高校教务选课系统的设计与实现

兴趣是最好的老师,只有学生选择了自己感兴趣的课程才能够更好的进行学习,目前有很多高校的选课中出现很多问题,如学生对开设的课程不了解,代选课程等等,这些问题多而繁杂,不容易解决。 本系统就是为了学生开放的在线选课系统,而网络选课系统是帮助学生了解到所学课程的内容,多自…

Android——使用ContentProvider共享数据

实验名称&#xff1a; 使用ContentProvider共享数据 实验目的&#xff1a; &#xff08;1&#xff09;能使用ContentProvider共享数据 &#xff08;2&#xff09;能使用内容观察者观察其他程序的数据变化 实验内容及原理&…

H2N-Hyp-FF-OH, 2493080-84-3

Hyp-Phe-Phe 是一种三肽&#xff0c;通过 Phe 环的芳香相互作用形成螺旋状的薄片&#xff0c;构成一个交叉螺旋结构。Hyp-Phe-Phe 具有很高的剪切压电特性&#xff0c;可作为一种压电材料。Hyp-Phe-Phe is a tripeptide that forms helical-like sheets via aromatic interacti…

Flowable定时器与实时流程图江南一点雨

1. 定时器 1.1. 流程定义定时激活 在之前松哥给小伙伴们介绍流程定义的时候&#xff0c;流程都是定义好之后立马就激活了&#xff0c;其实在流程定义的这个过程中&#xff0c;我们还可以设置一个激活时间&#xff0c;也就是流程定义好之后&#xff0c;并不会立马激活&#xf…