From 306e7ce63da5b331a559ce24f484c71ec870e625 Mon Sep 17 00:00:00 2001 From: Shaden Smith Date: Tue, 17 Mar 2020 17:20:49 -0700 Subject: [PATCH 1/7] added coming soon to posts --- docs/_config.yml | 3 ++- docs/_layouts/blog-home.html | 32 ++++++++++++++++++++++++ docs/_posts/2020-03-17-reduce-scatter.md | 2 +- docs/_posts/2020-03-17-zero-stage2.md | 2 +- docs/blog/index.html | 2 +- 5 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 docs/_layouts/blog-home.html diff --git a/docs/_config.yml b/docs/_config.yml index 53fc21f3798f..1e85e57f232e 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -37,10 +37,11 @@ defaults: values: layout: single author_profile: false - read_time: true + read_time: false comments: false share: true related: false + sneak_preview: false # _tutorials - scope: path: "" diff --git a/docs/_layouts/blog-home.html b/docs/_layouts/blog-home.html new file mode 100644 index 000000000000..93afa2ebe55d --- /dev/null +++ b/docs/_layouts/blog-home.html @@ -0,0 +1,32 @@ +--- +layout: archive +--- + +{{ content }} + + +{% if paginator %} + {% assign posts = paginator.posts %} +{% else %} + {% assign posts = site.posts %} +{% endif %} + + +

Features Coming Soon

+{% assign soon = posts | where: "sneak_preview", "true" %} + + +

{{ site.data.ui-text[site.locale].recent_posts | default: "Recent Posts" }}

+{% assign news = posts | where: "sneak_preview", "false" %} +{% for post in news %} + {% include archive-single.html %} +{% endfor %} + +{% include paginator.html %} diff --git a/docs/_posts/2020-03-17-reduce-scatter.md b/docs/_posts/2020-03-17-reduce-scatter.md index b7e9b8fe176d..5bc423c7e2eb 100644 --- a/docs/_posts/2020-03-17-reduce-scatter.md +++ b/docs/_posts/2020-03-17-reduce-scatter.md @@ -1,6 +1,6 @@ --- title: "ZeRO stage 1 with reduced communication" -date: 2020-03-13 +sneak_preview: true excerpt: "Partition-aware ZeRO with up to 2x reduction in communication time!" --- diff --git a/docs/_posts/2020-03-17-zero-stage2.md b/docs/_posts/2020-03-17-zero-stage2.md index 682dea687baf..9137487eac73 100644 --- a/docs/_posts/2020-03-17-zero-stage2.md +++ b/docs/_posts/2020-03-17-zero-stage2.md @@ -1,6 +1,6 @@ --- title: "ZeRO stage 2" -date: 2020-03-13 +sneak_preview: true excerpt: "Reduce memory footprint to enable training 10B models without model parallelism!" --- diff --git a/docs/blog/index.html b/docs/blog/index.html index e4d427d215f4..7bf9c9a1714c 100644 --- a/docs/blog/index.html +++ b/docs/blog/index.html @@ -1,3 +1,3 @@ --- -layout: home +layout: blog-home --- From 0065cd318c2bf34191cd57e2365c3db7547fb550 Mon Sep 17 00:00:00 2001 From: Shaden Smith Date: Tue, 17 Mar 2020 17:57:52 -0700 Subject: [PATCH 2/7] website tweaks --- docs/_data/navigation.yml | 10 +- .../{blog-home.html => news-home.html} | 7 +- docs/_posts/2020-03-17-reduce-scatter.md | 3 +- docs/_posts/2020-03-17-zero-stage2.md | 4 +- docs/_tutorials/getting-started.md | 2 +- docs/assets/css/main.scss | 49 ++++ docs/blog/index.html | 3 - docs/features.md | 1 + docs/index.md | 243 ------------------ docs/news/index.html | 3 + 10 files changed, 63 insertions(+), 262 deletions(-) rename docs/_layouts/{blog-home.html => news-home.html} (66%) create mode 100644 docs/assets/css/main.scss delete mode 100644 docs/blog/index.html create mode 100644 docs/news/index.html diff --git a/docs/_data/navigation.yml b/docs/_data/navigation.yml index e50c552240d4..1b48a31279b8 100644 --- a/docs/_data/navigation.yml +++ b/docs/_data/navigation.yml @@ -1,17 +1,17 @@ main: - title: "Getting Started" url: /getting-started/ - - title: "Blog" - url: /blog/ + - title: "News" + url: /news/ - title: "Tutorials" url: /tutorials/ - title: "Documentation" - url: https://ghpages-test.readthedocs.io/ + url: https://deepspeed.readthedocs.io/ - title: "GitHub" url: https://github.com/microsoft/DeepSpeed lnav: - - title: "This is a floating nav bar." + - title: "DeepSpeed Documentation" - title: "Getting Started" url: /getting-started/ children: @@ -19,3 +19,5 @@ lnav: url: /getting-started/#installation - title: "Configuration" url: /getting-started/#deepspeed-configuration + - title: "DeepSpeed Features" + url: /features/ diff --git a/docs/_layouts/blog-home.html b/docs/_layouts/news-home.html similarity index 66% rename from docs/_layouts/blog-home.html rename to docs/_layouts/news-home.html index 93afa2ebe55d..3ac509f06ef7 100644 --- a/docs/_layouts/blog-home.html +++ b/docs/_layouts/news-home.html @@ -14,14 +14,9 @@

Features Coming Soon

{% assign soon = posts | where: "sneak_preview", "true" %} -

{{ site.data.ui-text[site.locale].recent_posts | default: "Recent Posts" }}

{% assign news = posts | where: "sneak_preview", "false" %} diff --git a/docs/_posts/2020-03-17-reduce-scatter.md b/docs/_posts/2020-03-17-reduce-scatter.md index 5bc423c7e2eb..1753a22e3aa7 100644 --- a/docs/_posts/2020-03-17-reduce-scatter.md +++ b/docs/_posts/2020-03-17-reduce-scatter.md @@ -4,9 +4,8 @@ sneak_preview: true excerpt: "Partition-aware ZeRO with up to 2x reduction in communication time!" --- -# ZeRO stage 1 with reduced communication * Partition-aware approach instead of initial implementation that used a global collective (all-reduce) * Total communication volume reduction 1.5x -> 1x of data parallelism * Up to 2x reduction in communication time compared to all-reduce -# Further updates coming soon! +## Further updates coming soon! diff --git a/docs/_posts/2020-03-17-zero-stage2.md b/docs/_posts/2020-03-17-zero-stage2.md index 9137487eac73..18a1974cd956 100644 --- a/docs/_posts/2020-03-17-zero-stage2.md +++ b/docs/_posts/2020-03-17-zero-stage2.md @@ -3,10 +3,8 @@ title: "ZeRO stage 2" sneak_preview: true excerpt: "Reduce memory footprint to enable training 10B models without model parallelism!" --- - -# Zero Stage 2 * Reduce memory footprint of gradients * Train larger models: e.g., 10B parameters on 32GPUs without model parallelism * Train larger batch sizes -# Further updates coming soon! +## Further updates coming soon! diff --git a/docs/_tutorials/getting-started.md b/docs/_tutorials/getting-started.md index 26875f50a726..c6be8a05638d 100644 --- a/docs/_tutorials/getting-started.md +++ b/docs/_tutorials/getting-started.md @@ -213,7 +213,7 @@ deepspeed --include="worker-2:0,1" \ \ --deepspeed --deepspeed_config ds_config.json ``` - +This is a floating nav bar. ### MPI 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 diff --git a/docs/assets/css/main.scss b/docs/assets/css/main.scss new file mode 100644 index 000000000000..bcbc1b94c901 --- /dev/null +++ b/docs/assets/css/main.scss @@ -0,0 +1,49 @@ +--- +# Only the main Sass file needs front matter (the dashes are enough) +--- + +@charset "utf-8"; + +@import "minimal-mistakes/skins/{{ site.minimal_mistakes_skin | default: 'default' }}"; // skin +@import "minimal-mistakes"; // main partials + +// +// DeepSpeed customizations +// + + +.site-title { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-item-align: center; + align-self: center; + font-weight: bold; + font-size: $type-size-2; // DeepSpeed: increase size +} + + +.toc { + font-family: $sans-serif-narrow; + color: $gray; + background-color: $background-color; + border: 1px solid $border-color; + border-radius: $border-radius; + -webkit-box-shadow: $box-shadow; + box-shadow: $box-shadow; + position: fixed; + + .nav__title { + color: #fff; + font-size: $type-size-6; + background: $primary-color; + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; + } + + // Scrollspy marks toc items as .active when they are in focus + .active a { + @include yiq-contrasted($active-color); + } +} + diff --git a/docs/blog/index.html b/docs/blog/index.html deleted file mode 100644 index 7bf9c9a1714c..000000000000 --- a/docs/blog/index.html +++ /dev/null @@ -1,3 +0,0 @@ ---- -layout: blog-home ---- diff --git a/docs/features.md b/docs/features.md index e3f1d0beb4ff..f28efdae1062 100644 --- a/docs/features.md +++ b/docs/features.md @@ -1,6 +1,7 @@ --- title: "Feature Overview" layout: single +permalink: /features/ toc: true toc_label: "Contents" --- diff --git a/docs/index.md b/docs/index.md index 9412da692981..21df19de9ccb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -56,8 +56,6 @@ optimizations on advanced hyperparameter tuning and optimizers. For example: | 256 V100 GPUs | NVIDIA | 3.9 | | 256 V100 GPUs | DeepSpeed | **3.7** | - - *BERT Tutorial*: Coming Soon * DeepSpeed trains GPT2 (1.5 billion parameters) 3.75x faster than state-of-art, NVIDIA @@ -157,247 +155,6 @@ overview](features) for descriptions and usage. * [Performance Analysis and Debugging](features.md#performance-analysis-and-debugging) -# Getting Started - - -## Installation - -* Please see our [Azure tutorial](docs/azure.md) to get started with DeepSpeed on Azure! -* If you're not on Azure, we recommend using our docker image via `docker pull deepspeed/deepspeed:latest` which contains a pre-installed version of DeepSpeed and all the necessary dependencies. -* If you want to install DeepSpeed manually, we provide an install script [install.sh](install.sh) to help install on a local machine or across an entire cluster. - -## 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.inialize` 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.initialze` and the -DeepSpeed [configuration file](#deepspeed-configuration). - - -### Training - -Once the DeepSpeed engine has been initialized, it can be used to train the -model using three simple APIs for forward propagation (`()`), 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 schedule: - -* **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 Schedule**: if using DeepSpeed's learning rate - schedule, then DeepSpeed automatically handles any updates to the learning - rate when `step` is executed. - - - -### 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 other data in addition to these 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`. - - -## 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 [core API -doc](https://microsoft.github.io/DeepSpeed/docs/htmlfiles/api/full/index.html). - -```json -{ - "train_batch_size": 8, - "gradient_accumulation_steps": 1, - "optimizer": { - "type": "Adam", - "params": { - "lr": 0.00015 - } - }, - "fp16": { - "enabled": true - }, - "zero_optimization": true -} -``` - -## 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 (`~/`). - -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. - -# 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 \ - --deepspeed --deepspeed_config ds_config.json --hostfile=myhostfile -``` - -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 \ - \ - --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" \ - \ - --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" \ - \ - --deepspeed --deepspeed_config ds_config.json -``` - -### MPI 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 you simply pass us -an additional flag `--deepspeed_mpi`. DeepSpeed will then use -[mpi4py](https://pypi.org/project/mpi4py/) to discover the MPI environment (e.g., -rank, world size) and properly initialize torch distributed for training. In this -case you will explicitly invoke `python` to launch your model script instead of using -the `deepspeed` launcher, here is an example: -```bash -mpirun python \ - \ - --deepspeed_mpi --deepspeed --deepspeed_config ds_config.json -``` - -If you want to use this feature of DeepSpeed, please ensure that mpi4py is -installed via `pip install mpi4py`. - -## 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. - # Further Reading diff --git a/docs/news/index.html b/docs/news/index.html new file mode 100644 index 000000000000..95e7974b5050 --- /dev/null +++ b/docs/news/index.html @@ -0,0 +1,3 @@ +--- +layout: news-home +--- From 55e8699ea9c53c33d1db63a610839e91ad264a6e Mon Sep 17 00:00:00 2001 From: Shaden Smith Date: Tue, 17 Mar 2020 18:14:25 -0700 Subject: [PATCH 3/7] Add what's new section to main page --- docs/index.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/index.md b/docs/index.md index 21df19de9ccb..a7a7e0e428b4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,6 +18,16 @@ a language model (LM) with over 17B parameters called [Turing-NLG](https://www.microsoft.com/en-us/research/blog/turing-nlg-a-17-billion-parameter-language-model-by-microsoft), establishing a new SOTA in the LM category. +# What's New? +{% assign news = site.posts | where: "sneak_preview", "false" %} +{% for post in news limit:5 %} + {% if post.link %} + * [{{ post.title }}]({{ post.link }}) + {% else %} + * [{{ post.title }}]({{ post.url }}) + {% endif %} +{% endfor %} + # Why DeepSpeed? Training advanced deep learning models is challenging. Beyond model design, From 30f4b0b78cbcbf98d1f3201c049f622db3750aa7 Mon Sep 17 00:00:00 2001 From: Shaden Smith Date: Tue, 17 Mar 2020 18:21:33 -0700 Subject: [PATCH 4/7] formatter --- docs/assets/css/main.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/assets/css/main.scss b/docs/assets/css/main.scss index bcbc1b94c901..c2583467e4b7 100644 --- a/docs/assets/css/main.scss +++ b/docs/assets/css/main.scss @@ -46,4 +46,3 @@ @include yiq-contrasted($active-color); } } - From 341df3eaa883f3e99fee5952ddae07c8b5bc9a56 Mon Sep 17 00:00:00 2001 From: Shaden Smith Date: Wed, 18 Mar 2020 00:01:49 -0700 Subject: [PATCH 5/7] lots of website tweaks --- README.md | 48 +- azure/README.md | 2 +- docs/_config.yml | 19 +- docs/_data/navigation.yml | 18 +- docs/_pages/config_json.md | 193 ++++++++ docs/{ => _pages}/features.md | 51 +-- docs/_tutorials/1Cycle.md | 144 ++++++ docs/_tutorials/azure.md | 129 ++++++ docs/_tutorials/getting-started.md | 7 +- docs/_tutorials/lrrt.md | 148 ++++++ docs/_tutorials/megatron.md | 421 ++++++++++++++++++ docs/assets/css/main.scss | 2 +- docs/assets/images/1cycle_lr.png | Bin 0 -> 25115 bytes docs/assets/images/loss_and_lr.png | Bin 0 -> 41640 bytes docs/assets/images/lr_schedule.png | Bin 0 -> 11729 bytes .../assets/images/megatron-gpt2-perf-test.png | Bin 0 -> 42069 bytes docs/assets/images/model_convergence.png | Bin 0 -> 12691 bytes docs/contributing.md | 74 +++ docs/index.md | 29 +- 19 files changed, 1180 insertions(+), 105 deletions(-) create mode 100644 docs/_pages/config_json.md rename docs/{ => _pages}/features.md (75%) create mode 100644 docs/_tutorials/1Cycle.md create mode 100644 docs/_tutorials/azure.md create mode 100644 docs/_tutorials/lrrt.md create mode 100644 docs/_tutorials/megatron.md create mode 100644 docs/assets/images/1cycle_lr.png create mode 100644 docs/assets/images/loss_and_lr.png create mode 100644 docs/assets/images/lr_schedule.png create mode 100644 docs/assets/images/megatron-gpt2-perf-test.png create mode 100644 docs/assets/images/model_convergence.png create mode 100644 docs/contributing.md diff --git a/README.md b/README.md index b1ec9ab394a2..655582ead0b1 100755 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ optimizations on advanced hyperparameter tuning and optimizers. For example: * DeepSpeed trains GPT2 (1.5 billion parameters) 3.75x faster than state-of-art, NVIDIA Megatron on Azure GPUs. - *Read more*: [GPT tutorial](./docs/tutorials/MegatronGPT2Tutorial.md) + *Read more*: [GPT tutorial](https://www.deepspeed.ai/tutorials/megatron.md) @@ -106,10 +106,10 @@ combination. ZeRO boosts the scaling capability and efficiency further. significant performance gains compared to using model parallelism alone. *Read more*: [technical report](https://arxiv.org/abs/1910.02054), - and [GPT tutorial](./docs/tutorials/MegatronGPT2Tutorial.md). + and [GPT tutorial](https://www.deepspeed.ai/tutorials/megatron/). -![DeepSpeed-vs-Megatron](./docs/figures/DeepSpeed-vs-Megatron.png) +![DeepSpeed-vs-Megatron](./docs/assets/images/DeepSpeed-vs-Megatron.png)

The figure depicts system throughput improvements of DeepSpeed (combining ZeRO-powered data parallelism with model parallelism of NVIDIA Megatron-LM) over using Megatron-LM alone.

@@ -121,7 +121,7 @@ optimizers such as [LAMB](https://arxiv.org/abs/1904.00962). These improve the effectiveness of model training and reduce the number of samples required to convergence to desired accuracy. -*Read more*: [Tuning tutorial](./docs/tutorials/1Cycle.md), +*Read more*: [Tuning tutorial](https://www.deepspeed.ai/tutorials/1Cycle/), + ### Constant Buffer Optimization (CBO) CBO enables high network and memory throughput while restricting memory usage to a constant size. For memory- and network-bound operations such as normalization or @@ -131,18 +102,18 @@ The DeepSpeed core API consists of just a handful of methods: DeepSpeed supports all the features described in this document, via the use of these API, along with a `deepspeed_config` JSON file for enabling and disabling the features. -Please see the [core API doc](https://microsoft.github.io/DeepSpeed/docs/htmlfiles/api/full/index.html) for more details. +Please see the [core API doc](https://deepspeed.readthedocs.io/) for more details. ### Gradient Clipping DeepSpeed handles gradient clipping under the hood based on the max gradient norm specified by the user. -Please see the [core API doc](https://microsoft.github.io/DeepSpeed/docs/htmlfiles/api/full/index.html) for more details. +Please see the [core API doc](https://deepspeed.readthedocs.io/) for more details. ### Automatic loss scaling with mixed precision DeepSpeed internally handles loss scaling for mixed precision training. The parameters for loss scaling can be specified in the `deepspeed_config` JSON file. -Please see the [core API doc](https://microsoft.github.io/DeepSpeed/docs/htmlfiles/api/full/index.html) for more details. +Please see the [core API doc](https://deepspeed.readthedocs.io/) for more details. ## Training Optimizers @@ -176,19 +147,19 @@ more details see [ZeRO paper](https://arxiv.org/abs/1910.02054) . DeepSpeed can simplify checkpointing for you regardless of whether you are using data parallel training, model parallel training, mixed-precision training, a mix of these three, or using the zero optimizer to enable larger model sizes. -Please see the [Getting Started](../README.md#getting-started) guide +Please see the [Getting Started](/getting-started/) guide and the -[core API doc](https://microsoft.github.io/DeepSpeed/docs/htmlfiles/api/full/index.html) for more details. +Please see the [core API doc](https://deepspeed.readthedocs.io/) for more details. ## Advanced parameter search DeepSpeed supports multiple Learning Rate Schedules to enable faster convergence for large batch scaling. ### Learning Rate Range Test -Please refer to the [Learning Rate Range Test](tutorials/lrrt.md) tutorial. +Please refer to the [Learning Rate Range Test](/tutorials/lrrt/) tutorial. ### 1Cycle Learning Rate Schedule -Please refer to the [1Cycle Learning Rate Schedule](tutorials/1Cycle.md) tutorial. +Please refer to the [1Cycle Learning Rate Schedule](/tutorials/1Cycle/) tutorial. ## Simplified Data Loader @@ -200,7 +171,7 @@ can automatically handle batch creation appropriately. For performance debugging, DeepSpeed can give you a detailed breakdown of the time spent in different parts of the training with by simply enabling it in the `deepspeed_config` file. -Please see the [core API doc](https://microsoft.github.io/DeepSpeed/docs/htmlfiles/api/full/index.html) for more details. +Please see the [core API doc](https://deepspeed.readthedocs.io/) for more details. ```json { "wall_clock_breakdown": true diff --git a/docs/_tutorials/1Cycle.md b/docs/_tutorials/1Cycle.md new file mode 100644 index 000000000000..0cb8a45f31f0 --- /dev/null +++ b/docs/_tutorials/1Cycle.md @@ -0,0 +1,144 @@ +--- +title: "1-Cycle Schedule" +--- + +This tutorial shows how to implement 1Cycle schedules for learning rate and +momentum in PyTorch. + +## 1-Cycle Schedule +Recent research has demonstrated that the slow convergence problems of large +batch size training can be addressed by tuning critical hyperparameters such +as learning rate and momentum, during training using cyclic and decay +schedules. In DeepSpeed, we have implemented a state-of-the-art schedule called +[1-Cycle](https://arxiv.org/abs/1803.09820) to help data scientists +effectively use larger batch sizes to train their models in PyTorch. + +## Prerequisites + +To use 1-cycle schedule for model training, you should satisfy these two requirements: + +1. Integrate DeepSpeed into your training script using the [Getting +Started](/getting-started/) guide. +2. Add the parameters to configure a 1-Cycle schedule to the parameters of your +model. We will define the 1-Cycle parameters below. + +## Overview +The 1-cycle schedule operates in two phases, a cycle phase and a decay phase, +which span one iteration over the training data. For concreteness, we will +review how 1-cycle schedule of learning rate works. In the cycle phase, +the learning rate oscillates between a minimum value and a maximum value over a +number of training steps. In the decay phase, the learning rate decays starting +from the minimum value of the cycle phase. An example of 1-cycle learning rate +schedule during model training is illustrated below. + +![1cycle_lr](/assets/images/1cycle_lr.png) + +### 1-Cycle Parameters + +The 1-Cycle schedule is defined by a number of parameters which allow users +explore different configurations. The literature recommends concurrent tuning +of learning rate and momentum because they are correlated hyperparameters. We +have leveraged this recommendation to reduce configuration burden by organizing +the 1-cycle parameters into two groups to: + +1. Global parameters for configuring the cycle and decay phase +2. Local parameters for configuring learning rate and momentum + +The global parameters for configuring the 1-cycle phases are: + +1. `cycle_first_step_size`: The count of training steps to complete first step of cycle phase +2. `cycle_first_stair_count`: The count of updates (or stairs) in first step of cycle phase +3. `cycle_second_step_size`: The count of training steps to complete second step of cycle phase +4. `cycle_second_stair_count`: The count of updates (or stairs) in the second step of cycle phase +5. `post_cycle_decay_step_size`: The interval, in training steps, to decay hyperparameter in decay phase + +The local parameters for the hyperparameters are: + +**Learning rate**: + +1. `cycle_min_lr`: minimum learning rate in cycle phase +2. `cycle_max_lr`: maximum learning rate in cycle phase +3. `decay_lr_rate`: decay rate for learning rate in decay phase + +Although appropriate values `cycle_min_lr` and `cycle_max_lr` values can be +selected based on experience or expertise, we recommend using [learning rate +range test](/tutorials/lrrt/) feature of DeepSpeed to configure them. + +**Momentum** +1. `cycle_min_mom`: minimum momentum in cycle phase +2. `cycle_max_mom`: maximum momentum in cycle phase +3. `decay_mom_rate`: decay rate for momentum in decay phase + +## Required Model Configuration Changes + +To illustrate the required model configuration changes to use 1-Cycle schedule +in model training, we will use a schedule with the following properties: + +1. A symmetric cycle phase, where each half of the cycle spans the same number +of training steps. For this example, it will take 1000 training steps for the +learning rate to increase from 0.0001 to 0.0010 (10X scale), and then to +decrease back to 0.0001. The momentum will correspondingly cycle between 0.85 +and 0.99 in similar number of steps. +2. A decay phase, where learning rate decays by 0.001 every 1000 steps, while +momentum is not decayed. + +Note that these parameters are processed by DeepSpeed as session parameters, +and so should be added to the appropriate section of the model configuration. + +### **PyTorch model** + +PyTorch versions 1.0.1 and newer provide a feature for implementing schedulers +for hyper-parameters, called [learning rate + schedulers](https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html). + We have implemented 1-Cycle schedule using this feature. You will add a + scheduler entry of type **"OneCycle"** as illustrated below. + +```json +"scheduler": { + "type": "OneCycle", + "params": { + "cycle_first_step_size": 1000, + "cycle_first_stair_count": 500, + "cycle_second_step_size": 1000, + "cycle_second_stair_count": 500, + "decay_step_size": 1000, + "cycle_min_lr": 0.0001, + "cycle_max_lr": 0.0010, + "decay_lr_rate": 0.001, + "cycle_min_mom": 0.85, + "cycle_max_mom": 0.99, + "decay_mom_rate": 0.0 + } +}, +``` + +## Batch Scaling Example + +As example of how 1-Cycle schedule can enable effective batch scaling, we +briefly share our experience with an internal model in Microsoft. In this case, +the model was well-tuned for fast convergence (in data samples) on a single +GPU, but was converging slowly to target performance (AUC) when training on 8 +GPUs (8X batch size). The plot below shows model convergence with 8 GPUs for +these learning rate schedules: + +1. **Fixed**: using an optimal fixed learning rate for 1-GPU training. +2. **LinearScale**: using a fixed learning rate that is 8X of **Fixed**. +3. **1Cycle**: using 1-Cycle schedule. + +![model_convergence](/assets/images/model_convergence.png) + +With **1Cycle**, the model converges faster than the other schedules to the +target AUC . In fact, **1Cycle** converges as fast as the optimal 1-GPU +training (not shown). For **Fixed**, convergence is about 5X slower (needs 5X +more data samples). With **LinearScale**, the model diverges because the +learning rate is too high. The plot below illustrates the schedules by +reporting the learning rate values during 8-GPU training. + +![lr_schedule](/assets/images/lr_schedule.png) + +We see that the learning rate for **1Cycle** is always larger than **Fixed** +and is briefly larger than **LinearScale** to achieve faster convergence. Also +**1Cycle** lowers the learning rate later during training to avoid model +divergence, in contrast to **LinearScale**. In summary, by configuring an +appropriate 1-Cycle schedule we were able to effective scale the training batch +size for this model by 8X without loss of convergence speed. diff --git a/docs/_tutorials/azure.md b/docs/_tutorials/azure.md new file mode 100644 index 000000000000..f37d8f4a6abe --- /dev/null +++ b/docs/_tutorials/azure.md @@ -0,0 +1,129 @@ +# DeepSpeed with Azure + +This tutorial will help you get started running DeepSpeed on [Azure virtual +machines](https://azure.microsoft.com/en-us/services/virtual-machines/). +Looking forward, we will be integrating these techniques and additional enhancements +into the [Azure ML](https://azure.microsoft.com/en-us/services/machine-learning/) platform to +benefit all your large model training jobs. + +If you don't already have an Azure account please see more details here: [https://azure.microsoft.com/](https://azure.microsoft.com/). + +To help with launching Azure instances we suggest using the [Azure +CLI](https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest). We have created +several helper scripts to get you quickly started using DeepSpeed with Azure. + * Install Azure CLI on your local box: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli + * Alternatively you can use the Azure in-browser shell: https://shell.azure.com/ + +## Create an SSH key +Generate an SSH key that will be used across this tutorial to SSH into your VMs and +between Docker containers. `ssh-keygen` is the recommended way of doing this. Our scripts +assume your key is located inside the same directory as the Azure scripts. + +## Azure Config JSON +Our helper scripts depend on the following a configuration JSON for deployment +and setup. We have provided a simple example JSON in `azure_config.json` that +sets up a basic environment with two VMs. This config uses the NV6_Promo +instance type which has one NVIDIA Tesla M60 GPU per VM. You can read more +details about the VM on the [Linux Virtual Machines +Pricing](https://azure.microsoft.com/en-us/pricing/details/virtual-machines/linux/) +page. + +See the example below: + ```json +{ + "num_vms": 2, + "location": "southcentralus", + "azure_sku": "Standard_NV6_Promo", + "ssh_private_key": "id_rsa", + "docker_ssh_port": 2222 +} +``` + +## Dependencies +The scripts in this tutorial require [jq](https://stedolan.github.io/jq/) to help with +parsing JSON from the command line. Also it is recommended to install +[pdsh](https://linux.die.net/man/1/pdsh) to help launch ssh connections in parallel. + +## Create Azure VMs +We first need to allocate the VMs. We provide a script +```bash +./create_vms.sh +``` +to create VMs with the Azure SKU in the region specified in `azure_config.json`. Feel +free to customize your JSON to your desired region/SKU. This step will take a few minutes +to complete while it sets up all of your VMs on Azure. + +## Setup VM environment to use DeepSpeed +Next, we need to configure the VM environment for DeepSpeed. We provide a script +```bash +./setup_vms.sh +``` +to generate a [hostfile](../README.md#resource-configuration) and SSH +configuration on all of the VMs. This configuration will be used by the DeepSpeed +Docker containers in the next step. + +## Start the DeepSpeed docker container +We now setup the DeepSpeed Docker containers on the VMs. We provide a script +```bash +./setup_docker.sh +``` +to pull the DeepSpeed image onto all VMs and start a container instance in the +background. This will take several minutes since it needs to pull the entire Docker +image. + +## Access VMs +The tool [azure_ssh.sh](azure_ssh.sh) will let you SSH into any of the VMs with this +syntax: +```bash +./azure_ssh.sh [command] +``` +where the `node-id` is a number between `0` and `num_vms-1`. This script will find the +public IP address of your VM and use the SSH key provided in the Azure configuration +JSON. + +## Access DeepSpeed container +Everything should be up and running at this point. Let's access the running DeepSpeed +container on the first VM and make sure we can talk to the other containers in our deployment. + + * SSH into the first VM via: `./azure_ssh.sh 0` + * Change directories into the azure folder of this repo via: `cd ~/workdir/DeepSpeed/azure` + * Attach the running docker container via: `./attach.sh` + * You should now be able to `ssh` into any other docker container, the containers can be + accessed via their SSH alias of `worker-N`, where `N` is the VM number between `0` + and `num_vms-1`. In this example we should be able to successfully run `ssh worker-1 + hostname` which will return the hostname of worker-1. + +## Parallel SSH across containers + DeepSpeed comes installed with a helper script `ds_ssh` which is a wrapper around + the [pdsh](https://linux.die.net/man/1/pdsh) command that lets you issue commands + to groups of hosts (via SSH) in parallel. This wrapper simply connects with the + hostfile that defines all the containers in your deployment. For example if you run + `ds_ssh hostname` you should see a list of all the hostnames in your deployment. + +## Run CIFAR-10 example model +We will now run the DeepSpeed CIFAR-10 model example to test the VM setup. From inside +the first DeepSpeed container: + + 1) Install the python dependencies necessary to run the CIFAR-10 example model. You can + do this across your cluster via: + ```bash + ds_ssh pip install -r ~/workdir/DeepSpeed/DeepSpeedExamples/cifar/requirements.txt + ``` + + 2) Now change directories to the CIFAR example: + ```bash + cd ~/workdir/DeepSpeed/DeepSpeedExamples/cifar + ``` + + 3) Finally, launch training across all VMs: + ```bash + deepspeed cifar10_deepspeed.py --deepspeed --deepspeed_config ds_config.json + ``` + +## Megatron-LM GPT2 +DeepSpeed includes an example model using Megatron-LM's GPT2. Please refer to the full +[Megatron tutorial](../docs/tutorials/MegatronGPT2Tutorial.md) for more details. + * In order to fully train GPT2 with DeepSpeed and ZeRO we recommend using 8 instances of + Azure's Standard_ND40rs_v2 SKU for a total of 64 NVIDIA V100 GPUs. With this setup and + a batch size of 1536 you should be able to complete 100k training steps (153.6 million + samples) in less than 2 weeks of training. diff --git a/docs/_tutorials/getting-started.md b/docs/_tutorials/getting-started.md index c6be8a05638d..02d1aa530260 100644 --- a/docs/_tutorials/getting-started.md +++ b/docs/_tutorials/getting-started.md @@ -6,9 +6,10 @@ excerpt: "First steps with DeepSpeed" ## Installation -* Please see our [Azure tutorial](docs/azure.md) to get started with DeepSpeed on Azure! +* Please see our [Azure tutorial](/tutorials/azure/) to get started with DeepSpeed on Azure! * If you're not on Azure, we recommend using our docker image via `docker pull deepspeed/deepspeed:latest` which contains a pre-installed version of DeepSpeed and all the necessary dependencies. -* If you want to install DeepSpeed manually, we provide an install script [install.sh](install.sh) to help install on a local machine or across an entire cluster. +* If you want to install DeepSpeed manually, we provide an install script +* `install.sh` to help install on a local machine or across an entire cluster. ## Writing DeepSpeed Models DeepSpeed model training is accomplished using the DeepSpeed engine. The engine @@ -115,7 +116,7 @@ the `step` value is stored as part of the `client_sd`. 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 [core API -doc](https://microsoft.github.io/DeepSpeed/docs/htmlfiles/api/full/index.html). +doc](https://deepspeed.readthedocs.io/en/latest/). ```json { diff --git a/docs/_tutorials/lrrt.md b/docs/_tutorials/lrrt.md new file mode 100644 index 000000000000..d2e1e4051934 --- /dev/null +++ b/docs/_tutorials/lrrt.md @@ -0,0 +1,148 @@ +--- +title: "Learning Rate Range Test" +--- +This tutorial shows how to use to perform Learning Rate range tests in PyTorch. + +## Learning Rate Range Test (LRRT) + +Learning rate range test ( [LRRT](https://arxiv.org/abs/1803.09820) ) is a +method for discovering the largest learning rate values that can be used to +train a model without divergence. Data scientists are often interested in this +information because large learning rates lead to faster model convergence than +a small learning rates. Moreover, large learning rates are crucial in learning +rate schedules such as [CLR](https://arxiv.org/abs/1506.01186) and +[1Cycle](https://arxiv.org/abs/1803.09820), which are used to train effectively +with large batch sizes. DeepSpeed provides LRRT for model training in PyTorch +frameworks. + +## Prerequisites + +To use DeepSpeed's LRRT, you must satisfy the following two conditions: + +1. Integrate DeepSpeed into your training script using the [Getting +Started](/getting-started/) guide. +2. Add the parameters to configure LRRT to the parameters of your model. The +LRRT parameters are defined below. + +## LRRT Parameters + +LRRT works by linearly increasing the learning rate by a predefined amount, at +predefined intervals. Thus, LRRT is a form of learning rate schedule because it +defines how and when the learning rate should change during model training. To +configure LRRT, you will need to set these parameters: + +1. `lr_range_test_min_lr` : The initial learning rate for training `(float)` +2. `lr_range_test_step_size`: The interval for scaling up learning rate, +defined in training steps `(integer)` +3. `lr_range_test_step_rate`: The scaling factor for increasing learning rate +`(float)` +4. `lr_range_test_staircase`: If true, learning rate is changed every +`lr_range_test_step_size` training steps, otherwise learning rate is changed at +every training step `(boolean)` + +## Required Model Configuration Changes + +We will illustrate the required model configuration changes an example LRRT +schedule that: + +1. Starts training with an initial learning rate of 0.0001 +2. Uses a scaling rate of 5 +3. Uses a scaling interval of 200 training steps +4. Scales learning rate at every training step, i.e., does not use staircase + +### PyTorch + +For PyTorch models, LRRT is implemented as a [learning rate +scheduler](https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html), +a feature that is available in PyTorch versions 1.0.1 and newer. Thus, you can +add a `"scheduler"` entry of type `"LRRangeTest"` into your model configuration +as illustrated below: + +```json +"scheduler": { + "type": "LRRangeTest", + "params": { + "lr_range_test_min_lr": 0.0001, + "lr_range_test_step_size": 200, + "lr_range_test_step_rate": 5, + "lr_range_test_staircase": false + } +} +``` + + +## Example: Tuning for Large Batch Sizes + +We illustrate how LRRT can benefit data scientists with a snippet of our +experience of tuning an internal production model to converge efficiently on +larger batch sizes, as we scaled from one GPU (batch size 512) to four GPUs +(batch size 2048). Our goal was to train the model with the larger batch size +to match the performance of the smaller batch size using the same amount of +data samples. The challenge here is the well known problem of slow convergence +of large batch size training. Our approach was to use a +[1Cycle](/tutorials/1Cycle/) schedule in DeepSpeed to tackle +this problem, and we used LRRT to configure the schedule. + +In the plots below, we illustrate using LRRT to discover the maximum learning +rates for effective training with batch size 2048. The plot on the left shows +the impact of large learning rates on validation loss over the first 9000 +batches of training. The plot on the right shows the learning rate values +during the same period of training. Using grid search we discover that the +best fixed learning rate for the batch size 2048 is 0.0002. The blue line +(`lr=0.0002`) represents training with this fixed learning rate. We compare the +two LRRT schedules with this fixed learning rate. The orange +(`lr_range_test_step_rate=5`) and gray (`lr_range_test_step_rate=50`) lines +represent training with similar LRRT schedules that differ only in +`lr_range_test_step_rate` values. Although the LRRT schedules start from the +same base learning rate, the gray line's learning rate grows about 10 times +faster than the orange line. Also, the learning rates of the LRRT schedules had +grown larger than that of the blue line in the presented data points. We +subsequently refer to the gray line as "fast growing", and the orange line as +"slow growing" LRRT schedules respectively. + +![validation_loss](/assets/images/loss_and_lr.png) + +We make the following observations from this small example. + +1. Larger learning rates clearly benefit model performance, up to some point. +The fast growing LRRT schedule achieves validation loss of 0.46 after 3000 +batches, which the fixed learning rate does not achieve with 9000 batches. The +slow growing LRRT does not match that score until after 6000 batches, however +it maintains an increasing performance advantage over the fixed learning rate. + +2. There is an upper bound on learning rate values that are useful for training +the model. The fast growing LRRT schedule hits this boundary quickly and +diverges, while the slow growing LRRT will later diverge for the same reason. +LRRT helped us discover these boundaries quickly, using less than 2% of the +training data. These boundaries are useful information for constructing +learning rate schedules. + +These observations from LRRT helped us to configure the learning rate +boundaries and the cycle span for a 1Cycle schedule that solves the problem, as +shown below. + +```json +"OneCycle": { + "cycle_min_lr": 0.002, + "cycle_max_lr": 0.005, + "cycle_first_step_size": 2000, + "cycle_second_step_size": 2000, + ... +} +``` + +In our experience these are four most critical parameters of 1Cycle schedules. + +1. We chose to use the slower LRRT schedule (`lr_range_test_step_rate=5`) to +set `cycle_min_lr` because it achieves the best loss and the faster schedule +diverges fairly quickly. +2. We set `cycle_min_lr` to 0.005 even though the plot shows that performance +was still improving at slightly higher learning rate. This is because we +observed that if we wait till the maximum learning rate, the model could be at +the point of divergence and impossible to recover. +3. Since it takes 8000 batches for the learning rate to become 0.005, we set +`cycle_first_step_size` and (`cycle_second_step_size`) to 2000 which is the +number of steps that it takes for four GPUs to process 8000 batches. + +We hope this brief example sparks your imagination on using LRRT for your own +unique tuning challenges. diff --git a/docs/_tutorials/megatron.md b/docs/_tutorials/megatron.md new file mode 100644 index 000000000000..4575b32c3241 --- /dev/null +++ b/docs/_tutorials/megatron.md @@ -0,0 +1,421 @@ +--- +title: "Megatron-LM GPT2" +--- + +If you haven't already, we advise you to first read through the [Getting +Started](/getting-started/) guide before stepping through this tutorial. + +In this tutorial we will be adding DeepSpeed to Megatron-LM GPT2 model, which +is a large, powerful transformer. Megatron-LM supports model-parallel and multi-node +training. Please see the corresponding paper for more details: [Megatron-LM: +Training Multi-Billion Parameter Language Models Using Model +Parallelism](https://arxiv.org/abs/1909.08053). + +First, we discuss data and environment setup and how to train the GPT-2 model with the +original Megatron-LM. Next, we proceed step-by-step in enabling this model to run with +DeepSpeed. Finally, we demonstrate the **_performance gains_**, and **_memory footprint +reduction_** from using DeepSpeed. + +## Training GPT-2 with the Original Megatron-LM + +The original model code from +[Megatron-LM](https://github.com/NVIDIA/Megatron-LM). We've copied this repo +under +[DeepSpeedExamples/Megatron-LM/](https://github.com/microsoft/DeepSpeedExamples/tree/master/Megatron-LM) +and made it available as a submodule. To download, execute: +```bash +git submodule update --init --recursive +``` + +### Training Data Setup +* Follow Megatron's [instructions](https://github.com/NVIDIA/Megatron-LM#collecting-gpt2-webtext-data) + to download the webtext data and place a symbolic link under `DeepSpeedExamples/Megatron-LM/data`: + +### Running Unmodified Megatron-LM GPT2 model + +* For a single GPU run: + - change `scripts/pretrain_gpt2.sh`, set its `--train-data` argument as `"webtext"`. + - run `bash scripts/pretrain_gpt2.sh` + +* For multiple GPUs and/or nodes run: + - change `scripts/pretrain_gpt2_model_parallel.sh` + - set its `--train-data` argument as `"webtext"` + - `GPUS_PER_NODE` indicates how many GPUs per node involved in the testing + - `NNODES` indicates how many nodes involved in the testing + + - run `bash scripts/pretrain_gpt2_model_parallel.sh` + + +## Enabling DeepSpeed + +To use DeepSpeed we will modify three files : + +* `arguments.py` : Arguments configurations +* `pretrain_gpt2.py` : Main entry point for training +* `utils.py` : Checkpoints saving and loading utilities + + +### Argument Parsing +The first step is to apply DeepSpeed is adding DeepSpeed arguments to +Megatron-LM GPT2 model, using `deepspeed.add_config_arguments()` in +`arguments.py`. + +```python +def get_args(): + """Parse all the args.""" + + parser = argparse.ArgumentParser(description='PyTorch BERT Model') + parser = add_model_config_args(parser) + parser = add_fp16_config_args(parser) + parser = add_training_args(parser) + parser = add_evaluation_args(parser) + parser = add_text_generate_args(parser) + parser = add_data_args(parser) + + # Include DeepSpeed configuration arguments + parser = deepspeed.add_config_arguments(parser) +``` + + + +### Initialization and Training +We modify `pretrain.py` to enable training with DeepSpeed. + +#### Initialization +We use `deepspeed.initialize` to create `model_engine`, `optimizer` and LR +`scheduler`. Below is its definition: +```python +def initialize(args, + model, + optimizer=None, + model_parameters=None, + training_data=None, + lr_scheduler=None, + mpu=None, + dist_init_required=True, + collate_fn=None): +``` + +For the Megatron-LM GPT2 model, we initialize DeepSpeed in its +`setup_model_and_optimizer()` function as below, to pass the raw `model`, +`optimizer`, `args`, `lr_scheduler` and `mpu`. +```python +def setup_model_and_optimizer(args): + """Setup model and optimizer.""" + + model = get_model(args) + optimizer = get_optimizer(model, args) + lr_scheduler = get_learning_rate_scheduler(optimizer, args) + + if args.deepspeed: + import deepspeed + + print_rank_0("DeepSpeed is enabled.") + + model, optimizer, _, lr_scheduler = deepspeed.initialize( + model=model, + optimizer=optimizer, + args=args, + lr_scheduler=lr_scheduler, + mpu=mpu, + dist_init_required=False + ) +``` + + +Note that when FP16 is enabled, Megatron-LM GPT2 adds a wrapper to the `Adam` +optimizer. DeepSpeed has its own FP16 Optimizer, so we need to pass the `Adam` +optimizer to DeepSpeed directly without any wrapper. We return the unwrapped +Adam optimizer from `get_optimizer()` when DeepSpeed is enabled. +```python +def get_optimizer(model, args): + """Setup the optimizer.""" + + ...... + + # Use Adam. + optimizer = Adam(param_groups, + lr=args.lr, weight_decay=args.weight_decay) + + if args.deepspeed: + # fp16 wrapper is not required for DeepSpeed. + return optimizer +``` + +#### Using the Training API +The `model` returned by `deepspeed.initialize` is the _DeepSpeed Model Engine_ +that we will use to train the model using the forward, backward and step API. + + +##### Forward Propagation +The forward propagation API is compatible to PyTorch and no change is required. + + +##### Backward Propagation +Backward propagation is done by calling `backward(loss)` directly on the model engine. + +```python + def backward_step(optimizer, model, lm_loss, args, timers): + """Backward step.""" + + # Total loss. + loss = lm_loss + + # Backward pass. + if args.deepspeed: + model.backward(loss) + else: + optimizer.zero_grad() + if args.fp16: + optimizer.backward(loss, update_master_grads=False) + else: + loss.backward() +``` + +Zeroing the gradients is handled automatically by DeepSpeed after the weights +have been updated using a mini-batch. + +Furthermore, DeepSpeed addresses distributed data parallel and FP16 under the +hood, simplifying code in multiple places. + +(A) DeepSpeed also performs gradient averaging automatically at the gradient +accumulation boundaries. So we skip the allreduce communication. + + ```python + if args.deepspeed: + # DeepSpeed backward propagation already addressed all reduce communication. + # Reset the timer to avoid breaking timer logs below. + timers('allreduce').reset() + else: + torch.distributed.all_reduce(reduced_losses.data) + reduced_losses.data = reduced_losses.data / args.world_size + if not USE_TORCH_DDP: + timers('allreduce').start() + model.allreduce_params(reduce_after=False, + fp32_allreduce=args.fp32_allreduce) + timers('allreduce').stop() + + ``` + +(B) We also skip updating master gradients, since DeepSpeed addresses it internally. + + ```python + # Update master gradients. + if not args.deepspeed: + if args.fp16: + optimizer.update_master_grads() + + # Clipping gradients helps prevent the exploding gradient. + if args.clip_grad > 0: + if not args.fp16: + mpu.clip_grad_norm(model.parameters(), args.clip_grad) + else: + optimizer.clip_master_grads(args.clip_grad) + + return lm_loss_reduced + + ``` + +##### Updating the Model Parameters +The `step()` function in DeepSpeed engine updates the model parameters as well +as the learning rate. + +```python + if args.deepspeed: + model.step() + else: + optimizer.step() + + # Update learning rate. + if not (args.fp16 and optimizer.overflow): + lr_scheduler.step() + else: + skipped_iter = 1 + +``` + + + +##### Loss Scaling +The GPT2 training script logs the loss scaling value during training. Inside, +the DeepSpeed optimizer, this value is stored as `cur_scale` instead of +`loss_scale` in Megatron's optimizer. Therefore, we appropriately replace it in +the logging string. + +```python + if args.fp16: + log_string += ' loss scale {:.1f} |'.format( + optimizer.cur_scale if args.deepspeed else optimizer.loss_scale) + +``` + + +### Checkpoints Saving & Loading + +DeepSpeed engine has flexible APIs for checkpoint saving and loading, to handle +the states from both the client model and its own internal. + +```python +def save_checkpoint(self, save_dir, tag, client_state={}) +def load_checkpoint(self, load_dir, tag) +``` + +Applying DeepSpeed needs to update utils.py in which Megatron-LM GPT2 saves and +loads its checkpoints. + +A new function `save_ds_checkpoint()` is created as below for DeepSpeed, it +collects the client model states and passes to DeepSpeed engine by calling +`save_checkpoint()` of DeepSpeed. + +```python + def save_ds_checkpoint(iteration, model, args): + """Save a model checkpoint.""" + + sd = {} + sd['iteration'] = iteration + # rng states. + if not args.no_save_rng: + sd['random_rng_state'] = random.getstate() + sd['np_rng_state'] = np.random.get_state() + sd['torch_rng_state'] = torch.get_rng_state() + sd['cuda_rng_state'] = torch.cuda.get_rng_state() + sd['rng_tracker_states'] = mpu.get_cuda_rng_tracker().get_states() + + model.save_checkpoint(args.save, iteration, client_state = sd) + +``` + +In Megatron-LM GPT2 `save_checkpoint()` function, adds following lines to +invoke the above function for DeepSpeed. + +```python + def save_checkpoint(iteration, model, optimizer, + lr_scheduler, args): + """Save a model checkpoint.""" + if args.deepspeed: + save_ds_checkpoint(iteration, model, args) + else: + ...... + +``` + +In `load_checkpoint()` function, use DeepSpeed loading checkpoint API as below, +and return the states for the client model. + +```python + def load_checkpoint(model, optimizer, lr_scheduler, args): + """Load a model checkpoint.""" + + iteration, release = get_checkpoint_iteration(args) + + if args.deepspeed: + checkpoint_name, sd = model.load_checkpoint(args.load, iteration) + + if checkpoint_name is None: + if mpu.get_data_parallel_rank() == 0: + print("Unable to load checkpoint.") + return iteration + else: + ...... + +``` + +### Train scripts +Assume webtext data was prepared in previous step, to start training +Megatron-LM GPT2 model with DeepSpeed applied, execute the following command to +start training. + +- Single GPU run + - run `bash scripts/ds_pretrain_gpt2.sh` +- Multiple GPUs/Nodes run + - run `bash scripts/ds_pretrain_gpt2_model_parallel.sh` + + + +## Performance Improvements +DeepSpeed enables training very large models effectively via the advanced [ZeRO +optimizer](https://arxiv.org/abs/1910.02054v2). ZeRO significantly reduces the memory +footprint for training large models which means large models can be trained with i) less +model parallelism and ii) larger batch sizes. A lower model parallelism degree improves +training efficiency by increasing the granularity of the computation such as the matrix +multiplication where performance is directly related to the size of the matrices. +Furthermore, less model parallelism also results in less communication between model +parallel GPUs, which further boosts performance. Larger batch size has a similar effect +of increasing the computational granularity as well as reducing communication, also +resulting in better performance. Therefore, DeepSpeed combines ZeRO-powered data parallelism with +Megatron-LM tensor-slicing model parallelism, which is +significantly faster than using Megatron-LM alone. + +The observed performance improvements depend on several factors such as the memory per +GPU, the local GPU interconnect (i.e., PCI-E vs NVLINK vs NVSwitch), the model size, +inter node network interconnect, etc. Below, we show some of the performance improvements +from using DeepSpeed over Megatron on a 16 GPU Low Bandwidth (40 Gbps) cluster and a 400 GPU DGX-2 High Bandwidth (800 Gbps) cluster. +For details please see the [ZeRO Paper](https://arxiv.org/abs/1910.02054v2). We also +present performance improvement on a 64 GPU cluster along with detailed configuration +analysis to show where the improvements come from. + +![DeepSpeed-vs-Megatron](/assets/images/DeepSpeed-vs-Megatron.png) +

+The figure depicts system throughput improvements of DeepSpeed (combining ZeRO-powered data parallelism with model parallelism of Nvidia Megatron-LM) over using Megatron-LM alone. +

+ + +### On Low Bandwidth GPU Cluster +The figure above shows that training 1.5B parameter model with DeepSpeed is +nearly 4x faster than without DeepSpeed on a cluster with 4 nodes, 4 GPU per +node, and 16 GPUs total. These GPUs have 16GB of memory each, and PCI-E +interconnects GPUs within a node, and 40 Gbps infiniband across nodes. + +The performance improvement comes from lower model parallelism degree and +larger batch size as discussed earlier. Training 1.5B parameter model with +Megatron-LM alone requires 4-way model parallelism, and can only fit an effective +batch size of 32 using all 16 GPUs. On the other hand, DeepSpeed does not +require any model-parallelism to train this model, and can support an +effective batch size of 128 without running out of memory, resulting in +significantly higher performance. + + +### On High bandwidth DGX-2 GPU Cluster +Each GPU on the DGX-2 cluster has 32 GB of memory, and GPUs inside a box is connected via +the high-bandwidth NVSwitch. DGX-2 nodes are connected to each other via 800 Gbps (8 x 100Gbps) infiniband interconnect. As such, running a 1.5B model on DGX-2 requires less model +parallelism, and the performance improvement from DeepSpeed for this model size is less +significant. However, at larger model sizes, Megatron still requires significantly larger +model parallelism degree, and can only run much smaller batch sizes than DeepSpeed. +Therefore, as the model sizes get larger, DeepSpeed, by coming ZeRO with Megatron model parallelism, starts to significantly outperform +using Megatron-LM alone. + + +### Performance Improvements with Configuration Details +The figure below compares DeepSpeed with Megatron on a 64 GPU cluster with 4 +DGX-2 nodes. To give the readers a clear idea of source of the performance +improvements, we also present the configuration table for both Megatron and +DeepSpeed. It shows the smallest model parallelism degree and the largest batch +size that can be used to train these models without running out of memory. As +discussed above, the tables demonstrate that DeepSpeed runs with smaller model parallelism degree +and achieves better performance. + +![DeepSpeed Performance SpeedUp](/assets/images/megatron-gpt2-perf-test.png) +

+The figure depicts system throughput improvements of DeepSpeed (combining ZeRO-powered data parallelism with model parallelism of Nvidia Megatron-LM) over using Megatron-LM alone. +

+ + +**a ) Megatron-LM GPT2 Baseline** + +| | Model Parallelism | Data Parallelism | #gpus | batch size | layers | hidden size | attention heads | samples / sec | +| ---- | ----------------: | ---------------: | ----: | ---------: | -----: | -----------:| --------------: | ------------: | +| 1.5B | 2 | 32 | 64 | 512 | 48 | 1600 | 16 | 128.56 | +| 4B | 4 | 16 | 64 | 128 | 64 | 2304 | 16 | 49.36 | +| 8B | 4 | 16 | 64 | 128 | 72 | 3072 | 24 | 24.57 | +| 20B | 16 | 4 | 64 | 16 | 111 | 3808 | 32 | 3.42 | + + + +**b ) Megatron-LM GPT2 with DeepSpeed** + +| | Model Parallelism | Data Parallelism | #gpus | batch size | layers | hidden size | attention heads | samples / sec | +| ---- | ----------------: | ---------------: | ----: | ---------: | -----: | -----------:| --------------: | ------------: | +| 1.5B | 1 | 64 | 64 | 2048 | 48 | 1600 | 16 | 151.35 | +| 4B | 1 | 64 | 64 | 512 | 64 | 2304 | 16 | 75.13 | +| 8B | 2 | 32 | 64 | 512 | 72 | 3072 | 24 | 43.52 | +| 20B | 4 | 16 | 64 | 128 | 111 | 3808 | 32 | 12.65 | diff --git a/docs/assets/css/main.scss b/docs/assets/css/main.scss index c2583467e4b7..714744eacd7b 100644 --- a/docs/assets/css/main.scss +++ b/docs/assets/css/main.scss @@ -31,7 +31,7 @@ border-radius: $border-radius; -webkit-box-shadow: $box-shadow; box-shadow: $box-shadow; - position: fixed; + //position: fixed; .nav__title { color: #fff; diff --git a/docs/assets/images/1cycle_lr.png b/docs/assets/images/1cycle_lr.png new file mode 100644 index 0000000000000000000000000000000000000000..18246a6d412531ac4c5e2f579f98af5695f599ea GIT binary patch literal 25115 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�aEF^EOQ{01t8 zN9v$}4s`7vD2s$_zAr02Xta3ed(=EnlN(IZOPkXAo$Q?`Xy|G&_nYNd3#us?2=bta z8}*R*|DSWY@3w_*@k>oJUY=<(Hv*)|fd9XNuX&oAc;E=G*dFG!;?3(Ls6(h?&} zXS|&EnslTkT329#?QOzihLoKH<>cL>yD%bwcH2E;0V1kk%0+|Ze#&#kp$xERY9^R_ zPBh>oi;ySbbsI0PgHD|(aLU#smNU@oeXfSQ9edbBeidUR+XEqKC^K_~AAPHp#*!fZ zg5X9g?VnNpa%n{xeJgw^ZY*OJ%Oxzd;521h%q2WReW4W8OJ5D_9aLi|em#^7rs$si z1*k8JcliXFx}$#62;ttZGGwQEJApYkuG!>{fKA$bT2S*b1~puH_Ja`>sy^&}dh2%z z89fBmQ!*>;9{aSd36_ARPSUp&3BW#B`fNC6GjgCv-sNm5f?o>X_=GOxp`Q|>gkR*G zWkvGqC=5)j#YqLv$NrGRZ~X$Lma&!)5Z3r3=xqaPbOrxCPSO^6&^rzmUQtwGD#(?V z>uf42;y;AuJDVL}MI4SPq_|=&V#lo6!)`<&7#bG##FCV7${jKs?mk7t~Q5qAD@$^b>vJc{nA+_@3dI9b~TAr#lQKWACy zpS#_!=fE=Hy}(%rHiG#<23?%~lJBfnu*g-NsQ}(qIt_ftWJ{cn^h9&KJQvHF(gUn@ zZq<%~TPt!8YqYt(4t^L~!nI#@YbDX7+j(UrqFaFS%i>YtDdaE~VQ znh%rZ*Q)#s%a*RWc5|#z7C86;oleAfii^*ew9=|aazQv(a)AeH!@!iic^haNl zldUe?``@4Q00*w3*upMLUk0b)F4-U8{RLchQSdfehoy{VxtM^h78-@kW1o0_fHH+&Y*
PID!Ge-eT5RQwg6xdA4amh`G} z!nrTEVO_Yu#&K_KO>%s z7|c=AS${THzpQ^-M0a4<*WKFOvihMKaOsoq4CsaAs?xtR^$8=(@^D+yL4~i}h;W$7 zv0aSO*`e=o#?1<0L0%YWyVkKw4T#)=`v0$(YY&Gqeg7j`*+S{$kV6~VEvF4RHl})0mm>^G@~s?f3fa z^}F`J-}BFF-s|<8-urpp`?>GW=QHl!ulJN`rECL~kb?LWNQuesf3{phzrg%_Qt(v4=aZ;sFl@*=Sw=3u5a`33y55{0KAFg(I+^ULnE&0>L!8VE7s}o~1T* zZ7LqP#-|}9z(dd}dEl_14oucnhUJC!Tcvgcu|KU`>(x_C^i1tpfqW+;pcI9&f+9VC z1Xv)#q73obGMH>Y)AJ3Nr_E&G`Q8v9;{;&Rz(rL-y|=&;AAW|s>@sSZ-1cxc) zmnUcOW7nwY=uZtN>qEgONcQK|Oqnvy9QxhbST3HRpbSGzLPypIcK4?|i}5dyrgn_; zQdS=**$nTnh6DN;0pZ8ehmN+OPHg|TshL6b8c|q z7wzn&%$IZB+5=#)2f)>Vp{VmQvw#5g+g&bt;*<}z(n->F<>^lNg|#A;m_`V=ma_?l zYJ)Vi{MLY5;sg$p6*3qhmPu#n?Q=|}2}_%&;ulDmN!o_TFq9N@ba`NR0%X=`W04$X zA_)G0bpD!UVpy138s=sEYgt;&zBgSVXX|zPI~{=gbx|}GuD$p=2=zqrOs?H&?GCU8 zv}iS&)qG9S$ma*0^((}qA;|?bMUG7xEsh$nkFP!N_Iz7Nj=tf^e#eA z$0PK-AH+LwIZLl>0Y|D`3nT`wexY|WF1L!`9SQYW^BksvZ~^wnm|3(Qzgp%gi6T?{ zIk9ArK2wS(*2!7xb|&6kYF_0N^Roxyn!jt*`3`pc=9fA=sk?{+W9Ord;K34^mKN@k zUG(_E)!P7gJ8794j%)}e>UmOyN%>yA<>Q|vluxU=NYT8<#wr_9;(+t4UicsKeE#OM zV~Vk0SCD-`zJz$zU|DapTxeP*J|5ez#;Bb9EcBM_zH3)TBavD`Y%;x+8$RFx_ZLN- zv&CTBAc;8Gwls-jQt5I(YMeR#`Zl^mChy{>_ZuE7I7)gb2aCUeH~Jcu!3nOX?gB`z zmA(}#o9EF^7K7Pb1KSNuGtKJ?;R&+s^Ci1V_p}0e-`|vMsxs_jM!Q%iH-`;E_PNHH zO!h4v=N_`axU-W<)2^@uMRWvn*3ewB)6}-^ z#GsgI*2{~tbHmYo#OEGzFccJsftdNo=c8@z{lVSSA7=o1#X{X$(|7Aue!fg@cFS)4 z8#0rAacQd7q+qEcR&78oXQGpL)Pi%4HSmPzQ_NeOS`p&hPbJSl7&M+=x&7IZq2q!J zZwGZym%hpgT=zFYfV?S`^4RCUkgRTuwBjq6Iy72K_PDcSESsLn=})Un4TQ0$+J8Kd|I; zpcNKHY^B?0?Sg&()gTpb9d1-Y{Id3V(4N1{b1Xj*-0|#?Tk89bh}MMSaCgmY30wEc zdn?*}p7Zc#)3P0yYp39y^F*6^-M2x};@meQ)8Tx?>JoX)GrCY^DK67xX0GX7M)d2% ztL|ZWh9G|WG2RdT&cX?VL8S&CH4|eWq#Cv5Fw73kzA&Pe+qJImR1&E%h>m~`263;u z-ggwAwf}SeJkegz4Ku7ArcZxUS0bx-_fLh8I!NG#;XJ?PWOTS4!@6DgwDo zLGX_3I-EMtlgy^`a|BDtQ<~Ykd~v)H6((hBa5Sm!?!-A{)ogs~Y|r6X<(=vaAB z#*53H|la{u=JB1W8=p_AFk?sB5UjS`6!;Lb6NPut%EN+b|tcoBP&L z!xb3TI|FeWvx}&2dSdoy7B^cKzOZO|w9ZbW3{z6iNle#Yrt(Lmx|1C9e@gaUjhLx8 zeyaVCC2q&W%zkE^W(E8>$@VUlx%zpP^XVosmvl>4iO%^oNflF=+_87*G&z0;AJ;F7 zYw^7?NXf;k3GQjQWKVpaLatpGES*DsAOj9{4_vrgV77rKq`?QvTKcM5;>rapF%|=a zg<1|3K3LkqLmABbik}l{9{yN5qBX72VyE{xs7S#%)j%pt^Q{F0S*EA_X`-oT5FMW> zBNjoOLCp&H@_8)?%jH@bao-;Qp-@xxgtLIe{S;11B=yeApJ*+1jOtGQBQHc(q%8^S zwJ%tXhay^+-wZHYJr0=+%VQENo)F?`zw_P&G1hTiUP*X#JZ&SEoAwCOWaa<*{y7+V3%`TNVG+n%urFBv=+IR(}vgps}RSWpo za7<5kf{nA##A4c)OCtT2>WwR1$r5-s?p!3W3>9KGJMsxhGg&3sLHXLNF+LfH9yqBm zImt1iT$fGH<_fO};!ZU+K$!S`{#3(NMarCt1Ak>+s}pQov$GqTAkf|Uf4q6MY=>G%Xa zp+qIZIl;#4f;myH2lKQg?s&paNSEX*1&hy-jHrFIiTj@uY5qkerB9|tFFzERA&(_o zHw!lJTzgWeCHl~QiBNnIvHXe^0kR=~uTTO6D$MqyP%8UpjYAlve$!8Tyyz|8}JRT%q(Y&Hw#K|A!C=4jccMJn7$0^k1}CzGgQ5 zfi~$^q!Xk>^S2}Y$5Jq$!~Z2(3V#3htp4?Zt1?*IcDTq4u6G>Ym{*|$X|;kqX))^gfp>LFfQ#P)E6$wgj z8tj(Om!(yqB(@C_MFn@y)N>_VVsl3ZOWBzH<%w+;4>kr)mqfwA_RJz9^w(}E(DQ9n zBBSsM@i-7D>?Q~B(nl}(*w4n%$ZF&+r)sUX<&fC}XR0e_4Z70l-UR9Dx6Gqs?Ebq1 z5wR2%-nQ6!w#27(?c+>d94BINF}6M|CREkt5mS?^@|O9WAFrLu&U+8oU;V8|N zGL!HaGTiN9Lb2UI47E9HoJ(0G_uxh>j#1#{FAiPU$2Y33!+G0!RApfw_5~1`sS9JK zs7dPgs$~KbdnKx-Iq$uco{kIx?&H`V_{_6C+Vfs_4R=?cBdBvc z$dP;HHG^bkUbcM-NMO?2W63m47DU(nB&X z1}K&2?n$FOGadd=r-Iu}^8Pcb*O3&SHD+GjOwfvA^Ae5c=RSY#Got))~D4>oN4^ya}&w=yjvvu1aY+;`+|Tpy!^=Lk!F5?=ZE7Vg^Ah zmRgpNPb{JJvd3=63h8L}Mr?U^>}A=H^jqTIgqr3U6UL@kba8<*fh&jGUCT`m8)}r5 z`#4{BpEvY-ZdlkjbsP_oxhLFAUm}|GZDbhp>V>XXuF7mMjT{N_&f-dT-XZtMC9Fze zLyu&TE#~WD;><9aHJ<1=jF`dRRz#5r1}GDmC_On6vo}1_A!;zyDcKCiv1j+q2PP+f z9SW|nY6(ONZ&cWpuEYS%U~M<{OTI+sH2Eg3VHAOOFLim4H&j#gsu9MJyFRR+$bC<~ zYZjto`v`_NZ6J(B*K-+RBNCl?`t3iwy2`x$$h6y}3?T`+-C5eJS62YbRc$i0yMoRe zvWIUf!N78b>fKJ{K?H0j@_H3(4xdup-RHTVAlBwqAHa)c%wDR~iy-C>$9#`vhu}Czqw)zXoA$V3>3@lg zeBmc$MLgBiaU8ZU$iz%#t))4?#$TaukM0_`+9CfPB72W^ghCf1jk&s7v=MuH&dPFi zzeATcPwP_Da=?0*a?IC}M+Z;XunkuHbzi+bnD|Wh&EeFVQKY$U{K_w-epx#ONRJYy z;e%*OMV2Ak0_7<*3c;UBE7VzCZRA-?qR ziJ`%!L#R4)n2pek<3n%~(*&KXb66S1r>H}nn|p^4KUd0=J@-=Co$>7Ln-7V%!rr+h zJ!JD|jbx!y%iz)HE^e<>x>}-RXMO!VGZS#k+CCl&7bd|qd zFMS}EImExEd*Ve^CRe3aRkPn7XBMWqyO83Ol&>dB*f@uEG&YlAY9*?Fm<@UMxDy8@0y^)~VKC2w}g5GCL zrh>~*WmGBmymUe+si-?qb#5#(FAkwQAD-0tbL)SM>fmkI)OYA<^s2FXt(V|OT))`K z+RFJ9LoqFxQSG4P8PJ-JnF+nAUh#@UXXw|o`}dLW%b;g;2u>iq^kQx>^)b$SHe4rP zx##Qp3YAx~fgw6>OlDmbTiLf`k`6!HgjRwfHzpIc+)6LnZnvagS6QhyFFaKeh3Uy9 zdE=?bI%=cr;)}(}QF}>NNA?Fzrd>&dbSRGL&e)|8s9urm!){jwIVwU0x7|zLi!~VoI&|cD;H6o7MesMa)B6TS&qL&e|&r??+ zzo4{6PUOw{!TKdPwh?d7#b=Eaw2WQuUO?^o;+AYW#?En!bGbi%N@LC?uLqqp;@Teq zMGAqfiP;s%F%=KjFz-Lvh=COCK@r#V6+U0QU7A3&8pKEY4-LUFqPr*bLm!zZEG X7`yDfYop!|P$%q;I$2j9_Pg?LWSW*g literal 0 HcmV?d00001 diff --git a/docs/assets/images/loss_and_lr.png b/docs/assets/images/loss_and_lr.png new file mode 100644 index 0000000000000000000000000000000000000000..dedd62360ba704c72d00bd874b9c4457cbf23115 GIT binary patch literal 41640 zcmY(r2RNH;*ghWBRu|sVR!i}ApeQ=5mPD7Ty`^?lZ82&@%ucE;T51!k_DGEw5wvEF z+B-y1LLyeg4*xrSzwi4U{~U*-B=_??_kCaEJg@V*(@-5P74~Di#~=_0yXvC{dJxFL zMF@libL231XW>D@IQWOfLr>)%q^R@!Jow|F-CfPQ5J+*v@m;G!;P0bukBmJa5RL}s z4@-+{&NB!k9jf}^u7QsQl@XHiY#@NNzrUA>sj=`wQnAP(2LwjKZrZE#{N(bRf9@S|xXcn2mt=QV`1&nUk_S0yn$%KVDd0v9sQo793wm&{7bF>u(Q z_Bgm~63>KiJ@w@u{uhe3Exv|}7ygWRds|prM2T&?N_}!%Iw;D4b7$MpAkk!+qpSLu z(gyjwY+oeOQQLm}%_K#1(ZVxX&e!}*6Xo)luwwks2|{V`kfLm_C%3c1IK2pV$)^OonoOJuO?cPe6{p*%lw)x(E+)xK;-vF8CL{nvpj5PZ&i&*8{ zGR>TwXXLzhx8oMJS5fv&!H<2s%yRTHnm4BVr8!!)V>dor z+EdnRKigTor#)b(mN9EiHjhnzURyiWUCxux@jOJ2@G0L;Fh^R6C=qTFXdX@>kS=&V zHwcQRZ>?LEeau}IjV?bbXju@0sNZQiIrx$+V>mI1521*US%@Lv7k=fpIWY{TZ5nJ= zwpEpXR_wU>8SxL`1oZp^>m3~Yw+nn#R|v1B5t_7Y6wPwd4uIz{^$?)+l@j6^Y#7D7dz5VqfMud zP^?NwGSLwfZU61uKzb3yWXJ{z-fQRY{gyj(YT$J<8zh2|s5gn{d%m*jB<~f0neAJ37?D;K4rw$$ zzM6cUX!UgTF5~xC*621Ty8%1?e;ZyWEENR)tGCH=naI-MK8JyYC|D0$j?3WdNkWQ` zLt{A|wkM_i_X5ysL66w{yf(Htv$L)A+0s5~OQGckKI6oN^(@In^ZC^=eeJ<))=Mb~ z8{c|9t2E>|_s}HiMe2eTQu$Je_fi_7R-eTxd>IY?iVpa$EpJtm^KtL}o{?#+sL2`j zX?nKR?jMZH$})_TOrlNo8CJNVY4&HMBZeZDL=pmj4w+UiY+H`^cfF-W=CS@VHJjMZ zcM)6i=byuDJMd0!N01cGXsNX8m#y_px+zOGU^x zn7@F`-l-HN20IFgkplMK^WRNyUCM5bm6~`Ed+2)ykD%S^=1Nc3rOE41SawUx;5X-_ z?iKgEx_b?8TDrc~X)7oiwUF3STz*C*CrGjDQgClU_3k8gVFx5rJ*Sl4PcPW+gf&nyo$A%7<+6}V#HjHNYW z`ea(*h^%yD>t(q@O!H?mc(eO&0`ktv-pbK>&Wi~~Kifn61*RS5{+%1Y zUt2(4^7lot<$TiC_M%9e3%Z&O(fi?<^qH`-O0CuA=-!_wjGcL29d7>Xsa4kUV0Y!K z$SYX((4o5$J1-(GnRPxc+(GxP&$V-Rz0N9hcfein(r+Xnpdv6!7<N6K24 z;6YT(6R1Dz3ndr|3}nx0&d}juxo-PNY{5+o=9`Aa>%JCvyJFU6NyxOOrqb6E_aIB9 z$@S@Jj)+5AUKDyJYH0txfic7_&_B?l9&z6i?qA>=Seza7Fgy1!)UEnZ7+=Y5PWqu%?CRNY1Aj1NQBW8Ru8Gkuj% zd?FcU)W4o27a_(sgiVj3iZzk$(oI9#8VSljW3ONBTR>>`RMrPn_xczt)mlg=?OPUx z>+*3SC4M4j@%-9l(>WTBAw#WA$Q(!i7EV+Jo;7YmTgIZ_T*3W{47<{mMiDO6Fw2wy zXv`3Fw(rAzwme@B*<734vfAAT3Ae9rA60IE1M6rHVD&fL%x5L+^88M=^Q-;xt6>^O zM!TpNr?C?CByaL!?!ypR%g(#avgu$IH9%l;?5ZCPIAz{mUV-a(c^ifXZ@6!jIgRYy z;|&S^ke%y-YM-JMS`c%>vu7yct^)e)zr$+W2rD?9ty3xCA?soNw;>QxOBjCo{V6Xk z_$~gHd*m!@cVe*`gL2C*D@(WQmM8}1m@C4AuBh+!bUa6Ni1RTP`=xS{B$F~EFD*z< z()N%01k&FB?7krkjdWeg9EGDHgZNtkgJshPO>@u)HGd_I0Hr>hZrwKlJv!NcGCKW6OOwyO>T@aUY#}lGkC6Bk%2$N)|%;>SPE8QXG_FIlSolEJmc2wC| zwNeVulF+u;h||_)b7f%a09+J$`Ci&k~`84WL~ zr&afJw+fJg%TZCYnhbsRZZ*n{CO%zMdn8$~E0*Svz1`%$H8meB(q~}pe1qTtrDfk( z@kz#!=+EA|=GrMHLG*lc3LxPj6iz>IiTi~g>UiVlsv9n>009IEF3R6Mg1O__eKx^vR$?$6_Dvp_i8k%lCVa3t{Z~@TchSp69Ko z($niZ9_0LSK;IHY$iUlx8p0g2&b zgvAQEn$NDx|5-tKTFB+nXZy71ADX7wQ5Qv=Cr%YZhi(StuBbUyw`EMnN@a6$2WhwR z#ftQmA+l=q4c_~f|4Jt$@TxePp}dyHr&sdP{sB$`*W52Jn&@P*7OLBN|lM(Qi7k0$lg9XiOgL#*IW;S6AeCEST1 z)PQGzKtI%=5l}#y@e=GGJ@ajO`jDYXtSBtpXIvhW@-0YFlf<0&41!yWajNJYwF+$qQ8`OyokUJw>9hdDb=ylDxHpd!< zGRnn476~w(3h3UFjgxbQ*vj#%dwyKDb_4+7sTAxGx2c|lYiarMpBbhd|IZAbW^|Xp z0{W!WR@&p$EKbWPwyhbkRF39r0XUrV`ToM3?s!8+iAv@{>}o zH!EbC2tV_tuSw%0R8p|#(@V$#gQ2v`Pj>I$BHste%J6pgZ7KbB4m}5z_2iph$Y=8Y zOHwhK34u8IG;#w6#w>PmxNwDle?MyG8c7kvt zU$u#x-jb|tE=T=}Q6w)$e*+(gUA|36h`R>XgzL3mAj8{B47g;!mI)f9-*|8ET4YSC z%*>+PB*z&`%`$;96Vutxw^QVmvWA{(VLUrj`SbP0@1Yp9@PJ&G?Se&7FfW=^#WtnI zmQhGLn;-|>f6j-NA{RPO6EK4Rpju zjutu25d7pVbKMOSgSTa@P4%TMEo${PWtUR)h4qIvk1|nOZqJcTe}YAy%`L2gisgletH>Xy07r=%1RYNf}bXzBUxXYIN~kq7T9|xANDHzv0NUV!fh$ ziByC3ny2ZuEAkYNrQx> zH&~KmIp!8Nc$aBi!gIFOx#61jp~qW&UDOj&GbcH)H!w393jCKE$$<^u?&+ z*D*tGHSp2H^r~Li0Z4SGNDB0yD zB&i`}y0A=Af0b;gN4*Is_xJ@E)u1j8^C2!~XlLt2f3>DT9_s{rYW)K&q$R)KM`-D+ z?(vDNJk1uuV-&&RBq1x}eo+2O$%?NbBhOC)@e7Y=7*csGB8g?B1%kx$NzmT&S~tr@ z4kh_b%=u%~Yok9-p`$sG0!vwwhRw)@eja3WX!ZZ5BDS~vol7$ffq{39+@}?lV3U@` zG`l!$d1LdlYwLsKv<%+6q5aKFQplv~zH9Ftd2cO=aU=hR#PjW=Vkf-%wnIs-prUI_ z?DAb_(Y$FW>}+NLsu;11Ro>3nJ`%iLK<-aJ)XY+g9y=tJ<&aZA?u*Ut^`wjliw(Tw zRVQ|3Qz_C(t|<|xyt*hP|GiTQ$gr*osHV7cBdW&1B8gM5$dyyjs72TEjAp~mPVvJa z@s)=;_h_;2-3UjsNwm{NA^3-ukERW_d@PT*WbDhh6v|<4da=GZ#V_TVv}}zyJL%rt zb!nh;ezLeTLM3oP56KYJ+o%K>A4I%$b3hXiMdk5^z}qT571zpkP0+sK13|mE&ALF*cIc}ufPXhx6Fn?BltIPDv zcO+eg2yQG*jb==NrMlFHp9(w>W(cgDVB~lUEBTa+nF-wr#B3D^D}D}{qzI#3J`+lZ zkn);ggbjG^#@Um7yN-MQiZH1V>|@mW3@&b{XVqtlf`b;diDZkTGLcv zboh{!m^41IqukhmS72q^kl_$tqZPncSdOStBLojx%e%adQKso2jCJ@!70ML(Q@x%% zN~nX>6ZV$tArLjU#+VL zL|@kPxu-pT3nhoP+{&@ML$AZI)p2PDRcY`-AZ2;qG^eTOv8Y{HIqdzOzmH@ORp>a9 z>qqul9Sp4=^jp7<$|c#OGTwjXhd}IY9NTj=r$aAsVgr0^=lZPxpdlWOf%!9En(rFH z80M?{O@f#^sY_@%X9jU+Z?OAX;yxPN}n{+O47fB2>erV5=eu9Mb|B9~D znBssyG#<8Fx@TK8+}NucBnXP3mVduYhWf?)d*s!>N1m$PNBnc@KB5Efoi!SUBA?Sr zff}nYuR4{Rnc^NBJKR?(#ts(zV&pEO9`9|N$3O4LuceCnHXa{a`QiRJ*w8$O_l?QC za*p2{`;X{NU+H?l9SCL;$G6&|Nx_iFa$ySBMe=dNBzl-PB z{9H+Us68y-yKnVc*sz&T%gS2R5Ih`G8Ws603^%34n3m1nHdG%&`C(0Nfmvid8Vi+s zQh#Jd=#L_b=Wy7+VC>HaOWip(m6hzgA)^>ne~PR)1d@{lHV1rmr)O7%7#Hcf!dagd z$^lou*Ew;o{WutKN9OV(`23o6=Hh7gK6w`2nAz5U!|eTbNT>okx5%79R__3F8R35& z#a3Fo{_ROMq4}?)ZlYq`!i##-@3MhyK81jfJKUzHr{6LgEiYPc1?}Mr&8r8E3QcU_ z7>i%H0}kLh8s~%pAF8Mzo;_;}4i0v9bL&2Q_;3LR)8*^yTToq1z~OKO85s?uqoWHy zUbA`c?*&wQkiy4n0|+kTI2$=vVwuxWQM8sDyvVG$Jywd)^npiRM9F+0b;u?K7BH%X zR&)^2O8Pe45<%$6P@yhQHh9lq>M^ltq+;@yU&X{)jVUo1Pg(ArIuMiwsAL!$;qr7I&WS%`AV`%4Lf8 zDXyV)DwIF@aUfACsP&Km>%$odF(G}rqNvd0fq(R- z3{@WsJ&R5^L2FnkI>Y9Ztwy<6ipc~4Zd;9xOV6LN_tA@qqrAgG7V5Q#*+ zdX$gPaC38WN#S|$yr0>!nWNe6d`9Ch)Ihedmlx8X;y!h^lus3dieSOx|{SD zwAC4O>X*yCr+s_{lF+ZSNDcGl52433EBeTK?oe*TIL<4Rls^AveX)9J)NiQxQd0ADcsiue#G)TKbos9Cw+30l{_Z>CvqVyF;`4SUcQj!Y0 z%=(_^a~KHjE!-Q3Cu@7<`Wo`**D^-l>}lL96fcx3ypNFc-Af%TMTch7F?N3(61zPP zV{7Kl`HqIKY1Fv!C5HdY?Cibhrc;L0BivN6{PciBIj2JvAnciqWV$bClvM*{b8r*8Pj5x8 zLP>vt!ZvdA)geyk)3+*ztV)>f@U9xU6q8)GcHr;FaiVJnWT9-gc8Swzu?6hx>^4F# zLoWfRxUiPGzucHvQO9(c?;5E*$!{l+_3|FG8b-(B6hUI*ecJT?w2cTRAC9pNV9qyH zhMki$R#NRq9mQvkT)nfgWGD3U>8DCo9r@&fdhX%fEgHhv`6}f&b8sOEgfypl>hEIY zk_DfjV3*o~CZ;dCsf3>wRS2EmVrEcCcV4)llEpfI%YE0#8lRP?M#ruQfEB(qt?~65 zXz457hh2M2RCQz6I>II;@S@i2Ks|RL$jsgTYr>h!joy>>Zwr`C0gna^s+&AS13gUgqTvq>A!jPX#AvMOjwS7%-DG4|L)Jtcsn3!#05V z+*H(j`fC(z7P^-F(0!^gwBXb=EHAoJ|EYwOdn}GiDuTmfUNVd zj(4O&(4PMw8|1|-Pu=-nDfwoaOhRBXiiNyr20n%^w5Y)?_)8*P?$`<uBiUI1>!5F|qH0Vb4X zghW;#i1?}ng%2UPjkUFBLN8};3W3eMNnoaE@6|pUpc3|{u@<*@@@?dW=BEBwd=6Ex z$a?tCLET$xw!>RAQfz?bicYVj%!#|w`XH*WiL$b?awbEnak!FN;6F-2Jz_$?SNm@y zZBzE~M+A2cK&}kFWMvcBE=un+|dPuv$8sVg@5;83AyEC`iUnLp!P%-JT+ z0o@jCrcWI4SbjxA@PxkN+UroF*zvMsz-YoCwk2#t>H$5l1IfmoU+w$bR@pj7N&H1g z$xGN1JWM-;WeDomFNs(!KN2jv$h^qe-hM7E%1T8=WsnDiWcnM^vn$b_C9cQ0thLtASwX$l?LtsUSUWOcO^@g1$?6x0HG++yF&qoMV{Pak|!b_ zWh0^jJ$QyWkhid|Za?k#QAJ|FhB;+np+oIJVHltXN2{LCsExGh#%3|^cP9gIo?kIn zjrG<88mGI{?i-6fu>~0Q<2kZy|00L2GFGv z7;~Ub!3Q3x7z^2xfov=CfxA8+^~VDn<`6(kw`s+&aSAYf4ovcTb4v?iiCAMZ0aY|A zGIOYKo#<3MaFYjkn3rjpz3zxAZE?K%zhoVU2Qfkz#X7auB7GLds`?&2d2r$=g1CqIoNVjQ)i_Kq@dh%4#9QSMqPtzJfvPUp>HtaHA zi~tJ!B0*G@2Yn~Hk-6zFLV5Z51LleZIH9JdN1;z-nTTkMlaN*XOg{J*zqr$mv#xm$ zFDnFxxWrSb)L&``O5yrKi{RYNb-zEKRbcO#$AKtOvH)vJR;?5P@)(Okl#R=sjYnDy zr1F@%_QIF{*7L6m)yii@w9y@EEcOYF$&m=P#;Ph0QVh;eotSAa&(4`D&!l?_@sehh z*Z%V`tb>zNDWIG&0Ts)?51snnkZ{qRq>76x`hGkLgP;#k$q z|E?PVIV@{ILHTS52Y;Iy%Mlq+-c?|;To8u6TCLT-jqpX5E6u?6ZCV9P-v6IvYiny^ zgxUbVk&UAfGwrdoBLbk-L-8?i_MFHQY{b$_-vb8u-XX*Vs8F1>burQmy zaP%(~KyR%JW>`QGIE|Zo4IE{c-2PEt4^Owi?i!O3%xTIRFAnTs?bA@ zEjG9XD#7%)-#^AcKK0&NNBpG-$RiPe-A$e;DOCXLzM52Xvda|4= zI_%@eXMd;qTO?cnYO>C_@G(k6+cp!@p9hNBsDS(eOGNex$YjOVEp1xmAlR8M*L}Oc z$iS~BW3UBgz}HDA7FgkI1r$S^k^<*|n3$`mga8Q2U8sKD0^D4^>(^nOI7M{@Y*v|>>qRN=)|}$zO23HQJ`V!6v}qt8 zF6bMY+yW}CtsjC{j(|6-1`AE$-Und+1NnogmrX4WNO~zJC;oI(>l8uZAmRy#%J zfD}6J?=fs9xS7WLjy#>lptY$M*?7O*J=ha*!tIMU;NwEzl*lU*rhkj zYnEa!&oBw`X>)V)Ou?0grNaWCM8yK?Vk^WVeE=+)bDl~KnEP7b0(fD<=AcpbA5*f? zW4WG5$Et+RC_ntS13*Zkk!QP7_Pdd+Z(R}(b^CzTDn5V@y%n)B4`74b5np{^66f3p zs`HA{EKr>%MS55T^%(kEoufx^dy*~Z^MI)1;(KW!oL`}>mfPp5Ij(H&p)o}NHLzbu zV{API1vG#%vHw@Qryn%SypikP*vIn1_BnMFtM^=T7xp{t8S(q~J4RgJ4FEQzek7jf zOG%}h{Y_Oj6J3JB>W*KT{gnv!trmKb3$&3t=b$YY6;&~&6_S5*!xLc~K!T)>w7y{X8|1wg9vdC|?g^ms_a)yW2>+7V zAsH~>$!yQG8z{$jb#^R^ed&%s1keJr@&pk0`w|G{s|r?>=O{1`al` z8{M`_0<=#2Q0h6rxpYbZi7(;aoNNdw{fmAkJpdjMfW6yL{UboWeICNzeSoLEsQiJ^SKaY%#-6;i2_+DgDW8!_$viPa;Um&|9K0iNSTxePW z#zC3N%6|xHe@H*3l8F~>Q)5*g#wl&YpnXP2uptn;-;1Dq()$JPAiNjHjJ@wE`7A&A z?@sxZJ}c=GW|iLx5KF}%5B4U@LQK^Ee?`g&SeDv&p3su?$2L^D-zx5oX$$ST&DIku46Qoyn*0|koNX;Hqswuk7 z8LIGPb^7-M^*E3tJ>@_E&F)OTBDOOF4o7)F3JGqp7E56y3AGCPyN#k9V5P z#~2AMeEE_ObdPJGU+wXKm~C$hP)N+FJ;Z%`ZNA{t3!}m1#$+xhRA_a7v`;5!rQZr` zxO6@i6e?GGH#g<)cFaA-`?!xBwWu4;Y&&`I?mzl~${6$x4%+g`I$v>W@yn^+W{o?S zbs5w-Lb6L|OtSZQW$_7}++NWx#S%A|$%R$HZ~f}sj^XYBuSr!4&JxY&OUzs&+kcn^ z@~<+y_bp=cTKM@}kj7ewvP3>BG|W~#@=V8@|r z)7600KCyN5nUY*;yCpOvHoi)h%GS9k`6c#+u>o!}pxKnK3 zbFtcUUJt~a#=tTt$*MeYPqoI)h^3T%2|P}VG4Lx2MdlHn+jXo~ga2XK>;@`ayVfoM z-L}7Th;sofrAjJw7>_EYGYbHgj%T2x3>BGGoDyGNJy^KdY)@b-yRFMhxc3Qm3lvB`A0(g+d4uKQIjD)E{q52zVdrY#|N z){KTXi_S&>$EF=P_9RA4cyTxOZctznFHZz)drlhLh2m87(SL2cZ@%kcj_{%%ekOJ7hta3!=K{Jb2 zh>Hy<1yj|!^f`B)gLlhpJ-xk0vosUiMo9wXqP^V7Bd_A1y7c!70l7nl-hqBsL#vx{ zyZutegsAQAWEvnVuNV_{ z=qD1?jwOeG0ELAa=+c~6XwCQ*IUf^)LlMgC6CUOT{7-$TJ%~CLU)IO@oJpsSq#wH9 zRnm7|!a30ozd`hCwE{B=_`LH`LFNkHJ?&vsALjj}-6?fAArpx9NxQq4Q9=p>zOxau zU&LseCQxGqCsuTK=VR9i*_H}c6K4KD&bZb%RBM-y(EV7Oo!EX478vUfUIFRrDad3m zX4Brp1u71D#6WLlJwxL}Pa0hg3(7017d5^SM%0IK*?m4%!mmppqxWumznA?8aH@LLwhlcy^ z=1NKPj~EG4X2~VZS%)>4YBb-iI>H^Gu<#&+n+y4UfxDuqp_}Rk`4pL0*;li^cjBbE zRW{*N|972BZ^Rd~1|RRR^Nm$^`x3W#oc5=>E^~Y5R&F*1Rb-|x*!;+SQUq6}J(n8} za0%G@7Ib~z;`UR^fSsh8s>uWd%(JW0f>K=jvd4L`Ta8Kb2Jif4H-x;f{i*=#Up$fG zK|%+tkLaEHMX2h;Bpi3O3u}Lbo%}NPAw;)cQb6uSe13Lz_S$RIFvrI5H>=lJEY?Pd z<+qigrPc+<7jvkKdle@+4?RRQ14=x%W<)WkCwciZDk6_oF=jG)E?bn%GT4G{-x7k`oF_)R| z^|xG>YO^Rkjn;1uyDJ;sVZQ2D$R8CM2=2Q!&<2T%XBK-vVfW49FOmlcYIF>;D#VSP zq#jMTL;A3)vS%5*KGbLZXV!r-u^#MIvoh5B%-q7vcUBJZ%Oj;&Bqb?PqfJwGZ()RW zJ$^`QxFW`)ER*0mLhPe@(_pIU^Pa1JT1$do5e*K3rlMZD7NT2zvWc1rF=?s|*l8P` z5C9DVEK?%Qgrt__!N=ywx6N%x6)lmKP8QZR2w5MWX!_Od0<6-;ht@adH)_`=7G^p3 z1~??Qihr2~{zPxBoZH#CrLwT^?~S}6Di^QaS1<#@eBPtGoDa4zp zRWj&99MN2Exs7Ab?n$-!tmTI+^kI^(j0f&av%?V#Vzr<~U0=}zr6TQfv2&{q26QPx zc-hH^!6vn-_vR{enI7&g09_QiPBmc~RQRB>$uW1C(po!iH*DV@1 zeGxUtm<}o{7YQP#0o!=umnnnQyXvx@&!a}%wxsUMEz$`@eQLSqj;0@~Re7fasr|*} zv!>9@`}az_^%i~$d@2hcJhTbppeu0p-Sm&&l_bpGKtqz>%(|=Xfc1EN;P~rK8$WyKb+E{oUf?Vu2Kx+kK?(W`>E_p$G&^_f?=0Ru&d^Cq9$1 ztWAnO@FEms>v`FOG9SNG>Q6sXRjB!T(O>tFExLGdN7l#wE&b|l8CHol0aAfMnbOX2 z!4u%H*f(n^XG!rucC~AxB#~S?E<$i_3O8MECX26+ncAttDU1obbpj@^WRpbByw}&W zCT*^1Nh^L%qW1bb>`A8-K4@M4cCy&2A(#pBznTQwr@BlA_ua2r)+&m#1Em(QqVhn- zc8Pa+3rM*>Xz3UAmw~+Bkz4$=0{OPz98PQ+zwW_qIgALP%sy^uuZz_fo>3m!5Wwyg zPLzU;ExmsFKD=?hP2T)Mw)l)^Q&LgVPGeHTdbPI3xS?MiqiTG;qD!!(t2VH=cBS)B zV#PeJrh31Kzoy%!Lg2*k+^~;qOP?#?%{J_zpqBa@r&_pGEu}N8cW%B<5#(=PnQkf7 zgXnyGHdQpr`Vv+2b3xj7DUyA`za1B}_V|WzEDyg&V1qAQ(dmA+EMfEK6WQ|S?wbp1 zR~4XrT3zLd)r*ev#z^1UWOTp=WxrND{+-i<-PXRHg%nGeZP)JH#{lHaOs~44_j%V+ z4>{k$Qaky?>1N*Z=lyf8_l%6h)0u5x9dT?S5-0~cJ0}0HjDx(_M*_*{inN$}cK(*M zIp;4G2~SgH`J`8bE4)tr--d#dpE}h;i4wQuYPoCmD#Ll44DX zngAo$v;l%W-DuQRs`|07dLhwhC&bcz_qeoTAWg}8B*PMFpAtxYQ}gY262pyQXj)AQ zrz-X74u6maitOXT)NZ~)klGI6`tBo9jTLQT_9T`#M?kf|fjTuBTL@+9vl$tsG$9`d zuj{>vzk-p2uP-`OKSP6A67{=X(v@R8EaJ!RZPZ$uPcUen^^zjD>liJA6)TCd&vQ}4 za%t%swnIyF!jDpZ0N3Na>e6erV_kUfdI1JGO|M=e8f@v@`b0#X&oJ6&`fGrPySMrx z%XlQg7$<~$R<>*NZA+dda1eqYsTzc)x#ctNjcC3@c~ zz{&DT%}n{oywQ-yke^ybE&0sj@nbt35naPd0W|yhGb09EMY<~@+DlTJ8|q58tucj_ z&g$jkWmFZx;Z}7(c_c>(gi;}9zi5kKLuV}-MFm!bDD8yvNU+2m^KI;?22C`bM3WVw z-;yyL4maY0@QTQ}i{RdChAPM;^*{0jUr$tL&q~j|9)n{TsVWF9t!_%xD2s6E7NmJ7 z6uADP4Q})!84N*`hlhTqEt3UT%zNX+F{O7z{RV=Ye$2b11g=1Q*>DNd% z<>rR6KeVy4jHN=xFH7k~*LA@uG2R>C3d9KR5mX6>3=MNGGOJ zzgl1Ea)@i(jIslS*8v=#03d8Q7{30v_~~2FD;F0(3enG41e7n|?&PXVD8124U`Y@* z(P?R*OFcs{`QHYa^p(yOdFR-n{qHWn7(9NP65RM!(LEqG^NmXk6_-98c{Bil=s~0yyKd zXV9xfRm8Heq}r>s6`EC*6tGi^LE*|LAON)g@BI!5jpmL?SPOTaJ~vQZskFHQpiSwU_TQOv`CLiOJPOQ(sAdm)Krv$=-AU+9A6< znajtKBpS~KQSMbAt6wh-afzMj(ST&>>t9}!uEjT+XC6!f`U0ycIC&*I=-z&~yv8b7 zYTx391JA>q*q|T2@PN!UBh%eCfhSM!oj0ABaANE99v+1v7eXkQ(c{NEN3zvjTcPrq zuC0tP?WGc>eSqt+uKcChK|Z6kH4Blyf|hWIVPu7LP^{}lw95tNmz}fj0W}&3ZB_)( zMrsbjkFkF*b9&!sPK@?Ys}(&O+ahRIP?v^(@UKbNa#PJ<^}_MNy{7#njj^{q^kgOM z%VgJ)$F8QbYYSMWn)9&bubSh)KVtga%PXlU(l20Orq|E|=c@(pVUR_T!rbm*$GH3< zFBB)EeIVD)#Y&o&Fps%l6QLY}FeXgT({-n`I9b-;z%zAjXa;@w;wzcF$BD^m_w!Dk z6#>!$dzHZr&O(HL&cxvjsp2BJz1#6+A2RGFvk{ve<<4^>Guw2EO;|WczcvBFB#V~R z3LNC(R#ztO!(N(hw`J({TTUFP84NU&5y^qb~dLYVqHFa zIZo#$j-r$+lvz3?eUEm7qcrWK9Zd2pfz4(~HSSNY)So+6m5zEU`BBGWN^5FTaU>+( zVQt-*LRgN(D(#E6el9SH8J)8R@Oo`v{0e+)0#0hhG9Rl=-xsE{9`l+T5 z?Y#dorM_*Ay1gH|)!r2o;bwDX8^Ftv4ky!VO|Vk;;#`{nC#l-&5a8^&sT4rT&a z;RE^Xq%OzxBZAKmhEJZ;0jm!sS7= z+?Hx>G(T%Tu{W((?^@tzJNCTPb)vQ;_#JxudKC8FtEDdVxaJ9Hv=-D&E4HrlP5(k(w1rl;_R80{6#lP7w9O~{TTwNZ+N95n0L?r;fU zy`-7^dxu#psnnKD?5$*8TJPu78c|;|`z9x6Rw`4yG`tu^&6L}N&GDA3IHMp>gjX*o zM_LQ)m6Uu-Oh;diYjZk(U1&(JOUoN50Hl$WDsT`n4yM-e7Gcc^HF_ZH!T+AyRLlKx%tPk!7REgBEkC9WX-M*d*1zcv>Hx?GU;z3m=8b{03D)O~F z<$)To)>nwZ9g=nC^K&MY|N2kh?%sVgCUcIlTIx6;W?E_+2AXg%%KMA#$;7A7VaKUxxMah1 zgjp+XW=dA0g1#RPc~~lR;6=Q;YB~O35|<-N_@-IhFs;%2JbIW_=W5Nfi_Y93?w}e5 z5L^~M)|hNjs^m(<_Y&~CJSv>yw_h|ruJ%TZv?_O9y>I<-L-E@lzfyT8Tu@b*T5lh; zZC8jK;X!OZr4?~9A_ZL(fMD9b{RFqh9zIIMM+xJc-9Yo-nlM(=S!e(Bo3$JF z<$->QL=5xL!B4l_Jo%Q`e2Vnq#V90b>mR&MxexC_Ow`sCKoCHHO+`rQDS{}QMQ zt!@zv!uO|kPsqD(06EPzQ%5@4V2b+}=rR?SmfjS9`S5I&@9?$})Q;M<=YPYU=OL-R z&Xtu=>k61$Xk(kDM&^>Ty{UXxd}WmW{C>gMItpN!sUcicTKcpIYysXYwJ zFXy1;e&Vw!MBY?|QZ-?ZEDmto;+AdK-sZ;|+-{`Au>Ux5JZOkxRoEP&siArUYiX@) z2}J0@%*cT2Ql^a&lL!PNbLC{CGe^xQ1UOw}L$%@zh`kNk=+EWB0UM)t&!#$4uGg2! zXQ7KC)so%7L6b&SgY5dvICcROhjFFdkiR%xu|E(T?)vjE8a8UzK(zq}FO3B|F8g|q zkFVcV2*?Dk8}tN-YGTl7tuCD3RG5CI-2`KWXJZ88eOBm{V@DDTvBY7vwIX*rB}KqQ9t1MF^W$)5g^=*glHjW;!o z_Rsh9GJ`e@B$m<2WtAdXxsl)?t7%hrVd|N8|MerQAF!t@KUCX$+E(P@6puHK^^~98sXpLG;!)0LV zs7W|Dp)Je6xG=lO*b^e#X7g=OcJ7MYe0J8<5;dvR|8#kXZ7_&Ia31l`I5-fiR(C8o zjj(!6W>rhg5kh3L&bPTYh(ivn)x`3mp}ni|WydoZ$CVH@>gcjbT6IYp-}GEhh7BQD zpzZjn!t9_%rZ#b(bQ{t4(vPXk?R36Z&y<^o?NO&QNfRQpxxXIy}(%l^U2 z3~*@bD%FJ)6TJvrL`2CT83DwVXirq9`D@2b74o_gvzN@dDuzM1a~s2~TZ5h*0_+WjMJ zH>0F-T+w2D%bKLQB51a^%*R3Rpl4gQdXqG~T;g9i{L7nH&P9_9T;hE3%C2+@$KZp` zJ&r-zWVQ-P)fKEGK^BH1aN5dmCQZP~dFGK!f+fbOKfhI6b0#GZWmo~gTz??DbVGkR zE9Q>Zyc+CpSJ&T*;7WKIM&|Z~GnELcV1FgcDM7tr{Gnj;;ed?XdA2=$K+iP+uEMt8I5(ihrVtvF`nvMkhoKROx!&vE9>gGY)NI8g0rIJ9qowZ z^ch=nH0z-e)odqCrDI})?E7CBjvYFKGRzZ7 zaGxQsD{cfCQ|Wt1_db@z2V-)0lYNHHrRjz#aORv~QB4Lo&3Cf^%>!if%?eY2` z1JX|U`Vf#ru2%V2biewa41VE#|ILp@J+7xvm}w}kWlmiX#p z=R<;wEgy(giY70NyDYIZy%A<&Me9nX7QOC0XDv1tElMzb-Z3@n2*fAhyymfscNb_4 zabdl()po6mSD9JaoosV_kR$!g-yRWf8K0rWI5Qo(RWo*__t+zfPb4}J8O_HV?va2rVJx;zCL8D< zY->{R71wTN2XAm|!=a7xy*yeS)Xc7C|MkI^Q z8X7TA-G_RbzPA7P{H6Uj2msqt(p=eVUrN32Ub%jnEsV}ht~y;aX*`;9LSf~%DHs2j z4)nUzhS;s@LAFp8f-e#g|xgHWDaXVSaAH{atcKR8S zH(;?yjdq>_8!bfSVTC5uK*d5W#t#?`I6aW0-LLXeruF>uj;x`F5rMXt+($BF$AX-4 zfv8d#9N|A|6zi0smRm(Fe%|M2h7c7KCJsj$7rufLl4s{^vruII6qT=?&bf64w>Pe{ zP0D7;b9bHy7u&7wT2_Qu|d(l0tqCjt`VMbpjX~DtdkA(5L(PHuJbtoCw=nrvhLM&-0Hf4Z|RMBmvyVThGcBu81xc_ zzrSs_l`$vcQj1;?H{eFc=3sj+Qexn1133I=wsK5 zRil5uCd3d7LLPqk#o)l@=B1rP>`^d8m)K0a=TXb~9Zx?|<^-(R8b5IJ(zkEl`rt>J z*wN39i6-~;?d@>)V^KvPX+#|(TxX}T= z#EEkqpiFK)SUUn)hOXq5ex}oVi{#6F7hYbQmJ%tH?M@y$@9@V?Z`@&HpI_Y(c7G5y z9P^2hTvl(E&{{10{QmRK>@KzRq$cz3zCIJ+dpwO1puKSWQ^ZjO zuu9dM+}2hOO9{P|AI-WIDg4&5zn~u4p&(LyjNreTMi4DGZoR6lGoSu#L&A);BO6eb z)!t_W%&$FCEV!?7wxd(RRA`>Ix4v-@!Lc$2-_%W7lvoa{yVX}Luc>d(k~pPRd#T~7 zkVJm^>R#y)M?4d%>pikpTieh(IPoPuTgR}TnZ;&#OA2e7q*(H1%Y?hEa1*Q2S53J* z3-XOxIpn_rk+|mVIO}j5yNusnA|l!%G9gT`NWMXdCi4ozP?}G z)qS4;uB!Zrc#)1!u&Jz77%SU0hg~7#vf7YKzJY=)xUbq$;yC3a>f6be)#s zl@SrNt+M;7dD8Tzc$d+E(kb;R?B12=;u8rF2N(P}AZ_kqdxe<^<&hdcH9zy2H39v; z-^uCo`T>3qVl`r?H)rIa(V>pPg1-*vNhYo-ayb}|8i=k`=sJ0H;oG1 zH{!Srev6cr2+&~?%i8L{G`)H>~%j^CT-#xLz;L*+`(w$*vSTi&YK`yfo6ZAEAP z!YEtduDT;C`3PSe%yN*-z&_KfDRQ+)v%|-aA2ZG*H&l6@Xv9Adv$Bu*_s3h3GJgzS2Xd=RMp zygS1vcL>|qa%!vax?5J{{lN`(iy1ATU}sQLZ1$MTU2C`SqE;5IJJ?sFydQ>YVzDEB z&iQ}uLxtZKt9Vq;!@j_@s~_S#n_JgF_fL#@y8TclI*L#FY3!Kg-Fy*<|JA<;oJ4Nt zAM~Zz&;8EHF;F*bmeNb^?6xaufE>Z{=Uk*?FL28nXLc*!9#D@>mj*+ zrasloWps{ng+J|@;e!LHXKdvj_bpmdN9&6=k{C^CeI&p4KJ@9N9buAdJSHH5+^Um% z{k+3a__OLNW+3Jm4KHbZ?t9XTm5$D^lPrtz^Qm=0V5ylMsG_UK5^vf}d?NF@_xHza z5h0^a+$F{q4l%U$|FUy?dkEF_M72-W;H9+c8nNMfIA`y&41(bpGhp`BAlP7k0xJ@A zCO-zOfYNZDWB#EkL2P?AzmKzt1Cwt)^EDGIN%SwcIs~aDYZ}S$=FqUg0g>T?7OUNR z2)wY)>~7(CB+UIrnx;tEy%0}gA*a!FjRiUQ>+vaDVzDHqI*;?OkInhY~=BRS~ zQ9ECR9t-IWKa)7F5p&j!gPJXV*UhUS59dHij;yC+IQG#>!gSHM+At=gq0Ai1OVyjS z<5Kes@o)|bu>5oN8o9Y_*)&t||;=i>I=lSPXN%5z8rG~hyQy%*U z+CM@Iv_(RbsZH#g_}b~k#n&oyL4~%&j=ZgMrxind${l~Zp!mq5*R z4MHrksHpEoA9unQ%`_BCsn&HvN0I%Nxwa3G2SFDY9M>gPS@>V2+R#Zn zbgk5+GkG9LjDy3i=vSdxPo8+D*>u}+($-KSGC1wwZEj}K;tyf!sLJa}Ysqvk6`c;@ zk{LM&J85^C{rnoA@>Fx_rGQi20Tzt9bLRuTxMC`u5OpJ3%2&kdLN}AO=b=w!Lh?iv zQcFuq#u?LizH53c&~=crijIhQIo|)Aq)lNrbDv2G@)ZeKn{sR45-R)IcpdfPYzMP} z9rujVdqUY#K)2J}Z>j1{WvA3QS%2a(urA>!)P_4!;S(f*I*5|NBAkZ(>z?QDBt)yZ} z-yZU993@$xuZa1ynCHhh1t3Ss;;j>?@Xg?2zaTrkX?rCUxqZw6TKY8bwbbLktt`-2 zL|Z#W_qJl!GX>9M-yYKD4i=iJ=IO;XE|4d$eI??(aw>quXq1?ks6HHFwMtr$#>PoAM=Mkp}sLNMAB-Ra!Ij;p5@`xd3QsDgxNHbce2YJ(t{++(#P%`u6mw!Dyo_m5-ACJ=`s?W7xhnE-w~baKaNY zo~C#>J&ugscC2N27Ty1QX-rkrwlTvp8Y~irBoS{?Y8Ar&QoNM?y!A}`MzxSnl1>ua z%1@To0W&vGPfuV07rm<1gI~UjQ)#4){Gr|G5#(=8JxtIrcqw?W#^zmM?ZXcCfBf; zsnmVXO~rJr<4ai;rae3UDf6VkS?Gb^TnX*QpNP%QU<>UQ?~1;NVohdy3#YLfK4ukq zf?SE}4bTFnpg5YuWfYD*Fo8OJ#7c*mUMyj)o zk094xdB-Q^r~Bco`{BiSpjHJJUar0k@jTFP+DyfzfETPL`0l6sV3S`0y@6EA1pB;# z>gXN$ftvXFN9WntIGO$$1h5pkp*fh(9=Fg(x^i~&Vwl`G9;>SMJRrwm7m^$3h~L%? z&W`Ep*DoQJR);40q1sMeF*EhOblHn#S81;H^z^7=BGd;yDt(i6g}PzJ6;vF9YjAOA z{)4W+=-kuIbsWDZKr3DPmH1>;T7T*4GoQ=M%*?p`eT=otp&hdC*U<-7aos$L7?mfc z7x>u=K8)Cq*cno79+Ha--V_dQwR2|nH(sBYSXr@u^Mi4=io)|}D5^+K!F4C4DDInU zN>Q3lOtL+zgC>ft#AP$@k10Q;5^pnJp~Ck?j;i$e>VQT)zW7YtU(0_#LKv!2816Y zd}KXw_WEyYZqyCWf>r+cWl*%0E%~5}JBjo{^&Ryc1Ehspa2#oVxmmzFD13o0*3$W| zwIkvw;m1}*r=gEktjk^r2a^)XSc4H(vj6r1n5%uoJmkReDZX zjL@>sw1`f}(!T9WNKCxEUSkP8eB09#JSgCyb6JKk$TuM}5AzDu?{;tIPvf7n7mOPH zm_XtU=~hbH+`(p}{FM&t^}c?9!<+2T!EC$xa$x4D=tuMbR8XL67_2U0H}0 zHSvAv;^%8y`_v`HUKF*x2^cF%r~?ueFqAwZ(m?WeAFu)HWd~C4jbmeLf6N^-R)Hce*C6Yco;KeHs#xM0 zfr#-;ca!v=N=;AaCixjwBBvQBwEKhAyc!Q6uy;Ofjm|2nd^=AUH- zHa*>UWp#$s6dVLYi$iELe?tW*iBb7FVwM|l?TXZ!0wK5;Gd0X3q8ZwyXp*NP^`xBn zR-U@{tv`l!YX{=Am5XjoPoWIg?0WKpPFF4er+qK%q4IHUFeWa2?!8<3^|q&AfA&xa zMH=w({tiAKQVu;DCcTgQOYF@0Y{>)S0=SX%C#IN)8qXA4h9O0??aM@eT3RH~HBDmt z3<&d_ytc`cj#K=fS;y##j#bCG9!2GA)^N{v-GH{&)e|X-qr5WX`!XM@b`q}%?V3iI zo~w!1q_geTxy(ut5f$BOTkR(}$!Tyeg{j-RtT;ekork1|t%N;82(o+C99GJ&971V$ z^`{Q(zKysa@U-46Y)0-RT{p@DkT9{eUj3x6(Q;>{2DsGWG^WFBP0$!KyNJuH5YLTj-)lw^Jq<)QJ@!Lv)s zLbFg`%+^Pe2UJ{Ef@iYR4_A+f3FtIg_M@Q{OBc_&+V%#znLojK#l%8cQ)5SW6+hcA zZ?!xc#?~Z&sm`!`{>wS*>4kowRX=x4O-;1-Rtr*bCmcecM>Xe)g)_ z5e&3(b%8^NLa-AD4cOtCtfG$3fF+}rd#Nw({eyaOG3T!_*dLIOg~oK!e|*we({#(l zB$k}{MW2Pw^*X{zs*4)V8B*5G9eE>?2RFV?=9m}lJKGu1p{KyBLVA5Iu{EahvbB#? zaIm5culWJY)rgd@tSD4G#Eqt}zMUS&*6qK6^pOzPdfBBzuQ01wn-3J{+HPCu>guAs z1eJ*cQ?;vIS4V!}D&+@?trJ%hj+f_L z>Yjd&#D7R{MaPMoFPG*{msHW_*BJwGy;p1)c#X9G5ou%1Uo2c=CY1&GA43_Ql6UE* zBVU;heg$oNCR$E2ELj?(ydN*o3qqy#Aw9x-m$N^oOE#9v@C$B|0y!Fb1M6?MT& ztLXtu+@?y?-|aD6hkOtHetVH;28A#SgyQf{`&tQZ{Ttb8yTX6yPAm*b<4b>BNn}>&x2ZaVLX!}4KNC??(qyVb zF|di=WApu<4iTM7nP}Uio~M=<10!bq1~Q=2k82n9Tu+_;g}{#CUnF z#3}8}b%+f@?Z)uuU0%5ictbb}`J>wQ3NBKnHz{F7)BS}jvrgV;?w!j0sGEiQDJ$!lEJLy&Q}~IxUfPci&yO9A#jnd9h>9wqp6>tx6U1_G;b#m%n(ro?L(hT zzfO3?IPCv=QumIM)Gvslw~+@F*4Zdj7?nSEmwo@f7XWPv^6g6**NVaTq;pzxUYR${ zg6SC-*D!#l&ZJU4P$g0Z3ZQ&HG(!pALOKI7Xgz{kTI9g))rkK2sgE_!A#@k-{maBq zwLvBVP>>NfGIpQDgG-n0nx^kX%$oU6rxIa3$7!M8PVS&S@QFZ>s&{buah_@BlOOigx|iGViS_J z_JH)=Z5NZ5nbL-CA0CcH99G-_s$Tb3PnIsu<&~6t)IIR_<@8Jm(xM2pLUZsL(cyzZ zXz^Y%@DKG?k=Xn-BX@DcWv9&CEq66_u%9(k@^1pkX+pC2#{JYQ(Mrs6qZC&0tghRm z#JED@k$$BrIcs1i0aXG;zXJ3t&I?vDi*$e}$yQInoNVrxxin3RVBxF*$mnqrS_w4Si^Y5>g3$_p)#$IG|hQk6TjKOMxFP)nY}!O zksGi0#R37|=uxPn(V|YbB61WjfMfypAynmf_o~hNOYg8puFjN4w)&i~B9M)IfBw+4 z+7~x4T`rAYq|j!P{BgiO4P2_(GY9^(~6?g1*m^ea;{n+-OMEw%NyHZJH^S~+qz$DeSgZH%d8wpFmH1gVy zsKTV7Za4!p(GFyUV4428!O|X(O~?-fDX$a|zhEaSST(;7a&ij(wsM6H+Rm=xHx}b) zqI-?Spl%H*=}qb?qz9<&IS=OoSsM^))D3><@kS7$pkt+ASOn+}rCu-_x!|0FRm*bv zblTD@5RC&sZ{$R2CPH3aA`gQdDa7ZMvz<)TgJfOOa;VINTQy6DV-9j0LswTQS-aWQGn6sx;!R+>9|sI=^jvdzH3d!iRiJyGGT{d=I)@=2yQ zRb-nJ_2Qb~9D@V&2<~+Ko5^lHbqr@Z0rr4_b*5Z{b+DX3@&45_;%%lA@vv6S_Cd{?H zAGd`ItS@=LR1=#!|D6p>Y0mBgCL`MitJ};sQ7A6i#$v^I7=rYm_ij{AxeqZy-B^5t28P%c8uOuhhsrX z997xHRPOxa@LIWkxu1j;3m;{{HZM!c)^#B}!+lK1Vq?~xnQgiru3b4kQSR{)C^Yt< zC4u;CCt{3<5{t{Bp@;MiOOEOO2S8Wm@q%vA56{L72cjZ=6EUEfv`0M-djnf|_i|gm zc{N=lv>^(_2in{9K&=HV36U)m6We)q5M_KyF|ham>Y_mbl>AwAOv)Q$i(10OLuI;@ z{jwHBUjpMhC!T(xU#->Cya|Q+O8mzIRDOT~j8qt;_MzG?KwmN{vQ}-%f?2qv7NaU| z2257BThCQ_N-B1r;IUijXh-vMf4jkEc%bk(C;?ai#j5^Yw9Z{?$R8k`L^VUpIV#S? z-(fgEevCQ8imaNk5+Xr;3h09{LaGFS7Mo{y@)@9RFmrKXK>+Giha6wrITjX>zkrr3 zWDFX$j#gi2q6c2Nn(5?F`CTvzb<#Nf^2Q2dgc+$uAj2bgM9cuVQU7ibqUyOnku@rk z9(?d_Bh$h{L42pC6kqx@X0A2Jx5Ts^+%YePUB3VK+axq*PYR~-ZaQgZCJ(w4`657^ zZ4lysZ?HQe(mAN6b7P+6XczlZvc*oaT{%Uy{-Ji^wBu4w=2UcR-|q?s^VNATWC$uY zOQVl8b6(uLWrBDiva-zqFb6Mcnb=r!fCiIc)ya(q;+z^GNP_$u(!JgV&j2(Ov9#)!eQpXESt>Jb0vKJ*xUR7`*^@y!!iFv4 z+mX2iMhs3Ok!eKXw0O}&Kx0;v;E5`2OP$xVKr{*HwS-)KA4JoMeIH2OK%YA*zXxbp zy5cW(q4G8;v311Ed20%sObSA^J<5+9!0nT*2#XOGX#C1W<~trLD?jPwdqMeX`8m@0 zLQ+)EtZt6rPsv(Jum`OX8IIXAh$aGJI2dHn{yJ9yyfy4zWy$akrx~2p>_K+j35r%( z+7PcPJ6-Pi80qhCsDGp_1N2RD752AqeOHkV%nTiYL~H%ILcmY$T#U1`1sD>{0wl43 z`SJj-{jM3b{iE(4N)-A?sBB@=Y%O!oU*p?*iI`QnHoNM3Dei3o7Bg6CrQyFt3m;E$yBi}u`PS9XVjNF2KaOIO zRjpS31F>U#E?WyZtuG8??MQg=$r6JiY9~CPX?H<<$>Wm0e=pS2&^aU?lJ+Vae$#(1 zNT#Ek4pXbsLrZDdLc4T&%T-V-s=lbJ3NB{pjiuDUD3K1KB<5d|iv@B+N%I9&Gpy1^J?t!gFYpcj8eI3 z%Xf^A*~3veKHWA)Bbz8;yKC#$N+C||gOom~8fmNlDRUHrfKW1??F1ug^9g{yB$tVR zK*qmg|oaojq=|?J5ZSX5gw;lq~Xf zrw)W2gdG1|sMk{8s6tWmyX(WPC8Ao7P0zP{E>4$y0{y7KDFRo6et0_v2P1H`@J+-3 z+HTb%j5Fo|{$UKG`;ahhGxt?sR`LcklJ!8j#g&A!d{8IUt5(-+&Qv*@^i|{kq$yPr zjpj{+K9eHF!6Z8S_t3MBAe!M~pwG%EWU7EuQW>o#g~`E#c;*hFnZ@%5w}zd&A^izQ z8bFB;wQ1UysEfXti5olmQOb0f1xd33gTAXpodHrvTz>~bG%Eq2FqDW)|U zg{t{(M^XVHAE|z>2%%fI0wMN&v4#kt0_g_iVkZD<@AFDoqb}_+` zaeEJ-BZ-RyJ8BRZMZ#`hEEYI~1DH@zg9C8PZ#1EqElNXWkD+GXKugZ6DhQpNXa{ZJ zAT{p-^%`xiFih=}A?`K(Yh(4o$bu>f;hhNHa%E<_km$@W>}3{;?dF3gXSP$4V!5>k zQ;Zg9%$=*fIeuM*S}#O&h&zJ%Bod@n7OpZlFmcFjFu2yhZnxo^I}ah5bvDgxjFoG8Og_-U zqU~G&si1p9AJBprf0OgT*3fP!lEx+q$%n*r9*MIX{Qjm+C0hq*;KU~zKYsi`4*R2p z0H_9kO+T|$!vr2R1U)6hL+1`SGpY|qW~;9c$g9;M322k7fG}>!J!3o5y$GrH#XsOS zN1TIgws{hId4-*pU)|D6`J)O6VF?HZ^Da=u0=e5Ai;+EQ^2X4x$z|13eZW1(m#!V6 z29`^sdvY9;985^RMv42*UWV12ADfI(s=t<)RwSDL z=3-WRU#K+9p92pQcg=9-+QWMyBuz2{b8mj7H{U#uSSjt@o5A4_AXBAOK=}sB1E?-U z-xzH3`(tnO)wS~wn&G#ETnU&-_XdPt_3EW%LOW%EPaUb_BJtH*ZL7Y;O>H#ZiSx@o zRQEK#=YLKV6>JMk0ld=<075Vbu<9J5-3CF;jnmZcXWUx*okkNoWV%ame}QCP;QdYgv71&9PWk}D z>)AYn07X!+ebr$Jns8_|8o|L(^dMh~Lj69VKPO~94Z$@eLL}|AMO&j@DPyo38H=xbyrqcSlAqDA8^co?;Al?1sT+{gVZTTrIpyv zX&}Z(RVIRr(H992P#$TJn3A7WAy}6^66wN7t}?+c2|vmpb6j-Y1Z&pA%Y6QPJ;(}p zJf_OOqT;R%UQ17(53ZzYTrz-%(Ea%e3e{vfc3=?QZ$J3hDkcx|MT_Z;!_2*au_%na;`YW!Sk+on{s-xWp{Iglwn~W+J=?yp<*WJBI1t`OXVoA3U2!^esV<}Fco`Z)9dM`5n}mR8}dm}1Qe z7bhY=fIF7JmaHwA@BKCR21)&BqWjG~kA(JBZc7wU9B>A%+_8l*hhmG6V53EK@2Bt- zAf*!9EA?OdmEL8Qn4O_6MR>00=d+y*R(e%DDvhrTgApeUZwirK}3u>0TB5vlpUvzRSlv~xYmJ+)o5^7TplrG^4 ziYA^i%XcM6OO{!F7y8`SrSVH03m~4HV${c#+Ka@NdqWNx?o*m*+gF7&z-z2lJw^Bh za7+J6W$lwE9d`JGNRWpNE6_~pYt6Fd8@s}jLJ`)CA^#QjK>R#h%$m}5Q^egkOuK(O zOWVo)yLR7dvbN?53xENSN^^gouqV~U=4lRZzZ-O#Xq_GEkuY4xZ8fg_CdNv0mP87$ zx{OE=cBd#lgI`t%_EVYxz0o}qmO}0u+4lNF^!BdxJ+u8YsCw$pXOC)i2Y~AX%lJ1!5ZFQri;6es=BjpK)MnZvj3(=YVn)b$ zWT>*);dZkjtxCjiE-z?q_qctZh}nbLa?k&G2dAfP`{T`y&(G# z2$Bvwtm84why2?||yjiijp?)B)4zV^-l$krIW(rIZF4+v4I6;&sP_$?}B( z`%pFCIQR8zHV?zm^E-xehlHG#knsamdM^_RBrstTNVu!F3k^)3+h+-FzWzw?;Xfp7 zk;o!s0sSoLECrF?ob$_W)=i~_adcGg{}#sCTXi&v?zMu&?Nqw~y|4YXC=Vakjg!U9 z{OEl>l-X8IC~d$^L|+2*rw54}a`Y9#_M(iT5ZZoBplwa_kz6+sTurSUUzR~9v$HejVbm+lsX|(!7afqxj@RvJ)#P+$xUYQ?Ft%Jb$x_-h@{;P zWcc6GROVE(dmeNQR0(S?o$a~~4?c4lzgz8|69aJ|;=Tx;^kV7@B258(bEe>qeZAn0 zSyMRwr5&LzLn#3H0HbP34=rAK75#*#b>C7RwZ0E5Ch)`#I9`b#PWGv-yE2zM#|L{b z2^ZFQpUS+-o*W!EqfOT0(o6cO{J%DbrHQ>58CyZKPaY5WO(VGHzlMH|()CjPS?xyX z@0Y>~A>kwt0Svy;>_^?b{DGF-r#8g`d^-GN-Z^Z1&=+$=7XW(Lx6oy;${TU75LWac zxQ(6Lc0lG>jV^Z0h+=lDy*uMH$M2F!irBH+1qGp)+UP**?m!#U*|Q;tdBBj*hv-zc zWij4}+F9JRg0$v$#UpeMnTDh(REG(3gLZ9-D#9_Mx+)xGFX13Fr(TxxH->S7^Eb5G zUfJh!KJ|YgcAmhq(Ihas)e2XvH6kNcUkBZec`T(5QWFydLZk3xhYhX$ z-#w_yb1YwK|BciCTM$jbSLB#as({uxvQ7;m!iKtA|9Y>op7lLE zW>Spu!$$1?(NP9OE%g6$l#3`u3$P&MN+@VGo5GP>E2nUFu1{Lsx8K2DS3u5k#BU8l z)pNOBr(ddf7KRnd`dvi!!eBiNSu@lm* zkH4HgR?J5k-?V}+DHAuX%73g3Lk_)BzcOsOu`*oZNMZI!qwe;AUn+3z>%p$o;N>gD zcHgjx?PZEMQ#4!i_?CBsP@Ue?pbOP>i(hPC7;KjOCx(}FN( z5enoF$V5O;iut?EFR;OarJ*B+`l5R@l}&$6O;mFG#;;HQcEi~AQbzNQhQEP3C$L~@8`UialLVM=4zJ1oPYh9A$rr- zGL`=10nU9#P(cV31V8&>lQSmR!OC?!=AA8q7~cH#@FmjlmN!!TEtke2!DG6e>%w!= z4xSCk!v2@f-P;f1vIwpSKm4s5#ekXg0~;7^vs(-Yf}ZCS@(y+r;-SJ0Sn-`rtKr=f zB;%SXoETXV4_SsrosiqMr@_V>5@l&Ge+cTk<>?hKcNfY{p$jk%fpj*S?3n=we7vBY zmm71$F!9Q7RGcz3eCc?72SFP#)&tIGfn8k)=ue9Oz->!? ziyrfg?EK&;;OUqnc?JaCI*a=c54zp4#Wecxz35%iC%LQgz1XlJ+BeU$QCx{@vV*m$ zggZgLS%&^8?k!Nt6a=V>HgkL1-ArtS6&nMEFC=TFSb(AJ`dLi>e9Zj4xaYBDOi}K~ zFHphzqWl*MMGJDBaI-i=1mM8i)j?{N|5!%&#{ zUcjWBrW)tn10eI#s}RR(h80q2^pTr0tS z#R2g%X3@M_BzOiyw{O~$8$HychZYZQz5_|6AJuc)E-v8q+_;`&T{f39{QBtSMcV`G zOC@zJ7%MzRoC7pkfofYW9h+BS$JbwpUqB)#w4-e_^jR2O7Lw~lEPG+0A^8+UIS;7@ zZ~PZK@yy@2{d_W$h5HAuX_m~)149}Fg1UuqWFI_v7splZ5ijJtulg>;X6>4oebqcr z(`l@Q#E%Md!V&Tp`}AZ>^cUAHUr;4&nrw;)ay6xCEE+CA8p+%?msqHW<*TLjH>bi{ zKKmnz_wX$gE{~Vbno-xcXLhyb3fapGd0UX7^UiM6<-Wc=M_J&F9(e4}Oe;qJl}Yej zm7W0dtrsQAARlUXV(#I8!Yd-|OVe+hgLGApWBz4PU1IB;WQ>U4zaXNV`ka1<_xG{y zQuQKaKYF_>3-JB6lZO2a4ka}Irq3f^ND#Fx9Q=S&#s}Hn6f~Z3UGr&3sRec#N~TcC zw^YTs7E;u33;-LArOJ2xBQV)9RAclo{A@Z^G^1&-52{pDb&$;cWR8)pjrwh6sNkZ) zO^3v3f^1E<@!Mkp@Xu(#0mDj^FD{(z|0Lus`m`U8-nfXLbKPCEc=&TJ{+ah8?ZpBg zEboP9q`F8mQqih+KK&Qr!^#iNwb4TY=|5Riho~nuDlP<+!T$%xNnP!Cg};KIIAwr$ zT7oR}0$Z$t$eKEe2EkE&^v)$Vd>5!Y8%+5lcoO>m_-8+3O~Ql_L2vkJdk+Jo9-{yN zaQ=6Y{9j*T_5byk`AD9OB+t2sQY}dV0eJby>rX?t(`4F5O|BJ`<=%NS85|M;a6f*E z^Zhl&0>?;s(WQs@6fL#KpVNF28U&<@#m9(6%l2s|?>bli4a*I|Dz-1b>r|%JOt#~T zc?-l}J__MdxSe^s%HX;wb4HTP<>?JNIU&2U_O&yi?Q3U|n<)^CXU?g1q1B`#&QUk# z7iW**DpM*ph$oD84DL@<?-ZZT3V`c2r<`8k8*zCm%BENzjZ_u^a`s(pjI9v; zTCtj{x${VJqMDEK&toqZ}&ycFX@O(X7vf1#|16fbI<2 z`yR>X226ho4n7+aH9n`y36FF}7TaMzD(R=DCIlC{7HJsXCDr_(Oz!=)&ZA83Wv9sM zE0<$7mdDahP``W6jwwJwZgQgeK{5PE5c1Y3K$K1p{r+*^v~kjn`HA~=M%ggUn6=8O zetUU*LSO;8sx=s*UtEKeLOhIURPtE2zE;XsdTWK;gBcwXGUbo!(>4E0{^O%Px-n&Q zS4Ghb%7)h*qcN8i523Gz4P*I}6>MnnFlagf$^`P-kze+av zfx9x{davsS^;trbiMmI3-!$QFn-2M1<7W`PNsliSPnl8EWpa&XR8D>_;3ognF?vh* zk5wcZZwmO|sM>5R=;oQUd;Vu&i*p?*3#U1Fm5w<1o(u^|Xpr%8#9gIYQKE5dr@$GC zd+~>gm=!w9$SGu4Wi3%9+h}E~A&LGsuBWs ziY&oiAnCMwslD4^lutDYMM=A~5(Zh#mA_74v*FJF zxIghXadROY3lloi@&*i@M=&#?=m!kqefE>sBKI|ut*K&JX6i>ZDRU!)AU=J5b1)vJ zhuk%)W!a0*%4~KHGKBIV?#p>x=oLcm@cY8mzXJo8|M3HcpUbBel2sZ{h+f#I1+WU&h}A`O$qd?uwyb(>{orLW;i zr*w`~@b0|1t()mGyKLfJz*=P&@AP3xIu@GG;Hv*5pSSEx#q=!utW0dX7t5bjK5Wd< z&sMdoTVOSAft|^6EroSRHs~yP>E`l&Q#{>?50+`k1mkMfSFIo0d9xuv5w^TYK4~4} z66)R)A*EOT-#+6~vb0e>CO2f?_3thJal-Sma>w<0OJsj~*X3|#$>PcG?w+IAcFv>F z2&sO{G9ADE!)9FI>DmXrjTTz_s(6U|EZd7(oD)Yz>WBXInspidIAn<>;oGgwA3cw5 z)22GTr+o?!d95N!_;oG8en`~o$T!4sG-hrK%IiE~(m`fLVdZp#h_&~&0dkeedn=R6 zladB5xa;sBZKB3H_bW0>yF_cYAHamlcFN1j50oQ{$b!DMQt9@Sl{|8gW`NgpgA`Toqg^v#YPuTeV%#8geT%EtffT%AXq zI%!({++sd@k-oxQel;DBP>(TjxR-pepyA_M$oy<~rT=wqV9``cdRa{9;)d3}B zFhdju1$W)4_#8`Q0tDDXic;ZapLk{X%yU6?q~w?85i)BS^uRL+@H9(bomJ_wP7S@K zc+ZZNFZ&%iMwMeg&JTHdQ-Vb?E$NM8*|jv8%f>sAa!D(`p(0xL5=Xr1QjqhABx}dq zA!=OG5>TyoC!0|fp8YqODXUYX2>j%XY-1w%+%kqHEcY9-A^3k1(#|%sVti*8zt`PN zLbm8L@*-Ug1d}wK8muy-J6?1qf3lB3Ik{b-^UqGnO6Ne6d_cMQ&Wx-65))>hQh}EkwT2I!BGnt8V<-Diu3Uf6|La!6-S?iy?tZZ`*e$H zl3kpQ#z&a0LlTz8(KA-(TDEJd<_cgs|1R_=zA26_eJ#QRHql;oRjDf3uOFBMV7s7nuaZkGtQk7ye z%c7HK1Pe3MSRhsqXGX59F!i&mBx-&x_@}m~N#aL`tHUENE9eTB;N%nDaPeYB-oPqj zHzwi+lkz?}WpnB1CdlDjnrwWA7$MP%pj2i-x|sg27xD{Y9MN>EB6@QwM=pvFtUdXk zHPz-PE@d6dTeqg>jKni2Fj>N1Lv;t=-{$RBFuZ0G8Oiymcuu*$)#W^5M=oEEr%Y`} z^*9f?o#llKz=7<6`CM#v!}aFBxT7;C9;TgM(7n<13)v#1T_x%4{7Cm!**SM!YCeo0 z{?=`B8QRI8x%|~GX+A9$SqC1~9WR0Zy-p?XNQoW7Z98Uns5cw-#|r8iHmBgRlmIU> z;#HwS7Ir7FZx}68V2zJgL{*e;8V$EB&-_hYCS@0$sdGmSFK#7_>BhhfwFO*xaO0T=GP&(~O1R+( zo|T(noZ>e-G0(q;yPF{AahRj)w0pDab>w!P#uesEXa-iJW&FL%4Kjk=b~EP!v8Sr^ z<&b?jfO)CtY}U3TvxB(#XM^ORnSmZ3is|l8s=dLe?v}&Zs5aB6F~k^_W33C%Ho8K` zm)^L2KT%Hr2hU1Oa5_N}6O`9boypn?gnRoq5?a2b+_?E1`HcKmi>7Hzm%Ks21!P|0 zh&6;rzWi}^{i@wO*qZ9G-<7ndnu8jgwGm%ho)H_uE3Ay$jS~<%@#M?yc>p^lvLF8M z6@1>wSQO5*WcpiV?>>WDJs5G~W>}n*t_;(67i;7eUb-zV6;*bbd(}2N^8Q!(SriCG zliUNR3Szos$zw=lpdp_9Mlw@>FChyjSM7By5=QM+X2CNs%yDaho`+w#Ak%AwZken@ z3|FKM+G{)XCrQjoX4vr?rU)dN|Klod?uAS)>Xj}b^=#` zY>{3XA2~JF^&*rM;PCLDtP7IbR^mZ!CFAv)RrDqQL@z_n_e+Jc(pp){0ori;aP|MM z83ugm|NM^K|Ce9yG~ZmFSo?K3pcnF!JYLj)u#bmAm5guxZ6u8iG0v#xn2&KB_08MF z8=*20${GB;z^}jyFpOJ*O!TlCO%eQ%*39P4Dq3(v7O!l6q_>m0EoZbWw<4e{DgT1w z4`hJ~Cj(CTe7~G;F-FExjS zMZU|+w=~CHRN`-ctj2l909DvdhnCIUs=3z-X18WnNT>OpoNEqOJE(C8GMaCmOsqRL zMs$Ca!=MoPXaoNtP zCL}sgLJsVGr`<7YpE9v9A-NQ% zcF~%u%_dEX1|a)Ic1fFupNRmpqS5e>=^j^V?IRwJ4%CuKjei_*l12;$InJ3iS`^iv zVC^hmd09?*Gz)K^Jn02*aEyc*H|8ot|5LW~`}Cvy|n^d8jKO`S&HhCuCO&fh@^ zlqJ!r=jv?Pm!kN5ndRvCa6%}wI@+&}MR8A~KQZ-|^?Fyq=q*!4e4hC=MU#qsU4XTEga(>koqp3B{><}lWeypw z3BjncA7_Mw%l0L?9k}FH+oZATML*j3&o#ibA;9cCwZ0aTudnqHKUtRGNZh#XsbxLD^OFwHSbE-O9yiOJuxWu zHv`AS=twejXt!uWkV5?nB%S9;3jG<~@UuSC@wU8Wjju?^^FC3gXy{F!u_y8H;bGk-)WxcO~N<;GXH`xiJWE_y+A?{)59q91%$B=g?p^SN{nI!y|2ge^k z4*4aOO5HCcK&l9K@mu|F?=~-E`&t-f zWkRhUSa;cokEwl(_f9B>dd+;V!}D8w8}?>|O( zb|F>YM(gnuvHp^^YT_k&2U9f@t&z76Xg-?ye?;!p1aEa}po7Mpd_kuv5mPmzjc18P ze#G7(raQ7l@itfHmx*c_`mfuW1c#)U?lfy){|-4e^`q5j)-Rmvy?BhAZ7kHAFEvbC z^%{~VXiJ-wuFQA1Fmq`n)@n*7rrgoQ{>>s(HFnhPJ~?47%h;dEirqiTkcaT;|LE&j z8g6e93y}6G)-!yC=R2QFg=60F3f`xFfc*Q(pelYy)j=>5We9;#^tAMQ=BZY1^ z(qGpUcN&=0KUBOtzEH8sOhBPFk=sxH5|ai}G1p$zj}a4W6W_X=8Xq#E(qr2uOj#ic z)}4}(X0-Y6Jzpg=V(UCq-f}{76hY&_#lG-#s68dekHYk`Z7Y+32TCV(r^Yk6b-6Sk zyo51w!;i0Gr-$|eGyKJjxA~)0-g!DNIk9LtiN`5ahHbTKlIt~#9FkO2&MDJO)7xX` zR2}(f`o5d)o}_?zk*t$>$#YYfncJ&|{Lv(jW-amF;^uEK<{`cFJByEnh_uB@i8TVd zqMr(r38RFBc|^2>hO4faKCAMRV?T#36G#@Nyj;^Kh4ReX&&kpKf3ux*i1W%h@-##n zCwwi86Q#0-?`kJIETJUQUnovY&eS(32$ir~k($5*@#b}%Rq@3^H_q&aS{sixg*f!fEO znkPSK<`lWZIKcJrZm6BVtBf}_g;|A58O3N!ryIPu@4tSp?1t(^MW8PU{xzRURm_BP{ zdo@_c0p9SOz4&&vSVc26nRux{af0NQQRtq-Fhi#7?eEG#$mJ|6!SYocQ6q}XyTkz?XWXA0~sZDml>~rVq1bugSy7n?1 zrgk~tz1i~*6b^5}hCoL*%nbc{%Zt(ZFZIcH;9T(CL_T9Te`cR|hcD(CVPbV+j;==! zCIA^#59jVohk(kIrrX%j+@+W~71BlT2OJqfYvvPTJ!l<{E`xhq&)g5ix1fQ}1ySMM ziC~Zwj*%RD8r`D}G&Jw{cID@V1r)CvJo%bTQ^o8yG{LRs6hWl>BoI5A8P1i6w>3-W zXafU(E<+DpcyaL{i6rCYY#mmL$?T=#g~<$8FikYPjyQ&9DBdV7`lnyWz6Zw`C6zwc z+(e$kK>gR4`^|VR^eE*9LV;!+o0rKmz|UdbEhMmonPEJ7%F`-nV&zutoaSht`suPi zqbOTJ55xQzC15*MvOP^I$}>j&Pj{QdlobqnY@@hMQ1(;7B1SZ52dBgk*qtEtF1J{k zhQysEG-(857~agC0bh@rC@?glSHQgHa^*vw_BMg_jf5w^hT=#;RgI!0=N9b9t#q zCNs(_tU%D&x) zi?G~Cnn;{r6uBF~`3X0@^&apIReo!jaM_>3$6_Mdkwiejkg&aBXF-aU?i|Q=`Y!X} z)H8?lr>TB?t^Sh}1ot&r{jGK;Q}b$N zw2sEuJjg%0@KZxqSXyV+kQn=k5W@{~+m_6uKPd#9=z<%aN~|XsXIJTtXOQY%{FVJO z+3^6eX(>f>)CQCg57i~Rh5xhdhrA7SJXGk0Wk)%%gPQK-q9@#^$FDpH(2yEdosQ1e z9;m83XD_VPj^3p=wQVW=t8b61(0+5J@eYUOv#LF~2nac6?ECibXL~E$&vT`Gtk^o1 zts(5U2IcIfSU?vlon57vgRJr>ReG(kwsQfUU-#UpsmLK+s*e_W8XOpWc7n1n;@9Uo zNtMt3*RKecE;J0lkj`yTQw-JU_0p-!E-f@3D0@r{dAcVI0{34vXr6w)_PSW_x{C!aNUJ|Q_=9`1Dr6$l>KY;X zp*a$GGX}-PG!!f8*zhM9 zcOTFgExukd*cy>k8x~iOdpf)v(Iaym)k0fuIT^g(^oBm1KX;2wf@}D#dv8(Zd z=F5bJk-1#qs=;9*Ah{Ux3-tCdOavC^-E17%f3|((N7xaU5>215(hO%02fza*KOkD% zDn7Oxjv>ci=hi4h04OK?POC;a_A}hG*`1AZhqohZTg@6an!!A~3W^}HPsIdgKhtW6 z%aq_kgmBx*xJ>eVL%kF56k609LqQBNQg&puMLeB0|@w z4?lbUb1+QQAbDPELG^=uhv4foood(wtv4&>9dPDbk^2*sT(_#*sJ|)@6$M7_B~G;> zV7KVpN0$5fXW~H((NSG`JSkn@>^n0Umm>Dz_l`mTw-8*;duGy*Tq-lmV-l<`Z#nS*#a+DEMIulM$L92!6VX_Y z1GPnNf8Nd7Nw-XFn6G|P?zQG8bAguX)9Sr=$NW4=$^#=#G9T4zzE1XQzp)!C;2d$A z>=Kg#u?X5Kx+o>sYEV5dvoWkmLM2oj=8lWm97V6gNvR|B(B2IT;iwN_Gt3>2jnPQiaV^nvouQW?i%>!bqFrzHzCuv`VD;Q zN`;LS#+>PpAjaZ(S-fsZE88?=Uot{*dQneJ*ezD(h2Y z>%+#qYF}DrRAIjzm1=!6nX`t6_!vwR&Gyw4Gdbk0EH5GaYRdTTpTAXw2vxwYHSf!z zT<&7Da31#nH^8q9HyiUs)}g=Iql(k-aZiuyt3L;K4Q!Eb*lRg{Oxh(~zwL@~H|b8$ zBYLJGxZ5)*t|2rIsc`t+U_cXN1YQiTb1pJc>90~o;_(}TA(>10-3g1PRv6!P23Kgl z)z)5`YueAY`~sVeF*;!L`pS2U>p1X$-z0~mj+^SF{+FuIkv@YSumn5YVt654`_Z+^ zG_T6U$kWb`O$@%4!?C}36n0{nm5BSSnzSfq`>RO;qEG7L7o!oR@+yn>KkMKbtjTJ( m;o9T!+5dkz^5yco^}d1)ZOo7HVC{8Vm~N&5Cj6T zU%hhaCI|!pgFxVaV64EEa^-1W;2+rYrq%^eUYjrl_yKh|uX7#*D#RW7X|oUbeZcLC zi6;oeQP21T6H#yf0fA)hT)lMOz|V4iusl{+%V&Fe`)QhT$D!#1$8P2SiT&P`arIXC z_ogQ-aay8De}EdQ6&@w^`C^V~x|}h7BqIJO$Qc67q_1E-6B=Gu!2yPHa^R*NN1d`%G02dy-fq_7&`aHlXcp@c0Ak2ju zP++mt?&3>I$bNz%W@<+8ORD3I{slZ587y*xKwsYCt|-s#yCa;RMqp=lxoIcUw|@U#8LM4Z*bYIjzd zL=ELrIeN{f%b^)gUDZxl%$H-N)vuNNAIjbg%-9#sULAAybXzg|@(1dx46;f~Ws0+m zQFDsdsgz&BVc6H-xo_JjS`1>6{yi?G&Ea0C$=&hZpOekvxin<%tj(8Ht>hy~s#};mB?>`WrrY^f- zwwXce3#6!KCFywy&n=gI{V*5bgfPfnC?n357ssBXFPCOJmCM8Pez+vguYaYJ3-Ph8 zMUz;Zf92qEAO($BX(Sov#N=ta1TC)|qkNcO_NsW_NGx|95;n73=p%N~n%vKPmKT~* z(aS2FI&GP}DxcIld8QOj@o`i)D>W57vV`E)hiz(o(c7GAJs$P^nO?$`@Q5SN3%_w~ zuS`9Q>{K03SHAAre^#aGfJsf(<}=su!D*e>cHPy>JVch5s>b2Rx>ec4sa=eKsm(YJi?Tv#K&r8eUe)Y>!Bv zRZfr%w)EJ1)#c+PSTeAZQSDWpKuk__$C(V$bB5E&&a=0RXc4hT+9fIOAN_Q%)L?;E$Nu?A!Rq(k3S8_T|nA5fkBmYH;{(@|*b2l5m)#?RG+ zf(F!FlSMqg(n$0YE+2QD^J^fV;N$f6SaAvtcE##O+k4kHrnCDfM(4MdT}Ene!8|yv@gXW3;b(dypod#eYUx zRffctjeUDpL#jKf^AD*l?!--UwSs%}X%}^JDS?kvnt>w{3m3{i&)1~4dlI(2$+^|* zeHpVlaWOHvX*Hg+hiO?dLvaJaz6=RGr5Xdr6?2-jEL z@Y!NE0;l78N_*`_LPC4#U#`oin-u5Drb=bBNDai(zQUeFvzeZ!>Twi$FA~2oW|!ri zE$5n+K6|*8ABCH@8;BzVqD{qWu#;KI!vs5*CY3wh?OJ~)6Tc;|QT=(a7BOu`_#{XE zNDSl~J=EUd1NSDetyKMrreaXe@Fu@j~asz`!J`L~w~X$p!d!D7Bv z;eYrH%tmXqWJcgMl&vgUzO7mnhx9wdEQAdDPGm)k{;_cf zvdUb!p!Wb0PVpEY&nJ%8lq3OOX1Cy{?YfO^(b@zlw8atT1Dd>NY> z%q+71I()ZjGHR+wAkt~b@7yR>B9$w)VT^CPD7v2hdOVhXruX<;Rm%4QPJR?UUDu<1KRP;%iT%HQ+Lct*dnj zGH2AI%g1HPxA^CsD?=!BvTB##4Xeue1j!+ecVxbpyk^Jb0VU%iV2g;Xh{mnE6raql zsXy^i6i@EOsWRgA%kZgZx<@x&o*Pn%3dYZ$^4|7c4!mnB)*mJTa=WSQX1ZPWz+gB7 z@$^QBD`?*-^+-@{M3u)it18NiBVpv>uhMM;(w>%vkfPTxkZ=ZSGkap_gG^GD5Es7K z4{}OnHz5JpOHdBtI!I7lC#BFYrIjlLwI$DHb@FvTI-lS`5>Sh1!h(>{kx{vjABP;i z)bq;2P%+VUJm6{e!>1~_!m}z|f=ferYhx!Yj2)m)SlFAwZD`$U|jYt|2Li{>lGex5Qi+EOWPW zTb=t__hV&hzg~)ZF1q=`?zs+nt}P7KJ!BVR4f#1Pw*6W}J+Lg{jqt95QpJ1ot+vlj zFAkJ@x{ZE(Q1|kT1FN)A9$Qd_@1kgB&}L}@VS86yntxJbYj{D!L2DM>o62YxC#S#E zd`4%$>lpR@K6+Ycgh~Y(q66 zRy2BS8-It_UA<(rcj!%~A*lo5oMP(9Fu&QJ+-&^N=NQTQ;?33h9Q4M2mT+qP*B5k(Jtgtq>XrQH&`-5`oP_xu>G93;s3ckvpP?<;p$a} zWENId3QrmZtj?KqljWEi&f*YJ z?!r_`2uE{=5!>b?rfeOJSpNEv!G`0Q8v4d;!F%^S`3^fnDF9eu=8tQex}N(o4xh-^s%97Pn}}$r{49G?~Y} zL(0^#sSRFVvgtl^&cZ>nd7#ivtDD5he5aO|lQnw}$x_HVUeUSdzWo{{0lar}E?~={ zJvkSh;5pYbO1{T}&g`oTf0s7s*$7GN0VvY#@6Asc+ z7q-7%HQ&7aCe7;z(++1VjA|v+51um0w`89kz@x0XNjglS>*vxit%=G;aO`WdgU(fV z7l*2H&=ujkdh&`NR5I4!N46)!Z3Z>y>vr8F_};Tr4h*Yp)zJdSI5{hhS@pnmxBuQw z^Rm}u|EMZiTi+ZfSHA(gUgWR|KQmUMyYOHISc-~g=8Q>Y(mCIU$g-eKpKg*2bN@82 z2y6CQ!aoIZhxldhBRdSC6-;OK>Hy-tek4bFAG%BCL5T0PE8R0os zS82Ug;mGoUHP>#E2y^SOQY4v=b!c;K(Fh(4I0%2~L_@?8Lp@)nD@6N$|8`Zt3&1QZ z+WLq2uLU+2|GR+t{JILox89TA}T<0J}aRePKEpD$Y-&KClg6TV|4GX*@ z-l3_g08AbtXT(4&?lZ;x^zK&HN9&4DWLBKE)sZiyaE9+VX)xX6Pt_l~EV;6O3@B+u z3m+h71|0O-_shV}2=3GnX#Y~C_R8HS7N(~EsxJ)YS=ES^q5xBVC6fC9vv3`DTaXt- zaz_cI`{Qr(fQvhk#Ap$lCxbO1A*=3-K9sJEf}pz_aAo$W%W0kcy(j93U=D-aAX>MP z4FLgwX0HOMl#Ne%-f=tEl(*E7Jm|BxVlH`W zr+)08PefH8AP1~Wwq|ElF=MJb};p$v; zh1MEpNAPqo1i6C`1#l|&8~_idTZSBwm{=8`Ib#7ea`4STDLiVJW3$kAaVR@0Xh&x~ zW`(wmBQbjFKf*IZO%;r1mrvY)J`R_#j<&4y<7U-W+#0g?X%7Q3sS$jBCn*&qv;N53 zzhNTN)5I6zP>z81dP2S{d?v2uysatZx#H*UZ9M|5h`+V(C#?h zER0ZvP4&OI8lMoW#eGT;QTu9o2E8haX*)C>mZpV!xaH*h3_vh5e%qyq{%uh;dP+!Q z010h7&I4YpU|$k!m_N!wYg{3&T-hi)2#&;bN5&w|40G^ z@GAO{2SW4bHH+4T%mj{UC5)MTs$Div88xBSaOlcoJYbn6;Mt+7L*h75_`%IDJ&6Zy zKx>8MjZp)>kV`d0#69-!PTE+E0HW3pc#&pkPThw?_~E4Ix@=#nOO|J&cMLrnWd`lT zSvNvtR;1aZo>ZxPl;Co2ZP+9-{YE1^D*WC|N4(V3l>1I~KF<%Rc5FGWhe2 z)4aR%K`F@PG?-(&g-L!ZfA`BqfChb}Z!Ohx8tMi7R;Mm^Dj(-SeYHp`pIkd@uyaD3 zgtbB>hSj3X?N7ER8!hIaQ*o{XW!$Sb;x4!f?Rv_{H-MDcxEYYTX&W;W&2ctjy}4#a zwBr4{nZWHs$Tt1dSy7E(ATQ;!3n|?XLXr)+uKuQ|m@t5i1qOQmY?iArsM@mMhf^1H zJhHocfi)qM-e2NepXxW?Ujh&;25PPv`SQ8^XNgZ-?Jv&a3q(mlJHStX$PC>@xsx40 zrm44n>kRSQk`0Y1*p!$Sd7|{^ZVEf}MtYJGX&}fZXIW`Xi>+U^7>;y2#C*RvLH-GA zol>w>FgJBMe06(+HfxCcjgU%l5}N1X3shvML+h{6?B}Mqv8j zJ>+=??$M88pgl(d*f#2? z7PL`3v-~TrEiJgYIFmOlSc;kioGHtXQ4-HN29^VtF|TCT7;vcJ9rIds89ioiV%49* z2d*#mOrEraPNO#AS@{Ue;90GCfa2w$n=?biMR29&$08VJV7MbFO3sH(F-Q$Fv*!25 za;2abvYNUOM)7Fe@OYp}5S1YZbC_vWig}Y&P*Hr~{)pji`r7CKh-@;OLn2CO4r6qv@<=-LCyGXY6;kw zs3`J@HZvru*T@n$DE?kuhhHzzOfP9b^~7LXCSZ_h!y2C!j%NwFJigx3~_If?dwM;YSeB0)e|^~m%h0@EZ?Sf_|oD(f$H7cztjY`)bbkl)(F51MVm1s#oLL zKONqNXT!MIyZ&aK={d8YIx}hY9N1>w;M%#{{}RCr_7wK2Ur%GpfF@B2P=B{TYWG#t zFHC4Pg+3B(mpLlpH*U20Ox6fTY%ZkrQU8XG5ov43X5W(A5RS#L4vx%gD)Rc0+a};z z4ezR>TG99I(#d}X?2tHPy|6b;(Pd8JI{Vvg5Ew_z=s26O+{q$!ps&)+3w~4Wr=pY_ zAx84~cV|C;=X6*{TOattaPHQEZ_Oc%S?X(;AKB-m4jov>ZLgCttGzy(!`tw4?DKdeC1hJ!xJYYzBmXPW>6TI?rtLKh!?0M= z(v#!?>)f^$1m;K*>@7}JAwEeXqnNmF)=T{6Y=AH1 z1hYR`tvCoOv03AqzQ)ZpENEO~r?eU!Iklp<15|J-udf9;Qvo9kyMjw zfvU+HnHc^ZSgfb?O^<&Y@V8%$FR__QjtY~oR{IJ>D5RrKJIndO110n=w(_*@H%X`hnGFV%Q6VN2N9ntC1Fq%uy-8Mm2vyygJ72 zUPo=s8WsU5a9C9=HOGqki^g=GMa4(!3=}lggpg4Xo$D$;w*&Dbj^z@XA-(K$25 z=}{6Rs1FDXM{)@j~=)iQ*OTgo|QaIL~NDAKl22g-Aj@W@~jlleNg9PtUznZ`w zA7)I1cZ`%a5ecGw6-QA6HdLx7N$v3)C*YE)?RR7$ce-OGMu5D()B6BZzI~1{l$%5j zR|k#84_EpZ?QTF*fH|k)%*@&Pa()ij**>@zoH_Ob7&E}QWaN_b@)2M}t<~1XY<}20 z86RHvX?BHjGYKA`1VAsNT>UM@N=z^hMlBLk(+|`Q0*`#=`bNLmi+ZaYiy$Fi(uCClR^QK<{AR*Ej@;HMHPc1$XA8VJ!4?Sp7ba+} z^Z61Z09zM31X?&at-btaYLvkW+HHT4YJ3wGQ})#)ju3(witYURg3`MW9*F_EO~EHY z06ZGdK4L9iQNFyp_1`BzRWtls#rZC8twe#!X&K1a5}I+Ko~d?0ueMhzw`d<@EK=%h z9d7)pLd?bynl1F`O*j?<5bXzvV5eFY1~ol|LR(T_P3PUa7K!~`05SlmNZwoPd=Q&; zKAm=}F3*$27JCvhmxCb$i1gbtT3pHiGtEX%{%%t+l480B`*%Sqjik%^*bLpBf#3yi zRGNgfG(`#R-=R01e2gwdd%Fbo!Y`)8(34jwe!9D6E6|*&>sKFU@+S1U?GU0C=v%1sfd+UBs;KgqUA|j^xbbLT1Wp%VZ{0YVr*Xf9LY!Gj)V4U}U?bRGpBxcfyU;<{K`P_K% zs^Z|KEA3x_-bN9wJ*`!m?g(Uj`70|f05YQa#o^1S=U0`jg(dZp*}@|7jMo7d$mU08 zc`8vWWo869vhUIKKz@I+j^+Z`J`B1dcS!9T2~o@Fb!on7QU((cMxI|*GJR2ezlkbC zj8~wbV^5sD6HY>0hbn&*f{dxHjvbGI$|!tFZ_2AhXb;B~!84{wnUSEN#uiqtK?#Au z^cs84H;NkN|6wEcqDHGs9O zlz!ZE9n@wH*A+Nqb~reU!A2>cG44AzD(Lkqz@G* z>T;-|sgB*GU&(C=h=$Y^@CkOuNYJK4)IbRj=E=_T|2$(YpCflXTci{m$${fGK3%!tiXgZFCTEu|>T{bDXYbXUBstz)vDTM7Q&#*>T z;GdctkUj~%Z$=+#&0`U1il}9@y_4_!hTqFr#*wX`10})(iII;F4jJm5*@ewT==3-U zAbFmU$LfM_0VUsHG_4{rJLO~Rp1}dWP<=RlGgFfxia*frmV!JC>h==clQ^tup8^7u zPz>Z?eOP7i7GdV4$ZsQ7!cGB7?i#8JxXA6sXzV-uZZ0vP!1quwFoCSiM;%(?J>N33 zxmW|(xB!)KJ(77ysq?emqjnnl`idx@8IR3=kd%^N@m^%FD>e(1%Um{HXK$l%8^sx#)Y|j9UOO zKafa$7tgGTr`e8c^MZGx{|<9Z(D8>)XKIv?@@;t0?}Y%h+Atj{$jsk=6Po%L(9q(1 zP>bc4%TA{J4iA893?4tFyiU|1eR&P5J?6Cy;sy8SS>&KIf2RQkmq2i1u9_3P{^9`x z#c)3JmK3DpFMwu8Vt^Tn0i49_IZwZ0H03Xh0I+D-?)A&Ez@$rcsy3A6HLMIxyW4$6 zdrXYfhjSV({<9~WGtl^a&BZWd z_nANTWK;EBFqeYprl?!cu0Q-`S75kT1W*8hNX$-0KW5J+3Kbtu}(OB%V$ko#RqR$GpBZ-DtDldtPg!0AO~g&YWekp zy|xt8b-3Ds_GQlOAfNQde>Z;#?NvfH2B)};;9Cb?92QfhV-XZJ9(&)u2wQ^R~ zY*upVFFIu{E6<({+MtendU`Yr7!TRo+1+ThJ+&qfRr;tWQbKbZs$fde@#Qt(E^r@j zTFMPwFFfPWc3+z<-weNCSEwnSvo*>Y0&CP1<`<0;23SU}6a?e{wZz%z%DRw}3rzCh z%y=l0T)I_nol0C?7}S=2OSyLwy?`1hyMc)0tU7#4g0&I=`d%+*8);})=r$QuBO(k( z7bhG(t`b5Ie8f_9^jpME!&3kLeooQ*WH#v`hM#R*shuEr&)${-vg1?9-AS=q`CLQi z&VWXpIZ?JR!adv>Wu6q>oi~@cXlrW&4FF(f(Ou-XJDMK(KuOmJ7-Q)tfN5p97Bz6~ zt@pu2m?Y+1l$T+?>FdH!)ww=k0=J(1Hjn=lGI8JT>i?b7?EkG}e6uMmCeC>~U}-&s z&Y0&o7UOj6Sb&~$YNw-u=_1gE_fxfkf=FYz#{auNT>#pl0|akr7iiRE=W~qbmO}p< zK}Ovm7$({22Yk^8B82{5zFpk;&=GUNrN7u|>9b^tL5Sik&=41XZ(R6hBZsWM{d1*o z4MC)m^fYqm5CT97s{UcI?B|mi*^(S11T9JS=LfI!r(DH?q%UJ+-@r8Gy4kr135gryp%(eJ z-C3Dn&69=1R#ru`(h`D1UF_?RX}Ye1wku6!oBUG6Bw8a&E_>76RlmxX0r|o=pG+&| zD8Ws$kxms|LBdKwgf_2Q9Wf*9TK#o&;5aRPlW!5<^TPF(8j>JW9uFbh1J3+hXzB3= z64NElZ8d9wYYe-VFra9qrrC!vloajgI`7^`Kw^qQt-2=q)ca4nEa~BgOM5ewDWzmp zr2j_Ht56+M#%Ann%)oNjaA_1p$#Dbt$j-&ToaR)$Ufwm5JK;>QX}1A5y1b6vOyvCm zIs~c3jj_CWA^J#wi}A-cc2GU*N3V|TH2b>*0`i&PVEM#M;lPL;Ig42Q*jVjRCh^i1 z#a%yz-7i5&^yf?i+4@V|xu$ZupAapelG8`{@>SeoSvxkJ)YKkU+Fjb3PQ2kkJUk7F z1W|9w-oPHN+CX-E0E@dWYYOQ(D_lumd3>htQD#Y~cOQWidX;KiiG1VavPm^Ig*Jp4 zqp!OpIbrt)&uZ`g7%!@ad%EEfX6xGTSJ8$1qRwvSdu`?J=KOm1AFIMm2u$n?T?ZL} z4&^bdmJt?Fm@eydUVIrOP8p|YI)}BE0UmS+S^w61DmI5WhK%w1gHjsNV`v1ue%j5c zobn+m_NA<3uVguWK&c6N*e5U?E|->EzwY0$+E>b+_QP}YP_YOCg#OGL6VD5ZeJ}Ha zEPj{8Q>`QOGhBpCF*oy_kjt3=I4#N)4;Pg)!ZnglET48UD^58oKdO zwA56b>^B^Rv^zO;8J;Yg6P=lRuKLY-^e2|d}uBGb`f#BPL)qDhmVt|z6Z(DpN_z=TbB;_q0gNt^fPrf&B`6_ zFR-oa5yDQD+#$bn8mD`8;KYh8F3BX0z#<4Ad( zA9sQlP2p(pgAAo!??z&qF#s|R`)7ti*clf4||WYck?9LdUX*XaZ8 z5}ILNM`lH7JptsmOMk51IMCtq|NMM;_gm*K>!oe*CxT`UTg3Tp053pS5xST1E?D3D EA1n3$$p8QV literal 0 HcmV?d00001 diff --git a/docs/assets/images/megatron-gpt2-perf-test.png b/docs/assets/images/megatron-gpt2-perf-test.png new file mode 100644 index 0000000000000000000000000000000000000000..9fe5e66b239ef06e3277d361ee0ee371fa849d06 GIT binary patch literal 42069 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 +and then repeat the previous `git commit` command. + + +## Testing +DeepSpeed tracks two types of tests: unit tests and more costly model convergence tests. +The model convergence tests train +[DeepSpeedExamples](https://github.com/microsoft/DeepSpeedExamples/) and measure +end-to-end convergence and related metrics. Unit tests are found in `tests/unit/` and +the model convergence tests are found in `tests/model/`. + +### Unit Tests +[PyTest](https://docs.pytest.org/en/latest/) is used to execute tests. PyTest can be +installed from PyPI via `pip install pytest`. Simply invoke `pytest --forked` to run the +unit tests: +```bash +pytest --forked tests/unit/ +``` +You can also provide the `-v` flag to `pytest` to see additional information about the +tests. Note that [pytest-forked](https://github.com/pytest-dev/pytest-forked) and the +`--forked` flag are required to test CUDA functionality in distributed tests. + +### Model Tests +Model tests require four GPUs and training data downloaded for +[DeepSpeedExamples](https://github.com/microsoft/DeepSpeedExamples/). + +To execute model tests, first [install DeepSpeed](#installation). The +[DeepSpeedExamples](https://github.com/microsoft/DeepSpeedExamples/) repository is cloned +as part of this process. Next, execute the model test driver: +```bash +cd tests/model/ +pytest run_sanity_check.py +``` +Note that the `--forked` flag is not necessary for the model tests. + +## Contributor License Agreement +This project welcomes contributions and suggestions. Most contributions require you to +agree to a Contributor License Agreement (CLA) declaring that you have the right to, and +actually do, grant us the rights to use your contribution. For details, visit +https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need +to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply +follow the instructions provided by the bot. You will only need to do this once across +all repos using our CLA. + +## Code of Conduct +This project has adopted the [Microsoft Open Source Code of +Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the +[Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact +[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or +comments. diff --git a/docs/index.md b/docs/index.md index a7a7e0e428b4..cda12b9dad07 100644 --- a/docs/index.md +++ b/docs/index.md @@ -71,7 +71,7 @@ optimizations on advanced hyperparameter tuning and optimizers. For example: * DeepSpeed trains GPT2 (1.5 billion parameters) 3.75x faster than state-of-art, NVIDIA Megatron on Azure GPUs. - *Read more*: [GPT tutorial](./docs/tutorials/MegatronGPT2Tutorial.md) + *Read more*: [GPT tutorial](/tutorials/megatron/) @@ -105,8 +105,7 @@ combination. ZeRO boosts the scaling capability and efficiency further. significant performance gains compared to using model parallelism alone. *Read more*: [technical report](https://arxiv.org/abs/1910.02054), - and [GPT tutorial](./docs/tutorials/MegatronGPT2Tutorial.md). - + and [GPT tutorial](/tutorials/megatron). ![DeepSpeed-vs-Megatron](/assets/images/DeepSpeed-vs-Megatron.png)

@@ -120,13 +119,7 @@ optimizers such as [LAMB](https://arxiv.org/abs/1904.00962). These improve the effectiveness of model training and reduce the number of samples required to convergence to desired accuracy. -*Read more*: [Tuning tutorial](./docs/tutorials/1Cycle.md), - +*Read more*: [Tuning tutorial](/tutorials/1Cycle). ## Good Usability @@ -166,23 +159,9 @@ overview](features) for descriptions and usage. -# Further Reading - -| Article | Description | -| ---------------------------------------------------------------------------------------------- | -------------------------------------------- | -| [DeepSpeed Features](features.md) | DeepSpeed features | -| [DeepSpeed JSON Configuration](config_json.md) | Configuring DeepSpeed | -| [API Documentation](/code-docs/) | Generated DeepSpeed API documentation | -| [CIFAR-10 Tutorial](./docs/tutorials/CIFAR-10.md) | Getting started with CIFAR-10 and DeepSpeed | -| [Megatron-LM Tutorial](./docs/tutorials/MegatronGPT2Tutorial.md) | Train GPT2 with DeepSpeed and Megatron-LM | -| [Learning Rate Range Test Tutorial](./docs/tutorials/lrrt.md) | Faster training with large learning rates | -| [1Cycle Tutorial](./docs/tutorials/1Cycle.md) | SOTA learning schedule in DeepSpeed | - - - # Contributing DeepSpeed welcomes your contributions! Please see our -[contributing](CONTRIBUTING.md) guide for more details on formatting, testing, +[contributing](/contributing/) guide for more details on formatting, testing, etc. ## Contributor License Agreement From 27deec1a765f58f3bf212568fed4ca1daafeea2f Mon Sep 17 00:00:00 2001 From: Shaden Smith Date: Wed, 18 Mar 2020 00:06:33 -0700 Subject: [PATCH 6/7] file ending --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 655582ead0b1..9763e3a8cf09 100755 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ optimizations on advanced hyperparameter tuning and optimizers. For example: * DeepSpeed trains GPT2 (1.5 billion parameters) 3.75x faster than state-of-art, NVIDIA Megatron on Azure GPUs. - *Read more*: [GPT tutorial](https://www.deepspeed.ai/tutorials/megatron.md) + *Read more*: [GPT tutorial](https://www.deepspeed.ai/tutorials/megatron/) From 8fe182b3397f1f350442156a731a17d938994766 Mon Sep 17 00:00:00 2001 From: Shaden Smith Date: Wed, 18 Mar 2020 00:24:55 -0700 Subject: [PATCH 7/7] azure links --- docs/_data/navigation.yml | 2 ++ docs/_tutorials/azure.md | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/_data/navigation.yml b/docs/_data/navigation.yml index e4f9cb89e1fb..bd896797f76d 100644 --- a/docs/_data/navigation.yml +++ b/docs/_data/navigation.yml @@ -29,6 +29,8 @@ lnav: - title: "Tutorials" url: /tutorials/ children: + - title: "Getting Started on Azure" + url: /tutorials/azure/ - title: "CIFAR-10" url: /tutorials/cifar-10/ - title: "Megatron-LM GPT2" diff --git a/docs/_tutorials/azure.md b/docs/_tutorials/azure.md index f37d8f4a6abe..8f3ed2fd9959 100644 --- a/docs/_tutorials/azure.md +++ b/docs/_tutorials/azure.md @@ -1,4 +1,6 @@ -# DeepSpeed with Azure +--- +title: "Getting Started with DeepSpeed on Azure" +--- This tutorial will help you get started running DeepSpeed on [Azure virtual machines](https://azure.microsoft.com/en-us/services/virtual-machines/). @@ -58,7 +60,7 @@ Next, we need to configure the VM environment for DeepSpeed. We provide a script ```bash ./setup_vms.sh ``` -to generate a [hostfile](../README.md#resource-configuration) and SSH +to generate a [hostfile](/getting-started/#resource-configuration-multi-node) and SSH configuration on all of the VMs. This configuration will be used by the DeepSpeed Docker containers in the next step. @@ -72,7 +74,7 @@ background. This will take several minutes since it needs to pull the entire Doc image. ## Access VMs -The tool [azure_ssh.sh](azure_ssh.sh) will let you SSH into any of the VMs with this +The tool `azure_ssh.sh` will let you SSH into any of the VMs with this syntax: ```bash ./azure_ssh.sh [command] @@ -122,7 +124,7 @@ the first DeepSpeed container: ## Megatron-LM GPT2 DeepSpeed includes an example model using Megatron-LM's GPT2. Please refer to the full -[Megatron tutorial](../docs/tutorials/MegatronGPT2Tutorial.md) for more details. +[Megatron tutorial](/tutorials/megatron/) for more details. * In order to fully train GPT2 with DeepSpeed and ZeRO we recommend using 8 instances of Azure's Standard_ND40rs_v2 SKU for a total of 64 NVIDIA V100 GPUs. With this setup and a batch size of 1536 you should be able to complete 100k training steps (153.6 million