Генерация кода для сети LSTM с последовательностью в последовательности

Этот пример демонстрирует, как сгенерировать код CUDA ® для сети долгой краткосрочной памяти (LSTM). Пример генерирует приложение MEX, которое делает предсказания на каждом шаге входного timeseries. Демонстрируются два метода: метод, использующий стандартную сеть LSTM, и метод, использующий поведение одной и той же сети LSTM с учетом состояния. Этот пример использует данные датчика акселерометра со смартфона, носимого на корпусе, и делает предсказания по активности пользователя. Движения пользователей классифицируются в одну из пяти категорий, а именно танцы, бег, сидение, стоя и ходьба. В примере используется предварительно обученная сеть LSTM. Для получения дополнительной информации о обучении смотрите пример классификации последовательностей с использованием глубокого обучения из Deep Learning Toolbox™.

Необходимые условия для третьих лиц

Необходимый

Этот пример генерирует CUDA MEX и имеет следующие требования к третьим лицам.

  • CUDA включает графический процессор NVIDIA ® и совместимый драйвер.

Дополнительный

Для сборок, не являющихся MEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.

Проверьте окружение GPU

Используйте coder.checkGpuInstall (GPU Coder) для проверки правильности настройки компиляторов и библиотек, необходимых для выполнения этого примера.

envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

The lstmnet_predict Функция точки входа

Сеть LSTM от последовательности к последовательности позволяет вам делать различные предсказания для каждого отдельного временного шага последовательности данных. Функция точки входа lstmnet_predict.m принимает входную последовательность и передает ее обученной сети LSTM для предсказания. В частности, функция использует сеть LSTM, обученную в примере Sequence to Sequence Classification Using Deep Learning. Функция загружает сетевой объект из lstmnet_predict.mat файл в постоянную переменную и повторно использует постоянный объект при последующих вызовах предсказания.

Чтобы отобразить интерактивную визуализацию сетевой архитектуры и информацию о слоях сети, используйте analyzeNetwork функция.

type('lstmnet_predict.m')
function out = lstmnet_predict(in) %#codegen

% Copyright 2019 The MathWorks, Inc. 

persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork('lstmnet.mat');
end

% pass in input   
out = predict(mynet,in); 

Сгенерируйте CUDA MEX

Чтобы сгенерировать CUDA MEX для lstmnet_predict.m функция точки входа, создайте объект строения GPU и укажите цель, которая будет MEX. Установите целевой язык на C++. Создайте объект строения глубокого обучения, который задает целевую библиотеку как cuDNN. Прикрепите этот объект глубокого строения обучения к объекту графического процессора строения.

cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');

Во время компиляции GPU Coder™ должны знать типы данных всех входов в функцию точки входа. Укажите тип и размер входного параметра для codegen (MATLAB Coder) команда при помощи coder.typeof (MATLAB Coder) функция. В данном примере вход имеет двойной тип данных со значением размерности признаков три и переменную длину последовательности. Установка длины последовательности в виде переменных размеров позволяет нам выполнить предсказание на вход последовательности любой длины.

matrixInput = coder.typeof(double(0),[3 Inf],[false true]);

Выполните команду codegen.

codegen -config cfg lstmnet_predict -args {matrixInput} -report
Code generation successful: To view the report, open('codegen/mex/lstmnet_predict/html/report.mldatx').

Запуск сгенерированного MEX на тестовых данных

Загрузите HumanActivityValidate MAT-файл. Этот MAT-файл хранит переменную XValidate который содержит выборочный timeseries датчика, на которых можно протестировать сгенерированный код. Функции lstmnet_predict_mex по первому наблюдению.

load HumanActivityValidate
YPred1 = lstmnet_predict_mex(XValidate{1});

YPred1 является числовой матрицей 5 на 53888, содержащей вероятности пяти классов для каждого из 53888 временных шагов. Для каждого временного шага найдите предсказанный класс путем вычисления индекса максимальной вероятности.

[~, maxIndex] = max(YPred1, [], 1);

Связать индексы максимальной вероятности с соответствующей меткой. Отображение первых десяти меток. Из результатов можно увидеть, что сеть предсказала человеку сидеть первые десять временных шагов.

labels = categorical({'Dancing', 'Running', 'Sitting', 'Standing', 'Walking'});
predictedLabels1 = labels(maxIndex);
disp(predictedLabels1(1:10))
  Columns 1 through 6

     Sitting      Sitting      Sitting      Sitting      Sitting      Sitting 

  Columns 7 through 10

     Sitting      Sitting      Sitting      Sitting 

Сравнение предсказаний с тестовыми данными

Используйте график, чтобы сравнить выходные данные MEX с тестовыми данными.

figure
plot(predictedLabels1,'.-');
hold on
plot(YValidate{1});
hold off

xlabel("Time Step")
ylabel("Activity")
title("Predicted Activities")
legend(["Predicted" "Test Data"])

Вызов сгенерированного MEX для наблюдения с другой длиной последовательности

Функции lstmnet_predict_mex на втором наблюдении с другой длиной последовательности. В этом примере XValidate{2} имеет длину последовательности 64480, в то время как XValidate{1} имел длину последовательности 53888. Сгенерированный код правильно обрабатывает предсказание, потому что мы определили размерность длины последовательности как переменный.

YPred2 = lstmnet_predict_mex(XValidate{2});
[~, maxIndex] = max(YPred2, [], 1);
predictedLabels2 = labels(maxIndex);
disp(predictedLabels2(1:10))
  Columns 1 through 6

     Sitting      Sitting      Sitting      Sitting      Sitting      Sitting 

  Columns 7 through 10

     Sitting      Sitting      Sitting      Sitting 

Сгенерируйте MEX, который принимает в нескольких наблюдениях

Если вы хотите выполнить предсказание сразу для многих наблюдений, можно сгруппировать наблюдения вместе в массиве ячеек и передать массив ячеек для предсказания. Массив ячеек должен быть столбцом массивом ячеек, и каждая камера должен содержать одно наблюдение. Каждое наблюдение должно иметь одну и ту же размерность признаков, но длины последовательности могут варьироваться. В этом примере XValidate содержит пять наблюдений. Чтобы сгенерировать MEX, который может взять XValidate в качестве входных параметров задайте входной тип массива ячеек 5 на 1. Кроме того, укажите, что каждая камера имеет тот же тип, что и matrixInputтип, заданный для одиночного наблюдения в предыдущей codegen команда.

matrixInput = coder.typeof(double(0),[3 Inf],[false true]);
cellInput = coder.typeof({matrixInput}, [5 1]);

codegen -config cfg lstmnet_predict -args {cellInput} -report

YPred3 = lstmnet_predict_mex(XValidate);
Code generation successful: To view the report, open('codegen/mex/lstmnet_predict/html/report.mldatx').

Этот выход является массивом ячеек 5 на 1 предсказаниях для пяти пройденных наблюдений.

disp(YPred3)
    {5×53888 single}
    {5×64480 single}
    {5×53696 single}
    {5×56416 single}
    {5×50688 single}

Сгенерируйте MEX с состоянием LSTM

Вместо того, чтобы передавать все timeseries, чтобы предсказать за один шаг, мы можем запустить предсказание на входе, транслируя потоком в один временной интервал за раз, используя функцию predictAndUpdateState Эта функция принимает вход, создает выход предсказание и обновляет внутреннее состояние сети, так что будущие предсказания учитывают этот начальный вход.

Функция точки входа lstmnet_predict_and_update.m вводит однократный вход и обрабатывает вход с помощью predictAndUpdateState функция. predictAndUpdateState выводит предсказание для входа временного интервала и обновляет сеть так, чтобы последующие входы рассматривались как последующие временные интервалы той же выборки. После прохождения во всех timesteps по одному за раз, результат выхода такой же, как если бы все timesteps были переданы как один вход.

type('lstmnet_predict_and_update.m')
function out = lstmnet_predict_and_update(in) %#codegen

% Copyright 2019 The MathWorks, Inc. 

persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork('lstmnet.mat');
end

% pass in input
[mynet, out] = predictAndUpdateState(mynet,in);

Запустите codegen для этого нового файла проекта. Поскольку мы принимаем в одно время каждый вызов, мы задаем matrixInput иметь фиксированную размерность последовательности 1 вместо переменной длины последовательности.

matrixInput = coder.typeof(double(0),[3 1]);
codegen -config cfg lstmnet_predict_and_update -args {matrixInput} -report
Code generation successful: To view the report, open('codegen/mex/lstmnet_predict_and_update/html/report.mldatx').

Запустите сгенерированный MEX в первой валидации выборки первом временном шаге.

firstSample = XValidate{1};
firstTimestep = firstSample(:,1);
YPredStateful = lstmnet_predict_and_update_mex(firstTimestep);
[~, maxIndex] = max(YPredStateful, [], 1);
predictedLabelsStateful1 = labels(maxIndex)
predictedLabelsStateful1 = 

  categorical

     Sitting 

Сравните метку выхода с основной истиной.

YValidate{1}(1)
ans = 

  categorical

     Sitting 

Для просмотра документации необходимо авторизоваться на сайте