Сохранение в браузере: IndexedDB и LocalStorage

Браузеры предоставляют два основных способа хранения данных на стороне клиента: LocalStorage и IndexedDB. Их использование в сочетании с Keras.js позволяет сохранять нейронные сети, весовые коэффициенты и промежуточные данные между сессиями без необходимости обращения к серверу.


LocalStorage

LocalStorage представляет собой простое ключ-значение хранилище, доступное через объект window.localStorage. Основные характеристики:

  • Данные сохраняются в виде строк (string).
  • Размер ограничен примерно 5–10 МБ в зависимости от браузера.
  • Синхронный API — операции выполняются мгновенно, что может блокировать основной поток при больших объёмах данных.
  • Данные сохраняются между сессиями и доступны только в том же домене.

Пример сохранения весов модели в LocalStorage:

// Предположим, есть объект весов модели
const weights = model.getWeights(); // Получение весов из Keras.js
const weightsJSON = JSON.stringify(weights); // Сериализация в JSON

// Сохранение в LocalStorage
localStorage.setItem('modelWeights', weightsJSON);

Загрузка весов обратно:

const storedWeights = localStorage.getItem('modelWeights');
if (storedWeights) {
    const parsedWeights = JSON.parse(storedWeights);
    model.setWeights(parsedWeights);
}

Особенности использования с Keras.js:

  • Не подходит для хранения больших моделей, так как LocalStorage имеет ограничение по объёму.
  • Удобен для небольших моделей или метаданных, например, настроек пользователя или последних результатов обучения.

IndexedDB

IndexedDB — более продвинутое хранилище, ориентированное на работу с большими объёмами структурированных данных. Отличительные особенности:

  • Асинхронный API с использованием транзакций.
  • Возможность хранить бинарные данные (ArrayBuffer, Blob) — критично для весов модели в Keras.js.
  • Поддержка индексов и поиска по ключам.
  • Практически неограниченный объём (зависит от свободного места на диске и политики браузера).

Создание базы данных и объекта хранилища:

const request = indexedDB.open('kerasDB', 1);

request.onupgradenee ded = function(event) {
    const db = event.target.result;
    if (!db.objectStoreNames.contains('models')) {
        db.createObjectStore('models', { keyPath: 'name' });
    }
};

request.onsucc ess = function(event) {
    const db = event.target.result;
    console.log('IndexedDB готова к использованию');
};

Сохранение весов модели в IndexedDB:

function saveModelWeights(modelName, weights) {
    const dbRequest = indexedDB.open('kerasDB', 1);
    
    dbRequest.onsucc ess = function(event) {
        const db = event.target.result;
        const transaction = db.transaction(['models'], 'readwrite');
        const store = transaction.objectStore('models');
        
        const data = {
            name: modelName,
            weights: weights
        };
        
        const putRequest = store.put(data);
        putRequest.onsucc ess = () => console.log('Весовые коэффициенты сохранены');
        putRequest.oner ror = (e) => console.error('Ошибка при сохранении:', e);
    };
}

Загрузка весов из IndexedDB:

function loadModelWeights(modelName, callback) {
    const dbRequest = indexedDB.open('kerasDB', 1);
    
    dbRequest.onsucc ess = function(event) {
        const db = event.target.result;
        const transaction = db.transaction(['models'], 'readonly');
        const store = transaction.objectStore('models');
        
        const getRequest = store.get(modelName);
        getRequest.onsucc ess = () => {
            const result = getRequest.result;
            if (result) callback(result.weights);
        };
        getRequest.oner ror = (e) => console.error('Ошибка при загрузке:', e);
    };
}

Особенности использования с Keras.js:

  • Хранение бинарных данных весов напрямую через ArrayBuffer или TypedArray уменьшает объём сериализованных данных по сравнению с JSON.
  • Позволяет хранить несколько моделей и их версии одновременно.
  • Асинхронная природа IndexedDB предотвращает блокировку основного потока.

Сравнение LocalStorage и IndexedDB для Keras.js

Характеристика LocalStorage IndexedDB
Объём ~5–10 МБ Практически неограничен
Тип данных Только строки Строки, бинарные данные
Синхронность Синхронное API Асинхронное API
Подходит для Малых моделей, метаданных Больших моделей, весов, данных
Сложность использования Очень простое API Более сложное, требует транзакций

Рекомендации по использованию

  • Для малых моделей и настроек: LocalStorage удобен и прост в использовании.
  • Для больших моделей и весов Keras.js: IndexedDB обеспечивает безопасность данных и масштабируемость.
  • Использование Blob или ArrayBuffer в IndexedDB позволяет минимизировать накладные расходы на сериализацию.
  • Для совместимости с браузерами рекомендуется проверять поддержку IndexedDB и использовать LocalStorage как резервный вариант для простых данных.

Практические советы

  • При сохранении в LocalStorage или IndexedDB весов моделей рекомендуется использовать сжатие данных, например, через pako (gzip), чтобы уменьшить объём и ускорить загрузку.
  • Хранение версий моделей в IndexedDB позволяет откатываться к предыдущим состояниям без повторного скачивания с сервера.
  • Асинхронный доступ к IndexedDB необходимо оборачивать в Promise или async/await для удобной интеграции с Keras.js:
async function saveWeightsAsync(modelName, weights) {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open('kerasDB', 1);
        request.onsucc ess = function(event) {
            const db = event.target.result;
            const transaction = db.transaction(['models'], 'readwrite');
            const store = transaction.objectStore('models');
            const putReq = store.put({ name: modelName, weights: weights });
            putReq.onsucc ess = () => resolve();
            putReq.oner ror = (e) => reject(e);
        };
    });
}
  • Для загрузки весов в Keras.js рекомендуется использовать TypedArray формата Float32Array, что соответствует формату весов внутри библиотеки, минимизируя преобразования.