经典卷积神经网络的基本组成部分是下面的这个序列:
1.带填充以保持分辨率的卷积层;
2.非线性激活函数,如ReLU;
神经网络中的一个神经元接收多个输入,每个输入有对应的权值,与其相乘后相加起来经过激活函数得到神经元的输出。所以激活函数就是存在于上层节点的输出和下层节点的输入间。
激活函数也不是真的要去激活什么,而是把输入的参数(特征)在这个神经元上的表现保留并映射出来,即将神经元的输入映射到输出端。
需要激活函数是因为它可以加入非线性元素,线性组合训练出来的网络逼近能力有限,而非线性函数作为激活函数就可以逼近任何函数,得到更表达更准确的神经网络。
f(x)=max(0,x)
ReLu函数接收到负数则输出0,相当于神经元不被激活,收到正数则直接输出,这个称为单侧抑制,因为有许多不被激活的神经元,所以神经网络是稀疏的,这有利于计算效率也能更好挖掘数据特征来拟合训练数据。因为训练一个模型时,与目标相关的特征也只是部分,使用ReLu就不会让其他特征干扰到模型训练。
参考于ReLu函数
3.汇聚层,如最大汇聚层。
与AlexNet、LeNet一样,VGG网络可以分为两部分:第一部分主要由卷积层和汇聚层组成,第二部分由全连接层组成。如图中所示。
VGG神经网络连接图中的几个VGG块(在vgg_block函数中定义)。其中有超参数变量conv_arch。该变量指定了每个VGG块里卷积层个数和输出通道数。全连接模块则与AlexNet中的相同。
原始VGG网络有5个卷积块,其中前两个块各有一个卷积层,后三个块各包含两个卷积层。 第一个模块有64个输出通道,每个后续模块将输出通道数量翻倍,直到该数字达到512。由于该网络使用8个卷积层和3个全连接层,因此它通常被称为VGG-11。 来源
num_convs:卷积层的数量
num_channels:输出通道的数量
Conv2D() 创建2D卷积层
tf.keras.layers.Conv2D(
filters, # 卷积核个数
kernel_size, # 卷积核尺寸,正方形用一个数表示,长方形需指明长宽
strides=(1, 1), # 滑动步长,默认(1,1)
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)
)
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
该参数指定了每个块里卷积层个数和输出通道数,这个VGG网络包含8个卷积层和3个全连接层。
conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
定义了5个卷积块,前2个卷积块有各有1个卷积层,后面3个卷积块各有2个卷积层。
将输入层数据压成了一维数据,通常在卷积层和全连接层之间使用。(前者处理矩阵,后者处理向量)
全连接层相当于神经网络中的“特征提取器”, 卷积层、池化层和激活函数等操作是将原始数据映射到隐层特征空间的话,全连接层则起到将学到的特征表示映射到样本的标记空间的作用。引用自全连接层
全连接以人民代表大会的通俗解释 知乎
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)
参考7.2使用块的网络(VGG)