При работе с нейронными сетями одной из ключевых задач является подготовка входных данных. 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 или при глубокой архитектуре сети, где различия в масштабах признаков могут привести к затухающему или взрывающемуся градиенту.
ConvNetJS работает с сетями, создаваемыми через
convnetjs.Net, и тренировкой через Trainer.
Для корректной работы:
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 предоставляет минимальный встроенный функционал для обработки данных, грамотная предобработка через нормализацию и стандартизацию является критически важным этапом подготовки любой нейросети.