Hone logo
Hone
Problems

Implementing a Simple RNN for Sequence Prediction

Recurrent Neural Networks (RNNs) are powerful tools for processing sequential data, like text, time series, or speech. Understanding their core mechanics is crucial for anyone venturing into deep learning for sequential tasks. This challenge asks you to implement a basic Recurrent Neural Network from scratch to predict the next element in a sequence.

Problem Description

Your task is to build a simple Recurrent Neural Network (RNN) from scratch using Python and NumPy. This RNN will be trained on a given sequence of numbers and will learn to predict the next number in the sequence based on the previous elements. You will be responsible for defining the network architecture, implementing the forward pass, and writing a simplified training loop that updates the network's weights based on a loss function.

Key Requirements:

  1. RNN Cell Implementation: Implement a basic RNN cell that takes the current input and the previous hidden state, and computes the new hidden state and an output.
  2. Forward Pass: Implement the full forward pass for a sequence, iterating through the RNN cell for each element in the input sequence.
  3. Loss Function: Implement a simple loss function, such as Mean Squared Error (MSE), to quantify the difference between the predicted output and the target output.
  4. Weight Initialization: Initialize the network's weights and biases appropriately.
  5. Simplified Training (Conceptual): While a full backpropagation through time (BPTT) implementation is complex for a "from scratch" challenge, you will conceptually outline or simulate a single weight update step (e.g., a gradient descent update based on a pre-calculated gradient or a simplified manual update). For this challenge, we will focus on the forward pass and loss calculation, and you will be provided with a hypothetical gradient for a single update step to demonstrate how weights would be updated.

Expected Behavior:

Given an input sequence and a target sequence (where the target is the input sequence shifted by one element), the RNN should learn to approximate the target sequence. After training (or conceptual training step), the RNN should be able to predict the next element in a new sequence with reasonable accuracy.

Edge Cases to Consider:

  • Handling sequences of varying lengths (though for this challenge, we'll assume fixed input sequence lengths for simplicity).
  • Numerical stability during computations.

Examples

Example 1:

Input Sequence: [0.1, 0.2, 0.3, 0.4]
Target Sequence: [0.2, 0.3, 0.4, 0.5]  (The next expected element after each input)

Initial Weights (Hypothetical):
W_xh = [[0.5, -0.2], [0.3, 0.1]]  # Input to hidden weights
W_hh = [[-0.1, 0.4], [0.2, -0.3]]  # Hidden to hidden weights
b_h = [0.05, -0.02]             # Hidden bias
W_hy = [0.6, -0.4]              # Hidden to output weights
b_y = [-0.1]                    # Output bias

Hidden Layer Size: 2
Output Layer Size: 1

Hypothetical Output after one conceptual training step (weights updated):

Let's assume after training, the RNN can predict the sequence: Predicted Sequence: [0.21, 0.32, 0.41, 0.53]

Explanation: The input sequence is fed into the RNN one element at a time. The RNN maintains a hidden state that is updated at each time step. The output at each step is a prediction for the next element in the sequence. The target sequence represents the ground truth. The difference between the predicted and target sequences forms the loss. For this example, we show a hypothetical successful prediction after training.

Example 2:

Input Sequence: [1.0, 0.5, 0.2]
Target Sequence: [0.5, 0.2, 0.1]

Initial Weights (Hypothetical - different from Ex1):
W_xh = [[0.1, 0.2], [-0.3, 0.4]]
W_hh = [[0.5, -0.1], [-0.2, 0.3]]
b_h = [-0.01, 0.03]
W_hy = [-0.7, 0.5]
b_y = [0.2]

Hidden Layer Size: 2
Output Layer Size: 1

Hypothetical Output after one conceptual training step (weights updated):

Let's assume after training, the RNN can predict the sequence: Predicted Sequence: [0.48, 0.23, 0.11]

Explanation: Similar to Example 1, but with different initial conditions and input data. The RNN learns the underlying pattern to predict the subsequent values in the sequence.

Constraints

  • You must use NumPy for all numerical computations.
  • You are not allowed to use high-level deep learning libraries like TensorFlow, Keras, or PyTorch for the RNN implementation itself. You can use them for testing or comparison if you wish, but the core RNN logic must be your own.
  • The input sequences will consist of floating-point numbers.
  • The target sequences will be derived from the input sequences (shifted by one element).
  • Focus on implementing the forward pass and the core RNN cell logic. For the "training" aspect, you will conceptually demonstrate weight updates. We will provide a simplified gradient for a single hypothetical update step.
  • Hidden layer size and output layer size will be specified.

Notes

  • The core of an RNN is its ability to maintain a "memory" or "state" that is passed from one time step to the next. This state is updated based on the current input and the previous state.
  • The simplest RNN cell uses a tanh activation function for the hidden state.
  • For the output layer, a linear activation is often used for regression tasks like this.
  • Consider how you will handle the initial hidden state (often initialized to zeros).
  • For the weight update, imagine you have calculated the gradients dW_xh, dW_hh, db_h, dW_hy, db_y for a single time step or a simplified batch. Your task will be to show how you would apply these gradients to update the weights using a learning rate. For this challenge, you will be provided with a hypothetical gradient and you will implement the update rule.
Loading editor...
python