卷积神经网络-基础教程_哔哩哔哩_bilibili
卷积层
卷积运算的目的是提取输入的不同特征。
参数:
size:卷积核/过滤器大小,选择有1×1,3×3
padding:零填充、valid与same
stride:步长,通常默认为1
计算公式:
缺点:图像变小
边缘信息丢失
padding-零填充
Valid and Same卷积
奇数维度的过滤器
stride-步长
多通道卷积
就是一张图片用一个三通道filter卷积核最终得到一张feature map。
多卷积核
卷积总结
和之前用神经网络几万个参数相比确实少了很多。
设计单个卷积filter的计算公式:
nh和nw是长宽,nc是通道数RGB。
4维是因为例如100张28×28的彩色图片就是[100,28,28,3]
卷积层实现代码介绍:
卷积实现的难点在于如何通过图片和过滤器去循环图片获得区域。
需要注意的是以下代码有问题,很明显的就是自相矛盾,尤其是对数组的定义,不清楚是不是[维度,长,宽]所以肯定跑不了,但是它的作用更多的是给了一个实现的思路,和整体方法的理解。抄一遍代码结合视频还是挺有帮助的。不过我也感觉这视频虽然讲的挺好,但应该是培训视频,这个代码按理说应该给能运行的,只能说学习思路吧。
假代码:
#encoding = utf-8
#支持中文字符
import numpy as np
def conv_(img, conv_filter):
"""
卷积核计算操作
:param img:图片数据
:param conv_filter:卷积核
:return:一张feature map
"""
#1、获取卷积核大小
filter_size = conv_filter.shape[1]
#初始化卷积后的结果,给个较大的输出结果
result = np.zeros((img.shape))
#2、对图片进行循环使用卷积操作(获取当前区域并使用过滤器进行相乘操作,)
#(1)r和c为特征图的下标,从0到特征图输出大小
#见CNN2的CSDN公式,例如5×5的图和3×3的卷积核,那就会输出(5-3+2×0)/1 + 1长的特征图,那就从1到3,
# 总范围是[0,4],1是filter尺寸3/2>1得到的,即不从第一位的0而是从1开始,同理结束是5-3/2+1<5,故结束至3而不是最后一位的4。
for r in np.uint16(np.arange(filter_size/2.0, img.shape[0] - filter_size/2.0 + 1)):
for c in np.uint16(np.arange(filter_size/2.0, img.shape[1] - filter_size/2.0 + 1)):
#取出过滤器大小的图片区域,从图片左上角开始
curr_region = img[r-np.uint16(np.floor(filter_size/2.0)):r+np.uint16(np.ceil(filter_size/2.0)),
c-np.uint16(np.floor(filter_size/2.0)):c+np.uint16(np.ceil(filter_size/2.0))]
#图片当前区域与卷积核进行线性相乘
curr_result = curr_region * conv_filter
#结果求和并保存,按照下表保存
conv_sum = np.sum(curr_result)
result[r,c] = conv_sum
#裁剪矩阵
#实际上就是5×5的图+3×3卷积后是3×3的输出,但之前定义的是结果图是5×5,所以要裁剪至3×3
final_result = result[np.uint16(filter_size/2.0):result.shape[0]-np.uint16(filter_size/2.0),
np.uint16(filter_size/2.0):result.shape[1]-np.uint16(filter_size/2.0)]
return final_result
def conv(img, conv_filter):
"""
卷积过程实现
:param img:图像
:param conv_filter:卷积过滤器
:return:
"""
#1、输入的参数大小做异常检测
#检查输入的图片和卷积核是否一样大小
if len(img.shape) != len(conv_filter.shape) - 1:
print("Error:Number of dimensions in conv filter and image do not match.")
exit()
#检查输入的图片的通道数和卷积的深度一样
if len(img.shape) > 2 or len(conv_filter.shape) > 3:
if img.shape[-1] != conv_filter.shape[-1]:
print("Error:Number of channels in both image and filter must match.")
exit()
#检查是否过滤器的长宽一样
if conv_filter.shape[1] != conv_filter.shape[2]:
print("Error:Filter must be a square matrix.I.e.number of rows and columns must be same!")
exit()
#检查过滤器的维度是奇数
if conv_filter.shape[0] % 2 == 0:
print("Error:Filter must have an odd size.I.e. number of rows and columns must be odd.")
exit()
#2、初始化一个空的特征图来装入计算的结果
feature_maps = np.zeros((img.shape[0]-conv_filter.shape[1]+1,
img.shape[1]-conv_filter.shape[1]+1,
conv_filter.shape[0]))
#3、图片的卷积完整操作(分别使用每一个过滤器进行过滤操作)
for filter_num in range(conv_filter.shape[0]):
print("Filter", filter_num + 1)
#获取当前的filter参数
curr_filter = conv_filter[filter_num, : ]
#当前filter进行卷积核计算操作
if len(curr_filter.shape) > 2:
#对图片的每个channel进行卷积运算
conv_map = conv_(img[:, :, 0], curr_filter[:, :, 0])
for ch_num in range(1, curr_filter.shape[-1]):
conv_map = conv_map +conv_(img[:, :, ch_num], curr_filter[:, :, ch_num])
else:
#只有一个filter的情况
conv_map = conv_(img, curr_filter)
feature_maps[:, :, filter_num] = conv_map
return feature_maps
#使用过程
#1、定义这层有两个卷积核,每个大小3×3(例子默认对黑白图片进行计算),默认一个步长,不零填充
if __name__ == '__main__':
l1_filter = np.zeros((2,3,3))
#初始化参数
l1_filter[0, :, :] = np.array([[[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]]])
l1_filter[1, :, :] = np.array([[[1, 1, 1],
[0, 0, 0],
[-1, -1, 1]]])
#卷积计算
l1_feature_map = cnn.conv(img, l1_filter)