{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" }, "colab": { "name": "WhatIsAutodiff.ipynb", "provenance": [], "collapsed_sections": [] } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "5dVodh7LjlNy" }, "source": [ "# Automatic Differentiation is not numerical differentiation\n", "\n", "## Instructions:\n", " - Copy the notebook to your colab account;\n", " - Run the notebook with Shift-Enter at each cell;\n", " - Experiment and have fun!\n", "\n", "## What is this demo about?\n", "\n", "This demo will show you the difference between **Automatic Differentiation** (Autodiff), **algebraic differentiation** (the one you did in math classes) and **numerical differentiation** (coarse and shameless approximation to the derivative).\n", "\n", "There are two flavors for Autodiff: the forward and the backward modes. Backpropagation is a particular case of the backward mode and we will see an example of the forward mode -- easier to code, and illustrative of the Autodiff behavior.\n", "\n", "**For the forward Autodiff we will use the concept of dual numbers.**\n", "A dual number is an extension of the real numbers. Written out, the form looks similar to a complex number." ] }, { "cell_type": "markdown", "metadata": { "id": "Xz9rPyQejlN0" }, "source": [ "## Complex Numbers reviewed\n", "A complex number has the form $$z = a + bi$$ where we *define* the number $i$ so that $i^{2} = -1$. \n", "\n", "Sometimes the imaginary unit is notated as $j$ (as in Python)." ] }, { "cell_type": "markdown", "metadata": { "id": "ou2ZHmcSjlN1" }, "source": [ "No real number has this property. Hence the introduction of complex numbers." ] }, { "cell_type": "markdown", "metadata": { "id": "HvB1JsfrjlN1" }, "source": [ "Visually, you can think of a real number as a number lying on a straight line: the real line. Then, we extend the real field to 2 dimensions. The new axis is called the *imaginary* axis." ] }, { "cell_type": "code", "metadata": { "id": "9D93gFVHxtnR" }, "source": [ "def argand(a):\n", " import matplotlib.pyplot as plt\n", " import numpy as np\n", " fig, ax = plt.subplots()\n", " plt.axis(\"on\")\n", " plt.grid()\n", " # left y-axis and bottim x-axis to centre, passing through (0,0)\n", " ax.spines['left'].set_position('center')\n", " ax.spines['bottom'].set_position('center')\n", "\n", " # clean axes\n", " ax.spines['right'].set_color('none')\n", " ax.spines['top'].set_color('none')\n", "\n", " # Ticks on left and lower axes\n", " ax.xaxis.set_ticks_position('bottom')\n", " ax.yaxis.set_ticks_position('left')\n", "\n", " for x in range(len(a)):\n", " plt.plot([0,a[x].real],[0,a[x].imag],'rs-')\n", " limit=np.max(np.ceil(np.absolute(a))) \n", "\n", " plt.xlim((-limit,limit))\n", " plt.ylim((-limit,limit))\n", " plt.arrow(0, -limit, 0, 1.9*limit, head_width=limit/20, head_length=limit/20, fc='k', ec='k');\n", " plt.arrow(-limit, 0, 1.9*limit, 0, head_width=limit/20, head_length=limit/20, fc='k', ec='k');\n", "\n", " #plt.ylabel(30*' '+'Im', horizontalalignment='left',rotation=0)\n", " #plt.xlabel('Re')\n", " ax.set_xlabel(80*' '+'Re')\n", " ax.set_ylabel(50*' '+'Im')\n", " plt.show()\n", " \n", "a = [1+4j]\n", "argand(a)" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "3mTpVgrfzIkS" }, "source": [ "a = [1+4j, -2+2j]\n", "argand(a)" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "keX6xeP73GGr" }, "source": [ "a1 = 1+4j ; a2 = -2+2j\n", "a = [a1, a2,a1+a2]\n", "argand(a)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "XtFYOALSjlN1" }, "source": [ "### A few properties and operations on complex numbers\n", "\n", "$$z = a+b i$$\n", "\n", "\n", "* Real part: $\\text{Re}(z) = a$\n", "* Imaginary part: $\\text{Im}(z) = b$\n", "\n", "* Complex conjugate: $z^{*} = a - bi$.\n", "* Magnitude of a complex number: $\\left|z\\right|^{2} = zz^{*} = \\left(a+bi\\right)\\left(a-bi\\right) = a^{2} + b^{2}$.\n", "\n", "* Summation: $z_1 + z_2 = (a_1 + a_2) + (b_1 + b_2)i$\n", "* Multiplication: $z_1z_2 = (a_1+b_1i)(a_2+b_2i) = a_1a_2-\\mathbf{b_1b_2} + (a_1b_2 +a_2b_1)i$ *->* **Feedback of the imaginary part to the real part**" ] }, { "cell_type": "code", "metadata": { "id": "5d5k0BHT3smg" }, "source": [ "a1 = 1+4j ; a2 = -2+2j\n", "a = [a1, a2, a1*a2]\n", "argand(a)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "ENUg4j-2jlN2" }, "source": [ "## Definition of Dual Numbers\n", "A dual number has a real part $a$ and a dual part $b$. We write $$z = a + b \\epsilon $$." ] }, { "cell_type": "markdown", "metadata": { "id": "2hmVqS87jlN2" }, "source": [ "We *define* the number $\\epsilon \\not = 0$, so that $\\epsilon^{2} = 0$." ] }, { "cell_type": "markdown", "metadata": { "id": "NbL_50CXjlN2" }, "source": [ "**Note that $\\epsilon$ is NOT zero!** $\\epsilon$ is not a real number. You can imagine that $\\epsilon$ is a really small number. When you square it, it gets much much smaller." ] }, { "cell_type": "markdown", "metadata": { "id": "4tWFzzP7jlN3" }, "source": [ "#### Some properties of dual numbers:\n", "\n", "* Real part: $\\text{Re}(z) = a$\n", "* Dual part: $\\text{Dual}(z) = b$\n", "* Conjugate: $z^{*} = a - b \\epsilon $.\n", "* Magnitude: $\\left|z\\right|^{2} = zz^{*} = \\left(a+ b \\epsilon \\right)\\left(a- b \\epsilon \\right) = a^{2}$.\n", "* Summation: $z_1 + z_2 = (a_1+a_2) + (b_1+b_2) \\epsilon $.\n", "*Multiplication: $z_1z_2 = (a_1a_2 + b_1b_2\\mathbf{\\epsilon^2}) + (a_1b_2 + a_2b_1) \\epsilon = a_1a_2 + (a_1b_2 + a_2b_1) \\epsilon$ *->* **There is NO feedback of the dual part to the real part**\n", "\n", "\n" ] }, { "cell_type": "code", "metadata": { "id": "ZUorOukno7xi" }, "source": [ "# Motivation: take a small number, and square it\n", "small = 1e-3\n", "small, small**2" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "rhX7v_EO6unH" }, "source": [ "## Taylor series expansion\n", "A smooth function $f$ can be written as an infinite sum of polynomials\n", "\n", " $$ f(x) = f(a) + \\frac{f^\\prime(a)}{1!}(x-a) + \\frac{f^{\\prime\\prime}(a)}{2!}(x-a)^2 + \\frac{f^{\\prime\\prime\\prime}(a)}{3!}(x-a)^3 + \\cdots $$\n", "\n", " \n", "### Example: $e^x$\n", "\n", "$$f(x) = e^x$$\n", "\n", "Assume $a = 0$. Then,\n", "$$f(x) = 1 + x + \\frac{x^2}{2!} + \\frac{x^3}{3!}+ \\dots$$\n", "\n" ] }, { "cell_type": "code", "metadata": { "id": "FcrsXzM96pEh" }, "source": [ "def ExpTaylor(n,x):\n", " import math\n", " term = 1\n", " for k in range(1,n+1):\n", " term += x**k/math.factorial(k)\n", " #print(term)\n", " return term\n", "\n", "def PlotExpTaylor(n):\n", " import matplotlib.pyplot as plt\n", " import numpy as np\n", " x = np.arange(-2,2,0.1)\n", " eTaylor = [ExpTaylor(n,xi) for xi in x]\n", "\n", " fig, ax = plt.subplots()\n", " ax.plot(x, np.exp(x))\n", " ax.plot(x,eTaylor)\n", " ax.set_ylim([-2,np.exp(2)])\n", " ax.legend(['exp() function','Taylor Series'])\n", " plt.show()\n", "\n", "PlotExpTaylor(0)" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "kKEg3J4LUwF7" }, "source": [ "PlotExpTaylor(1)" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "RV2uL67OU0nQ" }, "source": [ "PlotExpTaylor(3)" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "agf1OwZMU6Qr" }, "source": [ "PlotExpTaylor(6)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "ml8GBXqFVQOo" }, "source": [ "## Taylor series and the dual number\n", "\n", "Lets apply the Taylor expansion to $ x = a+b \\epsilon$\n", "\n", " $$ f(a+b \\epsilon) = f(a) + \\frac{f^\\prime(a)}{1!} b \\epsilon + \\frac{f^{\\prime\\prime}(a)}{2!}b^2 \\epsilon^2 + \\frac{f^{\\prime\\prime\\prime}(a)}{3!}b^3 \\epsilon^2 \\epsilon + \\cdots $$\n", "\n", " And all terms that include multiplication by $\\epsilon^2$ are zero! So, we see that, for all possible $a$ and $b$,\n", "\n", " $$ f(a+b \\epsilon) = f(a) + f^\\prime(a) b \\epsilon $$\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "1gfR-k09jlN3" }, "source": [ "### Example\n", "Recall that the derivative of $f(x)=x^{2}$ is $f^{\\prime}(x) = 2x$." ] }, { "cell_type": "markdown", "metadata": { "id": "wnaUUGqZjlN3" }, "source": [ "Now if we extend $x$ so that it has a real part and a dual part ($x\\leftarrow a + b \\epsilon $) and evaluate $f$ we have\n", "\\begin{align}\n", " f(a + b \\epsilon) &= \\left(a + b \\epsilon \\right)^{2} \\\\\n", " &= a^{2} + 2ab\\epsilon + \\underbrace{b^{2}\\epsilon^{2}}_{=0} \\\\\n", " &= a^{2} + 2ab\\epsilon.\n", "\\end{align}" ] }, { "cell_type": "markdown", "metadata": { "id": "PTQNRc0YjlN3" }, "source": [ "#### Notice that the real part is $f$ evaluated at $a$, and the dual part contains the derivative of our function evaluated at $a$!!" ] }, { "cell_type": "markdown", "metadata": { "id": "KLpDyXDmjlN4" }, "source": [ "### Example\n", "Evaluate $y = \\sin\\left(x\\right)$ when $x\\leftarrow a + b\\epsilon$.\n", "\n", "We have\n", "\\begin{align}\n", " y & = \\sin\\left(a + b \\epsilon \\right) \\\\\n", " & = \\sin\\left(a\\right)\\cos\\left( b \\epsilon\\right) + \\cos\\left(a\\right)\\sin\\left( b \\epsilon\\right).\n", "\\end{align}" ] }, { "cell_type": "markdown", "metadata": { "id": "xaKU-I8FjlN4" }, "source": [ "Expanding $\\cos$ and $\\sin$ in their Taylor series gives \n", "\\begin{align}\n", " \\sin\\left(b \\epsilon \\right) &= b \\epsilon + \\dfrac{\\left( b \\epsilon \\right)^{3}}{3!} + \\cdots = b \\epsilon \\\\\n", " \\cos\\left(b \\epsilon \\right) &= 1 + \\dfrac{\\left( b \\epsilon \\right)^{2}}{2} + \\cdots = 1.\n", "\\end{align}\n", "Remember that $\\epsilon^2 =0$, and $\\epsilon \\not = 0$." ] }, { "cell_type": "markdown", "metadata": { "id": "2c9I42H_jlN4" }, "source": [ "So we see that \n", "\\begin{align}\n", " y & = \\sin\\left(a\\right) + \\cos\\left(a\\right) b \\epsilon.\n", "\\end{align}\n", "And once again the real component is the function and the dual component is the derivative times $b$. Make $b=1$... \n", "\n", "**And we have a closed-form computation for the derivative at a point a!!**\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "m6XKQqd2djoY" }, "source": [ "##Using Python Autograd\n", "\n" ] }, { "cell_type": "code", "metadata": { "id": "MrYwbZGb2XmF" }, "source": [ "import autograd\n", "import autograd.numpy as np\n", "autograd.grad(np.exp)(4.), np.exp(4.)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "WZTeGOkRidkK" }, "source": [ "Square root function:\n", "\n", "$$ f(x) = \\sqrt(x)$$\n", "\n", "Derivative:\n", "\n", "$$f^\\prime (x) = \\frac{1}{2 \\sqrt(x)}$$\n", "\n", "Try using autograd" ] }, { "cell_type": "code", "metadata": { "id": "0eI8D4gMf9UX" }, "source": [ "def derivSqrt(x):\n", " import numpy as np\n", " return 1.0/2/np.sqrt(x)\n", "\n", "def plotCompareSqrt():\n", " import matplotlib.pyplot as plt\n", " import autograd\n", " import autograd.numpy as np\n", " x = np.arange(0.1,2,0.05)\n", " dfdx = [derivSqrt(xi) for xi in x]\n", " autod = [autograd.grad(np.sqrt)(xi) for xi in x]\n", " fig, ax = plt.subplots()\n", " ax.plot(x, np.sqrt(x))\n", " ax.plot(x,dfdx)\n", " ax.plot(x,autod, 'o')\n", " ax.legend(['sqrt() function','Analytic (symbolic) derivative','Autodiff'])\n", " plt.show()\n", "\n", "plotCompareSqrt()" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "DxO_jsJJqHZG" }, "source": [ "Exercises\n", "\n", "Take function $f$ defined as\n", "$$\n", "f(x) = e^{x^2}.\n", "$$\n", "\n", "1. Compute the derivative of $f$ by hand. Remember that if $u = x^2$, then $$\\left . \\frac{df}{dx}(x) \\right|_{x=a} = \\left. \\frac{df}{du}\\frac{du}{dx}(x)\\right | _{x=a}.$$ \n", "1. Write a Python function receiving as arguments function $f$ and a step $h$ to approximate the derivative using finite differences, i.e., $$ \\text{NumDiff}(f,h) = \\frac{f(x+h) - f(x)}{h}.$$\n", "1. Evaluate the functions from exercises 1 and 2 with $x \\in [0.2,0.4]$, for $h \\in \\{0.1, 10^{-5}, 10^{-15}\\}$ and plot the results. What can you conclude?\n", "1. Deduce the expression of $f(a+\\epsilon)$. You will need the property $\\epsilon^2 = 0$ and the Taylor expansion above for $e^x$.\n", "1. Create a class `DualNumber` and equip it with the necessary methods to perform dual number arithmetic, namely addition, multiplication and power of a number `n`.\n", "\n", "1. Write a new Python function to compute the derivative of $f$ using this class. Remember you will be evaluating function $f(x)$ on the dual number $x=a+\\epsilon$. Compare the result in a plot also showing `NumDiff` and the symbolic derivative you computed in the first exercise.\n", " \n", "1. Now use the Python package `autograd`to compute the exact derivative and plot the result.\n", "\n", "1. Use `autograd` to compute the derivative of\n", "$$\n", "f(x) = e^{-(\\sin(x) - 4\\cos(x))^2}\n", "$$\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "A7XgPHu_Pm8Q" }, "source": [ "Solution:\n", "\n", "1. $2xe^{x^2}$\n", "1. Code below\n", "1. Code below\n", "1. $f(a+\\epsilon) = e^{a^2+2a\\epsilon} = e^{a^2}e^{2a\\epsilon}=e^{a^2} (1+ 2a\\epsilon)= e^{a^2} + 2ae^{a^2}\\epsilon$\n", "1. Code below\n", "1. Code below\n", "1. \n", "1. Code below" ] }, { "cell_type": "code", "metadata": { "id": "OwlgtwRskkm9" }, "source": [ "def NumDiff(f,h):\n", " return lambda x:(f(x+h)-f(x))/h\n", "\n", "def SymbolDer(x):\n", " import numpy as np\n", " return 2*x*np.exp(x**2)\n", "\n", "def exercise3():\n", " import numpy as np\n", " import matplotlib.pyplot as plt\n", " x= np.linspace(.2,.4,15)\n", " def symbF():\n", " return lambda x:np.exp(x**2)\n", " \n", " setOfh = [.1, 1e-2, 1e-12, 1e-15]\n", " ndiff = [NumDiff(symbF(), h) for h in setOfh];\n", " for k in range(len(setOfh)):\n", " plt.plot(x, ndiff[k](x), label = 'h={}'.format(setOfh[k]))\n", " \n", " plt.plot(x, SymbolDer(x), 'o', label='true')\n", " plt.legend()\n", " plt.xlabel('x')\n", " plt.ylabel('Derivative(x)')\n", " \n", "exercise3()\n", "\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "pR5RKm4WS47v" }, "source": [ "class DualNumber():\n", " ''' Dual Number object for AD '''\n", " def __init__(self, a,b=1.0):\n", " ''' Constructur method '''\n", " self.a = a\n", " self.b = b\n", " def __add__(self, o):\n", " try:\n", " return DualNumber(self.a+o.a,self.b+o.b)\n", " except AttributeError:\n", " return DualNumber(self.a+o,self.b)\n", " def __mul__(self, o):\n", " return DualNumber(self.a*o.a,self.b*o.a+o.b*self.a)\n", " def __str__(self):\n", " return \"a: %f, b: %f\" % (self.a,self.b)\n", " def __pow__(self,n): \n", " import functools\n", " return functools.reduce(lambda a,b: a*b, [self]*n)\n", "\n", "## Exercise 6\n", "def DualNumberExp(x):\n", " import numpy as np\n", " return DualNumber(np.exp(x.a), np.exp(x.a)*x.b)\n", "\n", "a= 1.456 \n", "y = DualNumber(a)\n", "print(y), print(\"f: % f, f\\': % f\" %(a*a,2*a)), print(y*y), print(y**2)," ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "P701swO7YmqN" }, "source": [ "a = 1\n", "y= DualNumber(a)\n", "print(DualNumberExp(y**2))" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "Trrsu309v6r7" }, "source": [ " Use `autograd` to compute the derivative of\n", "$$\n", "f(x) = e^{-(\\sin(x) - 4\\cos(x))^2}\n", "$$" ] }, { "cell_type": "code", "metadata": { "id": "4MoQ4WTJjAu8", "colab": { "base_uri": "https://localhost:8080/", "height": 265 }, "outputId": "eee76b1e-bff4-475c-897f-5909c2576a4c" }, "source": [ "def exercise8():\n", " import matplotlib.pyplot as plt\n", " import autograd\n", " import numpy as np\n", " x = np.arange(-2.5,2.5,0.05)\n", " def f(x):\n", " import autograd.numpy as np\n", " return np.exp(-(np.sin(x)-4*np.cos(x))**2)\n", " autod = [autograd.grad(f)(xi) for xi in x]\n", " fig, ax = plt.subplots()\n", " ax.plot(x, np.exp(-(np.sin(x)-4*np.cos(x))**2))\n", " ax.plot(x,autod, '--')\n", " ax.legend(['f','AD'])\n", " plt.show()\n", "\n", "exercise8()" ], "execution_count": null, "outputs": [ { "output_type": "display_data", "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "tags": [], "needs_background": "light" } } ] }, { "cell_type": "code", "metadata": { "id": "SXsqNUbfw3oj" }, "source": [ "" ], "execution_count": null, "outputs": [] } ] }