Разделение данных на обучающую и тестовую выборки

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


Основные принципы

Обучающая выборка (training set) используется для непосредственного обучения нейронной сети. Она содержит большинство примеров, на которых сеть будет корректировать свои веса через алгоритмы обратного распространения ошибки.

Тестовая выборка (test set) применяется исключительно для оценки качества обученной модели. Она не участвует в процессе обучения и позволяет объективно измерить способность сети к генерализации на новые данные.

Важные моменты:

  • Размер тестовой выборки обычно составляет от 10% до 30% от общей базы данных.
  • Данные должны быть случайно перемешаны перед разделением, чтобы избежать смещения из-за упорядоченности исходных данных.
  • Нельзя использовать тестовую выборку для настройки гиперпараметров модели, иначе оценка качества станет некорректной.

Методы разделения данных

  1. Простое случайное разделение
function splitData(data, testRatio) {
    let shuffled = data.slice();
    for (let i = shuffled.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
    }
    let testSize = Math.floor(data.length * testRatio);
    let testSet = shuffled.slice(0, testSize);
    let trainSet = shuffled.slice(testSize);
    return {trainSet, testSet};
}
  • data — исходный массив объектов с признаками и метками.
  • testRatio — доля данных для тестовой выборки.
  • Функция возвращает два массива: обучающую и тестовую выборки.

  1. Стратифицированное разделение

Для задач классификации важно, чтобы пропорции классов в обучающей и тестовой выборках соответствовали исходному распределению. Это предотвращает смещение метрик при редких классах.

function stratifiedSplit(data, labels, testRatio) {
    let labelMap = {};
    for (let i = 0; i < data.length; i++) {
        if (!labelMap[labels[i]]) labelMap[labels[i]] = [];
        labelMap[labels[i]].push(data[i]);
    }
    let trainSet = [];
    let testSet = [];
    for (let label in labelMap) {
        let items = labelMap[label];
        let testSize = Math.floor(items.length * testRatio);
        for (let i = 0; i < items.length; i++) {
            if (i < testSize) testSet.push(items[i]);
            else trainSet.push(items[i]);
        }
    }
    return {trainSet, testSet};
}
  • Этот метод обеспечивает сохранение распределения классов.
  • Особенно полезен для малых и несбалансированных наборов данных.

Интеграция с ConvNetJS

ConvNetJS использует объект Vol для представления входных данных. После разделения выборок данные преобразуются в объекты Vol с соответствующими метками для обучения и тестирования.

let trainData = trainSet.map(d => ({x: new convnetjs.Vol(d.input), y: d.label}));
let testData = testSet.map(d => ({x: new convnetjs.Vol(d.input), y: d.label}));
  • d.input — массив признаков для одного примера.
  • d.label — числовая метка класса.
  • Этот подход позволяет напрямую использовать данные с функциями trainer.train() и trainer.trainBatch().

Обучение с использованием разделенных данных

Пример организации процесса обучения с контролем тестовой выборки:

let trainer = new convnetjs.SGDTrainer(net, {learning_rate:0.01, momentum:0.9, batch_size:10, l2_decay:0.001});

for (let epoch = 0; epoch < 50; epoch++) {
    for (let i = 0; i < trainData.length; i++) {
        trainer.train(trainData[i].x, trainData[i].y);
    }

    // Проверка качества на тестовой выборке
    let correct = 0;
    for (let i = 0; i < testData.length; i++) {
        let predicted = net.forward(testData[i].x).w.indexOf(Math.max(...net.forward(testData[i].x).w));
        if (predicted === testData[i].y) correct++;
    }
    console.log(`Эпоха ${epoch}: точность на тестовой выборке ${(correct/testData.length*100).toFixed(2)}%`);
}
  • Пошаговая проверка после каждой эпохи позволяет отслеживать переобучение.
  • Использование trainData только для обучения, testData только для оценки — обязательное условие.

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

  • Всегда перемешивать данные перед разделением.
  • Для больших наборов данных достаточно простого случайного разбиения.
  • Для малых или несбалансированных классов рекомендуется стратифицированное разделение.
  • Тестовая выборка должна быть строго отделена до начала обучения.
  • Можно дополнительно выделять валидационную выборку, чтобы на ней настраивать гиперпараметры, не используя тестовую выборку.

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