C++实现卷积(conv)操作-三种方式(valid,full,same) ,卷积的三种模式:full, same, valid

#include<iostream>
#include<malloc.h>
using namespace std;

//matrix表示原图像,new_h表示原图像的高,new_w表示原图像的宽,m_h表示模板的高,m_w表示模板的宽.
//返回值为:填充好的图像.
int * zero_pad(int * matrix, int new_h, int new_w, int m_h, int m_w) {
	// 求出原图像在新图像当中的位置
	int start = (new_h - m_h) / 2;
	int end = new_h - start - 1;
	int left = (new_w - m_w) / 2;
	int right = new_w - left - 1;
	int i, j, k, l;
	int matrix_index = 0;
	int* result = (int*)malloc(sizeof(int)*new_h*new_w);
	for (i = 0; i < new_h; i++) {
		for (j = 0; j < new_w; j++) {
			if (i<start || i>end ||j<left || j>right) {
				result[i * new_w + j] = 0;
			}
			else {
				result[i * new_w + j] = matrix[matrix_index];
				matrix_index++;
			}

		}
	}
	return result;
}

//一、
//matrix表示原图像,v表示模板,m_h表示原图像的高,m_w表示原图像的宽,v_w表示模板的宽,v_h表示模板的高
//返回值为:valid方式卷积的图像.
int * valid_way(int *matrix, int *v, int m_w, int m_h, int v_w, int v_h) {
	int i, j, k, l;
	int a_h = m_h - v_h + 1;
	int b_w = m_w - v_w + 1;
	int* result = (int*)malloc(sizeof(int)*a_h*b_w);
	for (i = 0; i < a_h; i++) {
		for (j = 0; j < b_w; j++) {
			result[i*b_w + j] = 0;
			for (k = 0; k < v_h; k++) {
				for (l = 0; l < v_w; l++) {
					result[i*b_w + j] += matrix[(i + k)*m_w + j + l] * v[k*v_w + l];
				}
			}
		}
	}
	return result;
}
//二、
//matrix表示原图像,v表示模板,m_h表示原图像的高,m_w表示原图像的宽,v_w表示模板的宽,v_h表示模板的高.
//返回值为:full方式卷积的图像.
int * full_way(int *matrix, int *v,int m_h,int m_w,int v_h, int v_w) {
	int* result = (int*)malloc(sizeof(int)*(m_h + 2*v_h-2)*(m_w + 2 * v_w - 2));
	result = zero_pad(matrix, (m_h + 2 * v_h - 2), (m_w + 2 * v_w - 2), m_h, m_w);
	result = valid_way(result, v, (m_h + 2 * v_h - 2), (m_w + 2 * v_w - 2), v_w, v_h);
	return result;
}

//三、
//matrix表示原图像,v表示模板,m_h表示原图像的高,m_w表示原图像的宽,v_w表示模板的宽,v_h表示模板的高.
//返回值为:same方式卷积的图像.
int * same_way(int *matrix, int *v, int m_h, int m_w, int v_h, int v_w) {
	int* result = (int*)malloc(sizeof(int)*(m_h +  v_h - 1)*(m_w + v_w - 1));
	result = zero_pad(matrix, (m_h +  v_h - 1), (m_w + v_w - 1), m_h, m_w);
	result = valid_way(result, v, (m_h +  v_h -1), (m_w + v_w - 1), v_w, v_h);
	return result;
}

反卷积操作:

上采样有3种常见的方法:双线性插值(bilinear),反卷积(Transposed Convolution),反池化。反卷积是一种特殊的正向卷积,先按照一定的比例通过补 来扩大输入图像的尺寸,接着旋转卷积核,再进行正向卷积。

对于反卷积:其卷积填充的格式对应反卷积输入的填充格式:

No padding: p’ = k-1

Padding : p’ = k - p - 1

Half padding: p’ =  p = 向下取整(k/2)

Full padding: p’= 0

对于反卷积:其卷积stride的格式对应反卷积输入的stride填充0格式:

当stride = 1  ,则像素点间不填充0

当stride != 1,则像素点间填充0的个数是:stride - 1

No zero padding, unit strides, transposed:

Zero padding, unit strides, transposed:

Half (same) padding, transposed:

Full padding, transposed:

No zero padding, non-unit strides, transposed:

Zero padding, non-unit strides, transposed:

借鉴了:https://blog.csdn.net/huachao1001/article/details/79131814的代码,仅供自己学习。

# 根据输入map([h,w])和卷积核([k,k]),计算卷积后的feature map
import numpy as np

input_data=[
               [[1,0,1],
                [0,2,1],
                [1,1,0]],

               [[2,0,2],
                [0,1,0],
                [1,0,0]],

               [[1,1,1],
                [2,2,0],
                [1,1,1]],

               [[1,1,2],
                [1,0,1],
                [0,2,2]]

            ]
weights_data=[
              [[[ 1, 0, 1],
                [-1, 1, 0],
                [ 0,-1, 0]],
               [[-1, 0, 1],
                [ 0, 0, 1],
                [ 1, 1, 1]],
               [[ 0, 1, 1],
                [ 2, 0, 1],
                [ 1, 2, 1]],
               [[ 1, 1, 1],
                [ 0, 2, 1],
                [ 1, 0, 1]]],

              [[[ 1, 0, 2],
                [-2, 1, 1],
                [ 1,-1, 0]],
               [[-1, 0, 1],
                [-1, 2, 1],
                [ 1, 1, 1]],
               [[ 0, 0, 0],
                [ 2, 2, 1],
                [ 1,-1, 1]],
               [[ 2, 1, 1],
                [ 0,-1, 1],
                [ 1, 1, 1]]]
           ]

def compute_conv(fm, kernel):
    [h, w] = fm.shape
    [k, _] = kernel.shape
    r = int(k / 2)
    # 定义边界填充0后的map
    padding_fm = np.zeros([h + 2, w + 2], np.float32)
    # 保存计算结果
    rs = np.zeros([h, w], np.float32)
    # 将输入在指定该区域赋值,即除了4个边界后,剩下的区域
    padding_fm[1:h + 1, 1:w + 1] = fm
    # 对每个点为中心的区域遍历
    for i in range(1, h + 1):
        for j in range(1, w + 1):
            # 取出当前点为中心的k*k区域
            roi = padding_fm[i - r:i + r + 1, j - r:j + r + 1]
            # 计算当前点的卷积,对k*k个点点乘后求和
            rs[i - 1][j - 1] = np.sum(roi * kernel)

    return rs


# 填充0
def fill_zeros(input):
    [c, h, w] = input.shape
    #rs = np.zeros([c, h * 2 + 1, w * 2 + 1], np.float32)

    # ph = No padding: p’ = k-1
    # Padding : p’ = k - p - 1
    # Half padding: p’ =  p = 向下取整(k/2)
    # Full padding: p’= 0
    # pw 同理
    rs = np.zeros([c, h + (h - 1)*(stride - 1) + ph, w + (w - 1)*(stride - 1) + pw], np.float32)
    for i in range(c):
        for j in range(h):
            for k in range(w):
                rs[i, 2 * j + 1, 2 * k + 1] = input[i, j, k]
    return rs


def my_deconv(input, weights):
    # weights shape=[out_c,in_c,h,w]
    [out_c, in_c, h, w] = weights.shape
    out_h = h * 2
    out_w = w * 2
    rs = []
    for i in range(out_c):
        w = weights[i]
        tmp = np.zeros([out_h, out_w], np.float32)
        for j in range(in_c):
            conv = compute_conv(input[j], w[j])
            # 注意裁剪,最后一行和最后一列去掉
            tmp = tmp + conv[0:out_h, 0:out_w]
        rs.append(tmp)

    return rs


def main():
    input = np.asarray(input_data, np.float32)
    input = fill_zeros(input)
    weights = np.asarray(weights_data, np.float32)
    deconv = my_deconv(input, weights)

    print(np.asarray(deconv))


if __name__ == '__main__':
    main()

 

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值