lstmLayer

Слой Long short-term memory (LSTM)

Описание

Слой LSTM изучает долгосрочные зависимости между временными шагами в данных о последовательности и временных рядах.

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

Создание

Синтаксис

layer = lstmLayer(numHiddenUnits)
layer = lstmLayer(numHiddenUnits,Name,Value)

Описание

пример

layer = lstmLayer(numHiddenUnits) создает слой LSTM и устанавливает свойство NumHiddenUnits.

пример

layer = lstmLayer(numHiddenUnits,Name,Value) устанавливает дополнительный OutputMode, Активации, состояние, Параметры и Инициализация, Изучает Уровень и Регуляризацию и свойства Name с помощью одного или нескольких аргументов пары "имя-значение". Можно задать несколько аргументов пары "имя-значение". Заключите каждое имя свойства в кавычки.

Свойства

развернуть все

LSTM

Количество скрытых модулей (также известный как скрытый размер), заданный как положительное целое число.

Количество скрытых модулей соответствует объему информации, который помнят между временными шагами (скрытое состояние). Скрытое состояние может содержать информацию от всех предыдущих временных шагов, независимо от длины последовательности. Если количество скрытых модулей является слишком большим, то слой может сверхсоответствовать к данным тренировки. Это значение может отличаться от нескольких дюжин до нескольких тысяч.

Скрытое состояние не ограничивает количество временных шагов, обрабатываются в итерации. Чтобы разделить ваши последовательности в меньшие последовательности для обучения, используйте опцию 'SequenceLength' в trainingOptions.

Пример: 200

Формат вывода, заданного как одно из следующего:

  • 'sequence' – Выведите полную последовательность.

  • 'last' – Выведите последний временной шаг последовательности.

Введите размер, заданный как положительное целое число или 'auto'. Если InputSize является 'auto', то программное обеспечение автоматически присваивает входной размер в учебное время.

Пример: 100

Активации

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

  • tanh Используйте гиперболическую функцию тангенса (tanh).

  • 'softsign' – Используйте функцию softsign softsign(x)=x1+|x|.

Слой использует эту опцию в качестве функции σc в вычислениях, чтобы обновить ячейку и скрытое состояние. Для получения дополнительной информации о том, как функции активации используются в слое LSTM, видят Слой Long Short-Term Memory.

Функция активации, чтобы примениться к логическим элементам, заданным как одно из следующего:

  • 'sigmoid' – Используйте сигмоидальную функцию σ(x)=(1+ex)1.

  • 'hard-sigmoid' – Используйте трудную сигмоидальную функцию

    σ(x)={00.2x+0.51если x<2.5если2.5x2.5если x>2.5.

Слой использует эту опцию в качестве функции σg в вычислениях для входа, выводе, и забывают логический элемент. Для получения дополнительной информации о том, как функции активации используются в слое LSTM, видят Слой Long Short-Term Memory.

Состояние

Начальное значение состояния ячейки, заданного как NumHiddenUnits-by-1 числовой вектор. Это значение соответствует состоянию ячейки на временном шаге 0.

После установки этого свойства вызовы функции resetState устанавливают состояние ячейки на это значение.

Начальное значение скрытого состояния, заданного как NumHiddenUnits-by-1 числовой вектор. Это значение соответствует скрытому состоянию на временном шаге 0.

После установки этого свойства вызовы функции resetState устанавливают скрытое состояние на это значение.

Параметры и инициализация

Функция, чтобы инициализировать входные веса, заданные как одно из следующего:

  • 'glorot' – Инициализируйте входные веса с инициализатором Glorot [4] (также известный как инициализатор Ксавьера). Инициализатор Glorot независимо выборки от равномерного распределения с нулевым средним значением и отклонением 2/(InputSize + numOut), где numOut = 4*NumHiddenUnits.

  • 'he' – Инициализируйте входные веса с Ним инициализатор [5]. Он выборки инициализатора от нормального распределения с нулевым средним значением и отклонением 2/InputSize.

  • 'orthogonal' – Инициализируйте входные веса с Q, ортогональная матрица, данная разложением QR Z = Q R для случайного матричного Z, выбранного от модульного нормального распределения. [6]

  • 'narrow-normal' – Инициализируйте входные веса путем независимой выборки от нормального распределения с нулевым средним и стандартным отклонением 0.01.

  • нули Инициализируйте входные веса с нулями.

  • единицы Инициализируйте входные веса с единицами.

  • Указатель на функцию – Инициализирует входные веса с пользовательской функцией. Если вы задаете указатель на функцию, то функция должна иметь форму weights = func(sz), где sz является размером входных весов.

Слой только инициализирует входные веса, когда свойство InputWeights пусто.

Типы данных: char | string | function_handle

Функция, чтобы инициализировать текущие веса, заданные как одно из следующего:

  • 'orthogonal' – Инициализируйте текущие веса с Q, ортогональная матрица, данная разложением QR Z = Q R для случайного матричного Z, выбранного от модульного нормального распределения. [6]

  • 'glorot' – Инициализируйте текущие веса с инициализатором Glorot [4] (также известный как инициализатор Ксавьера). Инициализатор Glorot независимо выборки от равномерного распределения с нулевым средним значением и отклонением 2/(numIn + numOut), где numIn = NumHiddenUnits и numOut = 4*NumHiddenUnits.

  • 'he' – Инициализируйте текущие веса с Ним инициализатор [5]. Он выборки инициализатора от нормального распределения с нулевым средним значением и отклонением 2/NumHiddenUnits.

  • 'narrow-normal' – Инициализируйте текущие веса путем независимой выборки от нормального распределения с нулевым средним и стандартным отклонением 0.01.

  • нули Инициализируйте текущие веса с нулями.

  • единицы Инициализируйте текущие веса с единицами.

  • Указатель на функцию – Инициализирует текущие веса с пользовательской функцией. Если вы задаете указатель на функцию, то функция должна иметь форму weights = func(sz), где sz является размером текущих весов.

Слой только инициализирует текущие веса, когда свойство RecurrentWeights пусто.

Типы данных: char | string | function_handle

Функция, чтобы инициализировать смещение, заданное как одно из следующего:

  • 'unit-forget-gate' – Инициализируйте забыть смещение затвора с единицами и остающиеся смещения с нулями.

  • 'narrow-normal' – Инициализируйте смещение путем независимой выборки от нормального распределения с нулевым средним и стандартным отклонением 0.01.

  • единицы Инициализируйте смещение с единицами.

  • Указатель на функцию – Инициализирует смещение с пользовательской функцией. Если вы задаете указатель на функцию, то функция должна иметь форму bias = func(sz), где sz является размером смещения.

Слой только инициализирует смещение, когда свойство Bias пусто.

Типы данных: char | string | function_handle

Введите веса, заданные как матрица.

Входная матрица веса является конкатенацией четырех входных матриц веса для компонентов (логические элементы) в слое LSTM. Эти четыре матрицы конкатенированы вертикально в следующем порядке:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

Входные веса являются learnable параметрами. При обучении сети, если InputWeights непуст, то trainNetwork использует свойство InputWeights в качестве начального значения. Если InputWeights пуст, то trainNetwork использует инициализатор, заданный InputWeightsInitializer.

В учебное время InputWeights является 4*NumHiddenUnits-by-InputSize матрица.

Текущие веса, заданные как матрица.

Текущая матрица веса является конкатенацией четырех текущих матриц веса для компонентов (логические элементы) в слое LSTM. Эти четыре матрицы вертикально конкатенированы в следующем порядке:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

Текущие веса являются learnable параметрами. При обучении сети, если RecurrentWeights непуст, то trainNetwork использует свойство RecurrentWeights в качестве начального значения. Если RecurrentWeights пуст, то trainNetwork использует инициализатор, заданный RecurrentWeightsInitializer.

В учебное время RecurrentWeights является 4*NumHiddenUnits-by-NumHiddenUnits матрица.

Слой смещает для слоя LSTM, заданного как числовой вектор.

Вектор смещения является конкатенацией четырех векторов смещения для компонентов (логические элементы) в слое LSTM. Эти четыре вектора конкатенированы вертикально в следующем порядке:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

Смещения слоя являются learnable параметрами. При обучении сети, если Bias непуст, то trainNetwork использует свойство Bias в качестве начального значения. Если Bias пуст, то trainNetwork использует инициализатор, заданный BiasInitializer.

В учебное время Bias является 4*NumHiddenUnits-by-1 числовой вектор.

Изучите уровень и регуляризацию

Фактор темпа обучения для входных весов, заданных в виде числа или числового вектора 1 на 4.

Программное обеспечение умножает этот фактор на глобальный темп обучения, чтобы определить фактор темпа обучения для входных весов слоя. Например, если InputWeightsLearnRateFactor равняется 2, то фактором темпа обучения для входных весов слоя является дважды текущий глобальный темп обучения. Программное обеспечение определяет глобальный темп обучения на основе настроек, заданных с функцией trainingOptions.

Чтобы управлять значением фактора темпа обучения для четырех отдельных матриц в InputWeights, задайте вектор 1 на 4. Записи InputWeightsLearnRateFactor соответствуют фактору темпа обучения следующего:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

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

Пример 2

Пример: [1 2 1 1]

Фактор темпа обучения для текущих весов, заданных в виде числа или числового вектора 1 на 4.

Программное обеспечение умножает этот фактор на глобальный темп обучения, чтобы определить темп обучения для текущих весов слоя. Например, если RecurrentWeightsLearnRateFactor равняется 2, то темп обучения для текущих весов слоя является дважды текущим глобальным темпом обучения. Программное обеспечение определяет глобальный темп обучения на основе настроек, заданных с функцией trainingOptions.

Чтобы управлять значением фактора темпа обучения для четырех отдельных матриц в RecurrentWeights, задайте вектор 1 на 4. Записи RecurrentWeightsLearnRateFactor соответствуют фактору темпа обучения следующего:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

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

Пример 2

Пример: [1 2 1 1]

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

Программное обеспечение умножает этот фактор на глобальный темп обучения, чтобы определить темп обучения для смещений в этом слое. Например, если BiasLearnRateFactor равняется 2, то темп обучения для смещений в слое является дважды текущим глобальным темпом обучения. Программное обеспечение определяет глобальный темп обучения на основе настроек, заданных с функцией trainingOptions.

Чтобы управлять значением фактора темпа обучения для четырех отдельных матриц в Bias, задайте вектор 1 на 4. Записи BiasLearnRateFactor соответствуют фактору темпа обучения следующего:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

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

Пример 2

Пример: [1 2 1 1]

Фактор регуляризации L2 для входных весов, заданных в виде числа или числового вектора 1 на 4.

Программное обеспечение умножает этот фактор на глобальный фактор регуляризации L2, чтобы определить фактор регуляризации L2 для входных весов слоя. Например, если InputWeightsL2Factor равняется 2, то фактором регуляризации L2 для входных весов слоя является дважды текущий глобальный фактор регуляризации L2. Программное обеспечение определяет фактор регуляризации L2 на основе настроек, заданных с функцией trainingOptions.

Чтобы управлять значением фактора регуляризации L2 для четырех отдельных матриц в InputWeights, задайте вектор 1 на 4. Записи InputWeightsL2Factor соответствуют фактору регуляризации L2 следующего:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

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

Пример 2

Пример: [1 2 1 1]

Фактор регуляризации L2 для текущих весов, заданных в виде числа или числового вектора 1 на 4.

Программное обеспечение умножает этот фактор на глобальный фактор регуляризации L2, чтобы определить фактор регуляризации L2 для текущих весов слоя. Например, если RecurrentWeightsL2Factor равняется 2, то фактором регуляризации L2 для текущих весов слоя является дважды текущий глобальный фактор регуляризации L2. Программное обеспечение определяет фактор регуляризации L2 на основе настроек, заданных с функцией trainingOptions.

Чтобы управлять значением фактора регуляризации L2 для четырех отдельных матриц в RecurrentWeights, задайте вектор 1 на 4. Записи RecurrentWeightsL2Factor соответствуют фактору регуляризации L2 следующего:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

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

Пример 2

Пример: [1 2 1 1]

Фактор регуляризации L2 для смещений, заданных как неотрицательный скаляр или числовой вектор 1 на 4.

Программное обеспечение умножает этот фактор на глобальный фактор регуляризации L2, чтобы определить регуляризацию L2 для смещений в этом слое. Например, если BiasL2Factor равняется 2, то регуляризация L2 для смещений в этом слое является дважды глобальным фактором регуляризации L2. Можно задать глобальный фактор регуляризации L2 использование функции trainingOptions.

Чтобы управлять значением фактора регуляризации L2 для четырех отдельных матриц в Bias, задайте вектор 1 на 4. Записи BiasL2Factor соответствуют фактору регуляризации L2 следующего:

  1. Введите логический элемент

  2. Забудьте логический элемент

  3. Кандидат ячейки

  4. Выведите логический элемент

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

Пример 2

Пример: [1 2 1 1]

Слой

Имя слоя, заданное как вектор символов или скаляр строки. Если Name установлен в '', то программное обеспечение автоматически присваивает имя в учебное время.

Типы данных: char | string

Количество входных параметров слоя. Этот слой принимает один вход только.

Типы данных: double

Введите имена слоя. Этот слой принимает один вход только.

Типы данных: cell

Количество выходных параметров слоя. Этот слой имеет один вывод только.

Типы данных: double

Выведите имена слоя. Этот слой имеет один вывод только.

Типы данных: cell

Примеры

свернуть все

Создайте слой LSTM с именем 'lstm1' и 100 скрытых модулей.

layer = lstmLayer(100,'Name','lstm1')
layer = 
  LSTMLayer with properties:

                       Name: 'lstm1'

   Hyperparameters
                  InputSize: 'auto'
             NumHiddenUnits: 100
                 OutputMode: 'sequence'
    StateActivationFunction: 'tanh'
     GateActivationFunction: 'sigmoid'

   Learnable Parameters
               InputWeights: []
           RecurrentWeights: []
                       Bias: []

   State Parameters
                HiddenState: []
                  CellState: []

  Show all properties

Включайте слой LSTM в массив Layer.

inputSize = 12;
numHiddenUnits = 100;
numClasses = 9;

layers = [ ...
    sequenceInputLayer(inputSize)
    lstmLayer(numHiddenUnits)
    fullyConnectedLayer(numClasses)
    softmaxLayer
    classificationLayer]
layers = 
  5x1 Layer array with layers:

     1   ''   Sequence Input          Sequence input with 12 dimensions
     2   ''   LSTM                    LSTM with 100 hidden units
     3   ''   Fully Connected         9 fully connected layer
     4   ''   Softmax                 softmax
     5   ''   Classification Output   crossentropyex

Обучите сеть LSTM глубокого обучения для классификации последовательностей к метке.

Загрузите японский набор данных Гласных, как описано в [1] и [2]. XTrain является массивом ячеек, содержащим 270 последовательностей переменной длины с размерностью признаков 12. Y является категориальным вектором меток 1,2..., 9. Записи в XTrain являются матрицами с 12 строками (одна строка для каждого признака) и переменным количеством столбцов (один столбец для каждого временного шага).

[XTrain,YTrain] = japaneseVowelsTrainData;

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

figure
plot(XTrain{1}')
title("Training Observation 1")
numFeatures = size(XTrain{1},1);
legend("Feature " + string(1:numFeatures),'Location','northeastoutside')

Задайте архитектуру сети LSTM. Задайте входной размер как 12 (количество функций входных данных). Задайте слой LSTM, чтобы иметь 100 скрытых модулей и вывести последний элемент последовательности. Наконец, задайте девять классов включением полносвязного слоя размера 9, сопровождаемый softmax слоем и слоем классификации.

inputSize = 12;
numHiddenUnits = 100;
numClasses = 9;

layers = [ ...
    sequenceInputLayer(inputSize)
    lstmLayer(numHiddenUnits,'OutputMode','last')
    fullyConnectedLayer(numClasses)
    softmaxLayer
    classificationLayer]
layers = 
  5x1 Layer array with layers:

     1   ''   Sequence Input          Sequence input with 12 dimensions
     2   ''   LSTM                    LSTM with 100 hidden units
     3   ''   Fully Connected         9 fully connected layer
     4   ''   Softmax                 softmax
     5   ''   Classification Output   crossentropyex

Задайте опции обучения. Задайте решатель как 'adam' и 'GradientThreshold' как 1. Установите мини-пакетный размер на 27 и определите максимальный номер эпох к 100.

Поскольку мини-пакеты являются маленькими с короткими последовательностями, центральный процессор лучше подходит для обучения. Установите 'ExecutionEnvironment' на 'cpu'. Чтобы обучаться на графическом процессоре, при наличии, устанавливает 'ExecutionEnvironment' на 'auto' (значение по умолчанию).

maxEpochs = 100;
miniBatchSize = 27;

options = trainingOptions('adam', ...
    'ExecutionEnvironment','cpu', ...
    'MaxEpochs',maxEpochs, ...
    'MiniBatchSize',miniBatchSize, ...
    'GradientThreshold',1, ...
    'Verbose',false, ...
    'Plots','training-progress');

Обучите сеть LSTM с заданными опциями обучения.

net = trainNetwork(XTrain,YTrain,layers,options);

Загрузите набор тестов и классифицируйте последовательности в динамики.

[XTest,YTest] = japaneseVowelsTestData;

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

YPred = classify(net,XTest,'MiniBatchSize',miniBatchSize);

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

acc = sum(YPred == YTest)./numel(YTest)
acc = 0.9351

Чтобы создать сеть LSTM для классификации последовательностей к метке, создайте массив слоя, содержащий входной слой последовательности, слой LSTM, полносвязный слой, softmax слой и классификацию выходной слой.

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

Для слоя LSTM задайте количество скрытых модулей и режима вывода 'last'.

numFeatures = 12;
numHiddenUnits = 100;
numClasses = 9;
layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits,'OutputMode','last')
    fullyConnectedLayer(numClasses)
    softmaxLayer
    classificationLayer];

Для примера, показывающего, как обучить сеть LSTM для классификации последовательностей к метке и классифицировать новые данные, смотрите, что Классификация Последовательностей Использует Глубокое обучение.

Чтобы создать сеть LSTM для классификации от последовательности к последовательности, используйте ту же архитектуру что касается классификации последовательностей к метке, но установите режим вывода слоя LSTM к 'sequence'.

numFeatures = 12;
numHiddenUnits = 100;
numClasses = 9;
layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits,'OutputMode','sequence')
    fullyConnectedLayer(numClasses)
    softmaxLayer
    classificationLayer];

Чтобы создать сеть LSTM для sequence-one регрессии, создайте массив слоя, содержащий входной слой последовательности, слой LSTM, полносвязный слой и регрессию выходной слой.

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

Для слоя LSTM задайте количество скрытых модулей и режима вывода 'last'.

numFeatures = 12;
numHiddenUnits = 125;
numResponses = 1;

layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits,'OutputMode','last')
    fullyConnectedLayer(numResponses)
    regressionLayer];

Чтобы создать сеть LSTM для регрессии от последовательности к последовательности, используйте ту же архитектуру что касается sequence-one регрессии, но установите режим вывода слоя LSTM к 'sequence'.

numFeatures = 12;
numHiddenUnits = 125;
numResponses = 1;

layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits,'OutputMode','sequence')
    fullyConnectedLayer(numResponses)
    regressionLayer];

Для примера, показывающего, как обучить сеть LSTM для регрессии от последовательности к последовательности и предсказать на новых данных, смотрите, что Регрессия От последовательности к последовательности Использует Глубокое обучение.

Можно сделать сети LSTM глубже путем вставки дополнительных слоев LSTM с режимом вывода 'sequence' перед слоем LSTM. Чтобы предотвратить сверхподбор кривой, можно вставить слои уволенного после слоев LSTM.

Для сетей классификации последовательностей к метке режимом вывода последнего слоя LSTM должен быть 'last'.

numFeatures = 12;
numHiddenUnits1 = 125;
numHiddenUnits2 = 100;
numClasses = 9;
layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits1,'OutputMode','sequence')
    dropoutLayer(0.2)
    lstmLayer(numHiddenUnits2,'OutputMode','last')
    dropoutLayer(0.2)
    fullyConnectedLayer(numClasses)
    softmaxLayer
    classificationLayer];

Для сетей классификации от последовательности к последовательности режимом вывода последнего слоя LSTM должен быть 'sequence'.

numFeatures = 12;
numHiddenUnits1 = 125;
numHiddenUnits2 = 100;
numClasses = 9;
layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits1,'OutputMode','sequence')
    dropoutLayer(0.2)
    lstmLayer(numHiddenUnits2,'OutputMode','sequence')
    dropoutLayer(0.2)
    fullyConnectedLayer(numClasses)
    softmaxLayer
    classificationLayer];

Больше о

развернуть все

Вопросы совместимости

развернуть все

Поведение изменяется в R2019a

Поведение изменяется в R2019a

Ссылки

[1] М. Кудо, J. Тояма, и М. Шимбо. "Многомерная Классификация Кривых Используя Прохождение через области". Буквы Распознавания образов. Издание 20, № 11-13, страницы 1103-1111.

[2] Репозиторий машинного обучения UCI: японский набор данных гласных. https://archive.ics.uci.edu/ml/datasets/Japanese+Vowels

[3] Hochreiter, S, и Дж. Шмидхубер, 1997. Долгая краткосрочная память. Нейронное вычисление, 9 (8), pp.1735–1780.

[4] Glorot, Ксавьер и Иосуа Бенхио. "Понимая трудность учебных глубоких feedforward нейронных сетей". В Продолжениях тринадцатой международной конференции по вопросам искусственного интеллекта и статистики, стр 249-256. 2010.

[5] Он, Kaiming, Сянюй Чжан, Шаоцин Жэнь и Цзянь Сунь. "Копаясь глубоко в выпрямителях: Превосходная производительность человеческого уровня на imagenet классификации". В Продолжениях международной конференции IEEE по вопросам компьютерного зрения, стр 1026-1034. 2015.

[6] Saxe, Эндрю М., Джеймс Л. Макклеллэнд и Сурья Гэнгули. "Точные решения нелинейной динамики изучения в глубоких линейных нейронных сетях". arXiv предварительно распечатывают arXiv:1312.6120 (2013).

Введенный в R2017b