Глубокое обучение использует архитектуры нейронной сети, которые содержат много слоев обработки, включая сверточные слои. Модели глубокого обучения обычно работают над большими наборами маркированных данных. Обучение эти модели и выполняющий вывод в вычислительном отношении интенсивно, используя существенное количество памяти. Нейронные сети используют память, чтобы сохранить входные данные, параметры (веса) и активации от каждого слоя, когда вход распространяет через сеть. Большинство предварительно обученных нейронных сетей и нейронных сетей, обученных при помощи Deep Learning Toolbox™, использует типы данных с плавающей запятой с одинарной точностью. Даже сети, которые малы в размере, требуют, чтобы значительный объем памяти и оборудование выполнили эти арифметические операции с плавающей точкой. Эти ограничения могут запретить развертывание моделей глубокого обучения к устройствам, которые имеют низкую вычислительную силу и меньшие ресурсы памяти. При помощи более низкой точности, чтобы сохранить веса и активации, можно уменьшать требования к памяти сети.
Можно использовать Deep Learning Toolbox в тандеме с пакетом поддержки Библиотеки Квантования Модели Deep Learning Toolbox, чтобы уменьшать объем потребляемой памяти глубокой нейронной сети путем квантования весов, смещений и активаций слоев свертки к 8-битным масштабированным целочисленным типам данных. Затем можно использовать GPU Coder™, чтобы сгенерировать оптимизированный код CUDA® для квантованной сети. Сгенерированный код использует в своих интересах библиотеку глубокой нейронной сети NVIDIA® CUDA (cuDNN) или высокоэффективную библиотеку вывода TensorRT™. сгенерированный код может быть интегрирован в ваш проект как исходный код, статические или динамические библиотеки или исполняемые файлы, что можно развернуть в разнообразие NVIDIA платформы графического процессора.
В этом примере вы используете GPU Coder, чтобы сгенерировать код CUDA для квантованной глубокой сверточной нейронной сети и классифицировать изображение. Пример использует предварительно обученный squeezenet
Сверточная нейронная сеть (Deep Learning Toolbox), чтобы продемонстрировать передачу обучения, квантование и генерацию кода CUDA для квантованной сети.
SqueezeNet был обучен на более чем миллионе изображений и может классифицировать изображения в 1 000 категорий объектов (таких как клавиатура, кофейная кружка, карандаш и многие животные). Сеть изучила богатые представления функции для широкого спектра изображений. Сеть берет изображение в качестве входа и выводит метку для объекта в изображении вместе с вероятностями для каждой из категорий объектов.
Сторонние необходимые условия
Необходимый
CUDA включил NVIDIA® графический процессор и совместимый драйвер.
Дополнительный
Для сборок неMEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.
NVIDIA инструментарий CUDA.
Библиотека NVIDIA cuDNN.
Переменные окружения для компиляторов и библиотек. Для получения дополнительной информации смотрите Стороннее Оборудование и Подготовку Необходимых как условие продуктов.
Передача обучения Используя SqueezeNet
Чтобы выполнить классификацию на новом наборе изображений, вы подстраиваете предварительно обученную сверточную нейронную сеть SqueezeNet, переводом учась. В передаче обучения можно взять предварительно обученную сеть и использовать ее в качестве начальной точки, чтобы изучить новую задачу. Подстройка сети с передачей обучения обычно намного быстрее и легче, чем обучение сети со случайным образом инициализированными весами с нуля. Можно быстро передать изученные функции новой задаче с помощью меньшего числа учебных изображений.
Загрузите обучающие данные
Разархивируйте и загрузите новые изображения как datastore изображений. imageDatastore
функционируйте автоматически помечает изображения на основе имен папок и хранит данные как ImageDatastore
объект. Datastore изображений позволяет вам сохранить большие данные изображения, включая данные, которые не умещаются в памяти, и эффективно считать пакеты изображений во время обучения сверточной нейронной сети. Разделите данные на наборы данных обучения и валидации. Используйте 70% изображений для обучения и 30% для валидации. splitEachLabel
разделяет imds
datastore в два новых хранилища данных.
unzip('MerchData.zip'); imds = imageDatastore('MerchData', ... 'IncludeSubfolders',true, ... 'LabelSource','foldernames'); [imdsTrain,imdsValidation] = splitEachLabel(imds,0.7,'randomized'); numTrainImages = numel(imdsTrain.Labels); idx = randperm(numTrainImages,4); img = imtile(imds, 'Frames', idx); figure imshow(img) title('Random Images from Training Dataset');
Загрузите предварительно обученную сеть
Загрузите предварительно обученную сеть SqueezeNet. Если у вас нет необходимых пакетов поддержки установленными, программное обеспечение обеспечивает ссылку на загрузку.
net = squeezenet;
Объект net
содержит DAGNetwork
объект. Первый слой, входной слой для изображений, требует входных изображений размера 227 227 3, где 3 количество цветовых каналов. Можно использовать analyzeNetwork
(Deep Learning Toolbox) функция, чтобы отобразить интерактивную визуализацию сетевой архитектуры, обнаружить ошибки и проблемы в сети, и отобразить подробную информацию о слоях сети. Информация о слое включает размеры активаций слоя и настраиваемых параметров, общего количества настраиваемых параметров и размеров параметров состояния текущих слоев.
inputSize = net.Layers(1).InputSize;
Замените последние слои
Сверточные слои сетевого извлечения отображают функции что последний learnable слой и итоговое использование слоя классификации, чтобы классифицировать входное изображение. Эти два слоя, 'conv10'
и 'ClassificationLayer_predictions'
в SqueezeNet содержите информацию о том, как сочетать функции, которые сеть извлекает в вероятности класса, значение потерь и предсказанные метки.
Чтобы переобучить предварительно обученную сеть, чтобы классифицировать новые изображения, замените эти два слоя на новые слои, адаптированные к новому набору данных. Можно сделать это вручную или использовать функцию помощника findLayersToReplace
найти эти слои автоматически.
lgraph = layerGraph(net); [learnableLayer,classLayer] = findLayersToReplace(lgraph); numClasses = numel(categories(imdsTrain.Labels)); newConvLayer = convolution2dLayer([1, 1],numClasses,'WeightLearnRateFactor',... 10,'BiasLearnRateFactor',10,"Name",'new_conv'); lgraph = replaceLayer(lgraph,'conv10',newConvLayer); newClassificatonLayer = classificationLayer('Name','new_classoutput'); lgraph = replaceLayer(lgraph,'ClassificationLayer_predictions',newClassificatonLayer);
Обучение сети
Сеть требует входных изображений размера 227 227 3, но изображения в хранилищах данных изображений имеют различные размеры. Используйте увеличенный datastore изображений, чтобы автоматически изменить размер учебных изображений. Задайте дополнительные операции увеличения, чтобы выполнить на учебных изображениях: случайным образом инвертируйте учебные изображения вдоль вертикальной оси, и случайным образом переведите их до 30 пикселей горизонтально и вертикально. Увеличение данных помогает препятствовать тому, чтобы сеть сверхсоответствовала и запомнила точные детали учебных изображений.
pixelRange = [-30 30]; imageAugmenter = imageDataAugmenter( ... 'RandXReflection',true, ... 'RandXTranslation',pixelRange, ... 'RandYTranslation',pixelRange); augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain, ... 'DataAugmentation',imageAugmenter);
Чтобы автоматически изменить размер изображений валидации, не выполняя дальнейшее увеличение данных, используйте увеличенный datastore изображений, не задавая дополнительных операций предварительной обработки.
augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);
Задайте опции обучения. Для передачи обучения сохраните функции от ранних слоев предварительно обученной сети (переданные веса слоя). Чтобы замедлить изучение в переданных слоях, установите начальную скорость обучения на маленькое значение. На предыдущем шаге вы увеличили факторы скорости обучения для сверточного слоя, чтобы ускорить изучение в новых последних слоях. Эта комбинация настроек скорости обучения приводит к быстрому изучению только в новых слоях и более медленном изучении в других слоях. При использовании обучение с переносом вы не должны обучаться для как много эпох. Эпоха является полным учебным циклом на целом обучающем наборе данных. Задайте мини-пакетный размер, чтобы быть 11 так, чтобы в каждую эпоху вы рассмотрели все данные. Программное обеспечение проверяет сеть каждый ValidationFrequency
итерации во время обучения.
options = trainingOptions('sgdm', ... 'MiniBatchSize',11, ... 'MaxEpochs',7, ... 'InitialLearnRate',2e-4, ... 'Shuffle','every-epoch', ... 'ValidationData',augimdsValidation, ... 'ValidationFrequency',3, ... 'Verbose',false, ... 'Plots','training-progress');
Обучите сеть, которая состоит из переданных и новых слоев.
netTransfer = trainNetwork(augimdsTrain,lgraph,options);
classNames = netTransfer.Layers(end).Classes; save('mySqueezenet.mat','netTransfer');
Квантуйте сеть
Создайте dlquantizer
возразите и задайте сеть, чтобы квантовать.
quantObj = dlquantizer(netTransfer);
Задайте метрическую функцию, чтобы использовать, чтобы сравнить поведение сети до и после квантования.
type('hComputeModelAccuracy.m');
function accuracy = hComputeModelAccuracy(predictionScores, net, dataStore) %% Computes model-level accuracy statistics % Load ground truth tmp = readall(dataStore); groundTruth = tmp.response; % Compare with predicted label with actual ground truth predictionError = {}; for idx=1:numel(groundTruth) [~, idy] = max(predictionScores(idx,:)); yActual = net.Layers(end).Classes(idy); predictionError{end+1} = (yActual == groundTruth(idx)); %#ok end % Sum all prediction errors. predictionError = [predictionError{:}]; accuracy = sum(predictionError)/numel(predictionError); end
Задайте метрическую функцию в dlquantizationOptions
объект.
quantOpts = dlquantizationOptions('MetricFcn', ... {@(x)hComputeModelAccuracy(x,netTransfer,augimdsValidation)});
Используйте calibrate
функционируйте, чтобы осуществить сеть с демонстрационными входными параметрами и собрать информацию области значений. calibrate
функционируйте осуществляет сеть и собирает динамические диапазоны весов и смещений в свертке и полносвязных слоях сети и динамические диапазоны активаций во всех слоях сети. Функция возвращает таблицу. Каждая строка таблицы содержит информацию об области значений для настраиваемого параметра оптимизированной сети.
calResults = calibrate(quantObj,augimdsTrain); save('squeezenetCalResults.mat','calResults'); save('squeezenetQuantObj.mat','quantObj');
Можно использовать validate
функция, чтобы квантовать настраиваемые параметры в слоях свертки сети и осуществить сеть. Функция использует метрическую функцию, заданную в dlquantizationOptions
объект сравнить результаты сети до и после квантования.
valResults = validate(quantObj,augimdsValidation,quantOpts);
Создайте функцию точки входа
Напишите функцию точки входа в MATLAB что:
Использует coder.loadDeepLearningNetwork
функционируйте, чтобы загрузить модель глубокого обучения и создать и настроить класс CNN. Для получения дополнительной информации смотрите Предварительно обученные сети Загрузки для Генерации кода.
Вызывает predict
функция, чтобы предсказать ответы.
type('predict_int8.m');
function out = predict_int8(netFile, in) persistent mynet; if isempty(mynet) mynet = coder.loadDeepLearningNetwork(netFile); end out = predict(mynet,in); end
Постоянный объект mynet
загружает DAGNetwork
объект. В первом вызове функции точки входа постоянный объект создается и настраивается. На последующих вызовах функции тот же объект снова используется, чтобы вызвать predict
на входных параметрах, избегая восстановления и перезагрузки сетевого объекта.
Примечание
Убедитесь, что все операции предварительной обработки, выполняемые на шагах калибровки и валидации, включены в файл проекта.
Генерация кода при помощи codegen
Чтобы сконфигурировать настройки сборки, такие как имя выходного файла, местоположение и тип, вы создаете объекты настройки кодера. Чтобы создать объекты, используйте coder.gpuConfig
функция. Например, при генерации MEX CUDA с помощью codegen
команда, используйте cfg = coder.gpuConfig('mex');
Чтобы задать параметры генерации кода для cuDNN, установите DeepLearningConfig
свойство к coder.CuDNNConfig
возразите, что вы создаете при помощи coder.DeepLearningConfig
.
cfg = coder.gpuConfig('mex'); cfg.TargetLang = 'C++'; cfg.GpuConfig.ComputeCapability = '6.1'; cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn'); cfg.DeepLearningConfig.AutoTuning = true; cfg.DeepLearningConfig.CalibrationResultFile = 'squeezenetQuantObj.mat'; cfg.DeepLearningConfig.DataType = 'int8';
Задайте местоположение MAT-файла, содержащего калибровочные данные.
Задайте точность расчетов вывода в поддерживаемых слоях при помощи DataType
свойство. Для 8-битного целого числа используйте 'int8'
. Используйте ComputeCapability
свойство объекта настройки кода установить соответствующее вычисляет значение возможности.
Запустите codegen
команда. codegen
команда генерирует код CUDA от predict_int8.m
Функция точки входа MATLAB.
inputs = {coder.Constant('mySqueezenet.mat'),ones(inputSize,'uint8')}; codegen -config cfg -args inputs predict_int8
Code generation successful.
Когда генерация кода успешна, можно просмотреть получившийся отчет генерации кода путем нажатия на View Report в командном окне MATLAB. Отчет отображен в окне Report Viewer. Если генератор кода обнаруживает ошибки или предупреждения во время генерации кода, отчет описывает проблемы и обеспечивает ссылки на проблематичный код MATLAB.
Запустите сгенерированный MEX
Изображение, которое вы хотите классифицировать, должно иметь тот же размер как входной размер сети. Считайте изображение, что вы хотите классифицировать и изменить размер его к входному размеру сети. Это изменение размеров немного изменяет соотношение сторон изображения.
testImage = imread("MerchDataTest.jpg");
testImage = imresize(testImage,inputSize(1:2));
Вызов SqueezeNet предсказывает на входном изображении.
predictScores(:,1) = predict(netTransfer,testImage)';
predictScores(:,2) = predict_int8_mex('mySqueezenet.mat',testImage);
Отобразите предсказанные метки и их связанные вероятности как гистограмма.
h = figure; h.Position(3) = 2*h.Position(3); ax1 = subplot(1,2,1); ax2 = subplot(1,2,2); image(ax1,testImage); barh(ax2,predictScores) xlabel(ax2,'Probability') yticklabels(ax2,classNames) ax2.XLim = [0 1.1]; ax2.YAxisLocation = 'left'; legend('Matlab Single','cuDNN 8-bit integer'); sgtitle('Predictions using Squeezenet')
Функции помощника
function [learnableLayer,classLayer] = findLayersToReplace(lgraph) % findLayersToReplace(lgraph) finds the single classification layer and the % preceding learnable (fully connected or convolutional) layer of the layer % graph lgraph. if ~isa(lgraph,'nnet.cnn.LayerGraph') error('Argument must be a LayerGraph object.') end % Get source, destination, and layer names. src = string(lgraph.Connections.Source); dst = string(lgraph.Connections.Destination); layerNames = string({lgraph.Layers.Name}'); % Find the classification layer. The layer graph must have a single % classification layer. isClassificationLayer = arrayfun(@(l) ... (isa(l,'nnet.cnn.layer.ClassificationOutputLayer') ... |isa(l,'nnet.layer.ClassificationLayer')), ... lgraph.Layers); if sum(isClassificationLayer) ~= 1 error('Layer graph must have a single classification layer.') end classLayer = lgraph.Layers(isClassificationLayer); % Traverse the layer graph in reverse starting from the classification % layer. If the network branches, throw an error. currentLayerIdx = find(isClassificationLayer); while true if numel(currentLayerIdx) ~= 1 msg = ['Layer graph must have a single learnable ' ... 'layer preceding the classification layer.']; error(msg); end currentLayerType = class(lgraph.Layers(currentLayerIdx)); isLearnableLayer = ismember(currentLayerType, ... ['nnet.cnn.layer.FullyConnectedLayer','nnet.cnn.layer.Convolution2DLayer']); if isLearnableLayer learnableLayer = lgraph.Layers(currentLayerIdx); return end currentDstIdx = find(layerNames(currentLayerIdx) == dst); currentLayerIdx = find(src(currentDstIdx) == layerNames); end end
При выполнении вывода в INT8
точность с помощью cuDNN версию 8.1.0, проблемы в библиотеке NVIDIA могут вызвать значительное ухудшение в эффективности.
Следующие слои не поддерживаются для 8-битного целочисленного квантования при предназначении для библиотеки глубокой нейронной сети CUDA NVIDIA (cuDNN) библиотека.
leakyReluLayer
clippedReluLayer
globalAveragePooling2dLayer
codegen
| coder.loadDeepLearningNetwork
| calibrate
(Deep Learning Toolbox) | dlquantizationOptions
(Deep Learning Toolbox) | dlquantizer
(Deep Learning Toolbox) | validate
(Deep Learning Toolbox)