Этот пример показывает, как задать функцию модели декодера текста.
В контексте глубокого обучения декодер является частью нейронной сети для глубокого обучения, которая отображает латентный вектор в некоторую выборку пространство. Можно использовать декодирование векторов для различных задач. Для примера,
Генерация текста путем инициализации рекуррентной сети с закодированным вектором.
Перемещение последовательности в последовательность при помощи закодированного вектора в качестве контекстного вектора.
Подписывание изображения при помощи закодированного вектора в качестве контекстного вектора.
Загрузите закодированные данные из sonnetsEncoded.mat
. Этот файл MAT содержит кодировку слов, мини-пакет последовательностей dlX
и соответствующие закодированные данные dlZ
вывод энкодером, используемым в примере Define Text Encoder Model Function (Deep Learning Toolbox).
s = load("sonnetsEncoded.mat");
enc = s.enc;
dlX = s.dlX;
dlZ = s.dlZ;
[latentDimension,miniBatchSize] = size(dlZ,1:2);
Цель декодера состоит в том, чтобы сгенерировать последовательности, заданные некоторыми исходными входными данными и состоянием сети.
Инициализируйте параметры для следующей модели.
Декодер восстанавливает вход с помощью LSTM, инициализированного выходом энкодера. Для каждого временного шага декодер предсказывает следующий временной шаг и использует выход для следующих временных предсказаний. И энкодер, и декодер используют одно и то же встраивание.
Эта модель использует три операции:
Встраивание преобразует индексы слов в область значений 1, хотя vocabularySize
к векторам размерности embeddingDimension
, где vocabularySize
количество слов в кодирующем словаре и embeddingDimension
количество компонентов, выученных при внедрении.
Операция LSTM принимает за вход один вектор слова и выходов 1-by- numHiddenUnits
вектор, где numHiddenUnits
количество скрытых модулей в операции LSTM. Начальное состояние сети LSTM (состояние на первом временном шаге) является закодированным вектором, поэтому количество скрытых модулей должно совпадать с латентной размерностью энкодера.
Полностью связанная операция умножает вход на матрицу веса, добавляющую смещение, и выводит векторы размера vocabularySize
.
Задайте размерности параметров. Размеры встраивания должны совпадать с размером энкодера.
embeddingDimension = 100; vocabularySize = enc.NumWords; numHiddenUnits = latentDimension;
Создайте struct для параметров.
parameters = struct;
Инициализируйте веса встраивания, используя Гауссов метод initializeGaussian
функция, которая присоединена к этому примеру как вспомогательный файл. Задайте среднее значение 0 и стандартное отклонение 0,01. Для получения дополнительной информации смотрите Гауссову инициализацию (Deep Learning Toolbox).
mu = 0; sigma = 0.01; parameters.emb.Weights = initializeGaussian([embeddingDimension vocabularySize],mu,sigma);
Инициализируйте настраиваемые параметры для операции LSTM декодера:
Инициализируйте входные веса с помощью инициализатора Glorot с помощью initializeGlorot
функция, которая присоединена к этому примеру как вспомогательный файл. Для получения дополнительной информации смотрите Glorot Initialization (Deep Learning Toolbox).
Инициализируйте повторяющиеся веса с помощью ортогонального инициализатора с помощью initializeOrthogonal
функция, которая присоединена к этому примеру как вспомогательный файл. Дополнительные сведения см. в разделе Ортогональная инициализация (Deep Learning Toolbox).
Инициализируйте смещение с помощью модуля forget gate initializer с помощью initializeUnitForgetGate
функция, которая присоединена к этому примеру как вспомогательный файл. Для получения дополнительной информации смотрите Unit Forget Gate Initialization (Deep Learning Toolbox).
Размеры настраиваемых параметров зависят от размера входов. Поскольку входы в операцию LSTM являются последовательностями векторов слов от операции встраивания, количество входных каналов embeddingDimension
.
Вход веса имеет размер 4*numHiddenUnits
-by- inputSize
, где inputSize
- размерность входных данных.
Повторяющаяся матрица веса имеет размер 4*numHiddenUnits
-by- numHiddenUnits
.
Вектор смещения имеет размер 4*numHiddenUnits
-by-1.
sz = [4*numHiddenUnits embeddingDimension]; numOut = 4*numHiddenUnits; numIn = embeddingDimension; parameters.lstmDecoder.InputWeights = initializeGlorot(sz,numOut,numIn); parameters.lstmDecoder.RecurrentWeights = initializeOrthogonal([4*numHiddenUnits numHiddenUnits]); parameters.lstmDecoder.Bias = initializeUnitForgetGate(numHiddenUnits);
Инициализируйте настраиваемые параметры для полностью подключенной операции энкодера:
Инициализируйте веса с помощью инициализатора Glorot.
Инициализируйте смещение с нулями, используя initializeZeros
функция, которая присоединена к этому примеру как вспомогательный файл. Дополнительные сведения см. в разделе Инициализация нулей (Deep Learning Toolbox).
Размеры настраиваемых параметров зависят от размера входов. Поскольку входы в полносвязную операцию являются выходами в операции LSTM, количество входных каналов numHiddenUnits
. Чтобы сделать полносвязные выходные векторы операции с size latentDimension
, задайте размер выхода latentDimension
.
Матрица весов имеет размер outputSize
-by- inputSize
, где outputSize
и inputSize
соответствуют выходу и входным размерностям, соответственно.
Вектор смещения имеет размер outputSize
-by-1.
Чтобы сделать полносвязные выходные векторы операции с size vocabularySize
, задайте размер выхода vocabularySize
.
inputSize = numHiddenUnits; outputSize = vocabularySize; parameters.fcDecoder.Weights = dlarray(randn(outputSize,inputSize,'single')); parameters.fcDecoder.Bias = dlarray(zeros(outputSize,1,'single'));
Создайте функцию modelDecoder
, перечисленный в разделе Decoder Model Function примера, который вычисляет выход модели декодера. The modelDecoder
function, принимает в качестве входных последовательностей индексы слов, параметры модели и длины последовательности и возвращает соответствующий латентный вектор функции.
При обучении модели глубокого обучения с помощью пользовательского цикла обучения необходимо вычислить градиенты потери относительно настраиваемых параметров. Это вычисление зависит от выхода прямого прохода функции модели.
Существует два распространенных подхода к генерации текстовых данных с помощью декодера:
Замкнутый цикл - Для каждого временного шага делайте предсказания, используя предыдущее предсказание в качестве входных данных.
Разомкнутый контур - Для каждого временного шага выполните предсказания, используя входы из внешнего источника (для примера, обучения целей).
Генерация замкнутого цикла - это когда модель генерирует данные один временной шаг за раз и использует предыдущее предсказание в качестве входных данных для следующего предсказания. В отличие от генерации разомкнутого контура, этот процесс не требует какого-либо входа между предсказаниями и лучше всего подходит для сценариев без наблюдения. Например, модель языкового перевода, которая генерирует выходной текст за один раз.
Как использовать замкнутый цикл
Инициализируйте скрытое состояние сети LSTM с выходом энкодера dlZ
.
state = struct;
state.HiddenState = dlZ;
state.CellState = zeros(size(dlZ),'like',dlZ);
Для первого временного шага используйте массив начальных лексем в качестве входных данных для декодера. Для простоты извлеките массив стартовых лексем с первого временного шага обучающих данных.
decoderInput = dlX(:,:,1);
Предварительно выделите выход декодера, чтобы он имел размер numClasses
-by- miniBatchSize
-by- sequenceLength
с тем же типом данных, что и dlX
, где sequenceLength
- желаемая длина генерации, например, длина обучающих целей. В данном примере задайте длину последовательности 16.
sequenceLength = 16; dlY = zeros(vocabularySize,miniBatchSize,sequenceLength,'like',dlX); dlY = dlarray(dlY,'CBT');
Для каждого временного шага спрогнозируйте следующий временной шаг последовательности с помощью modelDecoder
функция. После каждого предсказания находите индексы, соответствующие максимальным значениям выхода декодера, и используйте эти индексы в качестве входов декодера для следующего временного шага.
for t = 1:sequenceLength [dlY(:,:,t), state] = modelDecoder(parameters,decoderInput,state); [~,idx] = max(dlY(:,:,t)); decoderInput = idx; end
Выходные выходы vocabularySize
-by- miniBatchSize
-by- sequenceLength
массив.
size(dlY)
ans = 1×3
3595 32 16
Этот фрагмент кода показывает пример выполнения генерации замкнутого цикла в функции градиентов модели.
function gradients = modelGradients(parameters,dlX,sequenceLengths) % Encode input. dlZ = modelEncoder(parameters,dlX,sequenceLengths); % Initialize LSTM state. state = struct; state.HiddenState = dlZ; state.CellState = zeros(size(dlZ),'like',dlZ); % Initialize decoder input. decoderInput = dlX(:,:,1); % Closed loop prediction. sequenceLength = size(dlX,3); dlY = zeros(numClasses,miniBatchSize,sequenceLength,'like',dlX); for t = 1:sequenceLength [dlY(:,:,t), state] = modelDecoder(parameters,decoderInput,state); [~,idx] = max(dlY(:,:,t)); decoderInput = idx; end % Calculate loss. % ... % Calculate gradients. % ... end
При обучении с генерацией замкнутого цикла предсказание наиболее вероятного слова для каждого шага в последовательности может привести к неоптимальным результатам. Например, в рабочем процессе с подписями к изображениям, если декодер предсказывает первое слово подписи «а» при выдаче изображения слона, то вероятность предсказания «слона» для следующего слова становится гораздо более маловероятной из-за крайне низкой вероятности появления фразы «слон» в английском тексте.
Чтобы помочь сети сходиться быстрее, можно использовать принуждение учителя: используйте целевые значения в качестве входных данных декодера вместо предыдущих предсказаний. Использование принуждения учителя помогает сети учиться характеристикам из более поздних временных шагов последовательностей, не дожидаясь, пока сеть правильно сгенерирует более ранние временные шаги последовательностей.
Чтобы выполнить принудительное обучение, используйте modelEncoder
функция непосредственно с целевой последовательностью в качестве входных данных.
Инициализируйте скрытое состояние сети LSTM с выходом энкодера dlZ
.
state = struct;
state.HiddenState = dlZ;
state.CellState = zeros(size(dlZ),'like',dlZ);
Делайте предсказания, используя целевую последовательность как вход.
dlY = modelDecoder(parameters,dlX,state);
Выходные выходы vocabularySize
-by- miniBatchSize
-by- sequenceLength
массив, где sequenceLength
- длина входных последовательностей.
size(dlY)
ans = 1×3
3595 32 14
Этот фрагмент кода показывает пример выполнения принудительного выполнения учителем в функции градиентов модели.
function gradients = modelGradients(parameters,dlX,sequenceLengths) % Encode input. dlZ = modelEncoder(parameters,dlX,dlZ); % Initialize LSTM state. state = struct; state.HiddenState = dlZ; state.CellState = zeros(size(dlZ),'like',dlZ); % Teacher forcing. dlY = modelDecoder(parameters,dlX,state); % Calculate loss. % ... % Calculate gradients. % ... end
The modelDecoder
функция, принимает за вход параметры модели, последовательности индексов слов и состояние сети и возвращает декодированные последовательности.
Потому что lstm
функция является статической (когда заданы временные ряды как вход, функция распространяет и обновляет состояние между каждым временным шагом) и что embed
и fullyconnect
функции распределены по умолчанию по времени (когда заданы временные ряды как вход, функции работают с каждым временным шагом независимо), modelDecoder
функция поддерживает как последовательность, так и один временной шаг входов.
function [dlY,state] = modelDecoder(parameters,dlX,state) % Embedding. weights = parameters.emb.Weights; dlX = embed(dlX,weights); % LSTM. inputWeights = parameters.lstmDecoder.InputWeights; recurrentWeights = parameters.lstmDecoder.RecurrentWeights; bias = parameters.lstmDecoder.Bias; hiddenState = state.HiddenState; cellState = state.CellState; [dlY,hiddenState,cellState] = lstm(dlX,hiddenState,cellState, ... inputWeights,recurrentWeights,bias); state.HiddenState = hiddenState; state.CellState = cellState; % Fully connect. weights = parameters.fcDecoder.Weights; bias = parameters.fcDecoder.Bias; dlY = fullyconnect(dlY,weights,bias); end
doc2sequence
| tokenizedDocument
| word2ind
| wordEncoding