All challenges
Medium 0 solved 0% acceptance

Train a Neuron with Gradient Descent

Repeat forward pass, gradients and weight updates to teach a sigmoid neuron from examples.

What you'll learn

  • Repeat forward pass, gradients and updates
  • Tune a learning rate
  • Watch a neuron learn from examples

Problem

Gradient descent improves the weights a little at a time by moving against the gradient:

w ← w - learning_rate × dL/dw

Train a sigmoid neuron with stochastic gradient descent. For each epoch, go through the samples in the given order, and for each sample:

  1. z = sample · weights + bias, y = 1 / (1 + e^(-z))
  2. delta = 2 × (y - target) × y × (1 - y)
  3. weights[i] ← weights[i] - learning_rate × delta × sample[i] (for every i), then bias ← bias - learning_rate × delta

Implement train_neuron(samples, targets, weights, bias, learning_rate, epochs).

Input

samples: m training examples, each with n values.

targets: The m correct outputs (between 0 and 1).

weights, bias: The starting weights (n values) and bias.

learning_rate, epochs: The step size and how many passes over the data.

Output

Return the trained weights followed by the trained bias (n + 1 numbers).

Constraints

1 ≤ m ≤ 50, 1 ≤ n ≤ 10, 1 ≤ epochs ≤ 1,000

0 < learning_rate ≤ 5

-5 ≤ each value ≤ 5

Examples

Example 1
Input:
bias = 0.0
epochs = 1
samples = [
    [1.0]
]
targets = [1.0]
weights = [0.0]
learning_rate = 1.0

Expected output:
expected = [0.25, 0.25]
Input:
double bias = 0.0;
long long epochs = 1;
std::vector<std::vector<double>> samples = {
    {1.0}
};
std::vector<double> targets = {1.0};
std::vector<double> weights = {0.0};
double learning_rate = 1.0;

Expected output:
std::vector<double> expected = {0.25, 0.25};
Input:
double bias = 0.0;
long epochs = 1;
double[][] samples = new double[][] {
    new double[] {1.0}
};
double[] targets = new double[] {1.0};
double[] weights = new double[] {0.0};
double learning_rate = 1.0;

Expected output:
double[] expected = new double[] {0.25, 0.25};

Explanation

y = σ(0) = 0.5, delta = 2 × (0.5 - 1) × 0.25 = -0.25. Weight: 0 - 1 × (-0.25) × 1 = 0.25. Bias: 0 - 1 × (-0.25) = 0.25. Result: [0.25, 0.25].

Example 2
Input:
bias = 0.0
epochs = 500
samples = [
    [0.0, 0.0],
    [0.0, 1.0],
    [1.0, 0.0],
    [1.0, 1.0]
]
targets = [0.0, 0.0, 0.0, 1.0]
weights = [0.0, 0.0]
learning_rate = 2.0

Expected output:
expected = [6.346558, 6.339863, -9.592092]
Input:
double bias = 0.0;
long long epochs = 500;
std::vector<std::vector<double>> samples = {
    {0.0, 0.0},
    {0.0, 1.0},
    {1.0, 0.0},
    {1.0, 1.0}
};
std::vector<double> targets = {0.0, 0.0, 0.0, 1.0};
std::vector<double> weights = {0.0, 0.0};
double learning_rate = 2.0;

Expected output:
std::vector<double> expected = {6.346558, 6.339863, -9.592092};
Input:
double bias = 0.0;
long epochs = 500;
double[][] samples = new double[][] {
    new double[] {0.0, 0.0},
    new double[] {0.0, 1.0},
    new double[] {1.0, 0.0},
    new double[] {1.0, 1.0}
};
double[] targets = new double[] {0.0, 0.0, 0.0, 1.0};
double[] weights = new double[] {0.0, 0.0};
double learning_rate = 2.0;

Expected output:
double[] expected = new double[] {6.346558, 6.339863, -9.592092};

Explanation

This is the logical AND gate. After 500 epochs both weights are large and positive and the bias is strongly negative, so only the input [1, 1] gives an output above 0.5.

References

This challenge is adapted for CodeUtility. Follow the statement and constraints above.

Learn from others

Community solutions

No published solutions yet. Solve this challenge to share the first one.