From 1aa689c205e8b113445f6c1de78bacad1ebb1080 Mon Sep 17 00:00:00 2001 From: leshe4ka46 Date: Sun, 21 Sep 2025 17:29:45 +0300 Subject: nvidia1: complete --- .../Introduction+to+CUDA+Python+with+Numba.ipynb | 860 ++++++++++++++++----- 1 file changed, 654 insertions(+), 206 deletions(-) (limited to 'nvidia1/Introduction+to+CUDA+Python+with+Numba.ipynb') diff --git a/nvidia1/Introduction+to+CUDA+Python+with+Numba.ipynb b/nvidia1/Introduction+to+CUDA+Python+with+Numba.ipynb index ba98a5c..c1e885e 100644 --- a/nvidia1/Introduction+to+CUDA+Python+with+Numba.ipynb +++ b/nvidia1/Introduction+to+CUDA+Python+with+Numba.ipynb @@ -172,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "metadata": { "collapsed": true }, @@ -203,7 +203,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -212,7 +212,7 @@ "5.0" ] }, - "execution_count": 3, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -230,7 +230,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -239,7 +239,7 @@ "5.0" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -259,14 +259,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "669 ns ± 0.53 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n" + "677 ns ± 0.576 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n" ] } ], @@ -283,11 +283,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "188 ns ± 0.0139 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n" + ] + } + ], "source": [ "%timeit hypot(3.0, 4.0)" ] @@ -301,11 +307,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "124 ns ± 0.0233 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n" + ] + } + ], "source": [ "%timeit math.hypot(3.0, 4.0)" ] @@ -336,7 +348,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { "collapsed": true }, @@ -347,16 +359,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# TODO: Import Numba's just-in-time compiler function\n", + "from numba import jit\n", "import random\n", "\n", "# TODO: Use the Numba compiler to compile this function\n", + "@jit\n", "def monte_carlo_pi(nsamples):\n", " acc = 0\n", " for i in range(nsamples):\n", @@ -369,7 +383,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { "collapsed": true }, @@ -384,22 +398,34 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10.5 ms ± 1.32 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], "source": [ "%timeit monte_carlo_pi(nsamples)" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "349 ms ± 4.68 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + } + ], "source": [ "%timeit monte_carlo_pi.py_func(nsamples)" ] @@ -419,12 +445,108 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": { - "collapsed": true, "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hypot (float64, float64)\n", + "--------------------------------------------------------------------------------\n", + "# File: \n", + "# --- LINE 6 --- \n", + "# label 0\n", + "\n", + "@jit\n", + "\n", + "# --- LINE 7 --- \n", + "\n", + "def hypot(x, y):\n", + "\n", + " # --- LINE 8 --- \n", + "\n", + " # Implementation from https://en.wikipedia.org/wiki/Hypot\n", + "\n", + " # --- LINE 9 --- \n", + " # x = arg(0, name=x) :: float64\n", + " # y = arg(1, name=y) :: float64\n", + " # $0.1 = global(abs: ) :: Function()\n", + " # $0.3 = call $0.1(x, func=$0.1, args=[Var(x, (9))], kws=(), vararg=None) :: (float64,) -> float64\n", + " # del x\n", + " # del $0.1\n", + " # x.1 = $0.3 :: float64\n", + " # del $0.3\n", + "\n", + " x = abs(x);\n", + "\n", + " # --- LINE 10 --- \n", + " # $0.4 = global(abs: ) :: Function()\n", + " # $0.6 = call $0.4(y, func=$0.4, args=[Var(y, (9))], kws=(), vararg=None) :: (float64,) -> float64\n", + " # del y\n", + " # del $0.4\n", + " # y.1 = $0.6 :: float64\n", + " # del $0.6\n", + "\n", + " y = abs(y);\n", + "\n", + " # --- LINE 11 --- \n", + " # $0.7 = global(min: ) :: Function()\n", + " # $0.10 = call $0.7(x.1, y.1, func=$0.7, args=[Var(x.1, (9)), Var(y.1, (10))], kws=(), vararg=None) :: (float64, float64) -> float64\n", + " # del $0.7\n", + " # t = $0.10 :: float64\n", + " # del $0.10\n", + "\n", + " t = min(x, y);\n", + "\n", + " # --- LINE 12 --- \n", + " # $0.11 = global(max: ) :: Function()\n", + " # $0.14 = call $0.11(x.1, y.1, func=$0.11, args=[Var(x.1, (9)), Var(y.1, (10))], kws=(), vararg=None) :: (float64, float64) -> float64\n", + " # del y.1\n", + " # del x.1\n", + " # del $0.11\n", + " # x.2 = $0.14 :: float64\n", + " # del $0.14\n", + "\n", + " x = max(x, y);\n", + "\n", + " # --- LINE 13 --- \n", + " # $0.17 = t / x.2 :: float64\n", + " # del t\n", + " # t.1 = $0.17 :: float64\n", + " # del $0.17\n", + "\n", + " t = t / x;\n", + "\n", + " # --- LINE 14 --- \n", + " # $0.19 = global(math: ) :: Module()\n", + " # $0.20 = getattr(value=$0.19, attr=sqrt) :: Function()\n", + " # del $0.19\n", + " # $const0.21 = const(int, 1) :: int64\n", + " # $0.24 = t.1 * t.1 :: float64\n", + " # del t.1\n", + " # $0.25 = $const0.21 + $0.24 :: float64\n", + " # del $const0.21\n", + " # del $0.24\n", + " # $0.26 = call $0.20($0.25, func=$0.20, args=[Var($0.25, (14))], kws=(), vararg=None) :: (float64,) -> float64\n", + " # del $0.25\n", + " # del $0.20\n", + " # $0.27 = x.2 * $0.26 :: float64\n", + " # del x.2\n", + " # del $0.26\n", + " # $0.28 = cast(value=$0.27) :: float64\n", + " # del $0.27\n", + " # return $0.28\n", + "\n", + " return x * math.sqrt(1+t*t)\n", + "\n", + "\n", + "================================================================================\n" + ] + } + ], "source": [ "hypot.inspect_types()" ] @@ -447,11 +569,20 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'value'" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "@jit\n", "def cannot_compile(x):\n", @@ -469,11 +600,24 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "ename": "TypingError", + "evalue": "Failed in nopython mode pipeline (step: nopython frontend)\nInternal error at :\n--%<----------------------------------------------------------------------------\nTraceback (most recent call last):\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/errors.py\", line 599, in new_error_context\n yield\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 199, in __call__\n assert ty.is_precise()\nAssertionError\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 142, in propagate\n constraint(typeinfer)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 200, in __call__\n typeinfer.add_type(self.dst, ty, loc=self.loc)\n File \"/home/appuser/Miniconda3/lib/python3.6/contextlib.py\", line 99, in __exit__\n self.gen.throw(type, value, traceback)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/errors.py\", line 607, in new_error_context\n six.reraise(type(newerr), newerr, tb)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/six.py\", line 659, in reraise\n raise value\nnumba.errors.InternalError: \n[1] During: typing of argument at (3)\n--%<----------------------------------------------------------------------------\n\n\nFile \"\", line 3:\ndef cannot_compile(x):\n return x['key']\n ^\n\nThis error may have been caused by the following argument(s):\n- argument 0: cannot determine Numba type of \n\nThis is not usually a problem with Numba itself but instead often caused by\nthe use of unsupported features or an issue in resolving types.\n\nTo see Python/NumPy features supported by the latest release of Numba visit:\nhttp://numba.pydata.org/numba-doc/dev/reference/pysupported.html\nand\nhttp://numba.pydata.org/numba-doc/dev/reference/numpysupported.html\n\nFor more information about typing errors and how to debug them visit:\nhttp://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-doesn-t-compile\n\nIf you think your code should work with Numba, please report the error message\nand traceback, along with a minimal reproducer at:\nhttps://github.com/numba/numba/issues/new\n", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypingError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'key'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mcannot_compile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'value'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/dispatcher.py\u001b[0m in \u001b[0;36m_compile_for_args\u001b[0;34m(self, *args, **kws)\u001b[0m\n\u001b[1;32m 346\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpatch_message\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 347\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 348\u001b[0;31m \u001b[0merror_rewrite\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'typing'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 349\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mUnsupportedError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 350\u001b[0m \u001b[0;31m# Something unsupported is present in the user code, add help info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/dispatcher.py\u001b[0m in \u001b[0;36merror_rewrite\u001b[0;34m(e, issue_type)\u001b[0m\n\u001b[1;32m 313\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 314\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 315\u001b[0;31m \u001b[0mreraise\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 316\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 317\u001b[0m \u001b[0margtypes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/six.py\u001b[0m in \u001b[0;36mreraise\u001b[0;34m(tp, value, tb)\u001b[0m\n\u001b[1;32m 656\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 657\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__traceback__\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 658\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 659\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 660\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypingError\u001b[0m: Failed in nopython mode pipeline (step: nopython frontend)\nInternal error at :\n--%<----------------------------------------------------------------------------\nTraceback (most recent call last):\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/errors.py\", line 599, in new_error_context\n yield\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 199, in __call__\n assert ty.is_precise()\nAssertionError\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 142, in propagate\n constraint(typeinfer)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 200, in __call__\n typeinfer.add_type(self.dst, ty, loc=self.loc)\n File \"/home/appuser/Miniconda3/lib/python3.6/contextlib.py\", line 99, in __exit__\n self.gen.throw(type, value, traceback)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/errors.py\", line 607, in new_error_context\n six.reraise(type(newerr), newerr, tb)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/six.py\", line 659, in reraise\n raise value\nnumba.errors.InternalError: \n[1] During: typing of argument at (3)\n--%<----------------------------------------------------------------------------\n\n\nFile \"\", line 3:\ndef cannot_compile(x):\n return x['key']\n ^\n\nThis error may have been caused by the following argument(s):\n- argument 0: cannot determine Numba type of \n\nThis is not usually a problem with Numba itself but instead often caused by\nthe use of unsupported features or an issue in resolving types.\n\nTo see Python/NumPy features supported by the latest release of Numba visit:\nhttp://numba.pydata.org/numba-doc/dev/reference/pysupported.html\nand\nhttp://numba.pydata.org/numba-doc/dev/reference/numpysupported.html\n\nFor more information about typing errors and how to debug them visit:\nhttp://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-doesn-t-compile\n\nIf you think your code should work with Numba, please report the error message\nand traceback, along with a minimal reproducer at:\nhttps://github.com/numba/numba/issues/new\n" + ] + } + ], "source": [ "@jit(nopython=True)\n", "def cannot_compile(x):\n", @@ -498,11 +642,24 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "ename": "TypingError", + "evalue": "Failed in nopython mode pipeline (step: nopython frontend)\nInternal error at :\n--%<----------------------------------------------------------------------------\nTraceback (most recent call last):\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/errors.py\", line 599, in new_error_context\n yield\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 199, in __call__\n assert ty.is_precise()\nAssertionError\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 142, in propagate\n constraint(typeinfer)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 200, in __call__\n typeinfer.add_type(self.dst, ty, loc=self.loc)\n File \"/home/appuser/Miniconda3/lib/python3.6/contextlib.py\", line 99, in __exit__\n self.gen.throw(type, value, traceback)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/errors.py\", line 607, in new_error_context\n six.reraise(type(newerr), newerr, tb)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/six.py\", line 659, in reraise\n raise value\nnumba.errors.InternalError: \n[1] During: typing of argument at (5)\n--%<----------------------------------------------------------------------------\n\n\nFile \"\", line 5:\ndef cannot_compile(x):\n return x['key']\n ^\n\nThis error may have been caused by the following argument(s):\n- argument 0: cannot determine Numba type of \n\nThis is not usually a problem with Numba itself but instead often caused by\nthe use of unsupported features or an issue in resolving types.\n\nTo see Python/NumPy features supported by the latest release of Numba visit:\nhttp://numba.pydata.org/numba-doc/dev/reference/pysupported.html\nand\nhttp://numba.pydata.org/numba-doc/dev/reference/numpysupported.html\n\nFor more information about typing errors and how to debug them visit:\nhttp://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-doesn-t-compile\n\nIf you think your code should work with Numba, please report the error message\nand traceback, along with a minimal reproducer at:\nhttps://github.com/numba/numba/issues/new\n", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypingError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'key'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mcannot_compile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'value'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/dispatcher.py\u001b[0m in \u001b[0;36m_compile_for_args\u001b[0;34m(self, *args, **kws)\u001b[0m\n\u001b[1;32m 346\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpatch_message\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 347\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 348\u001b[0;31m \u001b[0merror_rewrite\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'typing'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 349\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mUnsupportedError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 350\u001b[0m \u001b[0;31m# Something unsupported is present in the user code, add help info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/dispatcher.py\u001b[0m in \u001b[0;36merror_rewrite\u001b[0;34m(e, issue_type)\u001b[0m\n\u001b[1;32m 313\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 314\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 315\u001b[0;31m \u001b[0mreraise\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 316\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 317\u001b[0m \u001b[0margtypes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/six.py\u001b[0m in \u001b[0;36mreraise\u001b[0;34m(tp, value, tb)\u001b[0m\n\u001b[1;32m 656\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 657\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__traceback__\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 658\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 659\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 660\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypingError\u001b[0m: Failed in nopython mode pipeline (step: nopython frontend)\nInternal error at :\n--%<----------------------------------------------------------------------------\nTraceback (most recent call last):\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/errors.py\", line 599, in new_error_context\n yield\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 199, in __call__\n assert ty.is_precise()\nAssertionError\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 142, in propagate\n constraint(typeinfer)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/typeinfer.py\", line 200, in __call__\n typeinfer.add_type(self.dst, ty, loc=self.loc)\n File \"/home/appuser/Miniconda3/lib/python3.6/contextlib.py\", line 99, in __exit__\n self.gen.throw(type, value, traceback)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/errors.py\", line 607, in new_error_context\n six.reraise(type(newerr), newerr, tb)\n File \"/home/appuser/Miniconda3/lib/python3.6/site-packages/numba/six.py\", line 659, in reraise\n raise value\nnumba.errors.InternalError: \n[1] During: typing of argument at (5)\n--%<----------------------------------------------------------------------------\n\n\nFile \"\", line 5:\ndef cannot_compile(x):\n return x['key']\n ^\n\nThis error may have been caused by the following argument(s):\n- argument 0: cannot determine Numba type of \n\nThis is not usually a problem with Numba itself but instead often caused by\nthe use of unsupported features or an issue in resolving types.\n\nTo see Python/NumPy features supported by the latest release of Numba visit:\nhttp://numba.pydata.org/numba-doc/dev/reference/pysupported.html\nand\nhttp://numba.pydata.org/numba-doc/dev/reference/numpysupported.html\n\nFor more information about typing errors and how to debug them visit:\nhttp://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-doesn-t-compile\n\nIf you think your code should work with Numba, please report the error message\nand traceback, along with a minimal reproducer at:\nhttps://github.com/numba/numba/issues/new\n" + ] + } + ], "source": [ "from numba import njit\n", "\n", @@ -553,11 +710,20 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([11, 22, 33, 44])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import numpy as np\n", "\n", @@ -576,11 +742,20 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([101, 102, 103, 104])" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "np.add(a, 100) # Returns a new NumPy array resulting from adding 100 to every element in `a`" ] @@ -594,11 +769,33 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "c: [[ 0 1 2 3]\n", + " [ 4 5 6 7]\n", + " [ 8 9 10 11]\n", + " [12 13 14 15]]\n" + ] + }, + { + "data": { + "text/plain": [ + "array([[10, 21, 32, 43],\n", + " [14, 25, 36, 47],\n", + " [18, 29, 40, 51],\n", + " [22, 33, 44, 55]])" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "c = np.arange(4*4).reshape((4,4))\n", "print('c:', c)\n", @@ -624,7 +821,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": { "collapsed": true }, @@ -639,11 +836,20 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "nums = np.arange(10)\n", "add_ten(nums) # pass the whole array into the ufunc, it performs the operation on each element" @@ -665,7 +871,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "metadata": { "collapsed": true }, @@ -678,11 +884,20 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([11, 22, 33, 44])" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "add_ufunc(a, b)" ] @@ -707,22 +922,34 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "997 ns ± 0.647 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n" + ] + } + ], "source": [ "%timeit np.add(b, c) # NumPy on CPU" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "680 µs ± 1.71 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" + ] + } + ], "source": [ "%timeit add_ufunc(b, c) # Numba on GPU" ] @@ -746,7 +973,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "metadata": { "collapsed": true }, @@ -764,11 +991,20 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.00926774], dtype=float32)" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import numpy as np\n", "# Evaluate the Gaussian a million times!\n", @@ -782,11 +1018,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "63.8 ms ± 120 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" + ] + } + ], "source": [ "import scipy.stats # for definition of gaussian distribution, so we can compare CPU to GPU time\n", "norm_pdf = scipy.stats.norm\n", @@ -795,11 +1037,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4.15 ms ± 105 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], "source": [ "%timeit gaussian_pdf(x, mean, sigma)" ] @@ -815,7 +1063,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "metadata": { "collapsed": true }, @@ -829,11 +1077,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "22.4 ms ± 51.6 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" + ] + } + ], "source": [ "%timeit cpu_gaussian_pdf(x, mean, sigma)" ] @@ -860,7 +1114,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 40, "metadata": { "collapsed": true }, @@ -884,7 +1138,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'DeviceFunctionTemplate' object is not callable", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mpolar_to_cartesian\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m: 'DeviceFunctionTemplate' object is not callable" + ] + } + ], + "source": [ + "polar_to_cartesian(1.0, 2.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, "metadata": { "collapsed": true }, @@ -899,11 +1174,21 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([2.2186031, 1.3172561, 1.4999884, ..., 0.7888327, 2.3476734,\n", + " 1.5603681], dtype=float32)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "polar_distance(rho1, theta1, rho2, theta2)" ] @@ -943,11 +1228,30 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n/j96nzZ+iupJRQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# This allows us to plot right here in the notebook\n", "%matplotlib inline\n", @@ -971,12 +1275,11 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, + "execution_count": 53, + "metadata": {}, "outputs": [], "source": [ + "@vectorize(['int16(int16, int16)'], target='cuda')\n", "def zero_suppress(waveform_value, threshold):\n", " if waveform_value < threshold:\n", " result = 0\n", @@ -987,11 +1290,30 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\nTvSMMWa4/wVgxNtGhr5GaQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# This will throw an error until you successfully vectorize the `zero_suppress` function above.\n", "# The noise on the baseline should disappear when zero_suppress is implemented\n", @@ -1019,7 +1341,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 55, "metadata": { "collapsed": true }, @@ -1032,7 +1354,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 56, "metadata": { "collapsed": true, "scrolled": true @@ -1046,11 +1368,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.12 ms ± 552 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" + ] + } + ], "source": [ "%timeit add_ufunc(x, y) # Baseline performance with host arrays" ] @@ -1064,11 +1392,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "(100000,)\n", + "float32\n" + ] + } + ], "source": [ "from numba import cuda\n", "\n", @@ -1089,11 +1425,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "537 µs ± 339 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" + ] + } + ], "source": [ "%timeit add_ufunc(x_device, y_device)" ] @@ -1109,7 +1451,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 60, "metadata": { "collapsed": true }, @@ -1129,11 +1471,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "448 µs ± 1.29 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" + ] + } + ], "source": [ "%timeit add_ufunc(x_device, y_device, out=out_device)" ] @@ -1147,11 +1495,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 0. 3. 6. 9. 12. 15. 18. 21. 24. 27.]\n" + ] + } + ], "source": [ "out_host = out_device.copy_to_host()\n", "print(out_host[:10])" @@ -1179,7 +1533,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 63, "metadata": { "collapsed": true }, @@ -1208,23 +1562,44 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, + "execution_count": 71, + "metadata": {}, "outputs": [], "source": [ - "pulses = make_pulses(t, period, 100.0)\n", - "waveform = add_ufunc(pulses, noise)" + "noise_dev = cuda.to_device(noise)\n", + "t_dev = cuda.to_device(t)\n", + "pulses_dev = cuda.device_array(shape=(n,), dtype=np.float32)\n", + "\n", + "make_pulses(t_dev, period, 100.0, out=pulses_dev)\n", + "waveform = add_ufunc(pulses_dev, noise_dev)" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "%matplotlib inline\n", "from matplotlib import pyplot as plt\n", @@ -1274,7 +1649,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 73, "metadata": { "collapsed": true }, @@ -1310,7 +1685,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 74, "metadata": { "collapsed": true }, @@ -1319,31 +1694,35 @@ "# As you will recall, `numpy.exp` works on the CPU, but, cannot be used in GPU implmentations.\n", "# This import will work for the CPU-only boilerplate code provided below, but\n", "# you will need to modify this import before your GPU implementation will work.\n", - "from numpy import exp" + "# from numpy import exp\n", + "from math import exp" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 75, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Modify these 3 function calls to run on the GPU.\n", + "@vectorize(['float32(float32)'], target = 'cuda')\n", "def normalize(grayscales):\n", " return grayscales / 255\n", "\n", + "@vectorize(['float32(float32, float32)'], target = 'cuda')\n", "def weigh(values, weights):\n", " return values * weights\n", " \n", + "@vectorize(['float32(float32)'], target = 'cuda')\n", "def activate(values):\n", " return ( exp(values) - exp(-values) ) / ( exp(values) + exp(-values) )" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 84, "metadata": { "collapsed": true }, @@ -1352,15 +1731,19 @@ "# Modify the body of this function to optimize data transfers and therefore speed up performance.\n", "# As a constraint, even after you move work to the GPU, make this function return a host array.\n", "def create_hidden_layer(n, greyscales, weights, exp, normalize, weigh, activate):\n", + " greyscales_dev = cuda.to_device(greyscales)\n", + " weights_dev = cuda.to_device(weights)\n", + " \n", + " norm_dev = cuda.device_array(shape=(n,), dtype=np.float32)\n", + " weighted_dev = cuda.device_array(shape=(n,), dtype=np.float32)\n", + " activated_dev = cuda.device_array(shape=(n,), dtype=np.float32)\n", " \n", - " normalized = normalize(greyscales)\n", - " weighted = weigh(normalized, weights)\n", - " activated = activate(weighted)\n", + " normalize(greyscales, out=norm_dev)\n", + " weigh(norm_dev, weights_dev, out=weighted_dev)\n", + " activate(weighted_dev, out=activated_dev)\n", " \n", - " # The assessment mechanism will expect `activated` to be a host array, so,\n", - " # even after you refactor this code to run on the GPU, make sure to explicitly copy\n", - " # `activated` back to the host.\n", - " return activated" + " out_host = activated_dev.copy_to_host()\n", + " return out_host" ] }, { @@ -1379,7 +1762,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 85, "metadata": { "collapsed": true }, @@ -1398,11 +1781,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 86, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0.3338969 0.11722048 0.08675494 ... 0.1048661 0.18585935 0.05007837]\n" + ] + } + ], "source": [ "# Use this cell (and feel free to create others) to self-assess your function\n", "a = create_hidden_layer(**arguments)\n", @@ -1425,7 +1814,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 82, "metadata": { "collapsed": true }, @@ -1436,12 +1825,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 87, "metadata": { - "collapsed": true, "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting n to 100 million.\n", + "\n", + "Your function returns a host np.ndarray: True\n", + "\n", + "Your function took 0.56s to run.\n", + "Your function runs fast enough (less than 1 second): True\n", + "\n", + "Your function returns the correct results: True\n", + "Congratulations, you passed! See the instructions below for how to get credit for your work to count toward a certificate in the course.\n" + ] + } + ], "source": [ "assess(create_hidden_layer, arguments)" ] @@ -1493,11 +1897,29 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "./\r\n", + "./.ipynb_checkpoints/\r\n", + "./.ipynb_checkpoints/Introduction to CUDA Python with Numba-checkpoint.ipynb\r\n", + "./Introduction to CUDA Python with Numba.ipynb\r\n", + "./solutions/\r\n", + "./solutions/make_pulses_solution.py\r\n", + "./solutions/zero_suppress_solution.py\r\n", + "./solutions/monte_carlo_pi_solution.py\r\n", + "./images/\r\n", + "./images/DLI Header.png\r\n", + "./images/run_the_assessment.png\r\n", + "./images/numba_flowchart.png\r\n", + "tar: .: file changed as we read it\r\n" + ] + } + ], "source": [ "!tar -zcvf section1.tar.gz ." ] @@ -1528,7 +1950,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 89, "metadata": { "collapsed": true }, @@ -1563,11 +1985,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[-0.53340748 -0.84585842]\n", + " [-0.6538219 0.75664848]\n", + " [-0.33922312 0.94070594]\n", + " [ 0.66932384 -0.7429708 ]\n", + " [-0.80223363 0.59701022]\n", + " [-0.88033165 0.47435871]\n", + " [ 0.65265486 -0.75765535]\n", + " [ 0.83383129 -0.55201937]\n", + " [ 0.64985792 -0.76005571]\n", + " [-0.83615082 -0.54849959]]\n" + ] + } + ], "source": [ "angles = np.random.uniform(-np.pi, np.pi, 10)\n", "coords = np.stack([np.cos(angles), np.sin(angles)], axis=1)\n", @@ -1583,11 +2020,22 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1. , 1. , 1. , 1. , 1. ,\n", + " 0.99999994, 1. , 1. , 1. , 1. ],\n", + " dtype=float32)" + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "l2_norm(coords)" ] -- cgit v1.2.3