主要内容

이번역페이지는최신내용을담고있지않습니다。최신내용을문으로보려면여기를클릭하십시오。

딥러닝을사용하여비디오분류하기

이예제에서는사전훈련된영상분류모델과LSTM신경망을결합하여비디오를분류하는신경망을만드는방법을보여줍니다。

비디오를분류하는딥러닝신경망을만들려면다음을수행하십시오。

  1. GoogLeNet과같은사전훈련된컨벌루션신경망을사용하여비디오를특징벡터로구성된시퀀스로변환하여각프레임에서특징을추출합니다。

  2. 시퀀스를대상으로LSTM신경망을훈련시켜서비디오레이블을예측합니다。

  3. 두신경망의계층을결합하여비디오를직접분류하는신경망을조합합니다。

다음도식은신경망아키텍처를보여줍니다。

  • 신경망에상시퀀스를입력하려면시퀀스입력계층을사용하십시오。

  • 특징추출을위해컨벌루션계층을사용하려면,즉비디오의각프레임에독립적으로컨벌루션연산을적용하려면,시퀀스접기계층뒤에컨벌루션계층을사용하십시오。

  • 시퀀스구조체를복원하고출력값의형태를벡터시퀀스로변경하려면시퀀스펼치기계층과평탄화계층을사용하십시오。

  • 결과로생성되는벡터시퀀스를분류하려면LSTM계층을삽입하고그뒤에출력계층이오도록하십시오。

사전훈련된컨벌루션신경망불러오기

비디오프레임을특징벡터로변환하려면사전훈련된신경망의활성화값을사용하십시오。

googlenet함수를사용하여사전훈련된GoogLeNet모델을불러옵니다。이함수를사용하려면深度学习工具箱™模型为GoogLeNet网络지원패키지가필합니다。이지원패키지가설치되어있지않으면함수에서다운로드링크를제공합니다。

网络cnn =谷歌网络;

데이터불러오기

HMDB:大型人体运动数据库에서hmbd51데이터세트를다운로드하고“hmdb51_org”라는이름의폴더에rar파일의압축을풉니다。이데이터세트에는“喝”“运行”“shake_hands”등51개의클래스로구성된7000개의클립으로이루어진약2 gb분량의비디오데이터가있습니다。

파일의압축을푼후에는지원함수hmdb51Files를사용하여비디오의파일이름과레이블을가져옵니다。

dataFolder =“hmdb51_org”;[files,labels] = hmdb51Files(dataFolder);

이예제의끝부분에정의된readVideo헬퍼함수를사용하여첫번째비디오를읽어들후비디오의크기를확합니다。비디오는H×W×C×年代배열입니다。여기서HWC年代는비디오의높이,너비,채널개수,프레임개수입니다

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

대응되는레이블을확합니다。

标签(idx)
ans =分类brush_hair

비디오를보려면implay함수를사용하십시오(图像处理工具箱™필)。이함수는[0,1]범위내에있는데이터가필요하므로먼저데이터를255로나누어야합니다。또는루프를사용해개별프레임을순회하고imshow함수를사용할수도있습니다。

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

프레임을특징벡터로변환하기

비디오프레임을신경망에입력할때의활성화값을가져와서컨벌루션신경망을특징추출기로사용하십시오。비디오를특징벡터로구성된시퀀스로변환합니다。여기서특징벡터는GoogLeNet신경망의마지막풀링계층(“pool5-7x7_s1”)에대해激活함수를적용한결과의출력값입니다。

다음도식에서는신경망내의데이터흐름을보여줍니다。

비디오데이터를읽어들여서GoogLeNet신경망의입력크기와일치하도록크기조정하려면이예제의끝부분에정의된readVideocenterCrop헬퍼함수를사용하십시오。이단계는실행하는데시간이오래걸릴수있습니다。비디오를시퀀스로변환한후에는시퀀스를tempdir폴더에있는mat파일에저장합니다。垫파일이이미존재하는경우,시퀀스를다시변환하지않고垫파일에서불러옵니다。

inputSize = netCNN.Layers(1).InputSize(1:2);layerName =“pool5-7x7_s1”;tempFile = fullfile(tempdir,“hmdb51_org.mat”);如果存在(tempFile“文件”)负载(tempFile“序列”其他的numFiles = numel(文件);sequences = cell(numFiles,1);i = 1:numFiles fprintf"读取%d的文件%d…\n", i, numFiles)视频= readVideo(文件(i));视频= centerCrop(视频,inputSize);序列{i,1} =激活(netCNN,视频,layerName,“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 = numel(序列);idx = randperm(numObservations);N =地板(0.9 * numObservations);idxTrain = idx(1:N);sequencesTrain = sequences(idxTrain);labelsTrain = labels(idxTrain);idxValidation = idx(N+1:结束);sequencesValidation = sequences(idxValidation);labelsValidation = labels(idxValidation);

긴시퀀스제거하기

신경망에있는일반적인시퀀스보다훨씬긴시퀀스는훈련과정에서다량의채우기가적용되는원인이될수있습니다。너무많은채우기는분류정확도를저하시킬수있습니다。

훈련데이터의시퀀스길이를가져와서훈련데이터히스토그램으로시각화합니다。

numObservationsTrain = numel(sequencesTrain);sequenceLengths = 0 (1,numObservationsTrain);i = 1:numObservationsTrain sequence = sequencesTrain{i};sequenceLengths(i) = size(sequence,2);结束数字直方图(sequenceLengths)“序列长度”)包含(“序列长度”) ylabel (“频率”

400개이상의시간스텝이있는시퀀스는몇개밖에없습니다。분류정확도를높이려면400개이상의시간스텝이있는훈련시퀀스와그에대응되는레이블을제거하십시오。

maxLength = 400;idx = sequenceLengths > maxLength;sequencesTrain(idx) = [];labelsTrain(idx) = [];

LSTM신경망만들기

다음으로,비디오를나타내는특징벡터로구성된시퀀스를분류할수있는LSTM신경망을만듭니다。

LSTM신경망아키텍처를정의합니다。다음신경망계층을지정합니다。

  • 입력크기가특징벡터의특징차원과같은시퀀스입력계층

  • 2000개의은닉유닛이있고뒤에드롭아웃계층이오는BiLSTM계층。각시퀀스에대해1개의레이블만출력하려면BiLSTM계층의“OutputMode”옵션을“最后一次”로설정하십시오。

  • 출력크기가클래스개수와같은완전연결계층,소프트맥스계층및분류계층。

numFeatures = size(sequencesTrain{1},1);numClasses =编号(类别(labelsTrain));layers = [sequenceInputLayer(numFeatures,“名字”“序列”) bilstmLayer (2000,“OutputMode”“最后一次”“名字”“bilstm”) dropoutLayer (0.5,“名字”“下降”) fullyConnectedLayer (numClasses“名字”“俱乐部”) softmaxLayer (“名字”“softmax”) classificationLayer (“名字”“分类”));

훈련옵션지정하기

trainingOptions함수를사용하여훈련옵션을지정합니다。

  • 미니배치크기를16으로,초기학습률을0.0001로(기울기가한없이증가하지않도록)기울기임계값을2로설정합니다。

  • 매纪元마다데이터를섞습니다。

  • Epoch당한번씩신경망을검합니다。

  • 훈련진행상황을플롯에@ @시하고세부정보가출력되지않도록합니다。

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

LSTM신경망훈련시키기

trainNetwork함수를사용하여신경망을훈련시킵니다。실행하는데시간이오래걸릴수있습니다。

[netLSTM,info] = trainNetwork(sequencesTrain,labelsTrain,layers,options);

검세트에대한신경망의분류정확도를계산합니다。훈련옵션과동일한미니배치크기를사용합니다。

YPred = category (netLSTM,sequencesValidation,“MiniBatchSize”, miniBatchSize);YValidation = labelsValidation;accuracy = mean(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,layers);lgraph = connectLayers(“折/”“conv1-7x7_s2”);

LSTM계층추가하기

LSTM신경망의시퀀스입력계층을제거하여계층그래프에LSTM계층을추가합니다。시퀀스접기계층에의해제거된시퀀스구조체를복원하려면컨벌루션계층뒤에시퀀스펼치기계층을삽입하십시오。LSTM계층에는벡터로구성된시퀀스가필합니다。시퀀스펼치기계층의출력값형태를벡터시퀀스로변경하려면시퀀스펼치기계층뒤에평탄화계층을삽입하십시오。

LSTM신경망에서계층을취하고시퀀스입력계층을제거합니다。

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

계층그래프에시퀀스펼치기계층,평탄화계층및LSTM계층을추가합니다。마지막컨벌루션계층(“pool5-7x7_s1”)을시퀀스펼치기계층의입력값(“展开/”)에연결합니다。

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

펼치기계층이시퀀스구조체를복원할수있도록하려면시퀀스접기계층의“miniBatchSize”출력값을시퀀스펼치기계층의대응되는입력값에연결합니다。

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

신경망조합하기

analyzeNetwork함수를사용하여신경망이유효한지확합니다。

analyzeNetwork (lgraph)

assembleNetwork함수를사용하여신경망이예측을수행할준비가되도록조합합니다。

net =汇编网络(lgraph)
net = DAGNetwork with properties: Layers: [148×1 nnet.cnn.layer.Layer] Connections: [175×2 table]

새데이터를사용하여분류하기

앞에서와같은단계를사용하여비디오“pushup.mp4”를읽어들이고가운데에맞게자릅니다。

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

비디오를보려면implay함수를사용하십시오(图像处理工具箱필)。이함수는[0,1]범위내에있는데이터가필요하므로먼저데이터를255로나누어야합니다。또는루프를사용해개별프레임을순회하고imshow함수를사용할수도있습니다。

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

조합된신경망을사용하여비디오를분류합니다。分类함수에는입력비디오를포함하는셀형배열이필요하므로비디오를포함하는1×1셀형배열을입력해야합니다。

视频= centerCrop(视频,inputSize);YPred = category (net,{video})
YPred =分类俯卧撑

헬퍼 함수

readVideo함수는文件名에있는비디오를읽어들여서H×W×C -×年代배열을반환합니다。여기서HWC年代는비디오의높이,너비,채널개수,프레임개수입니다

函数视频= readVideo(文件名)vr = VideoReader(文件名);H = vr.高度;W = vr.宽度;C = 3;预分配视频数组numFrames =地板(vr。Duration * vr.FrameRate); video = zeros(H,W,C,numFrames);读帧百分比I = 0;hasFrame(vr) i = i + 1;video(:,:,:,i) = readFrame(vr);结束移除未分配的帧如果Size (video,4) > I video(:,:,:, I +1:end) = [];结束结束

centerCrop함수는비디오의가장긴모서리를자르고크기가inputSize가되도록조정합니다。

函数videoresize = centerCrop(视频,inputSize) sz =大小(视频);如果Sz (1) < Sz (2)%视频为横屏Idx = floor((sz(2) - sz(1))/2);视频(:,1:(idx-1),:,:) = [];视频(:,(sz(1)+1):end,:,:) = [];elseifSz (2) < Sz (1)%视频为竖屏Idx = floor((sz(1) - sz(2))/2);视频(1:(idx-1),:,:,:) = [];视频((sz(2)+1):end,::,:) = [];结束videoresize = imresize(视频,inputSize(1:2));结束

참고 항목

||||||

관련 항목