В этом примере показано, как обучить сеть, предназначенную для классификации облака точек.
Данные облака точек собираются различными датчиками, такими как лидар, радар и камеры глубины. Эти датчики фиксируют 3-D информацию о положении объектов в сцене, что полезно для многих приложений в автономном вождении и дополненной реальности. Например, различение транспортных средств от пешеходов имеет решающее значение для планирования пути автономного транспортного средства. Однако обучение надежных классификаторов данным облака точек является сложной задачей из-за разреженности данных на объект, окклюзии объектов и шума датчиков. Было показано, что методы глубокого обучения решают многие из этих проблем, изучая надежные представления функций непосредственно из данных облака точек. Один из оригинальных глубоких методов изучения для классификации облаков пункта - PointNet [1].
В этом примере выполняется подготовка классификатора по набору данных Sydney Urban Objects, созданному Сиднейским университетом [2]. Этот набор данных обеспечивает сбор данных облака точек, полученных из городской среды с помощью лидарного датчика. Набор данных содержит 100 помеченных объектов из 14 различных категорий, таких как автомобиль, пешеход и автобус.
Загрузите и извлеките набор данных Sydney Urban Objects во временный каталог.
downloadDirectory = tempdir; datapath = downloadSydneyUrbanObjects(downloadDirectory);
Загрузите загруженный набор данных обучения и проверки с помощью loadSydneyUrbanObjectsData вспомогательная функция, перечисленная в конце этого примера. Первые три складки данных используются для обучения, а четвертая - для проверки.
foldsTrain = 1:3; foldsVal = 4; dsTrain = loadSydneyUrbanObjectsData(datapath,foldsTrain); dsVal = loadSydneyUrbanObjectsData(datapath,foldsVal);
Прочитайте один из учебных образцов и визуализируйте его с помощью pcshow.
data = read(dsTrain);
ptCloud = data{1,1};
label = data{1,2};
figure
pcshow(ptCloud.Location,[0 1 0],"MarkerSize",40,"VerticalAxisDir","down")
xlabel("X")
ylabel("Y")
zlabel("Z")
title(label)
Прочитайте метки и подсчитайте количество точек, назначенных каждой метке, чтобы лучше понять распределение меток в наборе данных.
dsLabelCounts = transform(dsTrain,@(data){data{2} data{1}.Count});
labelCounts = readall(dsLabelCounts);
labels = vertcat(labelCounts{:,1});
counts = vertcat(labelCounts{:,2});Затем используйте гистограмму для визуализации распределения классов.
figure histogram(labels)

Гистограмма этикетки показывает, что набор данных несбалансирован и смещен по отношению к автомобилям и пешеходам, что может помешать подготовке надежного классификатора. Дисбаланс классов можно устранить путем избыточной выборки нечастых классов. Для набора данных Sydney Urban Objects копирование файлов, соответствующих нечастым классам, является простым методом устранения дисбаланса классов.
Сгруппируйте файлы по метке, подсчитайте количество наблюдений в классе и используйте randReplicateFiles вспомогательная функция, перечисленная в конце этого примера, для случайной избыточной выборки файлов до требуемого количества наблюдений на класс.
rng(0)
[G,classes] = findgroups(labels);
numObservations = splitapply(@numel,labels,G);
desiredNumObservationsPerClass = max(numObservations);
files = splitapply(@(x){randReplicateFiles(x,desiredNumObservationsPerClass)},dsTrain.Files,G);
files = vertcat(files{:});
dsTrain.Files = files;Дублирование файлов для устранения дисбаланса классов увеличивает вероятность переоборудования сети, поскольку большая часть данных обучения идентична. Чтобы компенсировать этот эффект, примените увеличение данных к учебным данным с помощью transform и augmentPointCloud вспомогательная функция, которая случайным образом вращает облако точек, случайным образом удаляет точки и случайным образом искажает точки гауссовым шумом.
dsTrain = transform(dsTrain,@augmentPointCloud);
Предварительный просмотр одного из дополненных обучающих образцов.
data = preview(dsTrain);
ptCloud = data{1,1};
label = data{1,2};
figure
pcshow(ptCloud.Location,[0 1 0],"MarkerSize",40,"VerticalAxisDir","down")
xlabel("X")
ylabel("Y")
zlabel("Z")
title(label)
Следует отметить, что, поскольку данные для измерения производительности обученной сети должны быть репрезентативными для исходного набора данных, увеличение данных не применяется к данным проверки или тестирования.
Для подготовки данных облака точек к обучению и прогнозированию требуются два этапа предварительной обработки.
Во-первых, чтобы включить пакетную обработку во время обучения, выберите фиксированное количество точек в каждом облаке точек. Оптимальное количество точек зависит от набора данных и количества точек, необходимых для точного захвата формы объекта. Чтобы помочь выбрать соответствующее количество точек, вычислите минимальное, максимальное и среднее количество точек в классе.
minPointCount = splitapply(@min,counts,G); maxPointCount = splitapply(@max,counts,G); meanPointCount = splitapply(@(x)round(mean(x)),counts,G); stats = table(classes,numObservations,minPointCount,maxPointCount,meanPointCount)
stats=14×5 table
classes numObservations minPointCount maxPointCount meanPointCount
______________ _______________ _____________ _____________ ______________
4wd 15 140 1955 751
building 15 193 8455 2708
bus 11 126 11767 2190
car 64 52 2377 528
pedestrian 107 20 297 110
pillar 15 80 751 357
pole 15 13 253 90
traffic lights 36 38 352 161
traffic sign 40 18 736 126
tree 24 53 2953 470
truck 9 445 3013 1376
trunk 42 32 766 241
ute 12 90 1380 580
van 28 91 5809 1125
Из-за большой величины внутриклассовой и межклассовой вариабельности в количестве баллов на класс, выбор значения, которое подходит для всех классов, затруднён. Одна эвристика состоит в том, чтобы выбрать достаточное количество точек для адекватного захвата формы объектов, не увеличивая при этом вычислительные затраты за счет обработки слишком большого количества точек. Значение 1024 обеспечивает хороший компромисс между этими двумя гранями. Можно также выбрать оптимальное количество точек на основе эмпирического анализа. Однако это выходит за рамки данного примера. Используйте transform для выбора 1024 точек в наборах обучения и проверки.
numPoints = 1024; dsTrain = transform(dsTrain,@(data)selectPoints(data,numPoints)); dsVal = transform(dsVal,@(data)selectPoints(data,numPoints));
Последним этапом предварительной обработки является нормализация данных облака точек между 0 и 1 для учета больших различий в диапазоне значений данных. Например, объекты ближе к лидаровому датчику имеют меньшие значения по сравнению с объектами, которые находятся дальше. Эти различия могут препятствовать сближению сети во время обучения. Использовать transform для нормализации данных облака точек в наборах обучения и проверки.
dsTrain = transform(dsTrain,@preprocessPointCloud); dsVal = transform(dsVal,@preprocessPointCloud);
Предварительный просмотр дополненных и предварительно обработанных учебных данных.
data = preview(dsTrain);
figure
pcshow(data{1,1},[0 1 0],"MarkerSize",40,"VerticalAxisDir","down");
xlabel("X")
ylabel("Y")
zlabel("Z")
title(data{1,2})
Модель классификации PointNet состоит из двух компонентов. Первый компонент представляет собой кодер облака точек, который учится кодировать разреженные данные облака точек в плотный характерный вектор. Второй компонент является классификатором, который предсказывает категориальный класс каждого закодированного облака точек.
Кроме того, модель Encoder (Кодировщик В Сети) состоит из четырех моделей, за которыми следует макс. операция.
Модель входного преобразования
Общая модель MLP
Модель преобразования элементов
Общая модель MLP
Совместно используемая модель MLP реализуется с использованием ряда операций свертки, пакетной нормализации и ReLU. Операция свертки сконфигурирована таким образом, что веса совместно используются в облаке входных точек. Модель преобразования состоит из общей MLP и обучаемой матрицы преобразования, которая применяется к каждому облаку точек. Совместно используемый MLP и макс. операция делают encoder (Кодер В Сети) инвариантным к порядку, в котором обрабатываются точки, в то время как модель преобразования обеспечивает инвариантность к изменениям ориентации.
Общие модели MLP и преобразования параметризуются количеством входных каналов и размерами скрытых каналов. Значения, выбранные в этом примере, выбираются путем настройки этих гиперпараметров в наборе данных Sydney Urban Objects. Обратите внимание на то, что если Вы хотите применить StartNet к другому набору данных, необходимо выполнить дополнительную гиперпараметрическую настройку.
Установите размер входного канала модели входного преобразования равным трем, а размер скрытого канала - 64, 128 и 256 и используйте initializeTransform вспомогательная функция, перечисленная в конце этого примера, для инициализации параметров модели.
inputChannelSize = 3; hiddenChannelSize1 = [64,128]; hiddenChannelSize2 = 256; [parameters.InputTransform, state.InputTransform] = initializeTransform(inputChannelSize,hiddenChannelSize1,hiddenChannelSize2);
Установите размер первого общего входного канала модели MLP равным трем, а размер скрытого канала равным 64 и используйте initializeSharedMLP вспомогательная функция, перечисленная в конце этого примера, для инициализации параметров модели.
inputChannelSize = 3; hiddenChannelSize = [64 64]; [parameters.SharedMLP1,state.SharedMLP1] = initializeSharedMLP(inputChannelSize,hiddenChannelSize);
Задайте для модели преобразования элементов размер входного канала 64, а для скрытого канала 64, 128 и 256 и используйте initializeTransform вспомогательная функция, перечисленная в конце этого примера, для инициализации параметров модели.
inputChannelSize = 64; hiddenChannelSize1 = [64,128]; hiddenChannelSize2 = 256; [parameters.FeatureTransform, state.FeatureTransform] = initializeTransform(inputChannelSize,hiddenChannelSize,hiddenChannelSize2);
Установите размер входного канала второй совместно используемой модели MLP 64, а размер скрытого канала 64 и используйте initializeSharedMLP функция, перечисленная в конце этого примера, для инициализации параметров модели.
inputChannelSize = 64; hiddenChannelSize = 64; [parameters.SharedMLP2,state.SharedMLP2] = initializeSharedMLP(inputChannelSize,hiddenChannelSize);
Модель классификатора PointNet состоит из общего MLP, полностью связанной операции и softmax активации. Установите входной размер модели классификатора 64, а размер скрытого канала 512 и 256 и используйте initalizeClassifier вспомогательная функция, перечисленная в конце этого примера, для инициализации параметров модели.
inputChannelSize = 64; hiddenChannelSize = [512,256]; numClasses = numel(classes); [parameters.ClassificationMLP, state.ClassificationMLP] = initializeClassificationMLP(inputChannelSize,hiddenChannelSize,numClasses);
Создание функции pointnetClassifier, перечисленных в разделе «Функция модели» в конце примера, чтобы вычислить выходные данные модели, основанной на StartNet. Функциональная модель принимает в качестве входных данных данные облака точек, обучаемые параметры модели, состояние модели и флаг, который определяет, возвращает ли модель выходные данные для обучения или прогнозирования. Сеть возвращает прогнозы для классификации облака входных точек.
Создание функции modelGradients, перечисленных в разделе «Функция градиентов модели» примера, который принимает в качестве входных данных параметры модели, состояние модели и мини-пакет входных данных, и возвращает градиенты потерь относительно обучаемых параметров в моделях и соответствующих потерь.
Подготовка на 10 периодов и загрузка данных партиями по 128. Установите начальную скорость обучения 0.002, а коэффициент регуляции L2 0.01.
numEpochs = 10; learnRate = 0.002; miniBatchSize = 128; l2Regularization = 0.01; learnRateDropPeriod = 15; learnRateDropFactor = 0.5;
Инициализируйте параметры оптимизации Adam.
gradientDecayFactor = 0.9; squaredGradientDecayFactor = 0.999;
Обучение модели с помощью пользовательского цикла обучения.
Перетасовать данные в начале тренировки.
Для каждой итерации:
Прочитайте пакет данных.
Оцените градиенты модели.
Примените регуляризацию веса L2.
Использовать adamupdate для обновления параметров модели.
Обновите график хода обучения.
В конце каждой эпохи оцените модель по набору данных проверки и соберите метрики путаницы для измерения точности классификации по мере прохождения обучения.
После завершения learnRateDropPeriod эпохи, снизить уровень обучения в раз learnRateDropFactor.
Инициализируйте скользящее среднее градиентов параметров и квадратов по элементам градиентов, используемых оптимизатором Адама.
avgGradients = []; avgSquaredGradients = [];
Обучить модель, если doTraining является правдой. В противном случае загрузите предварительно подготовленную сеть.
Обратите внимание, что обучение было проверено на NVIDIA Titan X с 12 ГБ памяти GPU. Если в графическом процессоре меньше памяти, во время обучения может не хватить памяти. Если это произойдет, опустите miniBatchSize. Обучение этой сети занимает около 5 минут. В зависимости от оборудования графического процессора это может занять больше времени.
doTraining = false; if doTraining % Create a minibatchqueue to batch data from training and validation % datastores. Use the batchData function, listed at the end of the % example, to batch the point cloud data and one-hot encode the label % data. numOutputsFromDSRead = 2; mbqTrain = minibatchqueue(dsTrain,numOutputsFromDSRead,... "MiniBatchSize", miniBatchSize,... "MiniBatchFcn",@batchData,... "MiniBatchFormat",["SCSB" "BC"]); mbqVal = minibatchqueue(dsVal,numOutputsFromDSRead,... "MiniBatchSize", miniBatchSize,... "MiniBatchFcn",@batchData,... "MiniBatchFormat",["SCSB" "BC"]); % Use the configureTrainingProgressPlot function, listed at the end of the % example, to initialize the training progress plot to display the training % loss, training accuracy, and validation accuracy. [lossPlotter, trainAccPlotter,valAccPlotter] = initializeTrainingProgressPlot; numClasses = numel(classes); iteration = 0; start = tic; for epoch = 1:numEpochs % Shuffle data every epoch. shuffle(mbqTrain); % Iterate through data set. while hasdata(mbqTrain) iteration = iteration + 1; % Read next batch of training data. [XTrain, YTrain] = next(mbqTrain); % Evaluate the model gradients and loss using dlfeval and the % modelGradients function. [gradients, loss, state, acc] = dlfeval(@modelGradients,XTrain,YTrain,parameters,state); % L2 regularization. gradients = dlupdate(@(g,p) g + l2Regularization*p,gradients,parameters); % Update the network parameters using the Adam optimizer. [parameters, avgGradients, avgSquaredGradients] = adamupdate(parameters, gradients, ... avgGradients, avgSquaredGradients, iteration,... learnRate,gradientDecayFactor, squaredGradientDecayFactor); % Update the training progress. D = duration(0,0,toc(start),"Format","hh:mm:ss"); title(lossPlotter.Parent,"Epoch: " + epoch + ", Elapsed: " + string(D)) addpoints(lossPlotter,iteration,double(gather(extractdata(loss)))) addpoints(trainAccPlotter,iteration,acc); drawnow end % Evaluate the model on validation data. cmat = sparse(numClasses,numClasses); while hasdata(mbqVal) % Read next batch of validation data. [XVal, YVal] = next(mbqVal); % Compute label predictions. isTraining = false; YPred = pointnetClassifier(XVal,parameters,state,isTraining); % Choose prediction with highest score as the class label for % XTest. [~,YValLabel] = max(YVal,[],1); [~,YPredLabel] = max(YPred,[],1); % Collect confusion metrics. cmat = aggreateConfusionMetric(cmat,YValLabel,YPredLabel); end % Update training progress plot with average classification accuracy. acc = sum(diag(cmat))./sum(cmat,"all"); addpoints(valAccPlotter,iteration,acc); % Upate the learning rate. if mod(epoch,learnRateDropPeriod) == 0 learnRate = learnRate * learnRateDropFactor; end % Reset training and validation data queues. reset(mbqTrain); reset(mbqVal); end else % Download pretrained model parameters, model state, and validation % results. pretrainedURL = 'https://ssd.mathworks.com/supportfiles/vision/data/pointnetSydneyUrbanObjects.zip'; pretrainedResults = downloadPretrainedPointNet(pretrainedURL); parameters = pretrainedResults.parameters; state = pretrainedResults.state; cmat = pretrainedResults.cmat; % Move model parameters to the GPU if possible and convert to a dlarray. parameters = prepareForPrediction(parameters,@(x)dlarray(toDevice(x,canUseGPU))); % Move model state to the GPU if possible. state = prepareForPrediction(state,@(x)toDevice(x,canUseGPU)); end
Отображение матрицы путаницы проверки.
figure chart = confusionchart(cmat,classes);

Вычислите среднюю точность обучения и проверки.
acc = sum(diag(cmat))./sum(cmat,"all")acc = 0.5742
Из-за ограниченного количества обучающих образцов в наборе данных Sydney Urban Objects повышение точности проверки более 60% является сложной задачей. Модель легко переопределяет данные обучения в отсутствие увеличения, определенного в augmentPointCloudData функция помощника. Для повышения надежности классификатора, необходимо дополнительное обучение.
Загрузка данных облака точек с помощью pcread, предварительно обработать облако точек, используя ту же функцию, что и во время обучения, и преобразовать результат в dlarray.
ptCloud = pcread("car.pcd"); X = preprocessPointCloud(ptCloud); dlX = dlarray(X{1},"SCSB");
Прогнозирование меток облака точек с помощью pointnetClassifier функция модели.
YPred = pointnetClassifier(dlX,parameters,state,false); [~,classIdx] = max(YPred,[],1);
Отображение облака точек и прогнозируемой метки с наивысшим баллом.
figure pcshow(ptCloud.Location,[0 1 0],"MarkerSize",40,"VerticalAxisDir","down") title(classes(classIdx))

Функция ModelGradients принимает в качестве входных данных мини-пакет данных dlX, соответствующая цель dlYи обучаемые параметры, и возвращает градиенты потерь относительно обучаемых параметров и соответствующих потерь. Потеря включает в себя член регуляризации, предназначенный для того, чтобы гарантировать, что матрица преобразования признаков, предсказанная шифратором, является приблизительно ортогональной. Чтобы вычислить градиенты, вычислите modelGradients с помощью функции dlfeval функция в обучающем цикле.
function [gradients, loss, state, acc] = modelGradients(X,Y,parameters,state) % Execute the model function. isTraining = true; [YPred,state,dlT] = pointnetClassifier(X,parameters,state,isTraining); % Add regularization term to ensure feature transform matrix is % approximately orthogonal. K = size(dlT,1); B = size(dlT, 4); I = repelem(eye(K),1,1,1,B); dlI = dlarray(I,"SSCB"); treg = mse(dlI,pagemtimes(dlT,permute(dlT,[2 1 3 4]))); factor = 0.001; % Compute the loss. loss = crossentropy(YPred,Y) + factor*treg; % Compute the parameter gradients with respect to the loss. gradients = dlgradient(loss, parameters); % Compute training accuracy metric. [~,YTest] = max(Y,[],1); [~,YPred] = max(YPred,[],1); acc = gather(extractdata(sum(YTest == YPred)./numel(YTest))); end
pointnetClassifier функция принимает в качестве входных данных данные облака точек dlX, параметры обучаемой модели, состояние модели и флаг isTraining, который определяет, возвращает ли модель выходные данные для обучения или прогнозирования. Затем функция вызывает кодировщик, а также многослойный перцептрон для извлечения классификационных признаков. Во время обучения отсев применяется после каждой операции перцептрона. После последнего перцептрона, fullyconnect операция сопоставляет функции классификации с количеством классов, и активация softmax используется для нормализации выходного сигнала в распределение вероятностей меток. Распределение вероятностей, обновленное состояние модели и матрица преобразования признаков, предсказанная с помощью кодера, возвращают в качестве выходных данных.
function [dlY,state,dlT] = pointnetClassifier(dlX,parameters,state,isTraining) % Invoke the PointNet encoder. [dlY,state,dlT] = pointnetEncoder(dlX,parameters,state,isTraining); % Invoke the classifier. p = parameters.ClassificationMLP.Perceptron; s = state.ClassificationMLP.Perceptron; for k = 1:numel(p) [dlY, s(k)] = perceptron(dlY,p(k),s(k),isTraining); % If training, apply inverted dropout with a probability of 0.3. if isTraining probability = 0.3; dropoutScaleFactor = 1 - probability; dropoutMask = ( rand(size(dlY), "like", dlY) > probability ) / dropoutScaleFactor; dlY = dlY.*dropoutMask; end end state.ClassificationMLP.Perceptron = s; % Apply final fully connected and softmax operations. weights = parameters.ClassificationMLP.FC.Weights; bias = parameters.ClassificationMLP.FC.Bias; dlY = fullyconnect(dlY,weights,bias); dlY = softmax(dlY); end
pointnetEncoder функция обрабатывает входной dlX с использованием входного преобразования, совместно используемого MLP, преобразования признаков, второго совместно используемого MLP и операции max, и возвращает результат операции max.
function [dlY,state,T] = pointnetEncoder(dlX,parameters,state,isTraining) % Input transform. [dlY,state.InputTransform] = dataTransform(dlX,parameters.InputTransform,state.InputTransform,isTraining); % Shared MLP. [dlY,state.SharedMLP1.Perceptron] = sharedMLP(dlY,parameters.SharedMLP1.Perceptron,state.SharedMLP1.Perceptron,isTraining); % Feature transform. [dlY,state.FeatureTransform,T] = dataTransform(dlY,parameters.FeatureTransform,state.FeatureTransform,isTraining); % Shared MLP. [dlY,state.SharedMLP2.Perceptron] = sharedMLP(dlY,parameters.SharedMLP2.Perceptron,state.SharedMLP2.Perceptron,isTraining); % Max operation. dlY = max(dlY,[],1); end
Общий многослойный perceptron функция обрабатывает входной dlX с помощью ряда операций перцептрона и возвращает результат последнего перцептрона.
function [dlY,state] = sharedMLP(dlX,parameters,state,isTraining) dlY = dlX; for k = 1:numel(parameters) [dlY, state(k)] = perceptron(dlY,parameters(k),state(k),isTraining); end end
Функция перцептрона обрабатывает входной dlX с помощью свертки, пакетной нормализации и операции relu и возвращает выходные данные операции ReLU.
function [dlY,state] = perceptron(dlX,parameters,state,isTraining) % Convolution. W = parameters.Conv.Weights; B = parameters.Conv.Bias; dlY = dlconv(dlX,W,B); % Batch normalization. Update batch normalization state when training. offset = parameters.BatchNorm.Offset; scale = parameters.BatchNorm.Scale; trainedMean = state.BatchNorm.TrainedMean; trainedVariance = state.BatchNorm.TrainedVariance; if isTraining [dlY,trainedMean,trainedVariance] = batchnorm(dlY,offset,scale,trainedMean,trainedVariance); % Update state. state.BatchNorm.TrainedMean = trainedMean; state.BatchNorm.TrainedVariance = trainedVariance; else dlY = batchnorm(dlY,offset,scale,trainedMean,trainedVariance); end % ReLU. dlY = relu(dlY); end
dataTransform функция обрабатывает входные данные dlX использование совместно используемой MLP, макс. операции и другой совместно используемой MLP для прогнозирования матрицы преобразования T. Матрица преобразования применяется к входу dlX с использованием операции умножения пакетной матрицы. Функция возвращает результат умножения пакетной матрицы и матрицы преобразования.
function [dlY,state,T] = dataTransform(dlX,parameters,state,isTraining) % Shared MLP. [dlY,state.Block1.Perceptron] = sharedMLP(dlX,parameters.Block1.Perceptron,state.Block1.Perceptron,isTraining); % Max operation. dlY = max(dlY,[],1); % Shared MLP. [dlY,state.Block2.Perceptron] = sharedMLP(dlY,parameters.Block2.Perceptron,state.Block2.Perceptron,isTraining); % Transform net (T-Net). Apply last fully connected operation as W*X to % predict tranformation matrix T. dlY = squeeze(dlY); % N-by-B T = parameters.Transform * stripdims(dlY); % K^2-by-B % Reshape T into a square matrix. K = sqrt(size(T,1)); T = reshape(T,K,K,1,[]); % [K K 1 B] T = T + eye(K); % Apply to input dlX using batch matrix multiply. [C,B] = size(dlX,[3 4]); % [M 1 K B] dlX = reshape(dlX,[],C,1,B); % [M K 1 B] Y = pagemtimes(dlX,T); dlY = dlarray(Y,"SCSB"); end
initializeTransform Функция initializeTransform принимает за вход размер канала и количество скрытых каналов для двух совместно используемых MLP и возвращает инициализированные параметры в структуре. Параметры инициализируются с помощью He weight initialization [3].
function [params,state] = initializeTransform(inputChannelSize,block1,block2) [params.Block1,state.Block1] = initializeSharedMLP(inputChannelSize,block1); [params.Block2,state.Block2] = initializeSharedMLP(block1(end),block2); % Parameters for the transform matrix. params.Transform = dlarray(zeros(inputChannelSize^2,block2(end))); end
initializeSharedMLP ФункцияФункция initialitySharedMLP принимает в качестве входных значений размер канала и скрытый размер канала и возвращает инициализированные параметры в структуре. Параметры инициализируются с помощью инициализации He weight.
function [params,state] = initializeSharedMLP(inputChannelSize,hiddenChannelSize) weights = initializeWeightsHe([1 1 inputChannelSize hiddenChannelSize(1)]); bias = zeros(hiddenChannelSize(1),1,"single"); p.Conv.Weights = dlarray(weights); p.Conv.Bias = dlarray(bias); p.BatchNorm.Offset = dlarray(zeros(hiddenChannelSize(1),1,"single")); p.BatchNorm.Scale = dlarray(ones(hiddenChannelSize(1),1,"single")); s.BatchNorm.TrainedMean = zeros(hiddenChannelSize(1),1,"single"); s.BatchNorm.TrainedVariance = ones(hiddenChannelSize(1),1,"single"); params.Perceptron(1) = p; state.Perceptron(1) = s; for k = 2:numel(hiddenChannelSize) weights = initializeWeightsHe([1 1 hiddenChannelSize(k-1) hiddenChannelSize(k)]); bias = zeros(hiddenChannelSize(k),1,"single"); p.Conv.Weights = dlarray(weights); p.Conv.Bias = dlarray(bias); p.BatchNorm.Offset = dlarray(zeros(hiddenChannelSize(k),1,"single")); p.BatchNorm.Scale = dlarray(ones(hiddenChannelSize(k),1,"single")); s.BatchNorm.TrainedMean = zeros(hiddenChannelSize(k),1,"single"); s.BatchNorm.TrainedVariance = ones(hiddenChannelSize(k),1,"single"); params.Perceptron(k) = p; state.Perceptron(k) = s; end end
initializeClassificationMLP Функция initializeClassificationMLP функция принимает в качестве входного значения размер канала, размер скрытого канала и количество классов и возвращает инициализированные параметры в структуре. Совместно используемый MLP инициализируется с помощью He weight initialization, а окончательная полностью подключенная операция инициализируется с использованием случайных гауссовых значений.
function [params,state] = initializeClassificationMLP(inputChannelSize,hiddenChannelSize,numClasses) [params,state] = initializeSharedMLP(inputChannelSize,hiddenChannelSize); weights = initializeWeightsGaussian([numClasses hiddenChannelSize(end)]); bias = zeros(numClasses,1,"single"); params.FC.Weights = dlarray(weights); params.FC.Bias = dlarray(bias); end
initializeWeightsHe Функция initializeWeightsHe инициализирует параметры с помощью инициализации He.
function x = initializeWeightsHe(sz) fanIn = prod(sz(1:3)); stddev = sqrt(2/fanIn); x = stddev .* randn(sz); end
initializeWeightsGaussian Функция initializeWeightsGaussian функция инициализирует параметры, используя гауссову инициализацию со стандартным отклонением 0,01.
function x = initializeWeightsGaussian(sz) x = randn(sz,"single") .* 0.01; end
preprocessPointCloudData Функция preprocessPointCloudData функция извлекает данные точек X, Y, Z из входных данных и нормализует данные между 0 и 1. Функция возвращает нормализованные данные X, Y, Z.
function data = preprocessPointCloud(data) if ~iscell(data) data = {data}; end numObservations = size(data,1); for i = 1:numObservations % Scale points between 0 and 1. xlim = data{i,1}.XLimits; ylim = data{i,1}.YLimits; zlim = data{i,1}.ZLimits; xyzMin = [xlim(1) ylim(1) zlim(1)]; xyzDiff = [diff(xlim) diff(ylim) diff(zlim)]; data{i,1} = (data{i,1}.Location - xyzMin) ./ xyzDiff; end end
selectPoints Функция selectPoints функция выполняет выборку требуемого количества точек. Если облако точек содержит больше требуемого количества точек, функция использует pcdownsample для случайного выбора точек. В противном случае функция реплицирует данные для получения требуемого количества точек.
function data = selectPoints(data,numPoints) % Select the desired number of points by downsampling or replicating % point cloud data. numObservations = size(data,1); for i = 1:numObservations ptCloud = data{i,1}; if ptCloud.Count > numPoints percentage = numPoints/ptCloud.Count; data{i,1} = pcdownsample(ptCloud,"random",percentage); else replicationFactor = ceil(numPoints/ptCloud.Count); ind = repmat(1:ptCloud.Count,1,replicationFactor); data{i,1} = select(ptCloud,ind(1:numPoints)); end end end
augmentPointCloudData функция случайным образом поворачивает облако точек вокруг оси z, случайным образом сбрасывает 30% точек и случайным образом искажает положение точки гауссовым шумом.
function data = augmentPointCloud(data) numObservations = size(data,1); for i = 1:numObservations ptCloud = data{i,1}; % Rotate the point cloud about "up axis", which is Z for this data set. tform = randomAffine3d(... "XReflection", true,... "YReflection", true,... "Rotation",@randomRotationAboutZ); ptCloud = pctransform(ptCloud,tform); % Randomly drop out 30% of the points. if rand > 0.5 ptCloud = pcdownsample(ptCloud,'random',0.3); end if rand > 0.5 % Jitter the point locations with Gaussian noise with a mean of 0 and % a standard deviation of 0.02 by creating a random displacement field. D = 0.02 * randn(size(ptCloud.Location)); ptCloud = pctransform(ptCloud,D); end data{i,1} = ptCloud; end end function [rotationAxis,theta] = randomRotationAboutZ() rotationAxis = [0 0 1]; theta = 2*pi*rand; end
aggregateConfusionMetric Функция aggregateConfusionMetric функция постепенно заполняет матрицу путаницы на основе прогнозируемых результатов YPred и ожидаемые результаты YTest.
function cmat = aggreateConfusionMetric(cmat,YTest,YPred) YTest = gather(extractdata(YTest)); YPred = gather(extractdata(YPred)); [m,n] = size(cmat); cmat = cmat + full(sparse(YTest,YPred,1,m,n)); end
initializeTrainingProgressPlot Функция initializeTrainingProgressPlot функция настраивает два графика для отображения потерь при обучении, точности обучения и точности проверки.
function [plotter,trainAccPlotter,valAccPlotter] = initializeTrainingProgressPlot() % Plot the loss, training accuracy, and validation accuracy. figure % Loss plot subplot(2,1,1) plotter = animatedline; xlabel("Iteration") ylabel("Loss") % Accuracy plot subplot(2,1,2) trainAccPlotter = animatedline('Color','b'); valAccPlotter = animatedline('Color','g'); legend('Training Accuracy','Validation Accuracy','Location','northwest'); xlabel("Iteration") ylabel("Accuracy") end
replicateFiles Функция replicateFiles функция случайным образом переполняет набор файлов и возвращает набор файлов с numDesired элементы.
function files = randReplicateFiles(files,numDesired) n = numel(files); ind = randi(n,numDesired,1); files = files(ind); end
downloadSydneyUrbanObjects Функция downloadSydneyUrbanObjects функция загружает набор данных и сохраняет его во временном каталоге.
function datapath = downloadSydneyUrbanObjects(dataLoc) if nargin == 0 dataLoc = pwd; end dataLoc = string(dataLoc); url = "http://www.acfr.usyd.edu.au/papers/data/"; name = "sydney-urban-objects-dataset.tar.gz"; datapath = fullfile(dataLoc,'sydney-urban-objects-dataset'); if ~exist(datapath,'dir') disp('Downloading Sydney Urban Objects data set...'); untar(url+name,dataLoc); end end
loadSydneyUrbanObjectsData ФункцияThe loadSydneyUrbanObjectsData создает хранилище данных для загрузки данных облака точек и меток из набора данных Sydney Urban Objects.
function ds = loadSydneyUrbanObjectsData(datapath,folds) if nargin == 0 return; end if nargin < 2 folds = 1:4; end datapath = string(datapath); path = fullfile(datapath,'objects',filesep); % Add folds to datastore. foldNames{1} = importdata(fullfile(datapath,'folds','fold0.txt')); foldNames{2} = importdata(fullfile(datapath,'folds','fold1.txt')); foldNames{3} = importdata(fullfile(datapath,'folds','fold2.txt')); foldNames{4} = importdata(fullfile(datapath,'folds','fold3.txt')); names = foldNames(folds); names = vertcat(names{:}); fullFilenames = append(path,names); ds = fileDatastore(fullFilenames,'ReadFcn',@extractTrainingData,'FileExtensions','.bin'); end
batchData Функция batchData функция сопоставляет данные в пакеты и перемещает данные в графический процессор для обработки.
function [X,Y] = batchData(ptCloud,labels) X = cat(4,ptCloud{:}); labels = cat(1,labels{:}); Y = onehotencode(labels,2); end
extractTrainingData ФункцияФункция extractTrainingData извлекает данные облака точек и метки из набора данных Sydney Urban Objects.
function dataOut = extractTrainingData(fname) [pointData,intensity] = readbin(fname); [~,name] = fileparts(fname); name = string(name); name = extractBefore(name,'.'); name = replace(name,'_',' '); labelNames = ["4wd","building","bus","car","pedestrian","pillar",... "pole","traffic lights","traffic sign","tree","truck","trunk","ute","van"]; label = categorical(name,labelNames); dataOut = {pointCloud(pointData,'Intensity',intensity),label}; end
readbin Функция readbin считывает данные облака точек из двоичных файлов объекта Sydney Urban Object.
function [pointData,intensity] = readbin(fname) % readbin Read point and intensity data from Sydney Urban Object binary % files. % names = ['t','intensity','id',... % 'x','y','z',... % 'azimuth','range','pid'] % % formats = ['int64', 'uint8', 'uint8',... % 'float32', 'float32', 'float32',... % 'float32', 'float32', 'int32'] fid = fopen(fname, 'r'); c = onCleanup(@() fclose(fid)); fseek(fid,10,-1); % Move to the first X point location 10 bytes from beginning X = fread(fid,inf,'single',30); fseek(fid,14,-1); Y = fread(fid,inf,'single',30); fseek(fid,18,-1); Z = fread(fid,inf,'single',30); fseek(fid,8,-1); intensity = fread(fid,inf,'uint8',33); pointData = [X,Y,Z]; end
downloadPretrainedPointNet Функция downloadPretrainedPointNet загружает предварительно подготовленную модель точечной сети.
function data = downloadPretrainedPointNet(pretrainedURL) % Download and load a pretrained pointnet model. if ~exist('pointnetSydneyUrbanObjects.mat', 'file') if ~exist('pointnetSydneyUrbanObjects.zip', 'file') disp('Downloading pretrained detector (5 MB)...'); websave('pointnetSydneyUrbanObjects.zip', pretrainedURL); end unzip('pointnetSydneyUrbanObjects.zip'); end data = load("pointnetSydneyUrbanObjects.mat"); end
prepareForPrediction Функция prepareForPrediction используется для применения определяемой пользователем функции к вложенным данным структуры. Используется для перемещения параметров модели и данных состояния в графический процессор.
function p = prepareForPrediction(p,fcn) for i = 1:numel(p) p(i) = structfun(@(x)invoke(fcn,x),p(i),'UniformOutput',0); end function data = invoke(fcn,data) if isstruct(data) data = prepareForPrediction(data,fcn); else data = fcn(data); end end end % Move data to the GPU. function x = toDevice(x,useGPU) if useGPU x = gpuArray(x); end end
[1] Чарльз, Р. Ци, Хао Су, Мо Кайчун и Леонидас Дж. Гибас. «StartNet: глубокое обучение наборам точек для классификации и сегментации 3D». В 2017 году Конференция IEEE по компьютерному зрению и распознаванию образов (CVPR), 77-85. Гонолулу, HI: IEEE, 2017. https://doi.org/10.1109/CVPR.2017.16.
[2] де Дьюж, Марк, Аластер Квадрас, Кальвин Хунг и Бертран Дуйяр. «Неуправляемое обучение функциям классификации наружных сканирований 3D». В Австралазийской конференции по робототехнике и автоматизации 2013 (ACRA 13). Сидней, Австралия: АКРА, 2013.
[3] Хэ, Каймин, Сянъу Чжан, Шаоцин Жэнь и Цзянь Сунь. «Углубляясь в выпрямители: превосходя показатели на уровне человека по классификации ImageNet». В 2015 году Международная конференция IEEE по компьютерному зрению (ICCV), 1026-34. Сантьяго, Чили: IEEE, 2015. https://doi.org/10.1109/ICCV.2015.123.