exponenta event banner

Классификация последовательности к последовательности с использованием сверток 1-D

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

В то время как задачи последовательности к последовательности обычно решаются с помощью рекуррентных нейронных сетевых архитектур, Bai et al. [1] показывают, что сверточные нейронные сети могут соответствовать производительности повторяющихся сетей на типичных задачах моделирования последовательностей или даже превосходить их. Потенциальными преимуществами использования сверточных сетей могут быть лучший параллелизм, лучший контроль над размером воспринимающего поля, лучший контроль памяти сети во время обучения и более стабильные градиенты. Как и повторяющиеся сети, сверточные сети могут работать с входными последовательностями переменной длины и могут использоваться для моделирования задач «последовательность-последовательность» или «последовательность-одна».

Этот пример обучает сеть TCN распознавать активность человека, носящего смартфон на теле, данные временных рядов, представляющие показания акселерометра в трех различных направлениях. Пример определяет TCN как функцию и обучает модель с помощью пользовательского обучающего цикла.

Для свертки во времени входных данных (также называемых 1-D свертками) используйте dlconv и укажите размеры весов с помощью 'WeightsFormat' параметр или укажите веса как отформатированные dlarray.

Загрузка данных обучения

Загрузка данных распознавания деятельности персонала. Данные содержат семь временных рядов данных датчиков, полученных от смартфона, надеваемого на корпус. Каждая последовательность имеет три признака и варьирует по длине. Три характеристики соответствуют показаниям акселерометра в трех различных направлениях. Шесть последовательностей используются для обучения, а одна последовательность используется для тестирования после обучения.

s = load("HumanActivityTrain.mat");

Создать arrayDatastore объекты, содержащие данные, и объединить их с помощью combine функция.

dsXTrain = arrayDatastore(s.XTrain,'OutputType','same');
dsYTrain = arrayDatastore(s.YTrain,'OutputType','same');
dsTrain = combine(dsXTrain,dsYTrain);

Просмотрите количество наблюдений в данных обучения.

numObservations = numel(s.XTrain)
numObservations = 6

Просмотрите количество занятий в данных обучения.

classes = categories(s.YTrain{1});
numClasses = numel(classes)
numClasses = 5

Визуализация одной из тренировочных последовательностей на графике. Постройте график особенностей первой обучающей последовательности и соответствующей операции.

figure
for i = 1:3
    X = s.XTrain{1}(i,:);

    subplot(4,1,i)
    plot(X)
    ylabel("Feature " + i + newline + "Acceleration")
end

subplot(4,1,4)

hold on
plot(s.YTrain{1})
hold off

xlabel("Time Step")
ylabel("Activity")

subplot(4,1,1)
title("Training Sequence 1")

Определение модели глубокого обучения

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

Чтобы создать контекст из предыдущих временных шагов, несколько сверточных слоев обычно укладываются друг на друга. Для достижения больших размеров воспринимающего поля коэффициент расширения последующих слоев свертки увеличивается экспоненциально, как показано на рисунке ниже. Предполагая, что коэффициент расширения k-го сверточного слоя равен 2 (k-1), а шаг равен 1, тогда размер воспринимающего поля такой сети может быть вычислен как R = (f-1) (2K-1) + 1, где f - размер фильтра, а K - количество сверточных слоев. Измените размер фильтра и количество слоев, чтобы легко настроить размер воспринимающего поля и количество или обучаемые параметры, необходимые для данных и задачи.

Одним из недостатков TCN по сравнению с RNN является более высокий объем памяти во время вывода. Для вычисления следующего временного шага требуется вся исходная последовательность. Чтобы уменьшить время вывода и потребление памяти, особенно для предсказаний с опережением шага, может быть выгодно обучать с наименьшим разумным размером R воспринимаемого поля и выполнять предсказание только с последними R временными шагами входной последовательности.

Общая архитектура TCN (как описано в [1]) состоит из нескольких остаточных блоков, каждый из которых содержит два набора слоев расширенного каузального свертывания с одинаковым коэффициентом расширения, с последующей нормализацией, активацией ReLU и слоями пространственного отсева. Вход к каждому блоку добавлен к продукции блока (включая скручивание 1 на 1 на входе, когда количество каналов между входом и выходом не соответствует), и применена заключительная функция активации.

Определение и инициализация параметров модели

Укажите параметры для архитектуры TCN с четырьмя остаточными блоками, содержащими дилатированные слои каузального свертывания с каждым 175 фильтром размера 3.

numBlocks = 4;
numFilters = 175;
filterSize = 3;
dropoutFactor = 0.05;

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

hyperparameters = struct;
hyperparameters.NumBlocks = numBlocks;
hyperparameters.DropoutFactor = dropoutFactor;

Создание структуры, содержащей dlarray объекты для всех обучаемых параметров модели на основе количества входных каналов и гиперпараметров, определяющих архитектуру модели. Каждый остаточный блок требует весовых параметров и параметров смещения для каждой из двух операций свертки. Первый остаточный блок обычно также требует весов и смещений для дополнительной операции свертки с размером фильтра 1. Конечная полностью подключенная операция также требует параметра весов и смещения. Инициализируйте веса и смещения обучаемого слоя с помощью initializeGaussian и initializeZeros соответственно. Эти функции присоединены к этому примеру как вспомогательный файл.

numInputChannels = 3;

parameters = struct;
numChannels = numInputChannels;

mu = 0;
sigma = 0.01;

for k = 1:numBlocks
    parametersBlock = struct;
    blockName = "Block"+k;

    % 1-D Convolution.
    sz = [filterSize numChannels numFilters];
    parametersBlock.Conv1.Weights = initializeGaussian(sz,mu,sigma);
    parametersBlock.Conv1.Bias = initializeZeros([numFilters 1]);

    % 1-D Convolution.
    sz = [filterSize numFilters numFilters];
    parametersBlock.Conv2.Weights = initializeGaussian(sz,mu,sigma);
    parametersBlock.Conv2.Bias = initializeZeros([numFilters 1]);

    % If the input and output of the block have different numbers of
    % channels, then add a convolution with filter size 1.
    if numChannels ~= numFilters

        % 1-D Convolution.
        sz = [1 numChannels numFilters];
        parametersBlock.Conv3.Weights = initializeGaussian(sz,mu,sigma);
        parametersBlock.Conv3.Bias = initializeZeros([numFilters 1]);
    end
    numChannels = numFilters;

    parameters.(blockName) = parametersBlock;
end

% Fully connect.
sz = [numClasses numChannels];
parameters.FC.Weights = initializeGaussian(sz,mu,sigma);
parameters.FC.Bias = initializeZeros([numClasses 1]);

Просмотрите параметры сети.

parameters
parameters = struct with fields:
    Block1: [1×1 struct]
    Block2: [1×1 struct]
    Block3: [1×1 struct]
    Block4: [1×1 struct]
        FC: [1×1 struct]

Просмотрите параметры первого блока.

parameters.Block1
ans = struct with fields:
    Conv1: [1×1 struct]
    Conv2: [1×1 struct]
    Conv3: [1×1 struct]

Просмотрите параметры первой операции свертки первого блока.

parameters.Block1.Conv1
ans = struct with fields:
    Weights: [3×3×175 dlarray]
       Bias: [175×1 dlarray]

Определение функций градиентов модели и модели

Создание функции model, перечисленных в разделе «Функция модели» в конце примера, который вычисляет выходные данные модели глубокого обучения. Функция model принимает входные данные, обучаемые параметры модели, гиперпараметры модели и флаг, который указывает, должна ли модель возвращать выходные данные для обучения или прогнозирования. Сеть выводит прогнозы для меток на каждом временном шаге входной последовательности.

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

Укажите параметры обучения

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

  • Поезд на 30 эпох с мини-партией размером 1.

  • Начните с начального коэффициента обучения 0,001

  • Умножьте скорость обучения на 0,1 каждые 12 эпох.

  • Срежьте градиенты, используя норму L2 с порогом 1.

maxEpochs = 30;
miniBatchSize = 1;
initialLearnRate = 0.001;
learnRateDropFactor = 0.1;
learnRateDropPeriod = 12;
gradientThreshold = 1;

Для контроля хода обучения можно построить график потерь обучения после каждой итерации. Создание переменной plots который содержит "training-progress". Если график хода обучения не требуется, установите для этого значения значение "none".

plots = "training-progress";

Модель поезда

Обучение сети с помощью стохастического градиентного спуска путем закольцовывания последовательностей в обучающем наборе данных, вычисления градиентов параметров и обновления параметров сети с помощью правила обновления Adam. Этот процесс повторяется многократно (называется эпохами) до тех пор, пока обучение не сойдется и не будет достигнуто максимальное количество эпох.

Использовать minibatchqueue обрабатывать и управлять мини-партиями изображений во время обучения. Для каждой мини-партии:

  • Предварительная обработка данных с помощью пользовательской функции предварительной обработки мини-партии preprocessMiniBatch (определенный в конце этого примера), который возвращает заполненные предикторы, дополненные однокодированные цели и маску заполнения. Функция имеет три выхода, поэтому укажите три выходные переменные для minibatchqueue объект.

  • Преобразование выходных данных в dlarray объекты с форматом 'CTB'(канал, время, партия). minibatchqueue object, по умолчанию выводит данные с базовым типом single.

  • Обучение на GPU, если он доступен. minibatchqueue объект по умолчанию преобразует каждый вывод в gpuArray если графический процессор доступен. Для использования графического процессора требуются параллельные вычислительные Toolbox™ и графический процессор NVIDIA ® с поддержкой CUDA ®. Дополнительные сведения см. в разделе Поддержка графического процессора по выпуску (Панель инструментов параллельных вычислений).

numDatastoreOutputs = 3;
mbq = minibatchqueue(dsTrain,numDatastoreOutputs,...
    'MiniBatchSize',miniBatchSize,...
    'MiniBatchFormat',{'CTB','CTB','CTB'},...
    'MiniBatchFcn', @preprocessMiniBatch);

Для каждой эпохи перетасуйте данные обучения. Для каждой мини-партии:

  • Оценка градиентов и потерь модели с помощью dlfeval и modelGradients функция.

  • Подрезка любых больших градиентов с помощью функции thresholdL2Norm, перечисленных в конце примера, и dlupdate функция.

  • Обновление параметров сети с помощью adamupdate функция.

  • Обновите график хода обучения.

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

Инициализируйте скорость обучения, которая будет умножена на LearnRateDropFactor значение каждый LearnRateDropPeriod эпохи.

learnRate = initialLearnRate;

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

trailingAvg = [];
trailingAvgSq = [];

Инициализируйте график, показывающий ход обучения.

if plots == "training-progress"
    figure
    lineLossTrain = animatedline('Color',[0.85 0.325 0.098]);
    ylim([0 inf])
    xlabel("Iteration")
    ylabel("Loss")
    grid on
end

Тренируйте модель.

iteration = 0;

start = tic;

% Loop over epochs.
for epoch = 1:maxEpochs

    % Shuffle the data.
    shuffle(mbq)

    % Loop over mini-batches.
    while hasdata(mbq)

        iteration = iteration + 1;

        [dlX,dlY,mask] = next(mbq);

        % Evaluate the model gradients and loss using dlfeval.
        [gradients, loss] = dlfeval(@modelGradients,parameters,hyperparameters,dlX,dlY,mask);

        % Clip the gradients.
        gradients = dlupdate(@(g) thresholdL2Norm(g,gradientThreshold),gradients);

        % Update the network parameters using the Adam optimizer.
        [parameters,trailingAvg,trailingAvgSq] = adamupdate(parameters,gradients, ...
            trailingAvg, trailingAvgSq, iteration, learnRate);

        if plots == "training-progress"
            % Plot training progress.
            D = duration(0,0,toc(start),'Format','hh:mm:ss');

            % Normalize the loss over the sequence lengths
            numTimeSteps = sum(mask(1,:,:),3);
            loss = mean(loss ./ numTimeSteps);
            loss = double(gather(extractdata(loss)));
            loss = mean(loss);

            addpoints(lineLossTrain,iteration, loss);

            title("Epoch: " + epoch + ", Elapsed: " + string(D))
            drawnow
        end
    end

    % Reduce the learning rate after learnRateDropPeriod epochs
    if mod(epoch,learnRateDropPeriod) == 0
        learnRate = learnRate*learnRateDropFactor;
    end
end

Тестовая модель

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

Создайте хранилище данных, содержащее предикторы теста.

s = load("HumanActivityTest.mat");

dsXTest = arrayDatastore(s.XTest,'OutputType','same');

После обучения составление прогнозов по новым данным не требует меток. Создать minibatchqueue объект, содержащий только предикторы тестовых данных:

  • Чтобы игнорировать метки для тестирования, установите число выходов мини-пакетной очереди равным 1.

  • Укажите размер мини-партии, используемый для обучения.

  • Предварительная обработка предикторов с помощью preprocessMiniBatchPredictors функция, перечисленная в конце примера.

  • Для одиночного вывода хранилища данных укажите формат мини-пакета. 'CTB' (канал, время, партия).

numDatastoreOutputs = 1;
mbqTest = minibatchqueue(dsXTest,numDatastoreOutputs,...
    'MiniBatchSize',miniBatchSize,...
    'MiniBatchFormat','CTB', ...
    'MiniBatchFcn', @preprocessMiniBatchPredictors);

Закольцовывать мини-пакеты и классифицировать последовательности с помощью modelPredictions функция, перечисленная в конце примера.

predictions = modelPredictions(parameters,hyperparameters,mbqTest,classes);

Оцените точность классификации, сравнив прогнозы с тестовыми метками.

YTest = s.YTest{1};
accuracy = mean(predictions == YTest)
accuracy = 0.9996

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

figure
for i = 1:3
    X = s.XTest{1}(i,:);

    subplot(4,1,i)
    plot(X)
    ylabel("Feature " + i + newline + "Acceleration")
end

subplot(4,1,4)

idx = 1;
plot(predictions(idx,:),'.-')
hold on
plot(YTest(idx,:))
hold off

xlabel("Time Step")
ylabel("Activity")
legend(["Predicted" "Test Data"],'Location','northeast')

subplot(4,1,1)
title("Test Sequence")

Функция модели

Функция model, описанный в разделе Определение функций модели и градиентов модели в примере, принимает в качестве входных параметров модели и гиперпараметров, входные данные dlX, и флаг doTraining который определяет, должна ли модель возвращать выходные данные для обучения или прогнозирования. Сеть выводит прогнозы для меток на каждом временном шаге входной последовательности. Модель состоит из нескольких остаточных блоков с экспоненциально увеличивающимися коэффициентами расширения. После последнего остаточного блока, финал fullyconnect операция сопоставляет выходные данные с количеством классов в целевых данных. Функция модели создает остаточные блоки с помощью residualBlock функция, указанная в разделе «Функция остаточного блока» примера.

function dlY = model(parameters,hyperparameters,dlX,doTraining)

numBlocks = hyperparameters.NumBlocks;
dropoutFactor = hyperparameters.DropoutFactor;

dlY = dlX;

% Residual blocks.
for k = 1:numBlocks
    dilationFactor = 2^(k-1);
    parametersBlock = parameters.("Block"+k);

    dlY = residualBlock(dlY,dilationFactor,dropoutFactor,parametersBlock,doTraining);
end

% Fully connect
weights = parameters.FC.Weights;
bias = parameters.FC.Bias;
dlY = fullyconnect(dlY,weights,bias);

% Softmax.
dlY = softmax(dlY);

end

Функция остаточного блока

Функция residualBlock реализует основной строительный блок временной сверточной сети.

Чтобы применить 1-D причинно-следственный расширенный сверток, используйте dlconv функция:

  • Чтобы свернуться по измерению времени, установите значение 'WeightsFormat' опция для 'TCU' (время, канал, не указано),

  • Установите 'DilationFactor' в соответствии с коэффициентом расширения остаточного блока.

  • Чтобы убедиться, что используются только прошлые шаги времени, примените заполнение только в начале последовательности.

function dlY = residualBlock(dlX,dilationFactor,dropoutFactor,parametersBlock,doTraining)

% Convolution options.
filterSize = size(parametersBlock.Conv1.Weights,1);
paddingSize = (filterSize - 1) * dilationFactor;

% Convolution.
weights = parametersBlock.Conv1.Weights;
bias =  parametersBlock.Conv1.Bias;
dlY = dlconv(dlX,weights,bias, ...
    'WeightsFormat','TCU', ...
    'DilationFactor', dilationFactor, ...
    'Padding', [paddingSize; 0]);

% Normalization.
dim = find(dims(dlY)=='T');
mu = mean(dlY,dim);
sigmaSq = var(dlY,1,dim);
epsilon = 1e-5;
dlY = (dlY - mu) ./ sqrt(sigmaSq + epsilon);

% ReLU, spatial dropout.
dlY = relu(dlY);
dlY = spatialDropout(dlY,dropoutFactor,doTraining);

% Convolution.
weights = parametersBlock.Conv2.Weights;
bias = parametersBlock.Conv2.Bias;
dlY = dlconv(dlY,weights,bias, ...
    'WeightsFormat','TCU', ...
    'DilationFactor', dilationFactor, ...
    'Padding',[paddingSize; 0]);

% Normalization.
dim = find(dims(dlY)=='T');
mu = mean(dlY,dim);
sigmaSq = var(dlY,1,dim);
epsilon = 1e-5;
dlY = (dlY - mu) ./ sqrt(sigmaSq + epsilon);

% ReLU, spatial dropout.
dlY = relu(dlY);
dlY = spatialDropout(dlY,dropoutFactor,doTraining);

% Optional 1-by-1 convolution.
if ~isequal(size(dlX),size(dlY))
    weights = parametersBlock.Conv3.Weights;
    bias = parametersBlock.Conv3.Bias;
    dlX = dlconv(dlX,weights,bias,'WeightsFormat','TCU');
end

% Addition and ReLU
dlY = relu(dlX + dlY);

end

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

modelGradients функция, описанная в разделе Определение функций модели и градиентов модели примера, принимает в качестве входных параметров модели и гиперпараметров мини-пакет входных данных dlX, соответствующие целевые последовательности dlTи маску заполнения последовательности, и возвращает градиенты потерь относительно обучаемых параметров и соответствующих потерь. Чтобы вычислить маскированную потерю перекрестной энтропии, используйте 'Mask' вариант crossentropy функция. Чтобы вычислить градиенты, вычислите modelGradients с помощью функции dlfeval функция в обучающем цикле.

function [gradients,loss] = modelGradients(parameters,hyperparameters,dlX,dlT,mask)

doTraining = true;
dlY = model(parameters,hyperparameters,dlX,doTraining);

mask = stripdims(mask);
loss = crossentropy(dlY,dlT, ...
    'Mask',mask, ...
    'Reduction','none');

loss = sum(loss,[1 3]);
loss = mean(loss);

gradients = dlgradient(loss,parameters);

end

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

modelPredictions функция принимает в качестве входных параметров модели и гиперпараметров, minibatchqueue входных данных mbqи сетевые классы, и вычисляет предсказания модели путем итерации по всем данным в minibatchqueue объект. Функция использует onehotdecode функция для поиска прогнозируемых классов с наивысшим баллом.

function predictions = modelPredictions(parameters,hyperparameters,mbq,classes)

doTraining = false;

predictions = [];

while hasdata(mbq)
    dlX = next(mbq);

    dlYPred = model(parameters,hyperparameters,dlX,doTraining);

    YPred = onehotdecode(dlYPred,classes,1);

    predictions = [predictions; YPred];
end

predictions = permute(predictions,[2 3 1]);

end

Функция пространственного отсева

spatialDropout функция выполняет пространственный отсев [3] на входе dlX с метками размеров fmt когда doTraining флаг - true. Пространственный отсев отбрасывает весь канал входных данных. То есть все временные шаги определенного канала сбрасываются с вероятностью, указанной dropoutFactor. Каналы удаляются независимо в измерении партии.

function dlY = spatialDropout(dlX,dropoutFactor,doTraining)

fmt = dims(dlX);

if doTraining
    maskSize = size(dlX);
    maskSize(ismember(fmt,'ST')) = 1;

    dropoutScaleFactor = single(1 - dropoutFactor);
    dropoutMask = (rand(maskSize,'like',dlX) > dropoutFactor) / dropoutScaleFactor;

    dlY = dlX .* dropoutMask;
else
    dlY = dlX;
end

end

Функция предварительной обработки мини-партий

preprocessMiniBatch функция предварительно обрабатывает данные для обучения. Функция преобразует входные последовательности в числовой массив дополненных влево 1-D последовательностей и также возвращает маску заполнения.

preprocessMiniBatch функция предварительно обрабатывает данные, используя следующий шаг:

  1. Предварительная обработка предикторов с помощью preprocessMiniBatchPredictors функция/.

  2. Однократное кодирование категориальных меток каждого шага времени в числовые массивы.

  3. Поместите последовательности на ту же длину, что и самая длинная последовательность в мини-партии, используя padsequences функция

function [XTransformed,YTransformed,mask] = preprocessMiniBatch(XCell,YCell)

XTransformed = preprocessMiniBatchPredictors(XCell);

miniBatchSize = numel(XCell);

responses = cell(1,miniBatchSize);
for i = 1:miniBatchSize
    responses{i} = onehotencode(YCell{i},1);
end

[YTransformed,mask] = padsequences(responses,2,'Direction','left');

end

Функция предварительной обработки мини-пакетных предикторов

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

function XTransformed = preprocessMiniBatchPredictors(XCell)

XTransformed = padsequences(XCell,2,'Direction','left');

end

Функция отсечения градиента

thresholdL2Norm функция масштабирует градиент g чтобы его L2 норма была равна gradientThreshold когда L2 норма градиента больше gradientThreshold.

function g = thresholdL2Norm(g,gradientThreshold)

gradientNorm = sqrt(sum(g.^2,'all'));
if gradientNorm > gradientThreshold
    g = g * (gradientThreshold / gradientNorm);
end

end

Ссылки

[1] Бай, Шаоцзе, Дж. Зико Колтер и Владлен Колтун. «Эмпирическая оценка общих сверточных и рекуррентных сетей для моделирования последовательностей». arXiv preprint arXiv:1803.01271 (2018).

[2] Ван ден Урд, Aäron, и др. «WaveNet: генеративная модель для необработанного звука». SSW 125 (2016).

[3] Томпсон, Джонатан и др. «Эффективная локализация объектов с использованием сверточных сетей». Материалы Конференции IEEE по компьютерному зрению и распознаванию образов. 2015.

См. также

| | | | | | | | | | |

Связанные темы