В этом примере показано, как классифицировать каждый временной шаг данных о последовательности с помощью типовой временной сверточной сети (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-ого сверточного слоя и шаг равняется 1, затем восприимчивый размер поля такой сети может быть вычислен как , где размер фильтра и количество сверточных слоев. Измените размер фильтра и количество слоев, чтобы легко настроить восприимчивый размер поля и номер или настраиваемые параметры по мере необходимости для данных и задачи под рукой.
Один из недостатков TCNs по сравнению с RNNs является более высоким объемом потребляемой памяти во время вывода. Целая необработанная последовательность требуется, чтобы вычислять следующий временной шаг. Чтобы уменьшать время вывода и потребление памяти, особенно для неродной вперед предсказаний, это может быть выгодно, чтобы обучаться с самым маленьким разумным восприимчивым размером поля и только выполните предсказание с последним временные шаги входной последовательности.
Общая архитектура 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]
Создайте функциональный model
, перечисленный в разделе Model Function в конце примера, который вычисляет выходные параметры модели глубокого обучения. Функциональный model
берет входные данные, learnable параметры модели, гиперпараметры модели и флаг, который задает, должна ли модель возвратить выходные параметры для обучения или предсказания. Сетевые выходные параметры предсказания для меток на каждом временном шаге входной последовательности.
Создайте функциональный modelGradients
, перечисленный в разделе Model Gradients Function в конце примера, который берет мини-пакет входных данных, соответствующих целевых последовательностей и параметров сети, и возвращает градиенты потери относительно настраиваемых параметров и соответствующей потери.
Задайте набор опций обучения, используемых в пользовательском учебном цикле.
Обучайтесь в течение 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";
Обучите сеть через стохастический градиентный спуск цикличным выполнением по последовательностям в обучающем наборе данных, вычислительных градиентах параметра и обновлении сетевых параметров через правило обновления Адама. Этот процесс повторяется многократно (называемый эпохами), пока обучение не сходится, и максимальное количество эпох достигнуто.
Используйте 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
функция предварительно обрабатывает данные с помощью следующего шага:
Предварительно обработайте предикторы с помощью 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] Бай, Shaojie, Х. Зико Кольтер и Владлен Кольтун. "Эмпирическая оценка типовых сверточных и текущих сетей для моделирования последовательности". arXiv предварительно распечатывают 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