Created
November 18, 2025 00:09
-
-
Save AhmedCoolProjects/a0fc5bc563c2ca38dc5437c3e6a27932 to your computer and use it in GitHub Desktop.
LSTM 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": "ABX9TyMqNwi7Ib84ZzLhFju2We1M", | |
| "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/a0fc5bc563c2ca38dc5437c3e6a27932/lstm-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": "2X8dfAMXRS-N" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "import numpy as np\n", | |
| "import matplotlib.pyplot as plt" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "class LSTM:\n", | |
| " def __init__(self, hidden_size, vocab_size):\n", | |
| " self.H = hidden_size\n", | |
| " self.V = vocab_size\n", | |
| "\n", | |
| " # Initialize weights (4 sets)\n", | |
| " # f: Forget, i: Input, c: Candidate, o: Output\n", | |
| " self._W_size = (self.H, self.H + self.V) # weights shape for all gates\n", | |
| " # Forget Gate\n", | |
| " self.Wf = np.random.randn(*self._W_size) * 0.01\n", | |
| " self.bf = np.zeros((self.H, 1))\n", | |
| "\n", | |
| " # Input Gate\n", | |
| " self.Wi = np.random.randn(*self._W_size) * 0.01\n", | |
| " self.bi = np.zeros((self.H, 1))\n", | |
| "\n", | |
| " # Candidate Layer\n", | |
| " self.Wc = np.random.randn(*self._W_size) * 0.01\n", | |
| " self.bc = np.zeros((self.H, 1))\n", | |
| "\n", | |
| " # Output Gate\n", | |
| " self.Wo = np.random.randn(*self._W_size) * 0.01\n", | |
| " self.bo = np.zeros((self.H, 1))\n", | |
| "\n", | |
| " # Final Output Layer\n", | |
| " self.Why = np.random.randn(self.V, self.H) * 0.01\n", | |
| " self.by = np.zeros((self.V, 1))\n", | |
| "\n", | |
| " def _sigmoid(self, z):\n", | |
| " return 1 / (1 + np.exp(-z))\n", | |
| "\n", | |
| " def _tanh(self, z):\n", | |
| " return np.tanh(z)\n", | |
| "\n", | |
| " def _softmax(self, z):\n", | |
| " e_z = np.exp(z - np.max(z))\n", | |
| " return e_z / np.sum(e_z, axis=0)\n", | |
| "\n", | |
| " def forward(self, inputs, h_prev, c_prev):\n", | |
| " '''\n", | |
| " inputs: list of input indices\n", | |
| " h_prev: previous hidden state (H x 1)\n", | |
| " c_prev: previous cell state (H x 1)\n", | |
| " '''\n", | |
| "\n", | |
| " xs, hs, cs, zs, ys = {}, {}, {}, {}, {} # store values for each time step\n", | |
| " fs, is_, cs_tilde, os = {}, {}, {}, {} # gate activations\n", | |
| " concat_inputs = {}\n", | |
| "\n", | |
| " hs[-1] = np.copy(h_prev)\n", | |
| " cs[-1] = np.copy(c_prev)\n", | |
| "\n", | |
| " total_cost = 0\n", | |
| "\n", | |
| " for t in range(len(inputs)):\n", | |
| " # 1. One-hot encode the input character\n", | |
| " xs[t] = np.zeros((self.V, 1))\n", | |
| " xs[t][inputs[t]] = 1\n", | |
| "\n", | |
| " # 2. Concatenate h_prev and x_t\n", | |
| " concat_inputs[t] = np.vstack((hs[t-1], xs[t])) # (H + V) x 1\n", | |
| "\n", | |
| " # 3. Forget Gate\n", | |
| " fs[t] = self._sigmoid(np.dot(self.Wf, concat_inputs[t]) + self.bf)\n", | |
| "\n", | |
| " # 4. Input Gate\n", | |
| " is_[t] = self._sigmoid(np.dot(self.Wi, concat_inputs[t]) + self.bi)\n", | |
| "\n", | |
| " # 5. Candidate Layer\n", | |
| " cs_tilde[t] = self._tanh(np.dot(self.Wc, concat_inputs[t]) + self.bc)\n", | |
| "\n", | |
| " # 6. Output Gate\n", | |
| " os[t] = self._sigmoid(np.dot(self.Wo, concat_inputs[t]) + self.bo)\n", | |
| "\n", | |
| " # 7. Update Cell State\n", | |
| " cs[t] = fs[t] * cs[t-1] + is_[t] * cs_tilde[t] # (H x 1)\n", | |
| "\n", | |
| " # 8. Compute Hidden State\n", | |
| " hs[t] = os[t] * self._tanh(cs[t]) # (H x 1)\n", | |
| "\n", | |
| " # 9. Compute Output\n", | |
| " zs[t] = np.dot(self.Why, hs[t]) + self.by\n", | |
| " ys[t] = self._softmax(zs[t]) # (V x 1)\n", | |
| "\n", | |
| " cache = (xs, hs, cs, fs, is_, cs_tilde, os, zs, ys, concat_inputs)\n", | |
| "\n", | |
| " return ys, hs[len(inputs)-1], cs[len(inputs)-1], cache\n", | |
| "\n", | |
| " def compute_cost(self, y_preds, targets):\n", | |
| " total_cost = 0\n", | |
| " for t in range(len(targets)):\n", | |
| " prob_of_target = y_preds[t][targets[t], 0] # [target_index, 0] gives the prob of that target and the 0 is to get the scalar from the (1,1) array\n", | |
| " total_cost += -np.log(prob_of_target + 1e-9) # add small value to avoid log(0)\n", | |
| " return total_cost / len(targets)\n", | |
| "\n", | |
| " def backpropagation(self, targets, cache):\n", | |
| " xs, hs, cs, fs, is_, cs_tilde, os, zs, ys, concat_inputs = cache\n", | |
| " # Initialize gradients\n", | |
| " self.dWf = np.zeros_like(self.Wf)\n", | |
| " self.dbf = np.zeros_like(self.bf)\n", | |
| " self.dWi = np.zeros_like(self.Wi)\n", | |
| " self.dbi = np.zeros_like(self.bi)\n", | |
| " self.dWc = np.zeros_like(self.Wc)\n", | |
| " self.dbc = np.zeros_like(self.bc)\n", | |
| " self.dWo = np.zeros_like(self.Wo)\n", | |
| " self.dbo = np.zeros_like(self.bo)\n", | |
| " self.dWhy = np.zeros_like(self.Why)\n", | |
| " self.dby = np.zeros_like(self.by)\n", | |
| "\n", | |
| " dh_next = np.zeros_like(hs[0])\n", | |
| " dc_next = np.zeros_like(cs[0])\n", | |
| "\n", | |
| " for t in reversed(range(len(targets))):\n", | |
| " # 1. Output layer\n", | |
| " dy = np.copy(ys[t])\n", | |
| " dy[targets[t]] -= 1 # y_pred - y_true\n", | |
| " self.dWhy += np.dot(dy, hs[t].T)\n", | |
| " self.dby += dy\n", | |
| "\n", | |
| " # 2. Gradient for hidden state dh_t\n", | |
| " dh = np.dot(self.Why.T, dy) + dh_next\n", | |
| "\n", | |
| " # 3. Gradient for output gate\n", | |
| " do = dh * self._tanh(cs[t]) * os[t] * (1 - os[t])\n", | |
| " self.dWo += np.dot(do, concat_inputs[t].T)\n", | |
| " self.dbo += do\n", | |
| "\n", | |
| " # 4. Gradient for cell state\n", | |
| " dc = dh * os[t] * (1 - self._tanh(cs[t])**2) + dc_next\n", | |
| "\n", | |
| " # 5. Gradient for forget gate\n", | |
| " df = dc * cs[t-1] * fs[t] * (1 - fs[t])\n", | |
| " self.dWf += np.dot(df, concat_inputs[t].T)\n", | |
| " self.dbf += df\n", | |
| "\n", | |
| " # 6. Gradient for input gate\n", | |
| " di = dc * cs_tilde[t] * is_[t] * (1 - is_[t])\n", | |
| " self.dWi += np.dot(di, concat_inputs[t].T)\n", | |
| " self.dbi += di\n", | |
| "\n", | |
| " # 7. Gradient for candidate layer\n", | |
| " dc_tilde = dc * is_[t] * (1 - cs_tilde[t]**2)\n", | |
| " self.dWc += np.dot(dc_tilde, concat_inputs[t].T)\n", | |
| " self.dbc += dc_tilde\n", | |
| "\n", | |
| " # 8. Gradient for concatenated input\n", | |
| " dconcat = (np.dot(self.Wf.T, df) +\n", | |
| " np.dot(self.Wi.T, di) +\n", | |
| " np.dot(self.Wc.T, dc_tilde) +\n", | |
| " np.dot(self.Wo.T, do))\n", | |
| " dh_next = dconcat[:self.H, :] # Gradient for h_(t-1)\n", | |
| " dc_next = dc * fs[t] # Gradient for C_(t-1)\n", | |
| "\n", | |
| " # Gradient clipping to prevent exploding gradients\n", | |
| " for grad in [self.dWf, self.dbf, self.dWi, self.dbi,\n", | |
| " self.dWc, self.dbc, self.dWo, self.dbo,\n", | |
| " self.dWhy, self.dby]:\n", | |
| " np.clip(grad, -5, 5, out=grad)\n", | |
| "\n", | |
| " def update_parameters(self, learning_rate=0.01):\n", | |
| " self.Wf -= learning_rate * self.dWf\n", | |
| " self.bf -= learning_rate * self.dbf\n", | |
| " self.Wi -= learning_rate * self.dWi\n", | |
| " self.bi -= learning_rate * self.dbi\n", | |
| " self.Wc -= learning_rate * self.dWc\n", | |
| " self.bc -= learning_rate * self.dbc\n", | |
| " self.Wo -= learning_rate * self.dWo\n", | |
| " self.bo -= learning_rate * self.dbo\n", | |
| " self.Why -= learning_rate * self.dWhy\n", | |
| " self.by -= learning_rate * self.dby\n", | |
| "\n", | |
| " def sample(self, seed_idx, h_prev, c_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", | |
| " # Gates\n", | |
| " f = self._sigmoid(np.dot(self.Wf, concat_input) + self.bf)\n", | |
| " i = self._sigmoid(np.dot(self.Wi, concat_input) + self.bi)\n", | |
| " c_tilde = self._tanh(np.dot(self.Wc, concat_input) + self.bc)\n", | |
| " o = self._sigmoid(np.dot(self.Wo, concat_input) + self.bo)\n", | |
| "\n", | |
| " # Update cell state\n", | |
| " c = f * c_prev + i * c_tilde\n", | |
| "\n", | |
| " # Compute hidden state\n", | |
| " h = o * self._tanh(c)\n", | |
| "\n", | |
| " z = np.dot(self.Why, h) + self.by\n", | |
| " y = self._softmax(z)\n", | |
| "\n", | |
| " # Sample from the probability distribution\n", | |
| " idx = np.random.choice(range(self.V), p=y.ravel()) # this gives us a scalar index meaning the index of the predicted character. the .ravel() is to convert the (V,1) shape to (V,) shape which is required by np.random.choice, this .choice samples according to the probabilities in y\n", | |
| " x = np.zeros((self.V, 1))\n", | |
| " x[idx] = 1\n", | |
| " indices.append(idx)\n", | |
| " h_prev = h\n", | |
| " c_prev = c\n", | |
| "\n", | |
| " return indices" | |
| ], | |
| "metadata": { | |
| "id": "KUqVTeIUR1Hr" | |
| }, | |
| "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": "W1FFDodJR351", | |
| "outputId": "a65af114-3d62-47a1-ccd8-20234e1bb656" | |
| }, | |
| "execution_count": 3, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "Data: helloahmed\n", | |
| "Vocabulary: ['l', 'a', 'e', 'd', 'o', 'h', 'm']\n", | |
| "Vocab Size: 7\n" | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "# 2. create model\n", | |
| "hidden_size = 25\n", | |
| "epochs = 3000\n", | |
| "\n", | |
| "lstm = LSTM(hidden_size, vocab_size)" | |
| ], | |
| "metadata": { | |
| "id": "3WtLKbh8R8GZ" | |
| }, | |
| "execution_count": 5, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "# 3. training loop\n", | |
| "print(\"Training LSTM...\")\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", | |
| " c_prev = np.zeros((hidden_size, 1))\n", | |
| "\n", | |
| " # Forward pass\n", | |
| " y_preds, h_final, c_final, cache = lstm.forward(inputs, h_prev, c_prev)\n", | |
| "\n", | |
| " cost = lstm.compute_cost(y_preds, targets)\n", | |
| "\n", | |
| " lstm.backpropagation(targets, cache)\n", | |
| "\n", | |
| " lstm.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": "U3DNz_TtSEBF", | |
| "outputId": "21f2a66f-3142-466b-cd74-864fc3b99e0d" | |
| }, | |
| "execution_count": 7, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "Training LSTM...\n", | |
| "Epoch 0, Cost: 1.9459308553119037\n", | |
| "Epoch 200, Cost: 1.888694596930537\n", | |
| "Epoch 400, Cost: 1.885747141311822\n", | |
| "Epoch 600, Cost: 1.869165401158513\n", | |
| "Epoch 800, Cost: 1.7772037343293763\n", | |
| "Epoch 1000, Cost: 1.4138688219022517\n", | |
| "Epoch 1200, Cost: 0.7320503793476106\n", | |
| "Epoch 1400, Cost: 0.3883764333872252\n", | |
| "Epoch 1600, Cost: 0.21691620735344425\n", | |
| "Epoch 1800, Cost: 0.12986328517492585\n", | |
| "Epoch 2000, Cost: 0.08541260344701034\n", | |
| "Epoch 2200, Cost: 0.06066953628544073\n", | |
| "Epoch 2400, Cost: 0.04568582684125432\n", | |
| "Epoch 2600, Cost: 0.035955796413271686\n", | |
| "Epoch 2800, Cost: 0.029270449962368588\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": "hiBCQMBKSQ0I", | |
| "outputId": "78d5db12-5c69-4884-bc82-25d38017481f" | |
| }, | |
| "execution_count": 9, | |
| "outputs": [ | |
| { | |
| "output_type": "display_data", | |
| "data": { | |
| "text/plain": [ | |
| "<Figure size 640x480 with 1 Axes>" | |
| ], | |
| "image/png": "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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", | |
| "c_sample = np.zeros((hidden_size, 1))\n", | |
| "\n", | |
| "generated_indices = lstm.sample(seed_char_idx, h_sample, c_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}'\")" | |
| ], | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "id": "44jjYmw5Snwz", | |
| "outputId": "d9cecd0a-3012-4bae-8e35-6665dd112154" | |
| }, | |
| "execution_count": 10, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "\n", | |
| "Sampling from the model:\n", | |
| "Generated text: 'helloahmedl'\n" | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [], | |
| "metadata": { | |
| "id": "qgZo2hekSxAH" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| } | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment