В задачах машинного обучения часто встречается проблема несбалансированных выборок, когда количество примеров одного класса значительно превышает количество примеров других классов. В таких условиях нейронные сети могут демонстрировать высокую точность на доминирующем классе, игнорируя редкие классы, что приводит к сильному смещению модели.
Смещение к основному классу Стандартный алгоритм обучения нейронной сети минимизирует ошибку на всей выборке. Если один класс преобладает, сеть будет «учиться» распознавать именно его, игнорируя редкие классы.
Недооценка редких событий В задачах классификации, например, диагностики заболеваний, редкие классы часто являются ключевыми. Несбалансированные данные приводят к тому, что сеть почти не выявляет важные, но редкие случаи.
Проблемы метрик качества Метрики, такие как точность (accuracy), становятся малоинформативными. Модель, предсказывающая всегда доминирующий класс, может иметь высокую точность, но при этом полностью игнорировать редкие классы. Более подходящие метрики: precision, recall, F1-score, матрица ошибок.
Brain.js позволяет влиять на процесс обучения через масштабирование значений ошибки для разных классов. Входные данные можно модифицировать так, чтобы редкие классы «весили» сильнее.
Пример:
const brain = require('brain.js');
const net = new brain.NeuralNetwork({ hiddenLayers: [10, 10] });
const trainingData = [
{ input: { cat: 1 }, output: { yes: 1 } },
{ input: { dog: 1 }, output: { no: 1 } },
{ input: { rareAnimal: 1 }, output: { yes: 1 } },
];
// Увеличиваем вес редкого класса вручную
const weightedData = trainingData.map(item => {
if (item.input.rareAnimal) {
return { ...item, weight: 5 };
}
return { ...item, weight: 1 };
});
net.train(weightedData, {
iterations: 20000,
log: true,
logPeriod: 1000,
});
Ключевой момент: Brain.js позволяет использовать
свойство weight для увеличения влияния редких примеров на
обучение.
Если класс редкий, можно создавать дополнительные синтетические примеры. На практике это делается с дублированием редких примеров или генерацией новых комбинаций признаков.
Пример дублирования:
let augmentedData = [...trainingData];
const rareExamples = trainingData.filter(d => d.input.rareAnimal);
for (let i = 0; i < 5; i++) {
augmentedData = augmentedData.concat(rareExamples);
}
Такой подход помогает сети увидеть больше примеров редкого класса, снижая смещение.
Если один класс сильно преобладает, можно уменьшить количество его примеров. Важно избегать потери информации, поэтому метод применяют осторожно.
const dominantClass = trainingData.filter(d => d.input.cat);
const rareClass = trainingData.filter(d => d.input.rareAnimal);
const balancedData = dominantClass.slice(0, rareClass.length * 2).concat(rareClass);
Метод уменьшает перекос, но требует достаточного количества данных для обучения.
В некоторых случаях несбалансированность можно компенсировать увеличением информативности входных данных. Например, кодирование категориальных признаков через one-hot или добавление новых признаков для редких классов.
const net = new brain.NeuralNetwork({ hiddenLayers: [20, 10] });
// Взвешивание и увеличение редких классов
const balancedTrainingData = trainingData.flatMap(item => {
if (item.input.rareAnimal) {
return Array(5).fill({ ...item, weight: 2 });
}
return { ...item, weight: 1 };
});
net.train(balancedTrainingData, {
iterations: 25000,
learningRate: 0.01,
log: true,
logPeriod: 2000,
});
Такой подход сочетает взвешивание, oversampling и тонкую настройку сети, что позволяет добиться более справедливого распознавания редких классов.
Эти метрики особенно важны, потому что простая точность может ввести в заблуждение, когда редкий класс представлен очень слабо.
Хотите, я могу подготовить раздел с конкретными стратегиями генерации синтетических данных для Brain.js, чтобы редкие классы всегда присутствовали в достаточном объеме и сеть не игнорировала их?