Skip to content
This repository has been archived by the owner on Mar 21, 2024. It is now read-only.

✨ Add environment locking #41

Merged
merged 3 commits into from
Jun 13, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 34 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Introduction
**InnerEye Inference API**
# Introduction

InnerEye-Inference is a AppService webapp in python to run inference on medical imaging models trained with the [InnerEye-DeepLearning toolkit](https://github.com/microsoft/InnerEye-Inference).

Expand All @@ -13,20 +12,23 @@ Download a Conda or Miniconda [installer for your platform](https://docs.conda.i
and run it.

### Creating a Conda environment
Note that in order to create the Conda environment you will need to have build tools installed on your machine. If you are running Windows, they should be already installed with Conda distribution.

You can install build tools on Ubuntu (and Debian-based distributions) by running
`sudo apt-get install build-essential`
If you are running CentOS/RHEL distributions, you can install the build tools by running
Note that in order to create the Conda environment you will need to have build tools installed on your machine. If you are running Windows, they should be already installed with Conda distribution.

You can install build tools on Ubuntu (and Debian-based distributions) by running
`sudo apt-get install build-essential`
peterhessey marked this conversation as resolved.
Show resolved Hide resolved
If you are running CentOS/RHEL distributions, you can install the build tools by running
`yum install gcc gcc-c++ kernel-devel make`

Start the `conda` prompt for your platform. In that prompt, navigate to your repository root and run

* `conda env create --file environment.yml`
* `conda activate inference`

### Configuration

Add this script with name set_environment.sh to set your env variables. This can be executed in Linux. The code will read the file if the environment variables are not present.

```bash
#!/bin/bash
export CUSTOMCONNSTR_AZUREML_SERVICE_PRINCIPAL_SECRET=
Expand All @@ -44,8 +46,8 @@ export IMAGE_DATA_FOLDER=

Run with `source set_environment.sh`


### Running flask app locally

* `flask run` to test it locally

### Testing flask app locally
Expand All @@ -56,13 +58,13 @@ The app can be tested locally using [`curl`](https://curl.se/).

To check that the server is running, issue this command from a local shell:

```
```console
curl -i -H "API_AUTH_SECRET: <val of CUSTOMCONNSTR_API_AUTH_SECRET>" http://localhost:5000/v1/ping
```

This should produce an output similar to:

```
```console
peterhessey marked this conversation as resolved.
Show resolved Hide resolved
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 0
Expand All @@ -74,7 +76,7 @@ Date: Wed, 18 Aug 2021 11:50:20 GMT

To test DICOM image segmentation of a file, first create `Tests/TestData/HN.zip` containing a zipped set of the test DICOM files in `Tests/TestData/HN`. Then assuming there is a model `PassThroughModel:4`, issue this command:

```
```console
curl -i \
-X POST \
-H "API_AUTH_SECRET: <val of CUSTOMCONNSTR_API_AUTH_SECRET>" \
Expand All @@ -84,7 +86,7 @@ curl -i \

This should produce an output similar to:

```
```console
HTTP/1.0 201 CREATED
Content-Type: text/plain
Content-Length: 33
Expand All @@ -100,7 +102,7 @@ here `api_inference_1629291609_fb5dfdf9` is the run id for the newly submitted i

To monitor the progress of the previously submitted inference job, issue this command:

```
```console
curl -i \
-H "API_AUTH_SECRET: <val of CUSTOMCONNSTR_API_AUTH_SECRET>" \
--head \
Expand All @@ -113,7 +115,7 @@ curl -i \

If the run is still in progress then this should produce output similar to:

```
```console
HTTP/1.0 202 ACCEPTED
Content-Type: text/html; charset=utf-8
Content-Length: 0
Expand All @@ -127,7 +129,7 @@ Date: Wed, 18 Aug 2021 13:45:20 GMT

If the run is complete then this should produce an output similar to:

```
```console
HTTP/1.0 200 OK
Content-Type: application/zip
Content-Length: 131202
Expand All @@ -142,8 +144,9 @@ Date: Wed, 18 Aug 2021 14:01:27 GMT
and download the inference result as a zipped DICOM-RT file to `HN_rt.zip`.

### Running flask app in Azure

* Install Azure CLI: `curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash`
* Login: `az login --use-device-code`
* Login: `az login --use-device-code`
peterhessey marked this conversation as resolved.
Show resolved Hide resolved
* Deploy: `az webapp up --sku S1 --name test-python12345 --subscription <your_subscription_name> -g InnerEyeInference --location <your region>`
* In the Azure portal go to Monitoring > Log Stream for debugging logs

Expand All @@ -158,6 +161,17 @@ If you would like to reproduce the automatic deployment of the service for testi

During inference the image data zip file is copied to the IMAGE_DATA_FOLDER in the AzureML workspace's DATASTORE_NAME datastore. At the end of inference the copied image data zip file is overwritten with a simple line of text. At present we cannot delete these. If you would like these overwritten files removed from your datastore you can [add a policy](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-lifecycle-management-concepts?tabs=azure-portal) to delete items from the datastore after a period of time. We recommend 7 days.

## Changing Primary Dependencies

1. Make your desired changes in `primary_deps.yml`. Make sure your package name and version are correct.
2. To create a new environment and a valid `environment.yml`, run the following command:

```shell
bash -i create_and_lock_environment.sh
```
peterhessey marked this conversation as resolved.
Show resolved Hide resolved

3. Voila! You will now have a new conda environment with your desired primary package versions, as well as a new `environment.yml` which can be ingested by AzureML to create a copy of your local environment.

## Help and Bug Reporting

1. [Guidelines for how to report bug.](./docs/BugReporting.md)
Expand All @@ -172,7 +186,7 @@ During inference the image data zip file is copied to the IMAGE_DATA_FOLDER in t

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
the rights to use your contribution. For details, visit the [the Microsoft CLA site](https://cla.opensource.microsoft.com).
peterhessey marked this conversation as resolved.
Show resolved Hide resolved

When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
Expand All @@ -186,8 +200,8 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).

# Resources:
## Resources

- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
* [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
peterhessey marked this conversation as resolved.
Show resolved Hide resolved
* [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
* Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
2 changes: 1 addition & 1 deletion Tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
# Test reference series.
TestDicomVolumeLocation: Path = TEST_DATA_DIR / "HN"

PASSTHROUGH_MODEL_ID = "PassThroughModel:1703"
PASSTHROUGH_MODEL_ID = "PassThroughModel:1729"


def assert_response_error_type(response: TestResponse, status_code: HTTP_STATUS_CODE,
Expand Down
39 changes: 39 additions & 0 deletions create_and_lock_environment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash

os_name=$(uname)
if [[ ! $os_name == *"Linux"* ]]; then
echo "ERROR: cannot run AML environment locking in non-linux environment. Windows users can do this using WSL - https://docs.microsoft.com/en-us/windows/wsl/install"
exit 1
else
echo "Starting AML environment locking..."
fi

# get environment name from primary dependencies YAML file
name_line="$(cat primary_deps.yml | grep 'name:')"
IFS=':' read -ra name_arr <<< "$name_line"
env_name="${name_arr[1]}"

# clear old conda envs, create new one
export CONDA_ALWAYS_YES="true"
peterhessey marked this conversation as resolved.
Show resolved Hide resolved
conda env remove --name ${env_name::-1}
conda env create --file primary_deps.yml

# export new environment to environment.yml
conda env export -n ${env_name::-1} | grep -v "prefix:" > environment.yml
unset CONDA_ALWAYS_YES

# remove python version hash (technically not locked, so still potential for problems here if python secondary deps change)
while IFS='' read -r line; do
if [[ $line == *"- python="* ]]; then

IFS='=' read -ra python_arr <<< "$line"
unset python_arr[-1]
echo "${python_arr[0]}"="${python_arr[1]}"
elif [[ ! $line == "#"* ]]; then
echo "${line}"
fi
done < environment.yml > environment.yml.tmp
echo "# WARNING - DO NOT EDIT THIS FILE MANUALLY" > environment.yml
echo "# Please refer to the environment documentation for instructions on how to create a new version of this file: https://github.com/microsoft/InnerEye-DeepLearning/blob/main/docs/environment.md" >> environment.yml
cat environment.yml.tmp >> environment.yml
rm environment.yml.tmp
peterhessey marked this conversation as resolved.
Show resolved Hide resolved
149 changes: 147 additions & 2 deletions environment.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,153 @@
# WARNING - DO NOT EDIT THIS FILE MANUALLY
# Please refer to the environment documentation for instructions on how to create a new version of this file: https://github.com/microsoft/InnerEye-DeepLearning/blob/main/docs/environment.md
name: inference
channels:
- defaults
dependencies:
- pip=20.1.1
- _libgcc_mutex=0.1=main
- _openmp_mutex=5.1=1_gnu
- ca-certificates=2022.4.26=h06a4308_0
- certifi=2022.5.18.1=py37h06a4308_0
- libedit=3.1.20210910=h7f8727e_0
- libffi=3.2.1=hf484d3e_1007
- libgcc-ng=11.2.0=h1234567_1
- libgomp=11.2.0=h1234567_1
- libstdcxx-ng=11.2.0=h1234567_1
- ncurses=6.3=h7f8727e_2
- openssl=1.1.1o=h7f8727e_0
- pip=20.1.1=py37_1
- python=3.7.3
- readline=7.0=h7b6447c_5
- setuptools=61.2.0=py37h06a4308_0
- sqlite=3.33.0=h62c20be_0
- tk=8.6.12=h1ccaba5_0
- wheel=0.37.1=pyhd3eb1b0_0
- xz=5.2.5=h7f8727e_1
- zlib=1.2.12=h7f8727e_2
- pip:
- -r file:requirements.txt
- absl-py==1.1.0
- adal==1.2.7
- applicationinsights==0.11.10
- argcomplete==2.0.0
- attrs==21.4.0
- azure-common==1.1.28
- azure-core==1.22.1
- azure-graphrbac==0.61.1
- azure-identity==1.7.0
- azure-mgmt-authorization==2.0.0
- azure-mgmt-containerregistry==9.1.0
- azure-mgmt-core==1.3.0
- azure-mgmt-keyvault==9.3.0
- azure-mgmt-resource==20.1.0
- azure-mgmt-storage==19.1.0
- azureml-automl-core==1.41.1.post1
- azureml-core==1.41.0.post3
- azureml-dataprep==3.1.4
- azureml-dataprep-native==38.0.0
- azureml-dataprep-rslex==2.5.5
- azureml-dataset-runtime==1.41.0
- azureml-pipeline==1.41.0
- azureml-pipeline-core==1.41.0
- azureml-pipeline-steps==1.41.0
- azureml-sdk==1.41.0
- azureml-telemetry==1.41.0
- azureml-tensorboard==1.42.0
- azureml-train-automl-client==1.41.0
- azureml-train-core==1.41.0
- azureml-train-restclients-hyperdrive==1.41.0
- backports-tempfile==1.0
- backports-weakref==1.0.post1
- bcrypt==3.2.2
- cachetools==5.2.0
- cffi==1.15.0
- charset-normalizer==2.0.12
- click==8.1.3
- cloudpickle==2.1.0
- conda-merge==0.2.0
- contextlib2==21.6.0
- coverage==6.4.1
- cryptography==36.0.2
- distro==1.7.0
- docker==5.0.3
- dotnetcore2==2.1.23
- flake8==3.8.4
- flask==2.1.1
- flask-injector==0.13.0
- fusepy==3.0.1
- google-auth==2.7.0
- google-auth-oauthlib==0.4.6
- grpcio==1.46.3
- hi-ml-azure==0.2.1
- humanfriendly==10.0
- idna==3.3
- importlib-metadata==4.11.4
- iniconfig==1.1.1
- injector==0.19.0
- isodate==0.6.1
- itsdangerous==2.1.2
- jeepney==0.8.0
- jinja2==3.1.2
- jmespath==0.10.0
- jsonpickle==2.2.0
- knack==0.9.0
- markdown==3.3.7
- markupsafe==2.1.1
- mccabe==0.6.1
- memory-tempfile==2.2.3
- more-itertools==8.13.0
- msal==1.18.0
- msal-extensions==0.3.1
- msrest==0.6.21
- msrestazure==0.6.4
- mypy==0.790
- mypy-extensions==0.4.3
- ndg-httpsclient==0.5.1
- numpy==1.21.6
- oauthlib==3.2.0
- packaging==21.3
- pandas==1.3.5
- param==1.12.1
- paramiko==2.11.0
- pathspec==0.9.0
- pkginfo==1.8.2
- pluggy==0.13.1
- portalocker==2.4.0
- protobuf==4.21.1
- py==1.11.0
- pyarrow==3.0.0
- pyasn1==0.4.8
- pyasn1-modules==0.2.8
- pycodestyle==2.6.0
- pycparser==2.21
- pydicom==2.1.2
- pyflakes==2.2.0
- pygments==2.12.0
- pyjwt==2.4.0
- pynacl==1.5.0
- pyopenssl==22.0.0
- pyparsing==3.0.9
- pysocks==1.7.1
- pytest==6.0.1
- pytest-cov==2.10.1
- python-dateutil==2.8.2
- pytz==2022.1
- pyyaml==6.0
- requests==2.27.1
- requests-oauthlib==1.3.1
- rsa==4.8
- ruamel-yaml==0.17.21
- ruamel-yaml-clib==0.2.6
- secretstorage==3.3.2
- simpleitk==2.0.2
- six==1.16.0
- tabulate==0.8.9
- tensorboard==2.9.0
- tensorboard-data-server==0.6.1
- tensorboard-plugin-wit==1.8.1
- toml==0.10.2
- typed-ast==1.4.3
- typing-extensions==4.2.0
- urllib3==1.26.7
- websocket-client==1.3.2
- werkzeug==2.1.1
- zipp==3.8.0
22 changes: 22 additions & 0 deletions primary_deps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# NOTE - this file defines the primary dependencies for the InnerEye Inference service python environment.
# If you update versions or add new packages in this file you will need to lock the environment.
# For instructions on how to do this, see https://github.com/microsoft/InnerEye-Inference/tree/phessey/env-locking#changing-primary-dependencies
name: inference
channels:
- defaults
dependencies:
- pip=20.1.1
- python=3.7.3
- pip:
- azureml-sdk==1.41.0
- flake8==3.8.4
- flask-injector==0.13.0
- Flask==2.1.1
- hi-ml-azure==0.2.1
- memory-tempfile==2.2.3
- mypy==0.790
- pydicom==2.1.2
- pytest-cov==2.10.1
- pytest==6.0.1
- SimpleITK==2.0.2
- Werkzeug==2.1.1
peterhessey marked this conversation as resolved.
Show resolved Hide resolved
Loading