您的位置:首页 > 其它

CNN-卷积计算

2018-01-01 15:06 671 查看

本文介绍卷积3种计算方式

卷积:

我们先认为图片是由不同的波形组成。在时域空间下,图片就是我们看到的图片,由很多不同频率波形混杂在一起。频域空间下,图片波型变的离散化,可以清楚看到每一个波形的å频率(这块解释非常的粗糙,如果看不明白,搜一下时域图和频域图)。在时域空间下,我们很难把一张图片上噪音完全过滤掉,一种做法,我认为是遍历整张图片,然后修改噪音部分,类似PS过程。另一种办法是将图片转换到频域空间下,开启上帝视角,直接滤掉某一固定频率的波,之后在转回时域空间。

对于后一个操作是:傅里叶变化->滤波->反傅里叶变化

再来看一下卷积算法:

F(f*g) = F(f)F(g)

也就是两个函数的卷积等于两个函数傅里叶变化后乘积的反傅里叶变化。

那么,可以将卷积运算对应于上述操作,个人觉得可以作为为什么CNN用卷积操作可以提取图像特种的解释。同时,这也提供了一种计算卷积的方法。

1.概念计算

这是我们最容易想明白并且可以很快自己实现的一种算法。

1)从左上到右下,对位相乘相加,然后移位。

def convolve2d(img, kernel):
k_w = kernel.shape[0]

def calc(pos_x, pos_y):
sum = 0
for i in range(k_w):
for j in range(k_w):
sum += img[pos_x+i][pos_y+j] * kernel[i][j]
return sum

rtval = np.array(np.zeros([img.shape[0], img.shape[1]]))
for j in range(img.shape[1] - k_w):
for i in range(img.shape[0] - k_w):
rtval[i][j] = calc(i,j)
return rtval


2.FFT(快速傅里叶)

1)F(f*g) = F(f)F(g)

from scipy import fftpack
import numpy as np

def convolve2d(in1, in2):
in1 = np.asarray(in1)
in2 = np.asarray(in2)

if in1.ndim == in2.ndim == 0:
return in1*in2
elif not in1.ndim == in2.ndim:
raise ValueError("in1 and in2 should have the       same dimensionality")
elif in1.size==0 or in2.size==0:
return array([])

s1 = np.array(in1.shape)
s2 = np.array(in2.shape)

shape = s1 + s2 -1
complex_result = (np.issubdtype(in1.dtype, np.complexfloating) or
np.issubdtype(in2.dtype, np.complexfloating))

fshape = [fftpack.helper.next_fast_len(int(d)) for d in shape]
fslice = tuple([slice(0, int(sz)) for sz in shape])

sp1 = np.fft.rfftn(in1, fshape)
sp2 = np.fft.rfftn(in2, fshape)
ret = (np.fft.irfftn(sp1 * sp2, fshape)[fslice].copy())

return ret


3.im2col

1)将移位乘加,转换为举证乘法。不重复讲思路了,可以搜索im2col去了解。

具体算法参考这篇

http://lib.csdn.net/article/aiframework/62849

def convolve2d(img, kernel):
img_row = img.shape[0]
img_col = img.shape[1]

kernel_row = kernel.shape[0]
kernel_col = kernel.shape[1]

output_row = img_row - kernel_row + 1
output_col = img_col - kernel_col + 1

N_h = kernel_row * kernel_col
N_w = output_row * output_col

N_matric = np.array(np.zeros([N_h,N_w]))

line = 0
for k_row in range(kernel_row):
for k_col in range(kernel_col):
tmp = 0
for row in range(output_row):
for col in range(output_col):
N_matric[line][tmp] = img[k_row+row][k_col+col]
tmp +=1
line += 1

K = kernel.reshape(-1)
rtval = np.matmul(K, N_matric)

return rtval.reshape(output_row,output_col)


图像尺寸:450 * 300

原图如下:



运行时间:

方法1:1.64s



方法2:0.013s



方法3: 0.98s



傅里叶变化效果非常诡异,感觉特别淡,不知道为什么。改写矩阵乘法再计算,确实可以加快卷积过程。

(之后需要回来补一下不同填充方式的处理)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: