主要内容

このページの翻訳は最新ではありません。ここをクリックして,英語の最新版を参照してください。

深層学習を使用したビデオの分類

この例では,事前学習済みのイメージ分類モデルとLSTMネットワークを組み合わせることによって,ビデオの分類用のネットワークを作成する方法を説明します。

ビデオの分类用の深层学习ネットワークを作成するには,以下のようにします。

  1. GoogLeNetなどの事前学習済みの畳み込みニューラルネットワークを使用してビデオを特徴ベクトルのシーケンスに変換し,各フレームから特徴を抽出します。

  2. シーケンスでLSTMネットワークに学習させて,ビデオのラベルを予測します。

  3. 両方のネットワークからの層を組み合わせることによってビデオを直接分類するネットワークを組み立てます。

次の図はネットワークアーキテクチャを示しています。

  • イメージシーケンスをネットワークに入力するには,シーケンス入力層を使用します。

  • 畳み込み層を使用して特徴を抽出する,つまり,畳み込み演算をビデオの各フレームに個別に適用するには,シーケンス折りたたみ層の後に畳み込み層を使用します。

  • シーケンス構造を復元し,出力をベクトルのシーケンスに形状変更するには,シーケンス展開層とフラット化層を使用します。

  • 結果のベクトルシーケンスを分類するには,LSTM層の後に出力層を含めます。

事前学习済み畳み込みネットワークネットワーク読み込み

ビデオのフレームを特徴ベクトルに変換するには,事前学習済みのネットワークの活性化を使用します。

関数googlenetを使用しし事前て习済みgooglenetモデルモデル読み込みます。この关键词,深学习工具箱™模型GoogLeNet网络サポートパッケージが必要です。このサポートパッケージがインストールされていない場合,関数によってダウンロード用リンクが表示されます。

netCNN = googlenet;

データの読み込み

HMDB(大規模人間動作データベース)からHMBD51データセットをダウンロードし,RARファイルを“hmdb51_org”という名前のフォルダーに解冻ますますます。このこのデータセットに,“喝”“运行”“shake_hands”7000年など,51クラスの個のクリップから成る約2 GBのビデオデータが格納されています。

RARファイルを解凍した後,サポート関数hmdb51Filesを使用してビデオのファイル名とラベルを取得します。

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

補助関数readVideo(この例の最後に定義)を使用して最初のビデオを読み取り,ビデオのサイズを表示します。ビデオはHxWxCx年代の配列です。ここで,HWC,および年代はそれぞれビデオの高さ,幅,チャネル数,およびフレーム数です。

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

対応するラベルを表示します。

标签(idx)
ans =分类brush_hair

ビデオを表示するには,関数implayを使用します(图像处理工具箱™が必要です)。この関数は,データが[0,1]の範囲内にあると想定しているため,まずデータを255で除算しなければなりません。または,個々のフレームに対してループ処理を行い,関数imshowを使用することもできます。

numFrames =大小(视频、4);数字i = 1:numFrames frame = video(:,:,:,i);imshow(帧/ 255);drawnow结束

フレームから特价ベクトルへの変换

ネットワークへのビデオフレームの入力時に活性化を取得することによって,畳み込みネットワークを特徴抽出器として使用します。ビデオを特徴ベクトルのシーケンスに変換します。ここで,特徴ベクトルは、GoogLeNet ネットワーク (“pool5-7x7_s1”)の最後のプーリング層に対する関数激活のの力です。

次の図は,ネットワークでのデータフローを示しています。

ビデオデータを読み取り,GoogLeNetネットワークの入力サイズに一致するようにサイズを変更するには,補助関数readVideoおよびcenterCrop(この例の最后に定义)ををの実行。このビデオかかることがありありたがをシーケンスこと変换ありたた后后后シーケンスことに変换した后,tempdirフォルダーの垫ファイルにシーケンスを保存します。垫ファイルが既に存在する場合,再変換せずに垫ファイルからシーケンスを読み込みます。

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 fprintf(“阅读文件%d%d ... \ n”, i, numFiles) video = readVideo(files(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 = floor(0.9 * numobations);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 sequence = sequencesTrain{i};sequenceLengths (i) =(序列,2)大小;结束图表直方图(Sequencelengths)标题(“序列长度”)包含(“序列长度”) ylabel (“频率”

400年タイムステップがを超えるシーケンスはわずかです。分類精度を向上させるには,タイムステップが400を超える学習シーケンスとそれに対応するラベルを削除します。

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

LSTMネットワークの作成

次に,ビデオを表す特徴ベクトルのシーケンスを分类できるLSTMネットワークを作成します。

LSTMネットワークアーキテクチャを定義します。次のネットワーク層を指定します。

  • 入力サイズが特徴ベクトルの特徴次元に対応するシーケンス入力层。

  • 後にドロップアウト層がある,隠れユニットが2000個のBiLSTM層。各シーケンスについて1つのラベルのみを出力するには,BiLSTM層の“OutputMode”オプションを“最后一次”に設定します。

  • 出力サイズがクラス数に対応する全結合層,ソフトマックス層,分類層。

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

学習オプションの指定

関数trainingOptionsを使用して学習オプションを指定します。

  • ミニバッチサイズを16日初期学習率を0.0001,勾配のしきい値を2に設定します(勾配の発散を防ぐため)。

  • すべてのエポックでデータをシャッフルします。

  • エポックごとに1回ネットワークを検证します。

  • プロットに学習の進行状況を表示し,詳細出力を表示しないようにします。

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

LSTMネットワークの学習

関数trainNetworkを使用してネットワークに学習させます。実行には時間がかかることがあります。

[netlstm,Info] = Trainnetwork(Sequencestrain,Labelstrain,图层,选项);

検証セットに対するネットワークの分類精度を計算します。学習オプションの場合と同じミニバッチサイズを使用します。

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) .Mean;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 (lgraph)
net =具有属性的Dagnetwork:图层:[148×1 nnet.cnn.layer.layer]连接:[175×2表]

新しいデータを使用した分類

前と同じ手顺に従ってビデオ“pushup.mp4”を読み取り,中心トリミングします。

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

ビデオを表示するには,関数implayを使用します(图像处理工具箱が必要です)。この関数は,データが[0,1]の範囲内にあると想定しているため,まずデータを255で除算しなければなりません。または,個々のフレームに対してループ処理を行い,関数imshowを使用することもできます。

numFrames =大小(视频、4);数字i = 1:numFrames frame = video(:,:,:,i);imshow(帧/ 255);drawnow结束

組み立てたネットワークを使用してビデオを分類します。関数分类はは力量ビデオ含む含む配列を想定している,ビデオビデオ含む1行1列ののをを入入なけれなりません。

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

補助関数

関数readVideo文件名のビデオを読み取り,HxWxC -x年代の配列を返します。ここで,HWC,および年代はそれぞれビデオの高さ,幅,チャネル数,およびフレーム数です。

函数视频= readVideo(filename) vr = VideoReader(filename);H = vr.Height;W = vr.Width;C = 3;%预分配视频阵列numFrames =地板(虚拟现实。Duration * vr.FrameRate); video = zeros(H,W,C,numFrames);%阅读框架我= 0;hasFrame(vr) i = i + 1;视频(::,:,我)= readFrame (vr);结束删除未分配的帧如果Size (video,4) > I video(:,:,:, I +1:end) = [];结束结束

関数centerCropは,ビデオの最も長いエッジをトリミングし,サイズがinputSizeになるように変更します。

函数VideeSized = CenterCrop(视频,输入)Sz =大小(视频);如果深圳(1)<深圳(2)%视频是横向的Idx = floor((sz(2) - sz(1))/2);视频(:1:(idx-1 ),:,:) = [];视频(:,(深圳(1)+ 1):结束 ,:,:) = [];elseifSZ(2)%视频是纵向的IDX =楼层((SZ(1) -  SZ(2))/ 2);视频(1:(idx-1),:,:,:) = [];视频((sz(2)+1):结束,:,:,:) = [];结束videoResized = imresize(视频、inputSize (1:2));结束

参考

||||||

関連するトピック