{ "metadata": { "name": "", "signature": "sha256:09f0c4a23d19d83f45364ecc8716c8aa9c856558700596c9958e01dee08cc31a" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "08/05/15 Theano day! " ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Notes on the theano day organized in the group by James, Zhenwen and Andreas." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Written by Alessandra Tosi, Fariba Yusefi and Javier Gonzalez" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Import Theano to start! \n", "import theano\n", "import GPy\n", "from theano import tensor as T\n", "import numpy as np" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "1. Getting started" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Create a two dimensioanal array\n", "X = T.matrix()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "# Sum of the elements (even when is empty)\n", "f = T.sum(T.square(X))\n", "f" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "Sum.0" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "# Define theano function using f and X\n", "my_func = theano.function([X], f) " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "# Generate some values for X and evaluate\n", "X_values = np.random.randn(3,4)\n", "my_func(X_values) " ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 5, "text": [ "array(12.963304040797144)" ] } ], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "# Define gradients\n", "g = theano.grad(f,X)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "# Compute the derivarives\n", "mu_new_func = theano.function([X], [f,g]) " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "# Theano derivatives\n", "mu_new_func(X_values)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 8, "text": [ "[array(12.963304040797144),\n", " array([[-2.38163752, -2.16098669, -0.87717575, 0.69632923],\n", " [ 2.54935613, -1.25319369, 0.35672432, -1.84071505],\n", " [ 0.31138535, -2.65571952, 1.61767688, 4.34798378]])]" ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "# Exact derivatives\n", "X_values*2 " ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 9, "text": [ "array([[-2.38163752, -2.16098669, -0.87717575, 0.69632923],\n", " [ 2.54935613, -1.25319369, 0.35672432, -1.84071505],\n", " [ 0.31138535, -2.65571952, 1.61767688, 4.34798378]])" ] } ], "prompt_number": 9 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2. Linear regression" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Define the elements of the regression\n", "w = T.dvector()\n", "Xw = T.dot(X,w)\n", "y = T.dvector()\n", "error = T.sum(T.square(y-Xw))\n", "sigma = T.dscalar()\n", "neg_log_lik = 0.5*y.size*np.log(2*np.pi) + 0.5*y.size*T.log(sigma**2) + 0.5*error/sigma**2 " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "# Create objective\n", "my_func = theano.function([X, y, sigma, w], [neg_log_lik, theano.grad(neg_log_lik, w), theano.grad(neg_log_lik, sigma)]) " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "# test with data\n", "w_true = np.random.randn(2)\n", "X_values = np.random.randn(200,2) \n", "y = np.dot(X_values, w_true) + np.random.randn(200)*0.01\n", "y_values = np.dot(X_values, w_true) + np.random.randn(200)*0.01" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "# evaluate likelihood, gradiends with respect to w and gradients with respect to sigma\n", "my_func(X_values, y_values , 0.02, np.array([1,1])) " ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 13, "text": [ "[array(1740553.6503363969),\n", " array([ 1130920.6618946 , 756385.18434244]),\n", " array(-174105226.72308418)]" ] } ], "prompt_number": 13 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "3. Team work (Alessandra, Fariba and Javier): implementing an RBF kernel in GPy using theano" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# elements of the kernel\n", "X = T.matrix()\n", "Z = T.matrix()\n", "len_scale = T.dscalar()\n", "sigma2 = T.dscalar()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 14 }, { "cell_type": "code", "collapsed": false, "input": [ "# create the RBF kernel\n", "r2 = ((X[:,None,:]/len_scale - Z[None,:,:]/len_scale)**2).sum(2)\n", "rbf_kernel = sigma2*T.exp(-0.5*r2)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "# Create the theano functions for r2 and the kernel\n", "r2_eval = theano.function([X,Z,len_scale],[r2])\n", "kern_eval = theano.function([X,Z,len_scale,sigma2],[rbf_kernel])" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "# Generate some data to evaluate r2 and the kernel\n", "X_val = np.random.randn(4,2)\n", "Z_val = np.random.randn(6,2)\n", "sigma2_val = 1\n", "len_scale_val = 2" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "# Distances evaluation!!! Order of the arguments should match\n", "r2_eval(X_val,Z_val,len_scale_val)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 18, "text": [ "[array([[ 0.11363081, 0.02207483, 0.26821606, 0.33116141, 0.28348765,\n", " 1.18291004],\n", " [ 0.47115938, 0.14625441, 0.84486132, 0.57121556, 0.13850336,\n", " 0.89131393],\n", " [ 0.21376622, 0.34201811, 0.04655479, 0.6857568 , 0.98337181,\n", " 2.25323581],\n", " [ 0.3233845 , 0.7621669 , 0.23656762, 0.48814614, 1.35426331,\n", " 2.07027349]])]" ] } ], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": [ "# Kernel evaluation\n", "kern_eval(X_val,Z_val,len_scale_val,sigma2_val)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 19, "text": [ "[array([[ 0.94476845, 0.98902328, 0.87449559, 0.84740147, 0.86784355,\n", " 0.55352131],\n", " [ 0.7901127 , 0.92948259, 0.6554517 , 0.75155733, 0.93309181,\n", " 0.64040341],\n", " [ 0.89863071, 0.84281394, 0.97699143, 0.70972451, 0.61159444,\n", " 0.32412763],\n", " [ 0.85070297, 0.68312088, 0.88844387, 0.78343039, 0.50807223,\n", " 0.35517781]])]" ] } ], "prompt_number": 19 }, { "cell_type": "code", "collapsed": false, "input": [ "# We check that it matches with the same GPy kernel" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "kernelGPy = GPy.kern.RBF(2, variance = sigma2_val, lengthscale=len_scale_val)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 21 }, { "cell_type": "code", "collapsed": false, "input": [ "kernelGPy.K(X_val,Z_val)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 22, "text": [ "array([[ 0.94476845, 0.98902328, 0.87449559, 0.84740147, 0.86784355,\n", " 0.55352131],\n", " [ 0.7901127 , 0.92948259, 0.6554517 , 0.75155733, 0.93309181,\n", " 0.64040341],\n", " [ 0.89863071, 0.84281394, 0.97699143, 0.70972451, 0.61159444,\n", " 0.32412763],\n", " [ 0.85070297, 0.68312088, 0.88844387, 0.78343039, 0.50807223,\n", " 0.35517781]])" ] } ], "prompt_number": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, it works!" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# We calculate the derivatives of our kernel with respect to sigma2\n", "dL_dK = T.matrix()\n", "h = T.sum(dL_dK * rbf_kernel) " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 24 }, { "cell_type": "code", "collapsed": false, "input": [ "# Define gradients with respect to sigma2\n", "grads_wrt_sigma2 = theano.grad(h,sigma2)\n", "grads_wrt_sigma2_eval = theano.function([X,Z,len_scale,sigma2,dL_dK],grads_wrt_sigma2)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 25 }, { "cell_type": "code", "collapsed": false, "input": [ "# Define gradients with respect to the lengthscale\n", "grads_wrt_lengthscale = theano.grad(h,len_scale)\n", "grads_wrt_lengthscale_eval = theano.function([X,Z,len_scale,sigma2,dL_dK],grads_wrt_lengthscale)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 26 }, { "cell_type": "code", "collapsed": false, "input": [ "# Define gradients with respect to X\n", "grads_wrt_X= theano.grad(h,X)\n", "grads_wrt_X_eval = theano.function([X,Z,len_scale,sigma2,dL_dK],grads_wrt_X)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 28 }, { "cell_type": "code", "collapsed": false, "input": [ "# All gradients together\n", "grads_all_eval = theano.function([X,Z,len_scale,sigma2,dL_dK], [grads_wrt_sigma2, grads_wrt_lengthscale, grads_wrt_X])" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 29 }, { "cell_type": "code", "collapsed": false, "input": [ "# We test the result in a simple GPy model\n", "import GPy\n", "from matplotlib import pyplot as plt" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 30 }, { "cell_type": "code", "collapsed": false, "input": [ "# Some data\n", "x = np.linspace(-np.pi, np.pi, 201)[:,None]\n", "y = np.sin(x) + np.random.rand(201)[:,None]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 31 }, { "cell_type": "code", "collapsed": false, "input": [ "# plot the model\n", "%pylab inline\n", "model = GPy.models.GPRegression(x,y)\n", "model.optimize()\n", "model.plot()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Populating the interactive namespace from numpy and matplotlib\n" ] }, { "output_type": "stream", "stream": "stderr", "text": [ "WARNING: pylab import has clobbered these variables: ['f']\n", "`%matplotlib` prevents importing * from pylab and numpy\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 33, "text": [ "{'dataplot': [],\n", " 'gpplot': [[],\n", " [],\n", " [],\n", " []]}" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 33 }, { "cell_type": "code", "collapsed": false, "input": [ "## Class of kernels for GPy using theano (that uses our grads_all_eval)\n", "\n", "class TheanoKern(GPy.kern.Kern):\n", " def __init__(self, input_dim, variance=1., lengthscale=1.):\n", " GPy.kern.Kern.__init__(self, input_dim, active_dims=None, name='theanokern')\n", " self.var = GPy.core.Param('variance', variance)\n", " self.ls = GPy.core.Param('lengthscale', lengthscale)\n", " self.link_parameters(self.var, self.ls)\n", " # Add here a function which initializes all the theano symbolic functions\n", " \n", " def K(self, X, X2=None):\n", " if X2 is None:\n", " X2 = X\n", " return kern_eval(X, X2, self.ls[0], self.var[0])[0]\n", " \n", " def Kdiag(self, X):\n", " return np.diag(self.K(X))\n", " \n", " def update_gradients_full(self, dL_dK, X, X2=None):\n", " if X2 is None:\n", " X2 = X\n", " dvar, dl, dX = grads_all_eval(X, X2, self.ls[0], self.var[0], dL_dK)\n", " self.var.gradient = dvar\n", " self.ls.gradient = dl \n", " \n", " def gradients_X(self, dL_dK, X, X2=None):\n", " if X2 is None:\n", " X2 = X\n", " return grads_wrt_X_eval(X, X2, self.ls[0], self.var[0], dL_dK)\n", " \n", " def update_gradients_diag(self, dL_dKdiag, X):\n", " pass" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 81 }, { "cell_type": "code", "collapsed": false, "input": [ "# Create our theano kernel\n", "k = TheanoKern(2)\n", "k.K(X_val)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 70, "text": [ "array([[ 1. , 0.7246144 , 0.63578887, 0.20724078],\n", " [ 0.7246144 , 1. , 0.22850941, 0.04283463],\n", " [ 0.63578887, 0.22850941, 1. , 0.3758315 ],\n", " [ 0.20724078, 0.04283463, 0.3758315 , 1. ]])" ] } ], "prompt_number": 70 }, { "cell_type": "code", "collapsed": false, "input": [ "# model\n", "m = GPy.models.GPRegression(x, y, kernel=TheanoKern(1))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 83 }, { "cell_type": "code", "collapsed": false, "input": [ "# Ckeck with the gradients\n", "m.checkgrad(1)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " Name | Ratio | Difference | Analytical | Numerical | dF_ratio \n", "-------------------------------------------------------------------------------------------------------------------------------\n", "\u001b[92m GP_regression.theanokern.variance[[0]] \u001b[0m | 1.000000 | 0.000000 | 1.896246 | 1.896246 | 2e-08 \n", "\u001b[92m GP_regression.theanokern.lengthscale[[0]] \u001b[0m | 1.000000 | 0.000000 | -5.847597 | -5.847597 | 6e-08 \n", "\u001b[92m GP_regression.Gaussian_noise.variance[[0]] \u001b[0m | 1.000000 | 0.000000 | 56.397305 | 56.397305 | 6e-07 \n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 84, "text": [ "True" ] } ], "prompt_number": 84 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Done! :)" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }