Квантуйте код Generate CUDA® и детекторы объектов

В этом примере показано, как сгенерировать код CUDA® для детектора транспортного средства SSD и детектора YOLO v2 транспортного средства, который выполняет расчеты вывода в 8-битных целых числах.

Глубокое обучение является мощным методом машинного обучения, в котором вы обучаете сеть, чтобы изучить функции изображений и выполнить задачи обнаружения. Существует несколько методов для обнаружения объектов с помощью глубокого обучения, таких как Faster R-CNN, Вы Только Взгляд Однажды (YOLO v2) и SSD. Для получения дополнительной информации смотрите, что Обнаружение объектов Использует глубокое обучение YOLO v2 и Обнаружение объектов Используя Глубокое обучение SSD.

Архитектуры нейронной сети, используемые для применения глубокого обучения, содержат много слоев обработки, включая сверточные слои. Модели глубокого обучения обычно работают над большими наборами маркированных данных. Выполнение вывода на этих моделях в вычислительном отношении интенсивно, используя существенное количество памяти. Нейронные сети используют память, чтобы сохранить входные данные, параметры (веса) и активации от каждого слоя, когда вход распространяет через сеть. Глубокие нейронные сети, обученные в MATLAB, используют типы данных с плавающей запятой с одинарной точностью. Даже сети, которые малы в размере, требуют, чтобы значительный объем памяти и оборудование выполнили эти арифметические операции с плавающей точкой. Эти ограничения могут запретить развертывание моделей глубокого обучения к устройствам, которые имеют низкую вычислительную силу и меньшие ресурсы памяти. При помощи более низкой точности, чтобы сохранить веса и активации, можно уменьшать требования к памяти сети.

Можно использовать Deep Learning Toolbox в тандеме с пакетом поддержки Библиотеки Квантования Модели Deep Learning Toolbox, чтобы уменьшать объем потребляемой памяти глубокой нейронной сети путем квантования весов, смещений и активаций слоев свертки к 8-битным масштабированным целочисленным типам данных. Затем можно использовать GPU Coder™, чтобы сгенерировать код CUDA для квантованной сети.

Загрузите предварительно обученную сеть

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

detectorType = 2
detectorType = 2
switch detectorType
    case 1
        if ~exist('ssdResNet50VehicleExample_20a.mat','file')
            disp('Downloading pretrained detector...');
            pretrainedURL = 'https://www.mathworks.com/supportfiles/vision/data/ssdResNet50VehicleExample_20a.mat';
            websave('ssdResNet50VehicleExample_20a.mat',pretrainedURL);
        end
    case 2
        if ~exist('yolov2ResNet50VehicleExample_19b.mat','file')    
            disp('Downloading pretrained detector...');
            pretrainedURL = 'https://www.mathworks.com/supportfiles/vision/data/yolov2ResNet50VehicleExample_19b.mat';
            websave('yolov2ResNet50VehicleExample_19b.mat',pretrainedURL);
        end
end
Downloading pretrained detector...

Загрузка данных

Этот пример использует набор данных небольшого транспортного средства, который содержит 295 изображений. Многие из этих изображений прибывают из Автомобилей Калифорнийского технологического института 1 999 и 2 001 набор данных, используемый с разрешением и доступный в Калифорнийском технологическом институте Вычислительный веб-сайт Видения, созданный Пьетро Пероной. Каждое изображение содержит один или два помеченных экземпляра транспортного средства. Небольшой набор данных полезен для исследования метода обучения, но на практике, более помеченные изображения необходимы, чтобы обучить устойчивый детектор. Извлеките изображения транспортного средства и загрузите достоверные данные транспортного средства.

unzip vehicleDatasetImages.zip
data = load('vehicleDatasetGroundTruth.mat');
vehicleDataset = data.vehicleDataset;

Подготовка данных для обучения, калибровки и валидации

Обучающие данные хранятся в таблице. Первый столбец содержит путь к файлам изображений. Остальные столбцы содержат метки ROI для транспортных средств. Отобразите первые несколько строк данных.

vehicleDataset(1:4,:)
ans=4×2 table
              imageFilename                   vehicle     
    _________________________________    _________________

    {'vehicleImages/image_00001.jpg'}    {[220 136 35 28]}
    {'vehicleImages/image_00002.jpg'}    {[175 126 61 45]}
    {'vehicleImages/image_00003.jpg'}    {[108 120 45 33]}
    {'vehicleImages/image_00004.jpg'}    {[124 112 38 36]}

Разделите набор данных в обучение, валидацию и наборы тестов. Выберите 60% данных для обучения, 10% для калибровки и остаток для проверки обученного детектора.

rng(0);
shuffledIndices = randperm(height(vehicleDataset));
idx = floor(0.6 * length(shuffledIndices) );

trainingIdx = 1:idx;
trainingDataTbl = vehicleDataset(shuffledIndices(trainingIdx),:);

calibrationIdx = idx+1 : idx + 1 + floor(0.1 * length(shuffledIndices) );
calibrationDataTbl = vehicleDataset(shuffledIndices(calibrationIdx),:);

validationIdx = calibrationIdx(end)+1 : length(shuffledIndices);
validationDataTbl = vehicleDataset(shuffledIndices(validationIdx),:);

Используйте imageDatastore и boxLabelDatastore создать хранилища данных для загрузки изображения и данных о метке во время обучения и оценки.

imdsTrain = imageDatastore(trainingDataTbl{:,'imageFilename'});
bldsTrain = boxLabelDatastore(trainingDataTbl(:,'vehicle'));

imdsCalibration = imageDatastore(calibrationDataTbl{:,'imageFilename'});
bldsCalibration = boxLabelDatastore(calibrationDataTbl(:,'vehicle'));

imdsValidation = imageDatastore(validationDataTbl{:,'imageFilename'});
bldsValidation = boxLabelDatastore(validationDataTbl(:,'vehicle'));

Объедините изображение и хранилища данных метки поля.

trainingData = combine(imdsTrain,bldsTrain);
calibrationData = combine(imdsCalibration,bldsCalibration);
validationData = combine(imdsValidation,bldsValidation);

Отобразите одно из учебных изображений и меток поля.

data = read(calibrationData);
I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,'Rectangle',bbox);
annotatedImage = imresize(annotatedImage,2);
figure
imshow(annotatedImage)

Параметры сети Define

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

inputSize = []; 
switch detectorType 
    case 1
        inputSize = [300 300 3]; % Minimum size for SSD
    case 2
        inputSize = [224 224 3]; % Minimum size for YOLO v2
end

Задайте количество классов объектов, чтобы обнаружить.

numClasses = width(vehicleDataset)-1;

Увеличение данных

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

Используйте преобразования, чтобы увеличить обучающие данные:

  • Случайным образом зеркальное отражение изображения и сопоставленного поля помечает горизонтально.

  • Случайным образом масштабируя изображение и сопоставленные метки поля.

  • Дрожание цвет изображения.

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

augmentedCalibrationData = transform(calibrationData,@augmentVehicleData);

Визуализируйте увеличенные обучающие данные путем чтения того же изображения многократно.

augmentedData = cell(4,1);
for k = 1:4
    data = read(augmentedCalibrationData);
    augmentedData{k} = insertShape(data{1},'Rectangle',data{2});
    reset(augmentedCalibrationData);
end

figure
montage(augmentedData,'BorderSize',10)

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

Предварительно обработайте увеличенные калибровочные данные, чтобы подготовиться к калибровке сети.

preprocessedCalibrationData = transform(augmentedCalibrationData,@(data)preprocessVehicleData(data,inputSize));

Считайте предварительно обработанные калибровочные данные.

data = read(preprocessedCalibrationData);

Отобразите поля изображения и ограничительные рамки.

I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,'Rectangle',bbox);
annotatedImage = imresize(annotatedImage,2);
figure
imshow(annotatedImage)

Загрузите и протестируйте предварительно обученный детектор

Загрузите предварительно обученный детектор.

switch detectorType
    case 1
        % Load pretrained SSD detector for the example.
        pretrained = load('ssdResNet50VehicleExample_20a.mat');
        detector = pretrained.detector;
    case 2 
        % Load pretrained YOLO v2 detector for the example.
        pretrained = load('yolov2ResNet50VehicleExample_19b.mat');
        detector = pretrained.detector;
end

Как быстрый тест, запустите детектор на одном тестовом изображении.

data = read(calibrationData);
I = data{1,1};
I = imresize(I,inputSize(1:2));
[bboxes,scores] = detect(detector,I, 'Threshold', 0.4);

Отобразите результаты.

I = insertObjectAnnotation(I,'rectangle',bboxes,scores);
figure
imshow(I)

Проверьте сеть с плавающей точкой

Оцените обученный детектор объектов на большом наборе изображений, чтобы измерить уровень. Computer Vision Toolbox™ обеспечивает функции, чтобы измерить общие метрики детектора объектов, такие как средняя точность (evaluateDetectionPrecision) и средние журналом коэффициенты непопаданий (evaluateDetectionMissRate). В данном примере используйте среднюю метрику точности, чтобы оценить эффективность. Средняя точность обеспечивает один номер, который включает способность детектора сделать правильные классификации (precision) и способность детектора найти все соответствующие объекты (recall).

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

preprocessedValidationData = transform(validationData,@(data)preprocessVehicleData(data,inputSize));

Запустите детектор на всех тестовых изображениях.

detectionResults = detect(detector, preprocessedValidationData,'Threshold',0.4);

Оцените детектор объектов с помощью средней метрики точности.

[ap,recall,precision] = evaluateDetectionPrecision(detectionResults,preprocessedValidationData);

Точность/отзыв (PR), который подсвечивает кривая, насколько точный детектор на различных уровнях отзыва. Идеально, точность 1 на всех уровнях отзыва. Используя большее количество данных может помочь улучшить среднюю точность, но может потребовать большего количества учебного времени. Постройте кривую PR.

figure
plot(recall,precision)
xlabel('Recall')
ylabel('Precision')
grid on
title(sprintf('Average Precision = %.2f',ap))

Квантуйте сеть

Создайте dlquantizer возразите и задайте детектор, чтобы квантовать. По умолчанию среда выполнения установлена в графический процессор. Чтобы узнать о продуктах, требуемых квантовать и развернуть детектор в среду графического процессора, смотрите Необходимые условия Рабочего процесса Квантования.

quantObj = dlquantizer(detector)
quantObj = 
  dlquantizer with properties:

           NetworkObject: [1×1 yolov2ObjectDetector]
    ExecutionEnvironment: 'GPU'

Задайте метрическую функцию в dlquantizationOptions объект.

quantOpts = dlquantizationOptions;
quantOpts = dlquantizationOptions('MetricFcn', ...
    {@(x)hVerifyDetectionResults(x, detector.Network, preprocessedValidationData)});

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

calResults = calibrate(quantObj,preprocessedCalibrationData)
calResults=147×5 table
                Optimized Layer Name                 Network Layer Name      Learnables / Activations    MinValue    MaxValue
    ____________________________________________    _____________________    ________________________    ________    ________

    {'conv1_activation_1_relu_Weights'         }    {'activation_1_relu'}           "Weights"             -9.3984      9.511 
    {'conv1_activation_1_relu_Bias'            }    {'activation_1_relu'}           "Bias"                -2.6468     6.3474 
    {'res2a_branch2a_activation_2_relu_Weights'}    {'activation_2_relu'}           "Weights"            -0.85967    0.35191 
    {'res2a_branch2a_activation_2_relu_Bias'   }    {'activation_2_relu'}           "Bias"                -5.0999     5.6429 
    {'res2a_branch2b_activation_3_relu_Weights'}    {'activation_3_relu'}           "Weights"            -0.24903    0.32103 
    {'res2a_branch2b_activation_3_relu_Bias'   }    {'activation_3_relu'}           "Bias"                 -2.749     5.1706 
    {'res2a_branch1_Weights'                   }    {'bn2a_branch1'     }           "Weights"             -2.4565     1.1476 
    {'res2a_branch1_Bias'                      }    {'bn2a_branch1'     }           "Bias"                -5.3913     22.913 
    {'res2a_branch2c_activation_4_relu_Weights'}    {'activation_4_relu'}           "Weights"             -1.6711     1.6394 
    {'res2a_branch2c_activation_4_relu_Bias'   }    {'activation_4_relu'}           "Bias"                -6.8159     9.2926 
    {'res2b_branch2a_activation_5_relu_Weights'}    {'activation_5_relu'}           "Weights"            -0.46713    0.34267 
    {'res2b_branch2a_activation_5_relu_Bias'   }    {'activation_5_relu'}           "Bias"                -2.9678     3.5533 
    {'res2b_branch2b_activation_6_relu_Weights'}    {'activation_6_relu'}           "Weights"            -0.42871    0.57949 
    {'res2b_branch2b_activation_6_relu_Bias'   }    {'activation_6_relu'}           "Bias"                 -2.697     2.1982 
    {'res2b_branch2c_activation_7_relu_Weights'}    {'activation_7_relu'}           "Weights"             -1.1761     1.3237 
    {'res2b_branch2c_activation_7_relu_Bias'   }    {'activation_7_relu'}           "Bias"                -4.9467     5.1857 
      ⋮

Используйте validate функция, чтобы квантовать настраиваемые параметры в слоях свертки сети и осуществить сеть. Функция использует метрическую функцию, заданную в dlquantizationOptions объект сравнить результаты сети до и после квантования.

Исследуйте MetricResults.Result поле валидации выход, чтобы видеть эффективность квантованной сети. Первая строка в таблице результатов содержит информацию для исходной, реализации с плавающей точкой. Вторая строка содержит информацию для квантованной реализации. Вывод метрической функции отображен в MetricOutput столбец.

valResults = validate(quantObj,preprocessedValidationData,quantOpts)

valResults = struct with fields:
       NumSamples: 88
    MetricResults: [1×1 struct]
       Statistics: [2×2 table]

valResults.MetricResults.Result
ans=2×2 table
    NetworkImplementation    MetricOutput
    _____________________    ____________

     {'Floating-Point'}        0.77119   
     {'Quantized'     }        0.75244   

Метрики показывают, что квантование уменьшает необходимую память приблизительно на 75% и сетевую точность приблизительно на 3%.

Чтобы визуализировать калибровочную статистику, используйте приложение Deep Network Quantizer. Во-первых, сохраните dlquantizer объект.

save('dlquantObj.mat','quantObj')

В Командном окне MATLAB® откройте приложение Deep Network Quantizer.

deepNetworkQuantizer

Затем импортируйте dlquantizer объект dq в приложении Deep Network Quantizer путем выбора New> Import dlquantizer объект.

Сгенерируйте код CUDA

После того, как вы обучите и оцените детектор, можно сгенерировать код для ssdObjectDetector или yolov2ObjectDetector использование GPU Coder™. Для получения дополнительной информации смотрите Генерацию кода для Обнаружения объектов при помощи Одного Детектора Мультиполя Выстрела (Computer Vision Toolbox) и Генерация кода для Обнаружения объектов при помощи (GPU Coder) YOLO v2.

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

% Check compute capability of GPU
gpuInfo = gpuDevice;
cc = gpuInfo.ComputeCapability;

% Create deep learning code generation configuration object
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');

% INT8 precision requires a CUDA GPU with minimum compute capability of
% 6.1, 6.3, or higher
cfg.GpuConfig.ComputeCapability = cc;
cfg.DeepLearningConfig.DataType = 'int8';
cfg.DeepLearningConfig.CalibrationResultFile = 'dlquantObj.mat';

Запустите codegen команда, чтобы сгенерировать код CUDA.

codegen -config cfg mynet_detect -args {coder.Constant(detectorType), ones(inputSize, 'single')} -report

Когда генерация кода успешна, можно просмотреть получившийся отчет генерации кода путем нажатия на View Report в командном окне MATLAB. Отчет отображен в окне Report Viewer. Если генератор кода обнаруживает ошибки или предупреждения во время генерации кода, отчет описывает проблемы и обеспечивает ссылки на проблематичный код MATLAB. См. Отчеты Генерации кода.

Ссылки

[1] Лю, Вэй, Драгомир Ангуелов, Думитру Эрхэн, Кристиан Сзеджеди, Скотт Рид, Ченг Янг Фу и Александр К. Берг. "SSD: Один Детектор Мультиполя Выстрела". В Компьютерном зрении - ECCV 2016, отредактированный Бастианом Лайбе, Иржи Матасом, Nicu Sebe и Максом Веллингом, 9905:21-37. Хан: Springer International Publishing, 2016. https://doi.org/10.1007/978-3-319-46448-0_2

[2] Redmon, Джозеф и Али Фархади. "YOLO9000: Лучше, Быстрее, Более сильный". На 2 017 Конференциях по IEEE по Компьютерному зрению и Распознаванию образов (CVPR), 6517-25. Гонолулу, HI: IEEE, 2017. https://doi.org/10.1109/CVPR.2017.690