{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Intro to Torch.ONNX—End-to-end AlexNet from PyTorch to Caffe2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exporting model from PyTorch to ONNX." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this tutorial, we describe how to use ONNX to convert a model defined in PyTorch into the ONNX format.\n", "\n", "ONNX is natively supported in PyTorch. However, ONNX exporter is **not yet** part of the [PyTorch repository](http://pytorch.org/docs/master/onnx.html) as what they mentioned.\n", "\n", "For working with this tutorial, you will need to install [ONNX](https://github.com/onnx/onnx). You can get binary builds of ONNX with `conda install onnx`.\n", "\n", "_NOTE: ONNX is under active development so for the best support consider building PyTorch master branch which can be installed by following [the instructions here](https://github.com/pytorch/pytorch#from-source) or install PyTorch preview using `conda install pytorch-nightly cuda92 -c pytorch`._" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will export a pretrained AlexNet as defined in `torchvision` into ONNX. It runs a single round of inference and then saves the resulting traced model to `alexnet.onnx` file." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Invoking exporter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pretty much it's a matter of replacing `my_model(input)` with `torch.onnx.export(my_model, input, \"my_model.onnx\")` in your script." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Limitations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ONNX exporter is a trace-based exporter, which means that it operates by executing your model once, and exporting the operators which were actually run during this run. This means that if your model is dynamic, e.g., changes behavior depending on input data, the export won’t be accurate.\n", "\n", "Similarly, a trace is might be valid only for a specific input size (which is one reason why we require explicit inputs on tracing). Most of the operators export size-agnostic versions and should work on different batch sizes or input sizes. We recommend examining the model trace and making sure the traced operators look reasonable." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import torch\n", "import torchvision" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Trying it out on AlexNet" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you already have your model built, it's just a few lines:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# Standard ImageNet input - 3 channels, 224x224,\n", "# values don't matter as we care about network structure.\n", "# But they can also be real inputs.\n", "dummy_input = torch.rand(10, 3, 224, 224, device='cuda')\n", "# Obtain your model, it can be also constructed in your script explicitly\n", "model = torchvision.models.alexnet(pretrained=True).cuda()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Providing input and output names sets the display names for values within the model's graph. Setting these does not change the semantics of the graph; it is only for readability.\n", "\n", "The inputs to the network consist of the flat list of inputs (i.e. the values you would pass to the forward() method) followed by the flat list of parameters. You can partially specify names, i.e. provide a list here shorter than the number of inputs to the model, and we will only set that subset of names, starting from the beginning." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "input_names = [\"actual_input_1\"] + [\"learned_%d\" % i for i in range(16)]\n", "output_names = [\"output1\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Invoke export:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "graph(%actual_input_1 : Float(10, 3, 224, 224)\n", " %learned_0 : Float(64, 3, 11, 11)\n", " %learned_1 : Float(64)\n", " %learned_2 : Float(192, 64, 5, 5)\n", " %learned_3 : Float(192)\n", " %learned_4 : Float(384, 192, 3, 3)\n", " %learned_5 : Float(384)\n", " %learned_6 : Float(256, 384, 3, 3)\n", " %learned_7 : Float(256)\n", " %learned_8 : Float(256, 256, 3, 3)\n", " %learned_9 : Float(256)\n", " %learned_10 : Float(4096, 9216)\n", " %learned_11 : Float(4096)\n", " %learned_12 : Float(4096, 4096)\n", " %learned_13 : Float(4096)\n", " %learned_14 : Float(1000, 4096)\n", " %learned_15 : Float(1000)) {\n", " %17 : Float(10, 64, 55, 55) = onnx::Conv[dilations=[1, 1], group=1, kernel_shape=[11, 11], pads=[2, 2, 2, 2], strides=[4, 4]](%actual_input_1, %learned_0, %learned_1), scope: AlexNet/Sequential[features]/Conv2d[0]\n", " %18 : Float(10, 64, 55, 55) = onnx::Relu(%17), scope: AlexNet/Sequential[features]/ReLU[1]\n", " %19 : Float(10, 64, 27, 27) = onnx::MaxPool[kernel_shape=[3, 3], pads=[0, 0, 0, 0], strides=[2, 2]](%18), scope: AlexNet/Sequential[features]/MaxPool2d[2]\n", " %20 : Float(10, 192, 27, 27) = onnx::Conv[dilations=[1, 1], group=1, kernel_shape=[5, 5], pads=[2, 2, 2, 2], strides=[1, 1]](%19, %learned_2, %learned_3), scope: AlexNet/Sequential[features]/Conv2d[3]\n", " %21 : Float(10, 192, 27, 27) = onnx::Relu(%20), scope: AlexNet/Sequential[features]/ReLU[4]\n", " %22 : Float(10, 192, 13, 13) = onnx::MaxPool[kernel_shape=[3, 3], pads=[0, 0, 0, 0], strides=[2, 2]](%21), scope: AlexNet/Sequential[features]/MaxPool2d[5]\n", " %23 : Float(10, 384, 13, 13) = onnx::Conv[dilations=[1, 1], group=1, kernel_shape=[3, 3], pads=[1, 1, 1, 1], strides=[1, 1]](%22, %learned_4, %learned_5), scope: AlexNet/Sequential[features]/Conv2d[6]\n", " %24 : Float(10, 384, 13, 13) = onnx::Relu(%23), scope: AlexNet/Sequential[features]/ReLU[7]\n", " %25 : Float(10, 256, 13, 13) = onnx::Conv[dilations=[1, 1], group=1, kernel_shape=[3, 3], pads=[1, 1, 1, 1], strides=[1, 1]](%24, %learned_6, %learned_7), scope: AlexNet/Sequential[features]/Conv2d[8]\n", " %26 : Float(10, 256, 13, 13) = onnx::Relu(%25), scope: AlexNet/Sequential[features]/ReLU[9]\n", " %27 : Float(10, 256, 13, 13) = onnx::Conv[dilations=[1, 1], group=1, kernel_shape=[3, 3], pads=[1, 1, 1, 1], strides=[1, 1]](%26, %learned_8, %learned_9), scope: AlexNet/Sequential[features]/Conv2d[10]\n", " %28 : Float(10, 256, 13, 13) = onnx::Relu(%27), scope: AlexNet/Sequential[features]/ReLU[11]\n", " %29 : Float(10, 256, 6, 6) = onnx::MaxPool[kernel_shape=[3, 3], pads=[0, 0, 0, 0], strides=[2, 2]](%28), scope: AlexNet/Sequential[features]/MaxPool2d[12]\n", " %30 : Long() = onnx::Constant[value={0}]()\n", " %31 : Dynamic = onnx::Shape(%29), scope: AlexNet\n", " %32 : Long() = onnx::Gather[axis=0](%31, %30), scope: AlexNet\n", " %33 : Long() = onnx::Constant[value={9216}]()\n", " %34 : Dynamic = onnx::Unsqueeze[axes=[0]](%32), scope: AlexNet\n", " %35 : Dynamic = onnx::Unsqueeze[axes=[0]](%33), scope: AlexNet\n", " %36 : int[] = onnx::Concat[axis=0](%34, %35), scope: AlexNet\n", " %37 : Float(10, 9216) = onnx::Reshape(%29, %36), scope: AlexNet\n", " %38 : Float(10, 9216), %39 : Dynamic = onnx::Dropout[ratio=0.5](%37), scope: AlexNet/Sequential[classifier]/Dropout[0]\n", " %40 : Float(10, 4096) = onnx::Gemm[alpha=1, beta=1, transB=1](%38, %learned_10, %learned_11)\n", " %41 : Float(10, 4096) = onnx::Relu(%40), scope: AlexNet/Sequential[classifier]/ReLU[2]\n", " %42 : Float(10, 4096), %43 : Dynamic = onnx::Dropout[ratio=0.5](%41), scope: AlexNet/Sequential[classifier]/Dropout[3]\n", " %44 : Float(10, 4096) = onnx::Gemm[alpha=1, beta=1, transB=1](%42, %learned_12, %learned_13)\n", " %45 : Float(10, 4096) = onnx::Relu(%44), scope: AlexNet/Sequential[classifier]/ReLU[5]\n", " %output1 : Float(10, 1000) = onnx::Gemm[alpha=1, beta=1, transB=1](%45, %learned_14, %learned_15)\n", " return (%output1);\n", "}\n", "\n" ] } ], "source": [ "torch.onnx.export(model, dummy_input, \"alexnet.onnx\", verbose=True, input_names=input_names,\n", " output_names=output_names)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**That's it!**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The resulting ``alexnet.onnx`` is a **binary protobuf file** which contains both\n", "the network structure and parameters of the model you exported\n", "(in this case, AlexNet). The keyword argument ``verbose=True`` causes the\n", "exporter to print out a human-readable representation of the network:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Inspecting model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use ONNX tooling to check the validity of the resulting model or inspect the details.\n", "\n", "You can verify the protobuf using the ONNX library." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Install ONNX" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, we need to install ONNX library:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can install onnx with conda:\n", "\n", "`conda install -c conda-forge onnx`" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "ename": "ModuleNotFoundError", "evalue": "No module named 'onnx'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mModuleNotFoundError\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[0;32mimport\u001b[0m \u001b[0monnx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'onnx'" ] } ], "source": [ "import onnx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Fix the previous error**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_WARNING: Don't install `onnx` from conda-forge channel. Run this command instead:_\n", "\n", "`conda install onnx`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If it fails and you see these errors:\n", "\n", "1. \"Solving environment: failed ...\":\n", "\n", "![thank to Haider for reporting this issue](../../../images/fastai_mobile/onnx_installation_error_1.png)\n", "\n", "Some possible solutions:\n", "- Ensure you are using Python version 3.6, not 3.7\n", "- Create a clean (new) Conda environment and install PyTorch 1.0 preview (nightly) and **nothing else**\n", "- _Note: don't install '[onnx-caffe2](https://github.com/onnx/onnx-caffe2)'. This repo is deprecated._\n", "\n", "If all else fails, please go to [ONNX GitHub repo](https://github.com/onnx/onnx#source). Then follow the instructions there.\n", "> You will need an install of [protobuf](https://github.com/protocolbuffers/protobuf).\n", "\n", "It will be a pain in the neck to install the correct version of protobuf that plays well with ONNX. A lot of factors can caused this step to fail. This highly depends on your system environment, such as the version of Ubuntu OS, are there any existing protobuf libraries installed by TensorFlow or even Ubuntu previously, etc.\n", "\n", "What works for me is, first I make sure to install the Protobuf compiler before building and installing ONNX locally from source code (_running the conda installation of onnx for some strange reason doesn't work for me_).\n", "\n", "```sh\n", "git clone https://github.com/onnx/onnx.git\n", "cd onnx\n", "git submodule update --init --recursive\n", "python setup.py install\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For other ONNX issues that I experienced, [see ONNX issues](#ONNX-Issues) section below.\n", "\n", "[ONNX issue specific to protocol buffer](#Protocol-Buffer-Required-by-ONNX)." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "import onnx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Load the ONNX model:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "model = onnx.load(\"alexnet.onnx\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Check that the IR is well formed:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "onnx.checker.check_model(model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print a human readable representation of the graph:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "graph torch-jit-export (\n", " %actual_input_1[FLOAT, 10x3x224x224]\n", ") initializers (\n", " %learned_0[FLOAT, 64x3x11x11]\n", " %learned_1[FLOAT, 64]\n", " %learned_2[FLOAT, 192x64x5x5]\n", " %learned_3[FLOAT, 192]\n", " %learned_4[FLOAT, 384x192x3x3]\n", " %learned_5[FLOAT, 384]\n", " %learned_6[FLOAT, 256x384x3x3]\n", " %learned_7[FLOAT, 256]\n", " %learned_8[FLOAT, 256x256x3x3]\n", " %learned_9[FLOAT, 256]\n", " %learned_10[FLOAT, 4096x9216]\n", " %learned_11[FLOAT, 4096]\n", " %learned_12[FLOAT, 4096x4096]\n", " %learned_13[FLOAT, 4096]\n", " %learned_14[FLOAT, 1000x4096]\n", " %learned_15[FLOAT, 1000]\n", ") {\n", " %17 = Conv[dilations = [1, 1], group = 1, kernel_shape = [11, 11], pads = [2, 2, 2, 2], strides = [4, 4]](%actual_input_1, %learned_0, %learned_1)\n", " %18 = Relu(%17)\n", " %19 = MaxPool[kernel_shape = [3, 3], pads = [0, 0, 0, 0], strides = [2, 2]](%18)\n", " %20 = Conv[dilations = [1, 1], group = 1, kernel_shape = [5, 5], pads = [2, 2, 2, 2], strides = [1, 1]](%19, %learned_2, %learned_3)\n", " %21 = Relu(%20)\n", " %22 = MaxPool[kernel_shape = [3, 3], pads = [0, 0, 0, 0], strides = [2, 2]](%21)\n", " %23 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%22, %learned_4, %learned_5)\n", " %24 = Relu(%23)\n", " %25 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%24, %learned_6, %learned_7)\n", " %26 = Relu(%25)\n", " %27 = Conv[dilations = [1, 1], group = 1, kernel_shape = [3, 3], pads = [1, 1, 1, 1], strides = [1, 1]](%26, %learned_8, %learned_9)\n", " %28 = Relu(%27)\n", " %29 = MaxPool[kernel_shape = [3, 3], pads = [0, 0, 0, 0], strides = [2, 2]](%28)\n", " %30 = Constant[value = ]()\n", " %31 = Shape(%29)\n", " %32 = Gather[axis = 0](%31, %30)\n", " %33 = Constant[value = ]()\n", " %34 = Unsqueeze[axes = [0]](%32)\n", " %35 = Unsqueeze[axes = [0]](%33)\n", " %36 = Concat[axis = 0](%34, %35)\n", " %37 = Reshape(%29, %36)\n", " %38, %39 = Dropout[ratio = 0.5](%37)\n", " %40 = Gemm[alpha = 1, beta = 1, transB = 1](%38, %learned_10, %learned_11)\n", " %41 = Relu(%40)\n", " %42, %43 = Dropout[ratio = 0.5](%41)\n", " %44 = Gemm[alpha = 1, beta = 1, transB = 1](%42, %learned_12, %learned_13)\n", " %45 = Relu(%44)\n", " %output1 = Gemm[alpha = 1, beta = 1, transB = 1](%45, %learned_14, %learned_15)\n", " return %output1\n", "}\n" ] } ], "source": [ "print(onnx.helper.printable_graph(model.graph))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that all parameters are listed as graph's inputs but they also have stored values initialized in `model.graph.initializers`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Caffe2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To run the following code with [Caffe2](https://caffe2.ai/), you will need to install Caffe2: If you don’t have one already, Please [follow the install instructions](https://caffe2.ai/docs/getting-started.html).\n", "\n", "_**NOTE: actually Caffe2 is already installed when you install PyTorch. And Caffe2 source code now lives in the PyTorch repository.**_ The following describe why the confusion:\n", "\n", "I referenced the following GitHub issues because of the discrepancies in current PyTorch docs and Caffe2 docs. The PyTorch docs lacks Caffe2 information, not clear enough or outdated. This confusing state has spawned out a large chunk of GitHub issues, for examples:\n", "- [Why it is so difficult to install caffe2??? (Jan 2018)](https://github.com/caffe2/caffe2/issues/1811)\n", "- [How to intall and use Caffe2 from this Pytorch branch?](https://github.com/pytorch/pytorch/issues/7029)\n", "- [Caffe2 Installation inside Pytorch](https://github.com/pytorch/pytorch/issues/12646)\n", "\n", "Once these are installed, you can use the backend for Caffe2:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "ename": "ModuleNotFoundError", "evalue": "No module named 'past'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mModuleNotFoundError\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 1\u001b[0m \u001b[0;31m# ...continuing from above\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mcaffe2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpython\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0monnx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbackend\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mbackend\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/anaconda3/envs/fastai-v1/lib/python3.6/site-packages/caffe2/python/onnx/backend.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 25\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcaffe2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 27\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mcaffe2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpython\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcore\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mworkspace\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrnn_cell\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgru_cell\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 28\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mcaffe2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpython\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcompatibility\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcontainer_abcs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mcaffe2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpython\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodel_helper\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mModelHelper\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/anaconda3/envs/fastai-v1/lib/python3.6/site-packages/caffe2/python/core.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mcollections\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnamedtuple\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mOrderedDict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdefaultdict\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mpast\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuiltins\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbasestring\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 10\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mfuture\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mviewitems\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mviewkeys\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mviewvalues\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mitertools\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mchain\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'past'" ] } ], "source": [ "# ...continuing from above\n", "import caffe2.python.onnx.backend as backend\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fix the previous error by installing the `future` package:\n", "\n", "`conda install future`\n", "\n", "Ref: https://github.com/caffe2/caffe2/issues/712#issuecomment-305962653" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# ...continuing from above\n", "import caffe2.python.onnx.backend as backend\n", "import numpy as np" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "CUDA operators do not support 64-bit doubles, please use arr.astype(np.float32) or np.int32 for ints. Blob: actual_input_1 type: float64\n" ] } ], "source": [ "rep = backend.prepare(model, device=\"CUDA:0\") # or \"CPU\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Get Predictions by Running the Model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The results come back as a multidimensional array of probabilities. Essentially each row is a percentage chance that the object matches something that the neural net recognizes. For example, when you run the flower it should give you over 95% rating that the flower is a daisy." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# For the Caffe2 backend:\n", "# rep.predict_net is the Caffe2 protobuf for the network\n", "# rep.workspace is the Caffe2 workspace for the network\n", "# (see the class caffe2.python.onnx.backend.Workspace)\n", "outputs = rep.run(np.random.randn(10, 3, 224, 224).astype(np.float32))" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 0.18165639 -1.3775781 -0.92282146 ... -1.0521079 -1.2983803\n", " 1.0103724 ]\n", " [ 0.01864959 -1.3792061 -1.3302151 ... -1.2658304 -0.76998174\n", " 0.9446579 ]\n", " [ 0.07622778 -1.1739718 -1.3213743 ... -1.0105549 -0.7218681\n", " 1.1605347 ]\n", " ...\n", " [-0.4785444 -1.2650945 -1.1094304 ... -1.1017692 -1.1647667\n", " 1.1024661 ]\n", " [ 0.11569691 -1.1947066 -1.456512 ... -1.3352914 -0.87671846\n", " 1.0735546 ]\n", " [-0.4444798 -1.4828541 -1.5199043 ... -1.2288797 -1.0344319\n", " 1.1123722 ]]\n" ] } ], "source": [ "# To run networks with more than one input, pass a tuple\n", "# rather than a single numpy ndarray.\n", "print(outputs[0])" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(10, 1000)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "outputs[0].shape # 10 inputs and predictions (ImageNet 1000 classes) for each input" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ========================== END OF TUTORIAL ==========================" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More on ONNX" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### LIMITATIONS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- The ONNX exporter is a trace-based exporter, which means that it operates by executing your model once, and exporting the operators which were actually run during this run. This means that if your model is dynamic, e.g., changes behavior depending on input data, the export won’t be accurate. Similarly, a trace is likely to be valid only for a specific input size (which is one reason why we require explicit inputs on tracing.) We recommend examining the model trace and making sure the traced operators look reasonable.\n", "- PyTorch and Caffe2 often have implementations of operators with some numeric differences. Depending on model structure, these differences may be negligible, but they can also cause major divergences in behavior (especially on untrained models.) In a future release, we plan to allow Caffe2 to call directly to Torch implementations of operators, to help you smooth over these differences when precision is important, and to also document these differences." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### SUPPORTED OPERATORS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following operators are supported:\n", "\n", "- add (nonzero alpha not supported)\n", "- sub (nonzero alpha not supported)\n", "- mul\n", "- div\n", "- cat\n", "- mm\n", "- addmm\n", "- neg\n", "- sqrt\n", "- tanh\n", "- sigmoid\n", "- mean\n", "- sum\n", "- prod\n", "- t\n", "- expand (only when used before a broadcasting ONNX operator; e.g., add)\n", "- transpose\n", "- view\n", "- split\n", "- squeeze\n", "- ...and many more\n", "\n", "The operator set above is sufficient to export the following models:\n", "\n", "- AlexNet\n", "- DCGAN\n", "- DenseNet\n", "- Inception (warning: this model is highly sensitive to changes in operator implementation)\n", "- ResNet\n", "- SuperResolution\n", "- VGG\n", "- word_language_model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Adding export support for operators is an _advance_ usage. To achieve this, developers need to touch the source code of PyTorch. Please follow the [instructions](https://github.com/pytorch/pytorch#from-source) for installing PyTorch from source. If the wanted operator is standardized in ONNX, it should be easy to add support for exporting such operator (adding a symbolic function for the operator). To confirm whether the operator is standardized or not, please check the [ONNX operator list](https://github.com/onnx/onnx/blob/master/docs/Operators.md).\n", "\n", "If the operator is an ATen operator, which means you can find the declaration of the function in `torch/csrc/autograd/generated/VariableType.h` (available in generated code in PyTorch install dir), you should add the symbolic function in `torch/onnx/symbolic.py` and follow the instructions listed as below:\n", "\n", "- Define the symbolic function in [torch/onnx/symbolic.py](https://github.com/pytorch/pytorch/blob/master/torch/onnx/symbolic.py). Make sure the function has the same name as the ATen operator/function defined in `VariableType.h`.\n", "- The first parameter is always the exported ONNX graph. Parameter names must EXACTLY match the names in `VariableType.h`, because dispatch is done with keyword arguments.\n", "- Parameter ordering does NOT necessarily match what is in `VariableType.h`, tensors (inputs) are always first, then non-tensor arguments.\n", "- In the symbolic function, if the operator is already standardized in ONNX, we only need to create a node to represent the ONNX operator in the graph.\n", "- If the input argument is a tensor, but ONNX asks for a scalar, we have to explicitly do the conversion. The helper function `_scalar` can convert a scalar tensor into a python scalar, and `_if_scalar_type_as` can turn a Python scalar into a PyTorch tensor.\n", "\n", "If the operator is a non-ATen operator, the symbolic function has to be added in the corresponding PyTorch Function class. Please read the following instructions:\n", "\n", "- Create a symbolic function named `symbolic` in the corresponding Function class.\n", "- The first parameter is always the exported ONNX graph.\n", "- Parameter names except the first must EXACTLY match the names in `forward`.\n", "- The output tuple size must match the outputs of `forward`.\n", "- In the symbolic function, if the operator is already standardized in ONNX, we just need to create a node to represent the ONNX operator in the graph." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Symbolic functions should be implemented in Python. All of these functions interact with Python methods which are implemented via C++-Python bindings, but intuitively the interface they provide looks like this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def operator/symbolic(g, *inputs):\n", " \"\"\"\n", " Modifies Graph (e.g., using \"op\"), adding the ONNX operations representing\n", " this PyTorch function, and returning a Value or tuple of Values specifying the\n", " ONNX outputs whose values correspond to the original PyTorch return values\n", " of the autograd Function (or None if an output is not supported by ONNX).\n", "\n", " Arguments:\n", " g (Graph): graph to write the ONNX representation into\n", " inputs (Value...): list of values representing the variables which contain\n", " the inputs for this function\n", " \"\"\"\n", "\n", "class Value(object):\n", " \"\"\"Represents an intermediate tensor value computed in ONNX.\"\"\"\n", " def type(self):\n", " \"\"\"Returns the Type of the value.\"\"\"\n", "\n", "class Type(object):\n", " def sizes(self):\n", " \"\"\"Returns a tuple of ints representing the shape of a tensor this describes.\"\"\"\n", "\n", "class Graph(object):\n", " def op(self, opname, *inputs, **attrs):\n", " \"\"\"\n", " Create an ONNX operator 'opname', taking 'args' as inputs\n", " and attributes 'kwargs' and add it as a node to the current graph,\n", " returning the value representing the single output of this\n", " operator (see the `outputs` keyword argument for multi-return\n", " nodes).\n", "\n", " The set of operators and the inputs/attributes they take\n", " is documented at https://github.com/onnx/onnx/blob/master/docs/Operators.md\n", "\n", " Arguments:\n", " opname (string): The ONNX operator name, e.g., `Abs` or `Add`.\n", " args (Value...): The inputs to the operator; usually provided\n", " as arguments to the `symbolic` definition.\n", " kwargs: The attributes of the ONNX operator, with keys named\n", " according to the following convention: `alpha_f` indicates\n", " the `alpha` attribute with type `f`. The valid type specifiers are\n", " `f` (float), `i` (int), `s` (string) or `t` (Tensor). An attribute\n", " specified with type float accepts either a single float, or a\n", " list of floats (e.g., you would say `dims_i` for a `dims` attribute\n", " that takes a list of integers).\n", " outputs (int, optional): The number of outputs this operator returns;\n", " by default an operator is assumed to return a single output.\n", " If `outputs` is greater than one, this functions returns a tuple\n", " of output `Value`, representing each output of the ONNX operator\n", " in positional.\n", " \"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ONNX graph C++ definition is in `torch/csrc/jit/ir.h`.\n", "\n", "Here is an example of handling missing symbolic function for `elu` operator. We try to export the model and see the error message as below:\n", "\n", "```sh\n", "UserWarning: ONNX export failed on elu because torch.onnx.symbolic.elu does not exist\n", "RuntimeError: ONNX export failed: Couldn't export operator elu\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The export fails because PyTorch does not support exporting `elu` operator. We find `virtual` `Tensor` `elu(const` `Tensor` `&` `input`, `Scalar` `alpha`, `bool` `inplace)` `const` `override;` in `VariableType.h`. This means `elu` is an ATen operator. We check the [ONNX operator list](http://https//github.com/onnx/onnx/blob/master/docs/Operators.md), and confirm that `Elu` is standardized in ONNX. We add the following lines to `symbolic.py`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def elu(g, input, alpha, inplace=False):\n", " return g.op(\"Elu\", input, alpha_f=_scalar(alpha))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now PyTorch is able to export `elu` operator.\n", "\n", "There are more examples in [symbolic.py](https://github.com/pytorch/pytorch/blob/master/torch/onnx/symbolic.py), [tensor.py](https://github.com/pytorch/pytorch/blob/99037d627da68cdf53d3d0315deceddfadf03bba/torch/autograd/_functions/tensor.py#L24), [padding.py](https://github.com/pytorch/pytorch/blob/99037d627da68cdf53d3d0315deceddfadf03bba/torch/nn/_functions/padding.py#L8).\n", "\n", "The interface for specifying operator definitions is experimental; adventurous users should note that the APIs will probably change in a future interface." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### FUNCTIONS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`torch.onnx.export(*args, **kwargs)`. [Source](https://pytorch.org/docs/master/_modules/torch/onnx.html#export)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ONNX Issues" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I experienced the following issues related to ONNX or the old ONNX-Caffe2 integration along the way in this task:\n", "- [RESOLVED] Error: \"ONNX checker Bad node spec\" and GitHub issues referenced:\n", " - https://github.com/onnx/onnx/issues/932\n", "- [RESOLVED] Error: \"onnx_cpp2py_export.cpython-36m-x86_64-linux-gnu.so: undefined symbol: ZNK6google8protobuf7Message11GetTypeNameB5cxx11Ev\" and GitHub issues referenced:\n", " - [SOLUTION] https://github.com/onnx/onnx/issues/745\n", " - https://github.com/onnx/onnx/issues/1516\n", " - https://github.com/onnx/onnx-caffe2/issues/19" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Protocol Buffer Required by ONNX\n", "\n", "I experienced the following issues related to protobuf along the way in this task:\n", "- I am using Ubuntu 16.04 LTS. It came with a default protobuf library, `protobuf.so.9`. This is causing some serious conflicts wth the one ONNX trying to install and link to. I have not tested this with Ubuntu 18.04 LTS yet.\n", "- [RESOLVED] Error: \"... SIGABRT ...\"\n", " - https://github.com/BVLC/caffe/issues/5711\n", "- [RESOLVED] Error: \"Segmentation Fault on ONNX\"\n", " - https://github.com/onnx/onnx/issues/875\n", "- [RESOLVED] Error: \"ValueError: The graph does not have an ir_version set properly.\"\n", " - https://github.com/onnx/onnx/issues/95#issuecomment-335515684" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## For Debugging Purposes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Conda environment on AWS p2.xlarge instance:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# conda environments:\r\n", "#\r\n", "base /home/ubuntu/anaconda3\r\n", "caffe2 * /home/ubuntu/anaconda3/envs/caffe2\r\n", "fastai /home/ubuntu/anaconda3/envs/fastai\r\n", "fastai-edge /home/ubuntu/anaconda3/envs/fastai-edge\r\n", "fastai-v1 /home/ubuntu/anaconda3/envs/fastai-v1\r\n", "mxnet /home/ubuntu/anaconda3/envs/mxnet\r\n", "tensorflow /home/ubuntu/anaconda3/envs/tensorflow\r\n", "\r\n" ] } ], "source": [ "!conda env list" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\r\n", " active environment : caffe2\r\n", " active env location : /home/ubuntu/anaconda3/envs/caffe2\r\n", " shell level : 1\r\n", " user config file : /home/ubuntu/.condarc\r\n", " populated config files : \r\n", " conda version : 4.5.11\r\n", " conda-build version : 3.0.27\r\n", " python version : 3.6.3.final.0\r\n", " base environment : /home/ubuntu/anaconda3 (writable)\r\n", " channel URLs : https://repo.anaconda.com/pkgs/main/linux-64\r\n", " https://repo.anaconda.com/pkgs/main/noarch\r\n", " https://repo.anaconda.com/pkgs/free/linux-64\r\n", " https://repo.anaconda.com/pkgs/free/noarch\r\n", " https://repo.anaconda.com/pkgs/r/linux-64\r\n", " https://repo.anaconda.com/pkgs/r/noarch\r\n", " https://repo.anaconda.com/pkgs/pro/linux-64\r\n", " https://repo.anaconda.com/pkgs/pro/noarch\r\n", " package cache : /home/ubuntu/anaconda3/pkgs\r\n", " /home/ubuntu/.conda/pkgs\r\n", " envs directories : /home/ubuntu/anaconda3/envs\r\n", " /home/ubuntu/.conda/envs\r\n", " platform : linux-64\r\n", " user-agent : conda/4.5.11 requests/2.18.4 CPython/3.6.3 Linux/4.4.0-59-generic ubuntu/16.04 glibc/2.23\r\n", " UID:GID : 1000:1000\r\n", " netrc file : None\r\n", " offline mode : False\r\n", "\r\n" ] } ], "source": [ "!conda info" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# packages in environment at /home/ubuntu/anaconda3/envs/caffe2:\r\n", "#\r\n", "# Name Version Build Channel\r\n", "asn1crypto 0.24.0 py36_0 \r\n", "backcall 0.1.0 py36_0 \r\n", "blas 1.0 mkl \r\n", "bleach 3.0.2 py36_0 \r\n", "ca-certificates 2018.03.07 0 \r\n", "certifi 2018.10.15 py36_0 \r\n", "cffi 1.11.5 py36he75722e_1 \r\n", "chardet 3.0.4 py36_1 \r\n", "cryptography 2.3.1 py36hc365091_0 \r\n", "cuda92 1.0 0 pytorch\r\n", "cycler 0.10.0 py36_0 \r\n", "cymem 2.0.2 py36hfd86e86_0 \r\n", "cytoolz 0.9.0.1 py36h14c3975_1 \r\n", "dataclasses 0.6 py_0 fastai\r\n", "dbus 1.13.2 h714fa37_1 \r\n", "decorator 4.3.0 py36_0 \r\n", "dill 0.2.8.2 py36_0 \r\n", "entrypoints 0.2.3 py36_2 \r\n", "expat 2.2.6 he6710b0_0 \r\n", "fastprogress 0.1.10 py_0 fastai\r\n", "fontconfig 2.13.0 h9420a91_0 \r\n", "freetype 2.9.1 h8a8886c_1 \r\n", "future 0.16.0 py36_0 \r\n", "glib 2.56.2 hd408876_0 \r\n", "gmp 6.1.2 h6c8ec71_1 \r\n", "gst-plugins-base 1.14.0 hbbd80ab_1 \r\n", "gstreamer 1.14.0 hb453b48_1 \r\n", "icu 58.2 h9c2bf20_1 \r\n", "idna 2.7 py36_0 \r\n", "intel-openmp 2019.0 118 \r\n", "ipykernel 5.1.0 py36h39e3cac_0 \r\n", "ipython 7.0.1 py36h39e3cac_0 \r\n", "ipython_genutils 0.2.0 py36_0 \r\n", "ipywidgets 7.4.2 py36_0 \r\n", "jedi 0.13.1 py36_0 \r\n", "jinja2 2.10 py36_0 \r\n", "jpeg 9b h024ee3a_2 \r\n", "jsonschema 2.6.0 py36_0 \r\n", "jupyter 1.0.0 py36_7 \r\n", "jupyter_client 5.2.3 py36_0 \r\n", "jupyter_console 6.0.0 py36_0 \r\n", "jupyter_core 4.4.0 py36_0 \r\n", "kiwisolver 1.0.1 py36hf484d3e_0 \r\n", "libedit 3.1.20170329 h6b74fdf_2 \r\n", "libffi 3.2.1 hd88cf55_4 \r\n", "libgcc-ng 8.2.0 hdf63c60_1 \r\n", "libgfortran 3.0.0 1 conda-forge\r\n", "libgfortran-ng 7.3.0 hdf63c60_0 \r\n", "libopenblas 0.3.3 h5a2b251_3 \r\n", "libpng 1.6.35 hbc83047_0 \r\n", "libprotobuf 3.6.0 hdbcaa40_0 \r\n", "libsodium 1.0.16 h1bed415_0 \r\n", "libstdcxx-ng 8.2.0 hdf63c60_1 \r\n", "libtiff 4.0.9 he85c1e1_2 \r\n", "libuuid 1.0.3 h1bed415_2 \r\n", "libxcb 1.13 h1bed415_1 \r\n", "libxml2 2.9.8 h26e45fe_1 \r\n", "markupsafe 1.0 py36h14c3975_1 \r\n", "mistune 0.8.4 py36h7b6447c_0 \r\n", "mkl 2019.0 118 \r\n", "mkl_fft 1.0.6 py36h7dd41cf_0 \r\n", "mkl_random 1.0.1 py36h4414c95_1 \r\n", "msgpack-python 0.5.6 py36h6bb024c_1 \r\n", "murmurhash 1.0.1 py36he6710b0_0 \r\n", "nbconvert 5.3.1 py36_0 \r\n", "nbformat 4.4.0 py36_0 \r\n", "ncurses 6.1 hf484d3e_0 \r\n", "ninja 1.8.2 py36h6bb024c_1 \r\n", "notebook 5.7.0 py36_0 \r\n", "numpy 1.15.3 py36h1d66e8a_0 \r\n", "numpy-base 1.15.3 py36h81de0dd_0 \r\n", "olefile 0.46 py36_0 \r\n", "onnx 1.3.0 \r\n", "openblas 0.3.3 ha44fe06_1 conda-forge\r\n", "openssl 1.0.2p h14c3975_0 \r\n", "pandoc 2.2.3.2 0 \r\n", "pandocfilters 1.4.2 py36_1 \r\n", "parso 0.3.1 py36_0 \r\n", "pcre 8.42 h439df22_0 \r\n", "pexpect 4.6.0 py36_0 \r\n", "pickleshare 0.7.5 py36_0 \r\n", "pillow 5.3.0 py36h34e0f95_0 \r\n", "pip 10.0.1 py36_0 \r\n", "plac 0.9.6 py36_0 \r\n", "preshed 2.0.1 py36he6710b0_0 \r\n", "prometheus_client 0.4.2 py36_0 \r\n", "prompt_toolkit 2.0.6 py36_0 \r\n", "protobuf 3.6.0 py36hf484d3e_0 \r\n", "ptyprocess 0.6.0 py36_0 \r\n", "pycparser 2.19 py36_0 \r\n", "pygments 2.2.0 py36_0 \r\n", "pyopenssl 18.0.0 py36_0 \r\n", "pyparsing 2.2.2 py36_0 \r\n", "pyqt 5.9.2 py36h05f1152_2 \r\n", "pysocks 1.6.8 py36_0 \r\n", "python 3.6.6 h6e4f718_2 \r\n", "python-dateutil 2.7.3 py36_0 \r\n", "pytorch-nightly 1.0.0.dev20181022 py3.6_cuda9.2.148_cudnn7.1.4_0 [cuda92] pytorch\r\n", "pytz 2018.5 py36_0 \r\n", "pyyaml 3.13 py36h14c3975_0 \r\n", "pyzmq 17.1.2 py36h14c3975_0 \r\n", "qt 5.9.6 h8703b6f_2 \r\n", "qtconsole 4.4.2 py36_0 \r\n", "readline 7.0 h7b6447c_5 \r\n", "regex 2018.08.29 py36h7b6447c_0 \r\n", "requests 2.19.1 py36_0 \r\n", "send2trash 1.5.0 py36_0 \r\n", "setuptools 40.4.3 py36_0 \r\n", "simplegeneric 0.8.1 py36_2 \r\n", "sip 4.19.8 py36hf484d3e_0 \r\n", "six 1.11.0 py36_1 \r\n", "sqlite 3.25.2 h7b6447c_0 \r\n", "terminado 0.8.1 py36_1 \r\n", "testpath 0.4.2 py36_0 \r\n", "tk 8.6.8 hbc83047_0 \r\n", "toolz 0.9.0 py36_0 \r\n", "torchvision-nightly 0.2.1 py_0 fastai\r\n", "tornado 5.1.1 py36h7b6447c_0 \r\n", "tqdm 4.26.0 py36h28b3542_0 \r\n", "traitlets 4.3.2 py36_0 \r\n", "typing 3.6.4 py36_0 \r\n", "typing-extensions 3.6.6 \r\n", "ujson 1.35 py36h14c3975_0 \r\n", "urllib3 1.23 py36_0 \r\n", "wcwidth 0.1.7 py36_0 \r\n", "webencodings 0.5.1 py36_1 \r\n", "wheel 0.32.2 py36_0 \r\n", "widgetsnbextension 3.4.2 py36_0 \r\n", "wrapt 1.10.11 py36h14c3975_2 \r\n", "xz 5.2.4 h14c3975_4 \r\n", "yaml 0.1.7 had09818_2 \r\n", "zeromq 4.2.5 hf484d3e_1 \r\n", "zlib 1.2.11 ha838bed_2 \r\n" ] } ], "source": [ "!conda list" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Fri Nov 2 01:50:07 2018 \r\n", "+-----------------------------------------------------------------------------+\r\n", "| NVIDIA-SMI 410.66 Driver Version: 410.66 CUDA Version: 10.0 |\r\n", "|-------------------------------+----------------------+----------------------+\r\n", "| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |\r\n", "| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |\r\n", "|===============================+======================+======================|\r\n", "| 0 Tesla K80 Off | 00000000:00:1E.0 Off | 0 |\r\n", "| N/A 35C P8 30W / 149W | 0MiB / 11441MiB | 0% Default |\r\n", "+-------------------------------+----------------------+----------------------+\r\n", " \r\n", "+-----------------------------------------------------------------------------+\r\n", "| Processes: GPU Memory |\r\n", "| GPU PID Type Process name Usage |\r\n", "|=============================================================================|\r\n", "| No running processes found |\r\n", "+-----------------------------------------------------------------------------+\r\n" ] } ], "source": [ "!nvidia-smi" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Verify if you've installed PyTorch properly:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.0.0.dev20181022\n" ] } ], "source": [ "# PyTorch 1.0 preview (nightly)\n", "\n", "import torch\n", "print(torch.__version__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Verify if you’ve installed GPU drivers properly:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n" ] } ], "source": [ "# You should see more than 0 in the output of this command.\n", "\n", "print(torch.cuda.device_count())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[Protocol Buffers](https://developers.google.com/protocol-buffers/) compiler version:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "libprotoc 3.6.0\r\n" ] } ], "source": [ "!protoc --version" ] } ], "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.6.6" } }, "nbformat": 4, "nbformat_minor": 2 }