Мини-батч градиентный спуск — способ, которым обучают почти любую нейронную сеть: разбейте данные на небольшие батчи и обновляйте веса после каждого.
Обучите y = w × x + b по среднеквадратичной ошибке, начиная с w = 0 и b = 0. В каждой эпохе разбивайте примеры по порядку на батчи по batch_size (последний батч может быть меньше). Для каждого батча размера n:
- errorᵢ = w × xᵢ + b - yᵢ для каждого примера в батче
- dw = (2 / n) × Σ errorᵢ × xᵢ и db = (2 / n) × Σ errorᵢ
- w ← w - learning_rate × dw и b ← b - learning_rate × db
Реализуйте train_mini_batch(xs, ys, batch_size, learning_rate, epochs).
Входные данные
xs, ys: Точки данных (одинаковой длины).
batch_size: Число примеров в батче.
learning_rate, epochs: Размер шага и число проходов по данным.
Выходные данные
Верните [w, b] после обучения.
Ограничения
1 ≤ число точек ≤ 1 000, 1 ≤ batch_size ≤ число точек, 0 ≤ epochs ≤ 1 000
0 < learning_rate ≤ 1
-100 ≤ каждое значение ≤ 100
Примеры
Ввод:
xs = [1.0, 2.0, 3.0]
ys = [2.0, 4.0, 6.0]
epochs = 1
batch_size = 2
learning_rate = 0.1
Ожидаемый вывод:
expected = [2.44, 1.08]
Ввод:
std::vector<double> xs = {1.0, 2.0, 3.0};
std::vector<double> ys = {2.0, 4.0, 6.0};
long long epochs = 1;
long long batch_size = 2;
double learning_rate = 0.1;
Ожидаемый вывод:
std::vector<double> expected = {2.44, 1.08};
Ввод:
double[] xs = new double[] {1.0, 2.0, 3.0};
double[] ys = new double[] {2.0, 4.0, 6.0};
long epochs = 1;
long batch_size = 2;
double learning_rate = 0.1;
Ожидаемый вывод:
double[] expected = new double[] {2.44, 1.08};
Пояснение
Батч 1 — это x = [1, 2]: ошибки -2 и -4, dw = -10, db = -6, поэтому w = 1 и b = 0.6. Батч 2 — только x = [3]: ошибка 1×3 + 0.6 - 6 = -2.4, dw = 2 × (-2.4) × 3 = -14.4 и db = -4.8, поэтому w = 2.44 и b = 1.08. Результат: [2.44, 1.08].
Ввод:
xs = [1.0, 2.0, 3.0, 4.0]
ys = [3.0, 5.0, 7.0, 9.0]
epochs = 1
batch_size = 4
learning_rate = 0.05
Ожидаемый вывод:
expected = [1.75, 0.6]
Ввод:
std::vector<double> xs = {1.0, 2.0, 3.0, 4.0};
std::vector<double> ys = {3.0, 5.0, 7.0, 9.0};
long long epochs = 1;
long long batch_size = 4;
double learning_rate = 0.05;
Ожидаемый вывод:
std::vector<double> expected = {1.75, 0.6};
Ввод:
double[] xs = new double[] {1.0, 2.0, 3.0, 4.0};
double[] ys = new double[] {3.0, 5.0, 7.0, 9.0};
long epochs = 1;
long batch_size = 4;
double learning_rate = 0.05;
Ожидаемый вывод:
double[] expected = new double[] {1.75, 0.6};
Пояснение
Батч размером с весь набор данных — это обычный пакетный градиентный спуск: одно обновление за эпоху. Результат: [1.75, 0.6].
Как подступиться
Сначала попробуйте сами, затем открывайте подсказки по одной.
Подсказка 1
Обрабатывайте примеры в заданном порядке и обновляйте параметры после каждого batch, а не после каждой точки.
Подсказка 2
Для каждого batch сначала вычислите ошибки предсказания, затем используйте их средние вместе со значениями x, чтобы получить два градиента.
Подсказка 3
Последний batch может быть меньше остальных, поэтому масштабирование градиента должно использовать его размер.
Ожидаемая сложность
O(epochs × n) по времени, O(1) по дополнительной памяти
Ссылки
Это задание адаптировано для CodeUtility. Следуйте условию и ограничениям выше.