chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
---
|
||||
title: 'Getting Started'
|
||||
permalink: /getting-started/
|
||||
excerpt: 'First steps with DeepSpeed'
|
||||
tags: getting-started
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
* Installing is as simple as `pip install deepspeed`, [see more details](/tutorials/advanced-install/).
|
||||
* To get started with DeepSpeed on AzureML, please see the [AzureML Examples GitHub](https://github.com/Azure/azureml-examples/tree/main/cli/jobs/deepspeed)
|
||||
* DeepSpeed has direct integrations with [HuggingFace Transformers](https://github.com/huggingface/transformers) and [PyTorch Lightning](https://github.com/PyTorchLightning/pytorch-lightning). HuggingFace Transformers users can now easily accelerate their models with DeepSpeed through a simple ``--deepspeed`` flag + config file [See more details](https://huggingface.co/docs/transformers/deepspeed). PyTorch Lightning provides easy access to DeepSpeed through the Lightning Trainer [See more details](https://pytorch-lightning.readthedocs.io/en/stable/advanced/multi_gpu.html?highlight=deepspeed#deepspeed).
|
||||
* DeepSpeed on AMD can be used via our [ROCm images](https://hub.docker.com/r/deepspeed/rocm501/tags), e.g., `docker pull deepspeed/rocm501:ds060_pytorch110`.
|
||||
* DeepSpeed also supports Intel Xeon CPU, Intel Data Center Max Series XPU, Intel Gaudi HPU, Huawei Ascend NPU etc, please refer to the [accelerator setup guide](/tutorials/accelerator-setup-guide/)
|
||||
|
||||
|
||||
|
||||
## Writing DeepSpeed Models
|
||||
|
||||
DeepSpeed model training is accomplished using the DeepSpeed engine. The engine
|
||||
can wrap any arbitrary model of type `torch.nn.module` and has a minimal set of APIs
|
||||
for training and checkpointing the model. Please see the tutorials for detailed
|
||||
examples.
|
||||
|
||||
To initialize the DeepSpeed engine:
|
||||
|
||||
```python
|
||||
model_engine, optimizer, _, _ = deepspeed.initialize(args=cmd_args,
|
||||
model=model,
|
||||
model_parameters=params)
|
||||
```
|
||||
|
||||
`deepspeed.initialize` ensures that all of the necessary setup required for
|
||||
distributed data parallel or mixed precision training are done
|
||||
appropriately under the hood. In addition to wrapping the model, DeepSpeed can
|
||||
construct and manage the training optimizer, data loader, and the learning rate
|
||||
scheduler based on the parameters passed to `deepspeed.initialize` and the
|
||||
DeepSpeed [configuration file](#deepspeed-configuration). Note that DeepSpeed automatically executes the learning rate schedule at every training step.
|
||||
|
||||
If you already have a distributed environment setup, you'd need to replace:
|
||||
|
||||
```python
|
||||
torch.distributed.init_process_group(...)
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```python
|
||||
deepspeed.init_distributed()
|
||||
```
|
||||
|
||||
The default is to use the NCCL backend, which DeepSpeed has been thoroughly tested with, but you can also [override the default](https://deepspeed.readthedocs.io/en/latest/initialize.html#distributed-initialization).
|
||||
|
||||
But if you don't need the distributed environment setup until after `deepspeed.initialize()` you don't have to use this function, as DeepSpeed will automatically initialize the distributed environment during its `initialize`. Regardless, you will need to remove `torch.distributed.init_process_group` if you already had it in place.
|
||||
|
||||
### Training
|
||||
|
||||
Once the DeepSpeed engine has been initialized, it can be used to train the
|
||||
model using three simple APIs for forward propagation (callable object), backward
|
||||
propagation (`backward`), and weight updates (`step`).
|
||||
|
||||
```python
|
||||
for step, batch in enumerate(data_loader):
|
||||
#forward() method
|
||||
loss = model_engine(batch)
|
||||
|
||||
#runs backpropagation
|
||||
model_engine.backward(loss)
|
||||
|
||||
#weight update
|
||||
model_engine.step()
|
||||
```
|
||||
|
||||
Under the hood, DeepSpeed automatically performs the necessary operations
|
||||
required for distributed data parallel training, in mixed precision, with a
|
||||
pre-defined learning rate scheduler:
|
||||
|
||||
- **Gradient Averaging**: in distributed data parallel training, `backward`
|
||||
ensures that gradients are averaged across data parallel processes after
|
||||
training on an `train_batch_size`.
|
||||
|
||||
- **Loss Scaling**: in FP16/mixed precision training, the DeepSpeed
|
||||
engine automatically handles scaling the loss to avoid precision loss in the
|
||||
gradients.
|
||||
|
||||
- **Learning Rate Scheduler**: when using a DeepSpeed's learning rate scheduler (specified in the `ds_config.json` file), DeepSpeed calls the `step()` method of the scheduler at every training step (when `model_engine.step()` is executed). When not using DeepSpeed's learning rate scheduler:
|
||||
- if the schedule is supposed to execute at every training step, then the user can pass the scheduler to `deepspeed.initialize` when initializing the DeepSpeed engine and let DeepSpeed manage it for update or save/restore.
|
||||
- if the schedule is supposed to execute at any other interval (e.g., training epochs), then the user should NOT pass the scheduler to DeepSpeed during initialization and must manage it explicitly.
|
||||
|
||||
### Model Checkpointing
|
||||
|
||||
Saving and loading the training state is handled via the `save_checkpoint` and
|
||||
`load_checkpoint` API in DeepSpeed which takes two arguments to uniquely
|
||||
identify a checkpoint:
|
||||
|
||||
- `ckpt_dir`: the directory where checkpoints will be saved.
|
||||
- `ckpt_id`: an identifier that uniquely identifies a checkpoint in the directory.
|
||||
In the following code snippet, we use the loss value as the checkpoint identifier.
|
||||
|
||||
```python
|
||||
#load checkpoint
|
||||
_, client_sd = model_engine.load_checkpoint(args.load_dir, args.ckpt_id)
|
||||
step = client_sd['step']
|
||||
|
||||
#advance data loader to ckpt step
|
||||
dataloader_to_step(data_loader, step + 1)
|
||||
|
||||
for step, batch in enumerate(data_loader):
|
||||
|
||||
#forward() method
|
||||
loss = model_engine(batch)
|
||||
|
||||
#runs backpropagation
|
||||
model_engine.backward(loss)
|
||||
|
||||
#weight update
|
||||
model_engine.step()
|
||||
|
||||
#save checkpoint
|
||||
if step % args.save_interval:
|
||||
client_sd['step'] = step
|
||||
ckpt_id = loss.item()
|
||||
model_engine.save_checkpoint(args.save_dir, ckpt_id, client_sd = client_sd)
|
||||
```
|
||||
|
||||
DeepSpeed can automatically save and restore the model, optimizer, and the
|
||||
learning rate scheduler states while hiding away these details from the user.
|
||||
However, the user may want to save additional data that are
|
||||
unique to a given model training. To support these items, `save_checkpoint`
|
||||
accepts a client state dictionary `client_sd` for saving. These items can be
|
||||
retrieved from `load_checkpoint` as a return argument. In the example above,
|
||||
the `step` value is stored as part of the `client_sd`.
|
||||
|
||||
**Important**: all processes must call this method and not just the process with rank 0. It is because
|
||||
each process needs to save its master weights and scheduler+optimizer states. This method will hang
|
||||
waiting to synchronize with other processes if it's called just for the process with rank 0.
|
||||
{: .notice--info}
|
||||
|
||||
## DeepSpeed Configuration
|
||||
|
||||
DeepSpeed features can be enabled, disabled, or configured using a config JSON
|
||||
file that should be specified as `args.deepspeed_config`. A sample config file
|
||||
is shown below. For a full set of features see [ API
|
||||
doc](/docs/config-json/).
|
||||
|
||||
```json
|
||||
{
|
||||
"train_batch_size": 8,
|
||||
"gradient_accumulation_steps": 1,
|
||||
"optimizer": {
|
||||
"type": "Adam",
|
||||
"params": {
|
||||
"lr": 0.00015
|
||||
}
|
||||
},
|
||||
"fp16": {
|
||||
"enabled": true
|
||||
},
|
||||
"zero_optimization": true
|
||||
}
|
||||
```
|
||||
|
||||
# Launching DeepSpeed Training
|
||||
|
||||
DeepSpeed installs the entry point `deepspeed` to launch distributed training.
|
||||
We illustrate an example usage of DeepSpeed with the following assumptions:
|
||||
|
||||
1. You have already integrated DeepSpeed into your model
|
||||
2. `client_entry.py` is the entry script for your model
|
||||
3. `client args` is the `argparse` command line arguments
|
||||
4. `ds_config.json` is the configuration file for DeepSpeed
|
||||
|
||||
## Resource Configuration (multi-node)
|
||||
|
||||
DeepSpeed configures multi-node compute resources with hostfiles that are compatible with
|
||||
[OpenMPI](https://www.open-mpi.org/) and [Horovod](https://github.com/horovod/horovod).
|
||||
A hostfile is a list of _hostnames_ (or SSH aliases), which are machines accessible via passwordless
|
||||
SSH, and _slot counts_, which specify the number of GPUs available on the system. For
|
||||
example,
|
||||
|
||||
```
|
||||
worker-1 slots=4
|
||||
worker-2 slots=4
|
||||
```
|
||||
|
||||
specifies that two machines named _worker-1_ and _worker-2_ each have four GPUs to use
|
||||
for training.
|
||||
|
||||
Hostfiles are specified with the `--hostfile` command line option. If no hostfile is
|
||||
specified, DeepSpeed searches for `/job/hostfile`. If no hostfile is specified or found,
|
||||
DeepSpeed queries the number of GPUs on the local machine to discover the number of local
|
||||
slots available.
|
||||
|
||||
The following command launches a PyTorch training job across all available nodes and GPUs
|
||||
specified in `myhostfile`:
|
||||
|
||||
```bash
|
||||
deepspeed --hostfile=myhostfile <client_entry.py> <client args> \
|
||||
--deepspeed --deepspeed_config ds_config.json
|
||||
```
|
||||
|
||||
Alternatively, DeepSpeed allows you to restrict distributed training of your model to a
|
||||
subset of the available nodes and GPUs. This feature is enabled through two command line
|
||||
arguments: `--num_nodes` and `--num_gpus`. For example, distributed training can be
|
||||
restricted to use only two nodes with the following command:
|
||||
|
||||
```bash
|
||||
deepspeed --num_nodes=2 \
|
||||
<client_entry.py> <client args> \
|
||||
--deepspeed --deepspeed_config ds_config.json
|
||||
```
|
||||
|
||||
You can instead include or exclude specific resources using the `--include` and
|
||||
`--exclude` flags. For example, to use all available resources **except** GPU 0 on node
|
||||
_worker-2_ and GPUs 0 and 1 on _worker-3_:
|
||||
|
||||
```bash
|
||||
deepspeed --exclude="worker-2:0@worker-3:0,1" \
|
||||
<client_entry.py> <client args> \
|
||||
--deepspeed --deepspeed_config ds_config.json
|
||||
```
|
||||
|
||||
Similarly, you can use **only** GPUs 0 and 1 on _worker-2_:
|
||||
|
||||
```bash
|
||||
deepspeed --include="worker-2:0,1" \
|
||||
<client_entry.py> <client args> \
|
||||
--deepspeed --deepspeed_config ds_config.json
|
||||
```
|
||||
### Launching without passwordless SSH
|
||||
|
||||
DeepSpeed now supports launching training jobs without the need for passwordless SSH. This mode is
|
||||
particularly useful in cloud environments such as Kubernetes, where flexible container orchestration
|
||||
is possible, and setting up a leader-worker architecture with passwordless SSH adds unnecessary
|
||||
complexity.
|
||||
|
||||
To use this mode, you need to run the DeepSpeed command separately on all nodes. The command should
|
||||
be structured as follows:
|
||||
|
||||
```bash
|
||||
deepspeed --hostfile=myhostfile --no_ssh --node_rank=<n> \
|
||||
--master_addr=<addr> --master_port=<port> \
|
||||
<client_entry.py> <client args> \
|
||||
--deepspeed --deepspeed_config ds_config.json
|
||||
```
|
||||
|
||||
- `--hostfile=myhostfile`: Specifies the hostfile that contains information about the nodes and GPUs.
|
||||
- `--no_ssh`: Enables the no-SSH mode.
|
||||
- `--node_rank=<n>`: Specifies the rank of the node. This should be a unique integer from 0 to n - 1.
|
||||
- `--master_addr=<addr>`: The address of the leader node (rank 0).
|
||||
- `--master_port=<port>`: The port of the leader node.
|
||||
|
||||
In this setup, the hostnames in the hostfile do not need to be reachable via passwordless SSH.
|
||||
However, the hostfile is still required for the launcher to collect information about the environment,
|
||||
such as the number of nodes and the number of GPUs per node.
|
||||
|
||||
Each node must be launched with a unique `node_rank`, and all nodes must be provided with the address
|
||||
and port of the leader node (rank 0). This mode causes the launcher to act similarly to the `torchrun`
|
||||
launcher, as described in the [PyTorch documentation](https://pytorch.org/docs/stable/elastic/run.html).
|
||||
|
||||
## Multi-Node Environment Variables
|
||||
|
||||
When training across multiple nodes we have found it useful to support
|
||||
propagating user-defined environment variables. By default DeepSpeed will
|
||||
propagate all NCCL and PYTHON related environment variables that are set. If
|
||||
you would like to propagate additional variables you can specify them in a
|
||||
dot-file named `.deepspeed_env` that contains a new-line separated list of
|
||||
`VAR=VAL` entries. The DeepSpeed launcher will look in the local path you are
|
||||
executing from and also in your home directory (`~/`). If you would like to
|
||||
override the default name of this file or path and name with your own, you
|
||||
can specify this with the environment variable, `DS_ENV_FILE`. This is
|
||||
mostly useful if you are launching multiple jobs that all require different
|
||||
variables.
|
||||
|
||||
As a concrete example, some clusters require special NCCL variables to set
|
||||
prior to training. The user can simply add these variables to a
|
||||
`.deepspeed_env` file in their home directory that looks like this:
|
||||
|
||||
```
|
||||
NCCL_IB_DISABLE=1
|
||||
NCCL_SOCKET_IFNAME=eth0
|
||||
```
|
||||
|
||||
DeepSpeed will then make sure that these environment variables are set when
|
||||
launching each process on every node across their training job.
|
||||
|
||||
### MPI and AzureML Compatibility
|
||||
|
||||
As described above, DeepSpeed provides its own parallel launcher to help launch
|
||||
multi-node/multi-gpu training jobs. If you prefer to launch your training job
|
||||
using MPI (e.g., mpirun), we provide support for this. It should be noted that
|
||||
DeepSpeed will still use the torch distributed NCCL backend and _not_ the MPI
|
||||
backend.
|
||||
|
||||
To launch your training job with mpirun + DeepSpeed or with AzureML (which uses
|
||||
mpirun as a launcher backend) you simply need to install the
|
||||
[mpi4py](https://pypi.org/project/mpi4py/) python package. DeepSpeed will use
|
||||
this to discover the MPI environment and pass the necessary state (e.g., world
|
||||
size, rank) to the torch distributed backend.
|
||||
|
||||
If you are using model parallelism, pipeline parallelism, or otherwise require
|
||||
torch.distributed calls before calling `deepspeed.initialize(..)` we provide
|
||||
the same MPI support with an additional DeepSpeed API call. Replace your initial
|
||||
`torch.distributed.init_process_group(..)` call with:
|
||||
|
||||
```python
|
||||
deepspeed.init_distributed()
|
||||
```
|
||||
|
||||
## Resource Configuration (single-node)
|
||||
|
||||
In the case that we are only running on a single node (with one or more GPUs)
|
||||
DeepSpeed _does not_ require a hostfile as described above. If a hostfile is
|
||||
not detected or passed in then DeepSpeed will query the number of GPUs on the
|
||||
local machine to discover the number of slots available. The `--include` and
|
||||
`--exclude` arguments work as normal, but the user should specify 'localhost'
|
||||
as the hostname.
|
||||
|
||||
Also note that `CUDA_VISIBLE_DEVICES` can be used with `deepspeed` to control
|
||||
which devices should be used on a single node. So either of these would work
|
||||
to launch just on devices 0 and 1 of the current node:
|
||||
|
||||
```bash
|
||||
deepspeed --include localhost:0,1 ...
|
||||
```
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=0,1 deepspeed ...
|
||||
```
|
||||
Reference in New Issue
Block a user