Repository: Xilinx/inference-server (language: python)

Issue:
Add ensembles to documentation
#176 and #178 add simple model ensembles but this functionality is not well-documented


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index bc163cba4..86293930f 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -47,13 +47,18 @@ Changed
 * Use const references throughout for ParameterMap (:pr:`172`)
 * Update workers' ``doRun`` method signature to produce and return a batch (:pr:`176`)
 * Use TOML-based configuration files in the repository by default (:pr:`178`)
+* Location of test model lists moved to ``tests`` directory (:pr:`180`)
 
 Deprecated
 ^^^^^^^^^^
 
+* N/A
+
 Removed
 ^^^^^^^
 
+* N/A
+
 Fixed
 ^^^^^
 
@@ -65,6 +70,8 @@ Fixed
 Security
 ^^^^^^^^
 
+* N/A
+
 :github:`0.3.0 <Xilinx/inference-server/releases/tag/v0.3.0>` - 2023-02-01
 --------------------------------------------------------------------------
 
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 7072b5025..960e8dd47 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -63,7 +63,7 @@ Raise pull requests
 A pull request should be made against an active issue.
 An active issue indicates that it has gone through a discussion already and is approved for development.
 You can fork the repository, make your additions and raise a pull request.
-Remember to `sign your git commits <Sign your work>`_.
+Remember to :ref:`sign your git commits <Sign your work>`_.
 The pull request will be reviewed by an owner and eventually approved for testing.
 If the automated testing passes, then it can be merged in.
 All code is licensed under the terms of the LICENSE file included in the repository.
diff --git a/README.rst b/README.rst
index d69b1b9d4..45039e410 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -38,13 +38,14 @@ The AMD Inference Server is integrated with the following libraries out of the g
 * TensorFlow and PyTorch models with `ZenDNN <https://developer.amd.com/zendnn/>`__ on AMD CPUs
 * ONNX models with `MIGraphX <https://github.com/ROCmSoftwarePlatform/AMDMIGraphX>`__ on AMD GPUs
 * XModel models with `Vitis AI <https://www.xilinx.com/products/design-tools/vitis/vitis-ai.html>`__ on AMD FPGAs
-* A graph of computation including as pre- and post-processing can be written using `AKS <https://github.com/Xilinx/Vitis-AI/tree/v2.5/src/AKS>`__ on AMD FPGAs for end-to-end inference
+* A graph of computation including as pre- and post-processing can be written using `AKS <https://github.com/Xilinx/Vitis-AI/tree/v3.0/src/AKS>`__ on AMD FPGAs for end-to-end inference
 
 Quick Start Deployment and Inference
 ------------------------------------
 
 The following example demonstrates how to deploy the server locally and run a sample inference.
 This example runs on the CPU and does not require any special hardware.
+You can see a more detailed version of this example in the `quickstart <https://xilinx.github.io/inference-server/main/quickstart_inference.html>`__.
 
 .. code-block:: bash
 
diff --git a/ROADMAP.rst b/ROADMAP.rst
index 4e204a092..a7235fdf2 100644
--- a/ROADMAP.rst
+++ b/ROADMAP.rst
@@ -19,7 +19,7 @@ Roadmap
 
 The AMD Inference Server is in active development and this is the tentative and non-exhaustive roadmap of features we would like to add.
 Of course, this is subject to change based on our own assessment and on feedback from the community, both of which may affect which features take priority over others.
-More detailed information about the work that's ongoing and/or completed can be found in the :ref:`change log <Changelog>` and the `Github roadmap <https://github.com/Xilinx/inference-server/projects/3>`__.
+More detailed information about the work that's ongoing and/or completed can be found in the :ref:`change log <Changelog>` and the `Github roadmap <https://github.com/orgs/Xilinx/projects/7>`__.
 
 2022
 ----
diff --git a/docker/generate.py b/docker/generate.py
index 24d94a6de..feb1aac2b 100644
--- a/docker/generate.py
+++ b/docker/generate.py
@@ -703,9 +703,11 @@ def install_python_packages():
                 sphinx_copybutton \\
                 sphinxcontrib-confluencebuilder \\
                 sphinx-argparse \\
+                sphinxemoji \\
                 sphinx-issues \\
                 exhale \\
                 sphinx-tabs \\
+                sphinx-tippy \\
                 sphinxcontrib-openapi \\
                 sphinxcontrib-jquery \\
                 # install linting tools
diff --git a/docker/template.dockerfile b/docker/template.dockerfile
index 6dc223bcb..60f431ad4 100644
--- a/docker/template.dockerfile
+++ b/docker/template.dockerfile
@@ -37,7 +37,7 @@ ARG TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
 # image type to build. This must be 'dev' or 'prod'
 ARG IMAGE_TYPE=${IMAGE_TYPE:-dev}
 
-# enable building platforms. By default, all platforms are opt-in
+# enable building backends. By default, all backends are opt-in
 ARG ENABLE_VITIS=${ENABLE_VITIS:-no}
 ARG ENABLE_TFZENDNN=${ENABLE_TFZENDNN:-no}
 ARG TFZENDNN_PATH
@@ -71,7 +71,7 @@ RUN if [[ ${TARGETPLATFORM} == "linux/amd64" ]]; then \
     && rm -rf /tmp/*
 
 # this stage builds any common dependencies between the inference server and
-# any of the platforms. Using common packages between the two ensures version
+# any of the backends. Using common packages between the two ensures version
 # compatibility. Note, some of the packages here are also used implicitly
 # by subsequent build stages
 FROM dev_base AS common_builder
diff --git a/docs/README.rst b/docs/README.rst
new file mode 100644
index 000000000..3b70ce699
--- /dev/null
+++ b/docs/README.rst
@@ -0,0 +1,43 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Documentation
+=============
+
+This directory contains the raw files used to build the `online documentation <InferenceServerDocumentation>`_.
+As such, this directory is not intended to be read directly because many of the links and images are only populated in the web documentation.
+
+Build the docs
+--------------
+
+Building the documentation requires Sphinx, Doxygen, and many other packages.
+The developer container has all of these dependencies and is currently the only supported way to build the documentation.
+The regular CMake build of the inference server adds two targets, ``doxygen`` and ``sphinx``, that can be used to build the documentation.
+In the development container:
+
+.. code-block:: console
+
+    $ amdinfer make doxygen
+    $ amdinfer make sphinx
+
+After running these commands, the documentation is built in ``build/docs/sphinx``.
+
+Deploy the docs
+---------------
+
+The easiest way to deploy the documentation is to use the ``deploy.sh`` script.
+This script must run in the development container and you must first build the inference server with ``amdinfer build`` beforehand.
+If you want to deploy to a specific version of the documentation, update the ``VERSION`` variable in the script prior to executing it.
+This script will update the links in the README to point to the appropriate version, build the documentation as described above, and push the built documentation to the ``gh-pages`` branch.
diff --git a/docs/aks.rst b/docs/aks.rst
index 273848794..da3a69a98 100644
--- a/docs/aks.rst
+++ b/docs/aks.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,8 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-.. _AKS:
-
 AKS
 ===
 
diff --git a/docs/cli.rst b/docs/amdinfer_script.rst
similarity index 79%
rename from docs/cli.rst
rename to docs/amdinfer_script.rst
index f8baaa728..d3c72ae7a 100644
--- a/docs/cli.rst
+++ b/docs/amdinfer_script.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,10 +14,10 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-Command-Line Interface
-======================
+amdinfer Script
+===============
 
-The :file:`amdinfer` script provides an easy way to launch containers and build the server during development.
+The *amdinfer* script provides an easy way to launch containers and build the server during development.
 The documentation for the options available in this Python script can be seen here or on the terminal using the ``--help`` flag.
 
 .. argparse::
diff --git a/docs/architecture.rst b/docs/architecture.rst
index 4a9c09e80..b111277b1 100644
--- a/docs/architecture.rst
+++ b/docs/architecture.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -97,7 +97,7 @@ gRPC
 ^^^^
 
 The gRPC functionality is provided through a custom implementation of a gRPC server.
-There are some examples in the `gRPC repository on Github <https://github.com/grpc/grpc/blob/master/examples/cpp>`__ that can be used for reference.
+There are some examples in the :github:`gRPC repository on Github <grpc/grpc/tree/master/examples/cpp>` that can be used for reference.
 It makes new dynamic objects to keep track of the incoming requests and a state machine is embedded inside to track state.
 A pointer to this object, ``CallData``, is put into the callback for the request so when the worker finishes this request, it will use it to respond to the request.
 After the response, the state machine is marked to finish and the object deallocates itself.
diff --git a/docs/backends.rst b/docs/backends.rst
new file mode 100644
index 000000000..2e225e346
--- /dev/null
+++ b/docs/backends.rst
@@ -0,0 +1,36 @@
+..
+    Copyright 2022 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Backends
+========
+
+The AMD Inference Server supports a number of backends.
+Each backend has its own sets of features and capabilities, which are summarized at a high-level in the table below.
+You can see more information about each backend on its own page.
+
+.. csv-table::
+    :header: Backend,Hardware,Model Formats,Model Support
+
+    :ref:`CPlusPlus <backends/cplusplus:CPlusPlus>`,CPU \| GPU \| FPGA,.so,✔
+    :ref:`MIGraphX <backends/migraphx:MIGraphX>`,GPU,.mxr \| .onnx,✔
+    :ref:`PT+ZenDNN <backends/ptzendnn:PtZenDNN>`,CPU,.pt,⚠
+    :ref:`TF+ZenDNN <backends/tfzendnn:TfZenDNN>`,CPU,.tf,⚠
+    :ref:`Vitis AI <backends/vitis_ai:Vitis AI>`,FPGA,.xmodel,✔
+
+.. toctree::
+    :hidden:
+    :glob:
+
+    backends/*
diff --git a/docs/backends/cplusplus.rst b/docs/backends/cplusplus.rst
new file mode 100644
index 000000000..b6aae127f
--- /dev/null
+++ b/docs/backends/cplusplus.rst
@@ -0,0 +1,140 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+CPlusPlus
+=========
+
+The CPlusPlus backend can run arbitrary C++ code targeting any hardware accelerator that adheres to the expected interface.
+
+Model support
+-------------
+
+Since this backend is for running C++ code, anything you can compile to a shared library correctly should work with this backend.
+It supports models with multiple input and output tensors.
+
+Hardware support
+----------------
+
+Depending on the content of the shared library, the backend could target CPUs, GPUs or FPGAs or other hardware accelerators.
+You will need any compile-time or run-time dependencies of what you are running if it requires additional software.
+
+Host setup
+----------
+
+Any setup needed for the host will depend on which models you want to deploy and what hardware/software they use.
+Follow the directions for the original tools you are using.
+
+Build an image
+--------------
+
+To build an image with the CPlusPlus backend enabled, you don't need to add any special flags.
+It is always enabled.
+
+.. code-block:: bash
+
+    # create the Dockerfile
+    python3 docker/generate.py
+
+    # build the development image $(whoami)/amdinfer-dev:latest
+    ./amdinfer dockerize
+
+    # build the development image $(whoami)/amdinfer-dev-basic:latest
+    ./amdinfer dockerize --suffix="-basic"
+
+    # build the deployment image $(whoami)/amdinfer-basic:latest
+    ./amdinfer dockerize --suffix="-basic" --production
+
+Start a container
+-----------------
+
+Depending on your use case and how you are using the server, you can start a container to use this backend in multiple ways.
+
+Deployment
+^^^^^^^^^^
+
+You can start a deployment container with something like:
+
+.. code-block:: console
+
+    $ docker run [--device ...] [--volume ...]
+
+Depending on the requirements of the models you want to deploy, you may need to pass hardware devices to the container using the ``--device`` flags or mount volumes with ``--volume`` flags.
+
+Development
+^^^^^^^^^^^
+
+A development container can be started with:
+
+.. code-block:: console
+
+    $ ./amdinfer run --dev
+
+This automatically publishes ports and mounts some convenient directories, such as your SSH directory, and drops you into a terminal in the container.
+
+Get test assets
+---------------
+
+Assets and models used with this backend are always downloaded so you can get them with any flags to:
+
+.. code-block:: console
+
+    $ ./amdinfer get
+
+Loading the backend
+-------------------
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_intro
+    :end-before: -loading_the_backend_intro
+
+.. tabs::
+
+    .. code-tab:: c++ C++
+
+        // amdinfer::Client* client;
+        // amdinfer::ParameterMap parameters;
+        std::string endpoint = client->workerLoad("cplusplus", parameters)
+
+    .. code-tab:: python Python
+
+        # client = amdinfer.Client()
+        # parameters = amdinfer.ParameterMap()
+        endpoint = client.workerLoad("cplusplus", parameters)
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_modelLoad
+    :end-before: -loading_the_backend_modelLoad
+
+Parameters
+^^^^^^^^^^
+
+You can provide the following backend-specific parameters at load-time:
+
+.. csv-table::
+    :header: Parameter,Type,Usage
+
+    ``batch_size``,integer,Requested batch size for incoming batches
+    ``model``,string,Full path to the shared library to load. Alternatively, you can pass a string not ending with ``.so`` and the backend will convert it to ``lib<model>.so`` and use the runtime loader to load this shared library.
+
+Troubleshooting
+---------------
+
+If you run into problems, first check the :ref:`general troubleshooting guide <troubleshooting:Troubleshooting>` guide.
+Then continue on to this CPlusPlus specific troubleshooting guide.
+You will need access to the machine where the inference server is running to debug.
+
+TODO
+
+.. |platform| replace:: ``amdinfer_cpp``
diff --git a/docs/backends/migraphx.rst b/docs/backends/migraphx.rst
new file mode 100644
index 000000000..481ca5198
--- /dev/null
+++ b/docs/backends/migraphx.rst
@@ -0,0 +1,162 @@
+..
+    Copyright 2022 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+MIGraphX
+========
+
+The MIGraphX backend executes an ONNX or MXR model on an AMD GPU.
+
+Model support
+-------------
+
+The MIGraphX backend should support most ONNX files and it supports models with multiple input and output tensors.
+The tested models are listed below:
+
+.. csv-table::
+    :header: Model type,Tested models
+
+    Classification,ResNet50
+    Object detection,YOLOv4
+
+Other models should also work but are currently untested.
+
+MXR is an MIGraphX-compiled format.
+When given an ONNX file, the MIGraphX backend will compile it to an MXR file.
+This MXR file will be different depending on the GPU as well as some load-time parameters such as batch size.
+If you move MXR files from one server to another, make sure they were compiled for the hardware on the new server.
+
+Hardware support
+----------------
+
+While not every model is tested on every GPU, the MIGraphX backend has run at least one model on the following devices:
+
+.. csv-table::
+    :header: Classification,Name,ID
+
+    CDNA,MI100,gfx908
+
+Other devices and DPUs may also work but are currently untested.
+
+Host setup
+----------
+
+Follow the `ROCm installation instructions <https://docs.amd.com/category/Release%20Documentation>`__ to install ROCm on your host machine.
+Your ROCm version should ideally match the version installed in the inference server container but mismatching versions may work as well in some cases.
+Ensure you can detect the GPUs on your host machine with ``/opt/rocm/bin/rocminfo``.
+
+Build an image
+--------------
+
+To build an image with MIGraphX enabled, you need to add the ``--migraphx`` to the ``amdinfer dockerize`` command:
+
+.. code-block:: bash
+
+    # create the Dockerfile
+    python3 docker/generate.py
+
+    # build the development image $(whoami)/amdinfer-dev:latest
+    ./amdinfer dockerize --migraphx
+
+    # build the development image $(whoami)/amdinfer-dev-migraphx:latest
+    ./amdinfer dockerize --migraphx --suffix="-migraphx"
+
+    # build the deployment image $(whoami)/amdinfer-migraphx:latest
+    ./amdinfer dockerize --migraphx --suffix="-migraphx" --production
+
+Start a container
+-----------------
+
+Depending on your use case and how you are using the server, you can start a container to use this backend in multiple ways.
+
+Deployment
+^^^^^^^^^^
+
+You can start a deployment container with something like:
+
+.. code-block:: console
+
+    $ docker run --device /dev/kfd --device /dev/dri [--volume ...]
+
+These ``--device`` flags pass the GPU to the container and you can mount other directories as needed to make models available.
+
+A development container can be started with:
+
+.. code-block:: console
+
+    $ ./amdinfer run --dev
+
+This automatically adds the detected devices, publishes ports, and mounts some convenient directories, such as your SSH directory, and drops you into a terminal in the container.
+
+Get test assets
+---------------
+
+You can download the assets and models used with this backend for tests and examples with:
+
+.. code-block:: console
+
+    $ ./amdinfer get --migraphx --all-models
+
+Loading the backend
+-------------------
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_intro
+    :end-before: -loading_the_backend_intro
+
+.. tabs::
+
+    .. code-tab:: c++ C++
+
+        // amdinfer::Client* client;
+        // amdinfer::ParameterMap parameters;
+        std::string endpoint = client->workerLoad("migraphx", parameters)
+
+    .. code-tab:: python Python
+
+        # client = amdinfer.Client()
+        # parameters = amdinfer.ParameterMap()
+        endpoint = client.workerLoad("migraphx", parameters)
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_modelLoad
+    :end-before: -loading_the_backend_modelLoad
+
+Parameters
+^^^^^^^^^^
+
+You can provide the following backend-specific parameters at load-time:
+
+.. csv-table::
+    :header: Parameter,Type,Usage
+
+    ``batch``,integer,Requested batch size for incoming batches. Defaults to 64.
+    ``model``,string,Full path to the model file to load
+    ``pad_batch``,boolean,Use the first request to pad out the incoming batch if it contains fewer requests than the batch size. Defaults to true.
+
+Troubleshooting
+---------------
+
+If you run into problems, first check the :ref:`general troubleshooting guide <troubleshooting:Troubleshooting>` guide.
+Then continue on to this XModel specific troubleshooting guide.
+You will need access to the machine where the inference server is running to debug.
+
+Gotchas
+^^^^^^^
+
+Some common easy-to-make errors are listed here:
+
+* MXR file mismatch: MXR files are compiled by the backend using the given ONNX file for the GPU and load-time parameters. The backend will also prefer to use MXR files if they exist. If you move the MXR files to a different server or use a network storage where the MXR files get used by different servers with different GPUs, the MXR file will not work and you will get cryptic errors. The solution is to delete the MXR file and let the backend recompile from the ONNX file for your hardware.
+
+.. |platform| replace:: ``onnx_onnxv1`` or ``migraphx_mxr``
diff --git a/docs/backends/ptzendnn.rst b/docs/backends/ptzendnn.rst
new file mode 100644
index 000000000..49b8a0d74
--- /dev/null
+++ b/docs/backends/ptzendnn.rst
@@ -0,0 +1,156 @@
+..
+    Copyright 2022 Xilinx, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+PtZenDNN
+========
+
+The PtZenDNN backend executes a PyTorch model on CPUs.
+On AMD CPUs, the ZenDNN library offers optimized performance.
+
+Model support
+-------------
+
+The PtZenDNN backend currently only supports ResNet50.
+
+To use PyTorch models with this backend , you need to `convert downloaded PyTorch Eager models to TorchScript <https://pytorch.org/tutorials/advanced/cpp_export.html#step-1-converting-your-pytorch-model-to-torch-script>`_.
+
+Hardware support
+----------------
+
+Check the `support matrix <https://www.amd.com/content/dam/amd/en/documents/developer/zendnn-support-matrix-4.0.pdf>`__ for compatible AMD CPUs.
+
+Host setup
+----------
+
+No special host setup is required to use the PtZenDNN backend.
+
+Build an image
+--------------
+
+To build an image with the PtZenDNN backend enabled, you need to download the ZenDNN library and then build the image by pointing the build script to the location of this downloaded package.
+
+You can download the PT+ZenDNN package from the `ZenDNN developer downloads <ZenDNN_download>`_: ``PT_v1.12_ZenDNN_v4.0_C++_API.zip``.
+Before downloading this packages, you will be required to read and agree to the :term:`EULA`.
+
+After downloading the package, place it in the root of the repository.
+To build an image with the backend enabled, you need to add the ``--ptzendnn`` flag to the ``amdinfer dockerize`` command and pass the file to the package:
+
+.. code-block:: bash
+
+    # create the Dockerfile
+    python3 docker/generate.py
+
+    # build the development image $(whoami)/amdinfer-dev:latest
+    ./amdinfer dockerize --ptzendnn=./PT_v1.12_ZenDNN_v4.0_C++_API.zip
+
+    # build the development image $(whoami)/amdinfer-dev-zendnn:latest
+    ./amdinfer dockerize --ptzendnn=./PT_v1.12_ZenDNN_v4.0_C++_API.zip --suffix="-zendnn"
+
+    # build the deployment image $(whoami)/amdinfer-zendnn:latest
+    ./amdinfer dockerize --ptzendnn=./PT_v1.12_ZenDNN_v4.0_C++_API.zip --suffix="-zendnn" --production
+
+.. note::
+
+    The downloaded ZenDNN package will be used by the Docker build process so it must be in the inference server repository directory and in a location that is not excluded by the ``.dockerignore`` file.
+    These instructions suggest using the repository root but any path that meets this criteria will work.
+
+Start a container
+-----------------
+
+Depending on your use case and how you are using the server, you can start a container to use this backend in multiple ways.
+
+Deployment
+^^^^^^^^^^
+
+You can start a deployment container with something like:
+
+.. code-block:: console
+
+    $ docker run ...
+
+Development
+^^^^^^^^^^^
+
+A development container can be started with:
+
+.. code-block:: console
+
+    $ ./amdinfer run --dev
+
+This automatically publishes ports and mounts some convenient directories, such as your SSH directory, and drops you into a terminal in the container.
+
+Get test assets
+---------------
+
+You can download the assets and models used with this backend for tests and examples with:
+
+.. code-block:: console
+
+    $ ./amdinfer get --ptzendnn --all-models
+
+Loading the backend
+-------------------
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_intro
+    :end-before: -loading_the_backend_intro
+
+.. tabs::
+
+    .. code-tab:: c++ C++
+
+        // amdinfer::Client* client;
+        // amdinfer::ParameterMap parameters;
+        std::string endpoint = client->workerLoad("ptzendnn", parameters)
+
+    .. code-tab:: python Python
+
+        # client = amdinfer.Client()
+        # parameters = amdinfer.ParameterMap()
+        endpoint = client.workerLoad("ptzendnn", parameters)
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_modelLoad
+    :end-before: -loading_the_backend_modelLoad
+
+Parameters
+^^^^^^^^^^
+
+You can provide the following backend-specific parameters at load-time:
+
+.. csv-table::
+    :header: Parameter,Type,Usage
+
+    ``batch_size``,integer,Requested batch size for incoming batches. Defaults to 1.
+    ``image_channels``,integer,Number of channels in the input image. Defaults to 3.
+    ``input_size``,integer,Assuming a square input image, the size of the image in pixels. Defaults to 224.
+    ``model``,string,Full path to the model to load
+    ``output_classes``,integer,Number of output classes in the classification model. Defaults to 1000.
+    ``threads``,integer,Number of threads to use in the thread pool for the backend. Defaults to 3.
+
+Troubleshooting
+---------------
+
+If you run into problems, first check the :ref:`general troubleshooting guide <troubleshooting:Troubleshooting>` guide.
+Then continue on to this XModel specific troubleshooting guide.
+You will need access to the machine where the inference server is running to debug.
+
+Tune performance
+^^^^^^^^^^^^^^^^
+
+For tuning ZenDNN performance, you can refer to the PyTorch + ZenDNN `user guide <LinkZenDNNptGuide_>`_.
+
+.. |platform| replace:: ``pytorch_torchscript``
diff --git a/docs/backends/tfzendnn.rst b/docs/backends/tfzendnn.rst
new file mode 100644
index 000000000..196ca9dc9
--- /dev/null
+++ b/docs/backends/tfzendnn.rst
@@ -0,0 +1,157 @@
+..
+    Copyright 2022 Xilinx, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+TfZenDNN
+========
+
+The TfZenDNN backend executes a TensorFlow model on CPUs.
+On AMD CPUs, the ZenDNN library offers optimized performance.
+
+Model support
+-------------
+
+The TfZenDNN backend currently only supports ResNet50.
+
+Hardware support
+----------------
+
+Check the `support matrix <https://www.amd.com/content/dam/amd/en/documents/developer/zendnn-support-matrix-4.0.pdf>`__ for compatible AMD CPUs.
+
+Host setup
+----------
+
+No special host setup is required to use the TfZenDNN backend.
+
+Build an image
+--------------
+
+To build an image with the TfZenDNN backend enabled, you need to download the ZenDNN library and then build the image by pointing the build script to the location of this downloaded package.
+
+You can download the PT+ZenDNN package from the `ZenDNN developer downloads <ZenDNN_download>`_: ``TF_v2.10_ZenDNN_v4.0_C++_API.zip``.
+Before downloading this packages, you will be required to read and agree to the :term:`EULA`.
+
+After downloading the package, place it in the root of the repository.
+To build an image with the backend enabled, you need to add the ``--tfzendnn`` flag to the ``amdinfer dockerize`` command and pass the file to the package:
+
+.. code-block:: bash
+
+    # create the Dockerfile
+    python3 docker/generate.py
+
+    # build the development image $(whoami)/amdinfer-dev:latest
+    ./amdinfer dockerize --tfzendnn=./TF_v2.10_ZenDNN_v4.0_C++_API.zip
+
+    # build the development image $(whoami)/amdinfer-dev-zendnn:latest
+    ./amdinfer dockerize --tfzendnn=./TF_v2.10_ZenDNN_v4.0_C++_API.zip --suffix="-zendnn"
+
+    # build the deployment image $(whoami)/amdinfer-zendnn:latest
+    ./amdinfer dockerize --tfzendnn=./TF_v2.10_ZenDNN_v4.0_C++_API.zip --suffix="-zendnn" --production
+
+.. note::
+
+    The downloaded ZenDNN package will be used by the Docker build process so it must be in the inference server repository directory and in a location that is not excluded by the ``.dockerignore`` file.
+    These instructions suggest using the repository root but any path that meets this criteria will work.
+
+Start a container
+-----------------
+
+Depending on your use case and how you are using the server, you can start a container to use this backend in multiple ways.
+
+Deployment
+^^^^^^^^^^
+
+You can start a deployment container with something like:
+
+.. code-block:: console
+
+    $ docker run ...
+
+Development
+^^^^^^^^^^^
+
+A development container can be started with:
+
+.. code-block:: console
+
+    $ ./amdinfer run --dev
+
+This automatically publishes ports and mounts some convenient directories, such as your SSH directory, and drops you into a terminal in the container.
+
+Get test assets
+---------------
+
+You can download the assets and models used with this backend for tests and examples with:
+
+.. code-block:: console
+
+    $ ./amdinfer get --tfzendnn --all-models
+
+Loading the backend
+-------------------
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_intro
+    :end-before: -loading_the_backend_intro
+
+.. tabs::
+
+    .. code-tab:: c++ C++
+
+        // amdinfer::Client* client;
+        // amdinfer::ParameterMap parameters;
+        std::string endpoint = client->workerLoad("tfzendnn", parameters)
+
+    .. code-tab:: python Python
+
+        # client = amdinfer.Client()
+        # parameters = amdinfer.ParameterMap()
+        endpoint = client.workerLoad("tfzendnn", parameters)
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_modelLoad
+    :end-before: -loading_the_backend_modelLoad
+
+Parameters
+^^^^^^^^^^
+
+You can provide the following backend-specific parameters at load-time:
+
+.. csv-table::
+    :header: Parameter,Type,Usage
+
+    ``batch_size``,integer,Requested batch size for incoming batches. Defaults to 1.
+    ``image_channels``,integer,Number of channels in the input image. Defaults to 3.
+    ``input_node``,string,Name of the first node in the graph, assuming one input tensor. Defaults to "input".
+    ``input_size``,integer,Assuming a square input image, the size of the image in pixels. Defaults to 224.
+    ``inter_op``,integer,TensorFlow parameter to set the number of threads used for parallelism between independent operations. Defaults to 1.
+    ``intra_op``,integer,TensorFlow parameter to set the number of threads used within an individual operation for parallelism. Defaults to 64.
+    ``model``,string,Full path to the model to load
+    ``output_classes``,integer,Number of output classes in the classification model. Defaults to 1000.
+    ``output_node``,string,Name of the last node in the graph, assuming one output tensor. Defaults to "predict".
+
+Troubleshooting
+---------------
+
+If you run into problems, first check the :ref:`general troubleshooting guide <troubleshooting:Troubleshooting>` guide.
+Then continue on to this XModel specific troubleshooting guide.
+You will need access to the machine where the inference server is running to debug.
+
+Tune performance
+^^^^^^^^^^^^^^^^
+
+For tuning ZenDNN performance, you can refer to the TensorFlow + ZenDNN `user guide <LinkZenDNNtfGuide_>`_.
+
+.. |platform| replace:: ``tensorflow_graphdef``
diff --git a/docs/backends/vitis_ai.rst b/docs/backends/vitis_ai.rst
new file mode 100644
index 000000000..47bae8899
--- /dev/null
+++ b/docs/backends/vitis_ai.rst
@@ -0,0 +1,232 @@
+..
+    Copyright 2022 Xilinx, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Vitis AI
+========
+
+The Vitis AI XModel backend executes an XModel on an AMD FPGA.
+It uses :term:`VART` to run the XModel.
+
+Model support
+-------------
+
+The Vitis AI backend should support most XModels that have one DPU subgraph and also supports models with multiple input and output tensors.
+The tested models are listed below:
+
+.. csv-table::
+    :header: Model type,Tested models
+
+    Classification,ResNet50
+    Object detection,DenseBox; YOLOv3
+
+Other models should also work but are currently untested.
+
+Hardware support
+----------------
+
+While not every model is tested on every FPGA, the Vitis AI backend has run at least one model on the following devices:
+
+.. csv-table::
+    :header: Family,FPGA,DPU
+
+    Alveo,U250,DPUCADF8H
+    Versal,VCK5000,DPUCVDX8H
+
+Other devices and DPUs may also work but are currently untested.
+
+Host setup
+----------
+
+The details for setting up your host are available online in the :vitisAItree:`Vitis AI <setup>` repository.
+These instructions will depend on the FPGAs you are targeting.
+In essence, you will need to install software, program the shell on the FPGA(s) and download its ``xclbin`` files.
+
+Software
+^^^^^^^^
+
+You need to install :term:`XRT` to communicate with the FPGA over PCIe.
+The XRT version on the host should match the one installed in the container where the server will be running.
+The Xilinx Resource Manager (XRM) is not needed on the host because it is already installed in the container.
+
+Shell
+^^^^^
+
+The Vitis AI repository contains scripts to install packages and flash the shell on your FPGA.
+They use XRT to program the FPGA.
+In most cases, flashing the shell will be a one-time act as it is persistent.
+However, for some FPGAs such as the Alveo U250, there is an intermediate second shell that must be reprogrammed after every power cycle.
+Follow the instructions in the scripts to install the secondary shell.
+
+You can use ``xbutil validate --device <device id>`` to confirm that your FPGA is ready to use.
+If this executable is not on your PATH, it should be in ``/opt/xilinx/xrt/bin``.
+
+XCLBINs
+^^^^^^^
+
+The ``xclbin`` files define the DPU that will run on the FPGA.
+By default, these are installed in ``/opt/xilinx/overlaybins/<DPU>/*``
+The environment variable ``XLNX_VART_FIRMWARE`` must be set in the container where the inference server is running to point to the directory where the ``xclbin`` files for your FPGA are.
+You can mount this directory in your container to enable it to access these files.
+Alternatively, you can also copy ``xclbin`` files directly into the container as well.
+
+Build an image
+--------------
+
+To build an image with the Vitis AI backend enabled, you need to add the ``--vitis`` to the ``amdinfer dockerize`` command:
+
+.. code-block:: bash
+
+    # create the Dockerfile
+    python3 docker/generate.py
+
+    # build the development image $(whoami)/amdinfer-dev:latest
+    ./amdinfer dockerize --vitis
+
+    # build the development image $(whoami)/amdinfer-dev-vitis:latest
+    ./amdinfer dockerize --vitis --suffix="-vitis"
+
+    # build the deployment image $(whoami)/amdinfer-vitis:latest
+    ./amdinfer dockerize --vitis --suffix="-vitis" --production
+
+Start a container
+-----------------
+
+Depending on your use case and how you are using the server, you can start a container to use this backend in multiple ways.
+
+Deployment
+^^^^^^^^^^
+
+You can start a deployment container with something like:
+
+.. code-block:: console
+
+    $ docker run --device /dev/xclmgmt<id> --device /dev/dri [--volume ...]
+
+These ``--device`` flags pass the FPGA(s) to the container and you can mount other directories as needed to make models available.
+The name of the ``xclmgmt`` file depends on your host so look in the ``/dev/`` directory to see what the file is.
+If you have multiple FPGAs, there will be multiple such files.
+The deployment image will need ``xclbin`` files.
+There are a few ways to achieve this:
+
+1. Copy ``xclbin`` files into ``./external/overlaybins/*`` before invoking the ``dockerize`` command to build the development image. The Dockerfile is configured to copy any files and directories from this path into the deployment image under ``/opt/xilinx/overlaybins``.
+2. Copy ``xclbin`` files into the image after building it
+3. Mount the ``xclbin`` files in the container at start time
+
+For deploying on Kubernetes-based platforms, you will need to add the FPGA as a resource to your deployment after installing the `Xilinx FPGA Kubernetes plugin <https://github.com/Xilinx/FPGA_as_a_Service/tree/master/k8s-device-plugin>`__.
+The exact name of the resource will depend on which FPGA and shell you are trying to request.
+
+.. code-block:: yaml
+
+    # rest of the deployment logic
+    resources:
+      limits:
+        cpu: "1"
+        memory: 2Gi
+        xilinx.com/fpga-xilinx_u250_gen3x16_xdma_shell_3_1-0: 1
+
+Development
+^^^^^^^^^^^
+
+A development container can be started with:
+
+.. code-block:: console
+
+    $ ./amdinfer run --dev
+
+This automatically adds the detected devices, publishes ports, and mounts some convenient directories, such as your SSH directory, and drops you into a terminal in the container.
+In particular, it will mount the default ``xclbin`` files directory from your host to the container.
+
+Get test assets
+---------------
+
+You can download the assets and models used with this backend for tests and examples with:
+
+.. code-block:: console
+
+    $ ./amdinfer get --vitis --all-models
+
+Loading the backend
+-------------------
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_intro
+    :end-before: -loading_the_backend_intro
+
+.. tabs::
+
+    .. code-tab:: c++ C++
+
+        // amdinfer::Client* client;
+        // amdinfer::ParameterMap parameters;
+        std::string endpoint = client->workerLoad("xmodel", parameters)
+
+    .. code-tab:: python Python
+
+        # client = amdinfer.Client()
+        # parameters = amdinfer.ParameterMap()
+        endpoint = client.workerLoad("xmodel", parameters)
+
+.. include:: /dry.rst
+    :start-after: +loading_the_backend_modelLoad
+    :end-before: -loading_the_backend_modelLoad
+
+Parameters
+^^^^^^^^^^
+
+You can provide the following backend-specific parameters at load-time:
+
+.. csv-table::
+    :header: Parameter,Type,Usage
+
+    ``model``,string,Full path to the XModel to load
+    ``threads``,integer,Number of threads to use in the thread pool for the backend. Defaults to 3.
+
+Troubleshooting
+---------------
+
+If you run into problems, first check the :ref:`general troubleshooting guide <troubleshooting:Troubleshooting>` guide.
+Then continue on to this XModel specific troubleshooting guide.
+You will need access to the machine where the inference server is running to debug.
+
+First things to check
+^^^^^^^^^^^^^^^^^^^^^
+
+Using FPGAs may not work as expected for a variety of reasons ranging from loose cables to misconfiguration in the container.
+Always do these first when debugging any issue to eliminate the most common sources of error.
+
+1. Use ``xbutil examine`` and ``xbutil validate`` on the host machine to first make sure your host machine can use the attached FPGA. If it doesn't work, check the logs. XRT will log error messages to the system log. Use ``journalctl`` or ``dmesg`` to view them.
+2. Make sure the XRT version matches in the host and in the container with ``xbutil --version``
+3. Optionally, repeat the ``xbutil examine`` and ``xbutil validate`` tests from the container. If this doesn't work, double-check how you are passing device files to the container.
+4. Make sure the XRM daemon is running in the container with ``sudo systemctl status xrmd``
+5. Run your failing test in the container and see if there are logs in the host machine's system logs.
+
+Gotchas
+^^^^^^^
+
+Some common easy-to-make errors are listed here:
+
+* Version mismatch: the XRT version on your host machine and the container must match
+* ``xclbin`` mismatch: the same ``xclbin`` files must exist at the same location in the host machine and the container. The easiest way to guarantee this is to mount the ``xclbin`` directory into the container. If you copy files in to the container, make sure they're in the same locations as on the host.
+
+CU timeouts
+^^^^^^^^^^^
+
+The CU refers to a compute unit on the FPGA and a timeout means it did not respond in time.
+This is usually a misconfiguration of the FPGA.
+The system logs on the host should help identify the problem.
+If not, you also try resetting the FPGA with ``xbutil reset`` or flashing the shell on the FPGA again with ``xbmgmt``.
+
+.. |platform| replace:: ``vitis_xmodel``
diff --git a/docs/changelog.rst b/docs/changelog.rst
index cc9e40aff..ec6610562 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
diff --git a/docs/conf.py b/docs/conf.py
index b2a3e3f8f..a8b47ee87 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -39,7 +39,7 @@
 # override this value to build different versions
 version = "main"
 
-if version != "main":
+if version != "main" and version != "dev":
     release = f"v{version}"
 else:
     release = version
@@ -52,7 +52,8 @@
 extensions = [
     "sphinxcontrib.jquery",
     "breathe",
-    "exhale",
+    # omitting the full C++ documentation generation for now
+    # "exhale",
     # adds argparse directive to parse CLIs
     "sphinxarg.ext",
     "sphinxcontrib.confluencebuilder",
@@ -67,6 +68,10 @@
     "sphinx_copybutton",
     "sphinx_issues",
     "sphinx_tabs.tabs",
+    # adds tooltips
+    "sphinx_tippy",
+    # add emoji
+    "sphinxemoji.sphinxemoji",
     "sphinxcontrib.openapi",
 ]
 
@@ -105,6 +110,16 @@
     "special-members": "__init__",
 }
 
+tippy_add_class = "has-tippy"
+tippy_skip_urls = [
+    # skip all URLs except those pointing to the glossary
+    r"^((?!glossary\.html).)*$"
+]
+tippy_enable_wikitips = False
+tippy_enable_doitips = False
+
+sphinxemoji_style = "twemoji"
+
 
 def hide_private_module(app, what, name, obj, options, signature, return_annotation):
     if signature is not None:
@@ -132,6 +147,7 @@ def hide_private_module(app, what, name, obj, options, signature, return_annotat
 raw_path = f"https://github.com/Xilinx/inference-server/raw/{release}/%s"
 xilinx_download = "https://www.xilinx.com/bin/public/openDownload?filename=%s"
 github_onnx = "https://github.com/onnx/models/raw/main/%s"
+vitis_ai_path = "https://github.com/Xilinx/Vitis-AI/tree/v3.0/%s"
 
 # sphinx.ext.extlinks configuration. syntax is key: (url, caption). The key should not have underscores.
 extlinks = {
@@ -143,6 +159,7 @@ def hide_private_module(app, what, name, obj, options, signature, return_annotat
     "github": ("https://github.com/%s", "%s"),
     "xilinxDownload": (xilinx_download, "%s"),
     "githubOnnx": (github_onnx, None),
+    "vitisAItree": (vitis_ai_path, None),
 }
 
 # sphinx-issues configuration
@@ -157,6 +174,14 @@ def hide_private_module(app, what, name, obj, options, signature, return_annotat
 # number all figures with captions
 numfig = True
 
+rst_prolog = """
+.. include:: /prolog.rst
+"""
+
+rst_epilog = """
+.. include:: /epilog.rst
+"""
+
 # Configure 'Edit on GitHub' extension
 edit_on_github_project = "Xilinx/inference-server"
 edit_on_github_branch = f"{release}/docs"
@@ -167,7 +192,15 @@ def hide_private_module(app, what, name, obj, options, signature, return_annotat
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "**/build/**", "**/uploads/**"]
+exclude_patterns = [
+    "_build",
+    "Thumbs.db",
+    ".DS_Store",
+    "**/build/**",
+    "**/uploads/**",
+    "epilog.rst",
+    "prolog.rst",
+]
 
 
 # -- Options for HTML output -------------------------------------------------
diff --git a/docs/contributing.rst b/docs/contributing.rst
index f764052eb..e0aabda68 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
diff --git a/docs/cpp_user_api.rst b/docs/cpp_user_api.rst
index f29890fb7..f5b3fe0a6 100644
--- a/docs/cpp_user_api.rst
+++ b/docs/cpp_user_api.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -26,6 +26,12 @@ Clients
 
 .. doxygenfunction:: amdinfer::waitUntilModelReady
 
+.. doxygenfunction:: amdinfer::waitUntilModelNotReady
+
+.. doxygenfunction:: amdinfer::loadEnsemble
+
+.. doxygenfunction:: amdinfer::unloadModels
+
 .. doxygenfunction:: amdinfer::inferAsyncOrdered
 
 .. doxygenfunction:: amdinfer::inferAsyncOrderedBatched
diff --git a/docs/dependencies.rst b/docs/dependencies.rst
index 54c03a342..e3c3427e5 100644
--- a/docs/dependencies.rst
+++ b/docs/dependencies.rst
@@ -137,8 +137,10 @@ The following packages (and any dependencies) are installed from the Python Pack
     :pypiPackages:`Sphinx`,latest,BSD-2 + others,Building documentation\ :superscript:`d 0`
     :pypiPackages:`sphinx-argparse`,latest,MIT,Sphinx plugin for documenting CLIs\ :superscript:`d 0`
     :pypiPackages:`sphinx-copybutton`,latest,MIT,Adds copy button for code blocks\ :superscript:`d 0`
+    :pypiPackages:`sphinxemoji`,latest,BSD-3,Sphinx plugin for enabling emoji\ :superscript:`d 0`
     :pypiPackages:`sphinx-issues`,latest,MIT,Sphinx plugin for links to the project's Github issue tracker\ :superscript:`d 0`
     :pypiPackages:`sphinx-tabs`,latest,MIT,Sphinx plugin to create tabs\ :superscript:`d 0`
+    :pypiPackages:`sphinx_tippy`,latest,MIT,Sphinx plugin to create tooltips\ :superscript:`d 0`
     :pypiPackages:`sphinxcontrib-confluencebuilder`,latest,BSD-2,Sphinx plugin to export documentation to Confluence\ :superscript:`d 0`
     :pypiPackages:`sphinxcontrib-jquery`,latest,BSD-0,Sphinx plugin to add JQuery\ :superscript:`d 0`
     :pypiPackages:`sphinxcontrib-openapi`,latest,BSD-2,Sphinx plugin to build OpenAPI docs\ :superscript:`d 0`
diff --git a/docs/deploy.sh b/docs/deploy.sh
new file mode 100755
index 000000000..1cef3bcc9
--- /dev/null
+++ b/docs/deploy.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+# Copyright 2021 Xilinx, Inc.
+# Copyright 2022 Advanced Micro Devices, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+VERSION=main
+echo "Pushing to ./$VERSION. Okay?"
+read response
+if [[ "$response" != "y" && "$response" != "Y" ]]; then
+    echo "Exiting"
+    exit
+fi
+
+cache_dir="/tmp/node_modules/gh-pages/.cache"
+mkdir -p "$cache_dir"
+
+config=($(<./build/config.txt))
+directory=${config[0]}
+sed -i -e "s/inference-server\/main/inference-server\/$VERSION/g" ./README.rst
+sed -i -e "s/version = \"main\"/version = \"$VERSION\"/g" ./docs/conf.py
+
+./amdinfer make doxygen
+./amdinfer make sphinx
+export CACHE_DIR="$cache_dir"
+# -t adds dotfiles
+gh-pages -t -d ./build/$directory/docs/sphinx/ -e ./$VERSION
+
+rm -rf "/tmp/node_modules"
+sed -i -e "s/version = \"$VERSION\"/version = \"main\"/g" ./docs/conf.py
+sed -i -e "s/inference-server\/$VERSION/inference-server\/main/g" ./README.rst
diff --git a/docs/docker.rst b/docs/deployment.rst
similarity index 51%
rename from docs/docker.rst
rename to docs/deployment.rst
index b85fff785..e9018ff7b 100644
--- a/docs/docker.rst
+++ b/docs/deployment.rst
@@ -1,5 +1,5 @@
 ..
-    Copyright 2022 Advanced Micro Devices, Inc.
+    Copyright 2023 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -13,33 +13,47 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-Docker
-======
+Deployment
+==========
 
-You can use the AMD Inference Server with Docker to deploy the server.
-For more powerful and easier to use deployments, consider using :ref:`KServe <kserve:KServe>`.
+Deployment is |define_deployment|.
+There are many different ways to deploy the server and the best one will depend on your use cases.
+However, you will use a container in all cases.
 
-Build the deployment Docker image
----------------------------------
+Deployment image
+----------------
 
-The deployment image is optimized for size and only contains the runtime dependencies of the server to allow for quicker deployments.
-It automatically starts the server executable as the image starts as opposed to opening a Bash shell though that can be overridden.
-To build the deployment image:
+The :ref:`deployment image <terminology~Deployment>` is optimized for size and automatically starts the server executable as the container runs.
+If you do not need to frequently debug the server or compile the executable in a custom way, using the deployment image provides a self-contained approach to deploy the server on a machine.
+
+Get the image
+^^^^^^^^^^^^^
+
+To use the pre-built images for the inference server, you can pull them from DockerHub:
+
+.. include:: dry.rst
+    :start-after: +docker_pull_deployment_images
+    :end-before: -docker_pull_deployment_images
+
+Build the image
+^^^^^^^^^^^^^^^
+
+If you want an image with a custom build of the server or with an arbitrary combination of backends, you will need to build it yourself.
+After cloning the inference server repository, you can build the deployment image with:
 
 .. code-block:: console
 
     $ python3 docker/generate.py
-    $ ./amdinfer dockerize --production <platform flags>
+    $ ./amdinfer dockerize --production <backend flags>
 
-Depending on what platforms you want to support, add the appropriate flags to enable :doc:`Vitis AI <vitis_ai>`, :doc:`ZenDNN <zendnn>` or :doc:`MIGraphX <migraphx>`.
-Refer to the help or the platform documentation for more information on how to build the right image.
+Depending on what backends you want to support, add the appropriate flags to enable them.
+You can enable multiple backends by passing flags for all the backends you want to enable in the image.
+Refer to the help for this command or the :ref:`backend documentation <backends:Backends>` for more information on how to build the right image.
 
 .. important::
 
-    Some platforms require additional steps before building the Docker image with them enabled.
-    Look at the platform-specific documentation for more information about how to build images for a given platform.
-
-.. _docker~push to a registry:
+    Some backends require additional steps before building the Docker image with them enabled.
+    Look at the backend-specific documentation for more information about how to build images for a given backend.
 
 Push to a registry
 ^^^^^^^^^^^^^^^^^^
@@ -66,12 +80,12 @@ The SHA is visible when you push the image to the registry or you can get it by
 
     $ docker inspect --format='{{index .RepoDigests 0}}' <registry>/<image>
 
-Prepare the image for Docker deployment
----------------------------------------
+Prepare the image
+^^^^^^^^^^^^^^^^^
 
-Once you build the basic deployment image or pull a pre-built version, you need to prepare it before it can be deployed on Docker.
+Once you build the basic deployment image or pull a pre-built version, you may need to prepare it before it can be deployed.
 While the image has the dependencies needed to run the server, there are no models present and the default environment may not be appropriate.
-You need to modify this image for the use case that you're targeting.
+You may need to modify this image for the use case that you're targeting.
 There are multiple ways of modifying an existing Docker image that are well-documented online and functionally equivalent.
 For example, one approach is using a Dockerfile to build a new image:
 
@@ -83,17 +97,16 @@ For example, one approach is using a Dockerfile to build a new image:
     ENV SomeVariable=SomeValue
     CMD ["amdinfer-server", "<more arguments?>"]
 
-In this case, you can build and save a new image that includes the models you want to serve.
-Depending on the platform, you may need to include other files as well that the platform runtime needs.
-As with the deployment image, this image may need to be :ref:`pushed to a registry server <docker~push to a registry>` for your use case.
+In this case, you can build and save a new image that includes the additional files you added.
+Depending on the backend, you may need to include other files as well that the backend runtime needs.
 
 Note that the command that the image runs and its environment can also be overridden at the command-line when starting the container.
-Therefore, an alternative approach to building a new image is to mount the needed files as volumes when starting the container and set the environment then.
+Therefore, an alternative approach to building a new image is to mount the needed files as volumes when starting the container and set the environment then as well.
 
-Start the container
--------------------
+Start a container
+-----------------
 
-You can start the deployment image with ``docker`` as any other container.
+You can start a deployment container with ``docker`` as any other container.
 You need to pass along any devices that you want to enable in your container and expose ports to access the server.
 Look at the ``docker run`` documentation for more information about what flags can be passed.
 
@@ -103,33 +116,23 @@ Look at the ``docker run`` documentation for more information about what flags c
 
 By default, the deployment container starts the server executable and it continues to run after the ``docker run`` command.
 But before it can serve requests, you need to load the models that you added into the image.
-The easiest way to communicate with the server is using the :ref:`Python library <python:install the python library>`.
-You can install it locally or use it in the development container to load the workers on the server.
-
-.. code-block:: python
-
-    import amdinfer
-
-    client = amdinfer.HttpClient("http://hostname:port")
-
-    # depending on the model, you need to use the appropriate worker
-    worker_name = "migraphx"
-
-    parameters = amdinfer.ParameterMap()
-    # specifies the path to the model on the server for it to open
-    parameters.put("model", "/path/to/model")
+You can set up a :ref:`model repository <model_repository:Model Repository>` that gets loaded automatically or manually load backends using the client API ``workerLoad()``.
+Look at the :ref:`backend documentation <backends:Backends>` for information on how to load them.
 
-    # workers may accept other parameters at load-time. Refer to worker documentation
+KServe
+------
 
-    endpoint = client.workerLoad(worker_name, parameters)
-    print(endpoint)
-    amdinfer.waitUntilModelReady(client, endpoint)
+You can deploy the deployment image with KServe onto a Kubernetes cluster.
+See the :ref:`KServe guide <kserve:KServe>` for more information.
 
-Clients that make requests to this worker need this endpoint to talk to it.
+Development image
+-----------------
 
-Make a request
---------------
+The :ref:`development image <terminology~Development>` contains all the libraries and tools to compile the server executable.
+If you are experimenting with development or debugging, using the development image can provide a way to deploy the server on a machine.
+See the :ref:`developer quickstart <quickstart_development:Developer Quickstart>` for how to get started with this image.
 
-As in the :ref:`Python examples <example_resnet50_python:running resnet50 - python>`, you can make a request by creating a client in Python by pointing it to the address of the server to communicate with.
-Unlike these examples, you can skip ahead to making the request for inference because the server is already started and the worker is ready to serve your request.
-Once you have it, you can use ``modelInfer`` to make the request.
+Once you have compiled the server, you can start it in the container and send it requests from within the container.
+If you are debugging, it can be helpful to start the server with ``gdb``.
+The container will also have published ports on the host machine so you can also send requests to your running server executable in the container from the outside using this port.
+Use ``docker ps`` to see what the port mapping is.
diff --git a/docs/dry.rst b/docs/dry.rst
new file mode 100644
index 000000000..d8e868d3e
--- /dev/null
+++ b/docs/dry.rst
@@ -0,0 +1,73 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+..
+    This page has blocks of text that are inserted in multiple pages in an
+    effort to avoid duplicating text and making the documentation easier to
+    maintain. The format for text snippets is:
+        +<label>
+        <contents>
+        -<label>
+    As an arbitrary convention, I'm using +/- prefixes to denote start and stop
+    labels. Note that due to how including sections of pages works in RST, the
+    labels must be entirely unique i.e. if you use "foobar" as a label, you
+    cannot use "foobar" at the start of any other label. Therefore, prefer
+    verbose labels to prevent unintentional matching.
+
++loading_the_backend_intro
+There are multiple ways to load this backend to make it available for inference requests from clients.
+If you are using a client's ``workerLoad()`` method:
+-loading_the_backend_intro
+
+
++loading_the_backend_modelLoad
+With a client's ``modelLoad()`` method or using the repository approach, you need to create a :ref:`model repository <model_repository:Model Repository>` and put a model in it.
+To use this backend with your model, use |platform| as the platform for your model.
+
+Then, you can load the model from the server after setting up the path to the model repository.
+The server may be set to automatically load all models from the configured model repository or you can load it manually using ``modelLoad()``.
+In this case, the endpoint is defined in the model's configuration file in the repository and it is used as the argument to ``modelLoad()``.
+
+.. tabs::
+
+    .. code-tab:: c++ C++
+
+        // amdinfer::Client* client;
+        // amdinfer::ParameterMap parameters;
+        client->modelLoad(<model>, parameters)
+
+    .. code-tab:: python Python
+
+        # client = amdinfer.Client()
+        # parameters = amdinfer.ParameterMap()
+        client.modelLoad(<model>, parameters)
+
+-loading_the_backend_modelLoad
+
++docker_pull_deployment_images
+.. tabs::
+
+    .. code-tab:: console CPU
+
+        $ docker pull amdih/serve:uif1.1_zendnn_amdinfer_0.3.0
+
+    .. code-tab:: text GPU
+
+        $ docker pull amdih/serve:uif1.1_migraphx_amdinfer_0.3.0
+
+    .. code-tab:: console FPGA
+
+        # this image is not currently pre-built but you can build it yourself
+-docker_pull_deployment_images
diff --git a/docs/ensembles.rst b/docs/ensembles.rst
new file mode 100644
index 000000000..114ccf2e6
--- /dev/null
+++ b/docs/ensembles.rst
@@ -0,0 +1,45 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Ensembles
+=========
+
+Ensembles are |define_ensemble|.
+You can use ensembles to define a pipeline like pre-processing, inference, and post-processing on the server.
+
+.. note::
+
+    Ensembles are currently limited to :term:`chains <Chain>`.
+    They must also be defined at load-time rather than at run-time.
+
+Defining ensembles
+------------------
+
+Ensembles can be defined in two ways: in the model repository and with the API.
+
+Model repository
+^^^^^^^^^^^^^^^^
+
+Ensembles can be defined in the model repository to enable their use with Docker and KServe deployments.
+You can also use this approach if you want to load a model from a local repository using ``modelLoad``.
+At a high-level, you must define the ensemble in the model's configuration file, place all the model files in the directory and the ensemble gets loaded as any other single model.
+For more details, see :ref:`how to define ensembles in the model repository <model_repository:Ensembles>`.
+
+API
+^^^
+
+You can also load a chain as a set of workers directly using the client API method ``loadEnsemble()`` and providing it an array of workers and corresponding parameters.
+The method returns an array of endpoints, where the first endpoint corresponds to the endpoint used to send requests to the ensemble.
+To unload an ensemble, you can use the client API method ``unloadModels()`` and provide the array of endpoints.
diff --git a/docs/epilog.rst b/docs/epilog.rst
new file mode 100644
index 000000000..ea748a22f
--- /dev/null
+++ b/docs/epilog.rst
@@ -0,0 +1,35 @@
+..
+    Copyright 2022 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+..
+    The contents of this file are inserted at the end of every RST source file
+
+.. _LinkDockerInstallLinux: https://docs.docker.com/engine/install/
+.. _LinkDockerRun: https://docs.docker.com/engine/reference/commandline/run/
+.. _LinkInferenceServerDockerHub: https://hub.docker.com/r/amdih/serve
+.. _LinkInferenceServerRepository: https://github.com/Xilinx/inference-server
+.. _LinkInferenceServerDocumentation: https://xilinx.github.io/inference-server/
+.. _LinkZenDNN: https://www.amd.com/en/developer/zendnn.html
+.. _LinkZenDNNdownload: https://www.amd.com/en/developer/zendnn.html#downloads
+.. _LinkZenDNNguide: https://www.amd.com/en/developer/zendnn.html#documentation
+.. _LinkZenDNNptGuide: https://www.amd.com/content/dam/amd/en/documents/developer/pytorch-zendnn-user-guide-4.0.pdf
+.. _LinkZenDNNtfGuide: https://www.amd.com/content/dam/amd/en/documents/developer/tensorflow-zendnn-user-guide-4.0.pdf
+
+
+.. |define_deployment| replace:: the act of making the AMD Inference Server available to respond to inference requests from clients
+
+.. |define_ensemble| replace:: a logical pipeline of workers to execute a graph of computations where the output tensors of one model are passed as input to others
+
+.. |define_model_repository| replace:: a directory that exists on the host machine where the server :term:`container <Container (Docker)>` is running and it holds the models you want to serve and their associated metadata in a standard structure
diff --git a/docs/example_resnet50_cpp.rst b/docs/example_resnet50_cpp.rst
index 7506b8a67..43fe166dc 100644
--- a/docs/example_resnet50_cpp.rst
+++ b/docs/example_resnet50_cpp.rst
@@ -21,7 +21,7 @@ These examples are intended to run in the development container because you need
 You can see the full source files used here in the :amdinferTree:`repository <examples/resnet50>` for more details.
 
 The inference server binds its C++ API to Python so the Python usage and functions look similar to their C++ counterparts but there are some differences due to the available features in both languages.
-You can read the :ref:`Python version of this example <example_resnet50_python:Running ResNet50 - Python` to better compare these two.
+You can read the :ref:`Python version of this example <example_resnet50_python:Running ResNet50 - Python>` to better compare these two.
 
 .. note::
     These examples are intended to demonstrate the API and how to communicate with the server.
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 046412aa7..9df096768 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -1,5 +1,5 @@
 ..
-    Copyright 2022 Advanced Micro Devices, Inc.
+    Copyright 2023 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,12 +14,49 @@
     limitations under the License.
 
 Glossary
-========
+--------
 
 .. glossary::
 
-    Xilinx Runtime
-        An open-source standardized software interface that facilitates communication between the application code and the accelerated-kernels deployed on the reconfigurable portion of PCIe-based Alveo accelerator cards, Zynq-7000, Zynq UltraScale+ MPSoC based embedded platforms or Versal ACAPs.
+    Administrator (User)
+        a :term:`user <User>` that sets up and maintains the inference server deployment container(s)
+
+    Chain
+        a linear :term:`ensemble <Ensemble>` where all the output tensors of one stage are inputs to the same next stage without having loops, broadcasts or concatenations
+
+    Client (User)
+        a :term:`user <User>` that interacts with a running server using its APIs to send it inference requests
+
+    Container (Docker)
+        a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another [1]_
+
+        see also: :term:`image <Image (Docker)>`
+
+    Developer (User)
+        a :term:`user <User>` that uses the development container to build and test the server executable
+
+    Ensemble
+        |define_ensemble|
+
+    EULA
+        End User License Agreement
+
+    Image (Docker)
+        a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings [1]_
+
+        see also: :term:`containers <Container (Docker)>`
+
+    Model repository
+        |define_model_repository|
+
+    User
+        anything or anyone that uses the AMD Inference Server i.e. :term:`clients <Client (User)>`, :term:`administrators <Administrator (User)>`, or :term:`developers <Developer (User)>`
+
+    VART
+        Vitis AI Runtime: enables applications to use the unified high-level runtime API for both Cloud and Edge
 
     XRT
-        See :term:`Xilinx Runtime`
+        Xilinx Runtime Library: an open-source standardized software interface that facilitates communication between the application code and the accelerated-kernels deployed on the reconfigurable portion of PCIe-based Alveo accelerator cards, Zynq-7000, Zynq UltraScale+ MPSoC based embedded platforms or Versal ACAPs
+
+
+.. [1] https://www.docker.com/resources/what-container/
diff --git a/docs/index.rst b/docs/index.rst
index 1b49e8f72..678da39ec 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -19,41 +19,34 @@ AMD Inference Server
 
 Welcome to the official documentation for the AMD Inference Server: an open-source tool to deploy your machine learning models and make them accessible to clients for inference.
 
-If you are new to the project, start with the :ref:`Introduction <introduction:introduction>` to get an overview of what it's about and how this documentation is organized.
+If you are new to the project, start with the :ref:`Introduction <introduction:introduction>` and the rest of the **Getting Started** section to get a high-level look at the features, documentation organization and important concepts.
 
 Use the sidebar to navigate through the different pages in the documentation.
 Note that the documentation is versioned.
 By default, it shows the latest documentation corresponding to the current state of the `code <https://github.com/Xilinx/inference-server>`__.
-To see other versions, you can use "Read the Docs" panel on the bottom-left, visit this `landing page <https://xilinx.github.io/inference-server/>`__ or edit the version in the URL directly.
+To see other versions, you can use "Read the Docs" panel on the bottom-left or edit the version in the URL directly.
 
 .. toctree::
     :maxdepth: 2
     :hidden:
-    :caption: About
+    :caption: Getting started
 
     introduction
-    dependencies
-    roadmap
-    changelog
-
-.. toctree::
-    :maxdepth: 2
-    :hidden:
-    :caption: Quickstart
-
-    Inference <quickstart_inference>
-    Deployment <quickstart_deployment>
-    Development <quickstart_development>
+    terminology
+    quickstart
 
 .. toctree::
     :maxdepth: 2
     :hidden:
-    :caption: Libraries and API
+    :caption: User guide
 
-    cpp_user_api
-    python
-    rest
-    cli
+    backends
+    model_repository
+    ensembles
+    deployment
+    kserve
+    performance_factors
+    troubleshooting
 
 .. toctree::
     :maxdepth: 2
@@ -64,26 +57,36 @@ To see other versions, you can use "Read the Docs" panel on the bottom-left, vis
     example_resnet50_cpp
     example_resnet50_python
 
-.. toctree::
-    :maxdepth: 2
-    :hidden:
-    :caption: Using the Server
-
-    platforms
-    Deploying with Docker <docker>
-    Deploying with KServe <kserve>
-    performance_factors
-
 .. toctree::
     :maxdepth: 2
     :hidden:
     :caption: Developers
 
-    contributing
+    quickstart_development
+    testing
     architecture
     aks
     logging
     benchmarking
     metrics
     tracing
-    cpp_api/cpp_root
+
+.. toctree::
+    :maxdepth: 2
+    :hidden:
+    :caption: About
+
+    contributing
+    dependencies
+    changelog
+    roadmap
+
+.. toctree::
+    :maxdepth: 2
+    :hidden:
+    :caption: Libraries and API
+
+    amdinfer_script
+    cpp_user_api
+    python
+    rest
diff --git a/docs/introduction.rst b/docs/introduction.rst
index 70b856ed7..88d14603c 100644
--- a/docs/introduction.rst
+++ b/docs/introduction.rst
@@ -31,10 +31,11 @@ Features
 * C++ library with Python bindings to simplify making requests to the server
 * Incoming requests are transparently batched based on the user specifications
 * Users can define how many models, and how many instances of each, to run in parallel
+* Users can define a linear chain of models to perform a series of steps such as pre-processing, inference, and post-processing on the server
 
 The AMD Inference Server is integrated with the following libraries out of the gate:
 
-* TensorFlow and PyTorch models with `ZenDNN <https://developer.amd.com/zendnn/>`__ on AMD CPUs
+* TensorFlow and PyTorch models with `ZenDNN <LinkZenDNN_>`_ on AMD CPUs
 * ONNX models with `MIGraphX <https://github.com/ROCmSoftwarePlatform/AMDMIGraphX>`__ on AMD GPUs
 * XModel models with `Vitis AI <https://www.xilinx.com/products/design-tools/vitis/vitis-ai.html>`__ on AMD (Xilinx) FPGAs
 * A graph of computation including pre- and post-processing for end-to-end inference with `AKS <https://github.com/Xilinx/Vitis-AI/tree/v2.5/src/AKS>`__ on AMD (Xilinx) FPGAs
@@ -44,7 +45,7 @@ Documentation overview
 
 The remainder of this documentation is organized as follows:
 
-* The **About** section continues to talk about the dependencies, licenses, roadmap and the changelog for the project
+* The **About** section continues to talk about the project at a high-level
 * The **Quickstart** section presents quick starts for different types of users
 * The **Libraries and API** section goes over the different libraries, APIs and tools available to users
 * The **Examples** section provides more commentary around the examples in the repository
diff --git a/docs/kserve.rst b/docs/kserve.rst
index 08e48546c..6fe7d2bbb 100644
--- a/docs/kserve.rst
+++ b/docs/kserve.rst
@@ -26,9 +26,9 @@ To use KServe, you will need a Kubernetes cluster.
 There are many ways to set up and configure a Kubernetes cluster depending on your use cases.
 Instructions for installing and configuring Kubernetes are out of this scope.
 
-Install KServe using the `instructions <https://kserve.github.io/website/admin/serverless/>`__ provided by KServe.
+Install KServe using the `instructions <https://kserve.github.io/website/master/admin/serverless/serverless>`__ provided by KServe.
 We have tested with KServe 0.8 using the standard serverless installation but other versions/configurations may work as well.
-Once KServe is installed, verify basic functionality of the cluster using KServe's `basic tutorial <https://kserve.github.io/website/get_started/first_isvc/>`__.
+Once KServe is installed, verify basic functionality of the cluster using KServe's `basic tutorial <https://kserve.github.io/website/master/get_started/first_isvc/>`__.
 If this succeeds, KServe should be installed correctly.
 KServe installation help and debugging are also out of scope for these instructions.
 If you run into problems, reach out to the KServe project.
@@ -44,7 +44,7 @@ The `kube-prometheus <https://github.com/prometheus-operator/kube-prometheus/>`_
 Get or build the AMD Inference Server Image
 -------------------------------------------
 
-To use with KServe, you will need to pull or :ref:`build the deployment container <docker:Build the deployment Docker image>`.
+To use with KServe, you will need a :ref:`deployment image <deployment:Deployment image>`.
 Once you have it somewhere, make sure you can use ``docker pull <image>`` on all the nodes in the Kubernetes cluster to get the image.
 
 Start an inference service
@@ -56,61 +56,9 @@ KServe provides a number of Custom Resource Definitions (CRDs) that you can use
 The current recommended approach from KServe is to use the ``ServingRuntime`` method.
 
 As you start an inference service, you will need models to serve.
-The model format for the AMD Inference Server is the following:
-
-.. code-block:: text
-
-    /
-    ├─ model_a/
-    │  ├─ 1/
-    │  │  ├─ <model>.x
-    │  ├─ <config>.toml
-
-The model name, ``model_a`` in this template, must be unique among the models loaded on a particular server.
-This name is used to name the endpoint used to make inference requests to.
-Under this directory, there must be a directory named ``1/`` containing the model file itself and a TOML file describing the configuration.
-This file, ``<config>.toml`` in this template, can have any name though ``config.toml`` is suggested and will be used in this documentation.
-You can also use ``.pbtxt`` format for single models as well.
-The model file can have an arbitrary name and the file extension depends on the type of the model.
-The ``config.toml`` file contains metadata for the model.
-Consider this example of an MNIST TensorFlow model:
-
-.. code-block:: toml
-
-    name = "mnist"
-    platform = "tensorflow_graphdef"
-
-    [[inputs]]
-    name = "images_in"
-    datatype = "FP32"
-    shape = [28, 28, 1]
-
-    [[outputs]]
-    name = "flatten/Reshape"
-    datatype = "FP32"
-    shape = [10]
-
-The name must match the name of the model directory, i.e. ``model_a``.
-The platform identifies the type of the model and determines the file extension of the model file.
-The supported platforms are:
-
-.. csv-table::
-    :header: Platform,Model file extension
-    :widths: 90, 10
-    :width: 22em
-
-    ``tensorflow_graphdef``,``.pb``
-    ``pytorch_torchscript``,``.pt``
-    ``vitis_xmodel``,``.xmodel``
-    ``onnx_onnxv1``,``.onnx``
-    ``migraphx_mxr``,``.mxr``
-    ``amdinfer_cpp``,``.so``
-
-The inputs and outputs define the list of input and output tensors for the model.
-The names of the tensors may be significant if the platform needs them to perform inference.
-
+These models should be in the format that the inference server expects for its :ref:`model repository <model_repository:Model Repository>`.
 You can put the model up on any of the cloud storage platforms that KServe supports like GCS, S3 and HTTP.
-If you use HTTP, the model should be zipped.
+If you use HTTP, the model should be zipped and should unzip in the expected model repository directory structure.
 Other archive formats such as ``.tar.gz`` may not work as expected.
 Wherever you store it, the URI will be needed to start inference services.
 
@@ -132,7 +80,7 @@ A sample ``ClusterServingRuntime`` definition is provided below.
       name: kserve-amdserver
     spec:
       supportedModelFormats:
-        # depending on the image you're using, and which platforms are added,
+        # depending on the image you're using, and which backends are added,
         # the supported formats could be different. For example, this assumes
         # that a ZenDNN image was created with both TF+ZenDNN and PT+ZenDNN
         # support
diff --git a/docs/links.rst b/docs/links.rst
deleted file mode 100644
index 8de69a0e4..000000000
--- a/docs/links.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-..
-    Copyright 2022 Advanced Micro Devices, Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-.. _InferenceServerRepository: https://github.com/Xilinx/inference-server
-.. _ZenDNN: https://www.amd.com/en/developer/zendnn.html
-.. _ZenDNN_download: https://www.amd.com/en/developer/zendnn.html#downloads
-.. _ZenDNN_guide: https://www.amd.com/en/developer/zendnn.html#documentation
diff --git a/docs/logging.rst b/docs/logging.rst
index c0ce998ad..819a3b746 100644
--- a/docs/logging.rst
+++ b/docs/logging.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
diff --git a/docs/metrics.rst b/docs/metrics.rst
index 9d8b6f381..29c8d813d 100644
--- a/docs/metrics.rst
+++ b/docs/metrics.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
diff --git a/docs/migraphx.rst b/docs/migraphx.rst
deleted file mode 100644
index 10094fae4..000000000
--- a/docs/migraphx.rst
+++ /dev/null
@@ -1,70 +0,0 @@
-..
-    Copyright 2022 Advanced Micro Devices, Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-GPUs - MIGraphX
-===============
-
-Using the AMD Inference Server with MIGraphX and GPUs requires some additional setup prior to use.
-
-Set up the host and GPUs
-------------------------
-
-Prior to installing the Inference Server, first ensure your system recognizes your GPU(s).
-Start by following the `ROCm installation instructions <https://docs.amd.com/category/ROCm%E2%84%A2%20v5.x>`__ for version 5.4.1 or newer.
-Once your system recognizes your GPU(s), proceed to the next step.
-
-Build an image
---------------
-
-To build an image with MIGraphX enabled, you need to add the ``--migraphx`` to the ``amdinfer dockerize`` command:
-
-.. code-block:: bash
-
-    # create the Dockerfile
-    python3 docker/generate.py
-
-    # build the dev image $(whoami)/amdinfer-dev-migraphx:latest
-    ./amdinfer dockerize --migraphx --suffix="-migraphx"
-
-    # build the deployment image $(whoami)/amdinfer-migraphx:latest
-    ./amdinfer dockerize --migraphx --suffix="-migraphx" --production
-
-Start an image
---------------
-
-The development container can be started with:
-
-.. code-block:: console
-
-    $ ./amdinfer run --dev
-
-This automatically adds the detected devices, publishes ports, and mounts some convenient directories, such as your SSH directory, and drops you into a terminal in the container.
-
-You can start the :ref:`deployment container on Docker <docker:start the container>` with something like:
-
-.. code-block:: console
-
-    $ docker run --device /dev/kfd --device /dev/dri [--volume ...]
-
-These ``--device`` flags pass the GPU to the container and you can mount other directories as needed to make models available.
-
-Get assets and models
----------------------
-
-You can download the assets and models used for tests and examples with:
-
-.. code-block:: console
-
-    $ ./amdinfer get --migraphx
diff --git a/docs/model_repository.rst b/docs/model_repository.rst
new file mode 100644
index 000000000..74c88e5b9
--- /dev/null
+++ b/docs/model_repository.rst
@@ -0,0 +1,208 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Model Repository
+================
+
+A model repository is |define_model_repository|.
+
+Single models
+-------------
+
+The directory structure for the model repository for a single model is:
+
+.. code-block:: text
+
+    /
+    ├─ model_a/
+    │  ├─ 1/
+    │  │  ├─ <model>
+    │  ├─ <config>
+    ├─ model_b/
+    |  ...
+
+The model name, ``model_a`` in this template, must be unique among the models loaded on a particular server.
+This name is used to name the endpoint used to make inference requests to.
+Under this directory, there must be a directory named ``1/`` containing the model file itself and a TOML file describing the configuration.
+The model file can have an arbitrary name and the file extension depends on the type of the model.
+This file, ``<config>`` in this template, can have any name though ``config.toml`` is suggested and will be used in this documentation.
+You can also use ``.pbtxt`` format files for single models as well.
+The configuration file contains metadata for the model.
+Consider this example of an MNIST TensorFlow model:
+
+.. code-block:: toml
+
+    name = "mnist"
+    platform = "tensorflow_graphdef"
+
+    [[inputs]]
+    name = "images_in"
+    datatype = "FP32"
+    shape = [28, 28, 1]
+
+    [[outputs]]
+    name = "flatten/Reshape"
+    datatype = "FP32"
+    shape = [10]
+
+The name must match the name of the model directory, i.e. ``model_a``.
+The platform identifies the type of the model and determines the file extension of the model file.
+The supported platforms are:
+
+.. csv-table::
+    :header: Platform,Model file extension
+    :widths: 90, 10
+    :width: 22em
+
+    ``tensorflow_graphdef``,``.pb``
+    ``pytorch_torchscript``,``.pt``
+    ``vitis_xmodel``,``.xmodel``
+    ``onnx_onnxv1``,``.onnx``
+    ``migraphx_mxr``,``.mxr``
+    ``amdinfer_cpp``,``.so``
+
+The inputs and outputs define the list of input and output tensors for the model.
+The names of the tensors may be significant if the platform needs them to perform inference.
+
+The equivalent configuration file as a ``.pbtxt`` file would be:
+
+.. code-block:: text
+
+    name: "mnist"
+    platform: "tensorflow_graphdef"
+    inputs [
+        {
+            name: "images_in"
+            datatype: "FP32"
+            shape: [28, 28, 1]
+        }
+    ]
+    outputs [
+        {
+            name: "flatten/Reshape"
+            datatype: "FP32"
+            shape: [10]
+        }
+    ]
+
+While the inference server will accept a configuration file in this format, note that TOML files take priority if both are present and this format does not support defining :ref:`ensembles <ensembles:Ensembles>`.
+
+Ensembles
+---------
+
+With :term:`ensembles <Ensemble>`, the "model" actually consists of a set of models.
+The directory structure for the model repository for ensembles is:
+
+.. code-block:: text
+
+    /
+    ├─ model_a/
+    │  ├─ 1/
+    │  │  ├─ <model_0>
+    │  │  ├─ <model_1>
+    │  │  ├─ ...
+    │  ├─ <config>
+    ├─ model_b/
+    |  ...
+
+
+As a concrete example, consider a three stage ensemble:
+
+1. ``cplusplus`` backend executing a ``base64_decode`` model: receive a base64-encoded JPEG image and decode it to an RGB array
+2. ``cplusplus`` backend executing a ``invert_image`` model: invert every pixel in the input RGB image
+3. ``cplusplus`` backend executing a ``base64_encode`` model: convert the input RGB image to JPEG, base64-encode it and send it back to client
+
+This ensemble uses the ``cplusplus`` backend for each stage with different models.
+The configuration file for this ensemble could be:
+
+.. code-block:: toml
+    :linenos:
+
+    [[models]]
+    name = "invert_image"
+    platform = "amdinfer_cpp"
+    id = "base64_decode.so"
+
+    [[models.inputs]]
+    name = "image_in"
+    datatype = "STRING"
+    shape = [1048576]
+    id = ""
+
+    [[models.outputs]]
+    name = "image_out"
+    datatype = "INT8"
+    shape = [1080, 1920, 3]
+    id = "preprocessed_image"
+
+    [[models]]
+    name = "execute"
+    platform = "amdinfer_cpp"
+    id = "invert_image.so"
+
+    [[models.inputs]]
+    name = "image_in"
+    datatype = "INT8"
+    shape = [1080, 1920, 3]
+    id = "preprocessed_image"
+
+    [[models.outputs]]
+    name = "image_out"
+    datatype = "INT8"
+    shape = [1080, 1920, 3]
+    id = "inverted_image"
+
+    [[models]]
+    name = "invert_image_postprocess"
+    platform = "amdinfer_cpp"
+    id = "base64_encode.so"
+
+    [[models.inputs]]
+    name = "image_in"
+    datatype = "INT8"
+    shape = [1080, 1920, 3]
+    id = "inverted_image"
+
+    [[models.outputs]]
+    name = "image_out"
+    datatype = "STRING"
+    shape = [1048576]
+    id = ""
+
+This single configuration file lists multiple models reflecting the multiple model files that are in the repository.
+Each model in the ensemble is marked with ``[[models]]`` and has a name and platform just like single models.
+As before, the name is used to define the endpoint.
+For :term:`chains <Chain>`, the first model's name should match the name of the parent directory because this is the endpoint that will be used to send requests to the whole ensemble.
+Each model also has an ID field that should be the name of the model file corresponding to this stage of the ensemble because the ``1/`` directory will contain multiple model files.
+
+You can define one or more input or output tensors for each model using multiple ``[[models.inputs]]`` or ``[[models.outputs]]`` tags, respectively.
+As in the single model case, each input/output tensor has a name, type and shape with the same meaning.
+In the ensemble case, they also have an ID.
+For output tensors, the ID is a unique string labeling this tensor.
+The ID for input tensors should match the ID of the output tensor that is feeding it.
+Input tensors with an empty ID indicate that the data comes from the external client.
+Similarly, output tensors with an empty output ID indicate that the data goes to the external client.
+
+The model repository for this example using the above configuration file would be:
+
+.. code-block:: text
+
+    /
+    ├─ invert_image/
+    │  ├─ 1/
+    │  │  ├─ base64_decode.so
+    │  │  ├─ base64_encode.so
+    │  │  ├─ invert_image.so
+    │  ├─ config.toml
diff --git a/docs/platforms.rst b/docs/prolog.rst
similarity index 74%
rename from docs/platforms.rst
rename to docs/prolog.rst
index 00d80ec60..b1b947b62 100644
--- a/docs/platforms.rst
+++ b/docs/prolog.rst
@@ -1,5 +1,5 @@
 ..
-    Copyright 2022 Advanced Micro Devices, Inc.
+    Copyright 2023 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -13,14 +13,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-Platforms
-=========
-
-The AMD Inference Server supports a number of platforms:
-
-.. toctree::
-    :titlesonly:
-
-    zendnn
-    migraphx
-    vitis_ai
+..
+    The contents of this file are inserted at the beginning of every RST source
+    file
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
new file mode 100644
index 000000000..4d0ceaae7
--- /dev/null
+++ b/docs/quickstart.rst
@@ -0,0 +1,285 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Quickstart
+==========
+
+This quickstart shows you how to deploy the server locally and send inference requests to it.
+These steps elaborate on the quick start example described in the project :github:`README <Xilinx/inference-server#quick-start-deployment-and-inference>`.
+The README example uses a script that takes care of the setup that is manually performed here but this guide should help you better understand what is needed to deploy the server and use it.
+If you already have the server deployed somewhere, you can skip ahead to the :ref:`inference section <deploymentSummary>`.
+
+.. note::
+
+    This guide shows you how to get started quickly.
+    It is not intended to demonstrate all the different options and settings that could be applied at different stages.
+
+Prerequisites
+-------------
+
+For making an inference:
+
+* A Linux host machine with Python 3.6+
+
+For deploying the server:
+
+* A Linux host machine with `Docker <LinkDockerInstallLinux_>`_ installed
+* Sufficient disk space to host your models
+
+This guide assumes that inference will be made from the same machine where the server is deployed.
+
+Prepare the model repository
+----------------------------
+
+A model repository is |define_model_repository|.
+
+.. code-block:: text
+
+    /
+    ├─ resnet50/
+    │  ├─ 1/
+    │  │  ├─ <model>
+    │  ├─ config.toml
+
+The model name, ``resnet50`` in this template, must be unique among the models loaded on a particular server and it must match the name used in the configuration TOML file.
+This name is used to name the endpoint that clients use to make inference requests.
+Under this directory, there must be a directory named ``1/`` containing the model file itself and a TOML file containing the metadata for the model.
+This TOML file may be named anything but ``config.toml`` is suggested and used throughout this documentation.
+The model file can also have an arbitrary name and the file extension depends on the type of the model.
+
+In this guide, you will deploy a single ResNet50 model.
+You can create a model repository in your current working directory using these steps.
+Depending on what hardware you want to use and have on your host machine, you can use the appropriate model.
+The CPU version has no special hardware requirements to run so you can always run that.
+
+.. tabs::
+
+    .. code-tab:: console CPU
+
+        $ wget -O tensorflow.zip https://www.xilinx.com/bin/public/openDownload?filename=tf_resnetv1_50_imagenet_224_224_6.97G_2.5.zip
+        $ unzip -j "tensorflow.zip" "tf_resnetv1_50_imagenet_224_224_6.97G_2.5/float/resnet_v1_50_baseline_6.96B_922.pb" -d .
+        $ mkdir -p ./model_repository/resnet50/1
+        $ mv ./resnet_v1_50_baseline_6.96B_922.pb ./model_repository/resnet50/1/
+
+    .. code-tab:: console GPU
+
+        $ wget https://github.com/onnx/models/raw/main/vision/classification/resnet/model/resnet50-v2-7.onnx
+        $ mkdir -p ./model_repository/resnet50/1
+        $ mv ./resnet50-v2-7.onnx ./model_repository/resnet50/1/
+
+    .. code-tab:: console FPGA
+
+        $ wget -O vitis.tar.gz https://www.xilinx.com/bin/public/openDownload?filename=resnet_v1_50_tf-u200-u250-r2.5.0.tar.gz
+        $ tar -xzf vitis.tar.gz "resnet_v1_50_tf/resnet_v1_50_tf.xmodel"
+        $ mkdir -p ./model_repository/resnet50/1
+        $ mv ./resnet_v1_50_tf/resnet_v1_50_tf.xmodel ./model_repository/resnet50/1/
+
+For the models used here, their corresponding ``config.toml`` should be placed in the chosen model repository (``./model_repository/resnet50/``):
+
+.. tabs::
+
+    .. code-tab:: toml CPU
+
+        name = "resnet50"
+        platform = "tensorflow_graphdef"
+
+        [[inputs]]
+        name = "input"
+        datatype = "FP32"
+        shape = [224, 224, 3]
+
+        [[outputs]]
+        name = "resnet_v1_50/predictions/Reshape_1"
+        datatype = "FP32"
+        shape = [1000]
+
+    .. code-tab:: text GPU
+
+        name = "resnet50"
+        platform = "onnx_onnxv1"
+
+        [[inputs]]
+        name = "input"
+        datatype = "FP32"
+        shape = [224, 224, 3]
+
+        [[outputs]]
+        name = "output"
+        datatype = "FP32"
+        shape = [1000]
+
+    .. code-tab:: console FPGA
+
+        name = "resnet50"
+        platform = "vitis_xmodel"
+
+        [[inputs]]
+        name = "input"
+        datatype = "INT8"
+        shape = [224, 224, 3]
+
+        [[outputs]]
+        name = "output"
+        datatype = "INT8"
+        shape = [1000]
+
+The name must match the name of the model directory: it defines the endpoint that will be used for inference.
+The platform identifies the type of the model and determines the file extension of the model file.
+
+The inputs and outputs define the list of input and output tensors for the model.
+The names of the tensors may be significant if the backend needs them to perform inference.
+
+Get the deployment image
+------------------------
+
+The deployment image is optimized for size and only contains the run-time dependencies of the server to allow for quicker deployments.
+It has limited debugging capabilities and it contains a precompiled executable for the server that automatically starts when the container starts.
+You can pull the :ref:`deployment image <deployment:Deployment image>` if it exists or build it yourself.
+
+.. include:: dry.rst
+    :start-after: +docker_pull_deployment_images
+    :end-before: -docker_pull_deployment_images
+
+Start the image
+---------------
+
+You can start a container from the deployment image with ``docker run`` as any other image.
+For more information about these flags and other options you can use, refer to its `documentation <LinkDockerRun_>`_.
+The flags used in this sample command are:
+
+* ``--volume $(pwd)/model_repository:/mnt/models:rw``: mount the model repository you created above into the container to where the server expects it to be. This allows the server to load these models at startup.
+* ``--net=host``: use the host networking in the container. By default, the server uses ports 8998 and 50051 for HTTP and gRPC communication, respectively. By using this flag, you can use these same ports on the host to send requests to the server in the container.
+* ``--device <path/to/device/file>``: pass the specified files into the server. If you are using hardware accelerators, these devices need to be passed into the container so they can be used. For GPUs, this will be ``--device /dev/kfd --device /dev/dri``. For FPGAs, this will be ``--device /dev/dri --device /dev/xclmgmt<id>``, where the ID of the ``xclmgmt`` device will depend on your particular machine.
+
+.. tip::
+
+    Using ``--net=host`` will not work if the default ports are unavailable on your host machine.
+    In this case, you can omit this flag and use ``--publish`` to map these ports in the container to other ports on your host machine.
+    Refer to the ``docker run`` documentation for more information.
+
+.. tabs::
+
+    .. code-tab:: console CPU
+
+        $ docker run -d --volume $(pwd)/model_repository:/mnt/models:rw --net=host amdih/serve:uif1.1_zendnn_amdinfer_0.3.0
+
+    .. code-tab:: console GPU
+
+        $ docker run -d --device /dev/kfd --device /dev/dri --volume $(pwd)/model_repository:/mnt/models:rw --publish 127.0.0.1::8998 --publish 127.0.0.1::50051 amdih/serve:uif1.1_migraphx_amdinfer_0.3.0
+
+    .. code-tab:: console FPGA
+
+        $ docker run -d --device /dev/dri --device /dev/xclmgmt<id> --volume $(pwd)/model_repository:/mnt/models:rw --publish 127.0.0.1::8998 --publish 127.0.0.1::50051 <image>
+
+The endpoints for each model will be the name of the model in the ``config.toml``, which should match the name of the parent directory in the model repository.
+In this example, it would be "resnet50".
+You are now ready to make requests to this server.
+
+.. _deploymentSummary:
+
+Server deployment summary
+-------------------------
+
+After setting up the server as above, you have the following information:
+
+* IP address: 127.0.0.1 since the server is running on the same machine where you will run the inference
+* Ports: 8998 and 50051 for HTTP and gRPC, respectively. If you used ``--publish``, your port numbers may be different and you can see what they are using ``docker ps``.
+* Endpoint: "resnet50" since that is what the model name was used in the model repository and in the configuration file
+
+The rest of this example will use these values in the sample code so substitute your own values if they are different.
+
+Get the Python library
+----------------------
+
+The ``amdinfer`` client library allows you to make clients that you can use to communicate with the server over any protocol that the server supports.
+Clients for different protocols have the same base set of methods so you can easily replace one with another.
+The library can be used from C++ or Python.
+In this example, you will use the Python library, which you can install with ``pip``:
+
+.. code-block:: console
+
+    $ pip install amdinfer
+
+Running an example
+------------------
+
+The `AMD Inference Server repository <LinkInferenceServerRepository_>`_ includes examples that demonstrate running an end-to-end inference request.
+This particular example targets the ResNet50 model you've already deployed on the server above.
+To perform the inference, you will need some files that are available in the repository:
+
+.. parsed-literal::
+
+    $ wget :amdinferRawFull:`examples/resnet50/imagenet_classes.txt`
+    $ wget :amdinferRawFull:`tests/assets/dog-3619020_640.jpg`
+    $ wget :amdinferRawFull:`examples/resnet50/resnet.py`
+
+These files provide the class labels, a sample image and a helper Python script.
+You will also need the particular example file corresponding to the same hardware your server is intended for.
+You can download this file and run it to perform an inference on the server.
+At a high-level, the example script performs pre-processing on the image, constructs a request and sends it to the server.
+The server responds with the results of the inference.
+These results are post-processed and the top 5 labels for the image are printed.
+
+.. tabs::
+
+    .. group-tab:: CPU
+
+        .. parsed-literal::
+
+            $ wget :amdinferRawFull:`examples/resnet50/tfzendnn.py`
+            $ python3 tfzendnn.py --ip 127.0.0.1 --grpc-port 50051 --endpoint resnet50 --image ./dog-3619020_640.jpg --labels ./imagenet_classes.txt
+
+    .. group-tab:: GPU
+
+        .. parsed-literal::
+
+            $ wget :amdinferRawFull:`examples/resnet50/migraphx.py`
+            $ python3 migraphx.py --ip 127.0.0.1 --http-port 8998 --endpoint resnet50 --image ./dog-3619020_640.jpg --labels ./imagenet_classes.txt
+
+    .. group-tab:: FPGA
+
+        .. parsed-literal::
+
+            $ wget :amdinferRawFull:`examples/resnet50/vitis.py`
+            $ python3 vitis.py --ip 127.0.0.1 --http-port 8998 --endpoint resnet50 --image ./dog-3619020_640.jpg --labels ./imagenet_classes.txt
+
+After running the script, you should get output similar to the following.
+The exact output may be slightly different depending on whether you used CPU, GPU or FPGA versions of the example.
+
+.. code-block:: text
+
+    Running the TF+ZenDNN example for ResNet50 in Python
+    Waiting until the server is ready...
+    Making inferences...
+    Top 5 classes for ./dog-3619020_640.jpg:
+      n02112018 Pomeranian
+      n02112350 keeshond
+      n02086079 Pekinese, Pekingese, Peke
+      n02112137 chow, chow chow
+      n02113023 Pembroke, Pembroke Welsh corgi
+
+Inference summary
+-----------------
+
+To perform inference, you need to write an application that uses the AMD Inference Server's client library to construct a request and send it to the server.
+Communicating with the server requires you to know its address, IP and port, as well as an endpoint.
+The endpoint uniquely identifies a particular model running in the server.
+When there are multiple models running, the endpoint becomes important to differentiate where to send to send the request.
+The server responds to the request and you can examine the results to take further action.
+
+Next steps
+----------
+
+To learn more about the Python script you ran to run the inference, walk through the script in this :ref:`example <example_resnet50_python:Running ResNet50 - Python>`.
diff --git a/docs/quickstart_deployment.rst b/docs/quickstart_deployment.rst
deleted file mode 100644
index 7c9f923eb..000000000
--- a/docs/quickstart_deployment.rst
+++ /dev/null
@@ -1,197 +0,0 @@
-..
-    Copyright 2022 Advanced Micro Devices, Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-Quickstart - Deployment
-=======================
-
-This quickstart is intended for a user who is deploying the inference server and configuring the available models for inference.
-There are multiple ways to deploy the server but this quickstart only covers one Docker-based deployment.
-Once the server is up, you and any clients can :ref:`make requests to it <quickstart_inference:Quickstart - Inference>`.
-
-Prerequisites
--------------
-
-* `Docker <https://docs.docker.com/get-docker/>`__
-* Network access to enable clients to access the server
-* Sufficient disk space to host your models
-
-Prepare the model repository
-----------------------------
-
-As the server administrator, you need to identify which models you want to make available for inference and organize them into a model repository.
-The model repository is a directory on your host machine where the server is running that will hold your models and their associated metadata.
-The format of the directory is as follows:
-
-.. code-block:: text
-
-    /
-    ├─ model_a/
-    │  ├─ 1/
-    │  │  ├─ <model>.x
-    │  ├─ config.toml
-    | model_b/
-    |  ...
-
-The model name, ``model_a`` in this template, must be unique among the models loaded on a particular server.
-This name is used to name the endpoint used to make inference requests to.
-Under this directory, there must be a directory named ``1/`` containing the model file itself and a TOML file containing the metadata for the model.
-This file may be named anything but ``config.toml`` is suggested and used throughout this documentation.
-The model file can have an arbitrary name and the file extension depends on the type of the model.
-
-As an example, consider a deployment of a single ResNet50 model.
-
-.. tabs::
-
-    .. code-tab:: console CPU
-
-        $ wget -O tensorflow.zip https://www.xilinx.com/bin/public/openDownload?filename=tf_resnetv1_50_imagenet_224_224_6.97G_2.5.zip
-        $ unzip -j "tensorflow.zip" "tf_resnetv1_50_imagenet_224_224_6.97G_2.5/float/resnet_v1_50_baseline_6.96B_922.pb" -d .
-        $ mkdir -p /tmp/model_repository/resnet50/1
-        $ mv ./resnet_v1_50_baseline_6.96B_922.pb /tmp/model_repository/resnet50/1/saved_model.pb
-
-    .. code-tab:: console GPU
-
-        $ wget https://github.com/onnx/models/raw/main/vision/classification/resnet/model/resnet50-v2-7.onnx
-        $ mkdir -p /tmp/model_repository/resnet50/1
-        $ mv ./resnet50-v2-7.onnx /tmp/model_repository/resnet50/1/saved_model.onnx
-
-    .. code-tab:: console FPGA
-
-        $ wget -O vitis.tar.gz https://www.xilinx.com/bin/public/openDownload?filename=resnet_v1_50_tf-u200-u250-r2.5.0.tar.gz
-        $ tar -xzf vitis.tar.gz "resnet_v1_50_tf/resnet_v1_50_tf.xmodel"
-        $ mkdir -p /tmp/model_repository/resnet50/1
-        $ mv ./resnet_v1_50_tf/resnet_v1_50_tf.xmodel /tmp/model_repository/resnet50/1/saved_model.xmodel
-
-For the models used here, their corresponding ``config.toml`` should be placed in the chosen model repository (``/tmp/model_repository/resnet50/``):
-
-.. tabs::
-
-    .. code-tab:: toml CPU
-
-        name = "resnet50"
-        platform = "tensorflow_graphdef"
-
-        [[inputs]]
-        name = "input"
-        datatype = "FP32"
-        shape = [224, 224, 3]
-
-        [[outputs]]
-        name = "resnet_v1_50/predictions/Reshape_1"
-        datatype = "FP32"
-        shape = [1000]
-
-    .. code-tab:: text GPU
-
-        name = "resnet50"
-        platform = "onnx_onnxv1"
-
-        [[inputs]]
-        name = "input"
-        datatype = "FP32"
-        shape = [224, 224, 3]
-
-        [[outputs]]
-        name = "output"
-        datatype = "FP32"
-        shape = [1000]
-
-    .. code-tab:: console FPGA
-
-        name = "resnet50"
-        platform = "vitis_xmodel"
-
-        [[inputs]]
-        name = "input"
-        datatype = "INT8"
-        shape = [224, 224, 3]
-
-        [[outputs]]
-        name = "output"
-        datatype = "INT8"
-        shape = [1000]
-
-The name must match the name of the model directory.
-The platform identifies the type of the model and determines the file extension of the model file.
-The supported platforms are:
-
-.. csv-table::
-    :header: Platform,Model file extension
-    :widths: 90, 10
-    :width: 22em
-
-    ``tensorflow_graphdef``,``.pb``
-    ``pytorch_torchscript``,``.pt``
-    ``vitis_xmodel``,``.xmodel``
-    ``onnx_onnxv1``,``.onnx``
-    ``migraphx_mxr``,``.mxr``
-    ``amdinfer_cpp``,``.so``
-
-The inputs and outputs define the list of input and output tensors for the model.
-The names of the tensors may be significant if the platform needs them to perform inference.
-
-Get the deployment image
-------------------------
-
-The deployment image is optimized for size and only contains the runtime dependencies of the server to allow for quicker deployments.
-It has limited debugging capabilities and it contains a precompiled executable for the server that automatically starts when the container starts.
-You can pull the deployment image with Docker if it exists or :ref:`build it yourself <docker:Build the deployment Docker image>`.
-
-.. tabs::
-
-    .. code-tab:: console CPU
-
-        $ docker pull amdih/serve:uif1.1_zendnn_amdinfer_0.3.0
-
-    .. code-tab:: text GPU
-
-        $ docker pull amdih/serve:uif1.1_migraphx_amdinfer_0.3.0
-
-    .. code-tab:: console FPGA
-
-        # this image is not currently pre-built but you can build it yourself
-
-Start the image
----------------
-
-You can start a container from the deployment image with ``docker`` as any other image:
-
-.. tabs::
-
-    .. code-tab:: console CPU
-
-        $ docker run -d --volume /path/to/model/repository:/mnt/models:rw --publish 127.0.0.1::8998 --publish 127.0.0.1::50051 <image>
-
-    .. code-tab:: console GPU
-
-        $ docker run -d --device /dev/kfd --device /dev/dri --volume /path/to/model/repository:/mnt/models:rw --publish 127.0.0.1::8998 --publish 127.0.0.1::50051 <image>
-
-    .. code-tab:: console FPGA
-
-        $ docker run -d --device /dev/dri --device /dev/xclmgmt<id> --volume /path/to/model/repository:/mnt/models:rw --publish 127.0.0.1::8998 --publish 127.0.0.1::50051 <image>
-
-.. note::
-
-    These commands are provided as an example for different hardware devices.
-    Depending on your particular device(s) or desired container configuration, you may need to add or remove flags.
-
-As the container starts, it will start the server and load the models from your model repository in ``/mnt/models`` in the container.
-By default, the container will start the server executable in the container that will use the repository at the default location of ``/mnt/models`` and load all the found models.
-The ``--publish`` flags will map ports 8998 and 50051 in the container to arbitrary free ports on the host machine for HTTP and gRPC requests, respectively.
-You can use ``docker ps`` to show the running containers and what ports on the host machine are used by the container.
-Your clients will need these port numbers to make requests to the server.
-The endpoints for each model will be the name of the model in the ``config.toml``, which should match the name of the parent directory in the model repository.
-In this example, it would be "resnet50".
-Once the container is started, you and any clients can :ref:`make requests to it <quickstart_inference:Quickstart - Inference>`.
diff --git a/docs/quickstart_development.rst b/docs/quickstart_development.rst
index 495e45e5e..b64df9476 100644
--- a/docs/quickstart_development.rst
+++ b/docs/quickstart_development.rst
@@ -14,30 +14,30 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-Quickstart - Development
-========================
+Developer Quickstart
+====================
 
 This quickstart is intended for a user who is developing, testing, debugging or otherwise working more deeply with the inference server.
-There are multiple ways to build the server but this quickstart only covers Docker-based development using the included Python run script ``amdinfer``.
+There are multiple ways to build the server but this quickstart only covers Docker-based development using the *amdinfer* script.
 
 Prerequisites
 -------------
 
+A Linux host machine with:
+
 * `Docker <https://docs.docker.com/get-docker/>`__
-* `Docker-Compose <https://docs.docker.com/compose/install/>`__ (optional - used for some tests)
 * Python3
 * git
-* Network access to clone the repository
+* Network access to clone the repository and get test artifacts
 * Sufficient disk space to download test data and assets
 
-
 Set up the host
 ---------------
 
-The inference server supports multiple platforms and hardware backends.
-Ensure that you set up your host appropriately depending on which platform(s) you are using.
+The inference server supports multiple backends.
+Ensure that you set up your host appropriately depending on which backend(s) you are using.
 For example, to use GPUs, you will need to install the drivers.
-More information on host setup can be found in :ref:`each platforms' guide <platforms:Platforms>`.
+More information on host setup can be found in :ref:`each backends' guide <backends:Backends>`.
 
 Get the code
 ------------
@@ -50,11 +50,33 @@ Use ``git`` to clone the repository from Github:
     $ cd inference-server
 
 Tests and examples need assets like images and videos to run.
-Some of these files are stored in `Git LFS <https://git-lfs.github.com/>`__.
+Some of these files are stored in the repository using `Git LFS <https://git-lfs.com/>`__.
 Depending on your host, these files may be automatically downloaded with the ``git clone``.
 If some of the files in ``tests/assets`` are very small (less than 300 bytes), then you haven't downloaded these Git LFS artifacts.
 From your host or after entering the development container, use ``git lfs pull`` to get these files.
 
+amdinfer script
+---------------
+
+This Python script is located at the root of the repository.
+It provides a standardized way to do common tasks such as building images, compiling the server, and running tests.
+This documentation exclusively uses this script for performing these tasks.
+
+The *amdinfer* script has serveral subcommands such as ``build``, ``dockerize`` and ``test``.
+The script's main ``--help`` lists all the supported subcommands.
+Each subcommand also has its own ``--help`` where its options are listed.
+If you want to see the underlying commands that are being executed, use the flag ``--dry-run`` before the subcommand.
+For example, to see the ``docker build`` command being invoked during ``dockerize``, use:
+
+.. code-block:: console
+
+    $ ./amdinfer --dry-run dockerize
+
+This functionality lets you edit the command if the default command does not work for you.
+However, you should use the ``--help`` flag first to see if what you need is already provided by a flag.
+
+You can see the full documentation for this script using the ``--help`` flags or :ref:`online <amdinfer_script:amdinfer Script>`.
+
 Build or get the Docker image
 -----------------------------
 
@@ -64,12 +86,14 @@ You can pull the development image from a Docker registry if it's already built.
 
     $ docker pull <image>
 
-To build a development image from source, run the following commands:
+To build a development image from the repository, run the following commands:
 
 .. tabs::
 
     .. code-tab:: console CPU
 
+        # The ZenDNN backend requires additional steps before building.
+        # See the ZenDNN backend documentation for more information
         $ python3 docker/generate.py
         $ ./amdinfer dockerize --ptzendnn /path/to/ptzendnn/archive --tfzendnn /path/to/tfzendnn/archive
 
@@ -84,10 +108,10 @@ To build a development image from source, run the following commands:
         $ ./amdinfer dockerize --vitis
 
 The ``generate.py`` script is used to create a dockerfile in the root directory, which is then used by the ``dockerize`` command.
-Then, this dockerfile is used to build the development image with the appropriate platform enabled.
-You can also combine the platform flags to enable multiple platforms in one image.
-Look at the :ref:`platform-specific documentation <platforms:Platforms>` for more information.
-By default, this builds the development image as ``<username>/amdinfer-dev:latest``.
+Then, this dockerfile is used to build the development image with the appropriate backend enabled.
+You can also combine the backend flags to enable multiple backends in one image.
+Look at the :ref:`backend-specific documentation <backends:Backends>` for more information about building an image with that backend.
+By default, this tags the resulting development image as ``<username>/amdinfer-dev:latest``.
 
 After the image is built, you can use it to start a container:
 
@@ -104,14 +128,15 @@ Compiling the AMD Inference Server
 ----------------------------------
 
 These commands are all run inside the development container.
-Here, :file:`./amdinfer` is aliased to :command:`amdinfer`.
+Here, ``./amdinfer`` is aliased to ``amdinfer``.
 
 .. code-block:: console
 
     $ amdinfer build
 
-The build command builds the :program:`amdinfer-server` executable, the C++ examples and the C++ tests.
-By default, this will be the debug version.
+The build command builds everything including the server executable (``amdinfer-server``), the C++ examples and the C++ tests.
+The ``build`` will also install the server's Python library in the development container.
+By default, everything will be compiled in Debug mode.
 You can pass flags to ``build`` to control the compile options.
 
 .. tip::
@@ -125,24 +150,18 @@ You can pass flags to ``build`` to control the compile options.
     In general, you should not use ``sudo`` to run ``amdinfer`` commands.
     Some commands create files in your working directory and using ``sudo`` creates files with mixed permissions in your container and host and will even fail in some cases.
 
-The ``build`` will also install the server's Python library in the development container.
-
-.. code-block:: console
-
-    pip list | grep amdinfer
-
 Get test artifacts
 ------------------
 
 For running tests and examples, you need to get models and other files that they use.
 Make sure you have `Git LFS <https://git-lfs.github.com/>`__ installed.
-You can download all files, as shown below with the ``--all`` flag, or download platform-specific files by passing the appropriate flag(s).
+You can download all files, as shown below with the flags, or download backend-specific/model-specific files by passing the appropriate flag(s).
 Use ``--help`` to see the options available.
 
 .. code-block:: console
 
     $ git lfs pull
-    $ amdinfer get --all
+    $ amdinfer get --all-models --all-backends
 
 You must abide by the license agreements of these files, if you choose to download them.
 
diff --git a/docs/quickstart_inference.rst b/docs/quickstart_inference.rst
deleted file mode 100644
index 3fa66a22e..000000000
--- a/docs/quickstart_inference.rst
+++ /dev/null
@@ -1,233 +0,0 @@
-..
-    Copyright 2022 Advanced Micro Devices, Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-.. include:: links.rst
-
-Quickstart - Inference
-======================
-
-This quickstart is intended for a user who is not configuring or maintaining the inference server and is just making inference requests to an existing server.
-There are multiple ways to make requests to the server but this quickstart only covers making requests using the inference server's client library ``amdinfer``.
-
-To make requests, you need the address of the server and the endpoint(s) for the models you want to use for inference.
-Depending on how it is configured, the server may support HTTP/REST, gRPC or both protocols.
-Your server administrator can provide this information.
-
-Get the library
----------------
-
-The ``amdinfer`` library allows you to make clients that you can use to communicate with the server over any protocol that the server supports.
-Clients for different protocols have the same base set of methods so you can easily replace one with another.
-The library can be used from C++ or Python.
-
-To use the Python library, install with ``pip``:
-
-.. code-block:: console
-
-    $ pip install amdinfer
-
-You can use the development container to use both the C++ and Python libraries:
-
-.. code-block:: console
-
-    $ git clone https://github.com/Xilinx/inference-server.git
-    $ cd inference-server
-    $ python3 docker/generate.py
-    $ ./amdinfer dockerize
-    $ ./amdinfer run --dev --net-host
-
-This will build, start the development container and drop you into a terminal in the container.
-Then, inside the container:
-
-.. code-block:: console
-
-    $ amdinfer install
-
-This will install both the C++ and Python libraries in the container, which you can confirm:
-
-.. tabs::
-
-    .. code-tab:: console Python
-
-        $ pip list | grep amdinfer
-
-    .. code-tab:: console C++
-
-        $ echo -e '#include "amdinfer/amdinfer.hpp"\nint main(){return 0;}' | g++ -x c++ -std=c++17 -o test.out /dev/stdin
-
-Running the examples
---------------------
-
-The `AMD Inference Server repository <InferenceServerRepository_>`_ includes examples that demonstrate running an end-to-end inference request.
-To run the examples listed here, you need to ensure that the ``amdinfer`` Python library is installed and that the server you're using has a compatible model loaded.
-These examples assume a ResNet50 model trained on the ImageNet dataset is available on the server and use a sample image and labels from the inference server repository but you can also use your own.
-
-.. parsed-literal::
-
-    $ wget :amdinferRawFull:`examples/resnet50/imagenet_classes.txt`
-    $ wget :amdinferRawFull:`tests/assets/dog-3619020_640.jpg`
-    $ wget :amdinferRawFull:`examples/resnet50/resnet.py`
-
-.. tabs::
-
-    .. group-tab:: CPU
-
-        .. parsed-literal::
-
-            $ wget :amdinferRawFull:`examples/resnet50/tfzendnn.py`
-            $ python3 tfzendnn.py --ip <ip_address> --grpc-port <port> --endpoint <endpoint> --image ./dog-3619020_640.jpg --labels ./imagenet_classes.txt
-
-    .. group-tab:: GPU
-
-        .. parsed-literal::
-
-            $ wget :amdinferRawFull:`examples/resnet50/migraphx.py`
-            $ python3 migraphx.py --ip <ip_address> --http-port <port> --endpoint <endpoint> --image ./dog-3619020_640.jpg --labels ./imagenet_classes.txt
-
-    .. group-tab:: FPGA
-
-        .. parsed-literal::
-
-            $ wget :amdinferRawFull:`examples/resnet50/vitis.py`
-            $ python3 vitis.py --ip <ip_address> --http-port <port> --endpoint <endpoint> --image ./dog-3619020_640.jpg --labels ./imagenet_classes.txt
-
-Using the library
------------------
-
-The examples above demonstrate a full end-to-end inference using the ``amdinfer`` Python library on a specific ResNet50 model.
-You can write your own scripts and programs to make inference requests to other models.
-The examples work similarly and you can use them for reference.
-
-The first step is to create a client.
-The type of client you create will depend on what protocols the server you're using supports and which protocol you want to use.
-
-.. tabs::
-
-    .. code-tab:: python
-
-        # your server administrator must provide the values for these variables:
-        #   - http_server_addr: HTTP address of the server, if supported
-        #   - grpc_server_addr: gRPC address of the server, if supported
-        #   - endpoint: string to identify the model for inference. If there are
-        #               multiple models available, each model will have its own
-        #               endpoint that you can use to request inferences from it
-        http_server_addr = "http://127.0.0.1:8998"
-        grpc_server_addr = "127.0.0.1:50051"
-        endpoint = "endpoint"
-
-        import amdinfer
-
-        # create a client to communicate to the server over HTTP
-        http_client = amdinfer.HttpClient(http_server_addr)
-
-        # create a client to communicate to the server over gRPC
-        grpc_client = amdinfer.GrpcClient(grpc_server_addr)
-
-    .. code-tab:: c++
-
-        // your server administrator must provide the values for these variables:
-        //   - http_server_addr: HTTP address of the server, if supported
-        //   - grpc_server_addr: gRPC address of the server, if supported
-        //   - endpoint: string to identify the model for inference. If there are
-        //               multiple models available, each model will have its own
-        //               endpoint that you can use to request inferences from it
-        const std::string http_server_addr = "http://127.0.0.1:8998";
-        const std::string grpc_server_addr = "127.0.0.1:50051";
-        const std::string endpoint = "endpoint";
-
-        #include "amdinfer/amdinfer.hpp"
-
-        // create a client to communicate to the server over HTTP
-        const amdinfer::HttpClient http_client{http_server_addr};
-
-        // create a client to communicate to the server over gRPC
-        const amdinfer::GrpcClient grpc_client{grpc_server_addr};
-
-The library also defines the object that you have to populate to send a request: an ``InferenceRequest``.
-A request is made up of, at minimum, one or more ``InferenceRequestInput`` objects that define the input tensor(s) of your request.
-Each tensor must have a name, a data type, an associated shape and the data itself.
-
-.. tabs::
-
-    .. code-tab:: python
-
-        request = amdinfer.InferenceRequest()
-
-        input_tensor = amdinfer.InferenceRequestInput()
-        # depending on the model, the string used here may be significant
-        input_tensor.name = "input_0"
-        input_tensor.datatype = amdinfer.DataType.INT64
-        input_tensor.shape = [2, 3]
-        # the data should be flattened
-        input_tensor.setInt64Data([1, 2, 3, 4, 5, 6])
-
-        request.addInputTensor(input_tensor)
-
-        response = http_client.modelInfer(endpoint, request)
-        # either client can be used interchangeably
-        # response = grpc_client.modelInfer(endpoint, request)
-
-    .. code-tab:: c++
-
-        amdinfer::InferenceRequest request;
-
-        amdinfer::InferenceRequestInput input_tensor;
-        // depending on the endpoint, the string used here may be significant
-        input_tensor.setName("input_0");
-        input_tensor.setDatatype(amdinfer::DataType::Int64);
-        input_tensor.setShape({2, 3});
-        // the data should be flattened
-        std::vector<uint64_t> data{{1, 2, 3, 4, 5, 6}};
-        input_tensor.setData(data.data());
-
-        request.addInputTensor(input_tensor)
-
-        response = http_client.modelInfer(endpoint, request)
-        // either client can be used interchangeably
-        // response = grpc_client.modelInfer(endpoint, request)
-
-The result of the inference is an ``InferenceResponse`` object that you can examine to get the results.
-
-.. tabs::
-
-    .. code-tab:: python
-
-        assert not response.isError()
-        output_tensors = response.getOutputs()
-
-        for output_tensor in output_tensors:
-            shape = output_tensor.shape
-            datatype = output_tensor.datatype
-            data = output.getFp32Data()
-            size = output.getSize()
-
-    .. code-tab:: c++
-
-        assert(!response.isError());
-        // vector of amdinfer::InferenceResponseOutput objects
-        auto output_tensors = response.getOutputs();
-
-        for(auto &output_tensor : outputs){
-            auto shape = output_tensor.getShape();
-            auto datatype = output_tensor.getDataType()
-            auto* data = static_cast<float*>(output_tensor.getData());
-            auto size = output.getSize();
-        }
-
-These examples show how to use the library to construct a request, make an inference and examine the response.
-They do not show any model-specific pre- and post-processing that may be needed.
-If needed, you must implement it or use an existing implementation for your model.
-
-For more information about usage and the available methods, look at the examples or the documentation for the :ref:`C++ <cpp_user_api:c++>` and :ref:`Python <python:API>` APIs.
diff --git a/docs/rest.rst b/docs/rest.rst
index e71806729..9353e3387 100644
--- a/docs/rest.rst
+++ b/docs/rest.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
diff --git a/docs/roadmap.rst b/docs/roadmap.rst
index 9562ef241..8a3c5f62a 100644
--- a/docs/roadmap.rst
+++ b/docs/roadmap.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
diff --git a/docs/terminology.rst b/docs/terminology.rst
new file mode 100644
index 000000000..08104f021
--- /dev/null
+++ b/docs/terminology.rst
@@ -0,0 +1,96 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Terminology
+===========
+
+This page presents some important terminology to frame the rest of the documentation.
+
+amdinfer
+--------
+
+Depending on the context, *amdinfer* can be used to refer to different things.
+If the usage is ambiguous, it will be qualified with the appropriate word to clarify the meaning:
+
+* *amdinfer* script: refers to the Python script named ``amdinfer`` in the root of the repository that is used for building and starting containers as well as starting the server and running tests.
+* *amdinfer* namespace: refers to the C++ namespace used in the source code
+* *amdinfer* package: refers to the Python package with the Python client library for the inference server. This package is installable from ``pip``.
+
+Types of Docker images
+----------------------
+
+There are two types of Docker images that are used in this project: *development* and *deployment*.
+
+.. _terminology~Development:
+
+Development
+^^^^^^^^^^^
+
+Development images contain both the build-time and run-time dependencies of the server executable.
+They also contains other tools such as linting tools to help the development process.
+These images are used to compile and test the server executable using the tests in the repository.
+They are not pre-built and must be built by the user using the provided scripts.
+The development images do not contain any inference server source code.
+Instead, the standard workflow to use development images is to clone the inference server repository, build a development image and start a container using the provided script that will mount the working directory into the container.
+Under the standard naming convention used by the *amdinfer* script during the build, this image will be tagged as ``$(whoami)/amdinfer-dev:latest``.
+
+.. _terminology~Deployment:
+
+Deployment
+^^^^^^^^^^
+
+Deployment images contain only the the compiled server executable and its run-time dependencies.
+They are optimized for size and used to deploy the server locally, on Kubernetes or on KServe.
+By default, as deployment images start, they start the server executable automatically with the default arguments.
+You can override these values by setting your own when you start a container from this image.
+The published images for the AMD Inference Server on `Docker Hub <LinkInferenceServerDockerHub_>`_ are deployment images.
+Under the standard naming convention used by the *amdinfer* script during the build, this image will be tagged as ``$(whoami)/amdinfer:latest``.
+
+Types of users
+--------------
+
+Different *users* of the AMD Inference Server have different needs.
+There are three overlapping sets of users for the inference server: *clients*, *administrators* and *developers*.
+Where appropriate, the documentation will note the intended audience of the content.
+
+Clients
+^^^^^^^
+
+Clients interact with the server using its APIs to send it inference requests.
+The server also provides additional methods to check its status or that of the running models that clients can use.
+Clients can talk to the server over any of the protocols that the server exposes for communication such as HTTP/REST or gRPC.
+Using the server's C++ API, clients can write custom applications that use the server backend directly.
+The easiest way for clients to communicate to the server is using one of the provided client libraries but they can also use the supported protocols directly.
+
+Administrators
+^^^^^^^^^^^^^^
+
+Administrators *deploy* the server by making it available to respond to inference requests from clients.
+They must configure which protocols the server will use, which models are active and how they are configured, and where the server will run.
+The AMD Inference Server is deployed with a deployment container running on a host machine with Docker.
+It can also be deployed on a cluster with Kubernetes or KServe.
+The appropriate Docker image(s) will be provided to administrators for deployment on the target machines.
+Choosing the appropriate machine(s) to host the server is important because it determines which *backends* are supported, which in turn determines which models can be used.
+Backends define how to execute a model.
+For example, the MIGraphX backend uses the MIGraphX library to execute ONNX models on AMD GPUs and it is only usable if the host machine has compatible GPUs.
+
+Developers
+^^^^^^^^^^
+
+Developers tinker with the server executable itself by compiling it from source.
+Building the server from source requires using a development container.
+In the development container, developers can build the server executable and run tests using the executable directly.
+The AMD Inference Server uses CMake to build the executables and tests.
+After testing, developers build the deployment images containing the server executable, backends, and the needed run-time dependencies using the *amdinfer* script.
diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst
new file mode 100644
index 000000000..9ffab64eb
--- /dev/null
+++ b/docs/troubleshooting.rst
@@ -0,0 +1,38 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Troubleshooting
+===============
+
+If things don't work as expected, use this page to help guide your debugging.
+The more information you can gather, the easier it will be for you to fix the problem yourself or provide detailed information in a bug report.
+If you're running into backend-specific errors, also take a look at the troubleshooting section for your :ref:`backend <backends:Backends>`.
+
+Use the latest version
+----------------------
+
+The inference server is in continuous development and every commit to the repository is tested so using the ``main`` branch directly should be the best way to get the latest features and bug fixes.
+Make sure you are using the latest version and that your container and source code versions match.
+
+Use server logs
+---------------
+
+You will need access to the running server to debug most issues.
+While the server may respond to erroneous requests from the client with information about what failed, it will probably not have sufficient context to learn the underlying cause.
+Instead, you should look at the server logs, if they are enabled.
+By default, the server logs are in ``~/.amdinfer/logs/server.log``.
+The home directory where the logs are located depend on how the server was started.
+If it is running as root, as is the case in deployment containers, the root user's home directory is in ``/root/*``.
+If it is running as the non-root user in the development container, the home directory is in ``/home/amdinfer-user/*``.
diff --git a/docs/vitis_ai.rst b/docs/vitis_ai.rst
deleted file mode 100644
index 07ca7d695..000000000
--- a/docs/vitis_ai.rst
+++ /dev/null
@@ -1,122 +0,0 @@
-..
-    Copyright 2022 Xilinx, Inc.
-    Copyright 2022 Advanced Micro Devices, Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-FPGAs - Vitis AI
-================
-
-Using the AMD Inference Server with Vitis AI and FPGAs requires some additional setup prior to use.
-
-Set up the host and FPGAs
--------------------------
-
-The details for setting up your host are available online in the :github:`Vitis AI <Xilinx/Vitis-AI/tree/2.5/setup>` repository.
-These instructions will depend on whether you are using :github:`Alveo cards <Xilinx/Vitis-AI/tree/2.5/setup/alveo>` or :github:`VCK5000 <Xilinx/Vitis-AI/tree/2.5/setup/vck5000>`.
-In essence, you will need to install software, program the shell on the FPGA(s) and download XCLBINs.
-
-Software
-^^^^^^^^
-
-You need to install the Xilinx Runtime (XRT) to communicate with the FPGA over PCIe.
-The XRT version on the host should match the one installed in the container where the server will be running.
-The Xilinx Resource Manager (XRM) is not needed on the host because it is already installed in the container.
-
-Shell
-^^^^^
-
-The Vitis AI repository contains scripts to install packages and flash the shell on your FPGA.
-They use XRT to program the FPGA.
-In most cases, flashing the shell will be a one-time act as it is persistent.
-However, for some FPGAs such as the Alveo U250, there is an intermediate second shell that must be reprogrammed after every power cycle.
-Follow the instructions in the scripts to install the secondary shell.
-
-You can use ``xbutil validate --device <device id>`` to confirm that your FPGA is ready to use.
-If this executable is not on your PATH, it should be in ``/opt/xilinx/xrt/bin``.
-
-XCLBINs
-^^^^^^^
-
-The XCLBINs define the DPU that will run on the FPGA.
-By default, these are installed in ``/opt/xilinx/overlaybins/<DPU>/*``
-The environment variable ``XLNX_VART_FIRMWARE`` must be set where the inference server is running to point to the directory where the XCLBINs for your FPGA are.
-You can mount this directory in your container to enable it to access these files.
-Alternatively, you can also copy XCLBINs directly into the container as well.
-
-Build an image
---------------
-
-To build an image with Vitis AI enabled, you need to add the ``--vitis`` to the ``amdinfer dockerize`` command:
-
-.. code-block:: bash
-
-    # create the Dockerfile
-    python3 docker/generate.py
-
-    # build the dev image $(whoami)/amdinfer-dev-vitis:latest
-    ./amdinfer dockerize --vitis --suffix="-vitis"
-
-    # build the deployment image $(whoami)/amdinfer-vitis:latest
-    ./amdinfer dockerize --vitis --suffix="-vitis" --production
-
-The deployment image will need XCLBINs.
-There are a few ways to achieve this:
-
-1. Copy XCLBINs into ``./external/overlaybins/*`` before invoking the ``dockerize`` command. The ``Dockerfile`` is configured to copy any files and directories at this path into the deployment image under ``/opt/xilinx/overlaybins``.
-2. Copy XCLBINs into the image after building it.
-3. Mount the XCLBINs in the container at start time
-
-Start an image
---------------
-
-The development container can be started with:
-
-.. code-block:: console
-
-    $ ./amdinfer run --dev
-
-This automatically adds the detected devices, publishes ports, and mounts some convenient directories, such as your SSH directory, and drops you into a terminal in the container.
-
-You can start the :ref:`deployment container on Docker <docker:start the container>` with something like:
-
-.. code-block:: console
-
-    $ docker run --device /dev/xclmgmt# --device /dev/dri [--volume ...]
-
-These ``--device`` flags pass the FPGA to the container and you can mount other directories as needed to make models available.
-The name of the ``xclmgmt`` file depends on your host.
-
-On Kubernetes, you will need to add the FPGA as a resource to your deployment after installing the `Xilinx FPGA Kubernetes plugin <https://github.com/Xilinx/FPGA_as_a_Service/tree/master/k8s-device-plugin>`__.
-The exact name of the resource will depend on which FPGA and shell you are trying to request.
-
-.. code-block:: yaml
-
-    # rest of the deployment logic
-    resources:
-      limits:
-        cpu: "1"
-        memory: 2Gi
-        xilinx.com/fpga-xilinx_u250_gen3x16_xdma_shell_3_1-0: 1
-
-Get assets and models
----------------------
-
-You can download the assets and models used for tests and examples with:
-
-.. code-block:: console
-
-    $ ./amdinfer get --vitis
-
-The AMD Inference Server is using models and XCLBINs from Vitis 2.5 in its tests and examples.
-Make sure you have compatible tools, shells and XCLBINs with `Vitis 2.5 <https://github.com/Xilinx/Vitis-AI/tree/v2.5/setup>`__.
diff --git a/docs/zendnn.rst b/docs/zendnn.rst
deleted file mode 100644
index 981da4766..000000000
--- a/docs/zendnn.rst
+++ /dev/null
@@ -1,98 +0,0 @@
-..
-    Copyright 2022 Advanced Micro Devices, Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-.. include:: links.rst
-
-CPUs - ZenDNN
-=============
-
-AMD Inference Server is integrated with `ZenDNN <ZenDNN_>`_ optimized libraries for running inference on AMD EPYC processors with TensorFlow and PyTorch.
-
-Build an image
---------------
-
-To build an image with TensorFlow/Pytorch + ZenDNN enabled, you need to download the ZenDNN libraries and then build the image by pointing the build script to the location of these downloaded packages.
-
-Download the ZenDNN packages
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-You can download the TF+ZenDNN and/or PT+ZenDNN packages from the `ZenDNN developer downloads <ZenDNN_download_>`_.
-Before downloading these packages, you will be required to read and agree to the End User License Agreement (EULA).
-
-1. For TensorFlow: download ``TF_v2.10_ZenDNN_v4.0_C++_API.zip``
-2. For PyTorch: download ``PT_v1.12_ZenDNN_v4.0_C++_API.zip``
-
-You can download one or both, depending on what you want to enable.
-
-Build the image
-^^^^^^^^^^^^^^^
-
-After downloading the packages, place them in the root of the repository.
-To build an image with ZenDNN enabled, you need to add the the appropriate flag(s) to the ``amdinfer dockerize`` command:
-
-.. code-block:: bash
-
-    # create the Dockerfile
-    python3 docker/generate.py
-
-    # build the dev image $(whoami)/amdinfer-dev-zendnn:latest
-    ./amdinfer dockerize --tfzendnn=./TF_v2.10_ZenDNN_v4.0_C++_API.zip --ptzendnn=./PT_v1.12_ZenDNN_v4.0_C++_API.zip --suffix="-zendnn"
-
-    # build the deployment image $(whoami)/amdinfer-zendnn:latest
-    ./amdinfer dockerize --tfzendnn=./TF_v2.10_ZenDNN_v4.0_C++_API.zip --ptzendnn=./PT_v1.12_ZenDNN_v4.0_C++_API.zip --suffix="-zendnn" --production
-
-You can choose to build a image with just TF+ZenDNN or just PT+ZenDNN by only passing the appropriate flag.
-
-.. note::
-
-    The downloaded ZenDNN packages will be used by the Docker build process so they must be in the inference server repository directory and in a location that is not excluded by the ``.dockerignore`` file.
-    These instructions suggest using the repository root but any path that meets this criteria will work.
-
-Get assets and models
----------------------
-
-You can download the assets and models used for tests and examples with:
-
-.. code-block:: console
-
-   $ ./amdinfer get --tfzendnn --ptzendnn
-
-Freezing PyTorch models
------------------------
-
-To use PyTorch models with the AMD Inference Server, you need to `convert downloaded PyTorch Eager models to TorchScript <https://pytorch.org/tutorials/advanced/cpp_export.html#step-1-converting-your-pytorch-model-to-torch-script>`_.
-
-Run Tests
----------
-
-To verify the working of TF/PT + ZenDNN in the AMD Inference Server, run a sample test case.
-This test will load a model and run with a sample image and assert the output.
-
-1. For TensorFlow + ZenDNN
-
-   .. code-block:: console
-
-      $ ./amdinfer test -k tfzendnn
-
-2. For PyTorch + ZenDNN
-
-   .. code-block:: console
-
-      $ ./amdinfer test -k ptzendnn
-
-Tune performance
-----------------
-
-For tuning ZenDNN performance, you can refer to the TensorFlow + ZenDNN and PyTorch + ZenDNN `user guides <ZenDNN_guide_>`_.
diff --git a/examples/resnet50/quickstart-setup.sh b/examples/resnet50/quickstart-setup.sh
index e00e2a283..0fa63655a 100755
--- a/examples/resnet50/quickstart-setup.sh
+++ b/examples/resnet50/quickstart-setup.sh
@@ -23,18 +23,18 @@ unzip -j "tensorflow.zip" "tf_resnetv1_50_imagenet_224_224_6.97G_2.5/float/resne
 mkdir -p model_repository/resnet50/1
 mv ./resnet_v1_50_baseline_6.96B_922.pb model_repository/resnet50/1/saved_model.pb
 cat << EOF > model_repository/resnet50/config.toml
-name = "mnist"
+name = "resnet50"
 platform = "tensorflow_graphdef"
 
 [[inputs]]
-name = "images_in"
+name = "input"
 datatype = "FP32"
-shape = [28, 28, 1]
+shape = [224, 224, 3]
 
 [[outputs]]
-name = "flatten/Reshape"
+name = "resnet_v1_50/predictions/Reshape_1"
 datatype = "FP32"
-shape = [10]
+shape = [1000]
 EOF
 
 # Download the class labels for this model
diff --git a/external/aks/README.rst b/external/aks/README.rst
index 40e5a0b43..8ebd31c34 100644
--- a/external/aks/README.rst
+++ b/external/aks/README.rst
@@ -1,6 +1,6 @@
 ..
     Copyright 2021 Xilinx, Inc.
-    Copyright 2022, Advanced Micro Devices, Inc.
+    Copyright 2022 Advanced Micro Devices, Inc.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.


Test patch:
diff --git a/docs/testing.rst b/docs/testing.rst
new file mode 100644
index 000000000..2b641209d
--- /dev/null
+++ b/docs/testing.rst
@@ -0,0 +1,67 @@
+..
+    Copyright 2023 Advanced Micro Devices, Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Testing
+=======
+
+The AMD Inference Server uses `pytest <https://docs.pytest.org>`__ to drive both Python and C++ tests.
+The tests must be run in the development container.
+In the container, use:
+
+.. code-block:: console
+
+    $ amdinfer test
+
+By default, this will run all Python and C++ tests while skipping the ones that require unsupported hardware without error.
+You can use ``--help`` to see the full options for this command.
+A few important ones are mentioned here:
+
+1. ``--cpp``: by default, this is set to ``all``. You can set the value of this flag to ``skip`` or ``only`` to not run or only run C++ tests, respectively.
+2. ``-k``: use this flag to filter tests by name. This is a `pytest option <https://docs.pytest.org/en/latest/example/markers.html#using-k-expr-to-select-tests-based-on-their-name>`__
+
+.. tip::
+
+    In addition to the flags that are listed when you use ``--help``, any unknown flags are passed directly to pytest.
+    This is how the ``-k`` flag works above.
+    Refer to the pytest documentation for the flags you can use to control pytest.
+
+Add a new test
+--------------
+
+The easiest way to add a new test is to find an existing test that is close to what you want to test.
+Then, you can copy it and adapt it for the new test.
+The tests are in the `tests <https://github.com/Xilinx/inference-server/tree/main/tests>`__ directory in the repository.
+
+Add assets
+^^^^^^^^^^
+
+The inference tests require using images and other files as input data.
+They also require models for performing inference.
+If you need other input data or models for a new test, you need to add them to the repository's download script so they can be downloaded with ``amdinfer get``.
+The downloading script is in `tests/download <https://github.com/Xilinx/inference-server/tree/main/tests/download>`__ directory.
+You need to append to or create a new file in the ``models`` directory.
+A downloaded asset, such as an image or model, is defined by a:
+
+1. Key: the key is a unique string that tests will use to get this asset
+2. URL: the location where to download the asset from
+3. Destination: the location to place the downloaded asset relative to where the downloaded files are being saved
+4. Source path: for archived files, a source path is used to define where the actual file is. It can be an empty string otherwise.
+
+These values are arguments to a class that defines how to download the file.
+If your asset is similar to download to an existing asset, you can reuse the same class.
+Otherwise, you may need to create your own class for downloading your asset.
+You should also gate the download of your asset with the appropriate backend it is intended for.
+
+The downloaded files are placed in a local directory in the inference server repository, which is fixed to ``external/artifacts``.
diff --git a/tests/download/main.py b/tests/download/main.py
index 86a041950..53fc365d0 100644
--- a/tests/download/main.py
+++ b/tests/download/main.py
@@ -219,23 +219,23 @@ def get_parser(parser=None):
         "-h", "--help", action="help", help="show this help message and exit"
     )
 
-    platforms = parser.add_argument_group("Platforms")
-    platforms.add_argument(
-        "--all-platforms", action="store_true", help="download files for all platforms"
+    backends = parser.add_argument_group("Backends")
+    backends.add_argument(
+        "--all-backends", action="store_true", help="download files for all backends"
     )
-    platforms.add_argument(
+    backends.add_argument(
         "--vitis", action="store_true", help="download all vitis-related files"
     )
-    platforms.add_argument(
+    backends.add_argument(
         "--ptzendnn", action="store_true", help="download all ptzendnn-related files"
     )
-    platforms.add_argument(
+    backends.add_argument(
         "--tfzendnn", action="store_true", help="download all tfzendnn-related files"
     )
-    platforms.add_argument(
+    backends.add_argument(
         "--zendnn", action="store_true", help="alias for --ptzendnn --tfzendnn"
     )
-    platforms.add_argument(
+    backends.add_argument(
         "--migraphx", action="store_true", help="download all migraphx-related files"
     )
 
@@ -262,7 +262,7 @@ def update_args(args):
     Returns:
         argparse.namespace: the updated arguments
     """
-    if args.all_platforms:
+    if args.all_backends:
         args.vitis = True
         args.zendnn = True
         args.migraphx = True