Задайте пользовательский слой классификации пикселей с потерей Dice

Задайте и создайте пользовательский слой классификации пикселей, который использует потерю Dice.

Можно использовать этот слой, чтобы обучить сети семантической сегментации. Чтобы узнать больше о создании пользовательских слоев глубокого обучения, смотрите, Задают Пользовательские Слои Глубокого обучения (Deep Learning Toolbox).

Поставьте на карту потерю

Потеря Dice основана на коэффициенте подобия Sørensen-Dice для измерения перекрытия между двумя сегментированными изображениями. Обобщенная потеря Dice [1,2] L поскольку между одним изображением Y и соответствующая основная истина T дают

L=1-2k=1Kwkm=1MYкмTкмk=1Kwkm=1MYкм2+Tкм2 ,

где K количество классов, M число элементов по первым двум измерениям Y, иwk специфичный для класса фактор взвешивания, который управляет вкладом, который каждый класс делает к потере. wk обычно обратная область ожидаемой области:

wk=1(m=1MTкм)2

Это взвешивание помогает возразить, что влияние более крупных областей на Dice выигрывает, и облегчает для сети изучать, как сегментировать меньшие области.

Шаблон слоя классификации

Скопируйте шаблон слоя классификации в новый файл в MATLAB®. Этот шаблон обрисовывает в общих чертах структуру слоя классификации и включает функции, которые задают поведение слоя. Остальная часть примера показывает, как завершить dicePixelClassificationLayer.

classdef dicePixelClassificationLayer < nnet.layer.ClassificationLayer

   properties
      % Optional properties
   end

   methods

        function loss = forwardLoss(layer, Y, T)
            % Layer forward loss function goes here.
        end
        
        function dLdY = backwardLoss(layer, Y, T)
            % Layer backward loss function goes here.
        end
    end
end

Объявите свойства слоя

По умолчанию пользовательские выходные слои имеют следующие свойства:

  • Name — Имя слоя, заданное как вектор символов или скаляр строки. Чтобы включать этот слой в график слоя, необходимо задать непустое уникальное имя слоя. Если вы обучаете серийную сеть с этим слоем и Name установлен в '', затем программное обеспечение автоматически присваивает имя в учебное время.

  • Description — Короткое описание слоя, заданного как вектор символов или скаляр строки. Это описание появляется, когда слой отображен в Layer массив. Если вы не задаете описание слоя, то программное обеспечение отображает имя класса слоя.

  • Type — Тип слоя, заданного как вектор символов или скаляр строки. Значение Type появляется, когда слой отображен в Layer массив. Если вы не задаете тип слоя, то программное обеспечение отображает 'Classification layer' или 'Regression layer'.

Пользовательские слои классификации также имеют следующее свойство:

  • Classes — Классы выходного слоя, заданного как категориальный вектор, массив строк, массив ячеек из символьных векторов или 'auto'. Если Classes 'auto', затем программное обеспечение автоматически устанавливает классы в учебное время. Если вы задаете массив строк или массив ячеек из символьных векторов str, затем программное обеспечение устанавливает классы выходного слоя к categorical(str,str). Значением по умолчанию является 'auto'.

Если слой не имеет никаких других свойств, то можно не использовать properties раздел.

Потеря Dice требует, чтобы маленькое постоянное значение предотвратило деление на нуль. Задайте свойство, Epsilon, содержать это значение.

classdef dicePixelClassificationLayer < nnet.layer.ClassificationLayer

    properties(Constant)
       % Small constant to prevent division by zero. 
       Epsilon = 1e-8;

    end

    ...
end

Создайте функцию конструктора

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

Задайте дополнительное имя входного параметра, чтобы присвоить Name свойство при создании.

        function layer = dicePixelClassificationLayer(name)
            % layer =  dicePixelClassificationLayer(name) creates a Dice
            % pixel classification layer with the specified name.
            
            % Set layer name.          
            layer.Name = name;
            
            % Set layer description.
            layer.Description = 'Dice loss';
        end

Создайте прямую функцию потерь

Создайте функцию с именем forwardLoss это возвращает взвешенную перекрестную энтропийную потерю между прогнозами, сделанными сетью и учебными целями. Синтаксис для forwardLoss loss = forwardLoss(layer, Y, T), где Y выход предыдущего слоя и T представляет учебные цели.

Для проблем семантической сегментации, размерностей T совпадайте с размерностью Y, где Y 4-D массив размера H- W- K- N, где K количество классов и N мини-пакетный размер.

Размер Y зависит от выхода предыдущего слоя. Гарантировать тот Y одного размера с T, необходимо включать слой, который выводит правильный размер перед выходным слоем. Например, чтобы гарантировать тот Y 4-D массив музыки прогноза к K классы, можно включать полносвязный слой размера K или сверточный слой с K фильтры сопровождаются softmax слоем перед выходным слоем.

        function loss = forwardLoss(layer, Y, T)
            % loss = forwardLoss(layer, Y, T) returns the Dice loss between
            % the predictions Y and the training targets T.   

            % Weights by inverse of region size.
            W = 1 ./ sum(sum(T,1),2).^2;
            
            intersection = sum(sum(Y.*T,1),2);
            union = sum(sum(Y.^2 + T.^2, 1),2);          
            
            numer = 2*sum(W.*intersection,3) + layer.Epsilon;
            denom = sum(W.*union,3) + layer.Epsilon;
            
            % Compute Dice score.
            dice = numer./denom;
            
            % Return average Dice loss.
            N = size(Y,4);
            loss = sum((1-dice))/N;
            
        end

Создайте обратную функцию потерь

Создайте обратную функцию потерь, которая возвращает производные потери Dice относительно прогнозов Y. Синтаксис для backwardLoss loss = backwardLoss(layer, Y, T), где Y выход предыдущего слоя и T представляет учебные цели.

Размерности Y и T совпадают с входными параметрами в forwardLoss.

        function dLdY = backwardLoss(layer, Y, T)
            % dLdY = backwardLoss(layer, Y, T) returns the derivatives of
            % the Dice loss with respect to the predictions Y.
            
            % Weights by inverse of region size.
            W = 1 ./ sum(sum(T,1),2).^2;
            
            intersection = sum(sum(Y.*T,1),2);
            union = sum(sum(Y.^2 + T.^2, 1),2);
     
            numer = 2*sum(W.*intersection,3) + layer.Epsilon;
            denom = sum(W.*union,3) + layer.Epsilon;
            
            N = size(Y,4);
      
            dLdY = (2*W.*Y.*numer./denom.^2 - 2*W.*T./denom)./N;
        end

Завершенный слой

Завершенный слой обеспечивается в dicePixelClassificationLayer.m.

classdef dicePixelClassificationLayer < nnet.layer.ClassificationLayer
    % This layer implements the generalized Dice loss function for training
    % semantic segmentation networks.
    
    properties(Constant)
        % Small constant to prevent division by zero. 
        Epsilon = 1e-8;
    end
    
    methods
        
        function layer = dicePixelClassificationLayer(name)
            % layer =  dicePixelClassificationLayer(name) creates a Dice
            % pixel classification layer with the specified name.
            
            % Set layer name.          
            layer.Name = name;
            
            % Set layer description.
            layer.Description = 'Dice loss';
        end
        
        
        function loss = forwardLoss(layer, Y, T)
            % loss = forwardLoss(layer, Y, T) returns the Dice loss between
            % the predictions Y and the training targets T.   

            % Weights by inverse of region size.
            W = 1 ./ sum(sum(T,1),2).^2;
            
            intersection = sum(sum(Y.*T,1),2);
            union = sum(sum(Y.^2 + T.^2, 1),2);          
            
            numer = 2*sum(W.*intersection,3) + layer.Epsilon;
            denom = sum(W.*union,3) + layer.Epsilon;
            
            % Compute Dice score.
            dice = numer./denom;
            
            % Return average Dice loss.
            N = size(Y,4);
            loss = sum((1-dice))/N;
            
        end
        
        function dLdY = backwardLoss(layer, Y, T)
            % dLdY = backwardLoss(layer, Y, T) returns the derivatives of
            % the Dice loss with respect to the predictions Y.
            
            % Weights by inverse of region size.
            W = 1 ./ sum(sum(T,1),2).^2;
            
            intersection = sum(sum(Y.*T,1),2);
            union = sum(sum(Y.^2 + T.^2, 1),2);
     
            numer = 2*sum(W.*intersection,3) + layer.Epsilon;
            denom = sum(W.*union,3) + layer.Epsilon;
            
            N = size(Y,4);
      
            dLdY = (2*W.*Y.*numer./denom.^2 - 2*W.*T./denom)./N;
        end
    end
end

Совместимость графического процессора

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

Функции MATLAB используются в forwardLoss и backwardLoss в dicePixelClassificationLayer вся поддержка gpuArray входные параметры, таким образом, слоем является совместимый графический процессор.

Проверяйте Выходную валидность слоя

Создайте экземпляр слоя.

layer = dicePixelClassificationLayer('dice');

Проверяйте валидность слоя слоя с помощью checkLayer. Задайте допустимый входной размер, чтобы быть размером одного наблюдения за типичным входом к слою. Слой ожидает H- W- K- N входные параметры массивов, где K количество классов и N количество наблюдений в мини-пакете.

numClasses = 2;
validInputSize = [4 4 numClasses];
checkLayer(layer,validInputSize, 'ObservationDimension',4)
Running nnet.checklayer.OutputLayerTestCase
.......... .......
Done nnet.checklayer.OutputLayerTestCase
__________

Test Summary:
	 17 Passed, 0 Failed, 0 Incomplete, 0 Skipped.
	 Time elapsed: 1.6227 seconds.

Тестовые сводные отчеты количество переданных, отказавших, неполные, и пропущенные тесты.

Используйте пользовательский слой в сети Семантической Сегментации

Создайте сеть семантической сегментации, которая использует dicePixelClassificationLayer.

layers = [
    imageInputLayer([32 32 1])
    convolution2dLayer(3,64,'Padding',1)
    reluLayer
    maxPooling2dLayer(2,'Stride',2)
    convolution2dLayer(3,64,'Padding',1)
    reluLayer
    transposedConv2dLayer(4,64,'Stride',2,'Cropping',1)
    convolution2dLayer(1,2)
    softmaxLayer
    dicePixelClassificationLayer('dice')]
layers = 
  10x1 Layer array with layers:

     1   ''       Image Input              32x32x1 images with 'zerocenter' normalization
     2   ''       Convolution              64 3x3 convolutions with stride [1  1] and padding [1  1  1  1]
     3   ''       ReLU                     ReLU
     4   ''       Max Pooling              2x2 max pooling with stride [2  2] and padding [0  0  0  0]
     5   ''       Convolution              64 3x3 convolutions with stride [1  1] and padding [1  1  1  1]
     6   ''       ReLU                     ReLU
     7   ''       Transposed Convolution   64 4x4 transposed convolutions with stride [2  2] and output cropping [1  1]
     8   ''       Convolution              2 1x1 convolutions with stride [1  1] and padding [0  0  0  0]
     9   ''       Softmax                  softmax
    10   'dice'   Classification Output    Dice loss

Загрузите обучающие данные для семантической сегментации с помощью imageDatastore и pixelLabelDatastore.

dataSetDir = fullfile(toolboxdir('vision'),'visiondata','triangleImages');
imageDir = fullfile(dataSetDir,'trainingImages');
labelDir = fullfile(dataSetDir,'trainingLabels');

imds = imageDatastore(imageDir);

classNames = ["triangle" "background"];
labelIDs = [255 0];
pxds = pixelLabelDatastore(labelDir, classNames, labelIDs);

Сопоставьте изображение и данные о пиксельных метках с помощью pixelLabelImageDatastore.

ds = pixelLabelImageDatastore(imds,pxds);

Установите опции обучения и обучите сеть.

options = trainingOptions('sgdm', ...
    'InitialLearnRate',1e-2, ...
    'MaxEpochs',100, ...
    'LearnRateDropFactor',1e-1, ...
    'LearnRateDropPeriod',50, ...
    'LearnRateSchedule','piecewise', ...
    'MiniBatchSize',128);

net = trainNetwork(ds,layers,options);
Training on single GPU.
Initializing image normalization.
|========================================================================================|
|  Epoch  |  Iteration  |  Time Elapsed  |  Mini-batch  |  Mini-batch  |  Base Learning  |
|         |             |   (hh:mm:ss)   |   Accuracy   |     Loss     |      Rate       |
|========================================================================================|
|       1 |           1 |       00:00:03 |       27.89% |       0.8346 |          0.0100 |
|      50 |          50 |       00:00:34 |       89.67% |       0.6384 |          0.0100 |
|     100 |         100 |       00:01:09 |       94.35% |       0.5024 |          0.0010 |
|========================================================================================|

Оцените обучивший сеть путем сегментации тестового изображения и отображения результата сегментации.

I = imread('triangleTest.jpg');

[C,scores] = semanticseg(I,net);

B = labeloverlay(I,C);
figure
imshow(imtile({I,B}))