10.1 全连接层网络的问题
所需的参数多,耗内存
10.3 卷积层的实现
在 TensorFlow 中,既可以通过自定义权值的底层实现方式搭建神经网络,也可以直接调用现成的卷积层类的高层方式快速搭建
10.3.1 自定义权值
tf.nn.conv2d 函数可以方便地实现 2D 卷积运算。
输入X:
卷积核W:
得到输出O:
x = tf.random.normal([2,5,5,3])
# 创建3通道的 2 x 5 x 5的 张量
w = tf.random.normal([3,3,3,4])
# 创建 4 通道的, 3 x 3 的卷积核大小的kernel
out = tf.nn.conv2d(x, w, strides=1, padding=[[0,0],[0,0],[0,0],[0,0]])
其中 padding 参数的设置格式为:
padding = [[0,0],[上,下],[左,右],[0,0]]
# 上: 是指在上面填充一个单位,其余同理
特别地,通过设置参数 padding = ‘SAME',strides = 1 可以直接得到输入,输出同大小的卷积层,其中 padding 的具体数量由 TensorFlow 自动计算并完成填充操作:
(tf.nn.conv2d 函数是没有实现偏置向量计算的,添加偏置只需要手动累加偏置张量即可:)
x = tf.random.normal([2,5,5,3])
w = tf.random.normal([3,3,3,4])
out = tf.nn.conv2d(x, w, strides=3,
padding='SAME')
b = tf.zeros([4])
out = out + b
10.3.2 卷积层类
通过卷积层类 layers.Conv2D 可以不需要手动定义卷积核 W 和 偏置 b 张量,直接调用类实例即可完成卷积层的前向计算,实现更加高层和快捷。
在 TensorFlow 中,API 的命名有一定的规律,首字母大写的对象一般表示类,全部小写的一般表示函数。
layer = layers.Conv2D(4, kernel_size = 3, strides = 1, padding='SAME')
out = layer(x)
10.4 LeNet-5
对其中细节不赘述,可以参考之前的文章,
传送门如下:
https://www.jianshu.com/p/5c427e9fa79b
10.9 经典卷积网络
10.9.1 AlexNet
AlexNet 创新点传送门:
https://www.jianshu.com/p/526d3ab08098
10.9.2 VGG 系列
VGG 系列创新点10.9.3 GoogLeNet
传送们:
https://www.jianshu.com/p/9162369c653d
10.10 CIFAR 10 与 VGG 13 实战
conv_layers = Sequential([
layers.Conv2D(64, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.Conv2D(64, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.MaxPool2D(pool_size = [2, 2], strides = 2, padding = 'same'),
layers.Conv2D(128, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.Conv2D(128, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.MaxPool2D(pool_size = [2, 2], strides = 2, padding = "same"),
layers.Conv2D(256, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.Conv2D(256, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.MaxPool2D(pool_size = [2, 2], strides = 2, padding = "same"),
layers.Conv2D(512, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.Conv2D(512, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.MaxPool2D(pool_size = [2, 2], strides = 2, padding = "same"),
layers.Conv2D(512, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.Conv2D(512, kernel_size = [3, 3], padding = "same", activation = tf.nn.relu),
layers.MaxPool2D(pool_size = [2, 2], strides = 2, padding = "same")
])
fc_net = Sequential([
layers.Dense(256, activation = tf.nn.relu),
layers.Dense(128, activation = tf.nn.relu),
layers.Dense(10, activation = None)
])
10.11 卷积层变种
10.11.3 分离卷积
普通卷积在对多通道输入进行运算时,卷积核的每个通道与输入的每个通道分别进行卷积运算,得到多通道的特征图,再对应元素相加产生单个卷积核的最终输出。
分离卷积的计算流程则不同,卷积核的每个通道与输入的每个通道进行卷积运算,得到多个通道的中间特征,然后这个多通道的中间特征张量接下来进行多个 1 x 1 卷积核的普通卷积运算,得到多个高度不变的输出,这些输出在通道轴上面进行拼接,产生最终的分离卷积层的输出。
分离卷积层包含了两步卷积运算,第一步卷积运算是单个卷积核,第二个卷积运算包含了多个 1 x 1 卷积核。
上图如果采用 4 个 卷积核的话,所需的参数是 3 x 3 x 3 x 4 = 108,
深度可分离卷积如果使用分类卷积的话,先用一个 3 x 3 的卷积,后面在分别用 4 个 1 x 1 的卷积,能得到和普通卷积核同样规模的输出,但是所需的参数为 3 x 3 x 3 x 1 + 1 x 1 x 3 x 4 = 39。
可以看出分离卷积的一个明显优势在于,同样的输入和输出,采用深度可分离卷积的参数量约是普通卷积大小的。
10.12 深度残差网络
研究人员发现网络的层数越深,越有可能获得更好的泛化能力。但是当模型加深以后,网络变得越来越难以训练(主要是因为梯度弥散现象--传递的过程中会出现梯度接近于0的现象)。
通过在输入和输出之间添加一条直接连接的 Skip Connection 可以让神经网络具有回退的能力,当深层神经网络可以轻松地回退到浅层神经网络时,深层神经网络可以获得与浅层神经网络相当的模型性能,而不至于更糟糕。
10.12.1 ResNet 原理
ResNet 通过在卷积层的输入和输出之间添加 Skip Connection 实现层数回退机制,如下图所示:
残差模块
听过两个卷积的特征变换后的输出,与输入进行对应元素的相加运算,得到最终输出:
其中,叫做残差模块。由于被 Skip Connection 包围的卷积神经网络需要学习映射 ,因此叫做残差网络。
因为有相加运算,所以必须保证输入的形状和一致。
当不一致时,需要在 Skip Connection 上添加额外的卷积运算环节将输入变换到与相同的形状。
10.13 DenseNet
由于 Skip Connection 在 ResNet 上面获得了巨大的成功,研究人员开始尝试不同的 Skip Connection 方案,其中比较流行的就是 DenseNet。
DenseNet 将前面所有层的特征图信息通过 Skip Connection 与当前层输出进行了聚合,与 ResNet 的对应位置相加不同,DenseNet 采用在通道轴 c 维度进行拼接操作,聚合特征信息。
DenseNet参考资料:https://github.com/dragen1860/Deep-Learning-with-TensorFlow-book
网友评论