В этом примере показано, как сгенерировать код CUDA ® MEX для приложения обнаружения и распознавания дорожных знаков, которое использует глубокое обучение. Обнаружение и распознавание дорожных знаков является важным приложением для систем помощи драйверу, оказания помощи и предоставления драйверу информации о дорожных знаках.
В этом примере обнаружения и распознавания дорожных знаков вы выполняете три шага - обнаружение, Non-Maximal Suppression (NMS) и распознавание. Во-первых, пример обнаруживает дорожные знаки на вход изображении с помощью сети обнаружения объектов, которая является вариантом сети You Only Look Once (YOLO). Затем перекрывающиеся обнаружения подавляются при помощи алгоритма NMS. Наконец, сеть распознавания классифицирует обнаруженные дорожные знаки.
Необходимый
Этот пример генерирует CUDA MEX и имеет следующие требования к третьим лицам.
Графический процессор NVIDIA с поддержкой CUDA ® и совместимый драйвер.
Дополнительный
Для сборок, не являющихся MEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.
Набор инструментальных средств NVIDIA.
Библиотека NVIDIA cuDNN.
Переменные окружения для компиляторов и библиотек. Для получения дополнительной информации см. раздел «Оборудование сторонних производителей» и «Настройка продуктов для подготовки».
Используйте coder.checkGpuInstall
функция для проверки правильности настройки компиляторов и библиотек, необходимых для выполнения этого примера.
envCfg = coder.gpuEnvConfig('host'); envCfg.DeepLibTarget = 'cudnn'; envCfg.DeepCodegen = 1; envCfg.Quiet = 1; coder.checkGpuInstall(envCfg);
Сеть обнаружения обучается в среде Darknet и импортируется в MATLAB ® для вывода. Поскольку размер дорожного знака относительно невелик относительно размера изображения, а количество обучающих выборок на класс меньше в обучающих данных, все дорожные знаки рассматриваются как один класс для настройки сети обнаружения.
Сеть обнаружения разделяет вход изображение на сетку 7 на 7. Каждая сетевая камера обнаруживает дорожный знак, если центр дорожного знака попадает в сетевую камеру. Каждая камера предсказывает два ограничивающих прямоугольника и оценки достоверности для этих ограничивающих прямоугольников. Оценками достоверности указать, содержит ли поле объект или нет. Каждая камера предсказывает вероятность нахождения знака трафика в сетевую камеру. Итоговый счет является продуктом предыдущих счетов. Вы применяете порог 0,2 для этого итогового счета, чтобы выбрать обнаружения.
Сеть распознавания обучается на тех же изображениях при помощи MATLAB.
Вспомогательный скрипт trainRecognitionnet.m показывает обучение сети распознавания.
Загрузите сети обнаружения и распознавания.
getTsdr();
Сеть обнаружения содержит 58 слоев, включая свертку, утечку ReLU и полносвязные слои.
load('yolo_tsr.mat');
yolo.Layers
ans = 58×1 Layer array with layers: 1 'input' Image Input 448×448×3 images 2 'conv1' Convolution 64 7×7×3 convolutions with stride [2 2] and padding [3 3 3 3] 3 'relu1' Leaky ReLU Leaky ReLU with scale 0.1 4 'pool1' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 5 'conv2' Convolution 192 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 6 'relu2' Leaky ReLU Leaky ReLU with scale 0.1 7 'pool2' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 8 'conv3' Convolution 128 1×1×192 convolutions with stride [1 1] and padding [0 0 0 0] 9 'relu3' Leaky ReLU Leaky ReLU with scale 0.1 10 'conv4' Convolution 256 3×3×128 convolutions with stride [1 1] and padding [1 1 1 1] 11 'relu4' Leaky ReLU Leaky ReLU with scale 0.1 12 'conv5' Convolution 256 1×1×256 convolutions with stride [1 1] and padding [0 0 0 0] 13 'relu5' Leaky ReLU Leaky ReLU with scale 0.1 14 'conv6' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 15 'relu6' Leaky ReLU Leaky ReLU with scale 0.1 16 'pool6' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 17 'conv7' Convolution 256 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0] 18 'relu7' Leaky ReLU Leaky ReLU with scale 0.1 19 'conv8' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 20 'relu8' Leaky ReLU Leaky ReLU with scale 0.1 21 'conv9' Convolution 256 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0] 22 'relu9' Leaky ReLU Leaky ReLU with scale 0.1 23 'conv10' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 24 'relu10' Leaky ReLU Leaky ReLU with scale 0.1 25 'conv11' Convolution 256 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0] 26 'relu11' Leaky ReLU Leaky ReLU with scale 0.1 27 'conv12' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 28 'relu12' Leaky ReLU Leaky ReLU with scale 0.1 29 'conv13' Convolution 256 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0] 30 'relu13' Leaky ReLU Leaky ReLU with scale 0.1 31 'conv14' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 32 'relu14' Leaky ReLU Leaky ReLU with scale 0.1 33 'conv15' Convolution 512 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0] 34 'relu15' Leaky ReLU Leaky ReLU with scale 0.1 35 'conv16' Convolution 1024 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1] 36 'relu16' Leaky ReLU Leaky ReLU with scale 0.1 37 'pool16' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 38 'conv17' Convolution 512 1×1×1024 convolutions with stride [1 1] and padding [0 0 0 0] 39 'relu17' Leaky ReLU Leaky ReLU with scale 0.1 40 'conv18' Convolution 1024 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1] 41 'relu18' Leaky ReLU Leaky ReLU with scale 0.1 42 'conv19' Convolution 512 1×1×1024 convolutions with stride [1 1] and padding [0 0 0 0] 43 'relu19' Leaky ReLU Leaky ReLU with scale 0.1 44 'conv20' Convolution 1024 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1] 45 'relu20' Leaky ReLU Leaky ReLU with scale 0.1 46 'conv21' Convolution 1024 3×3×1024 convolutions with stride [1 1] and padding [1 1 1 1] 47 'relu21' Leaky ReLU Leaky ReLU with scale 0.1 48 'conv22' Convolution 1024 3×3×1024 convolutions with stride [2 2] and padding [1 1 1 1] 49 'relu22' Leaky ReLU Leaky ReLU with scale 0.1 50 'conv23' Convolution 1024 3×3×1024 convolutions with stride [1 1] and padding [1 1 1 1] 51 'relu23' Leaky ReLU Leaky ReLU with scale 0.1 52 'conv24' Convolution 1024 3×3×1024 convolutions with stride [1 1] and padding [1 1 1 1] 53 'relu24' Leaky ReLU Leaky ReLU with scale 0.1 54 'fc25' Fully Connected 4096 fully connected layer 55 'relu25' Leaky ReLU Leaky ReLU with scale 0.1 56 'fc26' Fully Connected 539 fully connected layer 57 'softmax' Softmax softmax 58 'classoutput' Classification Output crossentropyex with '1' and 538 other classes
Сеть распознавания содержит 14 слоев, включая свертку, полностью соединенные и выходные слои классификации.
load('RecognitionNet.mat');
convnet.Layers
ans = 14×1 Layer array with layers: 1 'imageinput' Image Input 48×48×3 images with 'zerocenter' normalization and 'randfliplr' augmentations 2 'conv_1' Convolution 100 7×7×3 convolutions with stride [1 1] and padding [0 0 0 0] 3 'relu_1' ReLU ReLU 4 'maxpool_1' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 5 'conv_2' Convolution 150 4×4×100 convolutions with stride [1 1] and padding [0 0 0 0] 6 'relu_2' ReLU ReLU 7 'maxpool_2' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 8 'conv_3' Convolution 250 4×4×150 convolutions with stride [1 1] and padding [0 0 0 0] 9 'maxpool_3' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 10 'fc_1' Fully Connected 300 fully connected layer 11 'dropout' Dropout 90% dropout 12 'fc_2' Fully Connected 35 fully connected layer 13 'softmax' Softmax softmax 14 'classoutput' Classification Output crossentropyex with '0' and 34 other classes
tsdr_predict
Функция точки входаФункция точки входа tsdr_predict.m принимает изображение и обнаруживает дорожные знаки в изображении при помощи сети обнаружения. Функция подавляет перекрывающиеся обнаружения (NMS) при помощи selectStrongestBbox
и распознает знак трафика при помощи сети распознавания. Функция загружает сетевые объекты из yolo_tsr.mat
в постоянную переменную детектионнет и RecognitionNet.mat
в постоянную переменную распознавания. Функция повторно использует постоянные объекты при последующих вызовах.
type('tsdr_predict.m')
function [selectedBbox,idx] = tsdr_predict(img) %#codegen % This function detects the traffic signs in the image using Detection Network % (modified version of Yolo) and recognizes(classifies) using Recognition Network % % Inputs : % % im : Input test image % % Outputs : % % selectedBbox : Detected bounding boxes % idx : Corresponding classes % Copyright 2017-2019 The MathWorks, Inc. coder.gpu.kernelfun; % resize the image img_rz = imresize(img,[448,448]); % Converting into BGR format img_rz = img_rz(:,:,3:-1:1); img_rz = im2single(img_rz); %% TSD persistent detectionnet; if isempty(detectionnet) detectionnet = coder.loadDeepLearningNetwork('yolo_tsr.mat','Detection'); end predictions = detectionnet.activations(img_rz,56,'OutputAs','channels'); %% Convert predictions to bounding box attributes classes = 1; num = 2; side = 7; thresh = 0.2; [h,w,~] = size(img); boxes = single(zeros(0,4)); probs = single(zeros(0,1)); for i = 0:(side*side)-1 for n = 0:num-1 p_index = side*side*classes + i*num + n + 1; scale = predictions(p_index); prob = zeros(1,classes+1); for j = 0:classes class_index = i*classes + 1; tempProb = scale*predictions(class_index+j); if tempProb > thresh row = floor(i / side); col = mod(i,side); box_index = side*side*(classes + num) + (i*num + n)*4 + 1; bxX = (predictions(box_index + 0) + col) / side; bxY = (predictions(box_index + 1) + row) / side; bxW = (predictions(box_index + 2)^2); bxH = (predictions(box_index + 3)^2); prob(j+1) = tempProb; probs = [probs;tempProb]; boxX = (bxX-bxW/2)*w+1; boxY = (bxY-bxH/2)*h+1; boxW = bxW*w; boxH = bxH*h; boxes = [boxes; boxX,boxY,boxW,boxH]; end end end end %% Run Non-Maximal Suppression on the detected bounding boxess coder.varsize('selectedBbox',[98, 4],[1 0]); [selectedBbox,~] = selectStrongestBbox(round(boxes),probs); %% Recognition persistent recognitionnet; if isempty(recognitionnet) recognitionnet = coder.loadDeepLearningNetwork('RecognitionNet.mat','Recognition'); end idx = zeros(size(selectedBbox,1),1); inpImg = coder.nullcopy(zeros(48,48,3,size(selectedBbox,1))); for i = 1:size(selectedBbox,1) ymin = selectedBbox(i,2); ymax = ymin+selectedBbox(i,4); xmin = selectedBbox(i,1); xmax = xmin+selectedBbox(i,3); % Resize Image inpImg(:,:,:,i) = imresize(img(ymin:ymax,xmin:xmax,:),[48,48]); end for i = 1:size(selectedBbox,1) output = recognitionnet.predict(inpImg(:,:,:,i)); [~,idx(i)]=max(output); end
tsdr_predict
ФункцияСоздайте объект строения GPU для цели MEX и установите целевой язык на C++. Используйте coder.DeepLearningConfig
функция для создания CuDNN
объект строения глубокого обучения и присвоение его DeepLearningConfig
свойство объекта строения кода GPU. Чтобы сгенерировать CUDA MEX, используйте codegen
и задайте вход размера [480 704 3]. Это значение соответствует размеру входного изображения tsdr_predict
функция.
cfg = coder.gpuConfig('mex'); cfg.TargetLang = 'C++'; cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn'); codegen -config cfg tsdr_predict -args {ones(480,704,3,'uint8')} -report
Code generation successful: To view the report, open('codegen/mex/tsdr_predict/html/report.mldatx').
Чтобы сгенерировать код при помощи TensorRT, передайте coder.DeepLearningConfig('tensorrt')
как опция объекта строения кодера вместо 'cudnn'
.
Загрузите вход изображение.
im = imread('stop.jpg');
imshow(im);
Функции tsdr_predict_mex
на вход изображении.
im = imresize(im, [480,704]); [bboxes,classes] = tsdr_predict_mex(im);
Сопоставьте номера классов с именами знаков трафика в словаре классов.
classNames = {'addedLane','slow','dip','speedLimit25','speedLimit35','speedLimit40','speedLimit45',... 'speedLimit50','speedLimit55','speedLimit65','speedLimitUrdbl','doNotPass','intersection',... 'keepRight','laneEnds','merge','noLeftTurn','noRightTurn','stop','pedestrianCrossing',... 'stopAhead','rampSpeedAdvisory20','rampSpeedAdvisory45','truckSpeedLimit55',... 'rampSpeedAdvisory50','turnLeft','rampSpeedAdvisoryUrdbl','turnRight','rightLaneMustTurn',... 'yield','yieldAhead','school','schoolSpeedLimit25','zoneAhead45','signalAhead'}; classRec = classNames(classes);
Отображение обнаруженных дорожных знаков.
outputImage = insertShape(im,'Rectangle',bboxes,'LineWidth',3); for i = 1:size(bboxes,1) outputImage = insertText(outputImage,[bboxes(i,1)+bboxes(i,3) bboxes(i,2)-20],classRec{i},'FontSize',20,'TextColor','red'); end imshow(outputImage);
Включенный вспомогательный файл tsdr_testVideo.m захватывает системы координат из тестового видео, выполняет обнаружение и распознавание дорожных знаков и строит графики результатов на каждой системе координат тестового видео.
% Input video v = VideoReader('stop.avi'); fps = 0;
while hasFrame(v) % Take a frame picture = readFrame(v); picture = imresize(picture,[920,1632]); % Call MEX function for Traffic Sign Detection and Recognition tic; [bboxes,clases] = tsdr_predict_mex(picture); newt = toc;
% fps fps = .9*fps + .1*(1/newt);
% display
displayDetections(picture,bboxes,clases,fps); end
Очистить загруженные в память статические сетевые объекты.
clear mex;