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

Одним из недостатков TCN по сравнению с RNN является более высокий объем памяти во время вывода. Для вычисления следующего временного шага требуется вся исходная последовательность. Чтобы уменьшить время вывода и потребление памяти, особенно для предсказаний с опережением шага, может быть выгодно обучать с наименьшим разумным размером воспринимаемого поля и выполнять предсказание только с последними 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 эпох.
Срежьте градиенты, используя норму с порогом 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 функция предварительно обрабатывает данные, используя следующий шаг:
Предварительная обработка предикторов с помощью preprocessMiniBatchPredictors функция/.
Однократное кодирование категориальных меток каждого шага времени в числовые массивы.
Поместите последовательности на ту же длину, что и самая длинная последовательность в мини-партии, используя 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 чтобы его норма была равна gradientThreshold когда норма градиента больше 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.
adamupdate | crossentropy | dlarray | dlconv | dlfeval | dlgradient | fullyconnect | minibatchqueue | onehotdecode | onehotencode | relu | softmax