blob: f1acaebc7214799e9c89ebc45011b1d568d351be [file] [log] [blame]
<!DOCTYPE html>
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html lang=" en"><head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/versions/1.9.1/assets/img/mxnet-icon.png" rel="icon" type="image/png"><!-- Begin Jekyll SEO tag v2.6.1 -->
<title>Distributed Training in MXNet | Apache MXNet</title>
<meta name="generator" content="Jekyll v3.8.6" />
<meta property="og:title" content="Distributed Training in MXNet" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="A flexible and efficient library for deep learning." />
<meta property="og:description" content="A flexible and efficient library for deep learning." />
<link rel="canonical" href="https://mxnet.apache.org/versions/1.9.1/api/faq/distributed_training" />
<meta property="og:url" content="https://mxnet.apache.org/versions/1.9.1/api/faq/distributed_training" />
<meta property="og:site_name" content="Apache MXNet" />
<script type="application/ld+json">
{"description":"A flexible and efficient library for deep learning.","headline":"Distributed Training in MXNet","@type":"WebPage","url":"https://mxnet.apache.org/versions/1.9.1/api/faq/distributed_training","@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="/versions/1.9.1/assets/docsearch.min.css" /><link rel="stylesheet" href="/versions/1.9.1/assets/main.css"><link type="application/atom+xml" rel="alternate" href="https://mxnet.apache.org/versions/1.9.1/feed.xml" title="Apache MXNet" /><!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="https://analytics.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '23']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
<script src="/versions/1.9.1/assets/js/jquery-3.3.1.min.js"></script>
<script src="/versions/1.9.1/assets/js/docsearch.min.js"></script><script src="/versions/1.9.1/assets/js/globalSearch.js" defer></script>
<script src="/versions/1.9.1/assets/js/clipboard.js" defer></script>
<script src="/versions/1.9.1/assets/js/copycode.js" defer></script></head>
<body><header class="site-header" role="banner">
<script>
$(document).ready(function () {
// HEADER OPACITY LOGIC
function opacity_header() {
var value = "rgba(4,140,204," + ($(window).scrollTop() / 300 + 0.4) + ")"
$('.site-header').css("background-color", value)
}
$(window).scroll(function () {
opacity_header()
})
opacity_header();
// MENU SELECTOR LOGIC
$('.page-link').each( function () {
if (window.location.href.includes(this.href)) {
$(this).addClass("page-current");
}
});
})
</script>
<div class="wrapper">
<a class="site-title" rel="author" href="/versions/1.9.1/"><img
src="/versions/1.9.1/assets/img/mxnet_logo.png" class="site-header-logo"></a>
<nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger"/>
<label for="nav-trigger">
<span class="menu-icon">
<svg viewBox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"/>
</svg>
</span>
</label>
<div class="gs-search-border">
<div id="gs-search-icon"></div>
<form id="global-search-form">
<input id="global-search" type="text" title="Search" placeholder="Search" />
<div id="global-search-dropdown-container">
<button class="gs-current-version btn" type="button" data-toggle="dropdown">
<span id="gs-current-version-label">1.9.1</span>
<svg class="gs-dropdown-caret" viewBox="0 0 32 32" class="icon icon-caret-bottom" aria-hidden="true">
<path class="dropdown-caret-path" d="M24 11.305l-7.997 11.39L8 11.305z"></path>
</svg>
</button>
<ul class="gs-opt-group gs-version-dropdown">
<li class="gs-opt gs-versions">master</li>
<li class="gs-opt gs-versions active">1.9.1</li>
<li class="gs-opt gs-versions">1.8.0</li>
<li class="gs-opt gs-versions">1.7.0</li>
<li class="gs-opt gs-versions">1.6.0</li>
<li class="gs-opt gs-versions">1.5.0</li>
<li class="gs-opt gs-versions">1.4.1</li>
<li class="gs-opt gs-versions">1.3.1</li>
<li class="gs-opt gs-versions">1.2.1</li>
<li class="gs-opt gs-versions">1.1.0</li>
<li class="gs-opt gs-versions">1.0.0</li>
<li class="gs-opt gs-versions">0.12.1</li>
<li class="gs-opt gs-versions">0.11.0</li>
</ul>
</div>
<span id="global-search-close">x</span>
</form>
</div>
<div class="trigger">
<div id="global-search-mobile-border">
<div id="gs-search-icon-mobile"></div>
<input id="global-search-mobile" placeholder="Search..." type="text"/>
<div id="global-search-dropdown-container-mobile">
<button class="gs-current-version-mobile btn" type="button" data-toggle="dropdown">
<svg class="gs-dropdown-caret" viewBox="0 0 32 32" class="icon icon-caret-bottom" aria-hidden="true">
<path class="dropdown-caret-path" d="M24 11.305l-7.997 11.39L8 11.305z"></path>
</svg>
</button>
<ul class="gs-opt-group gs-version-dropdown-mobile">
<li class="gs-opt gs-versions">master</li>
<li class="gs-opt gs-versions active">1.9.1</li>
<li class="gs-opt gs-versions">1.8.0</li>
<li class="gs-opt gs-versions">1.7.0</li>
<li class="gs-opt gs-versions">1.6.0</li>
<li class="gs-opt gs-versions">1.5.0</li>
<li class="gs-opt gs-versions">1.4.1</li>
<li class="gs-opt gs-versions">1.3.1</li>
<li class="gs-opt gs-versions">1.2.1</li>
<li class="gs-opt gs-versions">1.1.0</li>
<li class="gs-opt gs-versions">1.0.0</li>
<li class="gs-opt gs-versions">0.12.1</li>
<li class="gs-opt gs-versions">0.11.0</li>
</ul>
</div>
</div>
<a class="page-link" href="/versions/1.9.1/get_started">Get Started</a>
<a class="page-link" href="/versions/1.9.1/features">Features</a>
<a class="page-link" href="/versions/1.9.1/ecosystem">Ecosystem</a>
<a class="page-link" href="/versions/1.9.1/api">Docs & Tutorials</a>
<a class="page-link" href="/versions/1.9.1/trusted_by">Trusted By</a>
<a class="page-link" href="https://github.com/apache/mxnet">GitHub</a>
<div class="dropdown" style="min-width:100px">
<span class="dropdown-header">Apache
<svg class="dropdown-caret" viewBox="0 0 32 32" class="icon icon-caret-bottom" aria-hidden="true"><path class="dropdown-caret-path" d="M24 11.305l-7.997 11.39L8 11.305z"></path></svg>
</span>
<div class="dropdown-content" style="min-width:250px">
<a href="https://www.apache.org/foundation/">Apache Software Foundation</a>
<a href="https://www.apache.org/licenses/">License</a>
<a href="/versions/1.9.1/api/faq/security.html">Security</a>
<a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy</a>
<a href="https://www.apache.org/events/current-event">Events</a>
<a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
<a href="https://www.apache.org/foundation/thanks.html">Thanks</a>
</div>
</div>
<div class="dropdown">
<span class="dropdown-header">1.9.1
<svg class="dropdown-caret" viewBox="0 0 32 32" class="icon icon-caret-bottom" aria-hidden="true"><path class="dropdown-caret-path" d="M24 11.305l-7.997 11.39L8 11.305z"></path></svg>
</span>
<div class="dropdown-content">
<a href="/">master</a>
<a class="dropdown-option-active" href="/versions/1.9.1/">1.9.1</a>
<a href="/versions/1.8.0/">1.8.0</a>
<a href="/versions/1.7.0/">1.7.0</a>
<a href="/versions/1.6.0/">1.6.0</a>
<a href="/versions/1.5.0/">1.5.0</a>
<a href="/versions/1.4.1/">1.4.1</a>
<a href="/versions/1.3.1/">1.3.1</a>
<a href="/versions/1.2.1/">1.2.1</a>
<a href="/versions/1.1.0/">1.1.0</a>
<a href="/versions/1.0.0/">1.0.0</a>
<a href="/versions/0.12.1/">0.12.1</a>
<a href="/versions/0.11.0/">0.11.0</a>
</div>
</div>
</div>
</nav>
</div>
</header>
<main class="page-content" aria-label="Content">
<script>
</script>
<article class="post">
<header class="post-header wrapper">
<h1 class="post-title">Distributed Training in MXNet</h1>
<h3></h3></header>
<div class="post-content">
<div class="wrapper">
<div class="row">
<div class="col-3 docs-side-bar">
<h3 style="text-transform: capitalize; padding-left:10px">faq</h3>
<ul>
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/add_op_in_backend">A Beginner's Guide to Implementing Operators in MXNet Backend</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/caffe">Convert from Caffe to MXNet</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/cloud">MXNet on the Cloud</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/distributed_training">Distributed Training in MXNet</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/env_var">Environment Variables</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/float16">Float16</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/large_tensor_support">Using MXNet with Large Tensor Support</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/model_parallel_lstm">Model Parallel</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/multi_device">Data Parallelism with Multiple CPU/GPUs on MXNet</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/new_op">Create New Operators</a></li>
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/nnpack">NNPACK for Multi-Core CPU Support in MXNet</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/perf">Some Tips for Improving MXNet Performance</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/recordio">Create a Dataset Using RecordIO</a></li>
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/s3_integration">Use data from S3 for training</a></li>
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/security">MXNet Security Best Practices</a></li>
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/smart_device">Deep Learning at the Edge</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/visualize_graph">Visualize Neural Networks</a></li>
<!-- page-category -->
<li><a href="/versions/1.9.1/api/faq/why_mxnet">Why MXNet came to be?</a></li>
<!-- page-category -->
<!-- page-category -->
<!-- page-category -->
<!-- resource-p -->
</ul>
</div>
<div class="col-9">
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
<!--- or more contributor license agreements. See the NOTICE file -->
<!--- distributed with this work for additional information -->
<!--- regarding copyright ownership. The ASF licenses this file -->
<!--- to you under the Apache License, Version 2.0 (the -->
<!--- "License"); you may not use this file except in compliance -->
<!--- with the License. You may obtain a copy of the License at -->
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
<!--- Unless required by applicable law or agreed to in writing, -->
<!--- software distributed under the License is distributed on an -->
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
<!--- KIND, either express or implied. See the License for the -->
<!--- specific language governing permissions and limitations -->
<!--- under the License. -->
<h1 id="distributed-training-in-mxnet">Distributed Training in MXNet</h1>
<p>MXNet supports distributed training enabling us to leverage multiple machines for faster training.
In this document, we describe how it works, how to launch a distributed training job and
some environment variables which provide more control.</p>
<h2 id="types-of-parallelism">Types of Parallelism</h2>
<p>There are two ways in which we can distribute the workload of training a neural network across multiple devices (can be either GPU or CPU).
The first way is <em>data parallelism</em>, which refers to the case where each device stores a complete copy of the model.
Each device works with a different part of the dataset, and the devices collectively update a shared model.
These devices can be located on a single machine or across multiple machines.
In this document, we describe how to train a model with devices distributed across machines in a data parallel way.</p>
<p>When models are so large that they don&#39;t fit into device memory, then a second way called <em>model parallelism</em> is useful.
Here, different devices are assigned the task of learning different parts of the model.
Currently, MXNet supports Model parallelism in a single machine only. Refer <a href="model_parallel_lstm">Training with multiple GPUs using model parallelism</a> for more on this.</p>
<h2 id="how-does-distributed-training-work">How Does Distributed Training Work?</h2>
<p>The following concepts are key to understanding distributed training in MXNet:</p>
<h3 id="types-of-processes">Types of Processes</h3>
<p>MXNet has three types of processes which communicate with each other to accomplish training of a model.
- Worker: A worker node actually performs training on a batch of training samples.
Before processing each batch, the workers pull weights from servers.
The workers also send gradients to the servers after each batch.
Depending on the workload for training a model, it might not be a good idea to run multiple worker processes on the same machine.
- Server: There can be multiple servers which store the model&#39;s parameters, and communicate with workers.
A server may or may not be co-located with the worker processes.
- Scheduler: There is only one scheduler. The role of the scheduler is to set up the cluster. This includes waiting for messages that each node has come up and which port the node is listening on.
The scheduler then lets all processes know about every other node in the cluster, so that they can communicate with each other.</p>
<h3 id="kv-store">KV Store</h3>
<p>MXNet provides a key-value store, which is a critical component used for multi-device training. The communication of parameters across devices on a single machine, as well as across multiple machines, is relayed through one or more servers with a key-value store for the parameters. Each value in this store is represented by a key and value, where each parameter array in the network is assigned a key, and value refers to the weights of that parameter array. Workers <code>push</code> gradients after processing a batch, and <code>pull</code> updated weights before processing a new batch.
We can also pass in optimizers for the KVStore to use while updating each weight. Optimizers like Stochastic Gradient Descent define an update rule,
essentially a mathematical formula to compute the new weight based on the old weight, gradient, and some parameters.</p>
<p>If you are using a Gluon Trainer object or the Module API,
it uses a kvstore object internally to aggregate gradients from multiple devices on the same machine as well as across different machines.</p>
<p>Although the API remains the same whether or not multiple machines are being used,
the notion of kvstore server exists only during distributed training.
In this case, each <code>push</code> and <code>pull</code> involves communication with the kvstore servers. When there are multiple devices on a single machine, gradients from these devices are first aggregated on the machine and then sent to the servers.
Note that we need to compile MXNet with the build flag <code>USE_DIST_KVSTORE=1</code> to use distributed training.</p>
<p>The distributed mode of KVStore is enabled by calling <code>mxnet.kvstore.create</code> function
with a string argument which contains the word <code>dist</code> as follows:</p>
<blockquote>
<p>kv = mxnet.kvstore.create(&#39;dist_sync&#39;)</p>
</blockquote>
<p>Refer <a href="/versions/1.9.1/api/python/docs/api/kvstore/index.html#mxnet.kvstore.KVStore">KVStore API</a> for more information about KVStore.</p>
<h3 id="distribution-of-keys">Distribution of Keys</h3>
<p>Each server doesn&#39;t necessarily store all the keys or parameter arrays.
Parameters are distributed across different servers. The decision of which server stores a particular key is made at random.
This distribution of keys across different servers is handled transparently by the KVStore.
It ensures that when a key is pulled, that request is sent to the server which has the corresponding value.
If the value of some key is very large, it may be sharded across different servers. This means that different servers hold different parts of the value.
Again, this is handled transparently so that the worker does not have to do anything different.
The threshold for this sharding can be controlled with the environment variable <code>MXNET_KVSTORE_BIGARRAY_BOUND</code>.
See <a href="#environment-variables">environment variables</a> for more details.</p>
<h3 id="split-training-data">Split training data</h3>
<p>When running distributed training in data parallel mode, we want each machine to be working on different parts of the dataset.</p>
<p>For data parallel training on a single worker,
we can use <code>mxnet.gluon.utils.split_and_load</code> to split a batch of samples provided by the data iterator, and then load each part of the batch on the device which will process it.</p>
<p>In the case of distributed training though, we would need to divide the dataset into <code>n</code> parts at the beginning, so that each worker gets a different part. Each worker can then use <code>split_and_load</code> to again divide that part of the dataset across different devices on a single machine.</p>
<p>Typically, this split of data for each worker happens through the data iterator,
on passing the number of parts and the index of parts to iterate over.
Some iterators in MXNet that support this feature are <a href="/api/python/docs/api/mxnet/io/index.html?MNISTIter#mxnet.io.MNISTIter">mxnet.io.MNISTIterator</a> and <a href="api/python/docs/api/mxnet/io/index.html?imagerecorditer#mxnet.io.ImageRecordIter">mxnet.io.ImageRecordIter</a>.
If you are using a different iterator, you can look at how the above iterators implement this.
We can use the kvstore object to get the number of workers (<code>kv.num_workers</code>) and rank of the current worker (<code>kv.rank</code>).
These can be passed as arguments to the iterator.
You can look at <a href="https://github.com/apache/mxnet/blob/master/example/gluon/image_classification.py">example/gluon/image_classification.py</a>
to see an example usage.</p>
<h3 id="updating-weights">Updating weights</h3>
<p>KVStore server supports two modes, one which aggregates the gradients and updates the weights using those gradients, and second where the server only aggregates gradients. In the latter case, when a worker process pulls from kvstore, it gets the aggregated gradients. The worker then uses these gradients and applies the weights locally.</p>
<p>When using Gluon there is an option to choose between these modes by passing <code>update_on_kvstore</code> variable when you create the <a href="/api/python/docs/api/gluon/trainer.html">Trainer</a> object like this:</p>
<div class="highlight"><pre><code class="language-" data-lang="">trainer = gluon.Trainer(net.collect_params(), optimizer='sgd',
optimizer_params={'learning_rate': opt.lr,
'wd': opt.wd,
'momentum': opt.momentum,
'multi_precision': True},
kvstore=kv,
update_on_kvstore=True)
</code></pre></div>
<p>When using the symbolic interface, it performs the weight updates on the server without the user having to do anything special.</p>
<h3 id="different-modes-of-distributed-training">Different Modes of Distributed Training</h3>
<p>Distributed training itself is enabled when kvstore creation string contains the word <code>dist</code>.</p>
<p>Different modes of distributed training can be enabled by using different types of kvstore.</p>
<ul>
<li><p><code>dist_sync</code>: In synchronous distributed training, all workers use the same synchronized set of model parameters at the start of every batch.
This means that after each batch, the server waits to receive gradients from each worker before it updates the model parameters.
This synchronization comes at a cost because the worker pulling parameters would have to wait till the server finishes this process.
In this mode, if a worker crashes, then it halts the progress of all workers.</p></li>
<li><p><code>dist_async</code>: In asynchronous distributed training, the server receives gradients from one worker and immediately updates its store, which it uses to respond to any future pulls.
This means that a worker who finishes processing a batch can pull the current parameters from server and start the next batch,
even if other workers haven&#39;t finished processing the earlier batch.
This is faster than <code>dist_sync</code> because there is no cost of synchronization, but can take more epochs to converge.
The update of weights is atomic, meaning no two updates happen on the same weight at the same time. However, the order of updates is not guaranteed.
In <code>async</code> mode, it is required to pass an optimizer because in the absence of an optimizer kvstore would replace the stored weights with received weights and this doesn&#39;t make sense for training in asynchronous mode. Hence, when using Gluon with <code>async</code> mode we need to set <code>update_on_kvstore</code> to <code>True</code>.</p></li>
<li><p><code>dist_sync_device</code>: Same as <code>dist_sync</code> except that when there are multiple GPUs being used on each node,
this mode aggregates gradients and updates weights on GPU while dist_sync does so on CPU memory.
This is faster than <code>dist_sync</code> because it reduces expensive communication between GPU and CPU, but it increases memory usage on GPU.</p></li>
<li><p><code>dist_async_device</code> : The analogue of <code>dist_sync_device</code> but in asynchronous mode.</p></li>
</ul>
<h3 id="gradient-compression">Gradient Compression</h3>
<p>When communication is expensive, and the ratio of computation time to communication time is low, communication can become a bottleneck.
In such cases, gradient compression can be used to reduce the cost of communication, thereby speeding up training.
Refer <a href="/versions/1.9.1/api/faq/gradient_compression">Gradient compression</a> for more details.</p>
<p>Note: For small models when the cost of computation is much lower than cost of communication,
distributed training might actually be slower than training on a single machine because of the overhead of communication and synchronization.</p>
<h2 id="how-to-start-distributed-training">How to Start Distributed Training?</h2>
<p>MXNet provides a script tools/launch.py to make it easy to launch a distributed training job. This supports various types of cluster resource managers like <code>ssh</code>, <code>mpirun</code>, <code>yarn</code> and <code>sge</code>.
If you already have one of these clusters setup, you can skip the next section on setting up a cluster.
If you want to use a type of cluster not mentioned above, skip ahead to Manually launching jobs section.</p>
<h3 id="setting-up-the-cluster">Setting up the Cluster</h3>
<p>An easy way to set up a cluster of EC2 instances for distributed deep learning is by using the <a href="https://github.com/awslabs/deeplearning-cfn">AWS CloudFormation template</a>.
If you can not use the above, this section will help you manually set up a cluster of instances
to enable you to use <code>ssh</code> for launching a distributed training job.
Let us denote one machine as the <code>master</code> of the cluster through which we will launch and monitor the distributed training on all machines.</p>
<p>If the machines in your cluster are a part of a cloud computing platform like AWS EC2, then your instances should be using key-based authentication already.
Ensure that you create all instances using the same key, say <code>mxnet-key</code> and in the same security group.
Next, we need to ensure that master has access to all other machines in the cluster through <code>ssh</code> by
adding this key to <a href="https://en.wikipedia.org/wiki/Ssh-agent">ssh-agent</a> and forwarding it to master when we log in. This will make <code>mxnet-key</code> the default key on master.</p>
<div class="highlight"><pre><code class="language-" data-lang="">ssh-add .ssh/mxnet-key
ssh -A user@MASTER_IP_ADDRESS
</code></pre></div>
<p>If your machines use passwords for authentication, see <a href="https://help.ubuntu.com/community/SSH/OpenSSH/Keys">here</a> for instructions on setting up password-less authentication between machines.</p>
<p>It is easier if all these machines have a shared file system so that they can access the training script. One way is to use <a href="https://aws.amazon.com/efs">Amazon Elastic File System</a> to create your network file system.
The options in the following command are the recommended options when mounting an AWS Elastic File System.</p>
<div class="highlight"><pre><code class="language-" data-lang="">sudo mkdir efs &amp;&amp; sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 NETWORK_FILE_SYSTEM_IP:/ efs
</code></pre></div>
<p>Tip: You might find it helpful to store large datasets on S3 for easy access from all machines in the cluster. Refer <a href="/versions/1.9.1/api/faq/s3_integration">Using data from S3 for training</a> for more information.</p>
<h3 id="using-launch-py">Using Launch.py</h3>
<p>MXNet provides a script <a href="https://github.com/apache/mxnet/blob/master/tools/launch.py">tools/launch.py</a> to make it easy to launch distributed training on a cluster with <code>ssh</code>, <code>mpi</code>, <code>sge</code> or <code>yarn</code>.
You can fetch this script by cloning the mxnet repository.</p>
<div class="highlight"><pre><code class="language-" data-lang="">git clone --recursive https://github.com/apache/mxnet
</code></pre></div>
<h4 id="example">Example</h4>
<p>Let us consider training a VGG11 model on the CIFAR10 dataset using <a href="https://github.com/apache/mxnet/blob/master/tools/launch.py">example/gluon/image_classification.py</a>.
<code>
cd example/gluon/
</code>
On a single machine, we can run this script as follows:
<code>
python image_classification.py --dataset cifar10 --model vgg11 --epochs 1
</code></p>
<p>For distributed training of this example, we would do the following:</p>
<p>If the mxnet directory which contains the script <code>image_classification.py</code> is accessible to all machines in the cluster (for example if they are on a network file system), we can run:
<code>
../../tools/launch.py -n 3 -H hosts --launcher ssh python image_classification.py --dataset cifar10 --model vgg11 --epochs 1 --kvstore dist_sync
</code></p>
<p>If the directory with the script is not accessible from the other machines in the cluster, then we can synchronize the current directory to all machines.
<code>
../../tools/launch.py -n 3 -H hosts --launcher ssh --sync-dst-dir /tmp/mxnet_job/ python image_classification.py --dataset cifar10 --model vgg11 --epochs 1 --kvstore dist_sync
</code></p>
<blockquote>
<p>Tip: If you don&#39;t have a cluster ready and still want to try this out, pass the option <code>--launcher local</code> instead of <code>ssh</code></p>
</blockquote>
<h4 id="options">Options</h4>
<p>Here, launch.py is used to submit the distributed training job. It takes the following options:
- <code>-n</code> denotes the number of worker nodes to be launched.
- <code>-s</code> denotes the number of server nodes to be launched.
If it is not specified, it is taken to be equal to the number of worker nodes.
The script tries to cycle through the hosts file to launch the servers and workers.
For example, if you have 5 hosts in the hosts file and you passed <code>n</code> as 3 (and nothing for <code>s</code>).
The script will launch a total of 3 server processes,
one each for the first three hosts and launch a total of 3 worker processes, one each for the fourth, fifth and first host.
If the hosts file has exactly <code>n</code> number of worker nodes, it will launch a server process and a worker process on each of the <code>n</code> hosts.
- <code>--launcher</code> denotes the mode of communication. The options are:
- <code>ssh</code> if machines can communicate through ssh without passwords. This is the default launcher mode.
- <code>mpi</code> if Open MPI is available
- <code>sge</code> for Sun Grid Engine
- <code>yarn</code> for Apache Yarn
- <code>local</code> for launching all processes on the same local machine. This can be used for debugging purposes.
- <code>-H</code> requires the path of the hosts file
This file contains IPs of the machines in the cluster. These machines should be able to communicate with each other without using passwords.
This file is only applicable and required when the launcher mode is <code>ssh</code> or <code>mpi</code>.
An example of the contents of the hosts file would be:
<code>
172.30.0.172
172.31.0.173
172.30.1.174
</code>
- <code>--sync-dst-dir</code> takes the path of a directory on all hosts to which the current working directory will be synchronized. This only supports <code>ssh</code> launcher mode.
This is necessary when the working directory is not accessible to all machines in the cluster. Setting this option synchronizes the current directory using rsync before the job is launched.
If you have not installed MXNet system-wide
then you have to copy the folder <code>python/mxnet</code> and the file <code>lib/libmxnet.so</code> into the current directory before running <code>launch.py</code>.
For example if you are in <code>example/gluon</code>, you can do this with <code>cp -r ../../python/mxnet ../../lib/libmxnet.so .</code>. This would work if your <code>lib</code> folder contains <code>libmxnet.so</code>, as would be the case when you use make. If you use CMake, this file would be in your <code>build</code> directory.</p>
<ul>
<li><code>python image_classification.py --dataset cifar10 --model vgg11 --epochs 1 --kvstore dist_sync</code>
is the command for the training job on each machine. Note the use of <code>dist_sync</code> for the kvstore used in the script.</li>
</ul>
<h4 id="terminating-jobs">Terminating Jobs</h4>
<p>If the training job crashes due to an error or if we try to terminate the launch script while training is running,
jobs on all machines might not have terminated. In such a case, we would need to terminate them manually.
If we are using <code>ssh</code> launcher, this can be done by running the following command where <code>hosts</code> is the path of the hostfile.
<code>
while read -u 10 host; do ssh -o &quot;StrictHostKeyChecking no&quot; $host &quot;pkill -f python&quot; ; done 10&lt;hosts
</code></p>
<h3 id="manually-launching-jobs">Manually Launching Jobs</h3>
<p>If for some reason, you do not want to use the script above to start distributed training, then this section will be helpful.
MXNet uses environment variables to assign roles to different processes and to let different processes find the scheduler.
The environment variables are required to be set correctly as follows for the training to start:
- <code>DMLC_ROLE</code>: Specifies the role of the process. This can be <code>server</code>, <code>worker</code> or <code>scheduler</code>. Note that there should only be one <code>scheduler</code>.
When <code>DMLC_ROLE</code> is set to <code>server</code> or <code>scheduler</code>, these processes start when mxnet is imported.
- <code>DMLC_PS_ROOT_URI</code>: Specifies the IP of the scheduler
- <code>DMLC_PS_ROOT_PORT</code>: Specifies the port that the scheduler listens to
- <code>DMLC_NUM_SERVER</code>: Specifies how many server nodes are in the cluster
- <code>DMLC_NUM_WORKER</code>: Specifies how many worker nodes are in the cluster</p>
<p>Below is an example to start all jobs locally on Linux or Mac. Note that starting all jobs on the same machine is not a good idea.
This is only to make the usage clear.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">export </span><span class="nv">COMMAND</span><span class="o">=</span><span class="s1">'python example/gluon/image_classification.py --dataset cifar10 --model vgg11 --epochs 1 --kvstore dist_sync'</span>
<span class="nv">DMLC_ROLE</span><span class="o">=</span>server <span class="nv">DMLC_PS_ROOT_URI</span><span class="o">=</span>127.0.0.1 <span class="nv">DMLC_PS_ROOT_PORT</span><span class="o">=</span>9092 <span class="nv">DMLC_NUM_SERVER</span><span class="o">=</span>2 <span class="nv">DMLC_NUM_WORKER</span><span class="o">=</span>2 <span class="nv">$COMMAND</span> &amp;
<span class="nv">DMLC_ROLE</span><span class="o">=</span>server <span class="nv">DMLC_PS_ROOT_URI</span><span class="o">=</span>127.0.0.1 <span class="nv">DMLC_PS_ROOT_PORT</span><span class="o">=</span>9092 <span class="nv">DMLC_NUM_SERVER</span><span class="o">=</span>2 <span class="nv">DMLC_NUM_WORKER</span><span class="o">=</span>2 <span class="nv">$COMMAND</span> &amp;
<span class="nv">DMLC_ROLE</span><span class="o">=</span>scheduler <span class="nv">DMLC_PS_ROOT_URI</span><span class="o">=</span>127.0.0.1 <span class="nv">DMLC_PS_ROOT_PORT</span><span class="o">=</span>9092 <span class="nv">DMLC_NUM_SERVER</span><span class="o">=</span>2 <span class="nv">DMLC_NUM_WORKER</span><span class="o">=</span>2 <span class="nv">$COMMAND</span> &amp;
<span class="nv">DMLC_ROLE</span><span class="o">=</span>worker <span class="nv">DMLC_PS_ROOT_URI</span><span class="o">=</span>127.0.0.1 <span class="nv">DMLC_PS_ROOT_PORT</span><span class="o">=</span>9092 <span class="nv">DMLC_NUM_SERVER</span><span class="o">=</span>2 <span class="nv">DMLC_NUM_WORKER</span><span class="o">=</span>2 <span class="nv">$COMMAND</span> &amp;
<span class="nv">DMLC_ROLE</span><span class="o">=</span>worker <span class="nv">DMLC_PS_ROOT_URI</span><span class="o">=</span>127.0.0.1 <span class="nv">DMLC_PS_ROOT_PORT</span><span class="o">=</span>9092 <span class="nv">DMLC_NUM_SERVER</span><span class="o">=</span>2 <span class="nv">DMLC_NUM_WORKER</span><span class="o">=</span>2 <span class="nv">$COMMAND</span>
</code></pre></div>
<p>For an in-depth discussion of how the scheduler sets up the cluster, you can go <a href="https://blog.kovalevskyi.com/mxnet-distributed-training-explained-in-depth-part-1-b90c84bda725">here</a>.</p>
<h2 id="environment-variables">Environment Variables</h2>
<h3 id="for-tuning-performance">For tuning performance</h3>
<ul>
<li><p><code>MXNET_KVSTORE_REDUCTION_NTHREADS</code>
Value type: Integer
Default value: 4
The number of CPU threads used for summing up big arrays on a single machine
This will also be used for <code>dist_sync</code> kvstore to sum up arrays from different contexts on a single machine.
This does not affect summing up of arrays from different machines on servers.
Summing up of arrays for <code>dist_sync_device</code> kvstore is also unaffected as that happens on GPUs.</p>
<ul>
<li><code>MXNET_KVSTORE_BIGARRAY_BOUND</code>
Value type: Integer
Default value: 1000000
The minimum size of a <em>big array</em>.
When the array size is bigger than this threshold, <code>MXNET_KVSTORE_REDUCTION_NTHREADS</code> threads are used for reduction.
This parameter is also used as a load balancer in kvstore.
It controls when to partition a single weight to all the servers.
If the size of a single weight matrix is less than this bound, then it is sent to a single randomly picked server; otherwise, it is partitioned to all the servers.</li>
<li><code>MXNET_ENABLE_GPU_P2P</code> GPU Peer-to-Peer communication
Value type: 0(false) or 1(true)
Default value: 1
If true, MXNet tries to use GPU peer-to-peer communication, if available on your device. This is used only when kvstore has the type <code>device</code> in it.</li>
</ul></li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li><p><code>DMLC_INTERFACE</code> Using a particular network interface
Value type: Name of interface
Example: <code>eth0</code>
MXNet often chooses the first available network interface.
But for machines with multiple interfaces, we can specify which network interface to use for data communication using this environment variable.</p></li>
<li><p><code>PS_VERBOSE</code> Logging communication
Value type: 1 or 2
Default value: (empty)</p>
<ul>
<li><code>PS_VERBOSE=1</code> logs connection information like the IPs and ports of all nodes</li>
<li><code>PS_VERBOSE=2</code> logs all data communication information</li>
</ul></li>
</ul>
<p>When the network is unreliable, messages being sent from one node to another might get lost.
The training process can hang when a critical message is not successfully delivered.
In such cases, an additional ACK can be sent for each message to track its delivery.
This can be done by setting <code>PS_RESEND</code> and <code>PS_RESEND_TIMEOUT</code>
- <code>PS_RESEND</code> Retransmission for unreliable network
Value type: 0(false) or 1(true)
Default value: 0
Whether or not to enable retransmission of messages
- <code>PS_RESEND_TIMEOUT</code> Timeout for ACK to be received
Value type: Integer (in milliseconds)
Default value: 1000
If ACK is not received in <code>PS_RESEND_TIMEOUT</code> milliseconds, then the message will be resent.</p>
</div>
</div>
</div>
</div>
</article>
</main><footer class="site-footer h-card">
<div class="wrapper">
<div class="row">
<div class="col-4">
<h4 class="footer-category-title">Resources</h4>
<ul class="contact-list">
<li><a href="/versions/1.9.1/community/contribute#mxnet-dev-communications">Mailing lists</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/MXNET/Apache+MXNet+Home">Developer Wiki</a></li>
<li><a href="https://issues.apache.org/jira/projects/MXNET/issues">Jira Tracker</a></li>
<li><a href="https://github.com/apache/mxnet/labels/Roadmap">Github Roadmap</a></li>
<li><a href="https://medium.com/apache-mxnet">Blog</a></li>
<li><a href="https://discuss.mxnet.io">Forum</a></li>
<li><a href="/versions/1.9.1/community/contribute">Contribute</a></li>
</ul>
</div>
<div class="col-4"><ul class="social-media-list"><li><a href="https://github.com/apache/mxnet"><svg class="svg-icon"><use xlink:href="/versions/1.9.1/assets/minima-social-icons.svg#github"></use></svg> <span class="username">apache/mxnet</span></a></li><li><a href="https://www.twitter.com/apachemxnet"><svg class="svg-icon"><use xlink:href="/versions/1.9.1/assets/minima-social-icons.svg#twitter"></use></svg> <span class="username">apachemxnet</span></a></li><li><a href="https://youtube.com/apachemxnet"><svg class="svg-icon"><use xlink:href="/versions/1.9.1/assets/minima-social-icons.svg#youtube"></use></svg> <span class="username">apachemxnet</span></a></li></ul>
</div>
<div class="col-4 footer-text">
<p>A flexible and efficient library for deep learning.</p>
</div>
</div>
</div>
</footer>
<footer class="site-footer2">
<div class="wrapper">
<div class="row">
<div class="col-3">
<img src="/versions/1.9.1/assets/img/asf_logo.svg" class="footer-logo col-2">
</div>
<div class="footer-bottom-warning col-9">
</p><p>"Copyright © 2017-2022, The Apache Software Foundation. Licensed under the Apache License, Version 2.0. Apache MXNet, MXNet, Apache, the Apache
feather, and the Apache MXNet project logo are either registered trademarks or trademarks of the
Apache Software Foundation."</p>
</div>
</div>
</div>
</footer>
</body>
</html>