From 4b2de42b8225e68040b1bcf23a5b4bd86f4b8662 Mon Sep 17 00:00:00 2001 From: Paul Aumann Date: Mon, 5 Jun 2023 08:35:46 +0200 Subject: [PATCH] Few more fixes --- Aufgabe 3/aufgabe03.ipynb | 230 ++++++++++++++++++++++++++++++-------- 1 file changed, 185 insertions(+), 45 deletions(-) mode change 100644 => 100755 Aufgabe 3/aufgabe03.ipynb diff --git a/Aufgabe 3/aufgabe03.ipynb b/Aufgabe 3/aufgabe03.ipynb old mode 100644 new mode 100755 index 76992fd..1b172b6 --- a/Aufgabe 3/aufgabe03.ipynb +++ b/Aufgabe 3/aufgabe03.ipynb @@ -2,18 +2,19 @@ "cells": [ { "cell_type": "code", - "execution_count": 89, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", + "from tqdm import tqdm\n", "\n", "rng = np.random.default_rng()" ] }, { "cell_type": "code", - "execution_count": 253, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -23,9 +24,10 @@ "\n", "sigmoid = np.vectorize(lambda x : 1 / (1 + np.exp(-x)))\n", "\n", - "inputs = [rng.integers(0, 1, size=(2,1), endpoint=True) for _ in range(10_000)]\n", - "outputs = [a[0] ^ b[0] for a, b in inputs]\n", - "data = list(zip(inputs, outputs))\n", + "def samples(n: int) -> list:\n", + " inputs = [rng.integers(0, 1, size=2, endpoint=True) for _ in range(n)]\n", + " outputs = [a ^ b for a, b in inputs]\n", + " return list(zip(inputs, outputs))\n", "\n", "# Aufgabe 3\n", "\n", @@ -42,7 +44,7 @@ }, { "cell_type": "code", - "execution_count": 287, + "execution_count": 168, "metadata": {}, "outputs": [], "source": [ @@ -51,7 +53,9 @@ "\n", "\n", "class NeuralNet:\n", - " def __init__(self, inputs: int = 2, hidden_layers: list[tuple[int, Callable]] = None):\n", + " def __init__(\n", + " self, inputs: int = 2, hidden_layers: list[tuple[int, Callable]] = None\n", + " ):\n", " \"\"\"\n", " Initializes the neural network.\n", " Hidden layers can be specified with the 'hidden_layers' parameter,\n", @@ -71,7 +75,9 @@ " self.activation_functions.append(activation_function)\n", "\n", " num_layer_inputs = inputs if index == 0 else self.layers[index - 1][0]\n", - " self.weights.append(rng.uniform(low=-1.0, high=1.0, size=(num_neurons, num_layer_inputs)))\n", + " self.weights.append(\n", + " rng.uniform(low=-1.0, high=1.0, size=(num_neurons, num_layer_inputs))\n", + " )\n", "\n", " def forward_pass(self, x: np.array) -> tuple:\n", " \"\"\"\n", @@ -80,27 +86,27 @@ " For the final output, see the last input in the F list.\n", " \"\"\"\n", "\n", - " x = np.array(x)\n", - " if x.shape != self.input_shape:\n", - " raise ValueError(f\"Input must be of shape {self.input_shape}.\")\n", + " x = np.reshape(x, self.input_shape)\n", "\n", " Z = [] # linear values for each layer\n", " F = [x] # activation function values for each layer\n", - " for weights, activation_function in zip(self.weights, self.activation_functions):\n", + " for weights, activation_function in zip(\n", + " self.weights, self.activation_functions\n", + " ):\n", " Z.append(np.matmul(weights, F[-1])) # linear\n", " F.append(activation_function(Z[-1]))\n", "\n", " return (Z, F)\n", "\n", - " def classify(self, x) -> bool:\n", + " def classify(self, x) -> float:\n", " \"\"\"\n", - " Executes a forward pass, and returns True if the resulting\n", - " value is greater than 0.5.\n", + " Executes a forward pass, and returns the\n", + " classification result ŷ.\n", " \"\"\"\n", "\n", " _, F = self.forward_pass(x)\n", - " ŷ = F[-1][0]\n", - " return ŷ > 0.5\n", + " ŷ = F[-1][0][0]\n", + " return ŷ\n", "\n", " # Aufgabe 4\n", " def backward_pass(self, x, y: float):\n", @@ -117,25 +123,57 @@ " # Backpropagation\n", " for i in reversed(range(len(self.layers) - 1)):\n", " layer_errors[i] = np.multiply(\n", - " self.weights[i + 1], layer_errors[i + 1] * derivatives[self.activation_functions[i]](Z[i].T)\n", + " np.dot(self.weights[i + 1].T, layer_errors[i + 1]),\n", + " derivatives[self.activation_functions[i]](Z[i]),\n", " )\n", "\n", - " Δweights = [np.multiply(error, F[i]).T for i, error in enumerate(layer_errors)]\n", + " Δweights = [np.dot(error, F[i].T) for i, error in enumerate(layer_errors)]\n", " return Δweights\n", "\n", " # Aufgabe 5\n", - " def train(self, data, learning_rate: float = 0.5):\n", + " def train(self, data: list, batch_size: int = 10, epochs: int = 50, learning_rate: float = 0.5):\n", " \"\"\"\n", " Train the neural network with the given input data.\n", " \"\"\"\n", - " for test_input, expected in data:\n", - " Δweights = self.backward_pass(test_input, expected)\n", - " self.weights = [w - learning_rate * Δw for w, Δw in zip(self.weights, Δweights, strict=True)]" + " from IPython import display\n", + " import matplotlib.pyplot as plt\n", + " hdisplay = display.display(\"\", display_id=True)\n", + " fig, ax = plt.subplots()\n", + "\n", + " losses = []\n", + " for epoch in tqdm(range(epochs)):\n", + " for i in range(0, len(data), batch_size):\n", + " batch = data[i : i + batch_size]\n", + " for x, y in batch:\n", + " Δweights = self.backward_pass(x, y)\n", + " self.weights = [\n", + " w - learning_rate * (Δw / float(batch_size))\n", + " for w, Δw in zip(self.weights, Δweights, strict=True)\n", + " ]\n", + "\n", + " L = bcel(y, self.classify(x))\n", + " losses.append(L)\n", + "\n", + " pic = []\n", + " for px in np.linspace(-1, 1, 30):\n", + " col = []\n", + " for py in np.linspace(-1, 1, 30):\n", + " col.append(self.classify((px, py)))\n", + " pic.append(col)\n", + " pic = np.array(pic)\n", + "\n", + " import matplotlib.pyplot as plt\n", + "\n", + " if epoch % 5 == 0:\n", + " ax.imshow(pic, cmap=\"hot\", interpolation=\"nearest\", extent=(-1, 1, 1, -1))\n", + " hdisplay.update(fig)\n", + "\n", + " return losses\n" ] }, { "cell_type": "code", - "execution_count": 286, + "execution_count": 155, "metadata": {}, "outputs": [], "source": [ @@ -174,40 +212,142 @@ }, { "cell_type": "code", - "execution_count": 257, + "execution_count": 173, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Before training: correct=761\n", - "After training: correct=1000\n" + "Correct classifications before training: 0.526\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 80/80 [00:07<00:00, 11.31it/s]\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Correct classifications after training: 0.769\n" ] } ], "source": [ - "nn = NeuralNet(hidden_layers=[(3, relu)])\n", + "# Aufgabe 4\n", "\n", - "correct = 0\n", - "for i in range(1000):\n", - " x = rng.integers(0, 1, size=(2,1), endpoint=True)\n", - " y = (x[0] ^ x[1])[0]\n", - " c = nn.classify(x)\n", - " if (c and y == 1) or (not c and y == 0):\n", - " correct += 1\n", - "print(f\"Before training: {correct=}\")\n", + "test_data = samples(1_000)\n", + "training_data = samples(100)\n", "\n", - "nn.train(data)\n", + "# Updating weights after every backward pass\n", + "nn = NeuralNet(hidden_layers=[(4, relu)])\n", "\n", - "correct = 0\n", - "for i in range(1000):\n", - " x = rng.integers(0, 1, size=(2,1), endpoint=True)\n", - " y = (x[0] ^ x[1])[0]\n", - " c = nn.classify(x)\n", - " if (c and y == 1) or (not c and y == 0):\n", - " correct += 1\n", - "print(f\"After training: {correct=}\")" + "correct = sum([round(nn.classify(x)) == y for x, y in test_data])\n", + "print(f\"Correct classifications before training: {correct/len(test_data)}\")\n", + "\n", + "l = nn.train(training_data, batch_size=10, learning_rate=1, epochs=80)\n", + "\n", + "plt.figure(figsize=(10,6))\n", + "plt.scatter(range(80), l)\n", + "plt.show()\n", + "\n", + "correct = sum([round(nn.classify(x)) == y for x, y in test_data])\n", + "print(f\"Correct classifications after training: {correct/len(test_data)}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "execution_count": 84, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Visualize learned separation\n", + "\n", + "def visualize(nn: NeuralNet):\n", + " # left, right, bottom, top \n", + " dim = (-1, 1, -1, 1)\n", + " resolution = 50\n", + "\n", + " data = []\n", + " for px in np.linspace(dim[1], dim[0], resolution):\n", + " col = []\n", + " for py in np.linspace(dim[2], dim[3], resolution):\n", + " col.append(nn.classify((px, py)))\n", + " data.append(col)\n", + " data = np.array(data)\n", + "\n", + " import matplotlib.pyplot as plt\n", + "\n", + " _, ax = plt.subplots()\n", + " ax.imshow(data, cmap=\"hot\", interpolation=\"nearest\", extent=dim)\n", + " ax.spines[\"left\"].set_position(\"center\")\n", + " ax.spines[\"bottom\"].set_position(\"center\")\n", + " ax.spines[\"right\"].set_color(\"none\")\n", + " ax.spines[\"top\"].set_color(\"none\")\n", + "\n", + "visualize(nn)\n" ] } ],