TensorFlow.js предоставляет мощные средства для работы с большими
датасетами напрямую в браузере или на Node.js, используя потоки
(tf.data). Потоки позволяют эффективно загружать,
преобразовывать и обрабатывать данные по мере необходимости, что
критично при работе с ограниченной памятью.
Ключевой концепцией является объект
tf.data.Dataset, который представляет собой
ленивый поток данных. Он может быть построен из массивов, генераторов,
файлов или других источников, и поддерживает цепочку трансформаций без
необходимости загружать весь датасет в память.
Из массива:
const data = [1, 2, 3, 4, 5];
const dataset = tf.data.array(data);
Метод tf.data.array создает поток, который выдает
элементы массива по одному. Для больших массивов это позволяет избежать
одновременной загрузки всего содержимого в оперативную память.
Из генератора:
function* dataGenerator() {
for (let i = 0; i < 1000; i++) {
yield i;
}
}
const dataset = tf.data.generator(dataGenerator);
Генераторы полезны, когда данные формируются динамически или считываются из внешних источников. В отличие от массивов, генератор создает элементы «на лету», экономя ресурсы.
TensorFlow.js позволяет последовательно применять преобразования к данным, формируя конвейеры обработки.
map — применяется к каждому
элементу:
const mappedDataset = dataset.map(x => x * 2);
batch — группировка элементов в
батчи:
const batchedDataset = mappedDataset.batch(32);
shuffle — случайная перестановка
элементов (важно для обучения нейросетей):
const shuffledDataset = batchedDataset.shuffle(100);
repeat — повторение потока для
нескольких эпох:
const repeatedDataset = shuffledDataset.repeat();
Трансформации можно комбинировать в цепочки, создавая конвейеры данных:
const processedDataset = tf.data
.generator(dataGenerator)
.map(x => x * 2)
.shuffle(50)
.batch(16)
.repeat();
TensorFlow.js поддерживает чтение данных из CSV и JSON-файлов. Это особенно важно при работе с большими датасетами, которые не помещаются в память.
CSV-файлы:
const csvDataset = tf.data.csv('data.csv', {
columnConfigs: {
label: { isLabel: true }
},
hasHeader: true
});
Параметр columnConfigs позволяет указать, какие колонки
являются целевыми метками. hasHeader учитывает первую
строку файла как заголовок.
Построчная обработка файлов:
Для кастомных форматов можно использовать генератор, который считывает файл построчно, создавая поток:
const fs = require('fs');
function* readFileLines(path) {
const lines = fs.readFileSync(path, 'utf-8').split('\n');
for (const line of lines) {
yield line;
}
}
const fileDataset = tf.data.generator(() => readFileLines('data.txt'));
Для потоков, источником которых являются асинхронные операции
(например, HTTP-запросы), используется
tf.data.asyncGenerator:
async function* asyncDataGenerator() {
for (let i = 0; i < 100; i++) {
const response = await fetch(`https://api.example.com/data/${i}`);
const json = await response.json();
yield json.value;
}
}
const asyncDataset = tf.data.asyncGenerator(asyncDataGenerator);
Асинхронные потоки позволяют работать с внешними источниками без
блокировки выполнения программы и поддерживают всю цепочку трансформаций
(map, batch, shuffle).
Объекты tf.data.Dataset напрямую интегрируются с
методами model.fit и model.fitDataset. Пример
обучения модели на потоке данных:
const model = tf.sequential();
model.add(tf.layers.dense({ units: 10, activation: 'relu', inputShape: [1] }));
model.add(tf.layers.dense({ units: 1 }));
model.compile({ optimizer: 'sgd', loss: 'meanSquaredError' });
const xs = tf.data.array([1, 2, 3, 4]);
const ys = tf.data.array([1, 3, 5, 7]);
const dataset = tf.data.zip({ xs, ys }).batch(2);
await model.fitDataset(dataset, { epochs: 10 });
Метод zip объединяет несколько потоков, формируя объекты
с входными данными и метками. Это упрощает подготовку обучающих данных
при работе с большими наборами.
map и
forEachAsync поддерживают параметр
numParallelCalls для распараллеливания обработки
элементов.prefetch(bufferSize)
позволяет заранее загружать элементы потока в память, сокращая задержки
при обучении:const optimizedDataset = dataset
.map(x => x * 2, { numParallelCalls: 4 })
.batch(32)
.prefetch(2);
shuffle и repeat только там, где
это необходимо для обучения.map, filter и другие
трансформации, строя компактные и читаемые конвейеры данных.Эта система позволяет строить гибкие и масштабируемые решения для обучения моделей на больших датасетах без необходимости полной загрузки данных в оперативную память, что критично для браузерного и серверного окружения.