Этот пример демонстрирует, как сгенерировать код CUDA ® для сети долгой краткосрочной памяти (LSTM). Пример генерирует приложение MEX, которое делает предсказания на каждом шаге входного timeseries. Демонстрируются два метода: метод, использующий стандартную сеть LSTM, и метод, использующий поведение одной и той же сети LSTM с учетом состояния. Этот пример использует данные датчика акселерометра со смартфона, носимого на корпусе, и делает предсказания по активности пользователя. Движения пользователей классифицируются в одну из пяти категорий, а именно танцы, бег, сидение, стоя и ходьба. В примере используется предварительно обученная сеть LSTM. Для получения дополнительной информации о обучении смотрите пример классификации последовательности с использованием глубокого обучения (Deep Learning Toolbox) из Deep Learning Toolbox™.
Необходимый
Этот пример генерирует CUDA MEX и имеет следующие требования к третьим лицам.
CUDA включает графический процессор NVIDIA ® и совместимый драйвер.
Дополнительный
Для сборок, не являющихся MEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.
Набор инструментальных средств NVIDIA.
Библиотека NVIDIA cuDNN.
Переменные окружения для компиляторов и библиотек. Для получения дополнительной информации см. раздел «Оборудование сторонних производителей» и «Настройка продуктов для подготовки».
Используйте coder.checkGpuInstall
функция для проверки правильности настройки компиляторов и библиотек, необходимых для выполнения этого примера.
envCfg = coder.gpuEnvConfig('host'); envCfg.DeepLibTarget = 'cudnn'; envCfg.DeepCodegen = 1; envCfg.Quiet = 1; coder.checkGpuInstall(envCfg);
lstmnet_predict
Функция точки входаСеть LSTM от последовательности к последовательности позволяет вам делать различные предсказания для каждого отдельного временного шага последовательности данных. Функция точки входа lstmnet_predict.m принимает входную последовательность и передает ее обученной сети LSTM для предсказания. В частности, функция использует сеть LSTM, обученную в примере Sequence to Sequence Classification Using Deep Learning. Функция загружает сетевой объект из lstmnet_predict.mat
файл в постоянную переменную и повторно использует постоянный объект при последующих вызовах предсказания.
Чтобы отобразить интерактивную визуализацию сетевой архитектуры и информацию о слоях сети, используйте analyzeNetwork
(Deep Learning Toolbox) функция.
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 для lstmnet_predict.m
функция точки входа, создайте объект строения GPU и укажите цель, которая будет MEX. Установите целевой язык на C++. Создайте объект строения глубокого обучения, который задает целевую библиотеку как cuDNN. Прикрепите этот объект глубокого строения обучения к объекту графического процессора строения.
cfg = coder.gpuConfig('mex'); cfg.TargetLang = 'C++'; cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
Во время компиляции GPU Coder™ должны знать типы данных всех входов в функцию точки входа. Укажите тип и размер входного параметра для codegen
команда при помощи coder.typeof
функция. В данном примере вход имеет двойной тип данных со значением размерности признаков три и переменную длину последовательности. Установка длины последовательности в виде переменных размеров позволяет нам выполнить предсказание на вход последовательности любой длины.
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').
Загрузите 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"])
Функции 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
Если вы хотите выполнить предсказание сразу для многих наблюдений, можно сгруппировать наблюдения вместе в массиве ячеек и передать массив ячеек для предсказания. Массив ячеек должен быть столбцом массивом ячеек, и каждая камера должен содержать одно наблюдение. Каждое наблюдение должно иметь одну и ту же размерность признаков, но длины последовательности могут варьироваться. В этом примере 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}
Вместо того, чтобы передавать все timeseries, чтобы предсказать за один шаг, мы можем запустить предсказание на входе, транслируя потоком в один временной интервал за раз, используя функцию predictAndUpdateState
(Deep Learning Toolbox) Эта функция вводит вход, создает выходное предсказание и обновляет внутреннее состояние сети, чтобы будущие предсказания учитывали этот исходный вход.
Функция точки входа lstmnet_predict_and_update.m вводит однократный вход и обрабатывает вход с помощью predictAndUpdateState
(Deep Learning Toolbox) функция. 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