Этот пример сначала показывает, как выполнить распознавание жеста с помощью предварительно обученного классификатора видео SlowFast [1] и затем показывает, как использовать передачу обучения, чтобы обучить классификатор на пользовательском наборе данных распознавания жеста.
Основанное на видении человеческое распознавание жеста включает предсказание жеста, такого как помахивание привет, жесты языка жестов или хлопание, с помощью набора видеокадров. Одна из привлекательных функций распознавания жеста - то, что они позволяют людям связаться с компьютерами и устройствами без потребности во внешнем входном оборудовании, такими как мышь или дистанционное управление. Распознавание жеста от видео имеет много приложений, таких как управление бытовой электроники и механических систем, изучения робота и компьютерных игр. Например, онлайновое предсказание нескольких действий для входящих видео от нескольких камер может быть важно для изучения робота. Сравненный с классификацией изображений, человеческое распознавание жеста с помощью видео сложно к модели из-за неточных достоверных данных для наборов видеоданных, множества жестов, которые агенты в видео могут выполнить, в большой степени класс неустойчивые наборы данных и большой объем данных, требуемый обучать устойчивый классификатор с нуля. Методы глубокого обучения, такие как SlowFast две трассы сверточные сети [1], показали улучшенную производительность на меньших наборах данных с помощью передачи обучения с сетями, предварительно обученными на больших видео наборах данных распознавания активности.
Примечание: Этот пример требует Модели Computer Vision Toolbox™ для Классификации Видео SlowFast. Можно установить Модель Computer Vision Toolbox для Классификации Видео SlowFast из Add-On Explorer. Для получения дополнительной информации об установке дополнений, смотрите, Получают и Управляют Дополнениями.
Загрузите предварительно обученный классификатор видео SlowFast наряду с видеофайлом, на котором можно выполнить распознавание жеста. Размер загруженного zip-файла составляет приблизительно 245 Мбайт.
downloadFolder = fullfile(tempdir,"gesture"); if ~isfolder(downloadFolder) mkdir(downloadFolder); end zipFile = "slowFastPretrained_fourClasses.zip"; if ~isfile(fullfile(downloadFolder,zipFile)) disp('Downloading the pretrained network...'); downloadURL = "https://ssd.mathworks.com/supportfiles/vision/data/" + zipFile; zipFile = fullfile(downloadFolder,zipFile); websave(zipFile,downloadURL); unzip(zipFile,downloadFolder); disp("Downloaded.") end
Downloading the pretrained network...
Downloaded.
Загрузите предварительно обученный классификатор видео SlowFast.
pretrainedDataFile = fullfile(downloadFolder,"slowFastPretrained_fourClasses.mat");
pretrained = load(pretrainedDataFile);
slowFastClassifier = pretrained.data.slowFast;
Отобразите имена метки класса предварительно обученного видео классификатора.
classes = slowFastClassifier.Classes
classes = 4×1 categorical
clapping
noAction
somethingElse
wavingHello
Считайте и отобразите видео waving-hello.avi
использование VideoReader
и vision.VideoPlayer
.
videoFilename = fullfile(downloadFolder,"waving-hello.avi"); videoReader = VideoReader(videoFilename); videoPlayer = vision.VideoPlayer; videoPlayer.Name = "waving-hello"; while hasFrame(videoReader) frame = readFrame(videoReader); step(videoPlayer,frame); end release(videoPlayer);
Выберите 10 случайным образом выбранных видео последовательностей, чтобы классифицировать видео, однородно покрыть полноту файла, чтобы найти класс действия, который преобладает в видео.
numSequences = 10;
Классифицируйте видеофайл с помощью classifyVideoFile
функция.
[gestureLabel,score] = classifyVideoFile(slowFastClassifier,videoFilename,NumSequences=numSequences)
gestureLabel = categorical
wavingHello
score = single
0.4753
Классификация может также быть применена к потоковому видео. Чтобы изучить, как классифицировать видео веб-камеры потоковой передачи, смотрите, Классифицируют Видео Веб-камеры Потоковой передачи Используя Классификатор Видео SlowFast (Computer Vision Toolbox).
Этот раздел примера показывает, как видео классификатор, показанный выше, обучен с помощью передачи обучения. Установите doTraining
переменная к false
использовать предварительно обученный видео классификатор, не имея необходимость ожидать обучения завершиться. В качестве альтернативы, если вы хотите обучить видео классификатор, установите doTraining
переменная к true
.
doTraining = false;
Этот пример обучает сеть классификации видео SlowFast использование загружаемого набора данных жеста, который содержит четыре жеста: "clapping","wavingHello","somethingElse", and "noAction"
. Набор данных содержит видео, которые помечены с помощью Video Labeler и соответствующих достоверных данных.
Создайте директории, чтобы хранить обучающие данные основной истины.
groundTruthFolder = fullfile(downloadFolder,"groundTruthFolder"); if ~isfolder(groundTruthFolder) mkdir(groundTruthFolder); end
Загрузите набор данных и извлеките архив zip в downloadFolder
.
zipFile = 'videoClipsAndSceneLabels.zip'; if ~isfile(fullfile(groundTruthFolder,zipFile)) disp('Downloading the ground truth training data...'); downloadURL = "https://ssd.mathworks.com/supportfiles/vision/data/" + zipFile; zipFile = fullfile(groundTruthFolder,zipFile); websave(zipFile,downloadURL); unzip(zipFile,groundTruthFolder); end
Чтобы обучить видео классификатор, вам нужны набор видео и его соответствующий набор меток сцены. Используйте функцию помощника extractVideoScenes, заданный в конце этого примера, чтобы извлечь помеченные видеоизображения из достоверных данных и записать им в диск как отдельные видеофайлы. Чтобы узнать больше об извлечении обучающих данных от видео, смотрите Обучающие данные Извлечения для Видео Классификации (Computer Vision Toolbox).
groundTruthFolder = fullfile(downloadFolder,"groundTruthFolder"); trainingFolder = fullfile(downloadFolder,"videoScenes"); extractVideoScenes(groundTruthFolder,trainingFolder,classes);
В общей сложности 40 видеоизображений извлечены из загруженных достоверных данных.
Этот пример использует datastore, чтобы считать сцены видео и метки, извлеченные из достоверных данных.
Задайте количество видеокадров, которые datastore должен быть сконфигурирован, чтобы вывести в течение каждого раза, когда данные считаны из datastore.
numFrames = 16;
Значение 16 используется здесь, чтобы сбалансировать время классификации и использование памяти. Общие значения, чтобы рассмотреть равняются 8, 16, 32, 64, или 128. Используя большее количество систем координат помогает получить дополнительную временную информацию, но требует большей памяти. Эмпирический анализ требуется, чтобы определять оптимальное количество кадров.
Затем задайте высоту и ширину систем координат, которые datastore должен быть сконфигурирован, чтобы вывести. Datastore автоматически изменяет размер необработанных видеокадров к заданному размеру, чтобы включить пакетную обработку данных нескольких видео последовательностей.
frameSize = [112,112];
Значение [112 112] используется, чтобы получить дольше временные отношения в видеоизображении, какая справка классифицируют жесты с долговременной длительностью. Общие значения для размера [112 112], [224 224], или [256 256]. Меньшие размеры включают использование большего количества видеокадров за счет использования памяти, время вычислений и пространственное разрешение. Как с количеством кадров, эмпирический анализ требуется, чтобы определять оптимальные значения.
Задайте количество каналов как 3, когда видео являются RGB.
numChannels = 3;
Используйте функцию помощника, createFileDatastore
, сконфигурировать FileDatastore
для загрузки данных. Функция помощника перечислена в конце этого примера.
isDataForTraining = true; dsTrain = createFileDatastore(trainingFolder,numFrames,numChannels,classes,isDataForTraining);
Создайте классификатор видео SlowFast для передачи обучения при помощи slowFastVideoClassifier
функция. slowFastVideoClassifier
функция создает объект классификатора видео SlowFast, который предварительно обучен на кинетике 400 наборов данных [2].
Задайте ResNet-50 как основную сетевую нейронную сеть свертки 3D архитектура для классификатора SlowFast.
baseNetwork = "resnet50-3d";
Задайте входной размер для классификатора видео SlowFast.
inputSize = [frameSize,numChannels,numFrames];
Создайте классификатор видео SlowFast путем определения классов для набора данных жеста и сетевого входного размера.
slowFast = slowFastVideoClassifier(baseNetwork,string(classes),InputSize=inputSize);
Задайте имя модели для видео классификатора.
slowFast.ModelName = "Gesture Recognizer Using Deep Learning";
Увеличение данных обеспечивает способ использовать наборы ограниченных данных для обучения. Увеличение на видеоданных должно быть тем же самым для набора систем координат на основе сетевого входного размера. Незначительные изменения, такие как перевод, обрезка, или преобразование изображения, обеспечивают, новые, отличные, и уникальные изображения, которые можно использовать, чтобы обучить устойчивый видео классификатор. Хранилища данных являются удобным способом считать и увеличить наборы данных. Увеличьте учебные видеоданные при помощи augmentVideo
поддерживание функции, заданной в конце этого примера.
dsTrain = transform(dsTrain,@augmentVideo);
Предварительно обработайте учебные видеоданные, чтобы изменить размер к входному размеру классификатора видео SlowFast, при помощи preprocessVideoClips
, заданный в конце этого примера. Задайте InputNormalizationStatistics
свойство видео классификатора и входного размера к предварительной обработке функционирует как значения полей в struct, preprocessInfo
. InputNormalizationStatistics
свойство используется, чтобы перемасштабировать видеокадры между 0 и 1, и затем нормировать перемасштабированные данные с помощью среднего и стандартного отклонения. Входной размер используется, чтобы изменить размер видеокадров с помощью imresize
на основе SizingOption
значение в info
struct (). В качестве альтернативы вы могли использовать "randomcrop"
или "centercrop"
как значения для SizingOption
к случайной обрезке или центру обрезают входные данные к входному размеру видео классификатора.
preprocessInfo.Statistics = slowFast.InputNormalizationStatistics;
preprocessInfo.InputSize = inputSize;
preprocessInfo.SizingOption = "resize";
dsTrain = transform(dsTrain,@(data)preprocessVideoClips(data,preprocessInfo));
modelGradients
функция, перечисленная в конце этого примера, берет в качестве входа классификатор видео SlowFast slowFast
, мини-пакет входных данных dlRGB
, и мини-пакет основной истины помечает данные dlY
. Функция возвращает учебное значение потерь, градиенты потери относительно настраиваемых параметров классификатора и мини-пакетной точности классификатора.
Потеря вычисляется путем вычисления потери перекрестной энтропии предсказаний от видео классификатора. Выходные предсказания сети являются вероятностями между 0 и 1 для каждого из классов.
Точность классификатора вычисляется путем сравнения классификатора predictions
к метке основной истины входных параметров, dlY
.
Обучайтесь с мини-пакетным размером 5 для 600 итераций. Задайте итерацию, после которой можно сохранить модель с лучшей мини-пакетной потерей при помощи SaveBestAfterIteration
параметр.
Задайте отжигающие косинус параметры расписания [3] скорости обучения:
Минимальная скорость обучения 1e-4.
Максимальная скорость обучения 1e-3.
Количество косинуса итераций 200, 300, и 400, после которого цикл расписания скорости обучения перезапускает. Опция CosineNumIterations
задает ширину каждого цикла косинуса.
Задайте параметры для оптимизации SGDM. Инициализируйте параметры оптимизации SGDM в начале обучения:
Импульс 0,9.
Начальный скоростной параметр, инициализированный как []
.
Фактор регуляризации L2 0,0005.
Задайте, чтобы диспетчеризировать данные в фоновом режиме с помощью параллельного пула. Если DispatchInBackground
установлен в истинный, откройте параллельный пул с конкретным количеством параллельных рабочих и создайте DispatchInBackgroundDatastore
, если как часть этого примера, который диспетчеризирует данные в фоновом режиме, чтобы ускорить обучение с помощью асинхронной загрузки данных и предварительной обработки. По умолчанию этот пример использует графический процессор, если вы доступны. В противном случае это использует центральный процессор. Используя графический процессор требует Parallel Computing Toolbox™, и CUDA® включил NVIDIA® графический процессор. Для получения информации о поддерживаемом вычислите возможности, смотрите Поддержку графического процессора Релизом (Parallel Computing Toolbox).
params.Classes = classes; params.MiniBatchSize = 5; params.NumIterations = 600; params.CosineNumIterations = [100 200 300]; params.SaveBestAfterIteration = 400; params.MinLearningRate = 1e-4; params.MaxLearningRate = 1e-3; params.Momentum = 0.9; params.Velocity = []; params.L2Regularization = 0.0005; params.ProgressPlot = false; params.Verbose = true; params.DispatchInBackground = true; params.NumWorkers = 12;
Обучите классификатор видео SlowFast с помощью видеоданных.
В течение каждой эпохи:
Переставьте данные перед цикличным выполнением по мини-пакетам данных.
Используйте minibatchqueue
циклично выполняться по мини-пакетам. Функция поддержки createMiniBatchQueue
, перечисленный в конце этого примера, использует данный учебный datastore, чтобы создать minibatchqueue
.
Отобразите результаты потери и точности за каждую эпоху с помощью функции поддержки displayVerboseOutputEveryEpoch
, перечисленный в конце этого примера.
Для каждого мини-пакета:
Преобразуйте видеоданные и метки к dlarray
объекты с базовым одним типом.
Чтобы позволить обработать измерение времени, видеоданные с помощью классификатора видео SlowFast задают временную размерность последовательности, "T"
. Укажите, что размерность маркирует "SSCTB"
(пространственный, пространственный, канал, временный, пакет) для видеоданных и "CB"
для данных о метке.
minibatchqueue
возразите использует функцию поддержки batchVideo
, перечисленный в конце этого примера, чтобы обработать видеоданные RGB в пакетном режиме.
params.ModelFilename = "slowFastPretrained_fourClasses.mat"; if doTraining epoch = 1; bestLoss = realmax; accTrain = []; lossTrain = []; iteration = 1; start = tic; trainTime = start; shuffled = shuffleTrainDs(dsTrain); % Number of outputs is two: One for RGB frames, and one for ground truth labels. numOutputs = 2; mbq = createMiniBatchQueue(shuffled, numOutputs, params); % Use the initializeTrainingProgressPlot and initializeVerboseOutput % supporting functions, listed at the end of the example, to initialize % the training progress plot and verbose output to display the training % loss, training accuracy, and validation accuracy. plotters = initializeTrainingProgressPlot(params); initializeVerboseOutput(params); while iteration <= params.NumIterations % Iterate through the data set. [dlX1,dlY] = next(mbq); % Evaluate the model gradients and loss using dlfeval. [gradients,loss,acc,state] = ... dlfeval(@modelGradients,slowFast,dlX1,dlY); % Accumulate the loss and accuracies. lossTrain = [lossTrain, loss]; accTrain = [accTrain, acc]; % Update the network state. slowFast.State = state; % Update the gradients and parameters for the video classifier % using the SGDM optimizer. [slowFast,params.Velocity,learnRate] = ... updateLearnables(slowFast,gradients,params,params.Velocity,iteration); if ~hasdata(mbq) || iteration == params.NumIterations % Current epoch is complete. Do validation and update progress. trainTime = toc(trainTime); accTrain = mean(accTrain); lossTrain = mean(lossTrain); % Update the training progress. displayVerboseOutputEveryEpoch(params,start,learnRate,epoch,iteration,... accTrain,lossTrain,trainTime); updateProgressPlot(params,plotters,epoch,iteration,start,lossTrain,accTrain); % Save the trained video classifier and the parameters, that gave % the best training loss so far. Use the saveData supporting function, % listed at the end of this example. bestLoss = saveData(slowFast,bestLoss,iteration,lossTrain,params); end if ~hasdata(mbq) && iteration < params.NumIterations % Current epoch is complete. Initialize the training loss, accuracy % values, and minibatchqueue for the next epoch. accTrain = []; lossTrain = []; epoch = epoch + 1; trainTime = tic; shuffled = shuffleTrainDs(dsTrain); mbq = createMiniBatchQueue(shuffled, numOutputs, params); end iteration = iteration + 1; end % Display a message when training is complete. endVerboseOutput(params); disp("Model saved to: " + params.ModelFilename); end
Чтобы оценить точность обученного классификатора видео SlowFast, установите isDataForTraining
переменная ко лжи и создает fileDatastore
. Обратите внимание на то, что увеличение данных не применяется к данным об оценке. Идеально, тест и данные об оценке должны быть представительными для исходных данных и оставлены немодифицированными для несмещенной оценки.
isDataForTraining = false; dsEval = createFileDatastore(trainingFolder,numFrames,numChannels,classes,isDataForTraining); dsEval = transform(dsEval,@(data)preprocessVideoClips(data,preprocessInfo));
Загрузите лучшую модель, сохраненную во время обучения, или используйте предварительно обученную модель.
if doTraining transferLearned = load(params.ModelFilename); slowFastClassifier = transferLearned.data.slowFast; end
Создайте minibatchqueue
возразите, чтобы загрузить пакеты тестовых данных.
numOutputs = 2; mbq = createMiniBatchQueue(dsEval,numOutputs,params);
Для каждого пакета данных об оценке сделайте предсказания с помощью классификатора видео SlowFast и вычислите точность предсказания с помощью матрицы беспорядка.
numClasses = numel(params.Classes); cmat = sparse(numClasses,numClasses); while hasdata(mbq) [dlVideo,dlY] = next(mbq); % Computer the predictions of the trained SlowFast % video classifier. dlYPred = predict(slowFastClassifier,dlVideo); dlYPred = squeezeIfNeeded(dlYPred,dlY); % Aggregate the confusion matrix by using the maximum % values of the prediction scores and the ground truth labels. [~,YTest] = max(dlY,[],1); [~,YPred] = max(dlYPred,[],1); cmat = aggregateConfusionMetric(cmat,YTest,YPred); end
Вычислите среднюю точность классификации клипов для обученного классификатора видео SlowFast.
evalClipAccuracy = sum(diag(cmat))./sum(cmat,"all")
evalClipAccuracy = 0.9847
Отобразите матрицу неточностей.
figure chart = confusionchart(cmat,classes);
Классификатор видео SlowFast, который предварительно обучен на кинетике 400 наборов данных [2], обеспечивает высокие показатели для человеческого распознавания жеста на передаче обучения. Вышеупомянутое обучение было запущено на Титане-X 24GB графический процессор в течение приблизительно 60 минут. Когда обучение с нуля на маленьком наборе видеоданных распознавания жеста, учебное время и сходимость берет намного дольше, чем предварительно обученный видео классификатор. Transer, изучающий использование кинетики, 400 предварительно обученных классификаторов видео SlowFast также стараются не сверхсоответствовать классификатору, когда запустился для большего числа эпох на таком маленьком наборе видеоданных распознавания жеста. Чтобы узнать больше о видео распознавании с помощью глубокого обучения, смотрите Начало работы с Видео Классификацией Используя Глубокое обучение (Computer Vision Toolbox).
createFileDatastore
createFileDatastore
функция создает FileDatastore
объект с помощью данного имени папки. FileDatastore
объект считывает данные в 'partialfile'
режим, таким образом, каждое чтение может возвратить частично системы координат чтения в видео. Эта функция помогает с чтением больших видеофайлов, если все системы координат не умещаются в памяти.
function datastore = createFileDatastore(trainingFolder,numFrames,numChannels,classes,isDataForTraining) readFcn = @(f,u)readVideo(f,u,numFrames,numChannels,classes,isDataForTraining); datastore = fileDatastore(trainingFolder,... 'IncludeSubfolders',true,... 'FileExtensions','.avi',... 'ReadFcn',readFcn,... 'ReadMode','partialfile'); end
shuffleTrainDs
shuffleTrainDs
функционируйте переставляет файлы, существующие в учебном datastore, dsTrain
.
function shuffled = shuffleTrainDs(dsTrain) shuffled = copy(dsTrain); transformed = isa(shuffled, 'matlab.io.datastore.TransformedDatastore'); if transformed files = shuffled.UnderlyingDatastores{1}.Files; else files = shuffled.Files; end n = numel(files); shuffledIndices = randperm(n); if transformed shuffled.UnderlyingDatastores{1}.Files = files(shuffledIndices); else shuffled.Files = files(shuffledIndices); end reset(shuffled); end
readVideo
readVideo
функционируйте читает видеокадры и соответствующие значения метки для данного видеофайла. Во время обучения функция чтения читает определенное количество кадров согласно сетевому входному размеру со случайным образом выбранной стартовой системой координат. Во время тестирования последовательно читаются все системы координат. Видеокадры изменены к необходимому входному размеру сети классификатора для обучения, и для тестирования и валидации.
function [data,userdata,done] = readVideo(filename,userdata,numFrames,numChannels,classes,isDataForTraining) if isempty(userdata) userdata.reader = VideoReader(filename); userdata.batchesRead = 0; userdata.label = getLabel(filename,classes); totalFrames = floor(userdata.reader.Duration * userdata.reader.FrameRate); totalFrames = min(totalFrames, userdata.reader.NumFrames); userdata.totalFrames = totalFrames; userdata.datatype = class(read(userdata.reader,1)); end reader = userdata.reader; totalFrames = userdata.totalFrames; label = userdata.label; batchesRead = userdata.batchesRead; if isDataForTraining video = readForTraining(reader,numFrames,totalFrames); else video = readForEvaluation(reader,userdata.datatype,numChannels,numFrames,totalFrames); end data = {video, label}; batchesRead = batchesRead + 1; userdata.batchesRead = batchesRead; if numFrames > totalFrames numBatches = 1; else numBatches = floor(totalFrames/numFrames); end % Set the done flag to true, if the reader has read all the frames or % if it is training. done = batchesRead == numBatches || isDataForTraining; end
readForTraining
readForTraining
функционируйте читает видеокадры для обучения видео классификатор. Функция читает определенное количество кадров согласно сетевому входному размеру со случайным образом выбранной стартовой системой координат. Если существует недостаточно перенесенных систем координат, видео последовательность повторяется, чтобы заполнить необходимое количество кадров.
function video = readForTraining(reader,numFrames,totalFrames) if numFrames >= totalFrames startIdx = 1; endIdx = totalFrames; else startIdx = randperm(totalFrames - numFrames + 1); startIdx = startIdx(1); endIdx = startIdx + numFrames - 1; end video = read(reader,[startIdx,endIdx]); if numFrames > totalFrames % Add more frames to fill in the network input size. additional = ceil(numFrames/totalFrames); video = repmat(video,1,1,1,additional); video = video(:,:,:,1:numFrames); end end
readForEvaluation
readForEvaluation
функционируйте читает видеокадры для оценки обученного видео классификатора. Функция читает определенное количество кадров последовательно согласно сетевому входному размеру. Если существует недостаточно перенесенных систем координат, видео последовательность повторяется, чтобы заполнить необходимое количество кадров.
function video = readForEvaluation(reader,datatype,numChannels,numFrames,totalFrames) H = reader.Height; W = reader.Width; toRead = min([numFrames,totalFrames]); video = zeros([H,W,numChannels,toRead],datatype); frameIndex = 0; while hasFrame(reader) && frameIndex < numFrames frame = readFrame(reader); frameIndex = frameIndex + 1; video(:,:,:,frameIndex) = frame; end if frameIndex < numFrames video = video(:,:,:,1:frameIndex); additional = ceil(numFrames/frameIndex); video = repmat(video,1,1,1,additional); video = video(:,:,:,1:numFrames); end end
getLabel
getLabel
функция получает имя метки из полного пути имени файла. Метка для файла является папкой, в которой она существует. Например, для пути к файлу, такого как "/path/to/data set/clapping/video_0001.avi"
, именем метки является "clapping"
.
function label = getLabel(filename,classes) folder = fileparts(string(filename)); [~,label] = fileparts(folder); label = categorical(string(label),string(classes)); end
augmentVideo
augmentVideo
функционируйте увеличивает видеокадры для обучения видео классификатор. Функция увеличивает видео последовательность с тем же методом увеличения, обеспеченным augmentTransform
функция.
function data = augmentVideo(data) numClips = size(data,1); for ii = 1:numClips video = data{ii,1}; % HxWxC sz = size(video,[1,2,3]); % One augment fcn per clip augmentFcn = augmentTransform(sz); data{ii,1} = augmentFcn(video); end end
augmentTransform
augmentTransform
функция создает метод увеличения со случайным зеркальным отражением лево-права и масштабными коэффициентами.
function augmentFcn = augmentTransform(sz) % Randomly flip and scale the image. tform = randomAffine2d('XReflection',true,'Scale',[1 1.1]); rout = affineOutputView(sz,tform,'BoundsStyle','CenterOutput'); augmentFcn = @(data)augmentData(data,tform,rout); function data = augmentData(data,tform,rout) data = imwarp(data,tform,'OutputView',rout); end end
preprocessVideoClips
preprocessVideoClips
функция предварительно обрабатывает учебные видеоданные, чтобы изменить размер к входному размеру классификатора видео SlowFast. Это берет InputNormalizationStatistics
и InputSize
свойства видео классификатора в struct, info
. InputNormalizationStatistics
свойство используется, чтобы перемасштабировать видеокадры между 0 и 1, и затем нормировать перемасштабированные данные с помощью среднего и стандартного отклонения. Входной размер используется, чтобы изменить размер видеокадров с помощью imresize
на основе SizingOption
значение в info
struct (). В качестве альтернативы вы могли использовать "randomcrop"
или "centercrop"
как значения для SizingOption
к случайной обрезке или центру обрезают входные данные к входному размеру видео классификатора.
function data = preprocessVideoClips(data, info) inputSize = info.InputSize(1:2); sizingOption = info.SizingOption; switch sizingOption case "resize" sizingFcn = @(x)imresize(x,inputSize); case "randomcrop" sizingFcn = @(x)cropVideo(x,@randomCropWindow2d,inputSize); case "centercrop" sizingFcn = @(x)cropVideo(x,@centerCropWindow2d,inputSize); end numClips = size(data,1); minValue = info.Statistics.Min; maxValue = info.Statistics.Max; meanValue = info.Statistics.Mean; stdValue = info.Statistics.StandardDeviation; minValue = reshape(minValue,1,1,3); maxValue = reshape(maxValue,1,1,3); meanValue = reshape(meanValue,1,1,3); stdValue = reshape(stdValue,1,1,3); for ii = 1:numClips video = data{ii,1}; resized = sizingFcn(video); % Cast the input to single. resized = single(resized); % Rescale the input between 0 and 1. resized = rescale(resized,0,1,InputMin=minValue,InputMax=maxValue); % Normalize using mean and standard deviation. resized = resized - meanValue; resized = resized./stdValue; data{ii,1} = resized; end function outData = cropVideo(data,cropFcn,inputSize) imsz = size(data,[1,2]); cropWindow = cropFcn(imsz,inputSize); numBatches = size(data,4); sz = [inputSize, size(data,3),numBatches]; outData = zeros(sz,'like',data); for b = 1:numBatches outData(:,:,:,b) = imcrop(data(:,:,:,b),cropWindow); end end end
createMiniBatchQueue
createMiniBatchQueue
функция создает minibatchqueue
объект, который обеспечивает miniBatchSize
объем данных от данного datastore. Это также создает DispatchInBackgroundDatastore
если параллельный пул открыт.
function mbq = createMiniBatchQueue(datastore, numOutputs, params) if params.DispatchInBackground && isempty(gcp('nocreate')) % Start a parallel pool, if DispatchInBackground is true, to dispatch % data in the background using the parallel pool. c = parcluster('local'); c.NumWorkers = params.NumWorkers; parpool('local',params.NumWorkers); end p = gcp('nocreate'); if ~isempty(p) datastore = DispatchInBackgroundDatastore(datastore, p.NumWorkers); end inputFormat(1:numOutputs-1) = "SSCTB"; outputFormat = "CB"; mbq = minibatchqueue(datastore, numOutputs, ... "MiniBatchSize", params.MiniBatchSize, ... "MiniBatchFcn", @batchVideo, ... "MiniBatchFormat", [inputFormat,outputFormat]); end
batchVideo
batchVideo
функционируйте обрабатывает в пакетном режиме видео и данные о метке из массивов ячеек. Это использует onehotencode
функция, чтобы закодировать основную истину категориальные метки в одногорячие массивы. Одногорячий закодированный массив содержит 1
в положении, соответствующем классу метки и 0
в любом положении.
function [video,labels] = batchVideo(video,labels) % Batch dimension: 5 video = cat(5,video{:}); % Batch dimension: 2 labels = cat(2,labels{:}); % Feature dimension: 1 labels = onehotencode(labels,1); end
modelGradients
modelGradients
функционируйте берет в качестве входа мини-пакет данных о RGB dlRGB
, и соответствующий целевой dlY
, и возвращает соответствующую потерю, градиенты потери относительно настраиваемых параметров и учебную точность. Чтобы вычислить градиенты, оцените modelGradients
функция с помощью dlfeval
функция в учебном цикле.
function [gradientsRGB,loss,acc,stateRGB] = modelGradients(slowFast,dlRGB,dlY) [dlYPredRGB,stateRGB] = forward(slowFast,dlRGB); dlYPred = squeezeIfNeeded(dlYPredRGB,dlY); loss = crossentropy(dlYPred,dlY); gradientsRGB = dlgradient(loss,slowFast.Learnables); % Calculate the accuracy of the predictions. [~,YTest] = max(dlY,[],1); [~,YPred] = max(dlYPred,[],1); acc = gather(extractdata(sum(YTest == YPred)./numel(YTest))); end
squeezeIfNeeded
squeezeIfNeeded
функционируйте берет в качестве предсказанных баллов, dlYPred
и соответствующий целевой Y
, и возвращает предсказанные баллы dlYPred
, после сжатия одноэлементных размерностей, если существует кто-либо.
function dlYPred = squeezeIfNeeded(dlYPred,Y) if ~isequal(size(Y),size(dlYPred)) dlYPred = squeeze(dlYPred); dlYPred = dlarray(dlYPred,dims(Y)); end end
updateLearnables
updateLearnables
функционируйте обновляет настраиваемые параметры классификатора видео SlowFast с градиентами и другими параметрами с помощью оптимизационной функции SGDM sgdmupdate
.
function [slowFast,velocity,learnRate] = updateLearnables(slowFast,gradients,params,velocity,iteration) % Determine the learning rate using the cosine-annealing learning rate schedule. learnRate = cosineAnnealingLearnRate(iteration, params); % Apply L2 regularization to the weights. learnables = slowFast.Learnables; idx = learnables.Parameter == "Weights"; gradients(idx,:) = dlupdate(@(g,w) g + params.L2Regularization*w,gradients(idx,:),learnables(idx,:)); % Update the network parameters using the SGDM optimizer. [slowFast, velocity] = sgdmupdate(slowFast,gradients,velocity,learnRate,params.Momentum); end
cosineAnnealingLearnRate
cosineAnnealingLearnRate
функция вычисляет скорость обучения на основе текущего номера итерации, минимальную скорость обучения, максимальную скорость обучения и количество итераций для отжига [3].
function lr = cosineAnnealingLearnRate(iteration,params) if iteration == params.NumIterations lr = params.MinLearningRate; return; end cosineNumIter = [0, params.CosineNumIterations]; csum = cumsum(cosineNumIter); block = find(csum >= iteration, 1,'first'); cosineIter = iteration - csum(block - 1); annealingIteration = mod(cosineIter,cosineNumIter(block)); cosineIteration = cosineNumIter(block); minR = params.MinLearningRate; maxR = params.MaxLearningRate; cosMult = 1 + cos(pi * annealingIteration / cosineIteration); lr = minR + ((maxR - minR) * cosMult / 2); end
aggregateConfusionMetric
aggregateConfusionMetric
функционируйте инкрементно заполняет матрицу беспорядка на основе предсказанных результатов YPred
и ожидаемые результаты YTest
.
function cmat = aggregateConfusionMetric(cmat,YTest,YPred) YTest = gather(extractdata(YTest)); YPred = gather(extractdata(YPred)); [m,n] = size(cmat); cmat = cmat + full(sparse(YTest,YPred,1,m,n)); end
saveData
saveData
функция сохраняет данный классификатор видео SlowFast, потерю и другие параметры обучения к MAT-файлу.
function bestLoss = saveData(slowFast,bestLoss,iteration,lossTrain,params) if iteration >= params.SaveBestAfterIteration trainingLoss = extractdata(gather(lossTrain)); if trainingLoss < bestLoss bestLoss = trainingLoss; slowFast = gatherFromGPUToSave(slowFast); data.BestLoss = bestLoss; data.slowFast = slowFast; data.Params = params; save(params.ModelFilename,'data'); end end end
gatherFromGPUToSave
gatherFromGPUToSave
функция собирает данные из графического процессора для того, чтобы сохранить модель на диск.
function slowfast = gatherFromGPUToSave(slowfast) if ~canUseGPU return; end slowfast.Learnables = gatherValues(slowfast.Learnables); slowfast.State = gatherValues(slowfast.State); function tbl = gatherValues(tbl) for ii = 1:height(tbl) tbl.Value{ii} = gather(tbl.Value{ii}); end end end
extractVideoScenes
extractVideoScenes
функционируйте извлекает учебные видеоданные из набора видео и его соответствующего набора меток сцены, при помощи функций sceneTimeRanges
и writeVideoScenes
.
function extractVideoScenes(groundTruthFolder,trainingFolder,classes) % If the video scenes are already extracted, no need to download % the data set and extract video scenes. if isfolder(trainingFolder) classFolders = fullfile(trainingFolder,string(classes)); allClassFoldersFound = true; for ii = 1:numel(classFolders) if ~isfolder(classFolders(ii)) allClassFoldersFound = false; break; end end if allClassFoldersFound return; end end if ~isfolder(groundTruthFolder) mkdir(groundTruthFolder); end downloadURL = "https://ssd.mathworks.com/supportfiles/vision/data/videoClipsAndSceneLabels.zip"; filename = fullfile(groundTruthFolder,"videoClipsAndSceneLabels.zip"); if ~exist(filename,'file') disp("Downloading the video clips and the corresponding scene labels to " + groundTruthFolder); websave(filename,downloadURL); end % Unzip the contents to the download folder. unzip(filename,groundTruthFolder); labelDataFiles = dir(fullfile(groundTruthFolder,"*_labelData.mat")); labelDataFiles = fullfile(groundTruthFolder,{labelDataFiles.name}'); numGtruth = numel(labelDataFiles); % Load the label data information and create ground truth objects. gTruth = groundTruth.empty(numGtruth,0); for ii = 1:numGtruth ld = load(labelDataFiles{ii}); videoFilename = fullfile(groundTruthFolder,ld.videoFilename); gds = groundTruthDataSource(videoFilename); gTruth(ii) = groundTruth(gds,ld.labelDefs,ld.labelData); end % Gather all the scene time ranges and the corresponding scene labels % using the sceneTimeRanges function. [timeRanges, sceneLabels] = sceneTimeRanges(gTruth); % Specify the subfolder names for each duration as the scene label names. foldernames = sceneLabels; % Delete the folder if it already exists. if isfolder(trainingFolder) rmdir(trainingFolder,'s'); end % Video files are written to the folders specified by the folderNames input. writeVideoScenes(gTruth,timeRanges,trainingFolder,foldernames); end
initializeTrainingProgressPlot
initializeTrainingProgressPlot
функция конфигурирует два графика для отображения учебной потери и учебной точности.
function plotters = initializeTrainingProgressPlot(params) if params.ProgressPlot % Plot the loss, training accuracy, and validation accuracy. figure % Loss plot subplot(2,1,1) plotters.LossPlotter = animatedline; xlabel("Iteration") ylabel("Loss") % Accuracy plot subplot(2,1,2) plotters.TrainAccPlotter = animatedline('Color','b'); legend('Training Accuracy','Location','northwest'); xlabel("Iteration") ylabel("Accuracy") else plotters = []; end end
updateProgressPlot
updateProgressPlot
функционируйте обновляет график прогресса с информацией о потере и точности во время обучения.
function updateProgressPlot(params,plotters,epoch,iteration,start,lossTrain,accuracyTrain) if params.ProgressPlot % Update the training progress. D = duration(0,0,toc(start),"Format","hh:mm:ss"); title(plotters.LossPlotter.Parent,"Epoch: " + epoch + ", Elapsed: " + string(D)); addpoints(plotters.LossPlotter,iteration,double(gather(extractdata(lossTrain)))); addpoints(plotters.TrainAccPlotter,iteration,accuracyTrain); drawnow end end
initializeVerboseOutput
initializeVerboseOutput
функционируйте отображает заголовки столбцов для таблицы учебных значений, которая показывает эпоху, мини-пакетную точность и другие учебные значения.
function initializeVerboseOutput(params) if params.Verbose disp(" ") if canUseGPU disp("Training on GPU.") else disp("Training on CPU.") end p = gcp('nocreate'); if ~isempty(p) disp("Training on parallel cluster '" + p.Cluster.Profile + "'. ") end disp("NumIterations:" + string(params.NumIterations)); disp("MiniBatchSize:" + string(params.MiniBatchSize)); disp("Classes:" + join(string(params.Classes),",")); disp("|===========================================================================================|") disp("| Epoch | Iteration | Time Elapsed | Mini-Batch | Mini-Batch | Base Learning | Train Time |") disp("| | | (hh:mm:ss) | Accuracy | Loss | Rate | (hh:mm:ss) |") disp("|===========================================================================================|") end end
displayVerboseOutputEveryEpoch
displayVerboseOutputEveryEpoch
функция отображает многословный вывод учебных значений, таких как эпоха, мини-пакетная точность и мини-пакетная потеря.
function displayVerboseOutputEveryEpoch(params,start,learnRate,epoch,iteration,... accTrain,lossTrain,trainTime) if params.Verbose D = duration(0,0,toc(start),'Format','hh:mm:ss'); trainTime = duration(0,0,trainTime,'Format','hh:mm:ss'); lossTrain = gather(extractdata(lossTrain)); lossTrain = compose('%.4f',lossTrain); accTrain = composePadAccuracy(accTrain); learnRate = compose('%.13f',learnRate); disp("| " + ... pad(string(epoch),5,'both') + " | " + ... pad(string(iteration),9,'both') + " | " + ... pad(string(D),12,'both') + " | " + ... pad(string(accTrain),10,'both') + " | " + ... pad(string(lossTrain),10,'both') + " | " + ... pad(string(learnRate),13,'both') + " | " + ... pad(string(trainTime),10,'both') + " |") end function acc = composePadAccuracy(acc) acc = compose('%.2f',acc*100) + "%"; acc = pad(string(acc),6,'left'); end end
endVerboseOutput
endVerboseOutput
функционируйте отображает конец многословного выхода во время обучения.
function endVerboseOutput(params) if params.Verbose disp("|===========================================================================================|") end end
[1] Кристоф Файхтенхофер, Хэоки Фэн, Джитендра Малик и Кэйминг он. "Сети SlowFast для видео распознавания". Продолжения конференции по IEEE по компьютерному зрению и распознаванию образов (CVPR), 2019.
[2] Уилл Кей, Жоао Карреира, Карен Симонян, Брайн Чжан, Хлоя Хиллир, Sudheendra Vijayanarasimhan, Фабио Виола, Тим Грин, Тревор Бэк, Пол Нацев, Мустафа Сулейман, Эндрю Зиссермен. "Набор Видеоданных Человеческой деятельности кинетики". arXiv предварительно распечатывают arXiv:1705.06950, 2017.
[3] Лощилов, Илья и Франк Хуттер. "SGDR: стохастический градиентный спуск с горячими перезапусками". Международный Conferencee на изучении представлений 2017. Тулон, Франция: ICLR, 2017.