前言
在图像分类中,CNN对静态图像的分类效果是十分好的,但是,在对于时序性的图像上CNN显得有些无能为力不能将其时序联系起来以此进行分类,下面的论文实现一种CNN+LSTM的LRCN网络,先用CNN提取到特征在使用LSTM联系时序性最后加上全连接网络实现对有时序性的图像进行分类。
原作者采用的是caffe来实现的LRCN,这里我们采用keras来实现LRCN网络。在keras里实现CNN+LSTM的话有很多种方法,如下讨论:
这位小哥想把2D的卷积网络接上LSTM网络上以此来对手写数字数据集mnist进行识别。他也查阅了很多方法,比如:他自己尝试改变CNN输出的形状来接上LSTM,但很明显出错了。
还有,使用keras官方提供的Timedistributed层来处理CNN后连接LSTM层
再有,有人另辟蹊径自己添加了额外的层来连接CNN和LSTM
最后,小哥发出了肺腑之言:为什么这么复杂呀!能不能来个简单的办法
在回答中,答主建议使用keras提供的Timedistributed层,使你的CNN也拥有时间步,这样你就可以连接起你的CNN和 LSTM了。
本文也将采用这种方法来实现CNN+LSTM,下面是官方对Timedistributed层的介绍:
这里所说的下标为1是因为在实际网络运行过程中第0维是你的样本数目,也就是说你在你的程序中写的是(时间步,图像长,图像宽,颜色通道数),但实际网络自己运行的时候是(样本数,时间步,图像长,图像宽,颜色通道数)所以时间步就变成了第1维。
关于Timedistributed层在github上有过充分的讨论:
链接:https://github.com/keras-team/keras/issues/129和https://github.com/keras-team/keras/issues/4172
还有https://github.com/keras-team/keras/issues/1029
并且fchollet 本人也做出了解释:
数据处理
采用行为识别公开数据集UCF101,样例:
先使用OpenCV库对视频进行提取帧处理,实现每秒截取一张图片,生成一系列具有时间序列的图片,程序如下:
程序中的路径以及图片大小、插值方式、读取路径、保存路径根据自己的需求进行修改即可,生成后的图片样式为:
每五秒为一个动作,也即时间步是5。
然后需要将数据读取到网络中,由于时间步的存在这里的5张图片也就相当于只用CNN进行识别的一张图片,所以要将图片处理成(样本数,时间维,图像长,图像宽,颜色通道数),如果有1000张图片的话,时间步是5那么这里读入的样本数就是200,时间步就是5,我们前期处理的图像大小是227*227的,颜色通道是3维,数据读取程序:
这里for循环里实现的是每读取5张图就将其放入frames列表中并将其转为array数组添加到总的数组X_tr中,值得注意的是,在读取图像的时候要使用到sorted函数,目的是顺序的读入图像。
数据读取完成后开始制作标签:
num_smples是你总的图片数除以你的时间步,这里我们实现三分类所以标签一共有三类0,1,2。
将标签转换为one_hot形式并读入
网络结构
可以看到,这里第一层的输入是(5,227,227,3),其他的卷积层可以自己进行适当修改。
设置一些超参数和监视值之类的,就可以开始训练了
训练结果
可以看出来在大概一百多次epoch时val_acc不断升上,但是,train_acc仍然不断下降,基本可以判定此时开始已经开始了过拟合现象。
测试
使用训练保存的最好的模型来进行测试的结果显示,每类的准确率都在84%以上。
领取专属 10元无门槛券
私享最新 技术干货