卷积神经网络的特点以及训练过程

卷积神经网络的特点以及训练过程

首先明确:卷积神经网络的训练是为了得到卷积核,方便之后进行其他操作

卷积神经网络的特点

1、局部感知:

一般认为图像的空间联系是局部的像素联系比较密切,而距离较远的像素相关性较弱,因此,每个神经元没必要对全局图像进行感知,只要对局部进行感知,然后在更高层将局部的信息综合起来得到全局信息。

2、参数共享:

在局部连接中,每个神经元的参数都是一样的,即:同一个卷积核在图像中都是共享的。(理解:卷积操作实际是在提取一个个局部信息,而局部信息的一些统计特性和其他部分是一样的,也就意味着这部分学到的特征也可以用到另一部分上。所以对图像上的所有位置,都能使用同样的学习特征。)卷积核共享有个问题:提取特征不充分,可以通过增加多个卷积核来弥补,可以学习多种特征。

3、采样(池化)层:

在通过卷积得到特征后,基于局部相关性原理进行亚采样,在减少数据量的同时保留有用信息。(压缩数据和参数的量,减少过拟合)(max-polling 和average-polling)

多核卷积

通过权值共享可以了解到:用一个卷积核操作只能得到一部分的特征,但是得不到全部特征,这时候就必须引入多卷积核来尽可能多的获取图像矩阵的全部特征,即每个卷积核学习不同特征(卷积核不同的值)来提取原图特征。

下面图片经过三个卷积核的卷积操作得到三个特征图,每个特征图体现原图不同特征。需要注意的是,在多核卷积的过程中每个卷积核的大小应该是相同的。

池化

池化层往往在卷积层后面,通过池化降低卷积层输出的特征向量,同时降低过拟合发生。

卷积神经网络CNN究竟是怎样一步一步工作

参考:https://www.jianshu.com/p/fe428f0b32c1

卷积的实际使用

代码:

代码中自行实现了卷积的操作,因为使用的卷积核都是对称的,所以不需要对其进行180旋转的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import matplotlib.pyplot as plt
import pylab
import numpy as np

def convolve(img, fil, mode='same'): # 分别提取三个通道
if mode == 'fill':
h = fil.shape[0] // 2
w = fil.shape[1] // 2
img = np.pad(img, ((h, h), (w, w), (0, 0)), 'constant')
conv_b = _convolve(img[:, :, 0], fil) # 然后去进行卷积操作
conv_g = _convolve(img[:, :, 1], fil)
conv_r = _convolve(img[:, :, 2], fil)

dstack = np.dstack([conv_b, conv_g, conv_r]) # 将卷积后的三个通道合并
return dstack # 返回卷积后的结果


def _convolve(img, fil):
fil_heigh = fil.shape[0] # 获取卷积核(滤波)的高度
fil_width = fil.shape[1] # 获取卷积核(滤波)的宽度

conv_heigh = img.shape[0] - fil.shape[0] + 1 # 确定卷积结果的大小
conv_width = img.shape[1] - fil.shape[1] + 1

conv = np.zeros((conv_heigh, conv_width), dtype='uint8')

for i in range(conv_heigh):
for j in range(conv_width): # 逐点相乘并求和得到每一个点
conv[i][j] = wise_element_sum(img[i:i + fil_heigh, j:j + fil_width], fil)
return conv


def wise_element_sum(img, fil):
res = (img * fil).sum()
if (res < 0):
res = 0
elif res > 255:
res = 255
return res


img = plt.imread("../res/test_jpg.jpg") # 在这里读取图片

# 卷积核应该是奇数行,奇数列的
fil = np.array([[-1, -1, 0],
[-1, 0, 1],
[0, 1, 1]])

res = convolve(img, fil, 'fill')
plt.imshow(res) # 显示卷积后的图片
pylab.show()

代码说明

首先构造一个卷积核(当然在实际使用中是通过训练得到的),然后通过这个卷积核对图像进行操作。

代码中kernal即为卷积核,将图片和卷积核都转为numpy类型,然后进行卷积操作。

对图片进行模糊

假设我们使用图片

使用kernal为

1
2
3
0.0, 0.2,  0.0,
0.2, 0.2, 0.2,
0.0, 0.2, 0.0

即我们通过将图片局部进行类似平均化的操作,达到模糊目的。

得到结果:

如果我们使用更大的卷积核来对图片操作,kernal设置为:

1
2
3
4
5
0, 0, 1, 0, 0,
0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
0, 1, 1, 1, 0,
0, 0, 1, 0, 0,

我们会得到更模糊的图片:

**另外有关图像的锐化,风格转化等更加详细的介绍可以参考下面的网址

我这篇博客就是根据其进行的总结,因为链接这篇文章已经说明的很清晰了,所以我就不再废话了:https://lodev.org/cgtutor/filtering.html

在运行过程中遇到的问题

关于 .jpg 与 .png的不同之处

对于jpg和png图像的不同之处,之前一直是没有了解,都是混用,但是在这次图像卷积实验中,看出了不同之处。

如果你把上面代码中的.jpg文件改为.png文件,那么就无法得到正常的结果,为什么呢?

这还要从jpg和png的不同之处说起。

.jpg 是由三通道组成的,Red(红色)Green(绿色)Blue(蓝色),也就是说转为numpy后的shape为(x,x,3)

.png是由四通道组成的,Red(红色)Green(绿色)Blue(蓝色)和Alpha,其中Alpha通道一般用做透明度参数,这就是为啥透明图像都保存成了png格式,一般在程序开发过程中会用到透明背景的图片,这些图片都是.png类型的。.png图像转为numpy后的shape为(x,x,4)。

这算是自己的无知采坑了吧。