im2col.cpp

2023-11-07 05:59
文章标签 cpp im2col

本文主要是介绍im2col.cpp,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

主要是两个函数,一个是im2col_cpu,一个是col2im_cpu函数。

im2col函数功能的是将原始的图像数据转化为一个矩阵,用于卷积操作,转换的目的是为了方便矩阵乘法。在进行了矩阵乘法之后,还要转换为图像形式,所以还需要col2im函数。

矩阵乘法参考: caffe im2col 详解

im2col 具体例子参考: caffe源码深入学习6:超级详细的im2col绘图解析,分析caffe卷积操作的底层实现

要弄懂caffe源码里面im2col具体实现,还需要知道 dilated convolution

我不完整的写出整个过程,只做一定笔记,或者关注其中的某些细节。


1.dilated细节

这里写图片描述

上图所示的
(a)是没有进行dilate的卷积核,
(b)图中dilation_h=dilation_w=2,
(c)图中dilation_h=dilation_w=3。

关注图中的红点,在dilation=1时,使用的就是原始的卷积核,否则9个红点继承原来的权值,其余部位填充为0。


2.矩阵乘法细节(卷积实现)

左边的矩阵.shape=(卷积核数目=输出通道数,图像输入通道数 * 卷积核权值数=图像输入通道数 * 卷积核高*卷积核宽)

右边的矩阵.shape=(图像输入通道数 * 卷积核权值数=图像输入通道数 * 卷积核高 * 卷积核宽 , 输出图像每层通道的数据 = 输出图像高 * 输出图像宽)

结果矩阵.shape=(图像输出通道数=卷积核数目,输出图像高 * 输出图像宽)


3.输出图像高、宽的计算

输出图像的高、宽的计算是根据stride、pad、dilation等计算出来的

const int output_h = (height + 2 * pad_h -
(dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;

const int output_w = (width + 2 * pad_w -
(dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;


4.is_a_ge_zero_and_a_lt_b(int a, int b)

判断 0<=a & & a<b

// Function uses casting from int to unsigned to compare if value of
// parameter a is greater or equal to zero and lower than value of
// parameter b. The b parameter is of type signed and is always positive,
// therefore its value is always lower than 0x800... where casting
// negative value of a parameter converts it to value higher than 0x800...
// The casting allows to use one condition instead of two.
inline bool is_a_ge_zero_and_a_lt_b(int a, int b) {return static_cast<unsigned>(a) < static_cast<unsigned>(b);
}

im2col_cpu


图像单通道的转化情形

template <typename Dtype>
void im2col_cpu(const Dtype* data_im, const int channels,const int height, const int width, const int kernel_h, const int kernel_w,const int pad_h, const int pad_w,const int stride_h, const int stride_w,const int dilation_h, const int dilation_w,Dtype* data_col) {const int output_h = (height + 2 * pad_h -(dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;const int output_w = (width + 2 * pad_w -(dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;const int channel_size = height * width;for (int channel = channels; channel--; data_im += channel_size) {for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++){int input_row = -pad_h + kernel_row * dilation_h;for (int output_rows = output_h; output_rows; output_rows--){if (!is_a_ge_zero_and_a_lt_b(input_row, height)){for (int output_cols = output_w; output_cols; output_cols--) {*(data_col++) = 0;}}else{int input_col = -pad_w + kernel_col * dilation_w;for (int output_col = output_w; output_col; output_col--){if (is_a_ge_zero_and_a_lt_b(input_col, width))*(data_col++) = data_im[input_row * width + input_col];else  *(data_col++) = 0;input_col += stride_w;}}input_row += stride_h;}}}}
}

col2im

针对单通道的情形


template <typename Dtype>
void col2im_cpu(const Dtype* data_col, const int channels,const int height, const int width, const int kernel_h, const int kernel_w,const int pad_h, const int pad_w,const int stride_h, const int stride_w,const int dilation_h, const int dilation_w,Dtype* data_im){caffe_set(height * width * channels, Dtype(0), data_im);const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1) ) / stride_h + 1;const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)  ) / stride_w + 1;const int channel_size = height * width;for (int channel = channels; channel--; data_im += channel_size){for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++){for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++){int input_row = -pad_h + kernel_row * dilation_h;for (int output_rows = output_h; output_rows; output_rows--){if (!is_a_ge_zero_and_a_lt_b(input_row, height))data_col += output_w;else{int input_col = -pad_w + kernel_col * dilation_w;for (int output_col = output_w; output_col; output_col--){if (is_a_ge_zero_and_a_lt_b(input_col, width)){data_im[input_row * width + input_col] += *data_col;}data_col++;input_col += stride_w;}}input_row += stride_h;}}}}
}

这篇关于im2col.cpp的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/361693

相关文章

类模板中.h和.cpp的实现方法

一般类的声明和实现放在两个文件中,然后在使用该类的主程序代码中,包含相应的头文件".h"就可以了,但是,模板类必须包含该其实现的.cpp文件才行。也就是说,在你的主程序中,将 #include"DouCirLList.h" 替换成 #include"DouCirLList.cpp" 应该就可以了。 在使用类模板技术时,可在.h中实现,也可在.h和.cpp中分开实现,若用.h实

CPP中的hash [more cpp-7]

写在前面 hash 在英文中是弄乱的含义。在编程中,hash是一种数据技术,它把任意类型的数据通过算法,生成一串数字(hash code),实现hash的函数称为哈希函数,又称散列函数,杂凑函数。在CPP中hashcode是一个size_t类型的数字。 你可能会问?把数据弄乱有什么用?为什么我们要把数据映射到一串数字上?这又什么意义吗?我们先看看hash的性质 一般hash性质 唯一性(唯

【最新华为OD机试E卷-支持在线评测】机器人活动区域(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 最新华为OD机试目录: https://blog.

llama.cpp demo

git clone https://github.com/ggerganov/llama.cppcd llama.cpp 修改Makefile使能mfma参数     MK_CFLAGS   += -mfma -mf16c -mavx     MK_CXXFLAGS += -mfma -mf16c -mavx 安装python3依赖 cat ./requirements/requirem

【最新华为OD机试E卷-支持在线评测】分糖果(100分)-多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 最新华为OD机试目录: https://blog.

【最新华为OD机试E卷-支持在线评测】查找充电设备组合(200分)-多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 最新华为OD机试目录: https://blog.

llama.cpp本地部署大模型

llama.cpp 是一个C++库,用于简化LLM推理的设置,它使得在本地机器上运行大模型(GGUF格式)成为可能。 官网:https://github.com/ggerganov/llama.cpp 模型库: https://huggingface.co/ HF-Mirror 魔搭社区 安装并且使用llama.cpp 0.安装llama.cpp 官方文档:https://gi

gcc/g++编译 cpp/c文件 生成可执行文件

g++编辑cpp生成exe 编译重命名等: g++ –c Hello.cc  编译文件,生成目标文件 Hello.o g++ Hello.o –o abc  连接 并重命名为可执行文件 abc g++ Hello.cc    编译连接一起,生成a.out g++ Hello.cc –o hello 生成a.out并命名为hello 多文件编译 $

TinyWebSever源码逐行注释(一)_webserver.cpp

前言 项目源码地址 项目详细介绍 项目简介: Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器. 使用 线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor和模拟Proactor均实现) 的并发模型使用状态机解析HTTP请求报文,支持解析GET和POST请求访问服务器数据库实现web端用户注册、登录功能,可以请

CPP多态

目录 前言 多态的概念 多态的定义及实现 多态的构成条件 虚函数 虚函数的重写 虚函数重写的两个例外 C++11 override 和 final 重载、覆盖(重写)、隐藏(重定义)的对比 抽象类 接口继承和实现继承 多态的原理 虚函数表 多态的原理 动态绑定与静态绑定 单继承和多继承关系的虚函数表 单继承中的虚函数表 多继承中的虚函数表 菱形继承、菱形虚拟