Implement a GRU (Gated Recurrent Unit) cell forward pass. Given input x_t, previous hidden state h_{t-1}, and weight matrices, compute the update gate, reset gate, candidate hidden state, and new hidden state.
import numpy as np
def sigmoid(x: np.ndarray) -> np.ndarray:
return 1.0 / (1.0 + np.exp(-np.clip(x, -500, 500)))
def gru_cell(x_t: np.ndarray, h_prev: np.ndarray,
W_z: np.ndarray, U_z: np.ndarray, b_z: np.ndarray,
W_r: np.ndarray, U_r: np.ndarray, b_r: np.ndarray,
W_h: np.ndarray, U_h: np.ndarray, b_h: np.ndarray) -> np.ndarray:
# Update gate
z_t = sigmoid(W_z @ x_t + U_z @ h_prev + b_z)
# Reset gate
r_t = sigmoid(W_r @ x_t + U_r @ h_prev + b_r)
# Candidate hidden state
h_candidate = np.tanh(W_h @ x_t + U_h @ (r_t * h_prev) + b_h)
# New hidden state
h_t = z_t * h_prev + (1 - z_t) * h_candidate
return h_t