【DL学习笔记06】深度学习入门——基于Python的理论与实现(ch07: 卷积神经网络 CNN)
目录
1. 整体结构
2. 卷积层
全连接层存在的问题
卷积运算
3维数据的卷积运算
批处理
3. 池化层
4. 卷积层和池化层的实现
卷积层
池化层的实现
5. CNN的实现
6. CNN的可视化
第1层权重的可视化
基于分层结构的信息提取
7. 具有代表性的CNN
LeNet
AlexNet
CNN被用于图像识别、语音识别等各种场景
1. 整体结构
- CNN通过组装层来构建,新出现了卷积层(Convolution层)和池化层(Pooling层)
- 全连接(fully-connected):相邻层的所有神经元之间都有连接,用Affine层实现
- 基于全连接层(Affine层):Affine - ReLU(Sigmoid)
- 基于CNN网络:Convolution - ReLU - Pooling
2. 卷积层
全连接层存在的问题
- 在全连接层中,相邻的神经元全部连接在一起,输出的数量可以任意决定
- 向全连接层输入时,会将3维数据拉平为1维数据,因此数据的形状会被“忽视”
- 卷积层可以保持形状不变,会以3维数据的形式接收输入数据,并同样传输至下一层
- CNN中,卷积层的输入数据称为输入特征图,输出为输出特征图,统称为特征图
卷积运算
卷积层进行的处理就是卷积运算,相当于图像处理中的“滤波器运算”
对于输入数据,卷积运算以一定间隔滑动滤波器的窗口并应用
偏置:向应用了滤波器的元素加上某个固定值
填充:在进行卷积层的处理之前,向输入数据的周围填入固定的数据(比如0),为了调整输出的大小,避免反复进行卷积运算时输出不断缩小到1,导致无法进行卷积运算
步幅:应用滤波器的位置间隔
3维数据的卷积运算
- 和2维数据相比,纵深方向(通道方向)上增加了特征图
- 通道方向上有多个特征图时,会按通道进行输入数据和滤波器的卷积运算,并将结果相加,从而得到输出
- 滤波器的通道数只能设定为和输入数据的通道数相同的值
- 结合方块思考
- 3维数据:(channel,height,width)(通道数,高度,长度)
- 滤波器
- 1个滤波器:(channel,height,width),数据输出是1张特征图
- n个滤波器:(output_channel,input_channel,height,width)(滤波器个数,通道数,高度,长度),数据输出是n张特征图
批处理
- 需要将在各层间传递的数据保存为4维数据,(batch_num,channel,height,width)
3. 池化层
池化层是缩小高、长方向上的空间的运算,在图像识别领域,主要使用Max池化,取出目标区域的最大值,此外还有Average池化等。一般来说,池化的窗口大小会和步幅设定成相同的值
- 特征:
- 没有要学习的参数
- 通道数不发生变化
- 对微小的位置变化具有健壮性
4. 卷积层和池化层的实现
NumPy中存在使用for语句后处理变慢的缺点。因此卷积运算我们不适用for语句,而是使用im2col这个函数实现
im2col函数(image to column)可以将输入数据展开以适合滤波器(权重)。会在所有应用滤波器的地方进行这个展开处理
函数的原理和实现可以参考im2col的原理和实现_dwyane12138的博客-CSDN博客_im2col
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):"""Parameters----------input_data : 由(数据量, 通道, 高, 长)的4维数组构成的输入数据filter_h : 滤波器的高filter_w : 滤波器的长stride : 步幅pad : 填充Returns-------col : 2维数组"""N, C, H, W = input_data.shapeout_h = (H + 2*pad - filter_h)//stride + 1out_w = (W + 2*pad - filter_w)//stride + 1img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))for y in range(filter_h):y_max = y + stride*out_hfor x in range(filter_w):x_max = x + stride*out_wcol[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)return col
# 用于反向传播的逆处理 def col2im(col, input_shape, filter_h, filter_w, stride=1, pad=0):"""Parameters----------col :input_shape : 输入数据的形状(例:(10, 1, 28, 28))filter_h :filter_wstridepadReturns-------"""N, C, H, W = input_shapeout_h = (H + 2*pad - filter_h)//stride + 1out_w = (W + 2*pad - filter_w)//stride + 1col = col.reshape(N, out_h, out_w, C, filter_h, filter_w).transpose(0, 3, 4, 5, 1, 2)img = np.zeros((N, C, H + 2*pad + stride - 1, W + 2*pad + stride - 1))for y in range(filter_h):y_max = y + stride*out_hfor x in range(filter_w):x_max = x + stride*out_wimg[:, :, y:y_max:stride, x:x_max:stride] += col[:, :, y, x, :, :]return img[:, :, pad:H + pad, pad:W + pad]
使用im2col展开输入数据后,再将卷积层的滤波器纵向展开为1列,并计算2个矩阵的乘积即可
卷积层
先举个例子!
x1 = np.random.rand(1, 3, 7, 7) col1 = im2col(x1, 5, 5, stride=1, pad=0) print(col1.shape) # (9,75)x2 = np.random.rand(10, 3, 7, 7) col2 = im2col(x2, 5, 5, stride=1, pad=0) print(col2.shape) # (90,75)
- 第一个是批大小为1,通道为3的7 x 7的数据,第二个是批大小改为10
- 第2维的元素个数均为75,是滤波器的元素个数的总和
实现
class Convolution:# 初始化,接收滤波器(权重)、偏置、步幅、填充def __init__(self, W, b, stride=1, pad=0):self.W = Wself.b = bself.stride = strideself.pad = paddef forward(self, x):# Filter Number(滤波器数量),Channel,Filter Height,Filter WidthFN, C, FH, FW = self.W.shapeN, C, H, W = x.shape# 用于还原转换被展开的数据out_h = int(1 + (H + 2*self.pad - FH) / self.stride)out_w = int(1 + (W + 2*self.pad - FW) / self.stride)# 用im2col函数展开输入数据,用reshape将滤波器展开为2维数组# 这里用了reshape(FN, -1)表示有FN行,然后-1会自动计算有几列col = im2col(x, FH, FW, self.strde, self.pad)col_W = self.W.reshape(FN, -1).Tout = np.dot(col, col_W) + self.b# transpose会更改多维数组的轴的顺序# 将原来的形状(N, H, W, C) 还原为 (N, C, H, W)out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)return outdef backward(self, dout):FN, C, FH, FW = self.W.shapedout = dout.transpose(0, 2, 3, 1).reshape(-1, FN)self.db = np.sum(dout, axis=0)self.dW = np.dot(self.col.T, dout)self.dW = self.dW.transpose(1, 0).reshape(FN, C, FH, FW)dcol = np.dot(dout, self.col_W.T)# im2col的逆处理->col2imdx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)return dx
池化层
池化层和卷积层相同,都使用im2col展开输入数据,不过池化层在通道方向上是独立的
class Pooling:def __init__(self, pool_h, pool_w, stride=1, pad=0):self.pool_h = pool_hself.pool_w = pool_wself.stride = strideself.pad = paddef forward(self, x):N, C, H, W = x.shapeout_h = int(1 + (H - self.pool_h) / self.stride)out_w = int(1 + (W - self.pool_w) / self.stride)# 展开,第二步是为了实现池化的应用区域按通道单独展开col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)col = col.reshape(-1, self.pool_h*self.pool_w)# 最大值out = np.max(col, axis=1)# 转换out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)return outdef backward(self, dout):dout = dout.transpose(0, 2, 3, 1)pool_size = self.pool_h * self.pool_wdmax = np.zeros((dout.size, pool_size))dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] = dout.flatten()dmax = dmax.reshape(dout.shape + (pool_size,))dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)dx = col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad)return dx
5. CNN的实现
这里我们搭建进行手写数字识别的CNN
网络构成:Convolution - ReLU - Pooling - Affine - ReLU - Affine - Softmax
初始化部分:
class SimpleConvNet:def __init__(self, input_dim=(1, 28, 28), conv_param=None,hidden_size=100, output_size=10, weight_init_std=0.01):""":param input_dim:输入数据的维度:(通道,高,长):param conv_param:卷积层的超参数(字典)。字典的关键字如下:filter_num - 滤波器数量;filter_size - 滤波器大小stride - 步幅;pad - 填充:param hidden_size:隐藏层(全连接)的神经元数量:param output_size:输出层(全连接)的神经元数量:param weight_init_std:初始化时权重的标准差"""# 将超参数从字典中取出来,计算卷积层的输出大小if conv_param is None:conv_param = {'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1}filter_num = conv_param['filter_num']filter_size = conv_param['filter_size']filter_pad = conv_param['pad']filter_stride = conv_param['stride']input_size = input_dim[1]conv_output_size = (input_size - filter_size + 2*filter_pad) / filter_stride + 1pool_output_size = int(filter_num * (conv_output_size/2) * (conv_output_size/2))# 权重参数的初始化# 包括第1层的卷积层和剩余两个全连接层的权重和偏置self.params = {'W1': weight_init_std * np.random.randn(filter_num, input_dim[0], filter_size, filter_size),'b1': np.zeros(filter_num),'W2': weight_init_std * np.random.randn(pool_output_size, hidden_size),'b2': np.zeros(hidden_size),'W3': weight_init_std * np.random.randn(hidden_size, output_size),'b3': np.zeros(output_size)}
推理和求损失函数值:
# 推理def predict(self, x):for layer in self.layers.values():x = layer.forward()return x# 求损失函数值 def loss(self, x, t):y = self.predict(x)return self.last_layer.forward(y, t)
误差反向传播法求梯度
def gradient(self, x, t):# forwardself.loss(x, t)# backwarddout = 1dout = self.lastLayer.backward(dout)layers = list(self.layers.values())layers.reverse()for layer in layers:dout = layer.backward(dout)# 设定grads = {'W1': self.layers['Conv1'].dW, 'b1': self.layers['Conv1'].db,'W2': self.layers['Affine1'].dW, 'b2': self.layers['Affine1'].db,'W3': self.layers['Affine2'].dW, 'b3': self.layers['Affine2'].db}return grads
6. CNN的可视化
第1层权重的可视化
上述对MNIST数据集的学习中,第1层的卷积层的权重形状是(30,1,5,5),意味着滤波器可以可视化为1通道的灰度图像
- 可以发现,学习前的滤波器是随即进行初始化的,学习后的滤波器变成了有规律的图像,比如从白变到黑的滤波器、含有块状区域(blob)的滤波器等
- 有规律的滤波器在“观察”边缘(颜色变化的分界线)和斑块(局部的块状区域)等
- 卷积层的滤波器会提取边缘或斑块等原始信息,而实现的CNN会将这些原始信息传递给后面的层
基于分层结构的信息提取
- 第1层的卷积层中提取了边缘或斑块等“低级”信息,但如果堆叠了多层卷积层,随着层次加深,提取的信息也愈加复杂、抽象。最开始的层对简单的边缘有响应,接下来的层对纹理有响应,再后面的层对更加复杂的物体部件有响应
- 下一节会介绍堆叠了多层卷积层和池化层最后经过全连接层输出结果的AlexNet
7. 具有代表性的CNN
LeNet
是进行手写数字识别的网络
AlexNet
【DL学习笔记06】深度学习入门——基于Python的理论与实现(ch07: 卷积神经网络 CNN)相关推荐
- 《深度学习入门——基于Python的理论与实现》笔记
PS:写这篇博客主要是记录下自己认为重要的部分以及阅读中遇到的些问题,加深自己的印象. 附上电子书及源代码: 链接:https://pan.baidu.com/s/1f2VFcnXSSK-u3wuvg ...
- 《深度学习入门-基于Python的理论与实现》学习笔记1
<深度学习入门-基于Python的理论与实现>学习笔记1 第一章Python入门 Python是一个简单.易读.易记的编程语言,可以用类似于英语的语法进行编写程序,可读性高,且能写出高性能 ...
- 《深度学习入门--基于python的理论与实现》——斋藤康毅读书笔记
<深度学习入门--基于python的理论与实现>读书笔记(第二章) 写在前面 第二章:感知机 2.1感知机是什么 2.2简单的逻辑电路 2.2.1与门(and gate) 2.2.2与非门 ...
- 学习笔记:深度学习(6)——基于深度学习的语言模型
学习时间:2022.04.22~2022.04.25 文章目录 5. 基于深度学习的语言模型 5.1 从NNLM到词嵌入 5.1.1 神经网络语言模型 NNLM 5.1.2 基于循环神经网络的语言模型 ...
- 深度学习入门 基于Python的理论与实现
作者:斋藤康毅 出版社:人民邮电出版社 品牌:iTuring 出版时间:2018-07-01 深度学习入门 基于Python的理论与实现
- 深度学习入门之PyTorch学习笔记:深度学习介绍
深度学习入门之PyTorch学习笔记:深度学习介绍 绪论 1 深度学习介绍 1.1 人工智能 1.2 数据挖掘.机器学习.深度学习 1.2.1 数据挖掘 1.2.2 机器学习 1.2.3 深度学习 第 ...
- 深度学习入门-基于Python的理论入门与实现源代码加mnist数据集下载推荐
深度学习入门-基于Python的理论入门与实现源代码加mnist数据集下载推荐 书籍封面 1-图灵网站下载 书里也说了,可以图灵网站下载https://www.ituring.com.cn/book/ ...
- 学习笔记:深度学习(3)——卷积神经网络(CNN)理论篇
学习时间:2022.04.10~2022.04.12 文章目录 3. 卷积神经网络CNN 3.1 卷积神经网络的概念 3.1.1 什么是CNN? 3.1.2 为什么要用CNN? 3.1.3 人类的视觉 ...
- 【长篇博文】Docker学习笔记与深度学习环境的搭建和部署(二)
长篇博文记录学习流程不容易,请关注.转发.点赞.评论,谢谢! 上一篇文章:Docker学习笔记与深度学习环境的搭建和部署(一) 文章末尾附加nvidia455.23.cuda11.1.cudnn8.0 ...
- ScalersTalk 机器学习小组第 21 周学习笔记(深度学习-10)
ScalersTalk 机器学习小组第 21 周学习笔记(深度学习-10) Scalers点评:机器学习小组是成长会的内部小组,这是成长会机器学习小组第21周学习笔记,也是深度学习第10次的复盘笔记 ...
最新文章
- 介绍并扩展Fitnesse的测试模块化机制:Scenario
- Linux命令CURL用法
- WiFi行业9大趋势解析
- php路径设置,php进行数据库路径设置的方法
- linux常用命令,知识在于总结
- 现代密码学2.1--完美安全和完美不可区分/Perfectly secret, Perfectly indistinguishable
- 【DFS】NYOJ-325-zb的生日
- 【100题】第三十二 数组、规划
- php url 2f,PHP2(url二次编码)
- 使用itext到处PDF,使用PDF模板导出PDF文件
- 【阅读分享】红楼梦第一回-甄士隐的故事
- 麒麟操作系统配置web服务器,银河麒麟服务器设置
- python roundup 和 rounddown
- js写的 几款时间轴
- nvidia jetson agx xavier运行 OpenCL
- GPU服务器的上手使用-小试牛刀
- 晶振串联电阻与并联电阻有什么作用?
- 微软azure DNS服务器,什么是 Azure 专用 DNS?
- icesword 是如何列出隐藏进程?
- 新能源造车的恒大创新样本