文档

分类使用深度学习视频

这个例子展示了如何创建一个网络视频分类结合pretrained图像分类模型和一个LSTM网络。

创建一个深度学习网络视频分类:

  1. 转换视频序列的特征向量使用pretrained卷积神经网络,如GoogLeNet,从每一帧中提取特征。

  2. 火车一个LSTM网络在视频序列来预测标签。

  3. 组装一个网络,直接将视频通过结合网络层。

下图说明了网络体系结构。

  • 向网络输入图像序列,使用序列输入层。

  • 利用卷积层提取特征,也就是说,应用卷积操作独立视频的每一帧,使用序列折叠层卷积层紧随其后。

  • 恢复序列结构和重塑输出向量序列,使用序列展开层和一个平层。

  • 分类结果向量序列,包括LSTM层输出层紧随其后。

负载Pretrained卷积网络

帧的视频转换成特征向量,利用pretrained网络的激活。

加载一个pretrained GoogLeNet模型使用googlenet函数。这个函数需要深度学习工具箱™模型GoogLeNet网络万博1manbetx支持包。如果这种支持包没万博1manbetx有安装,那么函数提供一个下载链接。

netCNN = googlenet;

加载数据

下载HBMD51数据集HMDB:一个巨大的人类运动数据库RAR文件提取到一个文件夹命名“hmdb51_org”。数据集包含了约7000年的2 GB的视频数据片段51类,如“喝”,“运行”,“shake_hands”

提取的RAR文件后,使用支持功能万博1manbetxhmdb51Files获取文件名称和标签的视频。

dataFolder =“hmdb51_org”;(文件、标签)= hmdb51Files (dataFolder);

阅读第一个视频使用readVideohelper函数,在这个例子中,定义并查看视频的大小。这个视频是一个H——- - - - - -W——- - - - - -C——- - - - - -年代数组,H,W,C,年代高度,宽度,渠道,和视频的帧数。

idx = 1;文件名=文件(idx);视频= readVideo(文件名);大小(视频)
ans =1×4240 320 409

查看相应的标签。

标签(idx)
ans =分类brush_hair

查看视频,使用implay函数(需要图像处理工具箱™)。这个函数将数据范围[0,1],所以首先必须的数据除以255。或者,您可以遍历各个框架和使用imshow函数。

numFrames =大小(视频、4);图i = 1: numFrames帧=视频(::,:,我);imshow(帧/ 255);drawnow结束

帧转换为特征向量

利用卷积网络特征提取器的输入视频帧到网络时激活。将视频序列的特征向量,特征向量的输出激活函数的最后池层GoogLeNet网络(“pool5-7x7_s1”)。

这个图表说明了通过网络数据流。

读取视频数据和调整它来匹配输入的大小GoogLeNet网络使用readVideocenterCrop辅助函数,定义在这个例子。这一步需要花很长时间。转换后的视频序列,保存在MAT-file序列tempdir文件夹中。如果垫文件已经存在,然后从MAT-file加载序列没有改造。

inputSize = netCNN.Layers (1) .InputSize (1:2);layerName =“pool5-7x7_s1”;tempFile = fullfile (tempdir,“hmdb51_org.mat”);如果存在(tempFile“文件”)负载(tempFile“序列”)其他的numFiles =元素个数(文件);序列=细胞(numFiles, 1);i = 1: numFiles流(“阅读文件% d % d…\ n”,我,numFiles)视频= readVideo(文件(i));视频= centerCrop(视频、inputSize);序列{我1}=激活(layerName netCNN、视频,“OutputAs”,“列”);结束保存(tempFile,“序列”,“-v7.3”);结束

视图的大小头几个序列。每个序列都是一个D——- - - - - -年代数组,D是功能的数量(池层的输出大小)和年代是视频的帧数。

序列(1:10)
ans =10×1单元阵列{1024×409单}{1024×395单}{1024×323单}{1024×246单}{1024×159单}{1024×137单}{1024×359单}{1024×191单}{1024×439单}{1024×528单}

准备训练数据

准备培训的数据分区的数据为训练和验证的分区和删除任何长序列。

创建分区训练和验证

分区的数据。90%的数据分配给培训验证分区分区和10%。

numObservations =元素个数(序列);idx = randperm (numObservations);地板(N = 0.9 * numObservations);idxTrain = idx (1: N);sequencesTrain =序列(idxTrain);labelsTrain =标签(idxTrain);idxValidation = idx (N + 1:结束);sequencesValidation =序列(idxValidation);labelsValidation =标签(idxValidation);

删除长序列

序列中比典型的长序列的网络可以在训练中引入大量填充过程。填充太多负面影响分类精度。

得到的序列长度的训练数据和可视化在训练数据的直方图。

numObservationsTrain =元素个数(sequencesTrain);numObservationsTrain sequenceLengths = 0 (1);i = 1: numObservationsTrain = sequencesTrain序列{};sequenceLengths (i) =(序列,2)大小;结束图直方图(sequenceLengths)标题(“序列长度”)包含(“序列长度”)ylabel (“频率”)

只有几个序列有超过400的时间步骤。提高分类精度,删除超过400时间步的训练序列及其对应的标签。

最大长度= 400;idx = sequenceLengths >最大长度;sequencesTrain (idx) = [];labelsTrain (idx) = [];

创建LSTM网络

接下来,创建一个LSTM网络可以表示视频序列的特征向量进行分类。

定义LSTM网络体系结构。指定以下网络层。

  • 序列输入层的大小对应于特征维的特征向量

  • BiLSTM层与2000隐藏单位辍学层之后。输出只有一个标签为每个序列通过设置“OutputMode”选择BiLSTM层“最后一次”

  • 完全连接层和一个输出尺寸对应类的数量,softmax层和一层分类。

numFeatures =大小(sequencesTrain {1}, 1);numClasses =元素个数(类别(labelsTrain));层= [sequenceInputLayer numFeatures,“名字”,“序列”)bilstmLayer (2000,“OutputMode”,“最后一次”,“名字”,“bilstm”)dropoutLayer (0.5,“名字”,“下降”)fullyConnectedLayer (numClasses“名字”,“俱乐部”)softmaxLayer (“名字”,“softmax”)classificationLayer (“名字”,“分类”));

指定培训选项

使用指定的培训选项trainingOptions函数。

  • 设置一个mini-batch尺寸16,0.0001的初始学习速率,梯度阈值的2(防止梯度爆炸)。

  • 截断在每个mini-batch序列有相同的长度最短的序列。

  • 混乱的数据每一时代。

  • 验证每个时代网络一次。

  • 显示在一块训练进展和抑制详细输出。

miniBatchSize = 16;numObservations =元素个数(sequencesTrain);numIterationsPerEpoch =地板(numObservations / miniBatchSize);选择= trainingOptions (“亚当”,“MiniBatchSize”miniBatchSize,“InitialLearnRate”1的军医,“GradientThreshold”2,“洗牌”,“every-epoch”,“ValidationData”{sequencesValidation, labelsValidation},“ValidationFrequency”numIterationsPerEpoch,“阴谋”,“训练进步”,“详细”、假);

火车LSTM网络

列车网络使用trainNetwork函数。这可能需要很长时间才能运行。

[netLSTM,信息]= trainNetwork (sequencesTrain、labelsTrain层,选择);

计算网络的分类精度验证设置。使用相同的培训mini-batch大小选项。

YPred =分类(netLSTM sequencesValidation,“MiniBatchSize”,miniBatchSize);YValidation = labelsValidation;精度=意味着(YPred = = YValidation)
精度= 0.6647

组装视频分类网络

直接创建一个分类的网络视频,网络组装使用创建的网络层。使用层从卷积网络将视频转换成向量序列和层次从LSTM网络分类向量序列。

下图说明了网络体系结构。

  • 向网络输入图像序列,使用序列输入层。

  • 利用卷积层提取特征,也就是说,应用卷积操作独立视频的每一帧,使用序列折叠层卷积层紧随其后。

  • 恢复序列结构和重塑输出向量序列,使用序列展开层和一个平层。

  • 分类结果向量序列,包括LSTM层输出层紧随其后。

添加回旋的层

首先,创建一个层GoogLeNet网络的图。

cnnLayers = layerGraph (netCNN);

删除输入层(“数据”)和层后池层用于激活(“pool5-drop_7x7_s1”,“loss3-classifier”,“概率”,“输出”)。

layerNames = [“数据”“pool5-drop_7x7_s1”“loss3-classifier”“概率”“输出”];cnnLayers = removeLayers (cnnLayers layerNames);

添加顺序输入层

创建一个序列输入层,接受图像序列包含的图像大小相同的输入GoogLeNet网络。规范化的图像使用相同的平均形象GoogLeNet网络设置“归一化”选择的顺序输入层“zerocenter”“的意思是”选择平均GoogLeNet的输入层的形象。

inputSize = netCNN.Layers (1) .InputSize (1:2);averageImage = netCNN.Layers (1) .AverageImage;inputLayer = sequenceInputLayer (inputSize [3],“归一化”,“zerocenter”,“的意思是”averageImage,“名字”,“输入”);

添加序列输入层到层图。应用卷积层独立的图像序列,去除图像序列的序列结构,包括一个序列折叠层之间的序列输入层和卷积层。的输出序列折叠层连接到输入的第一个回旋的层(“conv1-7x7_s2”)。

层= [inputLayer sequenceFoldingLayer (“名字”,“折”));lgraph = addLayers (cnnLayers层);lgraph = connectLayers (lgraph,“折/”,“conv1-7x7_s2”);

添加LSTM层

LSTM层添加到层图通过移除序列LSTM网络的输入层。恢复序列结构被序列折叠层,包括序列卷积后展开层层。LSTM层期望向量序列。重塑的输出序列展开层向量序列,包括平层后序列展开层。

从LSTM网络层和删除序列输入层。

lstmLayers = netLSTM.Layers;lstmLayers (1) = [];

添加序列折叠层、平层和LSTM层到层图。连接最后卷积层(“pool5-7x7_s1”)的输入序列展开层(“展开/”)

层= [sequenceUnfoldingLayer (“名字”,“展开”)flattenLayer (“名字”,“平”)lstmLayers);lgraph = addLayers (lgraph层);lgraph = connectLayers (lgraph,“pool5-7x7_s1”,“展开/”);

使展开层恢复序列结构,连接“miniBatchSize”的输出序列折叠层的相应输入序列展开层。

lgraph = connectLayers (lgraph,“折/ miniBatchSize”,“展开/ miniBatchSize”);

组装网络

检查网络是否有效使用analyzeNetwork函数。

analyzeNetwork (lgraph)

组装网络预测准备使用assembleNetwork函数。

净= assembleNetwork (lgraph)
网= DAGNetwork属性:层:[148×1 nnet.cnn.layer.Layer]连接:(175×2表)

使用新数据进行分类

阅读和center-crop视频“pushup.mp4”使用相同的步骤。

文件名=“pushup.mp4”;视频= readVideo(文件名);

查看视频,使用implay函数(需要图像处理工具箱)。这个函数将数据范围[0,1],所以首先必须的数据除以255。或者,您可以遍历各个框架和使用imshow函数。

numFrames =大小(视频、4);图i = 1: numFrames帧=视频(::,:,我);imshow(帧/ 255);drawnow结束

使用组装网络视频进行分类。的分类函数将一个单元阵列包含输入视频,所以你必须输入一个1×1单元阵列包含视频。

视频= centerCrop(视频、inputSize);{视频}YPred =分类(净)
YPred =分类俯卧撑

辅助函数

readVideo函数读取视频文件名并返回一个H——- - - - - -W——- - - - - -C -由- - - - - -年代数组,H,W,C,年代高度,宽度,渠道,和视频的帧数。

函数视频= readVideo(文件名)vr = VideoReader(文件名);H = vr.Height;W = vr.Width;C = 3;% Preallocate视频数组numFrames =地板(虚拟现实。Duration * vr.FrameRate); video = zeros(H,W,C,numFrames);%阅读框架我= 0;hasFrame (vr)我= + 1;视频(::,:,我)= readFrame (vr);结束%去除未分配的框架如果大小(视频,4)>我视频(:,:,:,i + 1:结束)= [];结束结束

centerCrop函数作物的最长边视频和尺寸大小inputSize

函数videoResized = centerCrop(视频、inputSize)深圳=大小(视频);如果深圳(1)<深圳(2)%视频讲的是风景地板idx =((深圳(2)-深圳(1)/ 2);视频(:,1:(idx-1):,:) = [];视频(:,(深圳(1)+ 1):,:,:)= [];elseif深圳(2)<深圳(1)%视频画像地板idx =((深圳(1)-深圳(2))/ 2);视频(1:(idx-1)::,:) = [];视频((深圳(2)+ 1):,:,:,:)= [];结束videoResized = imresize(视频、inputSize (1:2));结束