#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.youkuaiyun.com/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()