Created
November 18, 2025 12:44
-
-
Save AhmedCoolProjects/09c3bb6b1950f744047585e2ed629101 to your computer and use it in GitHub Desktop.
GRU application.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "nbformat": 4, | |
| "nbformat_minor": 0, | |
| "metadata": { | |
| "colab": { | |
| "provenance": [], | |
| "authorship_tag": "ABX9TyO/9u22khfPwSifq4TSYWNn", | |
| "include_colab_link": true | |
| }, | |
| "kernelspec": { | |
| "name": "python3", | |
| "display_name": "Python 3" | |
| }, | |
| "language_info": { | |
| "name": "python" | |
| } | |
| }, | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "id": "view-in-github", | |
| "colab_type": "text" | |
| }, | |
| "source": [ | |
| "<a href=\"https://colab.research.google.com/gist/AhmedCoolProjects/09c3bb6b1950f744047585e2ed629101/gru-application.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "metadata": { | |
| "id": "LN11Q64X9vTo" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "import numpy as np\n", | |
| "import matplotlib.pyplot as plt" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "class GRU:\n", | |
| " def __init__(self, hidden_size, vocab_size, learning_rate=0.01):\n", | |
| " self.H = hidden_size\n", | |
| " self.V = vocab_size\n", | |
| " self.lr = learning_rate\n", | |
| "\n", | |
| " # Weights Initialization\n", | |
| " W_shape = (self.H, self.H + self.V)\n", | |
| "\n", | |
| " self.Wr = np.random.randn(*W_shape) * 0.01\n", | |
| " self.br = np.zeros((self.H, 1))\n", | |
| "\n", | |
| " self.Wz = np.random.randn(*W_shape) * 0.01\n", | |
| " self.bz = np.zeros((self.H, 1))\n", | |
| "\n", | |
| " self.Wh = np.random.randn(*W_shape) * 0.01\n", | |
| " self.bh = np.zeros((self.H, 1))\n", | |
| "\n", | |
| " self.Wy = np.random.randn(self.V, self.H) * 0.01\n", | |
| " self.by = np.zeros((self.V, 1))\n", | |
| "\n", | |
| " # Gradients\n", | |
| " self.dWr, self.dWz, self.dWh, self.dWy = [None]*4\n", | |
| " self.dbr, self.dbz, self.dbh, self.dby = [None]*4\n", | |
| "\n", | |
| " def _sigmoid(self, z):\n", | |
| " return 1 / (1 + np.exp(-z))\n", | |
| "\n", | |
| " def _sigmoid_derivative(self, a):\n", | |
| " return a * (1 - a)\n", | |
| "\n", | |
| " def _tanh(self, z):\n", | |
| " return np.tanh(z)\n", | |
| "\n", | |
| " def _tanh_derivative(self, a):\n", | |
| " return 1 - a ** 2\n", | |
| "\n", | |
| " def _softmax(self, z):\n", | |
| " exp_z = np.exp(z - np.max(z))\n", | |
| " return exp_z / exp_z.sum(axis=0)\n", | |
| "\n", | |
| " def forward(self, inputs, h_prev):\n", | |
| " xs, hs, zs, ys = {}, {}, {}, {}\n", | |
| " rs_g, zs_g, h_cands = {}, {}, {}\n", | |
| " concat_inputs = {}\n", | |
| "\n", | |
| " hs[-1] = np.copy(h_prev)\n", | |
| "\n", | |
| " for t in range(len(inputs)):\n", | |
| " xs[t] = np.zeros((self.V, 1))\n", | |
| " xs[t][inputs[t]] = 1\n", | |
| "\n", | |
| " concat_inputs[t] = np.vstack((hs[t-1], xs[t]))\n", | |
| "\n", | |
| " rs_g[t] = self._sigmoid(np.dot(self.Wr, concat_inputs[t]) + self.br)\n", | |
| " zs_g[t] = self._sigmoid(np.dot(self.Wz, concat_inputs[t]) + self.bz)\n", | |
| " h_cands = self._tanh(np.dot(self.Wh, np.vstack((rs_g[t] * hs[t-1], xs[t]))) + self.bh)\n", | |
| "\n", | |
| " hs[t] = (1 - zs_g[t]) * hs[t-1] + zs_g[t] * h_cands\n", | |
| "\n", | |
| " # Final Prediction\n", | |
| " zs[t] = np.dot(self.Wy, hs[t]) + self.by\n", | |
| " ys[t] = self._softmax(zs[t])\n", | |
| "\n", | |
| " cache = (xs, hs, zs, ys, rs_g, zs_g, h_cands, concat_inputs)\n", | |
| " return ys, hs[len(inputs)-1], cache\n", | |
| "\n", | |
| " def compute_cost(self, ys, targets):\n", | |
| " total_cost = 0\n", | |
| " for t in range(len(targets)):\n", | |
| " prob = ys[t][targets[t], 0]\n", | |
| " total_cost += -np.log(prob + 1e-9)\n", | |
| " return total_cost / len(targets)\n", | |
| "\n", | |
| " def backpropagation(self, targets, cache):\n", | |
| " xs, hs, zs, ys, rs_g, zs_g, h_cands, concat_inputs = cache\n", | |
| " T = len(targets)\n", | |
| "\n", | |
| " self.dWr = np.zeros_like(self.Wr)\n", | |
| " self.dWz = np.zeros_like(self.Wz)\n", | |
| " self.dWh = np.zeros_like(self.Wh)\n", | |
| " self.dWy = np.zeros_like(self.Wy)\n", | |
| " self.dbr = np.zeros_like(self.br)\n", | |
| " self.dbz = np.zeros_like(self.bz)\n", | |
| " self.dbh = np.zeros_like(self.bh)\n", | |
| " self.dby = np.zeros_like(self.by)\n", | |
| " dh_next = np.zeros_like(hs[0])\n", | |
| "\n", | |
| " for t in reversed(range(T)):\n", | |
| " dy = np.copy(ys[t])\n", | |
| " dy[targets[t]] -= 1\n", | |
| "\n", | |
| " self.dWy += np.dot(dy, hs[t].T)\n", | |
| " self.dby += dy\n", | |
| "\n", | |
| " dh = np.dot(self.Wy.T, dy) + dh_next\n", | |
| "\n", | |
| " dz = dh * (h_cands[t] - hs[t-1]) * self._sigmoid_derivative(zs_g[t])\n", | |
| " self.dWz += np.dot(dz, concat_inputs[t].T)\n", | |
| " self.dbz += dz\n", | |
| "\n", | |
| " dh_cand = dh * zs_g[t] * self._tanh_derivative(h_cands[t])\n", | |
| " self.dWh += np.dot(dh_cand, np.vstack((rs_g[t] * hs[t-1], xs[t])).T)\n", | |
| " self.dbh += dh_cand\n", | |
| "\n", | |
| " dr = np.dot(self.Wh[:, :self.H].T, dh_cand) * hs[t-1] * self._sigmoid_derivative(rs_g[t])\n", | |
| " self.dWr += np.dot(dr, concat_inputs[t].T)\n", | |
| " self.dbr += dr\n", | |
| "\n", | |
| " # Gradient for Previous Hidden State (dh_next) at time t-1\n", | |
| " # a. From Linear Combination: dh_next += dh * (1 - zs_g[t])\n", | |
| " d_from_linear = dh * (1 - zs_g[t])\n", | |
| " # b. From Candidate Memory: dh_next += (W_h[:, :H].T * dh_cand) * rs_g[t]\n", | |
| " d_from_cand = np.dot(self.Wh[:, :self.H].T, dh_cand) * rs_g[t]\n", | |
| " # c. From Update Gate: dh_next += np.dot(W_z[:, :H].T * dz)\n", | |
| " d_from_update = np.dot(self.Wz[:, :self.H].T, dz)\n", | |
| " # d. From Reset Gate: dh_next += np.dot(W_r[:, :H].T * dr)\n", | |
| " d_from_reset = np.dot(self.Wr[:, :self.H].T, dr)\n", | |
| "\n", | |
| " dh_next = d_from_linear + d_from_cand + d_from_update + d_from_reset\n", | |
| "\n", | |
| " # Gradient Clipping\n", | |
| " for grad in [self.dWr, self.dWz, self.dWh, self.dWy, self.dbr, self.dbz, self.dbh, self.dby]:\n", | |
| " np.clip(grad, -5, 5, out=grad)\n", | |
| "\n", | |
| " def update_parameters(self):\n", | |
| " self.Wr -= self.lr * self.dWr\n", | |
| " self.Wz -= self.lr * self.dWz\n", | |
| " self.Wh -= self.lr * self.dWh\n", | |
| " self.Wy -= self.lr * self.dWy\n", | |
| " self.br -= self.lr * self.dbr\n", | |
| " self.bz -= self.lr * self.dbz\n", | |
| " self.bh -= self.lr * self.dbh\n", | |
| " self.by -= self.lr * self.dby\n", | |
| "\n", | |
| " def sample(self, seed_idx, h_prev, length=20):\n", | |
| " x = np.zeros((self.V, 1))\n", | |
| " x[seed_idx] = 1\n", | |
| " indices = []\n", | |
| "\n", | |
| " for t in range(length):\n", | |
| " concat_input = np.vstack((h_prev, x))\n", | |
| "\n", | |
| " r = self._sigmoid(np.dot(self.Wr, concat_input) + self.br)\n", | |
| " z = self._sigmoid(np.dot(self.Wz, concat_input) + self.bz)\n", | |
| " h_cand = self._tanh(np.dot(self.Wh, np.vstack((r * h_prev, x))) + self.bh)\n", | |
| " h = (1 - z) * h_prev + z * h_cand\n", | |
| " y = self._softmax(np.dot(self.Wy, h) + self.by)\n", | |
| " idx = np.random.choice(range(self.V), p=y.ravel())\n", | |
| " indices.append(idx)\n", | |
| " x = np.zeros((self.V, 1))\n", | |
| " x[idx] = 1\n", | |
| " h_prev = h\n", | |
| " return indices\n" | |
| ], | |
| "metadata": { | |
| "id": "2c5tXzqu9xko" | |
| }, | |
| "execution_count": 2, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "# 1. prepare data\n", | |
| "data = \"helloahmed\"\n", | |
| "chars = list(set(data))\n", | |
| "vocab_size = len(chars)\n", | |
| "char_to_idx = { ch:i for i,ch in enumerate(chars)}\n", | |
| "idx_to_char = { i:ch for i,ch in enumerate(chars)}\n", | |
| "\n", | |
| "print(f\"Data: {data}\")\n", | |
| "print(f\"Vocabulary: {chars}\")\n", | |
| "print(f\"Vocab Size: {vocab_size}\")" | |
| ], | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "id": "RMdNRx2R91mH", | |
| "outputId": "1b8f8c91-74c9-45ef-fdcc-048d47a03380" | |
| }, | |
| "execution_count": 18, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "Data: helloahmed\n", | |
| "Vocabulary: ['h', 'e', 'o', 'd', 'l', 'a', 'm']\n", | |
| "Vocab Size: 7\n" | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "# 2. create model\n", | |
| "hidden_size = 25\n", | |
| "epochs = 3000\n", | |
| "learning_rate = 0.01\n", | |
| "\n", | |
| "gru = GRU(hidden_size, vocab_size, learning_rate)" | |
| ], | |
| "metadata": { | |
| "id": "yqGicNYX939O" | |
| }, | |
| "execution_count": 19, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "# 3. training loop\n", | |
| "print(\"Training GRU...\")\n", | |
| "costs = []\n", | |
| "\n", | |
| "inputs = [char_to_idx[ch] for ch in data[:-1]] # all chars except last\n", | |
| "targets = [char_to_idx[ch] for ch in data[1:]] # all chars except first\n", | |
| "\n", | |
| "for epoch in range(epochs):\n", | |
| " # We reset the memory at the start of each epoch\n", | |
| " h_prev = np.zeros((hidden_size, 1))\n", | |
| "\n", | |
| " # Forward pass\n", | |
| " y_preds, h_final, cache = gru.forward(inputs, h_prev)\n", | |
| "\n", | |
| " cost = gru.compute_cost(y_preds, targets)\n", | |
| "\n", | |
| " gru.backpropagation(targets, cache)\n", | |
| "\n", | |
| " gru.update_parameters()\n", | |
| "\n", | |
| " if epoch % 200 == 0:\n", | |
| " print(f\"Epoch {epoch}, Cost: {cost}\")\n", | |
| " costs.append(cost) # Append cost for plotting\n", | |
| "\n", | |
| "print(\"Training complete.\")" | |
| ], | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "id": "9TQ5BDfa95_C", | |
| "outputId": "3fb3042d-f031-4b8c-bb68-cf5726b514f9" | |
| }, | |
| "execution_count": 20, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "Training GRU...\n", | |
| "Epoch 0, Cost: 1.9459141102092898\n", | |
| "Epoch 200, Cost: 1.8820941376017426\n", | |
| "Epoch 400, Cost: 1.7173890355162649\n", | |
| "Epoch 600, Cost: 0.8028859557757452\n", | |
| "Epoch 800, Cost: 0.3321508924395241\n", | |
| "Epoch 1000, Cost: 0.1979177453568896\n", | |
| "Epoch 1200, Cost: 0.11995815684712927\n", | |
| "Epoch 1400, Cost: 0.18499005840229943\n", | |
| "Epoch 1600, Cost: 0.18629243670532064\n", | |
| "Epoch 1800, Cost: 0.17070964217578966\n", | |
| "Epoch 2000, Cost: 0.11924944862850778\n", | |
| "Epoch 2200, Cost: 0.0873657902096159\n", | |
| "Epoch 2400, Cost: 0.05842180501814652\n", | |
| "Epoch 2600, Cost: 0.04516581113149621\n", | |
| "Epoch 2800, Cost: 0.03725497325100427\n", | |
| "Training complete.\n" | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "plt.plot(np.squeeze(costs))\n", | |
| "plt.ylabel('Cost')\n", | |
| "plt.xlabel('Epochs (per 200)')\n", | |
| "plt.title(f\"Learning rate = {0.01}\")\n", | |
| "plt.show()" | |
| ], | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/", | |
| "height": 472 | |
| }, | |
| "id": "a3vEAjW699q3", | |
| "outputId": "2ddaa498-c8b3-4147-8bd1-fc04a024df10" | |
| }, | |
| "execution_count": 21, | |
| "outputs": [ | |
| { | |
| "output_type": "display_data", | |
| "data": { | |
| "text/plain": [ | |
| "<Figure size 640x480 with 1 Axes>" | |
| ], | |
| "image/png": "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IovERmgiImoOBiCySJwRmoiImoMBiCxSn3ZtAbARmoiImoYBiCxSN00bNkITEVGTMQCRRWIjNBERNQcDEFksNkITEVFTMQCRxWIjNBERNRUDEFksNkITEVFTMQCRxWIjNBERNRUDEFms6o3QJ3gbjIiIGoEBiCxa9RejEhERNRQDEFm04Ft9QGyEJiKixmAAIotW/QoQG6GJiKihGIDIorERmoiImoIBiCwaG6GJiKgpGIDI4rERmoiIGosBiCweG6GJiKixGIDI4rERmoiIGosBiCweG6GJiKixGIDI4rERmoiIGosBiFoFNkITEVFjMABRq8BGaCIiagwGIGoV2AhNRESN0aQA9Prrr6OoqKjG+uLiYrz++uvNLoqosdgITUREjdGkAPTaa6+hoKCgxvqioiK89tprzS6KqLHYCE1ERI3RpAAkhIBCoaix/tixY3B3d292UURNUdUHxABERER3YtuYwW5ublAoFFAoFOjWrZtBCNLpdCgoKMBTTz3V4kUSNURwOzW+BhuhiYjozhoVgJYsWQIhBJ544gm89tprUKvV0jZ7e3sEBAQgMjKyxYskaojbG6Fru0pJREQENDIATZ48GQAQGBiIgQMHwta2UbsTGdXtjdD+7k5yl0RERGaqST1ALi4uOH36tPR506ZNiImJwcsvv4yysrIWK46oMdgITUREDdWkAPS3v/0N586dAwD88ccfGD9+PJycnLB+/Xq88MILDT7O7t27MWrUKPj5+UGhUGDjxo133Gfnzp246667oFKp0KVLF6xevbrGmKVLlyIgIAAODg6IiIjAwYMHG1wTWTY2QhMRUUM0KQCdO3cOoaGhAID169fj3nvvxZo1a7B69Wp89913DT5OYWEhQkJCsHTp0gaNT01NxciRIzFkyBAkJydj7ty5ePLJJ/G///1PGrNu3TrExcVh4cKFSEpKQkhICKKjo5GVldWocyTLVNUHxEZoIiKqT5OaeIQQ0Ov1AIDt27fjwQcfBAD4+/vj+vXrDT7OiBEjMGLEiAaPX758OQIDA7F48WIAQI8ePbB37168//77iI6OBgC89957mD59OqZOnSrt89NPP2HVqlV46aWXGvyzyDKxEZqIiBqiSVeAwsPD8eabb+K///0vdu3ahZEjRwKovELj4+PTogVWl5iYiKioKIN10dHRSExMBACUlZXhyJEjBmNs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\n" | |
| }, | |
| "metadata": {} | |
| } | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "# Test the model (sampling)\n", | |
| "print(\"\\nSampling from the model:\")\n", | |
| "# Get the index for our seed character 'h'\n", | |
| "seed_char_idx = char_to_idx['h']\n", | |
| "\n", | |
| "h_sample = np.zeros((hidden_size, 1))\n", | |
| "\n", | |
| "generated_indices = gru.sample(seed_char_idx, h_sample, length=10)\n", | |
| "generated_text = 'h' + ''.join(idx_to_char[idx] for idx in generated_indices)\n", | |
| "\n", | |
| "print(f\"Generated text: '{generated_text}'\")\n", | |
| "\n" | |
| ], | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "id": "-3i1shi_9__H", | |
| "outputId": "ae0c28bc-ecfc-45bd-93cd-2ff48b785b5d" | |
| }, | |
| "execution_count": 22, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "\n", | |
| "Sampling from the model:\n", | |
| "Generated text: 'helloahmedd'\n" | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [], | |
| "metadata": { | |
| "id": "nmu8yfiu-Ul5" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| } | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment