Многие задачи машинного обучения, особенно в области обработки естественного языка (NLP) и временных рядов, требуют работы с последовательностями различной длины. Для корректной работы моделей важно учитывать реальную длину последовательностей и игнорировать лишние элементы, добавленные для выравнивания батчей. Этот процесс называется маскированием.
В TensorFlow.js последовательности часто приводятся к одинаковой
длине с помощью padding. Например, при работе с
предложениями, каждое слово может быть закодировано как число (индекс в
словаре). Чтобы объединить предложения в батч, более короткие
последовательности дополняются специальным токеном (например,
0):
const sequences = [
[1, 2, 3],
[4, 5],
[6]
];
// Применяем padding до длины 3
const paddedSequences = [
[1, 2, 3],
[4, 5, 0],
[6, 0, 0]
];
Без маскирования модель будет учитывать нулевые токены как реальные данные, что приведет к искажению результатов.
TensorFlow.js поддерживает masking через слой
tf.layers.masking. Маска указывает, какие элементы
последовательности следует игнорировать в последующих слоях, таких как
LSTM или GRU.
const model = tf.sequential();
model.add(tf.layers.masking({
maskValue: 0, // Значение, которое будет игнорироваться
inputShape: [null, 1] // null позволяет работать с переменной длиной последовательности
}));
model.add(tf.layers.lstm({
units: 16,
returnSequences: true
}));
model.add(tf.layers.dense({ units: 1, activation: 'sigmoid' }));
Ключевые моменты:
maskValue задаёт значение, которое не будет учитываться
моделью.inputShape с null позволяет обрабатывать
последовательности любой длины.LSTM, GRU,
SimpleRNN).EmbeddingЕсли используется слой Embedding для преобразования
индексов слов в векторы, маскирование можно включить сразу:
model.add(tf.layers.embedding({
inputDim: 10000, // размер словаря
outputDim: 64, // размер вектора признаков
maskZero: true, // автоматически создает маску для нулевых токенов
inputLength: null
}));
maskZero: true создаёт маску для всех нулевых
элементов.Masking отдельно.При обучении модели с маскированными последовательностями:
const xs = tf.tensor3d([
[[1], [2], [3]],
[[4], [5], [0]],
[[6], [0], [0]]
]);
const ys = tf.tensor2d([
[1],
[0],
[1]
]);
model.compile({
optimizer: 'adam',
loss: 'binaryCrossentropy',
metrics: ['accuracy']
});
await model.fit(xs, ys, {
epochs: 10,
batchSize: 2
});
Маска предотвращает влияние нулевых элементов на обучение, обеспечивая корректную работу градиентов и точность модели.
Маскирование распространяется через рекуррентные слои автоматически.
Например, если LSTM получает маску, то:
returnSequences: true маска сохраняется для всех
последующих слоев.Можно использовать маску и в собственных слоях через аргумент
mask в методе call. Например:
class MyLayer extends tf.layers.Layer {
constructor() {
super({});
}
computeMask(inputs, mask) {
return mask; // передаем маску дальше
}
call(inputs, kwargs) {
const mask = kwargs['mask'];
// можно использовать mask для игнорирования padded элементов
return tf.mul(inputs, tf.cast(mask, 'float32'));
}
}
Это обеспечивает гибкость и позволяет строить сложные архитектуры, корректно обрабатывающие переменные длины последовательностей.
Embedding устанавливать
maskZero: true для автоматического управления маской.Маскирование является фундаментальным инструментом для работы с последовательностями в TensorFlow.js, обеспечивая корректность обучения и предсказаний при работе с данными переменной длины.