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

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

В то время как задачи от последовательности к последовательности обычно решаются с архитектурами рекуррентной нейронной сети, Бай и др. [1] показывают, что сверточные нейронные сети могут совпадать с эффективностью текущих сетей на типичных задачах моделирования последовательности или даже превзойти их по характеристикам. Потенциальные выгоды использования сверточных сетей могут быть лучшим параллелизмом, лучше управлять по восприимчивому размеру поля, лучшему управлению объема потребляемой памяти сети во время обучения и другие устойчивые градиенты. Точно так же, как текущие сети сверточные сети могут работать с входными последовательностями переменной длины и могут использоваться к от последовательности к последовательности модели или sequence-one задачам.

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

Чтобы применить операцию свертки по измерению времени входных данных (также известный как 1D свертки), используйте 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 количество сверточных слоев. Измените размер фильтра и количество слоев, чтобы легко настроить восприимчивый размер поля и номер или настраиваемые параметры по мере необходимости для данных и задачи под рукой.

Один из недостатков TCNs по сравнению с RNNs является более высоким объемом потребляемой памяти во время вывода. Целая необработанная последовательность требуется, чтобы вычислять следующий временной шаг. Чтобы уменьшать время вывода и потребление памяти, особенно для неродной вперед предсказаний, это может быть выгодно, чтобы обучаться с самым маленьким разумным восприимчивым размером поля 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. Финал полностью соединился, операция требует весов и параметра смещения также. Инициализируйте learnable веса слоя и смещения с помощью 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]

Модель Define и функции градиентов модели

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

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

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

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

  • Обучайтесь в течение 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";

Обучите модель

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

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

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

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

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

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

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

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

Создайте datastore, содержащий тестовые предикторы.

s = load("HumanActivityTest.mat");

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

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

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

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

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

  • Для одного выхода datastore задайте мини-пакетный формат '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, описанный в разделе Модель Define и Model Gradients Functions примера, берет в качестве входа параметры модели и гиперпараметры, входные данные dlX, и флаг doTraining который задает, должна ли модель возвратить выходные параметры для обучения или предсказания. Сетевые выходные параметры предсказания для меток на каждом временном шаге входной последовательности. Модель состоит из нескольких остаточных блоков с экспоненциально увеличивающимися коэффициентами расширения. После последнего остаточного блока, итогового fullyconnect операция сопоставляет выход с количеством классов в целевых данных. Функция модели создает остаточные блоки с помощью residualBlock функция перечислена в разделе Residual Block Function примера.

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 реализует базовый базовый блок временной сверточной сети.

Чтобы применить 1D причинную расширенную свертку, используйте 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 функция, описанная в разделе Модель Define и Model Gradients Functions примера, берет в качестве входа параметры модели и гиперпараметры, мини-пакет входных данных 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 функция предварительно обрабатывает данные для обучения. Функция преобразовывает входные последовательности к числовому массиву лево-заполненных 1D последовательностей и также возвращает дополнительную маску.

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] Бай, Shaojie, Х. Зико Кольтер и Владлен Кольтун. "Эмпирическая оценка типовых сверточных и текущих сетей для моделирования последовательности". arXiv предварительно распечатывают arXiv:1803.01271 (2018).

[2] Ван ден Урд, Aäron, и др. "WaveNet: порождающая модель для необработанного аудио". SSW 125 (2016).

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

Смотрите также

| | | | | | | | | | |

Похожие темы