{ "cells": [ { "cell_type": "markdown", "id": "crucial-desert", "metadata": { "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "# The Hopfield Network" ] }, { "cell_type": "markdown", "id": "expanded-specification", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "The Hopfield network is an artificial neural network that stores a set of patterns as attractors of its dynamics. The state of the network is represented by a vector $S_i$ for $i = 1, \\cdots, N$, where $N$ is the number of nodes in the network. We will consider nodes that can only take discrete values $\\pm 1$. The dynamics of the network is described by the update rule:\n", "\\begin{equation}\n", "S_i (t+1) = \\operatorname{sgn} \\Big( \\sum_j J_{ij} S_j (t) \\Big)\n", "\\end{equation}\n", "Here the matrix $J_{ij}$ represents the connections between the nodes.\n", "\n", "There are two ways to implement the update of all nodes. One way is to update all nodes together at the same time, which is called a \"synchronous\" update. The other way is to update the nodes one at a time, which is called \"asynchronous\". These are not equivalent because in the synchronous update, the new value of each node depends on the old values of all nodes, whereas in the asynchronous update, even if we sweep over all nodes in each round of updates, the new value of a node will depend on the new values of the nodes that have already been updated in the same round (and the old values of those not yet updated). The latter scheme may be considered more realistic biologically. In order to avoid bias, we will choose a random order to update the nodes, which introduces some stochasticity in the dynamics." ] }, { "cell_type": "markdown", "id": "0d431e68-a89b-42de-a7a0-baa60fb5d76f", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "A pattern is a state of the network where each node takes a specific value $\\xi_i = \\pm 1$. For a given pattern $\\xi_i$ to be stored in the network, it has to be a stable steady state of the dynamics. In that case, if we initialize the network at a state close to the pattern (a \"seed\" state), the network will follow its dynamics and converge to the steady state, thus retrieving the stored pattern. Hopfield found a simple form of $J_{ij}$ that allows the network to store multiple patterns, $\\xi_i^\\mu$ for $\\mu = 1, \\cdots, M$ (think of each $\\xi^\\mu$ as a vector with components $\\xi_i^\\mu$). That is,\n", "\\begin{equation}\n", "J_{ij} = \\frac{1}{N} \\sum_{\\mu=1}^{M} \\xi^\\mu_i \\xi^\\mu_j\n", "\\end{equation}\n", "With this connection matrix, each pattern $\\xi^\\mu$ is a locally stable steady state. Therefore, if we provide a seed to the network that is close to one of the patterns, the network will automatically retrieve the correct full pattern." ] }, { "cell_type": "markdown", "id": "former-brush", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Let us implement the Hopfield network as follows. First, we will write a base class to represent a general network with an arbitrary connection matrix, the dynamics of which is given by the update rule above. Such a network in which every node can be connected to all other nodes is called \"recurrent\" (more precisely, a recurrent network has a connnectivity graph that has cycles)." ] }, { "cell_type": "code", "execution_count": 1, "id": "capable-frequency", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 2, "id": "forbidden-journey", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [], "source": [ "class RecurrentNetwork:\n", " \"\"\"\n", " base class of neural network with recurrent connection matrix\n", " \"\"\"\n", "\n", " def __init__(self, N, sync=False):\n", " \"\"\"\n", " declare internal variables.\n", " inputs:\n", " N: int, number of neurons forming the network.\n", " init: 1-d array, initial state of the network.\n", " sync: bool, whether to update synchronously.\n", " \"\"\"\n", " self.N = int(N) # number of neurons\n", " self.state = np.zeros(self.N, dtype=int) # state of neurons, S_i\n", " self.connect = np.zeros((self.N,self.N)) # connection matrix, J_{ij}\n", " self.sync = sync\n", "\n", " def set_network(self, state=None, connect=None):\n", " \"\"\"\n", " set state and connection of the network.\n", " inputs:\n", " state: 1-d array, state of neurons to be set.\n", " connect: 2-d array, connection matrix to be set.\n", " \"\"\"\n", " if state is not None:\n", " self.state = np.asarray(state, dtype=int)\n", " if connect is not None:\n", " self.connect = np.asarray(connect, dtype=float)\n", "\n", " def update1(self, i):\n", " \"\"\"\n", " update one neuron of given index, as well as its effect on others.\n", " inputs:\n", " i: int, index of neuron to be updated.\n", " outputs:\n", " b: bool, whether the state of given neuron is changed.\n", " \"\"\"\n", " s = np.sign(self.input[i]).astype(int)\n", " if s != self.state[i]:\n", " self.state[i] = s\n", " self.input += 2*s*self.connect[:,i]\n", " return True\n", " else:\n", " return False\n", "\n", " def updateN(self, size=None, replace=True):\n", " \"\"\"\n", " update many neurons in random sequential order.\n", " inputs:\n", " size: number of neurons to update in a sweep, default is `self.N`.\n", " replace: whether to sample neurons with replacement.\n", " outputs:\n", " flip_any: bool, whether the state of any neuron is changed.\n", " \"\"\"\n", " if size is None:\n", " size = self.N\n", " seq = np.random.choice(np.arange(self.N), size=size, replace=replace)\n", " self.input = np.dot(self.connect, self.state)\n", " flip_any = False\n", " if self.sync: # update synchronously\n", " new_state = self.act(self.input[seq]).astype(int)\n", " flip_any = np.any(new_state != self.state[seq])\n", " self.state[seq] = new_state\n", " else: # update asynchronously\n", " for i in seq:\n", " flip = self.update1(i)\n", " flip_any = (flip_any or flip)\n", " return flip_any" ] }, { "cell_type": "markdown", "id": "approved-enclosure", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Then we will define a derived class to implement the Hopfield model by specifying the connection matrix. We will also define a method `Hopfield.overlap()` that calculates the overlap between the state of the network and given patterns." ] }, { "cell_type": "code", "execution_count": 3, "id": "operating-croatia", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [], "source": [ "class Hopfield(RecurrentNetwork):\n", " \"\"\"\n", " Hopfield network that stores patterns as attractors.\n", " \"\"\"\n", "\n", " def __init__(self, patterns, **kwargs):\n", " \"\"\"\n", " create Hopfield network from a set of patterns to be stored.\n", " inputs:\n", " patterns: 2-d array, each row is a pattern.\n", " \"\"\"\n", " N = np.shape(patterns)[1] # size of network\n", " RecurrentNetwork.__init__(self, N, **kwargs)\n", " self.p = 0 # number of stored patterns\n", " self.patterns = np.zeros((0,N)) # stored patterns, xi_i^mu\n", " self.store(patterns)\n", "\n", " def store(self, new_patterns):\n", " \"\"\"\n", " store new patterns into the connection matrix.\n", " inputs:\n", " new_patterns: 2-d array, each row is a new pattern.\n", " outputs:\n", " sym: 2-d array, updated symmetric connection matrix.\n", " \"\"\"\n", " new_patterns = np.reshape(new_patterns, (-1,self.N)).astype(float)\n", " self.p += new_patterns.shape[0]\n", " self.patterns = np.vstack([self.patterns, new_patterns])\n", " self.connect += np.dot(new_patterns.T, new_patterns) / self.N\n", " return self.connect\n", "\n", " def overlap(self, mu=None):\n", " \"\"\"\n", " calculate overlap between network state and each pattern.\n", " inputs:\n", " mu: int or 1-d array, index of pattern(s), if None, calculate for all.\n", " outputs:\n", " m_mu: real or 1-d array, overlap for given pattern(s).\n", " \"\"\"\n", " if mu is None:\n", " mu = np.arange(self.p)\n", " m_mu = np.dot(self.state, self.patterns[mu].T) / self.N\n", " return m_mu" ] }, { "cell_type": "markdown", "id": "brief-service", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Let us test the Hopfield network's ability to retrieve stored patterns. First, let us select some patterns for the network to store. To better visualize the process, we will use images as our patterns. These will be black and white images, such that each pixel takes a value 0 (black) or 1 (white). Each pixel corresponds to one node in the network. Let us load some images." ] }, { "cell_type": "code", "execution_count": 4, "id": "treated-paste", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "img1 = plt.imread('source/AlbertGator.png')\n", "img2 = plt.imread('source/AlbertEinstein.png')\n", "img_list = [img1, img2]\n", "M = len(img_list)\n", "\n", "fig, ax = plt.subplots(1,M, figsize=(2*M,2))\n", "for m in range(M):\n", " ax[m].imshow(img_list[m], cmap='Greys_r') # pixel values: 0 = black, 1 = white\n", " ax[m].axis('off')\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "surprised-battery", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "We have to convert the 2D images to 1D vectors, which will be the patterns to be stored. This is done simply by flattening the array. We also have to convert the raw values 0 and 1 to the values of the nodes 1 or -1." ] }, { "cell_type": "code", "execution_count": 5, "id": "6d8cbb52-ddeb-4df6-a022-c62adff466a9", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "def img2vec(img):\n", " \"\"\"\n", " convert a 2D black & white image to a 1D vector of +/-1.\n", " input:\n", " img: 2d-array of binary numbers (0 for black and 1 for white);\n", " some grayscale images have an extra dimension which is redundant and will be removed.\n", " output:\n", " vec: 1d-array of +/-1 values.\n", " \"\"\"\n", " if img.ndim > 2: # grayscale image with redundant dimension\n", " img = img[:,:,0] # remove redundant dimension\n", " vec = np.reshape(img, -1) # flatten array\n", " vec = 1-2*vec # convert from 0/1 to +/-1\n", " return vec\n", "\n", "def vec2img(vec, shape):\n", " \"\"\"\n", " convert a 1D vector of +/-1 to a 2D black & white image.\n", " input:\n", " vec: 1d-array of +/-1 values.\n", " shape: 2-tuple, shape of the 2d-array.\n", " output:\n", " img: 2d-array of binary numbers (0 for black and 1 for white).\n", " \"\"\"\n", " vec = (1-vec)/2\n", " img = np.reshape(vec, shape)\n", " return img" ] }, { "cell_type": "markdown", "id": "a090ad5f-db3c-4533-bdcd-35763c364dce", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "When we have converted the images to patterns, we will put them in a 2D array, where each row is a pattern. Then we can create the Hopfield network using these patterns." ] }, { "cell_type": "code", "execution_count": 6, "id": "essential-thomas", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "shape = img1.shape # shape of image (shape of 2d-array)\n", "N = np.prod(shape) # size of network (length of 1d-vector)\n", "\n", "patterns = []\n", "for img in img_list:\n", " vec = img2vec(img) # convert image to vector\n", " patterns.append(vec) # add vector as pattern\n", "\n", "net = Hopfield(patterns) # create Hopfield network" ] }, { "cell_type": "markdown", "id": "instrumental-relief", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "To retrieve a pattern, let us provide a seed, which can be a small section of the image we want to retrieve." ] }, { "cell_type": "code", "execution_count": 7, "id": "welsh-portugal", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHsAAAB7CAYAAABUx/9/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAF40lEQVR4nO3dTUgUfxzH8c8+jLmy5CYpGwYZC2InUQ8bHcSiIDLoYllQxzDxkCfx3E0QJRK9hIqHpYgOYRIRFgpBhof1kInRBrHiA+EquK7tw0yH//8/aLs7rv5Xd9zv5wULjvPgD9+Os/MAa9E0DSSDNdcDoMPD2IIwtiCMLQhjC8LYgtiNZg4MDPC87IhpbW21pJvHPVsQxhaEsQVhbEEYWxDGFoSxBWFsQRhbEMYWhLEFYWxBGFsQxhaEsQVhbEEYWxDGFoSxBWFsQRhbEMYWhLEFYWxBGFsQxhaEsQVhbEEYWxDGFoSxBWFsQRhbEMYWhLEFYWxBGFsQxhaEsQVhbEEYWxDGFoSxBWFsQRhbEMYWhLEFYWxBGFsQxhaEsQVhbEEYWxDGFoSxBWFsQRhbEMYWxPDjGfOBzWZL+f1EIoFEIpHR+pqmQVVVw+Xsdjs0zdyfZpn3se/fvw+LJfnjKcfHx3H58uVd15+YmIDf78fDhw8NlwuFQpiamkIgENj3WA9a3sdO59KlSzv2bFVVoShK0nIXL1403GPj8TgsFgusVvMfEc0/wgPyXyCr1YpoNIrS0tKUy6mqmhS7rKwMkUgEkUgENpvtSIQGBO/ZABAIBNDY2IhYLIa1tbWM1/v16xdqamr06ZmZGRQUFBzACLNLbGy/34+WlhbMzc3t+P78/Dxqa2uxsbGRdt3i4mK8fv1an7bbj8av8WiMMotGR0fx7t07zM/P4/Pnz0nzPR4PFEXBs2fPcOrUKQDA8PAwhoaGAABnzpzB8+fP4fF4DnXc2SAi9tOnT7G5uQkA8Pl8mJqa2jG/qKgIvb29aGlpAQD09fXhxo0bKCwsBAC43W5cuHBB/9rr9errPnnyRD+mm/34bTF6pzkwMGDuE8cMPHjwAKWlpbh58yZGR0exsLCQtMzJkyextLQEu92OsbEx2Gw2NDQ04NixYym3GY/HMT4+Dk3TcO3aNbS3t0NRFLjdbv0PJFdaW1uTzzP/lfd79pcvXxCNRtHU1AS/358ydiwWw+zsLJqbm9HY2AgAWF1dTYodiUQQCASwtbWl/1u/desWurq6oCgK3r59y/PsXKquroaqqoYXUNbX11FbW4tgMIgXL15AVVUsLCwgGo3uWO7bt29ob2+H2+3e8QbtqMj72JmKx+Nwu936dENDA9bX1xGPxwEADocD9+7dw/T0dK6G+L+Z991Ejn39+hVXrlzRp9va2tDf369fU8/02rqZMHYaZWVlePPmjT7d3d0Nu92e9DL7zY/tGDtLzp07hw8fPuR6GIbExR4bG0N3d3fWtnfixAlEo1HMzMygvr4+a9s9COJiFxUV6efCV69eRSgUSnoVFxdnvL0fP35AURQUFBSkvXduFuJit7W1wWq14vHjx3A6nXC5XEkvq9WKT58+4fz587tuz+VypbxfbkbiYs/OzmJwcBCvXr0yXK6yshJDQ0O4fv36IY3s4ImLDQDT09N4//59ynk9PT3o7e2Fw+FAVVUVHj16hKampkMe4cHgRZW/dHR0YGNjQz+u19TUoLOzE1VVVfj58ydGRkZSrjc5OYlgMHiYQ90zxs5AXV0d6urqEAwGEYvFEIvF8PLlS9y+fRvAP4eGO3fu4O7du6ioqMjtYA0w9l+8Xm/a25SnT5+Gz+fD1tYWlpeX4fP5sLS0BK/Xa/iwg1kw9jbhcBgfP37cdbnCwkJMTk4iHA6jvLx818eMzULkG7RUEokEnE5nxuF+//69p+XNgLH3YXNzM+cPKewHY+/RysoKnE5nroexL4y9B3Nzczh79uyRutO1Xd4/g7a2tpb2uOpwOFBeXg4A0DQN379/h8fjSXv5MxwOY3FxMe3POn78eM4fKxb9DJrL5TKcv7q6qn9dUlKCUChkuHxJSUk2hpUT/DcuCGMLwtiCMLYgjC0IYwvC2IIwtiCMLQhjC8LYgjC2IIwtCGMLwtiCMLYgjC0IYwvC2IIwtiCGT5dSfuGeLQhjC8LYgjC2IIwtCGML8geOrMk9HNsdegAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "section = np.zeros(shape) + 0.5 # default value 0.5 for gray\n", "section[55:80,45:70] = img1[55:80,45:70] # choose small section of image\n", "seed = img2vec(section) # transform section of image to seed pattern\n", "net.set_network(state=seed) # set network state to the seed pattern\n", "\n", "plt.figure(figsize=(2,2))\n", "plt.imshow(section, cmap='Greys_r')\n", "plt.axis('off')\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "formed-theater", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Now we are ready to run the network. To speed things up, we will update 1000 nodes at a time. We might want to record the state of the network after every update. But to see how the network approaches one of the patterns, we only need to record the overlap between the network state and each pattern." ] }, { "cell_type": "code", "execution_count": 8, "id": "therapeutic-leadership", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "T = 50\n", "overlap_hist = [net.overlap()]\n", "for t in range(T):\n", " flip = net.updateN(size=1000)\n", " overlap_hist.append(net.overlap())" ] }, { "cell_type": "markdown", "id": "497f681f-71f8-4c87-9c85-92fdae359429", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Let us visualize the final state of the network." ] }, { "cell_type": "code", "execution_count": 9, "id": "06fe2ebf-cece-4156-907d-927de47b729a", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "img = vec2img(net.state, shape) # convert vector to image\n", "plt.figure(figsize=(2,2))\n", "plt.imshow(img, cmap='Greys_r')\n", "plt.axis('off')\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "italic-century", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "We have successfully retrieved the full image!" ] }, { "cell_type": "markdown", "id": "b5d82400-5422-4252-a5ef-a1f73c9556fc", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Let us plot how the overlaps have changed over time." ] }, { "cell_type": "code", "execution_count": 10, "id": "clear-archives", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYYAAAEKCAYAAAAW8vJGAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAu6ElEQVR4nO3deXxU9bn48c+TySSTkJBACGsCAdkVUQigxYWqtaC2qHW/ba3SUmuttbe9t3rtYr3aWnttf71XW7XFWq11rQutey1qtSg7siMgkABhCdm3ycw8vz/OCUxiWAYzOZmZ5/16zeusM+c5Q/g+c77fc75fUVWMMcaYNmleB2CMMaZnscRgjDGmHUsMxhhj2rHEYIwxph1LDMYYY9pJ9zqAT6pfv35aUlLidRjGGJNQli5duk9VCzvblvCJoaSkhCVLlngdhjHGJBQR2XaobVaVZIwxph1LDMYYY9qxxGCMMaadhG9j6Exrayvl5eU0Nzd7HUqXCAQCFBUV4ff7vQ7FGJMCujUxiMhDwAXAHlU9oZPtAvwaOA9oBL6iqstiPU55eTm5ubmUlJTgfGTiUlUqKyspLy9n+PDhXodjjEkB3V2V9DAw8zDbZwGj3Ndc4LfHcpDm5mYKCgoSPikAiAgFBQVJc/VjjOn5ujUxqOrbwP7D7DIbeEQd7wH5IjLoWI6VDEmhTTKdizGm5+tpbQxDgLKo5XJ33a7onURkLs4VBUOHDu224Iwx5lBUldaw0tQaJhiKEAxHaA1FaA1HaHGnoYgSjigRVVQ5MB9RJRRWQhGlNRwhHHGWWyMH58MRdd9/8HOunzGSrAxfl59LT0sMR0VVHwQeBCgtLbUBJYwxgFM4N7WGaQqGCYYjtLQ6BXQw5BTOLaGwM211ps2tYZpbnfWtYSUYVYC3zQdDEZpDEZqCYVpCzmc3t01b2z4jTFNrmEg3lkZpAld/qiQlEsMOoDhquchdZ4xJAeGI0hgM0RgMu68Q9c0hqhqD7G9opaoxSFVDkP3utK45RH1L6MC0viVE+BOWzulpgt+XRrpPyPClkZGeRpbfR6bfR5Y/jYDfR16Wn4Df576c7QG/j6wMH5npaWSmO+/z+9pP09MEnwhpaUKaCGnCgfn0NCHdJ6SnpeH3Cb62ONKcdT6fs48v6jPipaclhvnADSLyBDANqFHVXUd4T0LbsmULd955JzU1NTzzzDNeh2PMJxaOKDVNre1etVHz1Y1BqhoPTqsag1Q3tlLfEiIYihzx87MzfPTJziA/20/vgJ/ivtnkBtLJzUwnJ5BOTqaf7AwfGelpZPjSyPSnHSjgM9Kdgj2Q7iPT3zafRqbfR4bPKZCtTa/7b1d9HJgB9BORcuDHgB9AVe8HXsK5VXUTzu2q13RnfF4YMWIE8+bN45JLLvE6FGMOqykYpqK2mV3VTeyqaaaitpm9dS3sq2+hsj5IZYMz3d8Y5HAjBgf8aW7BnkGfbD/jBvYmP9tPTiCdbH86vTKdX97ZGT6y/OnkZKbTp5efvr0y6JOdQcDf9VUnpr1uTQyqeuURtivwzW4Kxxjjam4NU1HTzM6aJipqmtlV08zO6iZ3XTMVNU1UNbZ+7H25gXT65WRS0CuDEf1ymFKSQUFOJn2y/eRlHXz1bpsG/HGpEzddq6dVJSWVSy+9lAEDBrBixQrKysp47LHHeOCBB3j//fc5/fTTmTdvntchmhRQ19zK7lqnsN9V08zummZ21TYfSAC7a5vZ3xD82Pv6ZPsZmJfFoLwAk4bmMzg/i4G9AwzKDzDIXW+/3pOTJYY4WrVqFaeeeir33nsvP/3pT5kzZw5vvvkmhYWFFBUV0dLSQn19PbfeeivLly/nZz/7GbfccovXYZsEoqpUNgQp29/I9v2NlFc1Uba/kR1t1T01zdS3hD72voJeGQzMCzAk3yn0B+UFGJiXxeC8AAPznILfftmnrqRPDD/56xrW7qzt0s8cP7g3P/7c8Yfdp7m5merqam666SbAeUhtzpw5DBrkPK/n8/nIyMigoKCA+++/v0vjM8lHVdlR3cSGijo27K5jY0UdG3bXs62ygcZguN2+/XIyGJKfxcjCHE4b2c8t9AMM7O1MB/S2X/rm8JI+MXhlzZo1TJo0ibQ05+HylStX8o1vfANw+nIaPHiw3f1gPkZV2V3bwsbddXy4p54Pd9excXcdG3fXt/vlPyQ/i9EDcjh1RAHFfbMo7pPN0IJsivpkkZ1h/63NJ5P0f0FH+mUfL6tWrWLixIkHlj/44ANOPPFEwEkSbfMmde1vCLK+ovbAr/+NbhKoaz6YAPr2ymBU/xy+MGkIYwb2ZszAHEYNyKV3wHraNfGT9InBK6tWrWLq1KmAU63U1NREnz59gPZJwiS/xmCIjbvr2VhRx/oKp/BfX1HHvvqWA/vkZfkZMyCX2ScNZvSAXEb1z2X0gBwKcjI9jNykKksMcXLPPfccmA8EAnz00UcHlq2BOXlV1rewdFsVH5TXHEgC2/c3Htge8KcxekAuM8YUMnZgLqMH5DJ2YC6FuZlWtWh6DEsMxhwjVWXz3nqWbK1i6TbntWVfAwC+NGF4v15MGJLHJZOLGDMwlzEDcinum40vjl0ZGNMVLDEYc5QagyFWltWwbLuTBJZtr6LafeirT7afycP6cGlpMaUlfZgwJM/u/DEJyxKDMYfQ3Bpm4ZZK3tqwl6Xbqli7q/ZAB22j+ufw2fEDmTysD5NL+jCiXy+rCjJJwxKDMVH21rWwYP0e/r5uN+9s2kdjMEyW38fJQ/O5fsZxTBrWh5OL88nPzvA6VGPixhKDSWmqypqdtby5YQ9vrN/DirJqVGFQXoCLJw3h7HEDOHVEgVULmZRiicGknPqWEO98uI8F6/ewYMMe9tQ5t41OLMrjO+eM5uxx/Rk/qLdVDZmUZYnBpITm1jCvrqngmaXlvLelktawkpuZzhmjC5kxppAZY/pTmGvPDBgDlhhMklu9o4anlpTx/PId1DaHGJKfxTXTh/PpMf0pLemD35fmdYjG9DiWGEzSqW4M8vzyHTy1pJy1u2rJSE9j1gkDuay0mFNHFMR1SERjkoElBo89//zzvPjii9TW1jJnzhzOPfdcr0NKSJGI8s6mfTy1pIzX1uwmGI4wYUge/z37eD4/cQh52da3kDFHyxKDxy688EIuvPBCqqqq+N73vmeJIUZl+xt5emk5f1lazo7qJvKz/Vw1bSiXlhZx/OA8r8MzJiFZYugh7rjjDr75TRvV9Gi0hMK8tmY3Ty4u493N+wA4bWQ/bjlvLOeMG2C3lhrzCVliiKOjGdpTVbn55puZNWsWkyZN8jrkHm3j7jqeWFTGc8vLqWpsZUh+FjedPZpLSosYkp/ldXjGJI3kTwwv3wwVq7r2MwdOgFl3HXG3oxna84EHHuDvf/87NTU1bNq0ieuuu65rY01wza1h5q/YyeOLt7N8ezV+n3Du8QO5Ykox04/rZw3JxsRB8icGjxzt0J433ngjN954o4eR9kx76pr508Jt/On97exvCDKyfw4/OH8cF508xMYoMCbOkj8xHMUv+3iwoT2Pzbpdtcx75yPmr9hJayTC2WMHMOe04Zwyoq99X8Z0k+RPDB6xoT2Pnqry5sa9zPvnR7yzaR9Zfh9XTC3mmunDGd6vl9fhGZNyLDHEiQ3teWQtoTAvrNjJ7/+5hY276xnYO8D3Z47lyqnF1nupMR6yxBAnNrTnoVU3Bnns/e08/K+t7K1rYdyg3vzq8omcP2EwGenWRYUxXrPEYLpNVUOQexds4s/vb6epNcwZowv51WUjmD6ywNoPjOlBLDGYuAuGIjyycCv/+8aH1LeEuPDkIXzt9BGMG9Tb69CMMZ2wxGDiRlV5dU0FP3t5PdsqGzljdCG3njeOMQNzvQ7NGHMYSZsYVDVpqidU1esQYvZBeTV3/G0di7buZ/SAHB6+ZgozxvT3OixjzFHo1sQgIjOBXwM+4PeqeleH7UOBPwL57j43q+pLsR4nEAhQWVlJQUHi112rKpWVlQQCAa9DOSp761q4+5X1PL20nIJeGdx50QlcXlpMuo17YEzC6LbEICI+4D7gM0A5sFhE5qvq2qjdfgA8paq/FZHxwEtASazHKioqory8nL1793ZB5N4LBAIUFRV5HcZhtbUj/PrvH9IcCvP1M0Zww1kjyQ1Yd9fGJJruvGKYCmxS1S0AIvIEMBuITgwKtLVI5gE7j+VAfr+f4cOHf4JQTSze3riXn/x1DZv3NvDpMYX88ILxjCjM8TosY8wx6s7EMAQoi1ouB6Z12Oc24DUR+RbQCzinsw8SkbnAXIChQ4d2eaDm6JTtb+T2v63l9bW7KSnI5qGvlHLW2AFeh2WM+YR6WuPzlcDDqnqPiJwKPCoiJ6hqJHonVX0QeBCgtLQ08VpmE5yq8viiMu54cS0C3DxrLNdMLyEz3cZBMCYZdGdi2AEURy0XueuizQFmAqjqQhEJAP2APd0SoTmiippmvv+XD3hr416mjyzg7ksm2lgIxiSZ7kwMi4FRIjIcJyFcAVzVYZ/twNnAwyIyDggAydGCnOBUlRdW7ORHL6wmGI5w++zj+eK0YTYegjFJqNsSg6qGROQG4FWcW1EfUtU1InI7sERV5wPfBX4nIt/BaYj+iibiTfxJprK+hR88v5qXV1cwaWg+91x2kvV6akwS69Y2BveZhJc6rPtR1PxaYHp3xmQO750P93HTkyuobWrl+zPHMveMEfjsKsGYpNbTGp9NDxEKR/j1Gx9y74JNjCzM4dE5U61vI2NShCUG8zEVNc3c+MRyFn20n0snF/GT2ceTnWF/KsakCvvfbtpZsGEP331qJc2tYX552UQuntSzn7g2xnQ9SwwGgNZwhP95bQMPvLWFsQNzufeqSYzsb08vG5OKLDEY9jcE+eZjy1i4pZKrpg3lRxeMJ+C3h9WMSVWWGFLchoo6vvrIYnbXtnDPpRP5wmSrOjIm1VliSGGvrangO0+uoFdmOk/OPYWTh/bxOiRjTA9giSEFqSr3/mMT97y+kYlFeTzwpVIG5iXGeA/GmPizxJBiGoMh/uOZD3jxg11cdPIQfnbxBGtPMMa0Y4khheyrb+HahxezakcNt8xynmJO9BHujDFdzxJDiijb38iXH1rErpomfvelUs4Zb+MmGGM6Z4khBazdWcvVf1hEMBThsa9OY/Kwvl6HZIzpwSwxJLn3tlTytT8uISeQzp+vO5VRA3K9DskY08NZYkhir6yu4MYnljO0bzaPXDuVwTagjjHmKFhiSFKPL9rOrc+tYmJxPg9dPYU+vTK8DskYkyAsMSShRxdu5YcvrGHGmEJ+82+TrGdUY0xMrMRIMk8vKeOHL6zhnHH9+e0XJ+P3pXkdkjEmwVipkUTmr9zJ9//yAaeP6se9V02ypGCMOSZWciSJtn6PSkv68uCXSu1pZmPMMbPEkATe2riXG/68nAlD8njoK1PIyrCkYIw5dpYYEtzCzZXMfWQJI/vn8MdrppKTac1GxphPxhJDAlu2vYo5f1zM0L7ZPDpnKnnZfq9DMsYkAUsMCWrj7jqu+cNiCnMzeeyr0yjIyfQ6JGNMkrDEkIDKqxr58rxFZKSn8ei10+jf28ZSMMZ0HUsMCaayvoUvz1tEQzDEI9dOZWhBttchGWOSjCWGBFLfEuKahxezo7qJeVdPYdyg3l6HZIxJQnYLS4JoCYX5+qNLWLOzlge+OJmpw63rbGNMfNgVQwIIR5R/f3Il726q5OdfONEG2THGxJUlhh5OVblt/hpeXLWLW88bxyWTi7wOyRiT5I6YGESkV3cEYjr3p/e38+h725h7xgi+dsYIr8MxxqSAo2lj+JmI9AYEKFTV8+Ick3G9t6WSn8xfw9lj+3PzzLFeh2OMSRFHvGJQ1RtV9SvAN4DVn+RgIjJTRDaIyCYRufkQ+1wmImtFZI2I/PmTHC+RlVc1cv1jyxhWkM2vrjiJtDTxOiRjTIo44hWDiPwnsAJYCxzzgMEi4gPuAz4DlAOLRWS+qq6N2mcUcAswXVWrRKT/sR4vkTUGQ8x9ZCmt4Qi/+3IpvQPW1YUxpvscTePzX4GBwPeBYhF5+BiPNRXYpKpbVDUIPAHM7rDP14D7VLUKQFX3HOOxEpaq8h/PfMD6ilr+78qTGVGY43VIxpgUc8QrBlVdB6wDHhERPxA5xmMNAcqilsuBaR32GQ0gIu8CPuA2VX2l4weJyFxgLsDQoUOPMZye6TdvbubFD3Zxy6yxzBiTkhdMxhiPHfXtqiLyO2AbsFVE3heR34nIt7o4nnRgFDADuBL4nYjkd9xJVR9U1VJVLS0sLOziELzzxrrd/M9rG5h90mDm2h1IxhiPxPLk8xlAsaqGRWQIMBE4MYb37wCKo5aL3HXRyoH3VbUV+EhENuIkisUxHCchbdlbz7efWMHxg3vz8y+ciIg1NhtjvBHLA27vAwUAqrpDVV9S1btieP9iYJSIDBeRDOAKYH6HfZ7HuVpARPrhVC1tieEYCaklFOZbjy8n3Sc2LKcxxnOxJIYHgLdE5HsicrqI5MVyIFUNATcAr+K0WTylqmtE5HYR+by726tApYisBRYA/6GqlbEcJxHd/coG1uys5ReXTGRwfpbX4RhjUpyo6tHtKPIR8CCgHKxGCqjqcfEL78hKS0t1yZIlXobwiSxYv4drHl7M1acO4yezT/A6HGNMihCRpapa2tm2WNoYylX1Zx0+2IYN+wT21Dbz3adXMnZgLrecN87rcIwxBoitKmmFiHw7eoWqtnRxPCkjElG+89QKGoMh7r3qZGtXMMb0GLFcMQwAzhGR7wPLgJXAClV9Oi6RJbn7397Mu5squeviCYzsf8wPlBtjTJc76sSgqpfBgeqj44EJOE8zW2KI0bLtVdzz2kbOnzCIy6cUH/kNxhjTjWIewc2tPlrmvkyMaptbufHx5QzsHeCnF0+w5xWMMT2ODe3ZzW6bv4ZdNc089fVTyMuyzvGMMT2PjeDWjd75cB/PLtvBdWeOYPIwG7PZGNMzHfUVg4gEgOuB03CeZXgH+K2qNscptqTS3BrmB8+voqQgm2+dNcrrcIwx5pBiqUp6BKgD/s9dvgp4FLi0q4NKRvf+YxNbKxt57KvT7NZUY0yPFktiOEFVx0ctL3C7rjBHsHF3Hfe/tZmLTx7C9JH9vA7HGGMOK5Y2hmUickrbgohMAxK3L4puEoko//XsKnIC6dx6vj3dbIzp+WK5YpgM/EtEtrvLQ4ENIrIKUFWNpQvulPHE4jKWbKvi7ktOpCDHehAxxvR8sSSGmXGLIkntqWvmrpfXMW14Xy6dXOR1OMYYc1RiefJ5m4j0wRk4JxC1/u14BJYM/vtv62hujdiDbMaYhBLL7apfBb6NM/LaCuAUYCFwVlwiS3BvbtjDX1fu5KZzRnFcYY7X4RhjzFGLpfH528AUYJuqfho4GaiOR1CJrrk1zA9fWM2Iwl58Y4anw1UYY0zMYkkMzW0Ps4lIpqquB8bEJ6zE9vt/bqFsfxN3zD6BzHR7ZsEYk1hiGqhHRPJxxmV+XUSqgG3xCCqRVdQ0c9+CzXz2+AF8yp5ZMMYkoFgany9yZ28TkQVAHvBKXKJKYHe/sp5wRLn1vPFH3tkYY3qgY+pdVVXf6upAksHy7VU8u3wH1515HEMLsr0OxxhjjskRE4OI1OF0mifu9MAmnAfbescptoSiqtz+t7UU5mZyw1kjvQ7HGGOO2RETg6rminMTfrGqbj/S/qnqhRU7Wb69mrsvOZGcTBvmwhiTuI7qriRVVeDFOMeSsBqDIe56eT0ThuRxySR7wtkYk9hi7URvStwiSWD3v7WFitpmfvS58aSl2RPOxpjEFkudxzTgiyKyFWjgYBtDSneet6O6iQfe2swFJw5iSomNymaMSXyxJIbPxi2KBHbXy+sBuOU861LbGJMcYqlK2g6cDlytqttw7lAaEJeoEsTSbfv568qdfP3M4xiSn+V1OMYY0yViSQy/AU4FrnSX64D7ujyiBKGq3PniOvrnZnLdmSO8DscYY7pMLIlhmqp+E2gGUNUqICMuUSWA19buZtn2ar7zmdFkZ9jtqcaY5BFLYmgVER/uQ24iUghE4hJVDxcKR7j7lfUcV9jLBuAxxiSdWBLD/wLPAf1F5E7gHeCnsRxMRGaKyAYR2SQiNx9mvy+IiIpIaSyf312eXlrO5r0N/OfMsaT7YvkKjTGm54ulE73HRGQpcDbOraoXquq6o32/e7VxH/AZoBxYLCLzVXVth/1yccZ+eP9oP7s7NQZD/Or1jUwe1odzx6d027sxJkkd9c9dEfl3oE5V71PVe2NJCq6pwCZV3aKqQeAJYHYn+/038HPctoye5g/vbmVPXQu3zBprw3UaY5JSLPUgucBrIvJPEblBRGL9uTwEKItaLnfXHSAik3D6ZDps9xsiMldElojIkr1798YYxrHb3xDk/jc385nxAyi1h9mMMUnqqBODqv5EVY8HvgkMAt4Skb93VSAikgb8EvjuUcTyoKqWqmppYWFhV4VwRPf+YxMNwRD/+VkbuM4Yk7yOpeV0D1ABVAL9Y3jfDqA4arnIXdcmFzgBeNPtduMUYH5PaYAu29/Io+9t5bLSYkYNyPU6HGOMiZtY2hiuF5E3gTeAAuBrMfaTtBgYJSLDRSQDuAKY37ZRVWtUtZ+qlqhqCfAe8HlVXRLDMeLmntc24EsTbjpntNehGGNMXMXyZFYxcJOqrjiWA6lqSERuAF4FfMBDqrpGRG4Hlqjq/MN/gndW76jh+RU7uX7GcQzMC3gdjjHGxFUst6veIiIT3cId4J+qujKWg6nqS8BLHdb96BD7zojls+PpF69uID/bz9fPPM7rUIwxJu5iqUq6EXgMp12hP/AnEflWvALrKVaWVfPWxr3MPWMEeVl+r8Mxxpi4i6Uq6as4/SU1AIjIz4GFwP/FI7Ce4t4Fm8jL8vOlU4Z5HYoxxnSLWO5KEiActRx21yWtdbtqeX3tbq6ZXkJuwK4WjDGpIZYrhj8A74vIc+7yhcC8Lo+oB7lvwSZyMtP5yqdKvA7FGGO6TSyNz790b1c9zV11jaouj0tUPcDmvfW8uGoX1515HPnZKdu7uDEmBcU0kICqLgOWxSmWHuU3CzaTmZ7GnNOGex2KMcZ0K+szuhNl+xt5fsUOrpo6jH45mV6HY4wx3coSQyd++9ZmfCLMPcOG7DTGpB5LDB3sqmnimSXlXFpaZE85G2NSkiWGDh58ewthVa6zp5yNMSnKEkOUvXUtPL5oOxedPITivtleh2OMMZ6wxBBl3jsf0RKKcP0Mu1owxqQuSwyumsZWHl24lQtOHMyIwhyvwzHGGM9YYnA9vng7DcEw151pdyIZY1KbJQagNRzhj//ayqkjCjh+cJ7X4RhjjKcsMQCvrK5gV02zPeVsjDFYYgCcRueSgmzOGhvLENbGGJOcUj4xLNtexYqyaq6ZPpy0tKTuRdwYY45KyieGee98RG4gnUsmF3kdijHG9AgpnRh2VDfxyuoKrpw6lF6ZMXU0a4wxSSulE8Mj/9qKqvLlU23YTmOMaZOyiaGhJcTji7Yz64RBFPWx7i+MMaZNyiaGvywrp7Y5xLWnlXgdijHG9CgpmRgiEeUP725lYnE+k4b28TocY4zpUVIyMSzYsIeP9jVw7fQSROwWVWOMiZaSieGhdz9iYO8A500Y5HUoxhjT46RcYli3q5Z3N1Xy5U8Nw+9LudM3xpgjSrmS8ZGF2wj407hq6lCvQzHGmB4ppRJDQ0uI+St2cP6EweRnZ3gdjjHG9EgplRj+unInDcEwV04t9joUY4zpsVIqMTyxuIyR/XOYPMxuUTXGmEPp1sQgIjNFZIOIbBKRmzvZ/u8islZEPhCRN0Sky/qqWF9Ry4qyaq6YUmy3qBpjzGF0W2IQER9wHzALGA9cKSLjO+y2HChV1ROBZ4C7u+r4TywqI8OXxsWTrBdVY4w5nO68YpgKbFLVLaoaBJ4AZkfvoKoLVLXRXXwP6JJSvLk1zLPLyvnsCQPp28sanY0x5nC6MzEMAcqilsvddYcyB3i5sw0iMldElojIkr179x7xwC+v3kVtc4grp1ijszHGHEmPbHwWkS8CpcAvOtuuqg+qaqmqlhYWFh7x8x5fVMawgmxOGVHQxZEaY0zy6c7EsAOI/sle5K5rR0TOAW4FPq+qLZ/0oJv31rPoo/1cPqXYhu40xngnEoFI2H1FQNV59UDdOWzZYmCUiAzHSQhXAFdF7yAiJwMPADNVdU9XHPTJxWWkp4kN3WlMT6EK4VaItLrTkPM6sM5dbpsPByHUBKEWaG2CULM7bTnEZ4ScwlfDoG5hrBFnOdI2DR3cr21eIwfjI6rQ1kjU53aIr62g1/DBz2p3nPDB4x2JpAHiTKVtmtY+po7z/74eenV9TUi3JQZVDYnIDcCrgA94SFXXiMjtwBJVnY9TdZQDPO3eUrpdVT9/rMcMhiL8ZWk554wbQP/cQBechTFJILowjC4cW5ugtRGCjdDacHDa2uwUxqGWj0/DwajCMqqQDrVAsAGC9e5nNhx8aTg+5yVpkJYOaX5nKgJpPreAdadpPveVHvXyHdx+4FZ2cefdAjo9A9J6Ofv7/J28P+3g54rv8Os6K+QPTNuuJCLOciTcSUxR8+mZcfkqu3WgY1V9CXipw7ofRc2f05XHe33tbiobglxhTzobL0XC7QvTYAME66Cl3ik426atTU5BG26FcEvUfNAthNvWtx4slNu2t60PByHkFtYf+1Xc9su1C6ovfJlOoeTzOwVxdGHp8zvbMnKg92DI6OW+csCfBb6M9vum+Z1Cs91n+dp/rj8L0gPtp74M99X2GT2yyTQhdWti6G5PLN7OkPwsTh915AZqY4iEP15VEWpy5ptrnFdTFTRXu/PVToEebDz4q/jAtOlgMoi0Hls8bYVvWrpbCGccfKVHzfvzPr4u+petRP9K9h0siNvtk+YUuBnZbgGe7cz7ezmFsD/LjcGNwwrhpJa0iaFsfyP//HAf3zlnND5rdE4toSA0VkLjPmfasA8a9x9cbqo+WNBHv0JNR3+M9AAE8iAz1y1EcyC7L/iLnF/H/ixIdwvT9EDUNMPZNyMHMnPaz7ft58t0qx3s79Z4I2kTw5OLy0gTuGyKNTr3eJEI1FdAzQ634N7vFuxtr/3OfgeqDNLB59Ylh1qcAr9h38H9W2oPcSCBrHzI6uMU6oE86D3o4HxGLvgDbgHdodqibZ9AvjP1W5uVSV5JmRjCEeXppWXMGNOfQXlZXodjWuqhfjfUVbgJoByqtkHVVqjeBtVlTh15R2l+yC5wCnKRzu8+8WU4d2VkF0CfEujVz5nPLoia73fwc3xJ+SdvTJdKyv8l/9q8j921Lfz4c3a10OXCIajd4RToVducAv9A3Xr9wTtPWuqcbfV7nPUdBfKhzzAYcDyMOc+Zzys+WJhn9XWqaaw6xZhul5SJ4bllO8gNpHPW2P5eh5LYGvfDR2/D1ndg30YnGdSUf/ye7LR0t668V/s7UAadBLkDIWeA88p1p72HOFU6xpgeKekSQ2MwxCtrKvj8xMEE/D6vw0ksLfWwfSFseRM+egsqVgPq3JnSfywMmQzHX+xU2fQZ5kxzB8XtXmpjjDeSLjG8uqaCxmCYi04+XP98KS7YCJUfwt4NzmvfBti7EfZvPlhvXzwNPv1fMPxMGDLJafg1xqSEpEsMzy7bwZD8LKaU9PU6lJ4h2AgVH8COZbBjKexcDvu3cOAhJ/FB3xFQOAbGfQ5KpkPxKc497MaYlJRUiWFPbTPvbtrH9TNGpm6HeQ373Kqgt51EsGfdwS4Icgc7v/5PvNxJBIVjoO9xzr31xhjjSqrEMH/lTiIKF01KoWqkYKPbLrDASQgVq5z1mXlQNBnGzILBk5yEkDvQ01CNMYkhqRLDs8t2MLEoj+MKc7wOpetFIlCzHfash73roqbrnP5x2toFzvohjPg0DD7JeXrWGGNilDSJYUNFHWt31XLb5zoOI52gGvbB9vecq4Gy92H3GudZgTa5g507haZdByPOhKGnOreJGmPMJ5Q0ieHZ5eX40oTPTRzsdSjHpmEfbHwFti2EsvegcpOz3pfp3CY6+StQOBb6j4N+o+05AGNM3CRFYghHlBeW7+TM0YUU5CTQPfVN1bD+b7D6L7DlLaeROKsvDD0FJn3ZuTto8En2nIAxplslRWJ4b0slFbXN3Hr+OK9DObJgA2x4GVY/C5ted9oH8ofB9G/D8RfBwAnWDYQxxlNJkRieXbaD3Mx0PjN+gNehdK61CT58HdY8CxtfddoKcgfBlK/BCV9w7hiyZGCM6SESPjFEFF5ZvYvzTxzUs7rACAVh8z+cZLD+JWfErux+MPFKOOFiGPopG+zEGNMjJXxiqG1qJRQMc9HJPaQn1V0rYfmfYNXTzmhfgXw4/kLnyqDkdOv22RjT4yV8KVXdGGRMfhbThnvYBUZDpZMIlv8Jdq9y7iQadwGceAWMmGFPFhtjEkrCJ4a6lhCzTxrc/V1gNNfC5jdgzXNOVVGk1elm+rz/gQmXOIPCGGNMAkr4xJAm0n09qVZvhw2vwIaXnDEKIq3OoDJTvwYn/RsMPKF74jDGmDhK+MQwblBvRg3Ijd8B6ipg+aOw5gWnmgigYBSc8g1n5LHiqdb1hDEmqSR8YohLDZKq0zvpknmw/kVnjIKhn4Jz74DRs6DfyDgc1BhjeoaETwxdqqkKVjwOSx5yBrLJ6uP0RVR6LRQc53V0xhjTLSwxgDN4zeLfw6pnINQMRVPhogdg/IXgD3gdnTHGdKvUTQytzc4dRYt/5wxo4+8FE6+AKV91uqUwxpgUlXqJoXq7c3Ww7FFo2u/0VDrrbicpBPK8js4YYzyXOomhbBEsvA/WzQcExp7v3GZacrr1U2SMMVGSOzGEQ04iWHgf7FjiXBF86kaYOhfyUmj4T2OMiUG3JgYRmQn8GvABv1fVuzpszwQeASYDlcDlqro15gOFgs6dRQvvhZoy6DvCeSJ54pWQmYTDfhpjTBfqtsQgIj7gPuAzQDmwWETmq+raqN3mAFWqOlJErgB+Dlwe04E2vgav3uKMgDZsutN+MHqm9WRqjDFHqTuvGKYCm1R1C4CIPAHMBqITw2zgNnf+GeBeERFV1SN++r4P4dX/gg9fg4KRcNXTMPrcLj0BY4xJBd2ZGIYAZVHL5cC0Q+2jqiERqQEKgH2H/FQNw6u3wvv3gz8bzr3TaUOwHk2NMeaYJGTjs4jMBeYCnDzYDws/gklfgrN+CDn9PY7OGGMSW3cmhh1AcdRykbuus33KRSQdyMNphG5HVR8EHgQoHd5HmfsPGHxyXII2xphU050tsouBUSIyXEQygCuA+R32mQ9c7c5fAvzjiO0LBcdZUjDGmC7UbVcMbpvBDcCrOLerPqSqa0TkdmCJqs4H5gGPisgmYD9O8jDGGNONurWNQVVfAl7qsO5HUfPNwKXdGZMxxpj27OZ+Y4wx7VhiMMYY044lBmOMMe1YYjDGGNOOJQZjjDHtWGIwxhjTjhxN/3Q9mYjUARu8jsND/ThcX1LJz87fzj9Vz/+TnvswVS3sbENC9pXUwQZVLfU6CK+IyBI7fzt/r+PwSiqffzzP3aqSjDHGtGOJwRhjTDvJkBge9DoAj9n5pzY7/9QVt3NP+MZnY4wxXSsZrhiMMcZ0IUsMxhhj2knoxCAiM0Vkg4hsEpGbvY4n3kTkIRHZIyKro9b1FZHXReRDd9rHyxjjRUSKRWSBiKwVkTUi8m13faqcf0BEFonISvf8f+KuHy4i77v/B550B8FKWiLiE5HlIvI3dzllzl9EtorIKhFZISJL3HVx+ftP2MQgIj7gPmAWMB64UkTGextV3D0MzOyw7mbgDVUdBbzhLiejEPBdVR0PnAJ80/33TpXzbwHOUtWJwEnATBE5Bfg58CtVHQlUAXO8C7FbfBtYF7Wcauf/aVU9Ker5hbj8/SdsYgCmAptUdYuqBoEngNkexxRXqvo2zsh20WYDf3Tn/whc2J0xdRdV3aWqy9z5OpzCYQipc/6qqvXuot99KXAW8Iy7PmnPH0BEioDzgd+7y0IKnf8hxOXvP5ETwxCgLGq53F2Xagao6i53vgIY4GUw3UFESoCTgfdJofN3q1FWAHuA14HNQLWqhtxdkv3/wP8D/hOIuMsFpNb5K/CaiCwVkbnuurj8/SdDlxjGpaoqIkl9/7GI5AB/AW5S1VrnR6Mj2c9fVcPASSKSDzwHjPU2ou4jIhcAe1R1qYjM8Dgcr5ymqjtEpD/wuoisj97YlX//iXzFsAMojlouctelmt0iMgjAne7xOJ64ERE/TlJ4TFWfdVenzPm3UdVqYAFwKpAvIm0/8JL5/8B04PMishWn2vgs4Nekzvmjqjvc6R6cHwZTidPffyInhsXAKPeuhAzgCmC+xzF5YT5wtTt/NfCCh7HEjVufPA9Yp6q/jNqUKudf6F4pICJZwGdw2lkWAJe4uyXt+avqLapapKolOP/X/6Gq/0aKnL+I9BKR3LZ54FxgNXH6+0/oJ59F5Dycekcf8JCq3ultRPElIo8DM3C6290N/Bh4HngKGApsAy5T1Y4N1AlPRE4D/gms4mAd83/htDOkwvmfiNO46MP5QfeUqt4uIiNwfkH3BZYDX1TVFu8ijT+3Kul7qnpBqpy/e57PuYvpwJ9V9U4RKSAOf/8JnRiMMcZ0vUSuSjLGGBMHlhiMMca0Y4nBGGNMO5YYjDHGtGOJwRhjTDuWGIwxxrRjicEYY0w7lhiMJ0QkX0Suj1r+V5yOUyQilx9m+/0iMr2T9Vki8pbbvXunY2G46w85JsihtnXHOCIicpuIfO8I+7T7N4jx8zNE5O2o7ihMErHEYLySDxwolFT1U3E6ztnApMNsPwV4r5P11wLPuh3XQSdjYRxuTJBDbeth44jkE/VvEAu3q/s3gEMmXZO4LDEYr9wFHOeORvULEakHp0ttEVkvIg+LyEYReUxEzhGRd91Rqqa2fYCIfFGcUc1WiMgDbb/uo7afBvwSuMTdZ0SH7eOAjVGFf7R/I6rfmUOMhXG4MUEOte2I44i430H0KH3fE5HbOnw/j4nIOhF5RkSy3W23ut/ZO8CYqPc/73bVvCaqu+aP/Rsc6jt1++l5UZzR41ZHXYE9735PJslYYjBeuRnY7I5G9R8dto0E7sHpVnoscBVwGvA9nP6R2gr1y4HpqnoSEKZDIaWq7+B0tjjbPc6WDseZBbzSMTC3U8YRqrr1COdwuDFBDrWtK8YRGQP8RlXHAbXA9SIyGadzuZOA84ApUftfq6qTgVLgRrd/Hejwb3CY73QmsFNVJ6rqCRz8zlZ3OI5JElY/aHqij1R1FYCIrMEZulBFZBVQ4u5zNjAZWOx0vEoWnXc5PAZY38l6gM8C13Syvh9QfazBd4MyVX3Xnf8TcCPO0KfPqWojgIhE9zR8o4hc5M4XA6OAyk4+91Df6Z+Be0Tk58DfVPWf4IwPISJBEcl1R9UzScISg+mJonvHjEQtRzj4NyvAH1X1lkN9iIj0A2qiRviK3pYN5Kvqzk7e2gQEjiLOw40JcqhtRzOOSIj2V/MdY+nY8+Uhe8J0eyI9BzhVVRtF5M1OPu/A7hziOxWRSThXIneIyBuqeru7KRNoPtTxTWKyqiTjlTog9xO8/w2ctoP+ACLSV0SGddinBOis4Af4NE5f/h+jqlWAT0SOlBwONybIobYdzTgiu4H+IlIgIpnABR22DxWRU935q4B3gLeBC927qXKBz7nb84AqNymMxWlsb9Px36DT71REBgONqvon4Be4jfluldQ+VW09wvdkEowlBuMJVa0E3nUbM39xDO9fC/wAZwzcD3DGQB7UYbf1QD/3GB3veuq0fSHKazjtGsCBsTAWAmNEpFxE5rhXIjcAr+IMmvOUqq5x4+t02+HeE3VurcDtwCL3vDpWhW0Aviki64A+wG9VdRnwJLASeBknAeGeY7q7711E3YHV8d/gMN/pBGCROONN/xi4w/2ITwMvHuY7NAnKxmMwKUlElgHTDvVr1606+Y6qfql7Izs8ESnBqec/oQfE8ixws6pu9DoW07XsisGkJFWddLgqEPcX+IKOt8Aah1sN9rwlheRkVwzGGGPasSsGY4wx7VhiMMYY044lBmOMMe1YYjDGGNOOJQZjjDHtWGIwxhjTjiUGY4wx7fx/M2FAm9TVYAcAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "overlap_hist = np.asarray(overlap_hist)\n", "plt.figure()\n", "for mu in range(M):\n", " plt.plot(overlap_hist[:,mu], label=r'$m^{%d}$' % (mu+1))\n", "plt.xlim(xmin=0)\n", "plt.xlabel(r'time $t$ / (1000 updates)')\n", "plt.ylabel(r'overlap $m^{\\mu}$')\n", "plt.legend(loc='upper left')\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "worse-morocco", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "It can be seen that the network moved quickly towards pattern 1, i.e., retrieving the first image. This is expected because the seed that we provided at the beginning was part of this very image." ] }, { "cell_type": "markdown", "id": "brilliant-hanging", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Since our patterns are images, it may be fun to watch how the image is changing over time as the network runs. So let us record the retrieval process as a movie, which can be done as follows." ] }, { "cell_type": "code", "execution_count": 11, "id": "fc260a46-cbb7-40c3-8e7c-055ae89780c8", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "import matplotlib.animation as anim\n", "\n", "plt.rcParams[\"animation.html\"] = \"jshtml\"\n", "fig, ax = plt.subplots(figsize=(2,2))\n", "ax.axis('off')\n", "\n", "net.set_network(state=seed)\n", "frame = vec2img(net.state, shape)\n", "img = ax.imshow(frame, cmap='Greys_r', interpolation='none')\n", "\n", "def animate(t):\n", " if t > 0:\n", " flip = net.updateN(size=1000)\n", " frame = vec2img(net.state, shape)\n", " img.set_data(frame)\n", "\n", "mov = anim.FuncAnimation(fig, animate, interval=100)\n", "# mov.save('figures/retrieve_img1.mp4', fps=10, extra_args=['-vcodec', 'libx264'])\n", "plt.close()" ] }, { "cell_type": "code", "execution_count": 12, "id": "8b25e6db-565b-430d-b976-ba879143f03c", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "
\n", " \n", "
\n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mov" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" } }, "nbformat": 4, "nbformat_minor": 5 }