Классификация облаков точек Используя глубокое обучение PointNet

В этом примере показано, как обучить сеть PointNet для классификации облаков точек.

Данные об облаке точек получены множеством датчиков, таких как лидар, радар и камеры глубины. Эти датчики получают 3-D информацию о положении об объектах в сцене, которая полезна для многих приложений в автономном управлении автомобилем и дополненной реальности. Например, отличительные транспортные средства от пешеходов очень важно для планирования пути автономного транспортного средства. Однако учебные устойчивые классификаторы с данными об облаке точек сложны из-за разреженности данных на объект, объектные поглощения газов и шум датчика. Методы глубокого обучения, как показывали, обратились ко многим из этих проблем путем изучения устойчивых представлений функции непосредственно от данных об облаке точек. Один из оригинальных методов глубокого обучения для классификации облаков точек является PointNet [1].

Этот пример обучает классификатор PointNet на наборе данных Сидни Урбана Обджектса, созданном Сиднейским университетом [2]. Этот набор данных обеспечивает набор данных об облаке точек, полученных городской средой с помощью датчика лидара. Набор данных имеет 100 помеченных объектов от 14 различных категорий, таких как автомобиль, пешеход и шина.

Загрузите набор данных

Загрузите и извлеките набор данных Сидни Урбана Обджектса к временной директории.

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)

Гистограмма метки показывает, что набор данных является неустойчивым и склоняется к автомобилям и пешеходам, которые могут предотвратить обучение устойчивого классификатора. Можно обратиться к неустойчивости класса путем сверхдискретизации нечастых классов. Для набора данных Сидни Урбана Обджектса, копируя файлы, соответствующие нечастым классам, простой метод обратиться к неустойчивости класса.

Сгруппируйте файлы меткой, считайте количество наблюдений в классе и используйте 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     

Из-за большой суммы внутрикласса и изменчивости межкласса в числе точек в классе, выбирая значение, которое соответствует всем классам, затрудняет. Одна эвристика должна выбрать достаточно точек, чтобы соответственно получить форму объектов, не увеличивая вычислительную стоимость путем обработки слишком многих точек. Значение 1 024 обеспечивает хороший компромисс между этими двумя фасетами. Можно также выбрать оптимальное число точек на основе эмпирического анализа. Однако это выходит за рамки этого примера. Используйте transform функционируйте, чтобы выбрать 1 024 точки в наборах обучения и валидации.

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

Модель классификации PointNet состоит из двух компонентов. Первый компонент является энкодером облака точек, который учится кодировать разреженные данные об облаке точек в плотный характеристический вектор. Второй компонент является классификатором, который предсказывает категориальный класс каждого закодированного облака точек.

Модель энкодера PointNet далее состоит из четырех моделей, сопровождаемых макс. операцией.

  1. Введите преобразовывают модель

  2. Разделяемая модель MLP

  3. Покажите преобразовывают модель

  4. Разделяемая модель MLP

Разделяемая модель MLP реализована с помощью серии свертки, нормализации партии. и операций ReLU. Операция свертки сконфигурирована таким образом, что веса совместно используются через облако точки ввода. Модель преобразования состоит из разделяемого MLP, и learnable преобразовывают матрицу, которая применяется к каждому облаку точек. Разделяемый MLP и макс. операция делают инвариант энкодера PointNet к порядку, в котором обрабатываются точки, в то время как модель преобразования предоставляет инвариантность изменениям ориентации.

Задайте параметры модели энкодера PointNet

Разделяемые MLP и преобразовывают модели, параметрируются количеством входных каналов и скрытых размеров канала. Значения, выбранные в этом примере, выбраны путем настройки этих гиперпараметров на наборе данных Сидни Урбана Обджектса. Обратите внимание на то, что, если вы хотите применить PointNet к различному набору данных, необходимо выполнить дополнительную настройку гиперпараметра.

Установите вход, преобразовывают входной размер канала модели к три и скрытые размеры канала к 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

Модель классификатора PointNet состоит из разделяемого MLP, полностью связанной операции и softmax активации. Установите входной размер модели классификатора на 64 и скрытый размер канала к 512 и 256 и используйте initalizeClassifier функция помощника, перечисленная в конце этого примера, чтобы инициализировать параметры модели.

inputChannelSize = 64;
hiddenChannelSize = [512,256];
numClasses = numel(classes);
[parameters.ClassificationMLP, state.ClassificationMLP] = initializeClassificationMLP(inputChannelSize,hiddenChannelSize,numClasses);

Задайте функцию PointNet

Создайте функциональный pointnetClassifier, перечисленный в разделе Model Function в конце примера, чтобы вычислить выходные параметры модели PointNet. Модель функции берет в качестве входа данные об облаке точек, learnable параметры модели, состояние модели и флаг, который задает, возвращает ли модель выходные параметры для обучения или предсказания. Сеть возвращает предсказания для классификации облака точки ввода.

Функция градиентов модели Define

Создайте функциональный modelGradients, перечисленный в разделе Model Gradients Function примера, который берет в качестве входа параметры модели, состояние модели и мини-пакет входных данных, и возвращает градиенты потери относительно настраиваемых параметров в моделях и соответствующей потери.

Задайте опции обучения

Обучайтесь в течение 10 эпох и загрузите данные в пакетах 128. Установите начальную скорость обучения на 0,002 и фактор регуляризации L2 к 0,01.

numEpochs = 10;
learnRate = 0.002;
miniBatchSize = 128;
l2Regularization = 0.01;
learnRateDropPeriod = 15;
learnRateDropFactor = 0.5;

Инициализируйте опции для оптимизации Адама.

gradientDecayFactor = 0.9;
squaredGradientDecayFactor = 0.999;

Обучите PointNet

Обучите модель с помощью пользовательского учебного цикла.

Переставьте данные в начале обучения.

Для каждой итерации:

  • Считайте пакет данных.

  • Оцените градиенты модели.

  • Примените регуляризацию веса L2.

  • Используйте adamupdate обновить параметры модели.

  • Обновите график процесса обучения.

В конце каждой эпохи оцените модель против набора данных валидации и соберите метрики беспорядка, чтобы измерить точность классификации, в то время как обучение прогрессирует.

После завершения learnRateDropPeriod эпохи, уменьшайте скорость обучения на коэффициент learnRateDropFactor.

Инициализируйте скользящее среднее значение градиентов параметра и поэлементные квадраты градиентов, используемых оптимизатором Адама.

avgGradients = [];
avgSquaredGradients = [];

Обучите модель если doTraining верно. В противном случае загружает предварительно обученную сеть.

Обратите внимание на то, что обучение было проверено на Титане NVIDIA X с 12 Гбайт памяти графического процессора. Если ваш графический процессор имеет меньше памяти, у можно закончиться память во время обучения. Если это происходит, понизьте 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

Из-за ограниченного количества обучающих выборок в наборе данных Сидни Урбана Обджектса, увеличивая точность валидации вне 60% сложно. Модель легко сверхсоответствует обучающим данным в отсутствие увеличения, заданного в augmentPointCloudData функция помощника. Чтобы улучшить робастность классификатора PointNet, дополнительное обучение требуется.

Классифицируйте данные об облаке точек Используя PointNet

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

Функция классификатора PointNet

pointnetClassifier функционируйте берет в качестве входа данные об облаке точек dlX, learnable параметры модели, состояние модели и флаг isTraining, который задает, возвращает ли модель выходные параметры для обучения или предсказания. Затем функция вызывает энкодер PointNet и многоуровневый perceptron, чтобы извлечь функции классификации. Во время обучения уволенный применяется после каждой perceptron операции. После последнего perceptron, fullyconnect операция сопоставляет функции классификации с количеством классов, и softmax активация используется, чтобы нормировать выход в вероятностное распределение меток. Вероятностное распределение, обновленное состояние модели и матрица преобразования функции, предсказанная энкодером PointNet, возвращены как выходные параметры.

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

Функция энкодера PointNet

pointnetEncoder функциональные процессы, которые вход dlX использование входа преобразовывает, разделяемый MLP, функция, преобразовывают, секунда совместно использовала MLP и макс. операцию, и возвращает результат макс. операции.

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

Разделяемый многоуровневый perceptron функциональные процессы вход dlX использование ряда perceptron операций и возвращают результат последнего perceptron.

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

Функция Perceptron

Функция perceptron обрабатывает вход 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 функционируйте берет в качестве входа, размер канала и количество скрытых каналов для двух совместно использовали MLPs и возвращают инициализированные параметры в struct. Параметры инициализируются с помощью Него инициализация веса [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 Функция

Функция initializeSharedMLP берет в качестве входа размер канала и скрытый размер канала, и возвращает инициализированные параметры в struct. Параметры инициализируются с помощью Него инициализация веса.

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 функционируйте берет в качестве входа размер канала, скрытый размер канала и количество классов и возвращает инициализированные параметры в struct. Разделяемый MLP инициализируется с помощью Него, инициализация веса и финал полностью соединились, операция инициализируется с помощью случайных Гауссовых значений.

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 функция инициализирует использование параметров Он инициализация.

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 функция создает datastore для облака пункта погрузки и данных о метке из набора данных Сидни Урбана Обджектса.

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 функционируют облако точек извлечений и данные о метке из набора данных Сидни Урбана Обджектса.

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 функция считывает данные об облаке точек из двоичных файлов Сидни Урбана Обджекта.

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 функционируйте загружает предварительно обученную pointnet модель.

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] Чарльз, Р. Ци, Хао Су, Мо Кэйчун и Леонидас Дж. Гуибас. “PointNet: Глубокое обучение на Наборах Точки для 3D Классификации и Сегментации”. На 2 017 Конференциях по IEEE по Компьютерному зрению и Распознаванию образов (CVPR), 77–85. Гонолулу, HI: IEEE, 2017. https://doi.org/10.1109/CVPR.2017.16.

[2] де Деж, Марк, Аластер Куэдрас, Келвин Хун и Бертран Дуиллар. "Безнадзорная Функция, Учащаяся для Классификации Наружных 3D Сканов". На австралазийской Конференции по Робототехнике и Автоматизации 2013 (ACRA 13). Сидней, Австралия: ACRA, 2013.

[3] Он, Kaiming, Сянюй Чжан, Шаоцин Жэнь и Цзянь Сунь. “Копаясь Глубоко в Выпрямителях: Превышение Эффективности Человеческого Уровня на Классификации ImageNet”. На 2 015 Международных конференциях IEEE по вопросам Компьютерного зрения (ICCV), 1026–34. Сантьяго, Чили: IEEE, 2015. https://doi.org/10.1109/ICCV.2015.123.

Похожие темы