1.典型的神经网络
1)LeNet-5网络
图1 LeNet-5神经网络结构
Le-Net-5神经网络大概有60k个参数。其结构为conv->pool->conv->pool->fc->fc->output,因为关于这个模型的论文发表于1998年,那个时候人们还不使用填充,所以这里卷积层都没有填充值。nh,nw在逐步减小,而nc逐步增加。
2)AlexNet 网络
图2 AlexNet 网络
AlexNe与LeNet-5类似,但是大概有60m的参数远比LeNet-5大的多,因此更适合大的图片集。 并且其卷积层会用ReLU函数激活,并且Pool层都是MaxPool,有些地方卷积层用same进行填充。最后用softmax进行1000个类别的输出。
3)VGG-16 网络
图3 VGG-16 网络
VGG-16是一个比较结构化的网络,其中的16代表有16层卷积网络。看起来比较简单,可以看到过滤器数量变化为64-128-256-512,都是成倍增加,而尺寸是从224-112-56-28-14-7成倍减半。它是一个非常大的网络,整个网络参数有130m之多。
2.ResNet 残差网络
太深的网络训练起来很难,因为有梯度小时和爆炸这类问题。而跳跃连接(skip connection)它能够让你从一层中得到激活并突然把它传递给下一层,甚至更深的神经网络层利用它,你就可以训练网络层很深很深的残差网络(ResNet)。
1)残差块 图 4 残差块示意图
残差块就是把l层的激活函数a[l]加在[l+2]层上,且这个添加需要在l+2层的激活函数之前。所以l+2层的激活函数变为:
a[l+2]=g(z[l+2]+a[l])
2)残差网络
图6残差网络
如图,网络中使用多个残差块可以实现残差网络,可以解决当网络层数过多的时候,误差会随着层数增加而增加的问题。
3.为什么残差网络具有有效性?
上一节知道残差网络的网络块l+2层的激活函数如下
a[l+2]=g(z[l+2]+a[l]) 假设激活函数为ReLU函数因为z[l+2]=w[l+2]a[l+1]+b[l+2] 如果w[l+2]=0 b[l+2]=0 将会得到a[l+2]=a[l]这时候我们将会重新获得a[l]放弃了l+1层和l+2层的学习参数,这就意味着残差块容易学习到恒等函数。所以就算添加l+1层和l+2层对网络本身并没有太大影响。
但是如果a[l+2]层如果是与a[l]层维度不同,可以将一个新的矩阵ws乘以a[l]以适用a[l+2]层的大小。
4.1x1卷积网络
当卷积层的过滤器大小为1x1时。此时便是1x1的卷积网络。我们可以通过1x1的卷积网络来减小网络的通道数量。
5.Inception Network
图7 Inception Network
如图7所示便是inception网络。它将多种过滤器过滤同一个输出,并将最后得出的结果进行汇总。1x1x192 的64个过滤器,3x3x192的128个过滤器。5x5x192的32个过滤器。再使用一个特殊的MAX-POOL过滤器(该过滤器详细的逻辑作者并没有在此说清楚,这个将在下一节有讲到)。最后得到一个由各个过滤器计算后堆叠成的大小为28x28x256的输出。 作者提到inception网络的计算成本问题。计算inception 5x5卷积部分的花费28x28x32x5x5x192=120m的乘法运算,其运算量过大,后来作者提出利用另外一种1x1卷积运算能减少这个计算量,如图所示:
图8 一种优化的卷积方法
其中先做一次与1x1x192的16个过滤器进行卷积,再进行与5x5x16的32个过滤器卷积,此种方法最后计算成本为12.4m的乘法大约是直接卷积的1/10。
6. Inception Network详解
图8 Inception 网络模块
在上图详细介绍了每个inception网络模块的结构,可以看到之前未理解的MAXPOOL步骤是,先通过一个3x3步长为1 并且填充为same的一个最大池化层,得到一个与原输入一样尺寸的张量,再通过一个1x1x192过滤器数量为32的1x1卷积层,便得到28x28x32的最大池化结果。
将多个inception网络模块组合后将会组成一个inception网络模块。
7.MobileNets移动端网络
由于移动端计算机资源比较少,针对此特点,depthwise-separable(纵深可分) 卷积网络将会发挥得更好。
图9 depthwise-separable网络
如图所示,depthwise-separable网络先进行一次Depthwise 卷积,也就是输入的每个通道与过滤器对应位置的通道进行按层卷积(此时过滤器大小为f x f x nc,而不是之前的fx fx nc x filternumber)得到一个新的no x no x nc的张量。 再经过一次nf个1x1xnc过滤器卷积,得到的输出将是no x no x nf的一个输出。
经过吴老师验证,depthwise-separable的计算量将是普通卷积的网络的大约10分之1左右。
8. MobileNets v2移动端网络
图10 第二版移动网络
如图所示,第二版的移动网络先进行Expansion(扩张)操作,将通道数量扩张,再进行Depthwise操作,最后再进行Pointwise将通道数量缩小。
v2版本有两个优点,首先,扩张操作将通道数量增加,那么depthwise中过滤器中的参数会变多,这样会使得可以学习到更多内容,然后再经过pointwise将通道数量减少(此过程也称作projection), 这样又可以减少整个网络所占用的内存和计算量,因此v2版本比v1版本性能更优。
10.EfficientNet
在这里,因为输入图片的解析度不同,因此需要的网络深度d,网络的整体宽度高度w需要做调整以适用不同解析度的图片,为了解决更好适应图片解析度的网络,吴老师提出了一个EfficientNet网络,但是未详细解析,因此这部分需要在github上去了解。
11.Transfer Learning迁移学习
因为前人在神经网络上给出了许多模型,因此我们没必要对每个自己的应用都新创一个模型,并进行学习,如果我们计算资源比较有限这样的话会很困难,因此我们可以借用其他人的模型,进行完全搬移过来,只是将输出层替换成我们想要的输出结果,其中的参数也可以使用他们,因为一个大型的神经网络其参数一定也是非常通用的。如果我们有充足的计算机资源,我们也可以只使用他们的模型而用自己初始化的参数进行学习。我们也可以只使用他们的模型的一部分(进行freeze操作,将不做更改的层freeze)而自己再新创一些层来更好地适应我们的项目。
12.Data Augmentation数据增强
我们可以将原始图片进行位移,色偏,旋转,截取等操作将样本数量扩张,这样的方式可以很好地扩充样本数量来增加学习的样本数量。
一般来说,数据增强过程,会有一个线程专门对样本进行增强操作,然后将增强后的图片给到卷积网络的线程处理。
13.编程作业
作业一:
1)keras的Conv2D()卷积函数使用 :
X = Conv2D(filters = F1, kernel_size = 1, strides = (1,1), padding = 'valid', kernel_initializer = initializer(seed=0))(X)
2)为了优化训练速度,在进行卷积后进行BatchNorm步骤: X = BatchNormalization(axis = 3)(X, training = training
3)在ResNet中主路径与捷径相加的函数Add():
X =Add()([X,X_shortcut])
4)当捷径与主路径的输出不同时需要将捷径进行一次Conv2D操作以适应主路径的输出大小、
5)创建Model
model = Model(inputs = X_input, outputs = X)
6)打印model的每层情况和参数数量: model.summary()
7)连接model:
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
8)学习样本: model.fit(X_train, Y_train, epochs = 10, batch_size = 32) 9)获得预测test样本集的性能
preds = model.evaluate(X_test, Y_test)
作业二:
1)预处理,从硬盘中预处理图片共给网络使用。 AUTOTUNE = tf.data.experimental.AUTOTUNE
train_dataset = train_dataset.prefetch(buffer_size=AUTOTUNE) 2)数据增强,旋转和平移
RandomFlip('horizontal')
RandomRotation(0.2)
3) 借用MobileNetV2的模型:
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
include_top=True,
weights='imagenet') 4)应用并取消MobileNetV2最上层 base_model = tf.keras.applications.MobileNetV2(input_shape=input_shape,
include_top=False, # <== Important!!!!
weights='imagenet') # From imageNet 5)冻结模型使其不可训练 base_model.trainable = False
6)创造输入层
inputs = tf.keras.Input(shape=input_shape)
7)给输入提供数据增强
x = data_augmentation(inputs)
8)使用原本的权重来预处理模型
x = preprocess_input(x)
9)这个步骤不懂意思。
# set training to False to avoid keeping track of statistics in the batch norm layer
x = base_model(x, training=False)
10)全局池化
x = tf.keras.layers.GlobalAveragePooling2D()(x)
11)dropout防止过拟合
x = tf.keras.layers.Dropout(0.2)(x)
12)创建1个输出的全链接层
outputs = tf.keras.layers.Dense(1,activation = 'linear')(x)
13)可以通过在最后一层中重新运行优化器(optimizer)来尝试微调模型,以提高精度。当使用较小的学习速率时,采取更小的步骤来让它更接近新数据。
14)冻结指定层
for layer in base_model.layers[:fine_tune_at]:
layer.trainable = False
15)定义一个BinaryCrossentropy的损失函数:
loss_function=tf.keras.losses.BinaryCrossentropy(from_logits=True)
16)定义一个为Adam的优化器,并设置学习速率为0.1倍的base_learning_rate
optimizer = tf.keras.optimizers.Adam(lr=(0.1 * base_learning_rate))
17)设置评价标准为accuracy
metrics=['accuracy']