В этом примере показано, как обучить SqueezeSegV2 сеть семантической сегментации на 3-D организованных данных облака точек лидара.
SqueezeSegV2 [1] является сверточной нейронной сетью (CNN) для выполнения сквозной семантической сегментации организованного лидара облака точек. Процедура обучения, показанная в этом примере, требует 2-D сферических проективных изображений в качестве входов для нейронной сети для глубокого обучения.
В этом примере используется набор данных PandaSet из Hesai и Scale [2]. PandaSet содержит 4800 неорганизованные сканы облака точек лидара различных городских сцен, захваченных с помощью датчика Pandar 64. Набор данных обеспечивает семантические метки сегментации для 42 различных классов, включая автомобиль, дорогу и пешехода.
Этот пример использует подмножество PandaSet, которое содержит 2560 предварительно обработанных организованных облаков точек. Каждое облако точек задано как матрица 64 на 1856. Соответствующая основная истина содержит метки семантической сегментации для 12 классов. Облака точек хранятся в формате PCD, а достоверные данные хранятся в формате PNG. Размер набора данных составляет 5,2 ГБ. Выполните этот код, чтобы загрузить набор данных.
url = 'https://ssd.mathworks.com/supportfiles/lidar/data/Pandaset_LidarData.tar.gz'; outputFolder = fullfile(tempdir,'Pandaset'); lidarDataTarFile = fullfile(outputFolder,'Pandaset_LidarData.tar.gz'); if ~exist(lidarDataTarFile, 'file') mkdir(outputFolder); disp('Downloading Pandaset Lidar driving data (5.2 GB)...'); websave(lidarDataTarFile, url); untar(lidarDataTarFile,outputFolder); end % Check if tar.gz file is downloaded, but not uncompressed. if (~exist(fullfile(outputFolder,'Lidar'), 'file'))... &&(~exist(fullfile(outputFolder,'semanticLabels'), 'file')) untar(lidarDataTarFile,outputFolder); end lidarData = fullfile(outputFolder,'Lidar'); labelsFolder = fullfile(outputFolder,'semanticLabels');
В зависимости от вашего подключения к Интернету процесс загрузки может занять некоторое время. Код приостанавливает выполнение MATLAB ® до завершения процесса загрузки. Также можно загрузить набор данных на локальный диск с помощью веб-браузера и затем извлечь Pandaset_LidarData
папка. Чтобы использовать загруженный из Интернета файл, измените outputFolder
переменная в коде в местоположении загруженного файла.
Процедура обучения для этого примера предназначена для организованных облаков точек. Пример, показывающий преобразование неорганизованных облаков точек в организованные, см. в разделе «Неорганизованное преобразование облаков точек с помощью сферической проекции» (Lidar Toolbox).
Загрузите предварительно обученную сеть, чтобы не ждать завершения обучения. Если вы хотите обучить сеть, установите doTraining
переменная в true
.
doTraining = false; pretrainedNetURL = ... 'https://ssd.mathworks.com/supportfiles/lidar/data/trainedSqueezeSegV2PandasetNet.zip'; if ~doTraining downloadPretrainedSqueezeSegV2Net(outputFolder, pretrainedNetURL); end
Используйте helperTransformOrganizedPointCloudToTrainingData
вспомогательная функция, присоединенная к этому примеру, для генерации обучающих данных из лидара облаков точек. Функция использует данные облака точек для создания пятиканальных входных изображений. Каждое обучающее изображение задается как массив 64 на 1856 на 5:
Высота каждого изображения составляет 64 пикселя.
Ширина каждого изображения составляет 1856 пикселей.
Каждое изображение имеет пять каналов. Пять каналов определяют координаты 3-D облака точек, интенсивность и область значений: .
Далее приводится визуальное представление обучающих данных.
Сгенерируйте пятиканальные обучающие изображения.
imagesFolder = fullfile(outputFolder,'images');
helperTransformOrganizedPointCloudToTrainingData(lidarData,imagesFolder);
Preprocessing data 100% complete
Пятиканальные изображения сохраняются как файлы MAT.
Обработка может занять некоторое время. Код приостанавливает выполнение MATLAB ® до завершения обработки.
mageDatastore
и p ixelLabelDatastore
Создайте imageDatastore
извлечь и сохранить пять каналов 2-D сферических изображений с помощью imageDatastore и вспомогательной функции helperImageMatReader, которая является пользовательским средством чтения файлов MAT. Эта функция присоединена к этому примеру как вспомогательный файл.
imds = imageDatastore(imagesFolder, ... 'FileExtensions', '.mat', ... 'ReadFcn', @helperImageMatReader);
Создайте хранилище datastore метки пикселя с помощью pixelLabelDatastore
(Computer Vision Toolbox) для хранения пиксельных меток из изображений меток пикселей. Объект сопоставляет каждую пиксельную метку с именем класса. В этом примере растительность, земля, дорога, дорожная разметка, тротуар, автомобили, грузовики, другие транспортные средства, пешеходный, дорожный барьер, знаки и создания являются объектами интереса; все другие пиксели являются фоном. Задайте эти классы и присвойте уникальный идентификатор метки каждому классу.
classNames = ["unlabelled" "Vegetation" "Ground" "Road" "RoadMarkings" "SideWalk" "Car" "Truck" "OtherVehicle" "Pedestrian" "RoadBarriers" "Signs" "Buildings"]; numClasses = numel(classNames); % Specify label IDs from 1 to the number of classes. labelIDs = 1 : numClasses; pxds = pixelLabelDatastore(labelsFolder, classNames, labelIDs);
Загрузите и отобразите одно из маркированных изображений путем наложения его на соответствующее изображение интенсивности с помощью helperDisplayLidarOverlaidImage
function, заданная в разделе Support Functions этого примера.
% Point cloud (channels 1, 2, and 3 are for location, channel 4 is for intensity, and channel 5 is for range). I = read(imds); labelMap = read(pxds); figure; helperDisplayLidarOverlaidImage(I, labelMap{1,1}, classNames); title('Ground Truth');
Используйте helperPartitionLidarSegmentationDataset
вспомогательная функция, присоединенная к этому примеру, чтобы разделить данные на наборы для обучения, валидации и тестирования. Можно разделить обучающие данные в соответствии с процентом, заданным trainingDataPercentage
. Разделите остальную часть данных в соотношении 2:1 на данные валидации и проверки. Значение по умолчанию trainingDataPercentage
является 0.7
.
[imdsTrain, imdsVal, imdsTest, pxdsTrain, pxdsVal, pxdsTest] = ... helperPartitionLidarSegmentationDataset(imds, pxds, 'trainingDataPercentage', 0.75);
Используйте combine
функция для объединения пиксельных меток и хранилищ данных изображений для данных обучения и валидации.
trainingData = combine(imdsTrain, pxdsTrain); validationData = combine(imdsVal, pxdsVal);
Увеличение количества данных используется для повышения точности сети путем случайного преобразования исходных данных во время обучения. При помощи увеличения данных можно добавить больше разнообразия в обучающие данные, не увеличивая на самом деле количество маркированных обучающих выборок.
Увеличение обучающих данных при помощи transform
функция с пользовательскими операциями предварительной обработки, заданными helperAugmentData
function, заданная в разделе Support Functions этого примера. Эта функция случайным образом разворачивает многоканальное 2-D изображение и связанные с ним метки в горизонтальном направлении. Применить увеличение данных только к набору обучающих данных.
augmentedTrainingData = transform(trainingData, @(x) helperAugmentData(x));
Создайте стандартную SqueezeSegV2 сеть [1] с помощью squeezesegv2Layers
(Lidar Toolbox) функция. В SqueezeSegV2 сети подсеть энкодера состоит из FireModules, перемежающихся слоями max-pooling. Эта схема последовательно уменьшает разрешение входного изображения. В сложение SqueezeSegV2 сеть использует функцию фокусных потерь, чтобы уменьшить эффект несбалансированного распределения классов на точность сети. Для получения дополнительной информации о том, как использовать функцию фокусных потерь в семантической сегментации, смотрите focalLossLayer
(Computer Vision Toolbox).
Выполните этот код, чтобы создать график слоев, который может использоваться для обучения сети.
inputSize = [64 1856 5]; lgraph = squeezesegv2Layers(inputSize, ... numClasses,'NumEncoderModules',4,'NumContextAggregationModules',2);
Используйте analyzeNetwork
функция для отображения интерактивной визуализации сетевой архитектуры.
analyzeNetwork(lgraph);
Используйте dam
A алгоритм оптимизации для обучения сети. Используйте
trainingOptions
функция для задания гиперпараметров.
maxEpochs = 30; initialLearningRate = 1e-3; miniBatchSize = 8; l2reg = 2e-4; options = trainingOptions('adam', ... 'InitialLearnRate', initialLearningRate, ... 'L2Regularization', l2reg, ... 'MaxEpochs', maxEpochs, ... 'MiniBatchSize', miniBatchSize, ... 'LearnRateSchedule', 'piecewise', ... 'LearnRateDropFactor', 0.1, ... 'LearnRateDropPeriod', 10, ... 'ValidationData', validationData, ... 'Plots', 'training-progress', ... 'VerboseFrequency', 20);
Примечание: Уменьшите miniBatchSize
значение для управления использованием памяти при обучении.
Можно обучить сеть самостоятельно, установив doTraining
аргумент в true
. Если вы обучаете сеть, можно использовать CPU или GPU. Для использования графический процессор требуется Parallel Computing Toolbox™ и поддерживаемый графический процессор. Для получения информации о поддерживаемых устройствах смотрите Поддержку GPU by Release (Parallel Computing Toolbox). В противном случае загружает предварительно обученную сеть
if doTraining [net, info] = trainNetwork(trainingData, lgraph, options); else load(fullfile(outputFolder,'trainedSqueezeSegV2PandasetNet.mat'),'net'); end
Используйте обученную сеть, чтобы предсказать результаты на облаке тестовых точек и отобразить результат сегментации. Сначала считайте пятиканальное входное изображение и предсказайте метки с помощью обученной сети.
Отобразите рисунок с сегментацией как наложение.
I = read(imdsTest);
predictedResult = semanticseg(I, net);
figure;
helperDisplayLidarOverlaidImage(I, predictedResult, classNames);
title('Semantic Segmentation Result');
Используйте helperDisplayLabelOverlaidPointCloud
функция, заданная в разделе Support Functions этого примера, для отображения результата сегментации в облаке точек.
figure;
helperDisplayLabelOverlaidPointCloud(I, predictedResult);
view([39.2 90.0 60]);
title('Semantic Segmentation Result on Point Cloud');
Используйте evaluateSemanticSegmentation
(Computer Vision Toolbox), чтобы вычислить метрики семантической сегментации из результатов тестового набора.
outputLocation = fullfile(tempdir, 'output'); if ~exist(outputLocation,'dir') mkdir(outputLocation); end pxdsResults = semanticseg(imdsTest, net, ... 'MiniBatchSize', 4, ... 'WriteLocation', outputLocation, ... 'Verbose', false); metrics = evaluateSemanticSegmentation(pxdsResults, pxdsTest, 'Verbose', false);
Можно измерить сумму перекрытия для класса с помощью метрики «перекресток по соединению» (IoU).
The evaluateSemanticSegmentation
функция возвращает метрики для всего набора данных, для отдельных классов и для каждого тестового изображения. Чтобы увидеть метрики на уровне набора данных, используйте metrics.DataSetMetrics
свойство.
metrics.DataSetMetrics
ans=1×5 table
GlobalAccuracy MeanAccuracy MeanIoU WeightedIoU MeanBFScore
______________ ____________ _______ ___________ ___________
0.89724 0.61685 0.54431 0.81806 0.74537
Метрики набора данных обеспечивают высокоуровневый обзор эффективности сети. Чтобы увидеть влияние каждого класса на общую эффективность, смотрите метрики для каждого класса, используя metrics.ClassMetrics
свойство.
metrics.ClassMetrics
ans=13×3 table
Accuracy IoU MeanBFScore
________ _______ ___________
unlabelled 0.94 0.9005 0.99911
Vegetation 0.77873 0.64819 0.95466
Ground 0.69019 0.59089 0.60657
Road 0.94045 0.83663 0.99084
RoadMarkings 0.37802 0.34149 0.77073
SideWalk 0.7874 0.65668 0.93687
Car 0.9334 0.81065 0.95448
Truck 0.30352 0.27401 0.37273
OtherVehicle 0.64397 0.58108 0.47253
Pedestrian 0.26214 0.20896 0.45918
RoadBarriers 0.23955 0.21971 0.19433
Signs 0.17276 0.15613 0.44275
Buildings 0.94891 0.85117 0.96929
Хотя общая эффективность сети хороша, метрики классов для некоторых классов, таких как RoadMarkings
и Truck
указать, что для повышения эффективности требуется больше обучающих данных.
The helperAugmentData
функция случайным образом разворачивает сферическое изображение и связанные с ним метки в горизонтальном направлении.
function out = helperAugmentData(inp) % Apply random horizontal flipping. out = cell(size(inp)); % Randomly flip the five-channel image and pixel labels horizontally. I = inp{1}; sz = size(I); tform = randomAffine2d('XReflection',true); rout = affineOutputView(sz,tform,'BoundsStyle','centerOutput'); out{1} = imwarp(I,tform,'OutputView',rout); out{2} = imwarp(inp{2},tform,'OutputView',rout); end
The helperDisplayLidarOverlaidImage
функция накладывает карту семантической сегментации на канал интенсивности 2-D сферического изображения. Функция также изменяет размер наложенного изображения для лучшей визуализации.
function helperDisplayLidarOverlaidImage(lidarImage, labelMap, classNames) % helperDisplayLidarOverlaidImage Overlay labels over the intensity image. % % helperDisplayLidarOverlaidImage(lidarImage, labelMap, classNames) % displays the overlaid image. lidarImage is a five-channel lidar input. % labelMap contains pixel labels and classNames is an array of label % names. % Read the intensity channel from the lidar image. intensityChannel = uint8(lidarImage(:,:,4)); % Load the lidar color map. cmap = helperPandasetColorMap; % Overlay the labels over the intensity image. B = labeloverlay(intensityChannel,labelMap,'Colormap',cmap,'Transparency',0.4); % Resize for better visualization. B = imresize(B,'Scale',[3 1],'method','nearest'); imshow(B); helperPixelLabelColorbar(cmap, classNames); end
The helperDisplayLabelOverlaidPointCloud
функция накладывает результат сегментации на 3-D организованное облако точек.
function helperDisplayLabelOverlaidPointCloud(I,predictedResult) % helperDisplayLabelOverlaidPointCloud Overlay labels over point cloud object. % helperDisplayLabelOverlaidPointCloud(I, predictedResult) % displays the overlaid pointCloud object. I is the 5 channels organized % input image. predictedResult contains pixel labels. ptCloud = pointCloud(I(:,:,1:3),'Intensity',I(:,:,4)); cmap = helperPandasetColorMap; B = ... labeloverlay(uint8(ptCloud.Intensity),predictedResult,'Colormap',cmap,'Transparency',0.4); pc = pointCloud(ptCloud.Location,'Color',B); figure; ax = pcshow(pc); set(ax,'XLim',[-70 70],'YLim',[-70 70]); zoom(ax,3.5); end
The helperPandasetColorMap
функция задает палитру, используемую набором данных лидара.
function cmap = helperPandasetColorMap cmap = [[30,30,30]; % Unlabeled [0,255,0]; % Vegetation [255, 150, 255]; % Ground [255,0,255]; % Road [255,0,0]; % Road Markings [90, 30, 150]; % Sidewalk [245,150,100]; % Car [250, 80, 100]; % Truck [150, 60, 30]; % Other Vehicle [255, 255, 0]; % Pedestrian [0, 200, 255]; % Road Barriers [170,100,150]; % Signs [30, 30, 255]]; % Building cmap = cmap./255; end
The helperPixelLabelColorbar
функция добавляет шкалу палитры к текущей оси. Шкала палитры форматирована, чтобы отображать имена классов с цветом.
function helperPixelLabelColorbar(cmap, classNames) colormap(gca, cmap); % Add a colorbar to the current figure. c = colorbar('peer', gca); % Use class names for tick marks. c.TickLabels = classNames; numClasses = size(classNames, 1); % Center tick labels. c.Ticks = 1/(numClasses * 2):1/numClasses:1; % Remove tick marks. c.TickLength = 0; end
The downloadPretrainedSqueezeSegV2Net
функция загружает предварительно обученную модель.
function downloadPretrainedSqueezeSegV2Net(outputFolder, pretrainedNetURL) preTrainedMATFile = fullfile(outputFolder,'trainedSqueezeSegV2PandasetNet.mat'); preTrainedZipFile = fullfile(outputFolder,'trainedSqueezeSegV2PandasetNet.zip'); if ~exist(preTrainedMATFile,'file') if ~exist(preTrainedZipFile,'file') disp('Downloading pretrained model (5 MB)...'); websave(preTrainedZipFile, pretrainedNetURL); end unzip(preTrainedZipFile, outputFolder); end end
[1] У, Бичэнь, Сюаньюй Чжоу, Сычэн Чжао, Сянъюй Юэ и Курт Кейцер. «SqueezeSegV2: улучшенная структура модели и неконтролируемая адаптация области для сегментации дорог и объектов из облака точек лИДАР». В 2019 году Международная конференция по робототехнике и автоматизации (ICRA), 4376-82. Монреаль, QC, Канада: IEEE, 2019.https://doi.org/10.1109/ICRA.2019.8793495.
[2] Хесаи и шкала. PandaSet. https://scale.com/open-datasets/pandaset