dannyvas23 commited on
Commit
57a92c3
1 Parent(s): d016df6

Upload runs/Mar25_20-32-24_nkd5rwp4qf/1648240347.1094823/quick_start_pytorch.ipynb

Browse files
runs/Mar25_20-32-24_nkd5rwp4qf/1648240347.1094823/quick_start_pytorch.ipynb ADDED
@@ -0,0 +1,921 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {
6
+ "gradient": {
7
+ "editing": false,
8
+ "id": "a4090294-3349-4815-96f4-98010b657359",
9
+ "kernelId": ""
10
+ }
11
+ },
12
+ "source": [
13
+ "# Paperspace Gradient: PyTorch Quick Start\n",
14
+ "Last modified: Nov 18th 2021"
15
+ ]
16
+ },
17
+ {
18
+ "cell_type": "markdown",
19
+ "metadata": {
20
+ "gradient": {
21
+ "editing": false,
22
+ "id": "4936c59a-8535-43cf-a527-e9323b2b658e",
23
+ "kernelId": ""
24
+ }
25
+ },
26
+ "source": [
27
+ "## Purpose and intended audience\n",
28
+ "\n",
29
+ "This Quick Start tutorial demonstrates PyTorch usage in a Gradient Notebook. It is aimed at users who are relatviely new to PyTorch, although you will need to be familiar with Python to understand PyTorch code.\n",
30
+ "\n",
31
+ "We use PyTorch to\n",
32
+ "\n",
33
+ "- Build a neural network that classifies FashionMNIST images\n",
34
+ "- Train and evaluate the network\n",
35
+ "- Save the model\n",
36
+ "- Perform predictions\n",
37
+ "\n",
38
+ "followed by some next steps that you can take to proceed with using Gradient.\n",
39
+ "\n",
40
+ "The material is based on the original [PyTorch Quick Start](https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html).\n",
41
+ "\n",
42
+ "See the end of the notebook for the original copyright notice."
43
+ ]
44
+ },
45
+ {
46
+ "cell_type": "markdown",
47
+ "metadata": {
48
+ "gradient": {
49
+ "editing": false,
50
+ "id": "a55c3131-9437-483d-9c19-a165fbf8b6d4",
51
+ "kernelId": ""
52
+ }
53
+ },
54
+ "source": [
55
+ "## Check that you are on a GPU instance\n",
56
+ "\n",
57
+ "The notebook is designed to run on a Gradient GPU instance (as opposed to a CPU-only instance). The instance type, e.g., A4000, can be seen by clicking on the instance icon on the left-hand navigation bar in the Gradient Notebook interface. It will say if it is CPU or GPU.\n",
58
+ "\n",
59
+ "![instance_type.png](instance_type.png)\n",
60
+ "\n",
61
+ "The *Creating models* section below also determines whether or not a GPU is available for us to use.\n",
62
+ "\n",
63
+ "If the instance type is CPU, you can change it by clicking *Stop Instance*, then the instance type displayed to get a drop-down list. Select a GPU instance and start up the Notebook again.\n",
64
+ "\n",
65
+ "For help with instances, see the Gradient documentation on [instance types](https://docs.paperspace.com/gradient/more/instance-types) or [starting a Gradient Notebook](https://docs.paperspace.com/gradient/explore-train-deploy/notebooks)."
66
+ ]
67
+ },
68
+ {
69
+ "cell_type": "markdown",
70
+ "metadata": {
71
+ "gradient": {
72
+ "editing": false,
73
+ "id": "cd28b5e4-862f-4fc5-b02d-2335345647fa",
74
+ "kernelId": ""
75
+ }
76
+ },
77
+ "source": [
78
+ "## Add ipywidgets\n",
79
+ "This is temporary to enable PyTorch to work on Gradient notebooks."
80
+ ]
81
+ },
82
+ {
83
+ "cell_type": "code",
84
+ "execution_count": null,
85
+ "metadata": {
86
+ "collapsed": false,
87
+ "gradient": {
88
+ "editing": false,
89
+ "execution_count": 1,
90
+ "id": "86ef45c8-089d-4d76-b919-99bccbd7edbb",
91
+ "kernelId": "",
92
+ "source_hidden": false
93
+ },
94
+ "jupyter": {
95
+ "outputs_hidden": false
96
+ }
97
+ },
98
+ "outputs": [
99
+ {
100
+ "name": "stdout",
101
+ "output_type": "stream",
102
+ "text": [
103
+ "Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.com\n",
104
+ "Collecting ipywidgets\n",
105
+ " Downloading ipywidgets-7.6.5-py2.py3-none-any.whl (121 kB)\n",
106
+ "\u001b[K |████████████████████████████████| 121 kB 26.7 MB/s eta 0:00:01\n",
107
+ "\u001b[?25hRequirement already satisfied: ipykernel>=4.5.1 in /opt/conda/lib/python3.8/site-packages (from ipywidgets) (6.4.1)\n",
108
+ "Requirement already satisfied: nbformat>=4.2.0 in /opt/conda/lib/python3.8/site-packages (from ipywidgets) (5.1.3)\n",
109
+ "Collecting jupyterlab-widgets>=1.0.0\n",
110
+ " Downloading jupyterlab_widgets-1.0.2-py3-none-any.whl (243 kB)\n",
111
+ "\u001b[K |████████████████████████████████| 243 kB 26.2 MB/s eta 0:00:01\n",
112
+ "\u001b[?25hRequirement already satisfied: traitlets>=4.3.1 in /opt/conda/lib/python3.8/site-packages (from ipywidgets) (5.1.0)\n",
113
+ "Requirement already satisfied: ipython-genutils~=0.2.0 in /opt/conda/lib/python3.8/site-packages (from ipywidgets) (0.2.0)\n",
114
+ "Requirement already satisfied: ipython>=4.0.0 in /opt/conda/lib/python3.8/site-packages (from ipywidgets) (7.28.0)\n",
115
+ "Collecting widgetsnbextension~=3.5.0\n",
116
+ " Downloading widgetsnbextension-3.5.2-py2.py3-none-any.whl (1.6 MB)\n",
117
+ "\u001b[K |████████████████████████████████| 1.6 MB 27.8 MB/s eta 0:00:01\n",
118
+ "\u001b[?25hRequirement already satisfied: jupyter-client<8.0 in /opt/conda/lib/python3.8/site-packages (from ipykernel>=4.5.1->ipywidgets) (7.0.6)\n",
119
+ "Requirement already satisfied: debugpy<2.0,>=1.0.0 in /opt/conda/lib/python3.8/site-packages (from ipykernel>=4.5.1->ipywidgets) (1.5.0)\n",
120
+ "Requirement already satisfied: matplotlib-inline<0.2.0,>=0.1.0 in /opt/conda/lib/python3.8/site-packages (from ipykernel>=4.5.1->ipywidgets) (0.1.3)\n",
121
+ "Requirement already satisfied: tornado<7.0,>=4.2 in /opt/conda/lib/python3.8/site-packages (from ipykernel>=4.5.1->ipywidgets) (6.1)\n",
122
+ "Requirement already satisfied: setuptools>=18.5 in /opt/conda/lib/python3.8/site-packages (from ipython>=4.0.0->ipywidgets) (58.2.0)\n",
123
+ "Requirement already satisfied: pickleshare in /opt/conda/lib/python3.8/site-packages (from ipython>=4.0.0->ipywidgets) (0.7.5)\n",
124
+ "Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /opt/conda/lib/python3.8/site-packages (from ipython>=4.0.0->ipywidgets) (3.0.20)\n",
125
+ "Requirement already satisfied: decorator in /opt/conda/lib/python3.8/site-packages (from ipython>=4.0.0->ipywidgets) (5.1.0)\n",
126
+ "Requirement already satisfied: pexpect>4.3 in /opt/conda/lib/python3.8/site-packages (from ipython>=4.0.0->ipywidgets) (4.8.0)\n",
127
+ "Requirement already satisfied: pygments in /opt/conda/lib/python3.8/site-packages (from ipython>=4.0.0->ipywidgets) (2.10.0)\n",
128
+ "Requirement already satisfied: jedi>=0.16 in /opt/conda/lib/python3.8/site-packages (from ipython>=4.0.0->ipywidgets) (0.18.0)\n",
129
+ "Requirement already satisfied: backcall in /opt/conda/lib/python3.8/site-packages (from ipython>=4.0.0->ipywidgets) (0.2.0)\n",
130
+ "Requirement already satisfied: parso<0.9.0,>=0.8.0 in /opt/conda/lib/python3.8/site-packages (from jedi>=0.16->ipython>=4.0.0->ipywidgets) (0.8.2)\n",
131
+ "Requirement already satisfied: nest-asyncio>=1.5 in /opt/conda/lib/python3.8/site-packages (from jupyter-client<8.0->ipykernel>=4.5.1->ipywidgets) (1.5.1)\n",
132
+ "Requirement already satisfied: jupyter-core>=4.6.0 in /opt/conda/lib/python3.8/site-packages (from jupyter-client<8.0->ipykernel>=4.5.1->ipywidgets) (4.8.1)\n",
133
+ "Requirement already satisfied: entrypoints in /opt/conda/lib/python3.8/site-packages (from jupyter-client<8.0->ipykernel>=4.5.1->ipywidgets) (0.3)\n",
134
+ "Requirement already satisfied: pyzmq>=13 in /opt/conda/lib/python3.8/site-packages (from jupyter-client<8.0->ipykernel>=4.5.1->ipywidgets) (22.3.0)\n",
135
+ "Requirement already satisfied: python-dateutil>=2.1 in /opt/conda/lib/python3.8/site-packages (from jupyter-client<8.0->ipykernel>=4.5.1->ipywidgets) (2.8.2)\n",
136
+ "Requirement already satisfied: jsonschema!=2.5.0,>=2.4 in /opt/conda/lib/python3.8/site-packages (from nbformat>=4.2.0->ipywidgets) (4.0.1)\n",
137
+ "Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /opt/conda/lib/python3.8/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat>=4.2.0->ipywidgets) (0.18.0)\n",
138
+ "Requirement already satisfied: attrs>=17.4.0 in /opt/conda/lib/python3.8/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat>=4.2.0->ipywidgets) (21.2.0)\n",
139
+ "Requirement already satisfied: ptyprocess>=0.5 in /opt/conda/lib/python3.8/site-packages (from pexpect>4.3->ipython>=4.0.0->ipywidgets) (0.7.0)\n",
140
+ "Requirement already satisfied: wcwidth in /opt/conda/lib/python3.8/site-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython>=4.0.0->ipywidgets) (0.2.5)\n",
141
+ "Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.8/site-packages (from python-dateutil>=2.1->jupyter-client<8.0->ipykernel>=4.5.1->ipywidgets) (1.16.0)\n",
142
+ "Requirement already satisfied: notebook>=4.4.1 in /opt/conda/lib/python3.8/site-packages (from widgetsnbextension~=3.5.0->ipywidgets) (6.4.1)\n",
143
+ "Requirement already satisfied: argon2-cffi in /opt/conda/lib/python3.8/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (21.1.0)\n",
144
+ "Requirement already satisfied: nbconvert in /opt/conda/lib/python3.8/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (6.2.0)\n",
145
+ "Requirement already satisfied: terminado>=0.8.3 in /opt/conda/lib/python3.8/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (0.12.1)\n",
146
+ "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.8/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (3.0.1)\n",
147
+ "Requirement already satisfied: prometheus-client in /opt/conda/lib/python3.8/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (0.11.0)\n",
148
+ "Requirement already satisfied: Send2Trash>=1.5.0 in /opt/conda/lib/python3.8/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (1.8.0)\n",
149
+ "Requirement already satisfied: cffi>=1.0.0 in /opt/conda/lib/python3.8/site-packages (from argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (1.14.6)\n",
150
+ "Requirement already satisfied: pycparser in /opt/conda/lib/python3.8/site-packages (from cffi>=1.0.0->argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (2.20)\n",
151
+ "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.8/site-packages (from jinja2->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (2.0.1)\n",
152
+ "Requirement already satisfied: nbclient<0.6.0,>=0.5.0 in /opt/conda/lib/python3.8/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (0.5.4)\n",
153
+ "Requirement already satisfied: bleach in /opt/conda/lib/python3.8/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (4.1.0)\n",
154
+ "Requirement already satisfied: pandocfilters>=1.4.1 in /opt/conda/lib/python3.8/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (1.5.0)\n",
155
+ "Requirement already satisfied: testpath in /opt/conda/lib/python3.8/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (0.5.0)\n",
156
+ "Requirement already satisfied: mistune<2,>=0.8.1 in /opt/conda/lib/python3.8/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (0.8.4)\n",
157
+ "Requirement already satisfied: defusedxml in /opt/conda/lib/python3.8/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (0.7.1)\n",
158
+ "Requirement already satisfied: jupyterlab-pygments in /opt/conda/lib/python3.8/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (0.1.2)\n",
159
+ "Requirement already satisfied: webencodings in /opt/conda/lib/python3.8/site-packages (from bleach->nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (0.5.1)\n",
160
+ "Requirement already satisfied: packaging in /opt/conda/lib/python3.8/site-packages (from bleach->nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (21.0)\n",
161
+ "Requirement already satisfied: pyparsing>=2.0.2 in /opt/conda/lib/python3.8/site-packages (from packaging->bleach->nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets) (2.4.7)\n",
162
+ "Installing collected packages: widgetsnbextension, jupyterlab-widgets, ipywidgets\n",
163
+ "Successfully installed ipywidgets-7.6.5 jupyterlab-widgets-1.0.2 widgetsnbextension-3.5.2\n",
164
+ "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\n"
165
+ ]
166
+ }
167
+ ],
168
+ "source": [
169
+ "!pip install ipywidgets"
170
+ ]
171
+ },
172
+ {
173
+ "cell_type": "markdown",
174
+ "metadata": {
175
+ "gradient": {
176
+ "editing": false,
177
+ "id": "28402a66-a8c4-4672-9592-cc530b58d439",
178
+ "kernelId": ""
179
+ }
180
+ },
181
+ "source": [
182
+ "## Working with data\n",
183
+ "\n",
184
+ "PyTorch has two [primitives to work with data](https://pytorch.org/docs/stable/data.html):\n",
185
+ "``torch.utils.data.DataLoader`` and ``torch.utils.data.Dataset``.\n",
186
+ "``Dataset`` stores the samples and their corresponding labels, and ``DataLoader`` wraps an iterable around\n",
187
+ "the ``Dataset``."
188
+ ]
189
+ },
190
+ {
191
+ "cell_type": "code",
192
+ "execution_count": null,
193
+ "metadata": {
194
+ "collapsed": false,
195
+ "gradient": {
196
+ "editing": false,
197
+ "execution_count": 2,
198
+ "id": "2bab3caa-e156-4635-bc21-53031ebea60d",
199
+ "kernelId": ""
200
+ },
201
+ "jupyter": {
202
+ "outputs_hidden": false
203
+ }
204
+ },
205
+ "outputs": [],
206
+ "source": [
207
+ "import torch\n",
208
+ "from torch import nn\n",
209
+ "from torch.utils.data import DataLoader\n",
210
+ "from torchvision import datasets\n",
211
+ "from torchvision.transforms import ToTensor, Lambda, Compose"
212
+ ]
213
+ },
214
+ {
215
+ "cell_type": "markdown",
216
+ "metadata": {
217
+ "gradient": {
218
+ "editing": false,
219
+ "id": "0dfb0116-56cd-4795-bc5e-79baad627726",
220
+ "kernelId": ""
221
+ }
222
+ },
223
+ "source": [
224
+ "PyTorch offers domain-specific libraries such as [TorchText](https://pytorch.org/text/stable/index.html),\n",
225
+ "[TorchVision](https://pytorch.org/vision/stable/index.html), and [TorchAudio](https://pytorch.org/audio/stable/index.html),\n",
226
+ "all of which include datasets. For this tutorial, we will be using a TorchVision dataset.\n",
227
+ "\n",
228
+ "The ``torchvision.datasets`` module contains ``Dataset`` objects for many real-world vision data like\n",
229
+ "CIFAR, COCO ([full list here](https://pytorch.org/vision/stable/datasets.html)). In this tutorial, we\n",
230
+ "use the FashionMNIST dataset. Every TorchVision ``Dataset`` includes two arguments: ``transform`` and\n",
231
+ "``target_transform`` to modify the samples and labels respectively."
232
+ ]
233
+ },
234
+ {
235
+ "cell_type": "code",
236
+ "execution_count": null,
237
+ "metadata": {
238
+ "collapsed": false,
239
+ "gradient": {
240
+ "editing": false,
241
+ "execution_count": 3,
242
+ "id": "631deddf-30f0-45f1-84ab-e5f4c510c500",
243
+ "kernelId": ""
244
+ },
245
+ "jupyter": {
246
+ "outputs_hidden": false
247
+ }
248
+ },
249
+ "outputs": [],
250
+ "source": [
251
+ "# Download training data from open datasets\n",
252
+ "training_data = datasets.FashionMNIST(\n",
253
+ " root=\"data\",\n",
254
+ " train=True,\n",
255
+ " download=True,\n",
256
+ " transform=ToTensor(),\n",
257
+ ")\n",
258
+ "\n",
259
+ "# Download test data from open datasets\n",
260
+ "test_data = datasets.FashionMNIST(\n",
261
+ " root=\"data\",\n",
262
+ " train=False,\n",
263
+ " download=True,\n",
264
+ " transform=ToTensor(),\n",
265
+ ")"
266
+ ]
267
+ },
268
+ {
269
+ "cell_type": "markdown",
270
+ "metadata": {
271
+ "gradient": {
272
+ "editing": false,
273
+ "id": "0ace6ebf-b493-4b75-9bfa-dc48bc676b21",
274
+ "kernelId": ""
275
+ }
276
+ },
277
+ "source": [
278
+ "We pass the ``Dataset`` as an argument to ``DataLoader``. This wraps an iterable over our dataset, and supports\n",
279
+ "automatic batching, sampling, shuffling and multiprocess data loading. Here we define a batch size of 64, i.e., each element\n",
280
+ "in the dataloader iterable will return a batch of 64 features and labels."
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": null,
286
+ "metadata": {
287
+ "collapsed": false,
288
+ "gradient": {
289
+ "editing": false,
290
+ "execution_count": 4,
291
+ "id": "8e65f970-dce8-460c-b5f2-9cbee0c14900",
292
+ "kernelId": ""
293
+ },
294
+ "jupyter": {
295
+ "outputs_hidden": false
296
+ }
297
+ },
298
+ "outputs": [
299
+ {
300
+ "name": "stdout",
301
+ "output_type": "stream",
302
+ "text": [
303
+ "Shape of X [N, C, H, W]: torch.Size([64, 1, 28, 28])\n",
304
+ "Shape of y: torch.Size([64]) torch.int64\n"
305
+ ]
306
+ }
307
+ ],
308
+ "source": [
309
+ "batch_size = 64\n",
310
+ "\n",
311
+ "# Create data loaders\n",
312
+ "train_dataloader = DataLoader(training_data, batch_size=batch_size)\n",
313
+ "test_dataloader = DataLoader(test_data, batch_size=batch_size)\n",
314
+ "\n",
315
+ "for X, y in test_dataloader:\n",
316
+ " print(\"Shape of X [N, C, H, W]: \", X.shape)\n",
317
+ " print(\"Shape of y: \", y.shape, y.dtype)\n",
318
+ " break"
319
+ ]
320
+ },
321
+ {
322
+ "cell_type": "markdown",
323
+ "metadata": {
324
+ "gradient": {
325
+ "editing": false,
326
+ "id": "f9d1b1f7-0850-4676-93b6-902f78be237d",
327
+ "kernelId": ""
328
+ }
329
+ },
330
+ "source": [
331
+ "Read more about [loading data in PyTorch](https://pytorch.org/tutorials/beginner/basics/data_tutorial.html)."
332
+ ]
333
+ },
334
+ {
335
+ "cell_type": "markdown",
336
+ "metadata": {
337
+ "gradient": {
338
+ "editing": false,
339
+ "id": "d9cc95fe-194b-4a6f-b01d-91510dfcfb00",
340
+ "kernelId": ""
341
+ }
342
+ },
343
+ "source": [
344
+ "## Creating models, including GPU\n",
345
+ "\n",
346
+ "To define a neural network in PyTorch, we create a class that inherits\n",
347
+ "from [nn.Module](https://pytorch.org/docs/stable/generated/torch.nn.Module.html). We define the layers of the network\n",
348
+ "in the ``__init__`` function and specify how data will pass through the network in the ``forward`` function. To accelerate\n",
349
+ "operations in the neural network, we move it to the GPU if available."
350
+ ]
351
+ },
352
+ {
353
+ "cell_type": "code",
354
+ "execution_count": null,
355
+ "metadata": {
356
+ "collapsed": false,
357
+ "gradient": {
358
+ "editing": false,
359
+ "execution_count": 5,
360
+ "id": "d58d5484-8ca0-4400-91c5-d0e71cf89c12",
361
+ "kernelId": ""
362
+ },
363
+ "jupyter": {
364
+ "outputs_hidden": false
365
+ }
366
+ },
367
+ "outputs": [
368
+ {
369
+ "name": "stdout",
370
+ "output_type": "stream",
371
+ "text": [
372
+ "Using cuda device\n",
373
+ "NeuralNetwork(\n",
374
+ " (flatten): Flatten(start_dim=1, end_dim=-1)\n",
375
+ " (linear_relu_stack): Sequential(\n",
376
+ " (0): Linear(in_features=784, out_features=512, bias=True)\n",
377
+ " (1): ReLU()\n",
378
+ " (2): Linear(in_features=512, out_features=512, bias=True)\n",
379
+ " (3): ReLU()\n",
380
+ " (4): Linear(in_features=512, out_features=10, bias=True)\n",
381
+ " )\n",
382
+ ")\n"
383
+ ]
384
+ }
385
+ ],
386
+ "source": [
387
+ "# Get cpu or gpu device for training\n",
388
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
389
+ "print(\"Using {} device\".format(device))\n",
390
+ "\n",
391
+ "# Define model\n",
392
+ "class NeuralNetwork(nn.Module):\n",
393
+ " def __init__(self):\n",
394
+ " super(NeuralNetwork, self).__init__()\n",
395
+ " self.flatten = nn.Flatten()\n",
396
+ " self.linear_relu_stack = nn.Sequential(\n",
397
+ " nn.Linear(28*28, 512),\n",
398
+ " nn.ReLU(),\n",
399
+ " nn.Linear(512, 512),\n",
400
+ " nn.ReLU(),\n",
401
+ " nn.Linear(512, 10)\n",
402
+ " )\n",
403
+ "\n",
404
+ " def forward(self, x):\n",
405
+ " x = self.flatten(x)\n",
406
+ " logits = self.linear_relu_stack(x)\n",
407
+ " return logits\n",
408
+ "\n",
409
+ "model = NeuralNetwork().to(device)\n",
410
+ "print(model)"
411
+ ]
412
+ },
413
+ {
414
+ "cell_type": "markdown",
415
+ "metadata": {
416
+ "gradient": {
417
+ "editing": false,
418
+ "id": "7ee591d8-e529-481b-8107-e84454893bd2",
419
+ "kernelId": ""
420
+ }
421
+ },
422
+ "source": [
423
+ "Read more about [building neural networks in PyTorch](https://pytorch.org/tutorials/beginner/basics/buildmodel_tutorial.html)."
424
+ ]
425
+ },
426
+ {
427
+ "cell_type": "markdown",
428
+ "metadata": {
429
+ "gradient": {
430
+ "editing": false,
431
+ "id": "b6db5b4f-80b9-4f9e-8feb-76d0ef1e346f",
432
+ "kernelId": ""
433
+ }
434
+ },
435
+ "source": [
436
+ "## Optimizing the model parameters\n",
437
+ "\n",
438
+ "To train a model, we need a [loss function](https://pytorch.org/docs/stable/nn.html#loss-functions)\n",
439
+ "and an [optimizer](https://pytorch.org/docs/stable/optim.html)."
440
+ ]
441
+ },
442
+ {
443
+ "cell_type": "code",
444
+ "execution_count": null,
445
+ "metadata": {
446
+ "collapsed": false,
447
+ "gradient": {
448
+ "editing": false,
449
+ "execution_count": 6,
450
+ "id": "8c22a532-16e0-440d-888e-d879e5f53c7c",
451
+ "kernelId": ""
452
+ },
453
+ "jupyter": {
454
+ "outputs_hidden": false
455
+ }
456
+ },
457
+ "outputs": [],
458
+ "source": [
459
+ "loss_fn = nn.CrossEntropyLoss()\n",
460
+ "optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)"
461
+ ]
462
+ },
463
+ {
464
+ "cell_type": "markdown",
465
+ "metadata": {
466
+ "gradient": {
467
+ "editing": false,
468
+ "id": "5efe3473-ecf7-411c-a13b-ba54f5c257a6",
469
+ "kernelId": ""
470
+ }
471
+ },
472
+ "source": [
473
+ "In a single training loop, the model makes predictions on the training dataset (fed to it in batches), and\n",
474
+ "backpropagates the prediction error to adjust the model's parameters."
475
+ ]
476
+ },
477
+ {
478
+ "cell_type": "code",
479
+ "execution_count": null,
480
+ "metadata": {
481
+ "collapsed": false,
482
+ "gradient": {
483
+ "editing": false,
484
+ "execution_count": 7,
485
+ "id": "3d1af6c1-299b-4572-902a-c5e52ce0a7d2",
486
+ "kernelId": ""
487
+ },
488
+ "jupyter": {
489
+ "outputs_hidden": false
490
+ }
491
+ },
492
+ "outputs": [],
493
+ "source": [
494
+ "def train(dataloader, model, loss_fn, optimizer):\n",
495
+ " size = len(dataloader.dataset)\n",
496
+ " model.train()\n",
497
+ " for batch, (X, y) in enumerate(dataloader):\n",
498
+ " X, y = X.to(device), y.to(device)\n",
499
+ "\n",
500
+ " # Compute prediction error\n",
501
+ " pred = model(X)\n",
502
+ " loss = loss_fn(pred, y)\n",
503
+ "\n",
504
+ " # Backpropagation\n",
505
+ " optimizer.zero_grad()\n",
506
+ " loss.backward()\n",
507
+ " optimizer.step()\n",
508
+ "\n",
509
+ " if batch % 100 == 0:\n",
510
+ " loss, current = loss.item(), batch * len(X)\n",
511
+ " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")"
512
+ ]
513
+ },
514
+ {
515
+ "cell_type": "markdown",
516
+ "metadata": {
517
+ "gradient": {
518
+ "editing": false,
519
+ "id": "f86e28f0-bb94-4443-a673-f6d3461d4e94",
520
+ "kernelId": ""
521
+ }
522
+ },
523
+ "source": [
524
+ "We also check the model's performance against the test dataset to ensure it is learning."
525
+ ]
526
+ },
527
+ {
528
+ "cell_type": "code",
529
+ "execution_count": null,
530
+ "metadata": {
531
+ "collapsed": false,
532
+ "gradient": {
533
+ "editing": false,
534
+ "execution_count": 8,
535
+ "id": "112d81e3-cdf8-4b1e-afca-6344be54f5e5",
536
+ "kernelId": ""
537
+ },
538
+ "jupyter": {
539
+ "outputs_hidden": false
540
+ }
541
+ },
542
+ "outputs": [],
543
+ "source": [
544
+ "def test(dataloader, model, loss_fn):\n",
545
+ " size = len(dataloader.dataset)\n",
546
+ " num_batches = len(dataloader)\n",
547
+ " model.eval()\n",
548
+ " test_loss, correct = 0, 0\n",
549
+ " with torch.no_grad():\n",
550
+ " for X, y in dataloader:\n",
551
+ " X, y = X.to(device), y.to(device)\n",
552
+ " pred = model(X)\n",
553
+ " test_loss += loss_fn(pred, y).item()\n",
554
+ " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n",
555
+ " test_loss /= num_batches\n",
556
+ " correct /= size\n",
557
+ " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")"
558
+ ]
559
+ },
560
+ {
561
+ "cell_type": "markdown",
562
+ "metadata": {
563
+ "gradient": {
564
+ "editing": false,
565
+ "id": "4e366ecc-735f-42dd-b04e-a94816b94fd8",
566
+ "kernelId": ""
567
+ }
568
+ },
569
+ "source": [
570
+ "The training process is conducted over several iterations (*epochs*). During each epoch, the model learns\n",
571
+ "parameters to make better predictions. We print the model's accuracy and loss at each epoch; we'd like to see the\n",
572
+ "accuracy increase and the loss decrease with every epoch."
573
+ ]
574
+ },
575
+ {
576
+ "cell_type": "code",
577
+ "execution_count": null,
578
+ "metadata": {
579
+ "collapsed": false,
580
+ "gradient": {
581
+ "editing": false,
582
+ "execution_count": 9,
583
+ "id": "50bf09d9-1318-43ef-92aa-6ee308fcafa1",
584
+ "kernelId": ""
585
+ },
586
+ "jupyter": {
587
+ "outputs_hidden": false
588
+ }
589
+ },
590
+ "outputs": [
591
+ {
592
+ "name": "stdout",
593
+ "output_type": "stream",
594
+ "text": [
595
+ "Epoch 1\n",
596
+ "-------------------------------\n",
597
+ "loss: 2.303235 [ 0/60000]\n",
598
+ "loss: 2.289679 [ 6400/60000]\n",
599
+ "loss: 2.273108 [12800/60000]\n",
600
+ "loss: 2.267172 [19200/60000]\n",
601
+ "loss: 2.248831 [25600/60000]\n",
602
+ "loss: 2.225987 [32000/60000]\n",
603
+ "loss: 2.227034 [38400/60000]\n",
604
+ "loss: 2.194261 [44800/60000]\n",
605
+ "loss: 2.190697 [51200/60000]\n",
606
+ "loss: 2.161292 [57600/60000]\n",
607
+ "Test Error: \n",
608
+ " Accuracy: 53.8%, Avg loss: 2.155593 \n",
609
+ "\n",
610
+ "Epoch 2\n",
611
+ "-------------------------------\n",
612
+ "loss: 2.169532 [ 0/60000]\n",
613
+ "loss: 2.153734 [ 6400/60000]\n",
614
+ "loss: 2.097200 [12800/60000]\n",
615
+ "loss: 2.113983 [19200/60000]\n",
616
+ "loss: 2.057467 [25600/60000]\n",
617
+ "loss: 2.015557 [32000/60000]\n",
618
+ "loss: 2.031434 [38400/60000]\n",
619
+ "loss: 1.952968 [44800/60000]\n",
620
+ "loss: 1.957087 [51200/60000]\n",
621
+ "loss: 1.897905 [57600/60000]\n",
622
+ "Test Error: \n",
623
+ " Accuracy: 60.1%, Avg loss: 1.885614 \n",
624
+ "\n",
625
+ "Epoch 3\n",
626
+ "-------------------------------\n",
627
+ "loss: 1.924514 [ 0/60000]\n",
628
+ "loss: 1.886686 [ 6400/60000]\n",
629
+ "loss: 1.767823 [12800/60000]\n",
630
+ "loss: 1.810671 [19200/60000]\n",
631
+ "loss: 1.700105 [25600/60000]\n",
632
+ "loss: 1.668604 [32000/60000]\n",
633
+ "loss: 1.677238 [38400/60000]\n",
634
+ "loss: 1.577084 [44800/60000]\n",
635
+ "loss: 1.603734 [51200/60000]\n",
636
+ "loss: 1.514089 [57600/60000]\n",
637
+ "Test Error: \n",
638
+ " Accuracy: 60.3%, Avg loss: 1.522196 \n",
639
+ "\n",
640
+ "Epoch 4\n",
641
+ "-------------------------------\n",
642
+ "loss: 1.592778 [ 0/60000]\n",
643
+ "loss: 1.553160 [ 6400/60000]\n",
644
+ "loss: 1.404765 [12800/60000]\n",
645
+ "loss: 1.476303 [19200/60000]\n",
646
+ "loss: 1.357471 [25600/60000]\n",
647
+ "loss: 1.362992 [32000/60000]\n",
648
+ "loss: 1.364555 [38400/60000]\n",
649
+ "loss: 1.289281 [44800/60000]\n",
650
+ "loss: 1.328217 [51200/60000]\n",
651
+ "loss: 1.238191 [57600/60000]\n",
652
+ "Test Error: \n",
653
+ " Accuracy: 62.5%, Avg loss: 1.260456 \n",
654
+ "\n",
655
+ "Epoch 5\n",
656
+ "-------------------------------\n",
657
+ "loss: 1.338341 [ 0/60000]\n",
658
+ "loss: 1.316752 [ 6400/60000]\n",
659
+ "loss: 1.157560 [12800/60000]\n",
660
+ "loss: 1.258749 [19200/60000]\n",
661
+ "loss: 1.131236 [25600/60000]\n",
662
+ "loss: 1.164936 [32000/60000]\n",
663
+ "loss: 1.173478 [38400/60000]\n",
664
+ "loss: 1.111497 [44800/60000]\n",
665
+ "loss: 1.156012 [51200/60000]\n",
666
+ "loss: 1.079641 [57600/60000]\n",
667
+ "Test Error: \n",
668
+ " Accuracy: 64.0%, Avg loss: 1.098095 \n",
669
+ "\n",
670
+ "Done!\n"
671
+ ]
672
+ }
673
+ ],
674
+ "source": [
675
+ "epochs = 5\n",
676
+ "for t in range(epochs):\n",
677
+ " print(f\"Epoch {t+1}\\n-------------------------------\")\n",
678
+ " train(train_dataloader, model, loss_fn, optimizer)\n",
679
+ " test(test_dataloader, model, loss_fn)\n",
680
+ "print(\"Done!\")"
681
+ ]
682
+ },
683
+ {
684
+ "cell_type": "markdown",
685
+ "metadata": {
686
+ "gradient": {
687
+ "editing": false,
688
+ "id": "7bfc0721-ce35-4380-9d90-0f3f17bae210",
689
+ "kernelId": ""
690
+ }
691
+ },
692
+ "source": [
693
+ "Read more about [Training your model](optimization_tutorial.html)."
694
+ ]
695
+ },
696
+ {
697
+ "cell_type": "markdown",
698
+ "metadata": {
699
+ "gradient": {
700
+ "editing": false,
701
+ "id": "88e2d48b-f1c2-43b0-956d-673d31e777cc",
702
+ "kernelId": ""
703
+ }
704
+ },
705
+ "source": [
706
+ "## Saving models\n",
707
+ "\n",
708
+ "A common way to save a model is to serialize the internal state dictionary (containing the model parameters)."
709
+ ]
710
+ },
711
+ {
712
+ "cell_type": "code",
713
+ "execution_count": null,
714
+ "metadata": {
715
+ "collapsed": false,
716
+ "gradient": {
717
+ "editing": false,
718
+ "execution_count": 10,
719
+ "id": "5674fda2-6f1d-447c-ac05-d21934c7fe6f",
720
+ "kernelId": ""
721
+ },
722
+ "jupyter": {
723
+ "outputs_hidden": false
724
+ }
725
+ },
726
+ "outputs": [
727
+ {
728
+ "name": "stdout",
729
+ "output_type": "stream",
730
+ "text": [
731
+ "Saved PyTorch Model State to model.pth\n"
732
+ ]
733
+ }
734
+ ],
735
+ "source": [
736
+ "torch.save(model.state_dict(), \"model.pth\")\n",
737
+ "print(\"Saved PyTorch Model State to model.pth\")"
738
+ ]
739
+ },
740
+ {
741
+ "cell_type": "markdown",
742
+ "metadata": {
743
+ "gradient": {
744
+ "editing": false,
745
+ "id": "b1e15431-85cf-4788-aa7f-5c12d77f4ac3",
746
+ "kernelId": ""
747
+ }
748
+ },
749
+ "source": [
750
+ "## Loading models\n",
751
+ "\n",
752
+ "The process for loading a model includes re-creating the model structure and loading\n",
753
+ "the state dictionary into it."
754
+ ]
755
+ },
756
+ {
757
+ "cell_type": "code",
758
+ "execution_count": null,
759
+ "metadata": {
760
+ "collapsed": false,
761
+ "gradient": {
762
+ "editing": false,
763
+ "execution_count": 11,
764
+ "id": "ee2271cf-5092-43ad-afed-b64d2e6aea2c",
765
+ "kernelId": ""
766
+ },
767
+ "jupyter": {
768
+ "outputs_hidden": false
769
+ }
770
+ },
771
+ "outputs": [
772
+ {
773
+ "data": {
774
+ "text/plain": [
775
+ "<All keys matched successfully>"
776
+ ]
777
+ },
778
+ "execution_count": 11,
779
+ "metadata": {},
780
+ "output_type": "execute_result"
781
+ }
782
+ ],
783
+ "source": [
784
+ "model = NeuralNetwork()\n",
785
+ "model.load_state_dict(torch.load(\"model.pth\"))"
786
+ ]
787
+ },
788
+ {
789
+ "cell_type": "markdown",
790
+ "metadata": {
791
+ "gradient": {
792
+ "editing": false,
793
+ "id": "83cc12b8-fca2-4ea0-91f6-cdd8065d6164",
794
+ "kernelId": ""
795
+ }
796
+ },
797
+ "source": [
798
+ "This model can now be used to make predictions.\n",
799
+ "\n"
800
+ ]
801
+ },
802
+ {
803
+ "cell_type": "code",
804
+ "execution_count": null,
805
+ "metadata": {
806
+ "collapsed": false,
807
+ "gradient": {
808
+ "editing": true,
809
+ "execution_count": 12,
810
+ "id": "efed4977-824f-4816-91c0-05f4e10d8b54",
811
+ "kernelId": ""
812
+ },
813
+ "jupyter": {
814
+ "outputs_hidden": false
815
+ }
816
+ },
817
+ "outputs": [
818
+ {
819
+ "name": "stdout",
820
+ "output_type": "stream",
821
+ "text": [
822
+ "Predicted: \"Ankle boot\", Actual: \"Ankle boot\"\n"
823
+ ]
824
+ }
825
+ ],
826
+ "source": [
827
+ "classes = [\n",
828
+ " \"T-shirt/top\",\n",
829
+ " \"Trouser\",\n",
830
+ " \"Pullover\",\n",
831
+ " \"Dress\",\n",
832
+ " \"Coat\",\n",
833
+ " \"Sandal\",\n",
834
+ " \"Shirt\",\n",
835
+ " \"Sneaker\",\n",
836
+ " \"Bag\",\n",
837
+ " \"Ankle boot\",\n",
838
+ "]\n",
839
+ "\n",
840
+ "model.eval()\n",
841
+ "x, y = test_data[0][0], test_data[0][1]\n",
842
+ "with torch.no_grad():\n",
843
+ " pred = model(x)\n",
844
+ " predicted, actual = classes[pred[0].argmax(0)], classes[y]\n",
845
+ " print(f'Predicted: \"{predicted}\", Actual: \"{actual}\"')"
846
+ ]
847
+ },
848
+ {
849
+ "cell_type": "markdown",
850
+ "metadata": {
851
+ "gradient": {
852
+ "editing": false,
853
+ "id": "0b064ce8-bacb-45c2-8ef3-3a45ff7ecd5a",
854
+ "kernelId": ""
855
+ }
856
+ },
857
+ "source": [
858
+ "Read more about [Saving & Loading your model](saveloadrun_tutorial.html)."
859
+ ]
860
+ },
861
+ {
862
+ "cell_type": "markdown",
863
+ "metadata": {
864
+ "gradient": {
865
+ "editing": false,
866
+ "id": "379b3389-034a-4c17-a742-dd7c6a8281ce",
867
+ "kernelId": ""
868
+ }
869
+ },
870
+ "source": [
871
+ "## Next steps\n",
872
+ "\n",
873
+ "To proceed with PyTorch in Gradient, you can:\n",
874
+ " \n",
875
+ " - Look at other Gradient material, such as the [tutorials](https://docs.paperspace.com/gradient/get-started/tutorials-list), [ML Showcase](https://ml-showcase.paperspace.com), [blog](https://blog.paperspace.com), or [community](https://community.paperspace.com)\n",
876
+ " - Try out further [PyTorch tutorials](https://pytorch.org/tutorials/beginner/basics/intro.html)\n",
877
+ " - Start writing your own projects, using our [documentation](https://docs.paperspace.com/gradient) when needed\n",
878
+ " \n",
879
+ "If you get stuck or need help, [contact support](https://support.paperspace.com), and we will be happy to assist.\n",
880
+ "\n",
881
+ "Good luck!"
882
+ ]
883
+ },
884
+ {
885
+ "cell_type": "markdown",
886
+ "metadata": {
887
+ "gradient": {
888
+ "editing": false,
889
+ "id": "a4d2e55f-6c65-48fe-a9e7-165931791ff2",
890
+ "kernelId": ""
891
+ }
892
+ },
893
+ "source": [
894
+ "## Original PyTorch copyright notice\n",
895
+ "\n",
896
+ "© Copyright 2021, PyTorch."
897
+ ]
898
+ }
899
+ ],
900
+ "metadata": {
901
+ "kernelspec": {
902
+ "display_name": "Python 3 (ipykernel)",
903
+ "language": "python",
904
+ "name": "python3"
905
+ },
906
+ "language_info": {
907
+ "codemirror_mode": {
908
+ "name": "ipython",
909
+ "version": 3
910
+ },
911
+ "file_extension": ".py",
912
+ "mimetype": "text/x-python",
913
+ "name": "python",
914
+ "nbconvert_exporter": "python",
915
+ "pygments_lexer": "ipython3",
916
+ "version": "3.8.12"
917
+ }
918
+ },
919
+ "nbformat": 4,
920
+ "nbformat_minor": 4
921
+ }