├── .gitignore ├── LICENSE ├── README.md ├── fig_permuted_mnist ├── Figure permuted MNIST.ipynb ├── Permuted MNIST.ipynb └── data_path_int[omega_decay=sum,xi=0.1]_optadam_lr1.00e-03_bs256_ep20_tsks10.pkl.gz ├── fig_split_mnist └── Figure split MNIST.ipynb ├── fig_transfer_cifar ├── Figure barplot.ipynb ├── split_cifar10_data_path_int[omega_decay=sum,xi=0.001]_lr1.00e-03_ep60.pkl.gz └── train.py └── pathint ├── __init__.py ├── keras_utils.py ├── optimizers.py ├── protocols.py ├── regularizers.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ben Poole & Friedemann Zenke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Continual Learning Through Synaptic Intelligence 2 | 3 | This repository contains code to reproduce the key findings of our path integral approach to prevent catastrophic forgetting in continual learning. 4 | 5 | Zenke, F.1, Poole, B.1, and Ganguli, S. (2017). Continual Learning Through 6 | Synaptic Intelligence. In Proceedings of the 34th International Conference on 7 | Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention 8 | Centre, Sydney, Australia: PMLR), pp. 3987–3995. 9 | 10 | http://proceedings.mlr.press/v70/zenke17a.html 11 | 12 | 1) Equal contribution 13 | 14 | ## BibTeX 15 | ``` 16 | @InProceedings{pmlr-v70-zenke17a, 17 | title = {Continual Learning Through Synaptic Intelligence}, 18 | author = {Friedemann Zenke and Ben Poole and Surya Ganguli}, 19 | booktitle = {Proceedings of the 34th International Conference on Machine Learning}, 20 | pages = {3987--3995}, 21 | year = {2017}, 22 | editor = {Doina Precup and Yee Whye Teh}, 23 | volume = {70}, 24 | series = {Proceedings of Machine Learning Research}, 25 | address = {International Convention Centre, Sydney, Australia}, 26 | month = {06--11 Aug}, 27 | publisher = {PMLR}, 28 | pdf = {http://proceedings.mlr.press/v70/zenke17a/zenke17a.pdf}, 29 | url = {http://proceedings.mlr.press/v70/zenke17a.html}, 30 | } 31 | ``` 32 | 33 | 34 | ## Requirements 35 | 36 | We have tested this maintenance release (v1.1) with the following configuration: 37 | 38 | * Python 3.5.2 39 | * Jupyter 4.4.0 40 | * Tensorflow 1.10 41 | * Keras 2.2.2 42 | 43 | Kudos to Mitra (https://github.com/MitraDarja) for making our code conform with Keras 2.2.2! 44 | 45 | 46 | ### Earlier releases 47 | 48 | For the original release (v1.0) we used the following configuration of the libraries which were available at the time: 49 | 50 | * Python 3.5.2 51 | * Jupyter 4.3.0 52 | * Tensorflow 1.2.1 53 | * Keras 2.0.5 54 | 55 | To revert to such a environment we suggest using virtualenv (https://virtualenv.pypa.io): 56 | 57 | ``` 58 | virtualenv -p python3 env 59 | source env/bin/activate 60 | pip3 install -vI keras==2.0.5 61 | pip3 install jupyter matplotlib numpy tensorflow-gpu tqdm seaborn 62 | ``` 63 | -------------------------------------------------------------------------------- /fig_permuted_mnist/Figure permuted MNIST.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "# Copyright (c) 2017 Ben Poole & Friedemann Zenke\n", 12 | "# MIT License -- see LICENSE for details\n", 13 | "# \n", 14 | "# This file is part of the code to reproduce the core results of:\n", 15 | "# Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through\n", 16 | "# Synaptic Intelligence. In Proceedings of the 34th International Conference on\n", 17 | "# Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention\n", 18 | "# Centre, Sydney, Australia: PMLR), pp. 3987–3995.\n", 19 | "# http://proceedings.mlr.press/v70/zenke17a.html" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": { 26 | "collapsed": false 27 | }, 28 | "outputs": [ 29 | { 30 | "name": "stdout", 31 | "output_type": "stream", 32 | "text": [ 33 | "The autoreload extension is already loaded. To reload it, use:\n", 34 | " %reload_ext autoreload\n", 35 | "Populating the interactive namespace from numpy and matplotlib\n" 36 | ] 37 | }, 38 | { 39 | "name": "stderr", 40 | "output_type": "stream", 41 | "text": [ 42 | "Using TensorFlow backend.\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "%load_ext autoreload\n", 48 | "%autoreload 2\n", 49 | "%pylab inline\n", 50 | "\n", 51 | "import sys, os\n", 52 | "sys.path.extend([os.path.expanduser('..')])\n", 53 | "from pathint import utils\n", 54 | "import seaborn as sns\n", 55 | "sns.set_style(\"white\")\n", 56 | "\n", 57 | "# import operator\n", 58 | "import matplotlib.colors as colors\n", 59 | "import matplotlib.cm as cmx\n", 60 | "\n", 61 | "rcParams['pdf.fonttype'] = 42\n", 62 | "rcParams['ps.fonttype'] = 42" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 6, 68 | "metadata": { 69 | "collapsed": true 70 | }, 71 | "outputs": [], 72 | "source": [ 73 | "# Load data\n", 74 | "n_tasks = 10\n", 75 | "all_evals = utils.load_zipped_pickle(\"data_path_int[omega_decay=sum,xi=0.1]_optadam_lr1.00e-03_bs256_ep20_tsks10.pkl.gz\")" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 7, 81 | "metadata": { 82 | "collapsed": false 83 | }, 84 | "outputs": [ 85 | { 86 | "name": "stdout", 87 | "output_type": "stream", 88 | "text": [ 89 | "[ 0. 0.01 0.02 0.1 ]\n" 90 | ] 91 | } 92 | ], 93 | "source": [ 94 | "keys = list(all_evals.keys())\n", 95 | "sorted_keys = np.sort(keys)\n", 96 | "print(sorted_keys)" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 8, 102 | "metadata": { 103 | "collapsed": true 104 | }, 105 | "outputs": [], 106 | "source": [ 107 | "sns.set_context(\"paper\")\n", 108 | "sns.set_style('ticks')" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 9, 114 | "metadata": { 115 | "collapsed": true 116 | }, 117 | "outputs": [], 118 | "source": [ 119 | "plt.rc('text', usetex=False)\n", 120 | "plt.rc('xtick', labelsize=8)\n", 121 | "plt.rc('ytick', labelsize=8)\n", 122 | "plt.rc('axes', labelsize=8)" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 10, 128 | "metadata": { 129 | "collapsed": true 130 | }, 131 | "outputs": [], 132 | "source": [ 133 | "def simple_axis(ax):\n", 134 | " ax.spines['top'].set_visible(False)\n", 135 | " ax.spines['right'].set_visible(False)\n", 136 | " ax.get_xaxis().tick_bottom()\n", 137 | " ax.get_yaxis().tick_left()" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 11, 143 | "metadata": { 144 | "collapsed": true 145 | }, 146 | "outputs": [], 147 | "source": [ 148 | "def plot_data():\n", 149 | " marker = iter(['o', 's', 's', 'd', 'o'])\n", 150 | " plot_kwargs = dict(alpha=0.9)\n", 151 | " \n", 152 | " for cval in sorted_keys:\n", 153 | " stuff = []\n", 154 | " for i in range(len(all_evals[cval])):#n_tasks):\n", 155 | " stuff.append(all_evals[cval][i][:i+1].mean())\n", 156 | " plot(range(1,n_tasks+1), stuff, '%s-'%next(marker), label=\"Test (c=%g)\"%cval, zorder=2, **plot_kwargs)" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 12, 162 | "metadata": { 163 | "collapsed": false 164 | }, 165 | "outputs": [ 166 | { 167 | "data": { 168 | "image/png": "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\n", 169 | "text/plain": [ 170 | "" 171 | ] 172 | }, 173 | "metadata": {}, 174 | "output_type": "display_data" 175 | } 176 | ], 177 | "source": [ 178 | "fig = plt.figure(figsize=(3.3,2.4))\n", 179 | "# fig, ax = plt.subplots()\n", 180 | "# plt.rc('font', family='serif', serif='Times')\n", 181 | "gs = GridSpec(2, 1, height_ratios=[0.5, 1])\n", 182 | "ax = plt.subplot(gs[0])\n", 183 | "plot_data()\n", 184 | "# Training error for control network -- trained conventionally\n", 185 | "# plt.arrow(10.5, 0.995198, -0.2, 0, head_width=0.005, head_length=0.2, fc='k', ec='k')\n", 186 | "plt.tick_params(\n", 187 | " axis='x', # changes apply to the x-axis\n", 188 | " which='both', # both major and minor ticks are affected\n", 189 | " bottom='off', # ticks along the bottom edge are off\n", 190 | " top='off', # ticks along the top edge are off\n", 191 | " labelbottom='off')\n", 192 | "plt.tick_params(\n", 193 | " axis='y', # changes apply to the x-axis\n", 194 | " which='both', # both major and minor ticks are affected\n", 195 | " right='off', # ticks along the bottom edge are off\n", 196 | " left='on')\n", 197 | "\n", 198 | "\n", 199 | "ax.spines['top'].set_visible(False)\n", 200 | "ax.spines['right'].set_visible(False)\n", 201 | "ax.spines['bottom'].set_visible(False)\n", 202 | "# ax.get_yaxis().tick_left()\n", 203 | "ylim(0.965, 1.005)\n", 204 | "yticks([0.97, 1.0])\n", 205 | "xlim(0.5, 10.46)\n", 206 | "\n", 207 | "ax2 = plt.subplot(gs[1])\n", 208 | "plot_data()\n", 209 | "\n", 210 | "xlabel('Number of tasks')\n", 211 | "ylabel('Fraction correct')\n", 212 | "ylim(0.48, 1.02)\n", 213 | "xlim(0.5, 10.5)\n", 214 | "simple_axis(ax2)\n", 215 | "yticks([0.5, 0.75, 1.0])\n", 216 | "\n", 217 | "from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes\n", 218 | "\n", 219 | "legend(loc='lower left', fontsize=6)\n", 220 | "\n", 221 | "plt.subplots_adjust(left=.18, bottom=.20, right=.99, top=.97)\n", 222 | "plt.savefig(\"accuracy_vs_nbtasks.pdf\", pad_inches=0)" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": null, 228 | "metadata": { 229 | "collapsed": true 230 | }, 231 | "outputs": [], 232 | "source": [] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "metadata": { 238 | "collapsed": true 239 | }, 240 | "outputs": [], 241 | "source": [] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": null, 246 | "metadata": { 247 | "collapsed": true 248 | }, 249 | "outputs": [], 250 | "source": [] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": null, 255 | "metadata": { 256 | "collapsed": true 257 | }, 258 | "outputs": [], 259 | "source": [] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": null, 264 | "metadata": { 265 | "collapsed": true 266 | }, 267 | "outputs": [], 268 | "source": [] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": null, 273 | "metadata": { 274 | "collapsed": true 275 | }, 276 | "outputs": [], 277 | "source": [] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": null, 282 | "metadata": { 283 | "collapsed": true 284 | }, 285 | "outputs": [], 286 | "source": [] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": null, 291 | "metadata": { 292 | "collapsed": true 293 | }, 294 | "outputs": [], 295 | "source": [] 296 | } 297 | ], 298 | "metadata": { 299 | "kernelspec": { 300 | "display_name": "Python 3", 301 | "language": "python", 302 | "name": "python3" 303 | }, 304 | "language_info": { 305 | "codemirror_mode": { 306 | "name": "ipython", 307 | "version": 3 308 | }, 309 | "file_extension": ".py", 310 | "mimetype": "text/x-python", 311 | "name": "python", 312 | "nbconvert_exporter": "python", 313 | "pygments_lexer": "ipython3", 314 | "version": "3.5.2" 315 | } 316 | }, 317 | "nbformat": 4, 318 | "nbformat_minor": 1 319 | } 320 | -------------------------------------------------------------------------------- /fig_permuted_mnist/data_path_int[omega_decay=sum,xi=0.1]_optadam_lr1.00e-03_bs256_ep20_tsks10.pkl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ganguli-lab/pathint/86c5e07c5603d6a44c2f53585c19ee70773ef15c/fig_permuted_mnist/data_path_int[omega_decay=sum,xi=0.1]_optadam_lr1.00e-03_bs256_ep20_tsks10.pkl.gz -------------------------------------------------------------------------------- /fig_split_mnist/Figure split MNIST.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "# Copyright (c) 2017 Ben Poole & Friedemann Zenke\n", 12 | "# MIT License -- see LICENSE for details\n", 13 | "# \n", 14 | "# This file is part of the code to reproduce the core results of:\n", 15 | "# Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through\n", 16 | "# Synaptic Intelligence. In Proceedings of the 34th International Conference on\n", 17 | "# Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention\n", 18 | "# Centre, Sydney, Australia: PMLR), pp. 3987–3995.\n", 19 | "# http://proceedings.mlr.press/v70/zenke17a.html" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 10, 25 | "metadata": { 26 | "collapsed": false, 27 | "scrolled": false 28 | }, 29 | "outputs": [ 30 | { 31 | "name": "stdout", 32 | "output_type": "stream", 33 | "text": [ 34 | "The autoreload extension is already loaded. To reload it, use:\n", 35 | " %reload_ext autoreload\n", 36 | "Populating the interactive namespace from numpy and matplotlib\n" 37 | ] 38 | }, 39 | { 40 | "name": "stderr", 41 | "output_type": "stream", 42 | "text": [ 43 | "/usr/local/lib/python3.5/dist-packages/IPython/core/magics/pylab.py:160: UserWarning: pylab import has clobbered these variables: ['colors']\n", 44 | "`%matplotlib` prevents importing * from pylab and numpy\n", 45 | " \"\\n`%matplotlib` prevents importing * from pylab and numpy\"\n" 46 | ] 47 | } 48 | ], 49 | "source": [ 50 | "%load_ext autoreload\n", 51 | "%autoreload 2\n", 52 | "%pylab inline\n", 53 | "\n", 54 | "import tensorflow as tf\n", 55 | "slim = tf.contrib.slim\n", 56 | "graph_replace = tf.contrib.graph_editor.graph_replace\n", 57 | "\n", 58 | "import sys, os\n", 59 | "sys.path.extend([os.path.expanduser('..')])\n", 60 | "from pathint import utils\n", 61 | "import seaborn as sns\n", 62 | "sns.set_style(\"ticks\")\n", 63 | "\n", 64 | "from tqdm import trange, tqdm\n", 65 | "\n", 66 | "# import operator\n", 67 | "import matplotlib.colors as colors\n", 68 | "import matplotlib.cm as cmx\n", 69 | "\n", 70 | "rcParams['pdf.fonttype'] = 42\n", 71 | "rcParams['ps.fonttype'] = 42" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "## Parameters" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 11, 84 | "metadata": { 85 | "collapsed": true 86 | }, 87 | "outputs": [], 88 | "source": [ 89 | "select = tf.select if hasattr(tf, 'select') else tf.where" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 12, 95 | "metadata": { 96 | "collapsed": true 97 | }, 98 | "outputs": [], 99 | "source": [ 100 | "# Data params\n", 101 | "input_dim = 784\n", 102 | "output_dim = 10\n", 103 | "\n", 104 | "# Network params\n", 105 | "n_hidden_units = 256\n", 106 | "activation_fn = tf.nn.relu\n", 107 | "\n", 108 | "# Optimization params\n", 109 | "batch_size = 64\n", 110 | "epochs_per_task = 10\n", 111 | "\n", 112 | "n_stats = 10\n", 113 | "\n", 114 | "# Reset optimizer after each age\n", 115 | "reset_optimizer = True" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "## Construct datasets" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 13, 128 | "metadata": { 129 | "collapsed": true 130 | }, 131 | "outputs": [], 132 | "source": [ 133 | "task_labels = [[0,1], [2,3]]#, [4,5], [6,7], [8,9]]\n", 134 | "task_labels = [[0,1], [2,3], [4,5], [6,7], [8,9]]\n", 135 | "# task_labels = [[0,1,2,3,4], [5,6,7,8,9]]\n", 136 | "n_tasks = len(task_labels)\n", 137 | "training_datasets = utils.construct_split_mnist(task_labels, split='train')\n", 138 | "validation_datasets = utils.construct_split_mnist(task_labels, split='test')\n", 139 | "# training_datasets = utils.mk_training_validation_splits(full_datasets, split_fractions=(0.9, 0.1))" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": {}, 145 | "source": [ 146 | "## Construct network, loss, and updates" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 14, 152 | "metadata": { 153 | "collapsed": true 154 | }, 155 | "outputs": [], 156 | "source": [ 157 | "tf.reset_default_graph()" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 15, 163 | "metadata": { 164 | "collapsed": true 165 | }, 166 | "outputs": [], 167 | "source": [ 168 | "config = tf.ConfigProto()\n", 169 | "config.gpu_options.allow_growth=True\n", 170 | "sess = tf.InteractiveSession(config=config)\n", 171 | "sess.run(tf.global_variables_initializer())" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": 9, 177 | "metadata": { 178 | "collapsed": true 179 | }, 180 | "outputs": [], 181 | "source": [ 182 | "# tf.equal(output_mask[None, :], 1.0)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 16, 188 | "metadata": { 189 | "collapsed": true 190 | }, 191 | "outputs": [], 192 | "source": [ 193 | "import keras.backend as K\n", 194 | "import keras.activations as activations\n", 195 | "\n", 196 | "output_mask = tf.Variable(tf.zeros(output_dim), name=\"mask\", trainable=False)\n", 197 | "\n", 198 | "def masked_softmax(logits):\n", 199 | " # logits are [batch_size, output_dim]\n", 200 | " x = select(tf.tile(tf.equal(output_mask[None, :], 1.0), [tf.shape(logits)[0], 1]), logits, -1e32 * tf.ones_like(logits))\n", 201 | " return activations.softmax(x)\n", 202 | "\n", 203 | "def set_active_outputs(labels):\n", 204 | " new_mask = np.zeros(output_dim)\n", 205 | " for l in labels:\n", 206 | " new_mask[l] = 1.0\n", 207 | " sess.run(output_mask.assign(new_mask))\n", 208 | " print(sess.run(output_mask))\n", 209 | " \n", 210 | "def masked_predict(model, data, targets):\n", 211 | " pred = model.predict(data)\n", 212 | " print(pred)\n", 213 | " acc = np.argmax(pred,1)==np.argmax(targets,1)\n", 214 | " return acc.mean()" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": 17, 220 | "metadata": { 221 | "collapsed": true 222 | }, 223 | "outputs": [], 224 | "source": [ 225 | "from keras.models import Sequential\n", 226 | "from keras.layers import Dense\n", 227 | "model = Sequential()\n", 228 | "model.add(Dense(n_hidden_units, activation=activation_fn, input_shape=(input_dim,)))\n", 229 | "model.add(Dense(n_hidden_units, activation=activation_fn))\n", 230 | "model.add(Dense(output_dim, kernel_initializer='zero', activation=masked_softmax))" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 9, 236 | "metadata": { 237 | "collapsed": true 238 | }, 239 | "outputs": [], 240 | "source": [ 241 | "from pathint import protocols\n", 242 | "from pathint.optimizers import KOOptimizer\n", 243 | "from keras.optimizers import Adam, RMSprop,SGD\n", 244 | "from keras.callbacks import Callback\n", 245 | "from pathint.keras_utils import LossHistory\n", 246 | "\n", 247 | "#protocol_name, protocol = protocols.PATH_INT_PROTOCOL(omega_decay='sum',xi=1e-3)\n", 248 | "protocol_name, protocol = protocols.PATH_INT_PROTOCOL(omega_decay='sum',xi=1e-3)\n", 249 | "# protocol_name, protocol = protocols.SUM_FISHER_PROTOCOL('sum')\n", 250 | "opt = Adam(lr=1e-3, beta_1=0.9, beta_2=0.999)\n", 251 | "# opt = SGD(1e-3)\n", 252 | "# opt = RMSprop(lr=1e-3)\n", 253 | "oopt = KOOptimizer(opt, model=model, **protocol)\n", 254 | "model.compile(loss='categorical_crossentropy', optimizer=oopt, metrics=['accuracy'])\n", 255 | "model._make_train_function()\n", 256 | "saved_weights = model.get_weights()\n", 257 | "\n", 258 | "history = LossHistory()\n", 259 | "callbacks = [history]\n", 260 | "datafile_name = \"split_mnist_data_%s.pkl.gz\"%protocol_name" 261 | ] 262 | }, 263 | { 264 | "cell_type": "markdown", 265 | "metadata": {}, 266 | "source": [ 267 | "## Train!" 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 10, 273 | "metadata": { 274 | "collapsed": true, 275 | "scrolled": true 276 | }, 277 | "outputs": [], 278 | "source": [ 279 | "# diag_vals = dict()\n", 280 | "# all_evals = dict()\n", 281 | "# data = utils.load_zipped_pickle(\"comparison_data_%s.pkl.gz\"%protocol_name)\n", 282 | "# returns empty dict if file not found\n", 283 | "\n", 284 | "def run_fits(cvals, training_data, valid_data, eval_on_train_set=False, nstats=1):\n", 285 | " acc_mean = dict()\n", 286 | " acc_std = dict()\n", 287 | " for cidx, cval_ in enumerate(tqdm(cvals)):\n", 288 | " runs = []\n", 289 | " for runid in range(nstats):\n", 290 | " sess.run(tf.global_variables_initializer())\n", 291 | " # model.set_weights(saved_weights)\n", 292 | " cstuffs = []\n", 293 | " evals = []\n", 294 | " print(\"setting cval\")\n", 295 | " cval = cval_\n", 296 | " oopt.set_strength(cval)\n", 297 | " oopt.init_task_vars()\n", 298 | " print(\"cval is\", sess.run(oopt.lam))\n", 299 | " for age, tidx in enumerate(range(n_tasks)):\n", 300 | " print(\"Age %i, cval is=%f\"%(age,cval))\n", 301 | " print(\"settint output mask\")\n", 302 | " set_active_outputs(task_labels[age])\n", 303 | " stuffs = model.fit(training_data[tidx][0], training_data[tidx][1], batch_size, epochs_per_task, callbacks=callbacks)\n", 304 | " oopt.update_task_metrics(training_data[tidx][0], training_data[tidx][1], batch_size)\n", 305 | " oopt.update_task_vars()\n", 306 | " ftask = []\n", 307 | " for j in range(n_tasks):\n", 308 | " set_active_outputs(task_labels[j])\n", 309 | " if eval_on_train_set:\n", 310 | " f_ = masked_predict(model, training_data[j][0], training_data[j][1])\n", 311 | " else:\n", 312 | " f_ = masked_predict(model, valid_data[j][0], valid_data[j][1])\n", 313 | " ftask.append(np.mean(f_))\n", 314 | " evals.append(ftask)\n", 315 | " cstuffs.append(stuffs)\n", 316 | "\n", 317 | " # Re-initialize optimizater variables\n", 318 | " if reset_optimizer:\n", 319 | " oopt.reset_optimizer()\n", 320 | "\n", 321 | " evals = np.array(evals)\n", 322 | " runs.append(evals)\n", 323 | " \n", 324 | " runs = np.array(runs)\n", 325 | " acc_mean[cval_] = runs.mean(0)\n", 326 | " acc_std[cval_] = runs.std(0)\n", 327 | " return dict(mean=acc_mean, std=acc_std)\n" 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": 11, 333 | "metadata": { 334 | "collapsed": false 335 | }, 336 | "outputs": [ 337 | { 338 | "name": "stdout", 339 | "output_type": "stream", 340 | "text": [ 341 | "[0, 1.0]\n" 342 | ] 343 | } 344 | ], 345 | "source": [ 346 | "# cvals = np.concatenate(([0], np.logspace(-2, 2, 10)))\n", 347 | "# cvals = np.concatenate(([0], np.logspace(-1, 2, 2)))\n", 348 | "# cvals = np.concatenate(([0], np.logspace(-2, 0, 3)))\n", 349 | "cvals = np.logspace(-3, 3, 7)#[0, 1.0, 2, 5, 10]\n", 350 | "cvals = [0, 1.0]\n", 351 | "print(cvals)\n" 352 | ] 353 | }, 354 | { 355 | "cell_type": "code", 356 | "execution_count": 12, 357 | "metadata": { 358 | "collapsed": true 359 | }, 360 | "outputs": [], 361 | "source": [ 362 | "%%capture\n", 363 | "\n", 364 | "recompute_data = True\n", 365 | "\n", 366 | "if recompute_data:\n", 367 | " data = run_fits(cvals, training_datasets, validation_datasets, eval_on_train_set=True, nstats=n_stats)\n", 368 | " utils.save_zipped_pickle(data, datafile_name)" 369 | ] 370 | }, 371 | { 372 | "cell_type": "code", 373 | "execution_count": 13, 374 | "metadata": { 375 | "collapsed": false 376 | }, 377 | "outputs": [ 378 | { 379 | "name": "stdout", 380 | "output_type": "stream", 381 | "text": [ 382 | "[0, 1.0]\n" 383 | ] 384 | } 385 | ], 386 | "source": [ 387 | "data = utils.load_zipped_pickle(datafile_name)\n", 388 | "print(cvals)" 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "execution_count": 14, 394 | "metadata": { 395 | "collapsed": false 396 | }, 397 | "outputs": [ 398 | { 399 | "name": "stdout", 400 | "output_type": "stream", 401 | "text": [ 402 | "(-5, 0.0)\n" 403 | ] 404 | } 405 | ], 406 | "source": [ 407 | "cmap = plt.get_cmap('cool') \n", 408 | "cNorm = colors.Normalize(vmin=-5, vmax=np.log(np.max(list(data['mean'].keys()))))\n", 409 | "scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cmap)\n", 410 | "print(scalarMap.get_clim())" 411 | ] 412 | }, 413 | { 414 | "cell_type": "code", 415 | "execution_count": 15, 416 | "metadata": { 417 | "collapsed": false 418 | }, 419 | "outputs": [ 420 | { 421 | "name": "stderr", 422 | "output_type": "stream", 423 | "text": [ 424 | "/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:13: RuntimeWarning: divide by zero encountered in log\n", 425 | " del sys.path[0]\n", 426 | "/usr/local/lib/python3.5/dist-packages/matplotlib/axes/_axes.py:545: UserWarning: No labelled objects found. Use label='...' kwarg on individual plots.\n", 427 | " warnings.warn(\"No labelled objects found. \"\n" 428 | ] 429 | }, 430 | { 431 | "data": { 432 | "image/png": "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\n", 433 | "text/plain": [ 434 | "" 435 | ] 436 | }, 437 | "metadata": {}, 438 | "output_type": "display_data" 439 | } 440 | ], 441 | "source": [ 442 | "figure(figsize=(14, 2.5))\n", 443 | "axs = [subplot(1,n_tasks+1,1)]#, None, None]\n", 444 | "for i in range(1, n_tasks + 1):\n", 445 | " axs.append(subplot(1, n_tasks+1, i+1, sharex=axs[0], sharey=axs[0]))\n", 446 | " \n", 447 | "keys = list(data['mean'].keys())\n", 448 | "sorted_keys = np.sort(keys)\n", 449 | "\n", 450 | "for cval in sorted_keys:\n", 451 | " mean_vals = data['mean'][cval]\n", 452 | " std_vals = data['std'][cval]\n", 453 | " for j in range(n_tasks):\n", 454 | " colorVal = scalarMap.to_rgba(np.log(cval))\n", 455 | " # axs[j].plot(evals[:, j], c=colorVal)\n", 456 | " axs[j].errorbar(range(n_tasks), mean_vals[:, j], yerr=std_vals[:, j]/np.sqrt(n_stats), c=colorVal)\n", 457 | " label = \"c=%g\"%cval\n", 458 | " average = mean_vals.mean(1)\n", 459 | " axs[-1].plot(average, c=colorVal, label=label)\n", 460 | " \n", 461 | "for i, ax in enumerate(axs):\n", 462 | " ax.legend(loc='best')\n", 463 | " ax.set_title((['task %d'%j for j in range(n_tasks)] + ['average'])[i])\n", 464 | "gcf().tight_layout()\n", 465 | "sns.despine()" 466 | ] 467 | }, 468 | { 469 | "cell_type": "code", 470 | "execution_count": 16, 471 | "metadata": { 472 | "collapsed": true 473 | }, 474 | "outputs": [], 475 | "source": [ 476 | "plt.rc('text', usetex=False)\n", 477 | "plt.rc('xtick', labelsize=8)\n", 478 | "plt.rc('ytick', labelsize=8)\n", 479 | "plt.rc('axes', labelsize=8)\n", 480 | "\n", 481 | "def simple_axis(ax):\n", 482 | " ax.spines['top'].set_visible(False)\n", 483 | " ax.spines['right'].set_visible(False)\n", 484 | " ax.get_xaxis().tick_bottom()\n", 485 | " ax.get_yaxis().tick_left()" 486 | ] 487 | }, 488 | { 489 | "cell_type": "code", 490 | "execution_count": 17, 491 | "metadata": { 492 | "collapsed": false 493 | }, 494 | "outputs": [ 495 | { 496 | "data": { 497 | "image/png": "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\n", 498 | "text/plain": [ 499 | "" 500 | ] 501 | }, 502 | "metadata": {}, 503 | "output_type": "display_data" 504 | } 505 | ], 506 | "source": [ 507 | "fig = plt.figure(figsize=(3.3,2.5))\n", 508 | "ax = plt.subplot(111)\n", 509 | "\n", 510 | "for cval in sorted_keys:\n", 511 | " mean_stuff = []\n", 512 | " std_stuff = []\n", 513 | " for i in range(len(data['mean'][cval])):\n", 514 | " mean_stuff.append(data['mean'][cval][i][:i+1].mean())\n", 515 | " std_stuff.append(np.sqrt((data['std'][cval][i][:i+1]**2).sum())/(n_stats*np.sqrt(n_stats)))\n", 516 | " # plot(range(1,n_tasks+1), mean_stuff, 'o-', label=\"c=%g\"%cval)\n", 517 | " errorbar(range(1,n_tasks+1), mean_stuff, yerr=std_stuff, fmt='o-', label=\"c=%g\"%cval)\n", 518 | " \n", 519 | "axhline(data['mean'][cval][0][0], linestyle='--', color='k')\n", 520 | "xlabel('Number of tasks')\n", 521 | "ylabel('Fraction correct')\n", 522 | "legend(loc='best')\n", 523 | "xlim(0.5, 5.5)\n", 524 | "ylim(0.7, 1.02)\n", 525 | "# grid('on')\n", 526 | "# sns.despine()\n", 527 | "simple_axis(ax)" 528 | ] 529 | }, 530 | { 531 | "cell_type": "code", 532 | "execution_count": 18, 533 | "metadata": { 534 | "collapsed": false 535 | }, 536 | "outputs": [ 537 | { 538 | "data": { 539 | "image/png": "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\n", 540 | "text/plain": [ 541 | "" 542 | ] 543 | }, 544 | "metadata": {}, 545 | "output_type": "display_data" 546 | } 547 | ], 548 | "source": [ 549 | "fig = plt.figure(figsize=(3.3,2.0))\n", 550 | "ax = plt.subplot(111)\n", 551 | "\n", 552 | "plot_keys =sorted(data['mean'].keys())# [0,1]\n", 553 | "\n", 554 | "for cval in plot_keys:\n", 555 | " mean_stuff = []\n", 556 | " std_stuff = []\n", 557 | " for i in range(len(data['mean'][cval])):\n", 558 | " mean_stuff.append(data['mean'][cval][i][:i+1].mean())\n", 559 | " std_stuff.append(np.sqrt((data['std'][cval][i][:i+1]**2).sum())/(n_stats*np.sqrt(n_stats)))\n", 560 | " # plot(range(1,n_tasks+1), mean_stuff, 'o-', label=\"c=%g\"%cval)\n", 561 | " errorbar(range(1,n_tasks+1), mean_stuff, yerr=std_stuff, fmt='o-', label=\"c=%g\"%cval)\n", 562 | " \n", 563 | "axhline(data['mean'][cval][0][0], linestyle=':', color='k')\n", 564 | "xlabel('Number of tasks')\n", 565 | "ylabel('Fraction correct')\n", 566 | "legend(loc='best', fontsize=8)\n", 567 | "xlim(0.5, 5.5)\n", 568 | "plt.yticks([0.6,0.8,1.0])\n", 569 | "ylim(0.6, 1.02)\n", 570 | "# grid('on')\n", 571 | "# sns.despine()\n", 572 | "simple_axis(ax)\n", 573 | "plt.subplots_adjust(left=.15, bottom=.18, right=.99, top=.97)\n", 574 | "plt.savefig(\"split_mnist_accuracy.pdf\")" 575 | ] 576 | }, 577 | { 578 | "cell_type": "code", 579 | "execution_count": 20, 580 | "metadata": { 581 | "collapsed": false, 582 | "scrolled": true 583 | }, 584 | "outputs": [ 585 | { 586 | "name": "stdout", 587 | "output_type": "stream", 588 | "text": [ 589 | "[0, 1.0]\n" 590 | ] 591 | }, 592 | { 593 | "data": { 594 | "image/png": "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\n", 595 | "text/plain": [ 596 | "" 597 | ] 598 | }, 599 | "metadata": {}, 600 | "output_type": "display_data" 601 | } 602 | ], 603 | "source": [ 604 | "figure(figsize=(7, 1.8))\n", 605 | "axs = [subplot(1,n_tasks+1,1)]\n", 606 | "for i in range(1,n_tasks+1):\n", 607 | " axs.append(subplot(1, n_tasks+1, i+1, sharex=axs[0], sharey=axs[0]))\n", 608 | "fmts = ['o', 's']\n", 609 | "\n", 610 | "plot_keys =sorted(data['mean'].keys())\n", 611 | "# plot_keys = [0]\n", 612 | "print(plot_keys)\n", 613 | "\n", 614 | "for i, cval in enumerate(plot_keys):\n", 615 | " label = \"c=%g\"%cval\n", 616 | " mean_vals = data['mean'][cval]\n", 617 | " std_vals = data['std'][cval]\n", 618 | " for j in range(n_tasks+1):\n", 619 | " sca(axs[j])\n", 620 | " errorbar_kwargs = dict(fmt=\"%s-\"%fmts[i], markersize=5)\n", 621 | " if j < n_tasks:\n", 622 | " # print(j,mean_vals[:, j])\n", 623 | " norm= np.sqrt(n_stats) # np.sqrt(n_stats) for SEM or 1 for STDEV\n", 624 | " axs[j].errorbar(np.arange(n_tasks)+1, mean_vals[:, j], yerr=std_vals[:, j]/norm, label=label, **errorbar_kwargs)\n", 625 | " else:\n", 626 | " mean_stuff = []\n", 627 | " std_stuff = []\n", 628 | " for i in range(len(data['mean'][cval])):\n", 629 | " mean_stuff.append(data['mean'][cval][i][:i+1].mean())\n", 630 | " #std_stuff.append(data['mean'][cval][i][:i+1].std()/np.sqrt(n_stats))\n", 631 | " std_stuff.append(np.sqrt((data['std'][cval][i][:i+1]**2).sum())/(n_stats*np.sqrt(n_stats)))\n", 632 | " # plot(range(1,n_tasks+1), mean_stuff, 'o-', label=\"c=%g\"%cval)\n", 633 | " errorbar(range(1,n_tasks+1), mean_stuff, yerr=std_stuff, label=\"c=%g\"%cval, **errorbar_kwargs)\n", 634 | " plt.xticks(np.arange(5)+1)\n", 635 | " plt.xlim((1.0,5.5))\n", 636 | " if j == 0:\n", 637 | " axs[j].set_yticks([0.5,1])\n", 638 | " else:\n", 639 | " setp(axs[j].get_yticklabels(), visible=False)\n", 640 | " plt.ylim((0.45,1.1))\n", 641 | "\n", 642 | "for i, ax in enumerate(axs):\n", 643 | " if i < n_tasks:\n", 644 | " ax.set_title((['Task %d (%d or %d)'%(j+1,task_labels[j][0], task_labels[j][1]) for j in range(n_tasks)] + ['average'])[i], fontsize=8)\n", 645 | " else:\n", 646 | " ax.set_title(\"Average\", fontsize=8)\n", 647 | " #ax.set_title((['Task %d'%(j+1) for j in xrange(n_tasks)] + ['average'])[i], fontsize=8)\n", 648 | " # ax.axhline(0.5, linestyle=':', color='k')\n", 649 | " ax.axhline(0.5, color='k', linestyle=':', label=\"chance\", zorder=0)\n", 650 | "handles, labels = axs[-1].get_legend_handles_labels()\n", 651 | "# Reorder legend so chance is last\n", 652 | "axs[-1].legend([handles[j] for j in [1,2,0]], [labels[j] for j in [1,2,0]], loc='lower right', fontsize=8, bbox_to_anchor=(-1.3, -.7), ncol=3, frameon=True)\n", 653 | "# axs[-1].legend(loc='lower right', fontsize=8, bbox_to_anchor=(-1.3, -.7), ncol=3, frameon=True)\n", 654 | " \n", 655 | "axs[0].set_xlabel(\"Tasks\")\n", 656 | "axs[0].set_ylabel(\"Accuracy\")\n", 657 | "gcf().tight_layout()\n", 658 | "sns.despine()\n", 659 | "plt.savefig(\"split_mnist_tasks.pdf\")" 660 | ] 661 | }, 662 | { 663 | "cell_type": "code", 664 | "execution_count": null, 665 | "metadata": { 666 | "collapsed": true 667 | }, 668 | "outputs": [], 669 | "source": [] 670 | }, 671 | { 672 | "cell_type": "code", 673 | "execution_count": null, 674 | "metadata": { 675 | "collapsed": true 676 | }, 677 | "outputs": [], 678 | "source": [] 679 | } 680 | ], 681 | "metadata": { 682 | "kernelspec": { 683 | "display_name": "Python 3", 684 | "language": "python", 685 | "name": "python3" 686 | }, 687 | "language_info": { 688 | "codemirror_mode": { 689 | "name": "ipython", 690 | "version": 3 691 | }, 692 | "file_extension": ".py", 693 | "mimetype": "text/x-python", 694 | "name": "python", 695 | "nbconvert_exporter": "python", 696 | "pygments_lexer": "ipython3", 697 | "version": "3.5.2" 698 | } 699 | }, 700 | "nbformat": 4, 701 | "nbformat_minor": 2 702 | } 703 | -------------------------------------------------------------------------------- /fig_transfer_cifar/Figure barplot.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "# Copyright (c) 2017 Ben Poole & Friedemann Zenke\n", 12 | "# MIT License -- see LICENSE for details\n", 13 | "# \n", 14 | "# This file is part of the code to reproduce the core results of:\n", 15 | "# Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through\n", 16 | "# Synaptic Intelligence. In Proceedings of the 34th International Conference on\n", 17 | "# Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention\n", 18 | "# Centre, Sydney, Australia: PMLR), pp. 3987–3995.\n", 19 | "# http://proceedings.mlr.press/v70/zenke17a.html" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 19, 25 | "metadata": { 26 | "collapsed": false 27 | }, 28 | "outputs": [ 29 | { 30 | "name": "stdout", 31 | "output_type": "stream", 32 | "text": [ 33 | "Populating the interactive namespace from numpy and matplotlib\n" 34 | ] 35 | }, 36 | { 37 | "name": "stderr", 38 | "output_type": "stream", 39 | "text": [ 40 | "/usr/local/lib/python3.5/dist-packages/IPython/core/magics/pylab.py:160: UserWarning: pylab import has clobbered these variables: ['colors']\n", 41 | "`%matplotlib` prevents importing * from pylab and numpy\n", 42 | " \"\\n`%matplotlib` prevents importing * from pylab and numpy\"\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "%pylab inline" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 20, 53 | "metadata": { 54 | "collapsed": true 55 | }, 56 | "outputs": [], 57 | "source": [ 58 | "import sys, os\n", 59 | "sys.path.extend([os.path.expanduser('..')])\n", 60 | "from pathint import utils\n", 61 | "import seaborn as sns\n", 62 | "\n", 63 | "rcParams['pdf.fonttype'] = 42\n", 64 | "rcParams['ps.fonttype'] = 42" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 21, 70 | "metadata": { 71 | "collapsed": true 72 | }, 73 | "outputs": [], 74 | "source": [ 75 | "datafile_name = \"split_cifar10_data_path_int[omega_decay=sum,xi=0.001]_lr1.00e-03_ep60.pkl.gz\"\n", 76 | "# backup all_evals to disk\n", 77 | "# all_evals = dict() # uncomment to delete on disk\n", 78 | "data = utils.load_zipped_pickle( datafile_name )" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 22, 84 | "metadata": { 85 | "collapsed": true 86 | }, 87 | "outputs": [], 88 | "source": [ 89 | "colors = (sns.color_palette(\"deep\"))\n", 90 | "colors[2] = 'lightgray'" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 23, 96 | "metadata": { 97 | "collapsed": false 98 | }, 99 | "outputs": [ 100 | { 101 | "data": { 102 | "image/png": "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\nnqZHJdcAAAAASUVORK5CYII=\n", 103 | "text/plain": [ 104 | "" 105 | ] 106 | }, 107 | "metadata": {}, 108 | "output_type": "display_data" 109 | } 110 | ], 111 | "source": [ 112 | "sns.set_style('ticks')\n", 113 | "figure(figsize=(3.3, 2.2))\n", 114 | "ax = axes()\n", 115 | "cval = 0.01 # orig value\n", 116 | "cvals = [0, cval, 'scratch']\n", 117 | "# cvals = [cval]\n", 118 | "# cvals = [0, cval]\n", 119 | "n_tasks = 6\n", 120 | "group_width = 0.8\n", 121 | "bar_width = group_width/len(cvals)\n", 122 | "bar_width = group_width/3\n", 123 | "index = np.arange(n_tasks)\n", 124 | "xtick_labels = ['Task %i'%(i+1) for i in range(n_tasks)]\n", 125 | "# xtick_labels[0] = 'CIFAR10'\n", 126 | "\n", 127 | "def do_plot(eval_type=0, age=-1):\n", 128 | " for k,cv in enumerate(cvals):\n", 129 | " means = []\n", 130 | " stdevs = []\n", 131 | " # print(cv)\n", 132 | " for tid in range(n_tasks):\n", 133 | " if cv=='scratch':\n", 134 | " a = tid\n", 135 | " else:\n", 136 | " a = age\n", 137 | " means.append( data['mean'][cv][a, tid, eval_type] )\n", 138 | " stdevs.append( data['std'][cv][a, tid, eval_type] )\n", 139 | " # print(means)\n", 140 | " \n", 141 | " bar(index+k*bar_width, means, width=bar_width, yerr=stdevs, color=colors[k], ecolor='gray')\n", 142 | " xticks(index)\n", 143 | " # gca().set_xticklabels()\n", 144 | " if eval_type==0:\n", 145 | " ylabel('Validation accuracy')\n", 146 | " else:\n", 147 | " ylabel('Training accuracy')\n", 148 | " xticks(index+group_width/2, xtick_labels, fontsize=8)\n", 149 | " xlim(-0.1, 6.0)\n", 150 | " # ylim(0.5, 1.0)\n", 151 | " yticks(np.arange(0.0, 1.1, 0.2))\n", 152 | " legend(('Fine tuning', 'Consolidation', 'From scratch'), bbox_to_anchor=(0., 1.02, 1., .102), loc=3,\n", 153 | " ncol=2, mode='expand', borderaxespad=0., fontsize=8)\n", 154 | " \n", 155 | " ax.annotate('CIFAR10', xy=(0.27, 0.12), xytext=(0.27, 0.02), xycoords='figure fraction', \n", 156 | " fontsize=8, ha='center', va='bottom',\n", 157 | " bbox=dict(boxstyle='square', fc='white'),\n", 158 | " arrowprops=dict(arrowstyle='-[, widthB=1.7, lengthB=0.5', lw=1.0))\n", 159 | "\n", 160 | " ax.annotate('CIFAR100, 10 classes per task', xy=(0.66, 0.12), xytext=(0.66, 0.02), xycoords='figure fraction', \n", 161 | " fontsize=8, ha='center', va='bottom',\n", 162 | " bbox=dict(boxstyle='square', fc='white'),\n", 163 | " arrowprops=dict(arrowstyle='-[, widthB=9.4, lengthB=0.5', lw=1.0))\n", 164 | "\n", 165 | "do_plot(eval_type=0)\n", 166 | "sns.despine()\n", 167 | "subplots_adjust(left=.21, bottom=.25, right=.98, top=.82)\n", 168 | "savefig(\"cifar10_cifar100_transfer_valid.pdf\")" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": 24, 174 | "metadata": { 175 | "collapsed": false 176 | }, 177 | "outputs": [ 178 | { 179 | "data": { 180 | "image/png": "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\n", 181 | "text/plain": [ 182 | "" 183 | ] 184 | }, 185 | "metadata": {}, 186 | "output_type": "display_data" 187 | } 188 | ], 189 | "source": [ 190 | "sns.set_style('ticks')\n", 191 | "figure(figsize=(3.3, 2.2))\n", 192 | "ax = axes()\n", 193 | "do_plot(eval_type=1)\n", 194 | "sns.despine()\n", 195 | "subplots_adjust(left=.21, bottom=.25, right=.98, top=.82)\n", 196 | "savefig(\"cifar10_cifar100_transfer_train.pdf\")" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": { 203 | "collapsed": true 204 | }, 205 | "outputs": [], 206 | "source": [] 207 | } 208 | ], 209 | "metadata": { 210 | "kernelspec": { 211 | "display_name": "Python 3", 212 | "language": "python", 213 | "name": "python3" 214 | }, 215 | "language_info": { 216 | "codemirror_mode": { 217 | "name": "ipython", 218 | "version": 3 219 | }, 220 | "file_extension": ".py", 221 | "mimetype": "text/x-python", 222 | "name": "python", 223 | "nbconvert_exporter": "python", 224 | "pygments_lexer": "ipython3", 225 | "version": "3.5.2" 226 | } 227 | }, 228 | "nbformat": 4, 229 | "nbformat_minor": 2 230 | } 231 | -------------------------------------------------------------------------------- /fig_transfer_cifar/split_cifar10_data_path_int[omega_decay=sum,xi=0.001]_lr1.00e-03_ep60.pkl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ganguli-lab/pathint/86c5e07c5603d6a44c2f53585c19ee70773ef15c/fig_transfer_cifar/split_cifar10_data_path_int[omega_decay=sum,xi=0.001]_lr1.00e-03_ep60.pkl.gz -------------------------------------------------------------------------------- /fig_transfer_cifar/train.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (c) 2017 Ben Poole & Friedemann Zenke 3 | # MIT License -- see LICENSE for details 4 | # 5 | # This file is part of the code to reproduce the core results of: 6 | # Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through 7 | # Synaptic Intelligence. In Proceedings of the 34th International Conference on 8 | # Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention 9 | # Centre, Sydney, Australia: PMLR), pp. 3987-3995. 10 | # http://proceedings.mlr.press/v70/zenke17a.html 11 | # 12 | 13 | import sys, os 14 | sys.path.extend([os.path.expanduser('..')]) 15 | 16 | import numpy as np 17 | import matplotlib.pyplot as plt 18 | import matplotlib.colors as colors 19 | import matplotlib.cm as cmx 20 | 21 | import seaborn as sns 22 | sns.set_style("white") 23 | 24 | from tqdm import trange, tqdm 25 | 26 | import tensorflow as tf 27 | 28 | from pathint import protocols 29 | from pathint.optimizers import KOOptimizer 30 | from keras.optimizers import Adam, RMSprop, SGD 31 | from keras.callbacks import Callback 32 | import keras.backend as K 33 | import keras.activations as activations 34 | from keras.models import Sequential 35 | from keras.layers import Dense, Dropout, Activation, Flatten 36 | from keras.layers import Conv2D, MaxPooling2D 37 | 38 | from pathint import utils 39 | from pathint.keras_utils import LossHistory 40 | 41 | # ## Parameters 42 | 43 | # Data params 44 | 45 | # Network params 46 | input_shape = (3,32,32) 47 | 48 | # size of pooling area for max pooling 49 | pool_size = (2, 2) 50 | 51 | # convolution kernel size 52 | kernel_size = (3, 3) 53 | 54 | # Optimization parameters 55 | batch_size = 256 56 | epochs_per_task = 60 57 | learning_rate = 1e-3 58 | nstats = 1 # repeats of experiment to compute stdev 59 | 60 | 61 | add_evals=False # Saves evals accross runs 62 | cvals = ['scratch', 0, 0.01, 0.05, 0.1, 0.2] 63 | cvals = ['scratch', 0, 0.01, 0.1] 64 | print("cvals %s"%cvals) 65 | 66 | 67 | debug=False 68 | if debug: 69 | cvals = [0.1] 70 | epochs_per_task = 1 71 | nstats = 1 72 | 73 | # Reset optimizer after each age 74 | reset_optimizer = True 75 | 76 | 77 | # ## Construct datasets 78 | n_tasks = 6 79 | output_dim = 10*n_tasks 80 | nb_classes = output_dim 81 | # task_labels = [ range(i*10,(i+1)*10) for i in range(n_tasks) ] 82 | 83 | task_labels, training_datasets = utils.construct_transfer_cifar10_cifar100(n_tasks, split='train') 84 | _, validation_datasets = utils.construct_transfer_cifar10_cifar100(n_tasks, split='test') 85 | print(task_labels) 86 | 87 | # training_datasets = utils.construct_split_cifar10(task_labels, split='train') 88 | # validation_datasets = utils.construct_split_cifar10(task_labels, split='test') 89 | 90 | # ## Construct network, loss, and updates 91 | tf.reset_default_graph() 92 | 93 | config = tf.ConfigProto() 94 | config.gpu_options.allow_growth=True 95 | sess = tf.InteractiveSession(config=config) 96 | sess.run(tf.global_variables_initializer()) 97 | 98 | 99 | # Instantiate masking functions 100 | output_mask = tf.Variable(tf.zeros(output_dim), name="mask", trainable=False) 101 | 102 | select = tf.select if hasattr(tf, 'select') else tf.where 103 | 104 | def masked_softmax(logits): 105 | # logits are [batch_size, output_dim] 106 | x = select(tf.tile(tf.equal(output_mask[None, :], 1.0), [tf.shape(logits)[0], 1]), logits, -1e32 * tf.ones_like(logits)) 107 | return activations.softmax(x) 108 | 109 | def set_active_outputs(labels): 110 | new_mask = np.zeros(output_dim) 111 | for l in labels: 112 | new_mask[l] = 1.0 113 | sess.run(output_mask.assign(new_mask)) 114 | # print("setting output mask") 115 | # print(sess.run(output_mask)) 116 | 117 | def masked_predict(model, data, targets): 118 | pred = model.predict(data) 119 | # print(pred) 120 | acc = np.argmax(pred,1)==np.argmax(targets,1) 121 | return acc.mean() 122 | 123 | # Assemble the network model 124 | model = Sequential() 125 | 126 | model.add(Conv2D(32, (3, 3), padding='same', 127 | input_shape=training_datasets[0][0].shape[1:])) 128 | model.add(Activation('relu')) 129 | model.add(Conv2D(32, (3, 3))) 130 | model.add(Activation('relu')) 131 | model.add(MaxPooling2D(pool_size=(2, 2))) 132 | model.add(Dropout(0.25)) 133 | 134 | model.add(Conv2D(64, (3, 3), padding='same')) 135 | model.add(Activation('relu')) 136 | model.add(Conv2D(64, (3, 3))) 137 | model.add(Activation('relu')) 138 | model.add(MaxPooling2D(pool_size=(2, 2))) 139 | model.add(Dropout(0.25)) 140 | 141 | model.add(Flatten()) 142 | model.add(Dense(512)) 143 | model.add(Activation('relu')) 144 | model.add(Dropout(0.5)) 145 | # model.add(Dense(nb_classes)) 146 | model.add(Dense(nb_classes, kernel_initializer='zero', activation=masked_softmax)) 147 | 148 | 149 | # Define our training protocol 150 | protocol_name, protocol = protocols.PATH_INT_PROTOCOL(omega_decay='sum', xi=1e-3 ) 151 | opt = Adam(lr=learning_rate, beta_1=0.9, beta_2=0.999) 152 | # opt = RMSprop(lr=1e-3) 153 | # opt = SGD(1e-3) 154 | oopt = KOOptimizer(opt, model=model, **protocol) 155 | model.compile(loss='categorical_crossentropy', optimizer=oopt, metrics=['accuracy']) 156 | model._make_train_function() 157 | 158 | history = LossHistory() 159 | callbacks = [history] 160 | datafile_name = "split_cifar10_data_%s_lr%.2e_ep%i.pkl.gz"%(protocol_name, learning_rate, epochs_per_task) 161 | 162 | 163 | 164 | def run_fits(cvals, training_data, valid_data, nstats=1): 165 | acc_mean = dict() 166 | acc_std = dict() 167 | for cidx, cval_ in enumerate(cvals): 168 | runs = [] 169 | for runid in range(nstats): 170 | evals = [] 171 | sess.run(tf.global_variables_initializer()) 172 | # model.set_weights(saved_weights) 173 | cstuffs = [] 174 | if cval_=='scratch': 175 | print("Scratch mode -- inits net before each age") 176 | cval = 0 177 | else: 178 | print("setting cval") 179 | cval = cval_ 180 | oopt.set_strength(cval) 181 | oopt.init_task_vars() 182 | print("cval is %f"%sess.run(oopt.lam)) 183 | for age, tidx in enumerate(range(n_tasks)): 184 | if cval_=='scratch': 185 | sess.run(tf.global_variables_initializer()) 186 | oopt.reset_optimizer() 187 | print("Age %i, cval is=%f"%(age,cval)) 188 | set_active_outputs(task_labels[age]) 189 | stuffs = model.fit(training_data[tidx][0], training_data[tidx][1], batch_size, epochs_per_task, callbacks=callbacks, verbose=0) 190 | oopt.update_task_metrics(training_data[tidx][0], training_data[tidx][1], batch_size) 191 | oopt.update_task_vars() 192 | ftask = [] 193 | for j in range(n_tasks): 194 | set_active_outputs(task_labels[j]) 195 | train_err = masked_predict(model, training_data[j][0], training_data[j][1]) 196 | valid_err = masked_predict(model, valid_data[j][0], valid_data[j][1]) 197 | ftask.append( (np.mean(valid_err), np.mean(train_err)) ) 198 | evals.append(ftask) 199 | cstuffs.append(stuffs) 200 | 201 | # Re-initialize optimizater variables 202 | if reset_optimizer: 203 | oopt.reset_optimizer() 204 | 205 | evals = np.array(evals) 206 | runs.append(evals) 207 | 208 | runs = np.array(runs) 209 | acc_mean[cval_] = runs.mean(0) 210 | acc_std[cval_] = runs.std(0) 211 | return dict(mean=acc_mean, std=acc_std) 212 | 213 | 214 | # Run the sim 215 | data = run_fits(cvals, training_datasets, validation_datasets, nstats=nstats) 216 | 217 | 218 | # data = dict(mean={0.1:0.0}, std={0.1:0.0}) 219 | # print(data) 220 | if add_evals: 221 | old_data = utils.load_zipped_pickle(datafile_name) 222 | # returns empty dict if file not found 223 | for k in old_data.keys(): 224 | for l in old_data[k].keys(): 225 | data[k][l] = old_data[k][l] 226 | 227 | # Save the data 228 | utils.save_zipped_pickle(data, datafile_name) 229 | 230 | # To overwrite the data in the file uncomment this 231 | # all_evals = dict() # uncomment to delete on disk 232 | # utils.save_zipped_pickle(data, datafile_name) 233 | -------------------------------------------------------------------------------- /pathint/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ganguli-lab/pathint/86c5e07c5603d6a44c2f53585c19ee70773ef15c/pathint/__init__.py -------------------------------------------------------------------------------- /pathint/keras_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Ben Poole & Friedemann Zenke 2 | # MIT License -- see LICENSE for details 3 | # 4 | # This file is part of the code to reproduce the core results of: 5 | # Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through 6 | # Synaptic Intelligence. In Proceedings of the 34th International Conference on 7 | # Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention 8 | # Centre, Sydney, Australia: PMLR), pp. 3987-3995. 9 | # http://proceedings.mlr.press/v70/zenke17a.html 10 | # 11 | 12 | # Keras-specific functions and utils 13 | from keras.callbacks import Callback 14 | from keras.models import Model 15 | import keras.backend as K 16 | from keras.layers import Dense 17 | import tensorflow as tf 18 | 19 | class LossHistory(Callback): 20 | def __init__(self, *args, **kwargs): 21 | super(LossHistory, self).__init__(*args, **kwargs) 22 | self.losses = [] 23 | self.regs = [] 24 | 25 | def on_batch_end(self, batch, logs={}): 26 | self.losses.append(logs.get('loss')) 27 | self.regs.append(K.get_session().run(self.model.optimizer.regularizer)) 28 | 29 | 30 | # Create a callback that tracks FisherInformation 31 | from keras.models import Model 32 | import keras.backend as K 33 | def compute_fishers(model): 34 | # Check that model only contains Dense layers 35 | for l in model.layers: 36 | if not isinstance(l, Dense): 37 | raise ValueError("All layers of the model must be Dense, got %s"%l) 38 | # Create new model used to extract activations at each layer 39 | new_model = Model(inputs=model.input, outputs=[l.output for l in model.layers]) 40 | acts = new_model(model.input) 41 | 42 | out = acts[-1] 43 | out_dim = out.get_shape().as_list()[-1] 44 | #assert len(model.weights) %2 == 0 45 | n_weights = len(model.weights) // 2 46 | 47 | 48 | def _get_fishers(): 49 | fisher_weights = [0.0] * n_weights 50 | fisher_biases = [0.0] * n_weights 51 | for idx in range(out_dim): 52 | # Clips output 53 | # https://github.com/fchollet/keras/blob/master/keras/backend/tensorflow_backend.py#L2743 54 | output = out[:, idx] 55 | epsilon = tf.convert_to_tensor(x) 56 | if epsilon.dtype != output.dtype.base_dtype: 57 | epsilon = tf.cast(epsilon, output.dtype.base_dtype) 58 | 59 | output = tf.clip_by_value(output, epsilon, 1. - epsilon) 60 | y = K.log(output) 61 | # From the post-nonlinearity outputs of each layer, we walk back up through the graph 62 | # to find the linear activation corresponding to h=XW + b. 63 | # Then we identify the weights W, biases b, and previous activation X. 64 | # 1. TensorFlow can compute dy/dh, giving us a [batch_size, n_neurons] matrix 65 | # 2. We manually comute dy/dW=dy/dh X and dy/db=dy/dh 66 | # 3. We sum the squared Jacobians 67 | 68 | # Identify pre-nonlinearity activation corresponding to h=XW+b 69 | def _walk_up_until_add(x): 70 | if x.op.type == 'BiasAdd': 71 | return x 72 | elif x.op.type == 'Select': 73 | return x.op.inputs[1] 74 | else: 75 | return _walk_up_until_add(x.op.inputs[0]) 76 | 77 | linear = [_walk_up_until_add(a) for a in acts] 78 | # Identify previous activation, X 79 | prev_acts = [l.op.inputs[0].op.inputs[0] for l in linear] 80 | # Compute dy/dh 81 | dy_dlinear = [tf.gradients(y,l)[0] for l in linear] 82 | 83 | # Figure out which Jacobians correspond to which weights 84 | if idx == 0: 85 | val_to_var = {v.value():v for v in model.weights} 86 | weight_vars = [val_to_var[l.op.inputs[0].op.inputs[1]] for l in linear] 87 | bias_vars = [val_to_var[l.op.inputs[1]] for l in linear] 88 | 89 | # Compute the sum of the Jacobian squared 90 | # Because each of the Jacobians are rank-1, we can compute this by first squaring and then summing: 91 | # \sum_i (u_i v_i^T)^2 = \sum_i (u_i^2 (v_i^2)^T) 92 | weights_sum_jacobian_squared = [tf.matmul(tf.transpose(a)**2, dh**2) for dh,a in zip(dy_dlinear, prev_acts)] 93 | bias_sum_jacobian_squared = [tf.reduce_sum(dh**2, 0) for dh in dy_dlinear] 94 | # Keep track of aggregate across outputs 95 | for jj in range(n_weights): 96 | fisher_weights[jj] += weights_sum_jacobian_squared[jj] 97 | fisher_biases[jj] += bias_sum_jacobian_squared[jj] 98 | var_to_fisher = dict(zip(weight_vars+bias_vars, fisher_weights+fisher_biases)) 99 | return {w: var_to_fisher[w] for w in model.weights} 100 | 101 | fishers = _get_fishers() 102 | return fishers 103 | 104 | # Allocate space for accumulated Fisher 105 | avg_fishers = [K.zeros(w.get_shape().as_list()) for w in model.weights] 106 | # Create updates to reset avg fisher, update, etc. 107 | update_fishers = tf.group(*[tf.assign_add(avg_f, f) for avg_f, f in zip(avg_fishers, fishers)]) 108 | zero_fishers = tf.group(*[tf.assign(avg_f, 0.0 * avg_f) for avg_f in avg_fishers]) 109 | return fishers, avg_fishers, update_fishers, zero_fishers 110 | 111 | -------------------------------------------------------------------------------- /pathint/optimizers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Ben Poole & Friedemann Zenke 2 | # MIT License -- see LICENSE for details 3 | # 4 | # This file is part of the code to reproduce the core results of: 5 | # Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through 6 | # Synaptic Intelligence. In Proceedings of the 34th International Conference on 7 | # Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention 8 | # Centre, Sydney, Australia: PMLR), pp. 3987-3995. 9 | # http://proceedings.mlr.press/v70/zenke17a.html 10 | # 11 | """Optimization algorithms.""" 12 | 13 | import tensorflow as tf 14 | 15 | import numpy as np 16 | import keras 17 | from keras import backend as K 18 | from keras.optimizers import Optimizer 19 | from keras.callbacks import Callback 20 | from pathint.utils import extract_weight_changes, compute_updates 21 | from pathint.regularizers import quadratic_regularizer 22 | from collections import OrderedDict 23 | 24 | 25 | class KOOptimizer(Optimizer): 26 | """An optimizer whose loss depends on its own updates.""" 27 | 28 | def _allocate_var(self, name=None): 29 | return {w: K.zeros(w.get_shape(), name=name) for w in self.weights} 30 | 31 | def _allocate_vars(self, names): 32 | #TODO: add names, better shape/init checking 33 | self.vars = {name: self._allocate_var(name=name) for name in names} 34 | 35 | def __init__(self, opt, step_updates=[], task_updates=[], init_updates=[], task_metrics = {}, regularizer_fn=quadratic_regularizer, 36 | lam=1.0, model=None, compute_average_loss=False, compute_average_weights=False, **kwargs): 37 | """Instantiate an optimzier that depends on its own updates. 38 | 39 | Args: 40 | opt: Keras optimizer 41 | step_updates: OrderedDict or List of tuples 42 | Contains variable names and updates to be run at each step: 43 | (name, lambda vars, weight, prev_val: new_val). See below for details. 44 | task_updates: same as step_updates but run after each task 45 | init_updates: updates to be run before using the optimizer 46 | task_metrics: list of names of metrics to compute on full data/unionset after a task 47 | regularizer_fn (optional): function, takes in weights and variables returns scalar 48 | defaults to EWC regularizer 49 | lam: scalar penalty that multiplies the regularization term 50 | model: Keras model to be optimized. Needed to compute Fisher information 51 | compute_average_loss: compute EMA of the loss, default: False 52 | compute_average_weights: compute EMA of the weights, default: False 53 | 54 | Variables are created for each name in the task and step updates. Note that you cannot 55 | use the name 'grads', 'unreg_grads' or 'deltas' as those are reserved to contain the gradients 56 | of the full loss, loss without regularization, and the weight updates at each step. 57 | You can access them in the vars dict, e.g.: oopt.vars['grads'] 58 | 59 | The step and task update functions have the signature: 60 | def update_fn(vars, weight, prev_val): 61 | '''Compute the new value for a variable. 62 | Args: 63 | vars: optimization variables (OuroborosOptimzier.vars) 64 | weight: weight Variable in model that this variable is associated with. 65 | prev_val: previous value of this varaible 66 | Returns: 67 | Tensor representing the new value''' 68 | 69 | You can run both task and step updates on the same variable, allowing you to reset 70 | step variables after each task. 71 | """ 72 | super(KOOptimizer, self).__init__(**kwargs) 73 | if not isinstance(opt, keras.optimizers.Optimizer): 74 | raise ValueError("opt must be an instance of keras.optimizers.Optimizer but got %s"%type(opt)) 75 | if not isinstance(step_updates, OrderedDict): 76 | step_updates = OrderedDict(step_updates) 77 | if not isinstance(task_updates, OrderedDict): task_updates = OrderedDict(task_updates) 78 | if not isinstance(init_updates, OrderedDict): init_updates = OrderedDict(init_updates) 79 | # task_metrics 80 | self.names = set().union(step_updates.keys(), task_updates.keys(), task_metrics.keys()) 81 | if 'grads' in self.names or 'deltas' in self.names: 82 | raise ValueError("Optimization variables cannot be named 'grads' or 'deltas'") 83 | self.step_updates = step_updates 84 | self.task_updates = task_updates 85 | self.init_updates = init_updates 86 | self.compute_average_loss = compute_average_loss 87 | self.regularizer_fn = regularizer_fn 88 | # Compute loss and gradients 89 | self.lam = K.variable(value=lam, dtype=tf.float32, name="lam") 90 | self.nb_data = K.variable(value=1.0, dtype=tf.float32, name="nb_data") 91 | self.opt = opt 92 | #self.compute_fisher = compute_fisher 93 | #if compute_fisher and model is None: 94 | # raise ValueError("To compute Fisher information, you need to pass in a Keras model object ") 95 | self.model = model 96 | self.task_metrics = task_metrics 97 | self.compute_average_weights = compute_average_weights 98 | 99 | def set_strength(self, val): 100 | K.set_value(self.lam, val) 101 | 102 | def set_nb_data(self, nb): 103 | K.set_value(self.nb_data, nb) 104 | 105 | def get_updates(self, params,loss,model=None): 106 | self.weights = params 107 | # Allocate variables 108 | with tf.variable_scope("KOOptimizer"): 109 | self._allocate_vars(self.names) 110 | 111 | #grads = self.get_gradients(loss, params) 112 | 113 | # Compute loss and gradients 114 | self.regularizer = 0.0 if self.regularizer_fn is None else self.regularizer_fn(params, self.vars) 115 | self.initial_loss = loss 116 | self.loss = loss + self.lam * self.regularizer 117 | with tf.variable_scope("wrapped_optimizer"): 118 | self._weight_update_op, self._grads, self._deltas = compute_updates(self.opt, self.loss, params) 119 | 120 | wrapped_opt_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, "wrapped_optimizer") 121 | self.init_opt_vars = tf.variables_initializer(wrapped_opt_vars) 122 | 123 | self.vars['unreg_grads'] = dict(zip(params, tf.gradients(self.initial_loss, params))) 124 | # Compute updates 125 | self.vars['grads'] = dict(zip(params, self._grads)) 126 | self.vars['deltas'] = dict(zip(params, self._deltas)) 127 | # Keep a pointer to self in vars so we can use it in the updates 128 | self.vars['oopt'] = self 129 | # Keep number of data samples handy for normalization purposes 130 | self.vars['nb_data'] = self.nb_data 131 | 132 | if self.compute_average_weights: 133 | with tf.variable_scope("weight_emga") as scope: 134 | weight_ema = tf.train.ExponentialMovingAverage(decay=0.99, zero_debias=True) 135 | self.maintain_weight_averages_op = weight_ema.apply(self.weights) 136 | self.vars['average_weights'] = {w: weight_ema.average(w) for w in self.weights} 137 | self.weight_ema_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=scope.name) 138 | self.init_weight_ema_vars = tf.variables_initializer(self.weight_ema_vars) 139 | print(">>>>>") 140 | K.get_session().run(self.init_weight_ema_vars) 141 | if self.compute_average_loss: 142 | with tf.variable_scope("ema") as scope: 143 | ema = tf.train.ExponentialMovingAverage(decay=0.99, zero_debias=True) 144 | self.maintain_averages_op = ema.apply([self.initial_loss]) 145 | self.ema_loss = ema.average(self.initial_loss) 146 | self.prev_loss = tf.Variable(0.0, trainable=False, name="prev_loss") 147 | self.delta_loss = tf.Variable(0.0, trainable=False, name="delta_loss") 148 | self.ema_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=scope.name) 149 | self.init_ema_vars = tf.variables_initializer(self.ema_vars) 150 | # if self.compute_fisher: 151 | # self._fishers, _, _, _ = compute_fishers(self.model) 152 | # #fishers = compute_fisher_information(model) 153 | # self.vars['fishers'] = dict(zip(weights, self._fishers)) 154 | # #fishers, avg_fishers, update_fishers, zero_fishers = compute_fisher_information(model) 155 | 156 | def _var_update(vars, update_fn): 157 | updates = [] 158 | for w in params: 159 | updates.append(tf.assign(vars[w], update_fn(self.vars, w, vars[w]))) 160 | return tf.group(*updates) 161 | 162 | def _compute_vars_update_op(updates): 163 | # Force task updates to happen sequentially 164 | update_op = tf.no_op() 165 | for name, update_fn in updates.items(): 166 | with tf.control_dependencies([update_op]): 167 | update_op = _var_update(self.vars[name], update_fn) 168 | return update_op 169 | 170 | self._vars_step_update_op = _compute_vars_update_op(self.step_updates) 171 | self._vars_task_update_op = _compute_vars_update_op(self.task_updates) 172 | self._vars_init_update_op = _compute_vars_update_op(self.init_updates) 173 | 174 | # Create task-relevant update ops 175 | reset_ops = [] 176 | update_ops = [] 177 | for name, metric_fn in self.task_metrics.items(): 178 | metric = metric_fn(self) 179 | for w in params: 180 | reset_ops.append(tf.assign(self.vars[name][w], 0*self.vars[name][w])) 181 | update_ops.append(tf.assign_add(self.vars[name][w], metric[w])) 182 | self._reset_task_metrics_op = tf.group(*reset_ops) 183 | self._update_task_metrics_op = tf.group(*update_ops) 184 | 185 | # Each step we update the weights using the optimizer as well as the step-specific variables 186 | self.step_op = tf.group(self._weight_update_op, self._vars_step_update_op) 187 | self.updates.append(self.step_op) 188 | # After each task, run task-specific variable updates 189 | self.task_op = self._vars_task_update_op 190 | self.init_op = self._vars_init_update_op 191 | 192 | if self.compute_average_weights: 193 | self.updates.append(self.maintain_weight_averages_op) 194 | 195 | if self.compute_average_loss: 196 | self.update_loss_op = tf.assign(self.prev_loss, self.ema_loss) 197 | bupdates = self.updates 198 | with tf.control_dependencies(bupdates + [self.update_loss_op]): 199 | self.updates = [tf.group(*[self.maintain_averages_op])] 200 | self.delta_loss = self.prev_loss - self.ema_loss 201 | 202 | return self.updates#[self._base_updates 203 | 204 | def init_task_vars(self): 205 | K.get_session().run([self.init_op]) 206 | 207 | def init_acc_vars(self): 208 | K.get_session().run(self.init_ema_vars) 209 | 210 | def init_loss(self, X, y, batch_size): 211 | pass 212 | #sess = K.get_session() 213 | #xi, yi, sample_weights = self.model.model._standardize_user_data(X[:batch_size], y[:batch_size], batch_size=batch_size) 214 | #sess.run(tf.assign(self.prev_loss, self.initial_loss), {self.model.input:xi[0], self.model.model.targets[0]:yi[0], self.model.model.sample_weights[0]:sample_weights[0], K.learning_phase():1}) 215 | 216 | def update_task_vars(self): 217 | K.get_session().run(self.task_op) 218 | 219 | def update_task_metrics(self, X, y, batch_size): 220 | # Reset metric accumulators 221 | n_batch = len(X) // batch_size 222 | 223 | sess = K.get_session() 224 | sess.run(self._reset_task_metrics_op) 225 | for i in range(n_batch): 226 | xi, yi, sample_weights = self.model._standardize_user_data(X[i * batch_size:(i+1) * batch_size], y[i*batch_size:(i+1)*batch_size], batch_size=batch_size) 227 | sess.run(self._update_task_metrics_op, {self.model.input:xi[0], self.model.targets[0]:yi[0], self.model.sample_weights[0]:sample_weights[0]}) 228 | 229 | 230 | def reset_optimizer(self): 231 | """Reset the optimizer variables""" 232 | K.get_session().run(self.init_opt_vars) 233 | 234 | def get_config(self): 235 | raise ValueError("Write the get_config bro") 236 | 237 | def get_numvals_list(self, key='omega'): 238 | """ Returns list of numerical values such as for instance omegas in reproducible order """ 239 | variables = self.vars[key] 240 | numvals = [] 241 | for p in self.weights: 242 | numval = K.get_value(tf.reshape(variables[p],(-1,))) 243 | numvals.append(numval) 244 | return numvals 245 | 246 | def get_numvals(self, key='omega'): 247 | """ Returns concatenated list of numerical values such as for instance omegas in reproducible order """ 248 | conc = np.concatenate(self.get_numvals_list(key)) 249 | return conc 250 | 251 | def get_state(self): 252 | state = [] 253 | vs = self.vars 254 | for key in vs.keys(): 255 | if key=='oopt': continue 256 | v = vs[key] 257 | for p in v.values(): 258 | state.append(K.get_value(p)) # FIXME WhyTF does this not work? 259 | return state 260 | 261 | def set_state(self, state): 262 | c = 0 263 | vs = self.vars 264 | for key in vs.keys(): 265 | if key=='oopt': continue 266 | v = vs[key] 267 | for p in v.values(): 268 | K.set_value(p,state[c]) 269 | c += 1 270 | -------------------------------------------------------------------------------- /pathint/protocols.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Ben Poole & Friedemann Zenke 2 | # MIT License -- see LICENSE for details 3 | # 4 | # This file is part of the code to reproduce the core results of: 5 | # Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through 6 | # Synaptic Intelligence. In Proceedings of the 34th International Conference on 7 | # Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention 8 | # Centre, Sydney, Australia: PMLR), pp. 3987-3995. 9 | # http://proceedings.mlr.press/v70/zenke17a.html 10 | # 11 | from pathint.utils import ema 12 | from pathint.regularizers import quadratic_regularizer, get_power_regularizer 13 | from pathint.keras_utils import compute_fishers 14 | import tensorflow as tf 15 | import numpy as np 16 | 17 | """ 18 | A protocol is a function that takes as input some parameters and returns a tuple: 19 | (protocol_name, optimizer_kwargs) 20 | The protocol name is just a string that describes the protocol. 21 | The optimizer_kwargs is a dictionary that will get passed to KOOptimizer. It typically contains: 22 | step_updates, task_updates, task_metrics, regularizer_fn 23 | """ 24 | 25 | 26 | 27 | PATH_INT_PROTOCOL = lambda omega_decay, xi: ( 28 | 'path_int[omega_decay=%s,xi=%s]'%(omega_decay,xi), 29 | { 30 | 'init_updates': [ 31 | ('cweights', lambda vars, w, prev_val: w.value() ), 32 | ], 33 | 'step_updates': [ 34 | ('grads2', lambda vars, w, prev_val: prev_val -vars['unreg_grads'][w] * vars['deltas'][w] ), 35 | ], 36 | 'task_updates': [ 37 | ('omega', lambda vars, w, prev_val: tf.nn.relu( ema(omega_decay, prev_val, vars['grads2'][w]/((vars['cweights'][w]-w.value())**2+xi)) ) ), 38 | #('cached_grads2', lambda vars, w, prev_val: vars['grads2'][w]), 39 | #('cached_cweights', lambda vars, w, prev_val: vars['cweights'][w]), 40 | ('cweights', lambda opt, w, prev_val: w.value()), 41 | ('grads2', lambda vars, w, prev_val: prev_val*0.0 ), 42 | ], 43 | 'regularizer_fn': quadratic_regularizer, 44 | }) 45 | 46 | 47 | FISHER_PROTOCOL = lambda omega_decay:( 48 | 'fisher[omega_decay=%s]'%omega_decay, 49 | { 50 | 'task_updates': [ 51 | ('omega', lambda vars, w, prev_val: ema(omega_decay, prev_val, vars['task_fisher'][w]/vars['nb_data'])), 52 | ('cweights', lambda opt, w, prev_val: w.value()), 53 | ], 54 | 'task_metrics': { 55 | 'task_fisher': lambda opt: compute_fishers(opt.model), 56 | }, 57 | 'regularizer_fn': quadratic_regularizer, 58 | }) 59 | 60 | def sum_regularizer_fn(weights, vars): 61 | reg = 0.0 62 | for w in weights: 63 | reg += tf.reduce_sum(vars['sum_omega'][w] * w**2 64 | - 2 * vars['sum_omega_cweights'][w] * w 65 | + vars['sum_omega_cweights_squared'][w]) 66 | 67 | return reg 68 | 69 | -------------------------------------------------------------------------------- /pathint/regularizers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Ben Poole & Friedemann Zenke 2 | # MIT License -- see LICENSE for details 3 | # 4 | # This file is part of the code to reproduce the core results of: 5 | # Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through 6 | # Synaptic Intelligence. In Proceedings of the 34th International Conference on 7 | # Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention 8 | # Centre, Sydney, Australia: PMLR), pp. 3987-3995. 9 | # http://proceedings.mlr.press/v70/zenke17a.html 10 | # 11 | import tensorflow as tf 12 | 13 | def quadratic_regularizer(weights, vars, norm=2): 14 | """Compute the regularization term. 15 | 16 | Args: 17 | weights: list of Variables 18 | _vars: dict from variable name to dictionary containing the variables. 19 | Each set of variables is stored as a dictionary mapping from weights to variables. 20 | For example, vars['grads'][w] would retreive the 'grads' variable for weight w 21 | norm: power for the norm of the (weights - consolidated weight) 22 | 23 | Returns: 24 | scalar Tensor regularization term 25 | """ 26 | reg = 0.0 27 | for w in weights: 28 | reg += tf.reduce_sum(vars['omega'][w] * (w - vars['cweights'][w])**norm) 29 | return reg 30 | 31 | def get_power_regularizer(power=2.0): 32 | """Power regularizers with different norms""" 33 | def _regularizer_fn(weights, vars): 34 | return quadratic_regularizer(weights, vars, norm=power) 35 | return _regularizer_fn 36 | -------------------------------------------------------------------------------- /pathint/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Copyright (c) 2017 Ben Poole & Friedemann Zenke 3 | # MIT License -- see LICENSE for details 4 | # 5 | # This file is part of the code to reproduce the core results of: 6 | # Zenke, F., Poole, B., and Ganguli, S. (2017). Continual Learning Through 7 | # Synaptic Intelligence. In Proceedings of the 34th International Conference on 8 | # Machine Learning, D. Precup, and Y.W. Teh, eds. (International Convention 9 | # Centre, Sydney, Australia: PMLR), pp. 3987-3995. 10 | # http://proceedings.mlr.press/v70/zenke17a.html 11 | # 12 | """Utility functions for benchmarking online learning""" 13 | from __future__ import division 14 | import numpy as np 15 | import keras 16 | from keras.utils import np_utils 17 | 18 | from keras.datasets import mnist, cifar10, cifar100 19 | from keras.optimizers import Adam, RMSprop, SGD 20 | import keras.backend as K 21 | 22 | import pickle 23 | import gzip 24 | 25 | import tensorflow as tf 26 | 27 | def ema(decay, prev_val, new_val): 28 | """Compute exponential moving average. 29 | 30 | Args: 31 | decay: 'sum' to sum up values, otherwise decay in [0, 1] 32 | prev_val: previous value of accumulator 33 | new_val: new value 34 | Returns: 35 | updated accumulator 36 | """ 37 | if decay == 'sum': 38 | return prev_val + new_val 39 | return decay * prev_val + (1.0 - decay) * new_val 40 | 41 | def leak(decay, prev_val, new_val): 42 | """Compute leaky integrator. 43 | 44 | Like ema, but expectation value depends on decay time constant. 45 | 46 | Args: 47 | decay: 'sum' to sum up values, otherwise decay in [0, 1] 48 | prev_val: previous value of accumulator 49 | new_val: new value 50 | Returns: 51 | updated accumulator 52 | """ 53 | if decay == 'sum': 54 | return prev_val + new_val 55 | return decay * prev_val + new_val 56 | 57 | def extract_weight_changes(weights, update_ops): 58 | """Given a list of weights and Assign ops, identify the change in weights. 59 | 60 | Args: 61 | weights: list of Variables 62 | update_ops: list of Assign ops, typically computed using Keras' opt.get_updates() 63 | 64 | Returns: 65 | list of Tensors containing the weight update for each variable 66 | """ 67 | name_to_var = {v.name: v.value() for v in weights} 68 | weight_update_ops = list(filter(lambda x: x.op.inputs[0].name in name_to_var, update_ops)) 69 | nonweight_update_ops = list(filter(lambda x: x.op.inputs[0].name not in name_to_var, update_ops)) 70 | # Make sure that all the weight update ops are Assign ops 71 | for weight in weight_update_ops: 72 | if weight.op.type != 'Assign': 73 | raise ValueError('Update op for weight %s is not of type Assign.'%weight.op.inputs[0].name) 74 | weight_changes = [(new_w.op.inputs[1] - name_to_var[new_w.op.inputs[0].name]) for new_w, old_w in zip(weight_update_ops, weights)] 75 | # Recreate the update ops, ensuring that we compute the weight changes before updating the weights 76 | with tf.control_dependencies(weight_changes): 77 | new_weight_update_ops = [tf.assign(new_w.op.inputs[0], new_w.op.inputs[1]) for new_w in weight_update_ops] 78 | return weight_changes, tf.group(*(nonweight_update_ops + new_weight_update_ops)) 79 | 80 | 81 | def compute_updates(opt, loss, weights): 82 | update_ops = opt.get_updates(weights, [], loss) 83 | deltas, new_update_op = extract_weight_changes(weights, update_ops) 84 | grads = tf.gradients(loss, weights) 85 | # Make sure that deltas are computed _before_ the weight is updated 86 | return new_update_op, grads, deltas 87 | 88 | 89 | def split_dataset_by_labels(X, y, task_labels, nb_classes=None, multihead=False): 90 | """Split dataset by labels. 91 | 92 | Args: 93 | X: data 94 | y: labels 95 | task_labels: list of list of labels, one for each dataset 96 | nb_classes: number of classes (used to convert to one-hot) 97 | Returns: 98 | List of (X, y) tuples representing each dataset 99 | """ 100 | if nb_classes is None: 101 | nb_classes = len(np.unique(y)) 102 | datasets = [] 103 | for labels in task_labels: 104 | idx = np.in1d(y, labels) 105 | if multihead: 106 | label_map = np.arange(nb_classes) 107 | label_map[labels] = np.arange(len(labels)) 108 | data = X[idx], np_utils.to_categorical(label_map[y[idx]], len(labels)) 109 | else: 110 | data = X[idx], np_utils.to_categorical(y[idx], nb_classes) 111 | datasets.append(data) 112 | return datasets 113 | 114 | def split_dataset_randomly(X, y, nb_splits, nb_classes=None): 115 | """Split dataset by labels. 116 | 117 | Args: 118 | X: data 119 | y: labels 120 | nb_splits: number of splits to return 121 | task_labels: list of list of labels, one for each dataset 122 | nb_classes: number of classes (used to convert to one-hot) 123 | Returns: 124 | List of (X, y) tuples representing each dataset 125 | """ 126 | if nb_classes is None: 127 | nb_classes = len(np.unique(y)) 128 | datasets = [] 129 | idx = range(len(y)) 130 | np.random.shuffle(idx) 131 | split_size = len(y)//nb_splits 132 | for i in range(nb_splits): 133 | data = X[idx[split_size*i:split_size*(i+1)]], np_utils.to_categorical(y[idx[split_size*i:split_size*(i+1)]], nb_classes) 134 | datasets.append(data) 135 | return datasets 136 | 137 | def get_mnist_variations(dsetnames=['MNIST_Rotated', 'MNIST_Basic'], datashape=(-1,1,28,28), validationset_fraction=0.1, multihead=False): 138 | """ Uses skdata package to import some MNIST variations 139 | 140 | The following dataset names exist in skdata: 141 | all = ['MNIST_Basic', 142 | 'MNIST_BackgroundImages', 143 | 'MNIST_BackgroundRandom', 144 | 'MNIST_Rotated', 145 | 'MNIST_Noise1', 146 | 'MNIST_Noise2', 147 | 'MNIST_Noise3', 148 | 'MNIST_Noise4', 149 | 'MNIST_Noise5', 150 | 'MNIST_Noise6' ] 151 | 152 | args: 153 | dsetnames: the names of the data sets from above list 154 | datashape: tuple with shape of the data (default (-1,1,28,28) 155 | validationset_fraction: the fraction of data to hold out 156 | multihead: whether to generate a multihead dataset or a single head one 157 | 158 | returns: 159 | doublet of training and validation set each being a list of tasks consisting of (X,y) tuples 160 | """ 161 | 162 | from skdata import larochelle_etal_2007 as L2007 163 | def dset(name): 164 | rval = getattr(L2007, name)() 165 | return rval 166 | 167 | n_tasks = len(dsetnames) 168 | training_datasets = [] 169 | validation_datasets = [] 170 | 171 | for i, dsname in enumerate(dsetnames): 172 | aa = dset(dsname) 173 | task = aa.classification_task() 174 | raw_data, raw_labels = task 175 | nb_datapoints = len(raw_data) 176 | label_offset = 0 177 | if multihead: 178 | nb_classes = 10*n_tasks 179 | label_offset = i*10 180 | else: 181 | nb_classes = 10 182 | nb_training_examples = int(nb_datapoints*(1.0-validationset_fraction)) 183 | data = raw_data.reshape(datashape) 184 | labels = np_utils.to_categorical(raw_labels+label_offset, nb_classes) 185 | training_datasets.append( (data[:nb_training_examples], labels[:nb_training_examples]) ) 186 | validation_datasets.append( (data[nb_training_examples:], labels[nb_training_examples:]) ) 187 | 188 | return training_datasets, validation_datasets 189 | 190 | def load_mnist(split='train'): 191 | (X_train, y_train), (X_test, y_test) = mnist.load_data() 192 | X_train = X_train.reshape(-1, 784) 193 | X_test = X_test.reshape(-1, 784) 194 | X_train = X_train.astype('float32') 195 | X_test = X_test.astype('float32') 196 | X_train /= 255 197 | X_test /= 255 198 | 199 | if split == 'train': 200 | X, y = X_train, y_train 201 | else: 202 | X, y = X_test, y_test 203 | nb_classes = 10 204 | y = np_utils.to_categorical(y, nb_classes) 205 | return X, y 206 | 207 | def construct_split_mnist(task_labels, split='train', multihead=False): 208 | """Split MNIST dataset by labels. 209 | 210 | Args: 211 | task_labels: list of list of labels, one for each dataset 212 | split: whether to use train or testing data 213 | 214 | Returns: 215 | List of (X, y) tuples representing each dataset 216 | """ 217 | # Load MNIST data and normalize 218 | nb_classes = 10 219 | (X_train, y_train), (X_test, y_test) = mnist.load_data() 220 | X_train = X_train.reshape(-1, 784) 221 | X_test = X_test.reshape(-1, 784) 222 | X_train = X_train.astype('float32') 223 | X_test = X_test.astype('float32') 224 | X_train /= 255 225 | X_test /= 255 226 | 227 | if split == 'train': 228 | X, y = X_train, y_train 229 | else: 230 | X, y = X_test, y_test 231 | 232 | return split_dataset_by_labels(X, y, task_labels, nb_classes, multihead) 233 | 234 | 235 | def construct_randomly_split_mnist(nb_splits=10, mode='train'): 236 | """Split MNIST dataset by labels. 237 | 238 | Args: 239 | nb_splits: numer of splits 240 | mode: whether to use train or testing data 241 | 242 | Returns: 243 | List of (X, y) tuples representing each dataset 244 | """ 245 | # Load MNIST data and normalize 246 | nb_classes = 10 247 | (X_train, y_train), (X_test, y_test) = mnist.load_data() 248 | X_train = X_train.reshape(-1, 784) 249 | X_test = X_test.reshape(-1, 784) 250 | X_train = X_train.astype('float32') 251 | X_test = X_test.astype('float32') 252 | X_train /= 255 253 | X_test /= 255 254 | 255 | if mode == 'train': 256 | X, y = X_train, y_train 257 | else: 258 | X, y = X_test, y_test 259 | 260 | return split_dataset_randomly(X, y, nb_splits, nb_classes) 261 | 262 | def construct_transfer_cifar10_cifar100(nb_tasks=4, split='train'): 263 | """ 264 | Returns a two task dataset in which the first task is the full CIFAR10 dataset and the second task are 10 from CIFAR100 265 | classes from the CIFAR100 dataset. 266 | 267 | params: 268 | nb_tasks The total number of tasks 269 | split Whether to return training or validation data 270 | 271 | returns: 272 | A list with two tuples containing the two data sets 273 | """ 274 | (X_train, y_train), (X_test, y_test) = cifar10.load_data() 275 | # X_train = X_train.reshape(-1, 3, 32, 32) 276 | # X_test = X_test.reshape(-1, 32**2) 277 | X_train = X_train.astype('float32') 278 | X_test = X_test.astype('float32') 279 | no = X_train.max() 280 | X_train /= no 281 | X_test /= no 282 | 283 | if split == 'train': 284 | X, y = X_train, y_train 285 | else: 286 | X, y = X_test, y_test 287 | 288 | nb_classes = nb_tasks*10 289 | datasets = [(X,np_utils.to_categorical(y, nb_classes))] 290 | 291 | # Load CIFAR100 data and normalize 292 | (X_train, y_train), (X_test, y_test) = cifar100.load_data() 293 | X_train = X_train.astype('float32') 294 | X_test = X_test.astype('float32') 295 | m = np.max( (np.max(X_train), np.max(X_test) ) ) 296 | X_train /= m 297 | X_test /= m 298 | 299 | if split == 'train': 300 | X, y = X_train, y_train 301 | else: 302 | X, y = X_test, y_test 303 | 304 | # split dataset by labels 305 | task_labels = [ range(10*i,10*(i+1)) for i in range(1,nb_tasks) ] 306 | for labels in task_labels: 307 | idx = np.in1d(y+10, labels) 308 | data = X[idx], np_utils.to_categorical(y[idx]+10, nb_classes) 309 | datasets.append(data) 310 | 311 | 312 | all_task_labels = [range(10)] 313 | all_task_labels.extend(task_labels) 314 | return all_task_labels, datasets 315 | 316 | def construct_split_cifar100(num_tasks=3, num_classes=10): 317 | """Split CIFAR100 dataset and relabel classes num_classes 318 | 319 | Args: 320 | num_tasks: the number of tasks 321 | num_classes: the number of classes per task 322 | 323 | Returns: 324 | List of (X, y) tuples representing each dataset 325 | """ 326 | # Load CIFAR100 data and normalize 327 | (X_train, y_train), (X_test, y_test) = cifar100.load_data() 328 | X_train = X_train.astype('float32') 329 | X_test = X_test.astype('float32') 330 | m = np.max( (np.max(X_train), np.max(X_test) ) ) 331 | X_train /= m 332 | X_test /= m 333 | 334 | X, y = X_train, y_train 335 | 336 | # split dataset by labels 337 | # here we also flatten the labels of cifar100 to match num_classes via modulus operation 338 | task_labels = [ range(num_classes*i,num_classes*(i+1)) for i in range(num_tasks) ] 339 | datasets = [] 340 | for labels in task_labels: 341 | idx = np.in1d(y, labels) 342 | data = X[idx], np_utils.to_categorical(y[idx]%num_classes, num_classes) 343 | datasets.append(data) 344 | 345 | return datasets 346 | 347 | def construct_permute_mnist(num_tasks=2, split='train', permute_all=False, subsample=1): 348 | """Create permuted MNIST tasks. 349 | 350 | Args: 351 | num_tasks: Number of tasks 352 | split: whether to use train or testing data 353 | permute_all: When set true also the first task is permuted otherwise it's standard MNIST 354 | subsample: subsample by so much 355 | 356 | Returns: 357 | List of (X, y) tuples representing each dataset 358 | """ 359 | # Load MNIST data and normalize 360 | nb_classes = 10 361 | (X_train, y_train), (X_test, y_test) = mnist.load_data() 362 | X_train = X_train.reshape(-1, 784) 363 | X_test = X_test.reshape(-1, 784) 364 | X_train = X_train.astype('float32') 365 | X_test = X_test.astype('float32') 366 | X_train /= 255 367 | X_test /= 255 368 | 369 | X_train, y_train = X_train[::subsample], y_train[::subsample] 370 | X_test, y_test = X_test[::subsample], y_test[::subsample] 371 | 372 | permutations = [] 373 | # Generate random permutations 374 | for i in range(num_tasks): 375 | idx = np.arange(X_train.shape[1],dtype=int) 376 | if permute_all or i>0: 377 | np.random.shuffle(idx) 378 | permutations.append(idx) 379 | 380 | both_datasets = [] 381 | for (X, y) in ((X_train, y_train), (X_test, y_test)): 382 | datasets = [] 383 | for perm in permutations: 384 | data = X[:,perm], np_utils.to_categorical(y, nb_classes) 385 | datasets.append(data) 386 | both_datasets.append(datasets) 387 | return both_datasets 388 | 389 | 390 | def construct_split_cifar10(task_labels, split='train'): 391 | """Split CIFAR10 dataset by labels. 392 | 393 | Args: 394 | task_labels: list of list of labels, one for each dataset 395 | split: whether to use train or testing data 396 | 397 | Returns: 398 | List of (X, y) tuples representing each dataset 399 | """ 400 | # Load CIFAR10 data and normalize 401 | nb_classes = 10 402 | (X_train, y_train), (X_test, y_test) = cifar10.load_data() 403 | # X_train = X_train.reshape(-1, 3, 32, 32) 404 | # X_test = X_test.reshape(-1, 32**2) 405 | X_train = X_train.astype('float32') 406 | X_test = X_test.astype('float32') 407 | no = X_train.max() 408 | X_train /= no 409 | X_test /= no 410 | 411 | if split == 'train': 412 | X, y = X_train, y_train 413 | else: 414 | X, y = X_test, y_test 415 | 416 | return split_dataset_by_labels(X, y, task_labels, nb_classes) 417 | 418 | 419 | def online_benchmark(datasets, model, loss, optimizer, epochs_per_dataset=1, 420 | ages=1, batch_size=256, callbacks=None, **kwargs): 421 | """Benchmark online learning. 422 | 423 | Sequentially optimize a set of tasks, and compute 424 | the predictions for each task over time. 425 | 426 | Args: 427 | datasets: list of (inputs, labels) tuples 428 | model: Keras model 429 | loss: string or function 430 | optimizer: string or Keras Optimizer object 431 | epochs_per_dataset: number of passes through an individual dataset 432 | ages: number of passes over datasets 433 | batch_size: batch size 434 | callbacks: list of functions to call with the model at each iteration 435 | 436 | Returns: 437 | labels: 438 | predictions: 439 | """ 440 | 441 | # Build the model 442 | model.compile(loss=loss, optimizer=optimizer, metrics=['accuracy']) 443 | 444 | ndataset = len(datasets) 445 | predictions = [[] for i in range(ndataset)] 446 | labels = [[] for i in range(ndataset)] 447 | if callbacks is not None: 448 | callback_outputs = [[] for i in range(len(callbacks))] 449 | for cidx, callback in enumerate(callbacks): 450 | callback_outputs[cidx].append(callback(model)) 451 | 452 | optimization_data = [[] for i in range(len(model.get_weights())) ] 453 | for age in range(ages): 454 | for didx, dataset in enumerate(datasets): 455 | 456 | model.fit(*dataset, batch_size=batch_size, nb_epoch=epochs_per_dataset, verbose=1) 457 | # Log w, g, g2, ... 458 | # For all variables, ... , 459 | if isinstance(optimizer, Adam): 460 | weights = model.get_weights() 461 | opt_vars = optimizer.weights[1:] 462 | ms = opt_vars[:len(opt_vars)//2] 463 | vs = opt_vars[len(opt_vars)//2:] 464 | sess = K.get_session() 465 | stuff = sess.run([ms, vs]) 466 | for i in range(len(model.get_weights())): 467 | optimization_data[i].append([stuff[0][i], stuff[1][i]]) 468 | #optimization_data.append(stuff) 469 | 470 | # Evaluate on all datasets 471 | for eval_didx, eval_dataset in enumerate(datasets): 472 | # Evaluate model on dataset 473 | preds = model.predict(eval_dataset[0]) 474 | predictions[eval_didx].append(preds) 475 | # Convert from 1-hot back to categorical 476 | labels[eval_didx].append(np.argmax(eval_dataset[1], 1)) 477 | print(model.evaluate(*eval_dataset)) 478 | print("") 479 | if callbacks is not None: 480 | for cidx, callback in enumerate(callbacks): 481 | callback_outputs[cidx].append(callback(model)) 482 | 483 | if callbacks is None: 484 | callback_outputs = None 485 | # TODO(ben): might break some shit 486 | 487 | 488 | return dict(labels=labels, predictions=predictions, 489 | callback_outputs=callback_outputs, 490 | optimization_data=optimization_data) 491 | 492 | 493 | def save_zipped_pickle(obj, filename, protocol=-1): 494 | with gzip.open(filename, 'wb') as f: 495 | pickle.dump(obj, f, protocol) 496 | 497 | 498 | def load_zipped_pickle(filename): 499 | try: 500 | with gzip.open(filename, 'rb') as f: 501 | loaded_object = pickle.load(f) 502 | return loaded_object 503 | except IOError: 504 | print("Warning: IO Error returning empty dict.") 505 | return dict() 506 | 507 | 508 | def split_dataset(ds, split_sizes, permute_data=True): 509 | """ Helper function to split a single dataset into train, valid and test set. 510 | 511 | args: 512 | ds the dataset being a tuple of (data,labels) 513 | split_sizes a list of fractional split sizes of howto divide up the dataset 514 | 515 | returns: 516 | a list of datasets with the respective split ratios 517 | """ 518 | raw_data, raw_labels = ds 519 | if permute_data: 520 | idx = range(len(raw_data)) 521 | np.random.shuffle(idx) 522 | data = raw_data[idx] 523 | labels = raw_labels[idx] 524 | else: 525 | data = raw_data 526 | labels = raw_labels 527 | nelems = len(labels) 528 | nbegin = 0 529 | splits = [] 530 | for split in split_sizes: 531 | nend = nbegin+int(split*nelems) 532 | splits.append( (data[nbegin:nend], labels[nbegin:nend]) ) 533 | nbegin = nend 534 | return splits 535 | 536 | def mk_training_validation_splits( full_datasets, split_fractions = (0.8, 0.1, 0.1) ): 537 | """ Splits multiple a list of tasks into training, validation and test sets 538 | 539 | args: 540 | full_datasets: The full dataset as a list of tasks each being of the form (data, labels) 541 | split_fractions: A list of split fractions which should sum up to 1.0 542 | 543 | returns: 544 | a list of length len(split_fractions) each containing a list of tasks 545 | """ 546 | results = [ [] for i in range(len(split_fractions)) ] 547 | for ds in full_datasets: 548 | splits = split_dataset(ds, split_fractions) 549 | for i,sp in enumerate(splits): 550 | results[i].append(sp) 551 | return results 552 | 553 | def mk_joined_dataset( full_datasets, split_fractions = (0.9, 0.1) ): 554 | """ Joins datasets from multiple tasks to a single dataset as a baseline control and returns training and validation splints. """ 555 | l = len(full_datasets) 556 | data = np.concatenate([ full_datasets[i][0] for i in range(l) ], 0) 557 | labels = np.concatenate([ full_datasets[i][1] for i in range(l) ], 0) 558 | return split_dataset((data, labels), split_fractions) 559 | 560 | 561 | 562 | def main(): 563 | """ Test code for permute MNIST task 564 | 565 | Plots the first digit of the first two tasks. """ 566 | import matplotlib.pyplot as plt 567 | ds = construct_split_cifar100() 568 | plt.subplot(121) 569 | plt.imshow(ds[0][0][0].transpose((1,2,0) ), interpolation='nearest') 570 | plt.subplot(122) 571 | plt.imshow(ds[1][0][0].transpose((1,2,0)), interpolation='nearest') 572 | plt.show() 573 | 574 | if __name__ == "__main__": 575 | main() 576 | 577 | --------------------------------------------------------------------------------