AlexNet的实现与应用
详解AlexNet,用TensorFlow实现该架构并用它来完成Kaggle上的Dogs Vs Cats竞赛。
总体架构
AlexNet的总体架构如下所示:
整个网络总共有八层,其中前五层为卷积层,后面三层为全连接层;
用了两个GPU(GTX 580,3G内存)进行训练,因此整个架构被平均分成了两部分,除了第二层与第三层是跨GPU进行连接,其他卷积层都只和各自的GPU内的前一层进行连接;
在第一、二个卷积层后进行现在并不常用的局部响应归一化(local response normalization,LRN),LRN的公式如下:
公式中的$k$、$n$、$\alpha$、$\beta$均为超参数,在验证集上实验得到$k = 2$、$n = 5$、$\alpha = 0.00001$、$\beta = 0.75$;
在LRN、第五层后面进行窗口大小和步幅不相等的最大池化,称为最大重叠池化;
批量大小为$128$,并使用ReLU作为激活函数,
用数据扩充和DropOut法来防止过拟合。
各层中的具体过程为:
- 输入的大小原为$224 \times 224 \times 3$,为方便后续处理将其调整为$227 \times 227 \times 3$;
- 第一层用$96$个大小为$11 \times 11$的卷积核进行步幅为$4$的卷积,之后用大小为$3\times3$的窗口进行步幅为$2$的最大重叠池化后,再进行尺度为$5\times5$的LRN;
- 第二层用$256$个大小为$5 \times 5$的卷积核进行步幅为$1$的卷积,之后和前一层一样进行重叠池化和LRN;
- 第三层用$384$个大小为$3 \times 3$的卷积核连接到第二层的所有输出;
- 第四、第五层分别用$384$、$256$个大小为$3 \times 3$的卷积核进行步幅为$1$的卷积,且在第五层后用大小为$3\times3$的窗口进行步幅为$2$的最大重叠池化。
- 第六层的输入大小为$6 \times 6 \times 256$,与$4096$个大小为$6 \times 6 \times 256$的卷积核进行卷积,就得到包含$4096$个节点的全连接层。训练时,需要在该全连接层进行一次drop_prob为$0.5$的Dropout。
- 第七层的$4096$个节点与上一个全连接层进行全连接,训练时,也需要在该全连接层进行一次drop_prob为$0.5$的Dropout。
- 第八层进行第三次全连接,并输出最后的结果。
TensorFlow实现
辅助方法
卷积:
1 | def conv(x, filter_height, filter_width, filters_num, stride_x, stride_y, name, padding='SAME', groups=1): # groups: 分成多个部分 |
池化、LRN、Dropout:
1 | def max_pool(x, filter_height, filter_width, stride_x, stride_y, name, padding='SAME'): |
用动态图测试上面的各方法:
1 | import tensorflow.contrib.eager as tfe |
整个模型
建立整个AlenNet:
1 | class AlexNetModel(object): |
模型测试
用原始的参数值来测试构建好的AlexNet模型,原始参数的文件可从这里下载。
1 | import matplotlib.pyplot as plt |
得到预测结果:
Dogs VS Cats
下载Kaggle上的Dogs vs. Cats Redux Competetion的数据集,考虑微调上面构建好的AlexNet来完成该竞赛。
解压其中的压缩包后,可以看到其中包含$25000$张带标签的训练数据:
和$15000$张不带标签的测试数据:
数据处理
首先将数据集划分一下,这里把$85%$的训练数据也就是$21250$张图片作为训练集,剩下的$4750$张图片作为验证集。
竞赛中要求将猫图的标签设为$0$,狗图的标签设为$1$。要使用这些数据来训练我们的模型,为了方便读取,可考虑获取所有的图片的路径和对应的标签,把它们统一放在一个txt文件中。实现该过程的程序如下:
1 | import os |
这样就能得到名为train.txt、validate.txt的两个文件,文件的内容如下:
前面是图片的数据路径,后面则是该图片对应的标签。
导入数据
用下面的辅助方法来调用tf.data.Dataset导入数据,并对数据进行一些简单的处理:
1 | # 数据处理 |
微调AlexNet,其中的卷积层仍采用原始参数,而使用现有的数据集来训练其中的全连接层。因此调用上面的方法导入数据,设置并初始化迭代器,并设置一些超参数如下:
1 | train_file = 'train.txt' |
建立并训练模型
建立AlexNet模型:
1 | model = AlexNetModel(num_classes=num_classes, skip_layer=train_layers) |
训练并保存模型:
1 | from datetime import datetime |
使用前面设置的超参数,本人的Colab上训练的结果如下:
精确度还不够高,可以尝试继续调整超参数。
测试模型
在测试集上测试训练好的模型:
1 | import os |
上传到kaggle上得到的成绩:
参考资料
- ImageNet classification with deep convolutional neural networks
- Finetuning AlexNet with TensorFlow
- AlexNet详细解读-CSDN
- finetune_alexnet_with_tensorflow-Github
- tensorflow-cnn-finetune-Github
更新历史:
- 2019.5.4 完成初稿
AlexNet的实现与应用