十、卷积神经网络

本文介绍了卷积神经网络(CNN)的基本原理和重要概念,包括全连接网络的问题、卷积运算、权值共享、卷积层的实现、Le-Net5实战、池化层、BatchNorm层以及经典卷积网络如AlexNet、VGG系列和GoogLeNet。此外,还探讨了空洞卷积、转置卷积、分离卷积、ResNet和DenseNet等卷积层变种,结合CIFAR10和CIFAR100的数据集进行了实战训练。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

十、卷积神经网络

内容参考来自https://github.com/dragen1860/Deep-Learning-with-TensorFlow-book开源书籍《TensorFlow2深度学习》,这只是我做的简单的学习笔记,方便以后复习。

1.全连接网络的问题

问题就是全连接网络的参数量太过庞大,超过了当时计算机的内存容量,无法存储全部的参数。

局部相关性:基于距离的重要性分布假设特性,它只关注和自己距离较近的部分节点,而忽略距离较远的节点。

从局部相关性引出了权值共享的概念,即对于每个输出节点 ,均使用相同的权值矩阵W。

卷积运算:

卷积的“卷”是指翻转平移操作,“积”是指积分运算。

2D 离散卷积运算流程:每次通过移动卷积核,并与图片对应位置处的感受野像素相乘累加,得到此位置的输出值。卷积核即是行、列为𝑙大小的权值矩阵W,应到特征图上大小为𝑙的窗口即为感受野,感受野与权值矩阵W相乘累加,得到此位置的输出值。通过权值共享,我们从左上方逐步向右、向下移动卷积核,提取每个位置上的像素特征,直至最右下方,完成卷积运算。

在这里插入图片描述

2.卷积神经网络

卷积神经网络通过充分利用局部相关性和权值共享的思想,大大地减少了网络的参数量,从而提高训练效率,更容易实现超大规模的深层网络。

2.1单通道输入和单卷积核

在这里插入图片描述

对应位置相乘再求和:-1-1+0-1+2+6+0-2+4=7

在这里插入图片描述

计算完成效果如图。

2.2多通道输入和单卷积核

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 多通道输入和多卷积核

在这里插入图片描述

2.4步长

感受野密度的控制手段一般是通过移动步长(Strides)实现的。步长是指感受野窗口每次移动的长度单位,对于 2D 输入来说,分为沿𝑦(向右)方向和𝑧(向下)方向的移动长度。如下图,步长为2

在这里插入图片描述

2.5填充

为了让输出𝑶的高宽能够与输入X的相等,一般通过在原输入X的高和宽维度上面进行填充(Padding)若干无效元素操作,得到增大的输入X′。通过精心设计填充单元的数量,在X′上面进行卷积运算得到输出𝑶的高宽可以和原输入X相等,甚至更大。

在这里插入图片描述
在这里插入图片描述

可以看到通过填充,输入和输出大小一致。
在这里插入图片描述
在这里插入图片描述

3.卷积层实现

3.1自定义权值

在 TensorFlow 中,通过 tf.nn.conv2d 函数可以方便地实现 2D 卷积运算。tf.nn.conv2d基于输入X:[b, h, w, c_in] 和卷积核W: [k, k, c_in, cout]进行卷积运算,得到输出𝑶 ℎ′ 𝑥′ 𝑐 𝑝𝑣𝑢 ,其中𝑐 𝑗𝑜 表示输入通道数,𝑐 𝑝𝑣𝑢 表示卷积核的数量,也是输出特征图的通道数。

x = tf.random.normal([2,5,5,3]) # 模拟输入,3 通道,高宽为 5
# 需要根据[k,k,cin,cout]格式创建 W 张量,4 个 3x3 大小卷积核
w = tf.random.normal([3,3,3,4])
# 步长为 1, padding 为 0,
out = tf.nn.conv2d(x,w,strides=1,padding=[[0,0],[0,0],[0,0],[0,0]])
out.shape  # TensorShape([2, 3, 3, 4])

上下左右各填充一个单位,则 padding 参数设置为[[0,0],[1,1],[1,1],[0,0]]

x = tf.random.normal([2,5,5,3]) # 模拟输入,3 通道,高宽为 5
# 需要根据[k,k,cin,cout]格式创建,4 个 3x3 大小卷积核
w = tf.random.normal([3,3,3,4])
# 步长为 1, padding 为 1,
out = tf.nn.conv2d(x,w,strides=1,padding=[[0,0],[1,1],[1,1],[0,0]])
out.shape # TensorShape([2, 5, 5, 4])

特别地,通过设置参数 padding=‘SAME’、strides=1 可以直接得到输入、输出同大小的卷积层,其中 padding 的具体数量由 TensorFlow 自动计算并完成填充操作。

x = tf.random.normal([2,5,5,3]) # 模拟输入,3 通道,高宽为 5
w = tf.random.normal([3,3,3,4]) # 4 个 3x3 大小的卷积核
# 步长为,padding 设置为输出、输入同大小
# 需要注意的是, padding=same 只有在 strides=1 时才是同大小
out = tf.nn.conv2d(x,w,strides=1,padding='SAME')
out.shape # TensorShape([2, 5, 5, 4])

当𝑠 > 时,设置 padding='SAME’将使得输出高、宽将成 1/s 倍地减少

x = tf.random.normal([2,5,5,3])
w = tf.random.normal([3,3,3,4])
# 高宽先 padding 成可以整除 3 的最小整数 6,然后 6 按 3 倍减少,得到 2x2
out = tf.nn.conv2d(x,w,strides=3,padding='SAME')
out.shape # TensorShape([2, 2, 2, 4])

卷积神经网络层与全连接层一样,可以设置网络带偏置向量。tf.nn.conv2d 函数是没有实现偏置向量计算的,添加偏置只需要手动累加偏置张量即可。

# 根据[cout]格式创建偏置向量
b = tf.zeros([4])
# 在卷积输出上叠加偏置向量,它会自动 broadcasting 为[b,h',w',cout]
out = out + b

3.2卷积层类

在新建卷积层类时,只需要指定卷积核数量参数 filters,卷积核大小 kernel_size,步长strides,填充 padding 等即可。如下创建了 4 个3 × 3大小的卷积核的卷积层,步长为 1,padding 方案为’SAME’

layer = layers.Conv2D(4,kernel_size=3,strides=1,padding='SAME')
# layer = layers.Conv2D(4,kernel_size=(3,4),strides=(2,1),padding='SAME')

x = tf.random.normal([2,5,5,3]) # 模拟输入,3 通道,高宽为 5
layer = layers.Conv2D(4,kernel_size=3,strides=1,padding='SAME')
out = layer(x) # 前向计算
out.shape # 输出张量的 shape   TensorShape([2, 5, 5, 4])

# 返回所有待优化张量列表
layer.trainable_variables

4.Le-Net5实战

1990 年代,Yann LeCun 等人提出了用于手写数字和机器打印字符图片识别的神经网络,被命名为 LeNet-5。LeNet-5 的提出,使得卷积神经网络在当时能够成功被商用,广泛应用在邮政编码、支票号码识别等任务中。

在这里插入图片描述

我们在 LeNet-5 的基础上进行了少许调整,使得它更容易在现代深度学习框架上实现。首先我们将输入𝒀形状由32 × 32调整为28 × 28,然后将 2 个下采样层实现为最大池化层(降低特征图的高、宽,后续会介绍),最后利用全连接层替换掉 Gaussian connections层。下文统一称修改的网络也为 LeNet-5 网络。

在这里插入图片描述

import tensorflow as tf
from tensorflow.keras import layers, optimizers, datasets, Sequential, losses
from matplotlib import pyplot as plt
import matplotlib

# Default parameters for plots
matplotlib.rcParams['font.size'] = 20
matplotlib.rcParams['figure.titlesize'] = 20
matplotlib.rcParams['figure.figsize'] = [9, 7]
matplotlib.rcParams['font.family'] = ['STKaiTi']
matplotlib.rcParams['axes.unicode_minus'] = False

network = Sequential([  # 网络容器
    layers.Conv2D(6, kernel_size=3, strides=1),  # 第一个卷积层, 6 个 3x3 卷积核
    layers.MaxPooling2D(pool_size=2, strides=2),  # 高宽各减半的池化层
    layers.ReLU(),  # 激活函数
    layers.Conv2D(16, kernel_size=3, strides=1),  # 第二个卷积层, 16 个 3x3 卷积核
    layers.MaxPooling2D(pool_size=2, strides=2),  # 高宽各减半的池化层
    layers.ReLU(),  # 激活函数
    layers.Flatten(),  # 打平层,方便全连接层处理
    layers.Dense(120, activation='relu'),  # 全连接层,120 个节点
    layers.Dense(84, activation='relu'),  # 全连接层,84 节点
    layers.Dense(10)  # 全连接层,10 个节点
])


def preprocess(x, y):
    # [0~1]
    x = 2 * tf.cast(x, dtype=tf.float32) / 255. - 1
    y = tf.cast(y, dtype=tf.int32)
    return x, y


(x, y), (x_test, y_test) = datasets.mnist.load_data()
print(x.shape, y.shape, x_test.shape, y_test.shape)

train_db = tf.data.Dataset.from_tensor_slices((x, y))
train_db = train_db.shuffle(1000).map(preprocess).batch(128)

test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_db = test_db.map(preprocess).batch(64)

sample = next(iter(train_db))
print(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coder_jyz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值