Этот пример показывает, как интегрировать код CUDA®, сгенерированный для нейронной сети для глубокого обучения в Simulink®. В то время как GPU Coder™ не поддержан для блоков Simulink, можно все еще использовать вычислительную мощность графических процессоров в Simulink путем генерации динамически подключаемой библиотеки (dll) с GPU Coder и затем интеграции его в Simulink как Блок s-function при помощи Legacy Code Tool. Обнаружение маршрута с GPU Coder используется в качестве примера, чтобы продемонстрировать эту концепцию. Исходный пример использовал файл C++ с функциями OpenCV, чтобы считать кадры, чертить маршруты и наложить информацию о частоте кадров о видеовыходе. Однако этот пример использует блоки Simulink от Computer Vision Toolbox™, чтобы выполнить те же операции.

Предпосылки

  • CUDA включил NVIDIA®, графический процессор с вычисляет возможность 3.2 или выше.

  • NVIDIA инструментарий CUDA и драйвер.

  • Библиотека NVIDIA cuDNN (v7).

  • Переменные окружения для компиляторов и библиотек. Для получения информации о поддерживаемых версиях компиляторов и библиотек, смотрите Сторонние продукты. Для подготовки переменных окружения смотрите Переменные окружения.

  • Simulink для создания модели.

  • Computer Vision Toolbox™ для видео средства чтения, средства просмотра и функциональности маркировки маршрута используется в примере.

  • Deep Learning Toolbox™ для использования объекта SeriesNetwork.

Создайте папку и скопируйте соответствующие файлы

Следующая строка кода создает папку в вашей текущей рабочей папке (pwd) и копирует все соответствующие файлы в эту папку. Если вы не хотите выполнять эту операцию или если вы не можете сгенерировать файлы в этой папке, изменить вашу текущую рабочую папку.

gpucoderdemo_setup('gpucoderdemo_lane_detection_simulink');

Проверьте среду графического процессора

Используйте coder.checkGpuInstall, функционируют и проверяют, что компиляторы и библиотеки, необходимые для выполнения этого примера, настраиваются правильно.

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

Обзор рабочего процесса

Следующая схема иллюстрирует общую процедуру для использования Legacy Code Tool, чтобы интегрировать код CUDA, сгенерированный для нейронной сети для глубокого обучения в Simulink.

Получите предварительно обученный SeriesNetwork

[laneNet, coeffMeans, coeffStds] = getLaneDetectionNetwork();

Архитектура предварительно обученного SeriesNetwork подобна AlexNet, за исключением того, что последние несколько слоев заменяются меньшим полносвязным слоем и регрессией выходной слой. Эта сеть берет вход изображений и выходные параметры два контура маршрута, которые соответствуют левым и правым маршрутам автомобиля, оборудованного датчиком. Каждый контур маршрута может быть представлен параболическим уравнением. Здесь, боковое смещение и продольное расстояние от автомобиля. Сетевые выходные параметры эти три параметра и описание параболического уравнения для левых и правых контуров маршрута.

Основная функция точки входа

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

Сгенерируйте DLL для функции

Переменные coeffStds и coeffMeans содержат среднее значение и значения станд. от обучившего сеть. Эти значения требуются во время симуляции. Чтобы запустить функцию detect_lane на графическом процессоре от Simulink, сгенерируйте разделяемую библиотеку при помощи GPU Coder. Входные параметры к функции detect_lane являются кадром видео, средним значением и значениями станд. Переданное использование значений опции -args отражает размер этих входных параметров. Скопируйте сгенерированную библиотеку в папку верхнего уровня.

coeffStds = [0.002995595096857,0.076600147330248,0.631288082601997,0.002600128777275,0.073641936476251,0.984567040148445];
coeffMeans = [-1.939450143265110e-04,1.557727430093527e-04,1.473991581706893,-1.909623131136531e-04,0.004474616468621,-1.378729416735388];
Isize = single(zeros(227,227));

cfg = coder.gpuConfig('dll');
cfg.TargetLang = 'C++';
cfg.GenerateReport = true;
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -args {ones(227,227,3,'single'),ones(1,6,'double'),ones(1,6,'double')} -config cfg detect_lane

if ispc
    copyfile(fullfile(pwd, 'codegen','dll', 'detect_lane','detect_lane.dll'), pwd);
else
    copyfile(fullfile(pwd, 'codegen','dll', 'detect_lane','detect_lane.so'), pwd);
end
Code generation successful: To view the report, open('codegen/dll/detect_lane/html/report.mldatx').

Предупреждение выдано относительно необъединенного доступа к переменной входных данных. Это вызвано тем, что команда codegen генерирует главный столбцом код. В целях этого примера может быть проигнорировано это предупреждение.

Сгенерируйте и скомпилируйте S-функцию

Пример обнаружения маршрута зависит от времени выполнения CUDA NVIDIA, cuBLAS, и cuDNN библиотеки. Структура данных Legacy Code Tool используется, чтобы задать:

  • Имя для S-функции

  • Спецификации для существующей функции C++

  • Вся библиотека, заголовочные файлы, требуемые для компиляции и их путей

  • Опции для сгенерированной S-функции

После определения структуры используйте функцию legacy_code для:

  • Инициализируйте структуру данных Legacy Code Tool для функции C++

  • Сгенерируйте S-функцию для использования во время симуляции

  • Скомпилируйте и соедините сгенерированную S-функцию в динамически загружаемый исполняемый файл (MEX)

  • Сгенерируйте Блок s-function маскированный для вызова сгенерированной S-функции

srcPath = fullfile(pwd, 'codegen', 'dll', 'detect_lane');

if ispc
    cuPath = getenv('CUDA_PATH');
    cudaLibPath = fullfile(cuPath,'lib','x64');
    cudaIncPath = fullfile(cuPath,'include');

    cudnnPath = getenv('NVIDIA_CUDNN');
    cudnnIncPath = fullfile(cudnnPath,'include');
    cudnnLibPath = fullfile(cudnnPath,'lib','x64');

    libs = {'detect_lane.lib','cudart.lib','cublas.lib','cudnn.lib'};

else
    [~,nvccPath] = system('which nvcc');
    nvccPath = regexp(nvccPath, '[\f\n\r]', 'split');
    cuPath = erase(nvccPath{1},'/bin/nvcc');
    cudaLibPath = fullfile(cuPath,'lib64');
    cudaIncPath = fullfile(cuPath,'include');

    cudnnPath = getenv('NVIDIA_CUDNN');
    cudnnIncPath = fullfile(cudnnPath,'include');
    cudnnLibPath = fullfile(cudnnPath,'lib64');

    libs = {'detect_lane.so','libcudart.so','libcublas.so','libcudnn.so'};
end

headerPath = {srcPath;cudnnIncPath;cudaIncPath};
libPath = {srcPath;cudnnLibPath;cudaLibPath};

% Define the Legacy Code Tool data structure
def = legacy_code('initialize');
def.SFunctionName = 'lane_detect_sfun';
def.OutputFcnSpec = 'void detect_lane(single u1[154587],double u2[6],double u3[6],uint8 y1[1],single y2[56],single y3[56])';
def.IncPaths = headerPath;
def.HeaderFiles = {'detect_lane.h'};
def.LibPaths = libPath;
def.HostLibFiles = libs;
def.Options.useTlcWithAccel = false;
def.Options.language = 'C++';

legacy_code('sfcn_cmex_generate', def);
legacy_code('compile', def);
### Start Compiling lane_detect_sfun
    mex('lane_detect_sfun.cpp', '-I/mathworks/devel/sbs/37/vravicha.lcmFirst/matlab/toolbox/gpucoder/gpucoderdemos/gpucoderdemo_lane_detection_simulink2/codegen/dll/detect_lane', '-I/mathworks/hub/3rdparty/R2019a/3840803/glnxa64/cuDNN/cuda/include', '-I/usr/local/cuda/include', '-I/mathworks/devel/sbs/37/vravicha.lcmFirst/matlab/toolbox/gpucoder/gpucoderdemos/gpucoderdemo_lane_detection_simulink2', '/mathworks/devel/sbs/37/vravicha.lcmFirst/matlab/toolbox/gpucoder/gpucoderdemos/gpucoderdemo_lane_detection_simulink2/codegen/dll/detect_lane/detect_lane.so', '/usr/local/cuda/lib64/libcudart.so', '/usr/local/cuda/lib64/libcublas.so', '/mathworks/hub/3rdparty/R2019a/3840803/glnxa64/cuDNN/cuda/lib64/libcudnn.so')
Building with 'g++'.
MEX completed successfully.
### Finish Compiling lane_detect_sfun
### Exit

Аргумент OutputFcnSpec задает функцию что S-вызовы-функции на каждом временном шаге. Заголовочный файл detect_lane.h в codegen папке предоставляет функциональную информацию о спецификации. Аргументы функции detect_lane должны быть сопоставлены с Блоком s-function Simulink при помощи исключительно пронумерованной лексемы u для входных портов и лексемы y для выходных портов. Типы данных генерации кода, заданные в tmwtypes.h, должны также быть сопоставлены с теми тот Simulink поддержки. Для получения дополнительной информации смотрите Объявление Спецификаций Функции Legacy Code Tool. Поскольку этот пример уже содержит полную модель Simulink, генерация Блока s-function не выполняется. Чтобы сгенерировать Блок s-function, использовать

legacy_code('slblock_generate', def);

Создайте модель Simulink для обнаружения маршрута

Весь пред - и операции последующей обработки, сделанные в файле main_lanenet.cpp исходного примера, должен быть перемещен в Simulink. Входная подсистема Обработки видеоданных удаляет нормализацию, выполняемую мультимедийным блоком читателя, и изменяет размер входного кадра видео к входному размеру слоя сети обнаружения маршрута, 227x227x3. Это затем преобразовывает 3D кадр видео в одномерный вектор, требуемый библиотекой detect_lane. Включенная подсистема Точек Маршрута выполняет обработку левых и правых точек маршрута, чтобы сделать его подходящим для блока Draw Lanes. Модель Simulink использует видеодисплей, чтобы показать обнаружение маршрута на демонстрационном видео.

open_system('main_lanenet');
set_param('main_lanenet', 'SimulationCommand', 'update');

Запустите модель Simulink (обнаружение маршрута)

Запустите симуляцию, чтобы видеть обнаружение маршрута на демонстрационном видео.

sim('main_lanenet', 'timeout', 30);

Команда выполнения: Очистка

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

close_system('main_lanenet');
clear mex
cleanup