【动手学深度学习】使用块的网络(VGG)

经典卷积神经网络VGG

    • 介绍
        • 激活函数
          • ReLu函数
    • 实现VGG-11
        • tf.keras.layers.Conv2D ( )
        • f.keras.layers.MaxPool2D ( )
      • 定义块
      • 卷积层部分
      • 全连接层
        • tf.keras.layers.Flatten()
        • tf.keras.layers.Dense()
      • 查看每个层输出的形状
      • 构建通道数较少的网络
      • 定义学习率、轮次和批大小
      • 训练
      • 结果

介绍

经典卷积神经网络的基本组成部分是下面的这个序列:

1.带填充以保持分辨率的卷积层;

2.非线性激活函数,如ReLU;


激活函数

神经网络中的一个神经元接收多个输入,每个输入有对应的权值,与其相乘后相加起来经过激活函数得到神经元的输出。所以激活函数就是存在于上层节点的输出和下层节点的输入间。

激活函数也不是真的要去激活什么,而是把输入的参数(特征)在这个神经元上的表现保留并映射出来,即将神经元的输入映射到输出端。

需要激活函数是因为它可以加入非线性元素,线性组合训练出来的网络逼近能力有限,而非线性函数作为激活函数就可以逼近任何函数,得到更表达更准确的神经网络。

ReLu函数

f(x)=max(0,x)

ReLu函数接收到负数则输出0,相当于神经元不被激活,收到正数则直接输出,这个称为单侧抑制,因为有许多不被激活的神经元,所以神经网络是稀疏的,这有利于计算效率也能更好挖掘数据特征来拟合训练数据。因为训练一个模型时,与目标相关的特征也只是部分,使用ReLu就不会让其他特征干扰到模型训练。

参考于ReLu函数


3.汇聚层,如最大汇聚层。

与AlexNet、LeNet一样,VGG网络可以分为两部分:第一部分主要由卷积层和汇聚层组成,第二部分由全连接层组成。如图中所示。

【动手学深度学习】使用块的网络(VGG)_第1张图片

VGG神经网络连接图中的几个VGG块(在vgg_block函数中定义)。其中有超参数变量conv_arch。该变量指定了每个VGG块里卷积层个数和输出通道数。全连接模块则与AlexNet中的相同。

原始VGG网络有5个卷积块,其中前两个块各有一个卷积层,后三个块各包含两个卷积层。 第一个模块有64个输出通道,每个后续模块将输出通道数量翻倍,直到该数字达到512。由于该网络使用8个卷积层和3个全连接层,因此它通常被称为VGG-11。 来源


实现VGG-11


  • 定义vgg块

num_convs:卷积层的数量
num_channels:输出通道的数量

tf.keras.layers.Conv2D ( )

Conv2D() 创建2D卷积层

tf.keras.layers.Conv2D(
    filters,  # 卷积核个数
    kernel_size, # 卷积核尺寸,正方形用一个数表示,长方形需指明长宽
    strides=(1, 1),  # 滑动步长,默认(11)
    padding='valid',  # 补0策略。“valid”代表只进行有效的卷积,即对边界数据不处理。“same”代表保留边界处的卷积结果,通常会导致输出shape与输入shape相同。
    data_format=None, # channels_last为(batch,height,width,channels),channels_first为(batch,channels,height,width).
    dilation_rate=(1, 1),  # 卷积核的膨胀系数(将卷积核进行形状膨胀,新的位置用0填充)
    activation=None # 激活函数,如果不指定该参数,将不会使用任何激活函数(即使用线性激活函数:a(x)=x)
)

f.keras.layers.MaxPool2D ( )

MaxPool2D ( )完成最大池化操作

tf.keras.layers.Max2D(
pool_size=(2, 2), # 在2*2的窗口中取最大值,如果只有一个数,那么两个维度都是这个数
strides=None, # 滑动池化窗口,没有的默认值为pool_size
padding='valid', # 'valid'无填充,'same'导致输入的周围均匀填充,输入和输出具有相同的高度和尺寸
data_format=None # 和卷积层一样
)

定义块

def vgg_block(num_convs, num_channels):
    blk = tf.keras.models.Sequential()
    for _ in range(num_convs):
        blk.add(tf.keras.layers.Conv2D(num_channels,kernel_size=3,
                                    padding='same',activation='relu'))
    blk.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2))
    return blk

  • 定义超参数变量conv_arch

该参数指定了每个块里卷积层个数和输出通道数,这个VGG网络包含8个卷积层和3个全连接层。

conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))

  • 定义vgg网络

卷积层部分

定义了5个卷积块,前2个卷积块有各有1个卷积层,后面3个卷积块各有2个卷积层。

全连接层

tf.keras.layers.Flatten()

将输入层数据压成了一维数据,通常在卷积层和全连接层之间使用。(前者处理矩阵,后者处理向量)

tf.keras.layers.Dense()

全连接层相当于神经网络中的“特征提取器”, 卷积层、池化层和激活函数等操作是将原始数据映射到隐层特征空间的话,全连接层则起到将学到的特征表示映射到样本的标记空间的作用。引用自全连接层

全连接以人民代表大会的通俗解释 知乎


tf.keras.layers.Dense(
    units,                                 # 正整数,输出空间的维数
    activation=None,                       # 激活函数,不指定则没有
    use_bias=True,						   # 布尔值,是否使用偏移向量
    kernel_initializer='glorot_uniform',   # 核权重矩阵的初始值设定项
    bias_initializer='zeros',              # 偏差向量的初始值设定项
    kernel_regularizer=None,               # 正则化函数应用于核权矩阵
    bias_regularizer=None,                 # 应用于偏差向量的正则化函数
    activity_regularizer=None,             # Regularizer function applied to the output of the layer (its "activation")
    kernel_constraint=None,                # Constraint function applied to the kernel weights matrix.
    bias_constraint=None, **kwargs         # Constraint function applied to the bias vector
)

代码部分:
def vgg(conv_arch):
    net = tf.keras.models.Sequential()
    # 卷积层部分
    for (num_convs, num_channels) in conv_arch:
        net.add(vgg_block(num_convs, num_channels))
    # 全连接层部分
    net.add(tf.keras.models.Sequential([
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(1024, activation='relu'),
        tf.keras.layers.Dropout(0.5),
        tf.keras.layers.Dense(1024, activation='relu'),
        tf.keras.layers.Dropout(0.5),
        tf.keras.layers.Dense(10)]))
    return net


查看每个层输出的形状

构建一个高度和宽度为128的单通道数据样本,以观察每个层输出的形状

net = vgg(conv_arch)
X = tf.random.uniform((1, 128, 128, 1))
for blk in net.layers:
    X = blk(X)
    print(blk.__class__.__name__,'output shape:\t', X.shape)
Sequential output shape:	 (1, 64, 64, 64)
Sequential output shape:	 (1, 32, 32, 128)
Sequential output shape:	 (1, 16, 16, 256)
Sequential output shape:	 (1, 8, 8, 512)
Sequential output shape:	 (1, 4, 4, 512)
Sequential output shape:	 (1, 10)

可以发现每个块的高度和宽度减半,这是因为网络使用了3X3的卷积核、填充为1(保持宽度和高度)的卷积层和带有2x2的汇聚窗口、步幅为2每个块后分辨率减半)的最大汇聚层。


构建通道数较少的网络

ratio = 4
small_conv_arch = [(pair[0], pair[1] // ratio) for pair in conv_arch]
# 回想一下,这必须是一个将被放入“d2l.train_ch6()”的函数,为了利用我们现有的CPU/GPU设备,这样模型构建/编译需要在strategy.scope()中
net = lambda: vgg(small_conv_arch)

此时的形状

Sequential output shape:	 (1, 64, 64, 16)
Sequential output shape:	 (1, 32, 32, 32)
Sequential output shape:	 (1, 16, 16, 64)
Sequential output shape:	 (1, 8, 8, 128)
Sequential output shape:	 (1, 4, 4, 128)
Sequential output shape:	 (1, 10)

定义学习率、轮次和批大小

lr, num_epochs, batch_size = 0.05, 10, 64

训练

net2=d2l.train_ch6(net, train_iter, test_iter, 48, lr, d2l.try_gpu()) #这里的轮次改成了48

这个train_ch6是在d2l中定义好的训练函数,其中包含了一个可视化的训练进展的回调TrainCallback(tf.keras.callbacks.Callback)
6.6卷积神经网络(LeNet)


结果

【动手学深度学习】使用块的网络(VGG)_第2张图片


参考7.2使用块的网络(VGG)

你可能感兴趣的:(深度学习,网络,神经网络)