Нормализация и стандартизация данных

При работе с нейронными сетями одной из ключевых задач является подготовка входных данных. ConvNetJS, как и большинство библиотек для глубокого обучения, требует, чтобы данные имели определённый масштаб и распределение. Нормализация и стандартизация являются двумя основными подходами к этому процессу.


Нормализация данных

Нормализация предполагает преобразование исходных значений признаков в заданный диапазон, обычно ([0, 1]) или ([-1, 1]). Это помогает улучшить сходимость градиентного спуска и предотвращает доминирование признаков с большими числовыми значениями.

Формула нормализации для диапазона ([0, 1]):

[ x_{} = ]

где (x) — исходное значение признака, (x_{}) и (x_{}) — минимальное и максимальное значение признака в наборе данных.

В ConvNetJS данные часто представляются объектами Vol, которые содержат массивы чисел. Нормализация Vol выполняется путём итерации по всем элементам и применения формулы выше.

Пример нормализации Vol:

function normalizeVol(vol) {
    let min = Math.min(...vol.w);
    let max = Math.max(...vol.w);
    let range = max - min;
    let normalized = vol.clone();
    for (let i = 0; i < normalized.w.length; i++) {
        normalized.w[i] = (normalized.w[i] - min) / range;
    }
    return normalized;
}

Особое внимание следует уделять тому, что минимальные и максимальные значения должны вычисляться только по тренировочному набору, чтобы избежать утечки информации из тестовой выборки.


Стандартизация данных

Стандартизация (z-score normalization) преобразует признаки так, чтобы они имели среднее 0 и стандартное отклонение 1. Это особенно важно для сетей с активациями ReLU, tanh или sigmoid, поскольку стандартизированные данные обеспечивают более стабильное обучение.

Формула стандартизации:

[ x_{} = ]

где () — среднее значение признака, () — стандартное отклонение.

В ConvNetJS стандартизация может быть реализована следующим образом:

function standardizeVol(vol) {
    let mean = vol.w.reduce((a,b) => a+b, 0) / vol.w.length;
    let variance = vol.w.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / vol.w.length;
    let std = Math.sqrt(variance);
    let standardized = vol.clone();
    for (let i = 0; i < standardized.w.length; i++) {
        standardized.w[i] = (standardized.w[i] - mean) / std;
    }
    return standardized;
}

Стандартизация особенно полезна при использовании Batch Normalization или при глубокой архитектуре сети, где различия в масштабах признаков могут привести к затухающему или взрывающемуся градиенту.


Выбор между нормализацией и стандартизацией

  • Нормализация чаще используется для изображений и данных с фиксированным диапазоном, например, пиксели в интервале [0, 255]. Преобразование в диапазон [0, 1] или [-1, 1] обеспечивает совместимость с функциями активации и ускоряет обучение.
  • Стандартизация предпочтительна для признаков с разными шкалами, например, в финансовых данных, сенсорных измерениях или других числовых наборах, где значения могут сильно различаться по порядку величины.

Практическая интеграция в ConvNetJS

ConvNetJS работает с сетями, создаваемыми через convnetjs.Net, и тренировкой через Trainer. Для корректной работы:

  1. Данные должны быть представлены в виде массивов чисел или объектов Vol.
  2. Все входные признаки необходимо привести к совместимому масштабу с помощью нормализации или стандартизации.
  3. При использовании Trainer.train() следует убедиться, что входные Vol уже преобразованы.

Пример подготовки изображений для сети:

let imgData = getImageData(); // массив пикселей [0,255]
let vol = new convnetjs.Vol(imgData);
vol = normalizeVol(vol); // нормализация в диапазон [0,1]
net.forward(vol);

Совместное использование нормализации и стандартизации

Иногда применяется комбинированный подход: сначала данные нормализуются в диапазон [0, 1], а затем стандартизируются с вычислением среднего и стандартного отклонения по нормализованным значениям. Это позволяет достичь более стабильного и быстрого обучения, особенно при сложных архитектурах ConvNetJS.


Контроль и диагностика

После нормализации или стандартизации полезно проверять распределение признаков:

function printStats(vol) {
    let mean = vol.w.reduce((a,b) => a+b, 0) / vol.w.length;
    let variance = vol.w.reduce((sum,val) => sum + Math.pow(val - mean,2),0) / vol.w.length;
    console.log(`Mean: ${mean}, Std: ${Math.sqrt(variance)}`);
}

Правильное масштабирование данных предотвращает аномалии в обучении и помогает добиться высокой точности модели.


Хотя ConvNetJS предоставляет минимальный встроенный функционал для обработки данных, грамотная предобработка через нормализацию и стандартизацию является критически важным этапом подготовки любой нейросети.