В этом примере показано, как обучить 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 переменная в коде к местоположению загруженного файла.
Процедура обучения для этого примера предназначена для организованных облаков точек. Пример преобразования неорганизованных облаков в организованные см. в разделе Неорганизованное преобразование облаков точек с помощью сферической проекции.
Загрузите предварительно обученную сеть, чтобы избежать необходимости ждать завершения обучения. Если вы хотите обучить сеть, установите 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 координаты облака точек, интенсивность и диапазон: + z2.
Ниже приведено визуальное представление обучающих данных.

Создание пятиканальных обучающих изображений.
imagesFolder = fullfile(outputFolder,'images');
helperTransformOrganizedPointCloudToTrainingData(lidarData,imagesFolder);Preprocessing data 100% complete
Пятиканальные изображения сохраняются в виде файлов MAT.
Обработка может занять некоторое время. Код приостанавливает выполнение MATLAB ® до завершения обработки.
mageDatastore и pixelLabelDatastoreСоздание imageDatastore для извлечения и хранения пяти каналов 2-D сферических изображений с использованием imageDatastore и поддерживающей функции helperImageMatReader, которая является пользовательским устройством чтения файлов MAT. Эта функция присоединена к этому примеру как вспомогательный файл.
imds = imageDatastore(imagesFolder, ... 'FileExtensions', '.mat', ... 'ReadFcn', @helperImageMatReader);
Создание хранилища данных меток пикселей с помощью pixelLabelDatastore для сохранения пиксельных меток из изображений пиксельных меток. Объект сопоставляет каждую пиксельную метку с именем класса. В этом примере представляющими интерес объектами являются растительность, грунт, дорога, дорожная разметка, тротуар, автомобили, грузовики, другие транспортные средства, пешеходы, дорожный барьер, знаки и здания; все остальные пикселы являются фоном. Укажите эти классы и присвойте каждому классу уникальный идентификатор метки.
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 , определенной в разделе «Вспомогательные функции» данного примера.
% 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 , определенной в разделе «Вспомогательные функции» данного примера. Эта функция случайным образом разворачивает многоканальное изображение 2-D и связанные с ним метки в горизонтальном направлении. Применение увеличения данных только к набору данных обучения.
augmentedTrainingData = transform(trainingData, @(x) helperAugmentData(x));
Создайте стандартную сеть SqueezeSegV2 [1] с помощью squeezesegv2Layers функция. В SqueezeSegV2 сети подсеть кодера состоит из FireModules, чередующихся с уровнями максимального пула. Эта компоновка последовательно уменьшает разрешение входного изображения. Кроме того, SqueezeSegV2 сеть использует функцию фокальных потерь для уменьшения влияния несбалансированного распределения классов на точность сети. Дополнительные сведения об использовании функции фокусных потерь в семантической сегментации см. в разделе focalLossLayer.
Выполните этот код, чтобы создать график уровня, который можно использовать для обучения сети.
inputSize = [64 1856 5]; lgraph = squeezesegv2Layers(inputSize, ... numClasses,'NumEncoderModules',4,'NumContextAggregationModules',2);
Используйте analyzeNetwork Функция (Deep Learning Toolbox) для отображения интерактивной визуализации сетевой архитектуры.
analyzeNetwork(lgraph);
Использовать Аdam алгоритм оптимизации для обучения сети. Используйте 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. При обучении сети можно использовать ЦП или графический процессор. Для использования графического процессора требуется Toolbox™ параллельных вычислений и поддерживаемое устройство графического процессора. Сведения о поддерживаемых устройствах см. в разделе Поддержка графического процессора по выпуску (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 функция, определенная в разделе «Вспомогательные функции» данного примера, для отображения результата сегментации в облаке точек.
figure;
helperDisplayLabelOverlaidPointCloud(I, predictedResult);
view([39.2 90.0 60]);
title('Semantic Segmentation Result on Point Cloud');
Используйте evaluateSemanticSegmentation функция для вычисления метрик семантической сегментации по результатам тестового набора.
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).
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 указывают на то, что для повышения производительности требуется больше данных по обучению.
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
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
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
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
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
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: Улучшенная структура модели и незарегистрированная адаптация домена для сегментации дорожных объектов из облака точек LiDAR». В 2019 году Международная конференция по робототехнике и автоматизации (ICRA), 4376-82. Монреаль, КК, Канада: IEEE, 2019.https://doi.org/10.1109/ICRA.2019.8793495.
[2] Хесай и масштаб. PandaSet. https://scale.com/open-datasets/pandaset