美文网首页
AlexNet在猫狗识别中的应用

AlexNet在猫狗识别中的应用

作者: Rethinkpossible | 来源:发表于2018-08-26 13:33 被阅读0次

        最近倒腾了许多CNN的实验,有人问这些实验大把大把啊,做完就算了,为什么要写总结。其实在我看来,我们做实验也只是不断复现大牛的网络,我们会花更长时间在调参、防止过拟合以及如何提高训练速度,甚至是落地问题。从这样的角度看,我们只要copy别人代码就完事,其中的细枝末节根本可以不用理会,这样会妨碍我们在人工智能领域能力的发展,甚至你的调参能力也仅限于某些数据集。因此作为不管是机器学习还是深度学习的工程师,都应该习惯写笔记,定期总结实验,用更加逻辑化的、通俗易懂的语言去表达,这样非常有助于我们研究能力的提升。

上图所示是刘昕博士总结的CNN结构演变的历史,一开始是神经认知机模型,此时已经出现了卷积结构,经典的LeNet诞生于1998年。然而之后CNN的锋芒开始被SVM等超越。随着ReLU和Dropout的提出,以及GPU和大数据带来的历史机遇,CNN在2012年迎来了历史突破———AlexNet。下图是自己对AlexNet的理解做的图,展示了一张3通道的227*227的图像如何经过各个隐含层的处理最终形成分类。绿色柱子的是指经过卷积层处理后的特征图(Feature Map),比如第一层卷积层深度为96,或者说有96个滤波器,又或者说输出通道为96,那么就会生成96个特征图,当然也可以认为该层有96个神经元。总的来说,深度=滤波器个数=输出通道数=神经元个数。蓝色柱子是指经过池化层处理后的特征图。蓝色条带是指经过全连接层处理后的特征向量。下面的小黑框是介绍VALID和SAME的两种padding方式下,生成新的特征图的宽度和高度的计算公式,strides[1]是指竖直移动的步进,strides[2]是指水平移动的步进。

    下面来说一下激活函数的选择。传统神经网络中最常用到的两个激活函数Sigmoid和Tanh,同时也被视为神经网络的核心所在。

从其数学图像可以看到,由于Sigmoid和Tanh激活函数左右两端在很大程度上接近极值,容易饱和,因此在进行计算时,传递的数值过小或者过大都会使得梯度接近于0,权重无法及时更新。为了克服Sigmoid和Tanh弊端,就有ReLU函数,

相较于Sigmoid和Tanh函数,ReLU主要有以下几个特点:

1、收敛快:对于SGD的收敛有巨大的加速作用,可以看到对于达到阈值的数据,其激活力度是随数值的加大而增大,且呈现一个线性关系。

2、计算简单

3、不易过拟合:使用ReLU进行模型计算时,一部分神经元在计算时如果有一个过大的梯度经过,则次神经元的梯度会被强行设置为0,而整个其后的训练过程中这个神经元都不会被激活,这会导致数据多样化的丢失,但是也能防止过拟合。

原理讲的差不多了,下面看看实验所遇到的一些问题。在此之前先看看TensorFlow的数据读取机制。假设硬盘中有一个图片数据集,只需要把它们读取到内存中,然后提供给GPU或者CPU进行计算即可。这听起来容易,但事实远没有这么简单。事实上,必须先读入数据后才能进行计算,假如读入用时0.1s,计算用时0.9s,那么即意味着每过1s,GPU都有0.1s无事可做,这大大降低了运算效率。解决方法就是将读入数据和计算分别放在两个线程中,这样就可以解决GPU因为I/O而空闲的问题。而在TensorFlow中,为了方便管理Epoch,在内存队列前又添加了一层“文件名队列”。该“文件名队列”可以按顺序排列,也可以乱序排列。下面是生成batch的函数,可以理解为一个generator。这里用tf.train.slice_input_producer函数生成一个文件名队列,接着是对图片的读取、图片解码(解码才能显示图像,否则只是字符串,无法显示)、选截图片大小,最后用tf.train.batch函数返回一个batch的样本和样本标签。

def  get_train_batch_data(self,img_width,img_height,capacity):

image = tf.cast(self.image_train_list, tf.string)

label = tf.cast(self.label_train_list, tf.int32)

input_queue = tf.train.slice_input_producer([image, label])

label = input_queue[1]

image_contents = tf.read_file(input_queue[0])

image = tf.image.decode_jpeg(image_contents, channels=3)

image = tf.image.resize_image_with_crop_or_pad(image,img_width,img_height)

self.image_train_batch,self.label_train_batch = tf.train.batch([image, label], batch_size=self.batch_size, \

num_threads=64,capacity=capacity)

self.label_train_batch = tf.reshape(self.label_train_batch, [self.batch_size])

在使用了tf.train.slice_input_producer(或者tf.train.string_input_producer)创建文件名队列后,整个系统其实还处于“停滞”状态,也就是说,文件名并没有真正被加入队列中,这样启动计算,系统会一直处于阻塞状态。所以我们需要在开启sesstion后,使用tf.train.start_queue_runners函数,才会启动填充队列的线程。

实验代码放在Github上,参考地址<1>。在参数上,我设置了200的batch_size,学习率为1e-4100个epoch,第一个全连接层长度为4096,第二个全连接层长度为2048;在每个epoch里迭代更新的次数 = 训练集长度(25000) / batch_size;在池化层都用了平均池化(tf.nn.avg_pool),没用到最大池化(tf.nn.max_pool)。下面是一些实验结果,包括损失函数以及预测精度,样本外的测试精度均值也才75.8%,并没有想象中这么棒。下回看看GoogLeNet在猫狗大战中的效果。

<1> https://github.com/DemonDamon/comparisons-among-various-deep-nets-in-dogs-vs-cats-dataset/blob/master/alexnet_dog_vs_cat.py

相关文章

网友评论

      本文标题:AlexNet在猫狗识别中的应用

      本文链接:https://www.haomeiwen.com/subject/dokoiftx.html