blob: 5c032b1494083408a0f230a9dcbe0cb1efcfe7fd [file] [log] [blame]
{
"cells": [
{
"cell_type": "markdown",
"id": "2d0f6ceb",
"metadata": {},
"source": [
"<!--- Licensed to the Apache Software Foundation (ASF) under one -->\n",
"<!--- or more contributor license agreements. See the NOTICE file -->\n",
"<!--- distributed with this work for additional information -->\n",
"<!--- regarding copyright ownership. The ASF licenses this file -->\n",
"<!--- to you under the Apache License, Version 2.0 (the -->\n",
"<!--- \"License\"); you may not use this file except in compliance -->\n",
"<!--- with the License. You may obtain a copy of the License at -->\n",
"\n",
"<!--- http://www.apache.org/licenses/LICENSE-2.0 -->\n",
"\n",
"<!--- Unless required by applicable law or agreed to in writing, -->\n",
"<!--- software distributed under the License is distributed on an -->\n",
"<!--- \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->\n",
"<!--- KIND, either express or implied. See the License for the -->\n",
"<!--- specific language governing permissions and limitations -->\n",
"<!--- under the License. -->\n",
"\n",
"# Saving and Loading Gluon Models\n",
"\n",
"Training large models take a lot of time and it is a good idea to save the trained models to files to avoid training them again and again. There are a number of reasons to do this. For example, you might want to do inference on a machine that is different from the one where the model was trained. Sometimes model's performance on validation set decreases towards the end of the training because of overfitting. If you saved your model parameters after every epoch, at the end you can decide to use the model that performs best on the validation set. Another reason would be to train your model using one language (like Python that has a lot of tools for training) and run inference using a different language (like Scala probably because your application is built on Scala).\n",
"\n",
"In this tutorial, we will learn ways to save and load Gluon models. There are two ways to save/load Gluon models:\n",
"\n",
"**1. Save/load model parameters only**\n",
"\n",
"Parameters of any Gluon model can be saved using the `save_parameters` and `load_parameters` method. This does not save model architecture. This method is used to save parameters of dynamic (non-hybrid) models. Model architecture cannot be saved for dynamic models because model architecture changes during execution.\n",
"\n",
"**2. Save/load model parameters AND architecture**\n",
"\n",
"The Model architecture of `Hybrid` models stays static and don't change during execution. Therefore both model parameters AND architecture can be saved and loaded using `export`, `imports` methods.\n",
"\n",
"Let's look at the above methods in more detail. Let's start by importing the modules we'll need."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "809a0ae4",
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"\n",
"import mxnet as mx\n",
"from mxnet import np, npx, autograd, gluon\n",
"from mxnet.gluon.data.vision import transforms\n",
"\n",
"import numpy as onp"
]
},
{
"cell_type": "markdown",
"id": "1d0e7c62",
"metadata": {},
"source": [
"## Setup: build and train a simple model\n",
"\n",
"We need a trained model before we can save it to a file. So let's go ahead and build a very simple convolutional network and train it on MNIST data.\n",
"\n",
"Let's define a helper function to build a LeNet model and another helper to train LeNet with MNIST."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "26c0db2e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Downloading /home/jenkins_slave/.mxnet/datasets/mnist/train-images-idx3-ubyte.gz from https://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/gluon/dataset/mnist/train-images-idx3-ubyte.gz...\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Downloading /home/jenkins_slave/.mxnet/datasets/mnist/train-labels-idx1-ubyte.gz from https://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/gluon/dataset/mnist/train-labels-idx1-ubyte.gz...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[04:46:12] /work/mxnet/src/storage/storage.cc:202: Using Pooled (Naive) StorageManager for CPU\n"
]
}
],
"source": [
"# Use GPU if one exists, else use CPU\n",
"device = mx.gpu() if mx.device.num_gpus() else mx.cpu()\n",
"\n",
"# MNIST images are 28x28. Total pixels in input layer is 28x28 = 784\n",
"num_inputs = 784\n",
"# Clasify the images into one of the 10 digits\n",
"num_outputs = 10\n",
"# 64 images in a batch\n",
"batch_size = 64\n",
"\n",
"# Load the training data\n",
"train_data = gluon.data.DataLoader(gluon.data.vision.MNIST(train=True).transform_first(transforms.ToTensor()),\n",
" batch_size, shuffle=True)\n",
"\n",
"# Build a simple convolutional network\n",
"def build_lenet(net): \n",
" # First convolution\n",
" net.add(gluon.nn.Conv2D(channels=20, kernel_size=5, activation='relu'))\n",
" net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))\n",
" # Second convolution\n",
" net.add(gluon.nn.Conv2D(channels=50, kernel_size=5, activation='relu'))\n",
" net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))\n",
" # Flatten the output before the fully connected layers\n",
" net.add(gluon.nn.Flatten())\n",
" # First fully connected layers with 512 neurons\n",
" net.add(gluon.nn.Dense(512, activation=\"relu\"))\n",
" # Second fully connected layer with as many neurons as the number of classes\n",
" net.add(gluon.nn.Dense(num_outputs))\n",
"\n",
" return net\n",
"\n",
"# Train a given model using MNIST data\n",
"def train_model(model):\n",
" # Initialize the parameters with Xavier initializer\n",
" model.initialize(mx.init.Xavier(), device=device)\n",
" # Use cross entropy loss\n",
" softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()\n",
" # Use Adam optimizer\n",
" trainer = gluon.Trainer(model.collect_params(), 'adam', {'learning_rate': .001})\n",
"\n",
" # Train for one epoch\n",
" for epoch in range(1):\n",
" # Iterate through the images and labels in the training data\n",
" for batch_num, (data, label) in enumerate(train_data):\n",
" # get the images and labels\n",
" data = data.to_device(device)\n",
" label = label.to_device(device)\n",
" # Ask autograd to record the forward pass\n",
" with autograd.record():\n",
" # Run the forward pass\n",
" output = model(data)\n",
" # Compute the loss\n",
" loss = softmax_cross_entropy(output, label)\n",
" # Compute gradients\n",
" loss.backward()\n",
" # Update parameters\n",
" trainer.step(data.shape[0])\n",
"\n",
" # Print loss once in a while\n",
" if batch_num % 50 == 0:\n",
" curr_loss = np.mean(loss).item()\n",
" print(\"Epoch: %d; Batch %d; Loss %f\" % (epoch, batch_num, curr_loss))"
]
},
{
"cell_type": "markdown",
"id": "9d1fc1a9",
"metadata": {},
"source": [
"Let's build a model and train it. After training, we will save and restore this model from a file."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "49e04540",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[04:46:15] /work/mxnet/src/storage/storage.cc:202: Using Pooled (Naive) StorageManager for GPU\n",
"[04:46:16] /work/mxnet/src/operator/cudnn_ops.cc:421: Auto-tuning cuDNN op, set MXNET_CUDNN_AUTOTUNE_DEFAULT to 0 to disable\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[04:46:17] /work/mxnet/src/operator/cudnn_ops.cc:421: Auto-tuning cuDNN op, set MXNET_CUDNN_AUTOTUNE_DEFAULT to 0 to disable\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 0; Loss 2.282379\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 50; Loss 0.485588\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 100; Loss 0.155776\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 150; Loss 0.054582\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 200; Loss 0.027289\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 250; Loss 0.019336\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 300; Loss 0.039793\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 350; Loss 0.194553\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 400; Loss 0.074898\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 450; Loss 0.018919\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 500; Loss 0.021001\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 550; Loss 0.046894\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 600; Loss 0.006695\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 650; Loss 0.033298\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 700; Loss 0.022084\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 750; Loss 0.171372\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 800; Loss 0.099912\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 850; Loss 0.041335\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 900; Loss 0.093764\n"
]
}
],
"source": [
"net = build_lenet(gluon.nn.Sequential())\n",
"train_model(net)"
]
},
{
"cell_type": "markdown",
"id": "fe943ead",
"metadata": {},
"source": [
"<pre>Epoch: 0; Batch 0; Loss 2.288904 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 50; Loss 0.269372 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 100; Loss 0.238990 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 150; Loss 0.320592 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 200; Loss 0.048619 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 250; Loss 0.121555 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 300; Loss 0.083645 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 350; Loss 0.040627 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 400; Loss 0.195946 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 450; Loss 0.155514 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 500; Loss 0.031762 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 550; Loss 0.056516 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 600; Loss 0.095174 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 650; Loss 0.054901 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 700; Loss 0.030067 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 750; Loss 0.102611 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 800; Loss 0.010036 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 850; Loss 0.051853 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 900; Loss 0.008402 <!--notebook-skip-line-->\n",
"</pre> <!--notebook-skip-line-->\n",
"\n",
"## Saving model parameters to file\n",
"\n",
"Okay, we now have a model (`net`) that we can save to a file. Let's save the parameters of this model to a file using the `save_parameters` function."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "cc75eef4",
"metadata": {},
"outputs": [],
"source": [
"file_name = \"net.params\"\n",
"net.save_parameters(file_name)"
]
},
{
"cell_type": "markdown",
"id": "9bc6f120",
"metadata": {},
"source": [
"We have successfully saved the parameters of the model into a file.\n",
"\n",
"## Loading model parameters from file\n",
"\n",
"Let's now create a network with the parameters we saved into the file. We build the network again using the helper first and then load the weights from the file we saved using the `load_parameters` function."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "df239613",
"metadata": {},
"outputs": [],
"source": [
"new_net = build_lenet(gluon.nn.Sequential())\n",
"new_net.load_parameters(file_name, device=device)"
]
},
{
"cell_type": "markdown",
"id": "12f67e1f",
"metadata": {},
"source": [
"Note that to do this, we need the definition of the network as Python code. If we want to recreate this network on a different machine using the saved weights, we need the same Python code (`build_lenet`) that created the network to create the `new_net` object shown above. This means Python code needs to be copied over to any machine where we want to run this network.\n",
"\n",
"If our network is [Hybrid](./hybridize.ipynb), we can even save the network architecture into files and we won't need the network definition in a Python file to load the network. We'll see how to do it in the next section.\n",
"\n",
"Let's test the model we just loaded from file."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "5eb41e1d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Downloading /home/jenkins_slave/.mxnet/datasets/mnist/t10k-images-idx3-ubyte.gz from https://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/gluon/dataset/mnist/t10k-images-idx3-ubyte.gz...\n",
"Downloading /home/jenkins_slave/.mxnet/datasets/mnist/t10k-labels-idx1-ubyte.gz from https://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/gluon/dataset/mnist/t10k-labels-idx1-ubyte.gz...\n"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model predictions: [5 4 6 0 9 0 4 9 1 9]\n"
]
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"def verify_loaded_model(net):\n",
" \"\"\"Run inference using ten random images.\n",
" Print both input and output of the model\"\"\"\n",
"\n",
" def transform(data, label):\n",
" return data.astype(np.float32)/255, label.astype(np.float32)\n",
"\n",
" # Load ten random images from the test dataset\n",
" sample_data = mx.gluon.data.DataLoader(mx.gluon.data.vision.MNIST(train=False).transform(transform),\n",
" 10, shuffle=True)\n",
"\n",
" for data, label in sample_data:\n",
"\n",
" # Display the images\n",
" img = np.transpose(data, (1,0,2,3))\n",
" img = npx.reshape(img, (28,10*28,1))\n",
" imtiles = np.tile(img, (1,1,3))\n",
" plt.imshow(imtiles.asnumpy())\n",
" plt.show()\n",
"\n",
" # Display the predictions\n",
" data = np.transpose(data, (0, 3, 1, 2))\n",
" out = net(data.to_device(device))\n",
" predictions = np.argmax(out, axis=1)\n",
" print('Model predictions: ', predictions.asnumpy())\n",
"\n",
" break\n",
"\n",
"verify_loaded_model(new_net)"
]
},
{
"cell_type": "markdown",
"id": "b7f56a0c",
"metadata": {},
"source": [
"![Model inputs mnist in 1](https://raw.githubusercontent.com/indhub/web-data/4a9c100aa996df3dff0e7f493029d411c2b526c3/mxnet/tutorials/gluon/save_load_params/mnist_in_1.png) <!--notebook-skip-line-->\n",
"\n",
"Model predictions: [1. 1. 4. 5. 0. 5. 7. 0. 3. 6.] <!--notebook-skip-line-->\n",
"\n",
"## Saving model parameters AND architecture to file\n",
"\n",
"[Hybrid](./hybridize.ipynb) models can be serialized as JSON files using the `export` function. Once serialized, these models can be loaded from other language bindings like C++ or Scala for faster inference or inference in different environments.\n",
"\n",
"Note that the network we created above is not a Hybrid network and therefore cannot be serialized into a JSON file. So, let's create a Hybrid version of the same network and train it."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "43a20b58",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 0; Loss 2.297905\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 50; Loss 0.279512\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 100; Loss 0.320809\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 150; Loss 0.122951\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 200; Loss 0.172625\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 250; Loss 0.063134\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 300; Loss 0.162333\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 350; Loss 0.061574\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 400; Loss 0.063895\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 450; Loss 0.204456\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 500; Loss 0.107851\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 550; Loss 0.025380\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 600; Loss 0.056878\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 650; Loss 0.044420\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 700; Loss 0.027201\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 750; Loss 0.013869\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 800; Loss 0.048232\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 850; Loss 0.038755\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0; Batch 900; Loss 0.037504\n"
]
}
],
"source": [
"net = build_lenet(gluon.nn.HybridSequential())\n",
"net.hybridize()\n",
"train_model(net)"
]
},
{
"cell_type": "markdown",
"id": "d842b606",
"metadata": {},
"source": [
"<pre>Epoch: 0; Batch 0; Loss 2.323284 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 50; Loss 0.444733 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 100; Loss 0.103407 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 150; Loss 0.166772 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 200; Loss 0.227569 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 250; Loss 0.069515 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 300; Loss 0.074086 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 350; Loss 0.074382 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 400; Loss 0.026569 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 450; Loss 0.097248 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 500; Loss 0.059895 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 550; Loss 0.053194 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 600; Loss 0.076294 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 650; Loss 0.047274 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 700; Loss 0.007898 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 750; Loss 0.039478 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 800; Loss 0.031342 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 850; Loss 0.059289 <!--notebook-skip-line-->\n",
"Epoch: 0; Batch 900; Loss 0.037809 <!--notebook-skip-line-->\n",
"</pre> <!--notebook-skip-line-->\n",
"\n",
"We now have a trained hybrid network. This can be exported into files using the `export` function. The `export` function will export the model architecture into a `.json` file and model parameters into a `.params` file."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "e4c49b00",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('lenet-symbol.json', 'lenet-0001.params')"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net.export(\"lenet\", epoch=1)"
]
},
{
"cell_type": "markdown",
"id": "10f52c44",
"metadata": {},
"source": [
"`export` in this case creates `lenet-symbol.json` and `lenet-0001.params` in the current directory.\n",
"\n",
"## Loading model parameters AND architecture from file\n",
"\n",
"\n",
"### From Python\n",
"\n",
"Serialized Hybrid networks (saved as .JSON and .params file) can be loaded and used inside Python frontend using `gluon.nn.SymbolBlock`. To demonstrate that, let's load the network we serialized above."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "60fa394a",
"metadata": {},
"outputs": [],
"source": [
"import warnings\n",
"with warnings.catch_warnings():\n",
" warnings.simplefilter(\"ignore\")\n",
" deserialized_net = gluon.nn.SymbolBlock.imports(\"lenet-symbol.json\", ['data'], \"lenet-0001.params\", device=device)"
]
},
{
"cell_type": "markdown",
"id": "68ffbbb8",
"metadata": {},
"source": [
"`deserialized_net` now contains the network we deserialized from files. Let's test the deserialized network to make sure it works."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "4fccb211",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model predictions: [2 0 2 2 4 5 9 8 4 7]\n"
]
}
],
"source": [
"verify_loaded_model(deserialized_net)"
]
},
{
"cell_type": "markdown",
"id": "ae02024f",
"metadata": {},
"source": [
"![Model inputs mnist in 2](https://raw.githubusercontent.com/indhub/web-data/4a9c100aa996df3dff0e7f493029d411c2b526c3/mxnet/tutorials/gluon/save_load_params/mnist_in_2.png) <!--notebook-skip-line-->\n",
"\n",
"Model predictions: [4. 8. 0. 1. 5. 5. 8. 8. 1. 9.] <!--notebook-skip-line-->\n",
"\n",
"That's all! We learned how to save and load Gluon networks from files. Parameters of any Gluon network can be persisted into files. For hybrid networks, both the architecture of the network and the parameters can be saved to and loaded from files."
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}