Problème
La descente de gradient par mini-lots est la façon dont presque tous les réseaux de neurones sont entraînés : découpez les données en petits lots et mettez à jour les poids après chacun.
Entraînez y = w × x + b sur l'erreur quadratique moyenne, en partant de w = 0 et b = 0. À chaque époque, découpez les exemples dans l'ordre en lots de batch_size (le dernier lot peut être plus petit). Pour chaque lot de taille n :
- errorᵢ = w × xᵢ + b - yᵢ pour chaque exemple du lot
- dw = (2 / n) × Σ errorᵢ × xᵢ et db = (2 / n) × Σ errorᵢ
- w ← w - learning_rate × dw et b ← b - learning_rate × db
Implémentez train_mini_batch(xs, ys, batch_size, learning_rate, epochs).
Entrée
xs, ys : Les points de données (même longueur).
batch_size : Le nombre d'exemples par lot.
learning_rate, epochs : La taille du pas et le nombre de passes sur les données.
Sortie
Renvoyez [w, b] après l'entraînement.
Contraintes
1 ≤ nombre de points ≤ 1 000, 1 ≤ batch_size ≤ nombre de points, 0 ≤ epochs ≤ 1 000
0 < learning_rate ≤ 1
-100 ≤ chaque valeur ≤ 100
Exemples
Entrée :
xs = [1.0, 2.0, 3.0]
ys = [2.0, 4.0, 6.0]
epochs = 1
batch_size = 2
learning_rate = 0.1
Sortie attendue :
expected = [2.44, 1.08]
Entrée :
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;
Sortie attendue :
std::vector<double> expected = {2.44, 1.08};
Entrée :
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;
Sortie attendue :
double[] expected = new double[] {2.44, 1.08};
Explication
Le lot 1 est x = [1, 2] : erreurs -2 et -4, dw = -10, db = -6, donc w = 1 et b = 0.6. Le lot 2 est x = [3] seul : erreur 1×3 + 0.6 - 6 = -2.4, dw = 2 × (-2.4) × 3 = -14.4 et db = -4.8, donc w = 2.44 et b = 1.08. Résultat : [2.44, 1.08].
Entrée :
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
Sortie attendue :
expected = [1.75, 0.6]
Entrée :
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;
Sortie attendue :
std::vector<double> expected = {1.75, 0.6};
Entrée :
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;
Sortie attendue :
double[] expected = new double[] {1.75, 0.6};
Explication
Un lot aussi grand que le jeu de données correspond à la descente de gradient classique : une mise à jour par époque. Résultat : [1.75, 0.6].
Comment l'aborder
Essayez d'abord seul, puis ouvrez les indices un par un.
Indice 1
Traite les échantillons dans l’ordre donné, en mettant à jour les paramètres après chaque batch au lieu de chaque point.
Indice 2
Pour chaque batch, calcule d’abord les erreurs de prédiction, puis utilise leurs moyennes avec les valeurs de x pour obtenir les deux gradients.
Indice 3
Le dernier batch peut être plus petit que les autres, donc son échelle de gradient doit utiliser la taille de ce batch.
Complexité attendue
temps O(epochs × n), espace supplémentaire O(1)
Références
Ce défi a été adapté pour CodeUtility. Suivez l'énoncé et les contraintes ci-dessus.