В этом примере показано, как задать функцию модели текстового энкодера.
В контексте глубокого обучения энкодер является частью нейронной сети для глубокого обучения, которая отображает вход в некоторое скрытое пространство. Можно использовать эти векторы для различных задач. Для примера,
Классификация путем применения операции softmax к кодированным данным и использования потери перекрестной энтропии.
Перемещение последовательности в последовательность при помощи закодированного вектора в качестве контекстного вектора.
Файл sonnets.txt
содержит все сонеты Шекспира в одном текстовом файле.
Считайте данные Sonnets Шекспира из файла "sonnets.txt"
.
filename = "sonnets.txt";
textData = fileread(filename);
Сонеты изрезаны двумя пробелами символов. Удалите углубления с помощью replace
и разделите текст на отдельные линии, используя split
функция. Удалите заголовок из первых девяти элементов и кратких заголовков сонетов.
textData = replace(textData," ",""); textData = split(textData,newline); textData(1:9) = []; textData(strlength(textData)<5) = [];
Создайте функцию, которая токенизирует и предварительно обрабатывает текстовые данные. Функция preprocessText
, перечисленный в конце примера, выполняет следующие шаги:
Готовит и добавляет каждую входную строку с заданными начальным и стоповым лексемами, соответственно.
Токенизация текста с помощью tokenizedDocument
.
Предварительно обработайте текстовые данные и задайте начальные и стоповые лексемы "<start>"
и "<stop>"
, соответственно.
startToken = "<start>"; stopToken = "<stop>"; documents = preprocessText(textData,startToken,stopToken);
Создайте объект кодирования слов из токенизированных документов.
enc = wordEncoding(documents);
При обучении модели глубокого обучения входные данные должны быть числовым массивом, содержащим последовательности фиксированной длины. Поскольку документы имеют разную длину, необходимо дополнить более короткие последовательности значением заполнения.
Повторно создайте кодировку слова, чтобы также включить лексему заполнения и определить индекс этой лексемы.
paddingToken = "<pad>";
newVocabulary = [enc.Vocabulary paddingToken];
enc = wordEncoding(newVocabulary);
paddingIdx = word2ind(enc,paddingToken)
paddingIdx = 3595
Цель энкодера состоит в том, чтобы сопоставить последовательности индексов слов с векторами в некотором скрытом пространстве.
Инициализируйте параметры для следующей модели.
Эта модель использует три операции:
Встраивание преобразует индексы слов в область значений 1, хотя vocabularySize
к векторам размерности embeddingDimension
, где vocabularySize
количество слов в кодирующем словаре и embeddingDimension
количество компонентов, выученных при внедрении.
Операция LSTM принимает за вход последовательности векторов слов и выходов 1-by- numHiddenUnits
векторы, где numHiddenUnits
количество скрытых модулей в операции LSTM.
Полностью связанная операция умножает вход на матрицу веса, добавляющую смещение, и выводит векторы размера latentDimension
, где latentDimension
- размерность скрытого пространства.
Задайте размерности параметров.
embeddingDimension = 100; numHiddenUnits = 150; latentDimension = 50; vocabularySize = enc.NumWords;
Создайте 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.lstmEncoder.InputWeights = initializeGlorot(sz,numOut,numIn); parameters.lstmEncoder.RecurrentWeights = initializeOrthogonal([4*numHiddenUnits numHiddenUnits]); parameters.lstmEncoder.Bias = initializeUnitForgetGate(numHiddenUnits);
Инициализируйте настраиваемые параметры для полностью подключенной операции энкодера:
Инициализируйте веса с помощью инициализатора Glorot.
Инициализируйте смещение с нулями, используя initializeZeros
функция, которая присоединена к этому примеру как вспомогательный файл. Дополнительные сведения см. в разделе Инициализация нулей (Deep Learning Toolbox).
Размеры настраиваемых параметров зависят от размера входов. Поскольку входы в полносвязную операцию являются выходами в операции LSTM, количество входных каналов numHiddenUnits
. Чтобы сделать полносвязные выходные векторы операции с size latentDimension
, задайте размер выхода latentDimension
.
Матрица весов имеет размер outputSize
-by- inputSize
, где outputSize
и inputSize
соответствуют выходу и входным размерностям, соответственно.
Вектор смещения имеет размер outputSize
-by-1.
sz = [latentDimension numHiddenUnits]; numOut = latentDimension; numIn = numHiddenUnits; parameters.fcEncoder.Weights = initializeGlorot(sz,numOut,numIn); parameters.fcEncoder.Bias = initializeZeros([latentDimension 1]);
Создайте функцию modelEncoder
, перечисленный в разделе Encoder Model Function примера, который вычисляет выход модели энкодера. The modelEncoder
function, принимает в качестве входных последовательностей индексы слов, параметры модели и длины последовательности и возвращает соответствующий латентный вектор функции.
Чтобы обучить модель с помощью пользовательского цикла обучения, вы должны выполнить итерацию по мини-пакетам данных и преобразовать ее в формат, необходимый для модели энкодера и функций градиентов модели. Этот раздел примера иллюстрирует шаги, необходимые для подготовки мини-пакета данных в пользовательском цикле обучения.
Подготовим пример мини-пакета данных. Выберите мини-пакет из 32 документов из documents
. Это представляет мини-пакет данных, используемых в итерации пользовательского цикла обучения.
miniBatchSize = 32; idx = 1:miniBatchSize; documentsBatch = documents(idx);
Преобразуйте документы в последовательности с помощью doc2sequence
и задайте для правого дополнения последовательностей индексом слова, соответствующим лексеме заполнения.
X = doc2sequence(enc,documentsBatch, ... 'PaddingDirection','right', ... 'PaddingValue',paddingIdx);
Выходные выходы doc2sequence
функция является массивом ячеек, где каждый элемент является вектором-строкой словесных индексов. Поскольку функция модели энкодера требует числового входа, соедините строки данных с помощью cat
функцию и задать для конкатенации по первой размерности. Размер выхода miniBatchSize
-by- sequenceLength
, где sequenceLength
- длина самой длинной последовательности в мини-пакете.
X = cat(1,X{:}); size(X)
ans = 1×2
32 14
Преобразуйте данные в dlarray
с форматом 'BTC'
(пакет, время, канал). Программа автоматически переставляет выход в формат 'CTB'
поэтому выход имеет размер 1
-by- miniBatchSize
-by- sequenceLength
.
dlX = dlarray(X,'BTC');
size(dlX)
ans = 1×3
1 32 14
Для маскировки вычислите незакрытые длины последовательности входных данных с помощью doclength
функция с мини-пакетом документов в качестве входных данных.
sequenceLengths = doclength(documentsBatch);
Этот фрагмент кода показывает пример подготовки мини-пакета в пользовательском цикле обучения.
iteration = 0; % Loop over epochs. for epoch = 1:numEpochs % Loop over mini-batches. for i = 1:numIterationsPerEpoch iteration = iteration + 1; % Read mini-batch. idx = (i-1)*miniBatchSize+1:i*miniBatchSize; documentsBatch = documents(idx); % Convert to sequences. X = doc2sequence(enc,documentsBatch, ... 'PaddingDirection','right', ... 'PaddingValue',paddingIdx); X = cat(1,X{:}); % Convert to dlarray. dlX = dlarray(X,'BTC'); % Calculate sequence lengths. sequenceLengths = doclength(documentsBatch); % Evaluate model gradients. % ... % Update learnable parameters. % ... end end
При обучении модели глубокого обучения с помощью пользовательского цикла обучения необходимо вычислить градиенты потери относительно настраиваемых параметров. Это вычисление зависит от выхода прямого прохода функции модели.
Для выполнения прямого прохода энкодера используйте modelEncoder
прямая функция с параметрами, данными и длинами последовательности в качестве входных параметров. Выходные выходы latentDimension
-by- miniBatchSize
матрица.
dlZ = modelEncoder(parameters,dlX,sequenceLengths); size(dlZ)
ans = 1×2
50 32
Этот фрагмент кода показывает пример использования функции энкодера модели внутри функции градиентов модели.
function gradients = modelGradients(parameters,dlX,sequenceLengths) dlZ = modelEncoder(parameters,dlX,sequenceLengths); % Calculate loss. % ... % Calculate gradients. % ... end
Этот фрагмент кода показывает пример оценки градиентов модели в пользовательском цикле обучения.
iteration = 0; % Loop over epochs. for epoch = 1:numEpochs % Loop over mini-batches. for i = 1:numIterationsPerEpoch iteration = iteration + 1; % Prepare mini-batch. % ... % Evaluate model gradients. gradients = dlfeval(@modelGradients, parameters, dlX, sequenceLengths); % Update learnable parameters. [parameters,trailingAvg,trailingAvgSq] = adamupdate(parameters,gradients, ... trailingAvg,trailingAvgSq,iteration); end end
The modelEncoder
function, принимает за вход параметры модели, последовательности словесных индексов и длины последовательности и возвращает соответствующий латентный вектор функции.
Поскольку входные данные содержат заполненные последовательности различной длины, заполнение может иметь неблагоприятные эффекты для вычислений потерь. Для операции LSTM, вместо возврата выхода последнего временного шага последовательности (который, вероятно, соответствует состоянию LSTM после обработки партий значений заполнения), определите фактический последний временной шаг, заданный sequenceLengths
вход.
function dlZ = modelEncoder(parameters,dlX,sequenceLengths) % Embedding. weights = parameters.emb.Weights; dlZ = embed(dlX,weights); % LSTM. inputWeights = parameters.lstmEncoder.InputWeights; recurrentWeights = parameters.lstmEncoder.RecurrentWeights; bias = parameters.lstmEncoder.Bias; numHiddenUnits = size(recurrentWeights,2); hiddenState = zeros(numHiddenUnits,1,'like',dlX); cellState = zeros(numHiddenUnits,1,'like',dlX); dlZ1 = lstm(dlZ,hiddenState,cellState,inputWeights,recurrentWeights,bias); % Output mode 'last' with masking. miniBatchSize = size(dlZ1,2); dlZ = zeros(numHiddenUnits,miniBatchSize,'like',dlZ1); dlZ = dlarray(dlZ,'CB'); for n = 1:miniBatchSize t = sequenceLengths(n); dlZ(:,n) = dlZ1(:,n,t); end % Fully connect. weights = parameters.fcEncoder.Weights; bias = parameters.fcEncoder.Bias; dlZ = fullyconnect(dlZ,weights,bias); end
Функция preprocessText
выполняет следующие шаги:
Готовит и добавляет каждую входную строку с заданными начальным и стоповым лексемами, соответственно.
Токенизация текста с помощью tokenizedDocument
.
function documents = preprocessText(textData,startToken,stopToken) % Add start and stop tokens. textData = startToken + textData + stopToken; % Tokenize the text. documents = tokenizedDocument(textData,'CustomTokens',[startToken stopToken]); end
doc2sequence
| tokenizedDocument
| word2ind
| wordEncoding