主要内容

分类视频使用深度学习和自定义训练循环

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

您可以执行视频分类循环利用不使用一个定制的培训trainNetwork函数。例如,看到的分类使用深度学习视频。然而,如果trainingOptions不提供你需要的选项(例如,一个定制的学习速率的时间表),然后你可以定义自己的自定义训练循环,如本例所示。

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

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

  2. 训练序列分类网络的序列来预测视频标签。

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

下图说明了网络架构:

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

  • 从图像序列中提取特征,利用卷积层从pretrained GoogLeNet网络。

  • 分类结果向量序列,包括序列分类层。

视频分类(5). png

当这种类型的网络培训trainNetwork函数(在本例中没有完成),您必须使用序列折叠和展开层独立处理视频帧。当你训练,这种类型的网络dlnetwork对象和一个自定义训练循环(在本例中),序列折叠和展开层不是必需的,因为网络使用的维度信息dlarray尺寸标签。

负载Pretrained卷积网络

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

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

netCNN = googlenet;

加载数据

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

提取RAR文件之后,确保文件夹hmdb51_org包含子文件夹命名的身体动作。如果它包含RAR文件,您需要提取。使用支持函数金宝apphmdb51Files获取文件名称和标签的视频。加快训练精度为代价的,指定一个分数区间[0 1]的只读文件从数据库中随机子集。如果分数没有指定输入参数,函数hmdb51Files读取完整的数据集在不改变文件的顺序。

dataFolder =“hmdb51_org”;分数= 1;(文件、标签)= hmdb51Files (dataFolder,分数);

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

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

查看相应的标签。

标签(idx)
ans =分类shoot_ball

查看视频,遍历各个帧和使用图像函数。或者,您可以使用implay函数(需要图像处理工具箱)。

numFrames =大小(视频、4);图i = 1: numFrames帧=视频(::,:,我);图像(框架);xticklabels ([]);yticklabels ([]);drawnow结束

帧转换为特征向量

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

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

activationsDiagram_resized.png

读取视频数据使用readVideo函数,在这个例子中,定义和调整它来匹配输入的大小GoogLeNet网络。注意,这一步需要花很长时间运行。转换后的视频序列,保存序列和相应的标签在垫子上文件tempdir文件夹中。如果垫文件已经存在,然后加载序列直接从垫文件和标签。以防垫文件已经存在但你想覆盖它,设置变量overwriteSequences真正的

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

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

序列(1:10)
ans =10×1单元阵列{1024×115单}{1024×227单}{1024×180单}{1024×40个}{1024×60个}{1024×156单}{1024×83单}{1024×42个}{1024×82单}{1024×110单}

准备训练数据

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

创建分区训练和验证

分区的数据。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) = [];

创建数据存储的数据

创建一个arrayDatastore对象的序列和标签,然后将它们组合成一个单一的数据存储。

dsXTrain = arrayDatastore (sequencesTrain,“OutputType”,“相同”);dsYTrain = arrayDatastore (labelsTrain,“OutputType”,“细胞”);dsTrain =结合(dsXTrain dsYTrain);

确定训练数据的类。

类=类别(labelsTrain);

创建序列分类网络

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

定义序列分类网络体系结构。指定以下网络层:

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

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

  • 一层辍学概率为0.5。

  • 一个完全连接层和一个输出相应的类的数量和大小softmax层。

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

转换层layerGraph对象。

lgraph = layerGraph(层);

创建一个dlnetwork对象的层图。

dlnet = dlnetwork (lgraph);

指定培训选项

火车15时代并指定mini-batch大小为16。

numEpochs = 15;miniBatchSize = 16;

指定的选项为亚当的优化。指定一个初始的学习速率1的军医衰变的0.001,0.9的梯度衰变,0.999平方梯度衰变。

initialLearnRate = 1的军医;衰变= 0.001;gradDecay = 0.9;sqGradDecay = 0.999;

可视化培训进展阴谋。

情节=“训练进步”;

训练序列分类网络

创建一个minibatchqueue对象流程和管理mini-batches序列的培训。为每个mini-batch:

  • 使用自定义mini-batch预处理功能preprocessLabeledSequences(在这个例子中定义)标签转换为虚拟变量。

  • 维的向量序列数据标签格式“施”(通道、时间、批次)。默认情况下,minibatchqueue把数据转换为对象dlarray对象与基本类型。不格式添加到类的标签。

  • 火车在GPU如果一个是可用的。默认情况下,minibatchqueue将每个输出转换为对象gpuArray对象如果GPU可用。使用GPU需要并行计算工具箱™和支持GPU设备。金宝app支持设备的信息,请参阅金宝appGPU计算的需求(并行计算工具箱)

兆贝可= minibatchqueue (dsTrain,“MiniBatchSize”miniBatchSize,“MiniBatchFcn”@preprocessLabeledSequences,“MiniBatchFormat”,{“施”,});

初始化培训进展阴谋。

如果情节= =“训练进步”图lineLossTrain = animatedline (“颜色”[0.85 0.325 0.098]);ylim([0正])包含(“迭代”)ylabel (“损失”网格)结束

初始化平均梯度和亚当的平均平方梯度参数解算器。

averageGrad = [];averageSqGrad = [];

火车模型使用自定义训练循环。对于每一个时代,洗牌和遍历mini-batches数据的数据。为每个mini-batch:

  • 评估模型的梯度、州和损失dlfevalmodelGradients功能和更新网络状态。

  • 确定基于时间的学习速率衰减学习速率的时间表:对于每一次迭代,求解器使用的学习速率 ρ t = ρ 0 1 + k t ,在那里t是迭代数, ρ 0 最初的学习速率,k是衰减的。

  • 更新网络参数使用adamupdate函数。

  • 显示培训进展。

注意,培训可以花很长时间。

迭代= 0;开始=抽搐;%循环时期。时代= 1:numEpochs%洗牌数据。洗牌(兆贝可);%在mini-batches循环。hasdata(兆贝可)迭代=迭代+ 1;% mini-batch读取的数据。[dlX,海底]=下一个(兆贝可);%评估模型梯度、州和使用dlfeval和损失% modelGradients函数。(渐变、州损失)= dlfeval (@modelGradients, dlnet dlX,海底);%确定为基于时间的学习速率衰减学习速率的时间表。learnRate = initialLearnRate /(1 +衰变*迭代);%更新使用亚当优化网络参数。[dlnet, averageGrad averageSqGrad] = adamupdate (dlnet、渐变averageGrad averageSqGrad,迭代,learnRate、gradDecay sqGradDecay);%显示培训进展。如果情节= =“训练进步”D =持续时间(0,0,toc(开始),“格式”,“hh: mm: ss”);addpoints (lineLossTrain、迭代、双(收集(extractdata(损失))))标题(”时代:“+时代+“的”+ numEpochs +”,过去:“+ drawnow字符串(D))结束结束结束

测试模型

测试模型的分类精度比较预测验证集和真正的标签。

培训完成后,做出预测新数据不需要标签。

创建一个minibatchqueue测试对象:

  • 创建一个数据存储数组只包含测试数据的预测。

  • 指定相同的mini-batch大小用于培训。

  • 预处理预测使用preprocessUnlabeledSequenceshelper函数,列出的例子。

  • 对于单一的输出数据存储,指定mini-batch格式“施”(通道、时间、批次)。

dsXValidation = arrayDatastore (sequencesValidation,“OutputType”,“相同”);mbqTest = minibatchqueue (dsXValidation,“MiniBatchSize”miniBatchSize,“MiniBatchFcn”@preprocessUnlabeledSequences,“MiniBatchFormat”,“施”);

循环mini-batches和使用的图像进行分类modelPredictionshelper函数,列出的例子。

预测= modelPredictions (dlnet、mbqTest、类);

评估分类精度进行比较预测标签真正验证标签。

= = labelsValidation精度=意味着(预测)
精度= 0.6721

组装视频分类网络

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

下图说明了网络架构:

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

  • 利用卷积层提取特征,也就是说,应用卷积操作独立视频的每一帧,使用GoogLeNet卷积层。

  • 分类结果向量序列,包括序列分类层。

视频分类(5). png

当这种类型的网络培训trainNetwork函数(在本例中没有完成),必须使用序列折叠和展开层独立处理视频帧。当训练,这种类型的网络dlnetwork对象和一个自定义训练循环(在本例中),序列折叠和展开层不是必需的,因为网络使用的维度信息dlarray尺寸标签。

添加回旋的层

首先,创建一个层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) .Mean;inputLayer = sequenceInputLayer (inputSize [3],“归一化”,“zerocenter”,“的意思是”averageImage,“名字”,“输入”);

添加序列输入层到层图。输入层的输出连接到输入的第一个卷积层(“conv1-7x7_s2”)。

lgraph = addLayers (cnnLayers inputLayer);lgraph = connectLayers (lgraph,“输入”,“conv1-7x7_s2”);

添加序列分类层

以前训练序列分类网络层添加到层图和连接它们。

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

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

序列分类层添加到层图。最后卷积层连接pool5-7x7_s1bilstm层。

lgraph = addLayers (lgraph lstmLayers);lgraph = connectLayers (lgraph,“pool5-7x7_s1”,“bilstm”);

转换为dlnetwork

能够做预测,转换层图dlnetwork对象。

dlnetAssembled = dlnetwork (lgraph)
dlnetAssembled = dlnetwork属性:层:[144×1 nnet.cnn.layer.Layer]连接:[170×2表]可学的:(119×3表)状态:[2×3表]InputNames:{“输入”}OutputNames: {“softmax”}初始化:1

使用新数据进行分类

解压该文件pushup_mathworker.zip。

解压缩(“pushup_mathworker.zip”)

提取的pushup_mathworker文件夹包含一个视频,一个俯卧撑。这个文件夹中创建一个文件数据存储。使用一个定制的读函数读取视频。

ds = fileDatastore (“pushup_mathworker”,“ReadFcn”,@readVideo);

从数据存储读取第一个视频。能读懂视频,重置数据存储。

视频=阅读(ds);重置(ds);

查看视频,遍历各个帧和使用图像函数。或者,您可以使用implay函数(需要图像处理工具箱)。

numFrames =大小(视频、4);图i = 1: numFrames帧=视频(::,:,我);图像(框架);xticklabels ([]);yticklabels ([]);drawnow结束

对视频进行预处理所期望的输入规模的网络,使用变换功能和应用imresize函数中的每个图像数据存储。

dsXTest =变换(ds, @ (x) imresize (x, inputSize));

管理和处理标记的视频,创建一个minibatchqueue:

  • 指定一个mini-batch 1的大小。

  • 预处理的视频使用preprocessUnlabeledVideoshelper函数,列出的例子。

  • 对于单一的输出数据存储,指定mini-batch格式“SSCTB”(空间、空间、通道、时间、批次)。

mbqTest = minibatchqueue (dsXTest,“MiniBatchSize”,1“MiniBatchFcn”@preprocessUnlabeledVideos,“MiniBatchFormat”,{“SSCTB”});

分类的视频使用modelPredictionshelper函数,定义在这个例子。预计三个输入功能:dlnetwork对象,minibatchqueue对象,包含网络类单元阵列。

(预测)= modelPredictions (dlnetAssembled、mbqTest类)
预测=分类俯卧撑

辅助函数

电子阅读功能

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

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

模型梯度函数

modelGradients函数作为输入dlnetwork对象dlnet和mini-batch输入数据dlX与相应的标签Y的梯度,并返回损失对可学的参数dlnet、网络状态和损失。自动计算梯度,使用dlgradient函数。

函数(渐变、州损失)= modelGradients (dlnet dlX Y) [dlYPred、州]=向前(dlnet dlX);损失= crossentropy (dlYPred Y);梯度= dlgradient(损失、dlnet.Learnables);结束

模型的预测函数

modelPredictions函数作为输入dlnetwork对象dlnet,一个minibatchqueue输入数据的对象兆贝可网络类,计算模型预测通过遍历所有mini-batch队列中的数据。这个函数使用onehotdecode函数找到预测类最高的分数。函数返回预测的标签。

函数(预测)= modelPredictions (dlnet、兆贝可类)预测= [];hasdata(兆贝可)%提取mini-batch minibatchqueue和通过它%网络预测[dlXTest] =下一个(兆贝可);dlYPred =预测(dlnet dlXTest);%获得分类标签,一个炎热的解码的预测YPred = onehotdecode (dlYPred、类1)';预测=[预测;YPred];结束结束

标记序列数据预处理功能

preprocessLabeledSequences函数序列预处理数据使用下面的步骤:

  1. 使用padsequences函数来填充序列在时间维度和连接他们的批处理维度。

  2. 从传入单元阵列提取标签数据和连接到一个分类数组。

  3. 一个炎热的分类标签编码成数字数组。

  4. 转置的一个炎热的编码标签匹配网络输出的形状。

函数(X, Y) = preprocessLabeledSequences(伊势亚YCell)%垫的序列零第二第三个维度(时间)和连接%维度(批处理)X = padsequences(伊势亚2);%从细胞中提取标签数据和连接Y =猫(1,YCell{1:结束});%一个炎热的编码标签Y, Y = onehotencode (2);%的转置编码标签匹配网络的输出Y = Y ';结束

标记序列数据预处理功能

preprocessUnlabeledSequences函数序列预处理数据使用padsequences函数。这个函数垫0的序列在时间维度和连接导致批维度。

函数[X] = preprocessUnlabeledSequences(伊势亚)%垫的序列零第二第三个维度(时间)和连接%维度(批处理)X = padsequences(伊势亚2);结束

无标号视频数据预处理功能

preprocessUnlabeledVideos预处理标记视频数据使用的函数padsequences函数。这个函数与零垫的视频时间维度和连接导致批维度。

函数[X] = preprocessUnlabeledVideos(伊势亚)%垫的序列在第四维度(时间)和0%连接在第五维度(批处理)X = padsequences(伊势亚,4);结束

另请参阅

||||

相关的话题