Задайте функцию модели декодера текста

Этот пример показывает, как задать функцию модели декодера текста.

В контексте глубокого обучения декодер является частью нейронной сети для глубокого обучения, которая отображает латентный вектор в некоторую выборку пространство. Можно использовать декодирование векторов для различных задач. Для примера,

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

  • Перемещение последовательности в последовательность при помощи закодированного вектора в качестве контекстного вектора.

  • Подписывание изображения при помощи закодированного вектора в качестве контекстного вектора.

Загрузка данных

Загрузите закодированные данные из sonnetsEncoded.mat. Этот файл MAT содержит кодировку слов, мини-пакет последовательностей dlXи соответствующие закодированные данные dlZ вывод энкодером, используемым в примере Define Text Encoder Model Function.

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. Для получения дополнительной информации смотрите Гауссову инициализацию.

mu = 0;
sigma = 0.01;
parameters.emb.Weights = initializeGaussian([embeddingDimension vocabularySize],mu,sigma);

Инициализируйте настраиваемые параметры для операции LSTM декодера:

  • Инициализируйте входные веса с помощью инициализатора Glorot с помощью initializeGlorot функция, которая присоединена к этому примеру как вспомогательный файл. Дополнительные сведения см. в разделе «Инициализация Glorot».

  • Инициализируйте повторяющиеся веса с помощью ортогонального инициализатора с помощью initializeOrthogonal функция, которая присоединена к этому примеру как вспомогательный файл. Дополнительные сведения см. в разделе Ортогональная инициализация.

  • Инициализируйте смещение с помощью модуля forget gate initializer с помощью initializeUnitForgetGate функция, которая присоединена к этому примеру как вспомогательный файл. Для получения дополнительной информации смотрите Unit Forget Gate Initialization.

Размеры настраиваемых параметров зависят от размера входов. Поскольку входы в операцию 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 функция, которая присоединена к этому примеру как вспомогательный файл. Дополнительные сведения см. в разделе Инициализация нулей.

Размеры настраиваемых параметров зависят от размера входов. Поскольку входы в полносвязную операцию являются выходами в операции 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, принимает в качестве входных последовательностей индексы слов, параметры модели и длины последовательности и возвращает соответствующий латентный вектор функции.

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

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

Существует два распространенных подхода к генерации текстовых данных с помощью декодера:

  1. Замкнутый цикл - Для каждого временного шага делайте предсказания, используя предыдущее предсказание в качестве входных данных.

  2. Разомкнутый контур - Для каждого временного шага выполните предсказания, используя входы из внешнего источника (для примера, обучения целей).

Генерация замкнутого цикла

Генерация замкнутого цикла - это когда модель генерирует данные один временной шаг за раз и использует предыдущее предсказание в качестве входных данных для следующего предсказания. В отличие от генерации разомкнутого контура, этот процесс не требует какого-либо входа между предсказаниями и лучше всего подходит для сценариев без наблюдения. Например, модель языкового перевода, которая генерирует выходной текст за один раз.

Как использовать замкнутый цикл

Инициализируйте скрытое состояние сети 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

См. также

| |

Похожие темы