├── .github └── workflows │ └── azureml-ci-cd.yml ├── .gitignore ├── LICENSE ├── Readme.md ├── aml_service ├── ci_cd │ ├── 00-WorkSpace.py │ ├── 01-AttachAmlCluster.py │ ├── 02-AttachDSVM.py │ ├── 03-AttachRemoteCompute.py │ ├── 10-Train.py │ ├── 20-RegisterModel.py │ ├── 30-ProfileModel.py │ ├── 40-DevDeployment.py │ ├── 50-TestDeployment.py │ ├── 60-ProdDeployment.py │ ├── helper │ │ ├── __init__.py │ │ └── utils.py │ └── requirements.txt └── settings.json ├── code ├── scoring │ └── score.py ├── testing │ ├── __init__.py │ └── test_functions.py └── training │ └── train.py ├── data ├── diabetes.csv ├── diabetes_bad_dist.csv ├── diabetes_bad_schema.csv └── diabetes_missing_values.csv └── pictures ├── github-actions-azure-machine-learning.png └── ml-lifecycle.png /.github/workflows/azureml-ci-cd.yml: -------------------------------------------------------------------------------- 1 | name: DevOps for ML (CI/CD) 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - 'code/**' 9 | 10 | jobs: 11 | train-and-deploy: 12 | name: Model Training and Deployment 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Check Out Repository 17 | uses: actions/checkout@master 18 | 19 | - name: Azure Login 20 | uses: azure/login@v1 21 | with: 22 | creds: ${{ secrets.AZURE_CREDENTIALS }} 23 | 24 | - name: Set up Python 3.7 25 | uses: actions/setup-python@v1 26 | with: 27 | python-version: 3.7 28 | 29 | - name: Install Dependencies 30 | run: | 31 | python -m pip install --upgrade pip 32 | pip install -r 'aml_service/ci_cd/requirements.txt' 33 | 34 | - name: Create or Connect to Workspace 35 | run: | 36 | python 'aml_service/ci_cd/00-WorkSpace.py' --subscription-id ${{ secrets.SUBSCRIPTION_ID }} --workspace-name ${{ secrets.WORKSPACE_NAME }} --resource-group ${{ secrets.RESOURCE_GROUP }} --location ${{ secrets.LOCATION }} --friendly-name ${{ secrets.FRIENDLY_NAME }} 37 | 38 | - name: Create or Load Azure Machine Learning Compute 39 | run: | 40 | python 'aml_service/ci_cd/01-AttachAmlCluster.py' 41 | 42 | - name: Train Model 43 | run: | 44 | python 'aml_service/ci_cd/10-Train.py' 45 | 46 | - name: Evaluate and Register Model 47 | run: | 48 | python 'aml_service/ci_cd/20-RegisterModel.py' 49 | 50 | - name: Profile Model 51 | run: | 52 | python 'aml_service/ci_cd/30-ProfileModel.py' 53 | 54 | - name: Dev Deployment 55 | run: | 56 | python 'aml_service/ci_cd/40-DevDeployment.py' 57 | 58 | - name: Test Deployment 59 | run: | 60 | python 'aml_service/ci_cd/50-TestDeployment.py' 61 | 62 | - name: Production Deployment 63 | run: | 64 | python 'aml_service/ci_cd/60-ProdDeployment.py' 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | *.vscode 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ### **INFO: We have built a new and even simpler method to do MLOps with GitHub Actions. Please visit this repository to get started: https://github.com/machine-learning-apps/ml-template-azure** 2 | 3 |

4 | 5 | GitHub Actions status 6 | 7 |

8 |

9 | GitHub Actions and Azure Machine Learning 10 |

11 | 12 | # ML DevOps with GitHub Actions and Azure ML 13 | 14 | This repository demonstrates how to automate the machine learning lifecycle using the CI/CD pipeline tools of [GitHub Actions](https://github.com/features/actions) and [Azure Machine Learning](https://docs.microsoft.com/en-us/azure/machine-learning/) for training and deployment. The repository does not make use of Azure DevOps, but uses [GitHub Actions](https://github.com/features/actions) as a future proof backend system for workflow automation. 15 | 16 | The repository includes the following features: 17 | - [GitHub Actions](https://github.com/features/actions) for the continuous integration (CI) and continuous delivery (CD) pipeline 18 | - [Azure Machine Learning](https://docs.microsoft.com/en-us/azure/machine-learning/) as a backend for training and deployment of machine learning models 19 | - CI/CD pipeline as code: the repository uses the [Azure Machine Learning Python SDK](https://docs.microsoft.com/en-us/python/api/overview/azure/ml/intro?view=azure-ml-py) to define the CI/CD steps and implements almost all features of this framework 20 | - Central settings file in json format to enable quick customization of of each step of the pipline 21 | 22 | ## Implemented Azure ML features in the CI/CD pipeline 23 | 24 | The repository and the CI/CD pipeline makes use of the following key features of [Azure Machine Learning](https://docs.microsoft.com/en-us/azure/machine-learning/): 25 | - Loading or deployment of Workspace 26 | - Training on different compute engines: Azure Machine Learning Compute, Data Science VM, Remote VM 27 | - Automatically creates or attaches the compute engine, if it is not available yet 28 | - Allows extensive customizations of the compute engine depending on your requirements 29 | - Granular adjustment of training process 30 | - Custom docker images and container registries 31 | - Distributed training backends: MPI, Parameter Server, Gloo, NCCL 32 | - Supports all frameworks: TensorFlow, PyTorch, SKLearn, Chainer, etc. 33 | - Registration of environment 34 | - Hyperparameter Tuning 35 | - Comparison of models before registration in workspace 36 | - Comparison of production model and newly trained model based on metrics defined in central settings file 37 | - Model profiling after training has completed successfully 38 | - Recommends number of CPUs and RAM size for deployment 39 | - Deployment with testing in three phases: 40 | - Dev deployment: deployment on Azure Container Instance 41 | - Test deployment: deployment on Azure Kubernetes Service with purpose DEV_TEST 42 | - Production deployment: deployment on Azure Kubernetes Service with purpose FAST_PROD 43 | - And many others ... 44 | 45 | ## What is ML DevOps? 46 | 47 |

48 | Azure Machine Learning Lifecycle 49 |

50 | 51 | MLOps empowers data scientists and app developers to bring together their knowledge and skills to simplify the model development as well as the release and deployment of them. ML DevOps enables you to track, version, test, certify and reuse assets in every part of the machine learning lifecycle and provides orchestration services to streamline managing this lifecycle. This allows to automate the end to end machine Learning lifecycle to frequently update models, test new models, and continuously roll out new ML models alongside your other applications and services. 52 | 53 | This repository enables Data Scientists to focus on the training and deployment code of their machine learning project (`code` folder of this repository). Once new code is checked into the `code` folder of the master branch of this repository, the CI/CD pipeline is triggered and the training process starts automatically in the linked Azure Machine Learning workspace. Once the training process is completed successfully, the deployment of the model takes place in three stages: dev, test and production stage. 54 | 55 | ## Key challenges solved by ML DevOps 56 | 57 | **Model reproducibility & versioning** 58 | - Track, snapshot & manage assets used to create the model 59 | - Enable collaboration and sharing of ML pipelines 60 | 61 | **Model auditability & explainability** 62 | - Maintain asset integrity & persist access control logs 63 | - Certify model behavior meets regulatory & adversarial standards 64 | 65 | **Model packaging & validation** 66 | - Support model portability across a variety of platforms 67 | - Certify model performance meets functional and latency requirements 68 | 69 | **Model deployment & monitoring** 70 | - Release models with confidence 71 | - Monitor & know when to retrain by analyzing signals such as data drift 72 | 73 | ## Prerequisites 74 | 75 | The following prerequisites are required to make this repository work: 76 | - Azure subscription 77 | - Contributor access to the Azure subscription 78 | - Access to the [GitHub Actions Beta](https://github.com/features/actions) 79 | 80 | If you don’t have an Azure subscription, create a free account before you begin. Try the [free or paid version of Azure Machine Learning](https://aka.ms/AMLFree) today. 81 | 82 | ## Settings file 83 | 84 | The repository uses a central settings file in [`/aml_service/settings.json`](/aml_service/settings.json) to enable quick customizations of the end to end pipeline. The file can be found [here](/aml_service/settings.json) and can be used to adjust the parameters of: 85 | - The compute engines for training and deployment, 86 | - The training process (experiment and run) and 87 | - The deployment process. 88 | 89 | ## GitHub Workflow 90 | 91 | The GitHub Workflow requires the follwing secrets: 92 | - `AZURE_CREDENTIALS`: Used for the az login action in the [GitHub Actions Workflow](https://github.com/features/actions). Please visit [this website](https://github.com/Azure/login#github-actions-for-deploying-to-azure) for a tutorial of this GitHub Action. 93 | - `FRIENDLY_NAME`: Friendly name of the Azure ML workspace. 94 | - `LOCATION`: Location of the workspace (e.g. `westeurope`, etc.) 95 | - `RESOURCE_GROUP`: Resource group where Azure Machine Learning was or will be deployed. 96 | - `SUBSCRIPTION_ID`: ID of the Azure subscription that should be used. 97 | - `WORKSPACE_NAME`: Name of your workspace or the workspace that should be created by the pipeline. 98 | 99 | ## Further Links 100 | 101 | - [GitHub Actions Documentation](https://help.github.com/en/github/automating-your-workflow-with-github-actions) 102 | - [Azure Machine Learning Documentation](https://docs.microsoft.com/en-us/azure/machine-learning/) 103 | - [Azure Machine Learning Python SDK Reference](https://docs.microsoft.com/en-us/python/api/overview/azure/ml/intro?view=azure-ml-py) 104 | 105 | ## TODO 106 | 107 | - Implement automatic Swagger generation 108 | - Handover of model name to training script 109 | - Bugfix in model evaluation 110 | - stop pileine failing if model performs worse: use features in GitHub Actions for improvement 111 | -------------------------------------------------------------------------------- /aml_service/ci_cd/00-WorkSpace.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | 27 | import os, json, sys, argparse 28 | import azureml.core 29 | from azureml.core import Workspace 30 | from azureml.exceptions import WorkspaceException 31 | from azureml.core.authentication import AzureCliAuthentication 32 | 33 | print("SDK Version of azureml: ", azureml.core.VERSION) 34 | print("Current directory: " + os.getcwd()) 35 | 36 | # Parse Arguments 37 | print("Parsing arguments") 38 | parser = argparse.ArgumentParser(description="Azure Machine Learning Service - CI/CD") 39 | parser.add_argument("--subscription-id", type=str, dest="subscription_id", help="ID of the Subscription that should be used") 40 | parser.add_argument("--workspace-name", type=str, dest="workspace_name", help="Name of the Azure Machine Learning Workscpace") 41 | parser.add_argument("--resource-group", type=str, dest="resource_group", help="Name of the Resource Group") 42 | parser.add_argument("--location", type=str, dest="location", help="Region in Azure") 43 | parser.add_argument("--friendly-name", type=str, dest="friendly_name", help="Friendly name of the Azure Machine Learning Workspace") 44 | args = parser.parse_args() 45 | 46 | # Mask values 47 | print("Masking values") 48 | print(f"::add-mask::{args.subscription_id}") 49 | 50 | # Use Azure CLI authentication 51 | cli_auth = AzureCliAuthentication() 52 | 53 | try: 54 | print("Loading existing Workspace") 55 | ws = Workspace.get( 56 | name=args.workspace_name, 57 | subscription_id=args.subscription_id, 58 | resource_group=args.resource_group, 59 | auth=cli_auth 60 | ) 61 | print("Found existing Workspace") 62 | except WorkspaceException: 63 | print("Loading failed") 64 | print("Creating new Workspace") 65 | ws = Workspace.create( 66 | name=args.workspace_name, 67 | auth=cli_auth, 68 | subscription_id=args.subscription_id, 69 | resource_group=args.resource_group, 70 | location=args.location, 71 | create_resource_group=True, 72 | friendly_name=args.friendly_name, 73 | show_output=True 74 | ) 75 | 76 | # Write out the Workspace ARM properties to a config file 77 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 78 | config_file_name = "aml_arm_config.json" 79 | ws.write_config( 80 | path=config_file_path, 81 | file_name=config_file_name 82 | ) 83 | 84 | # Print Workspace details --> only print, if repository is private 85 | print("Workspace name: " + ws.name, 86 | "Azure region: " + ws.location, 87 | "Subscription id: " + ws.subscription_id, 88 | "Resource group: " + ws.resource_group, sep = '\n') 89 | print("Successfully loaded Workspace") -------------------------------------------------------------------------------- /aml_service/ci_cd/01-AttachAmlCluster.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | 27 | import os, json 28 | from azureml.core import Workspace 29 | from azureml.core.compute import ComputeTarget, AmlCompute 30 | from azureml.exceptions import ComputeTargetException 31 | from azureml.core.authentication import AzureCliAuthentication 32 | 33 | # Load the JSON settings file 34 | print("Loading settings") 35 | with open(os.path.join("aml_service", "settings.json")) as f: 36 | settings = json.load(f) 37 | aml_settings = settings["compute_target"]["training"]["amlcompute"] 38 | 39 | # Get workspace 40 | print("Loading Workspace") 41 | cli_auth = AzureCliAuthentication() 42 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 43 | config_file_name = "aml_arm_config.json" 44 | ws = Workspace.from_config( 45 | path=config_file_path, 46 | auth=cli_auth, 47 | _file_name=config_file_name) 48 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 49 | 50 | try: 51 | # Loading AMLCompute 52 | print("Loading existing AML Compute") 53 | cluster = AmlCompute(workspace=ws, name=aml_settings["name"]) 54 | 55 | # Check settings and redeploy if required settings have changed 56 | print("Found existing cluster") 57 | if cluster.vm_size.lower() != aml_settings["vm_size"].lower() or cluster.vm_priority.lower() != aml_settings["vm_priority"].lower(): 58 | cluster.delete() 59 | cluster.wait_for_completion(show_output=True) 60 | raise ComputeTargetException("Cluster is of incorrect size or has incorrect priority. Deleting cluster and provisioning a new one.") 61 | 62 | # Update AMLCompute 63 | #if cluster.provisioning_configuration.min_nodes != aml_settings["min_nodes"] or cluster.provisioning_configuration.max_nodes != aml_settings["max_nodes"] or cluster.provisioning_configuration.idle_seconds_before_scaledown != aml_settings["idle_seconds_before_scaledown"]: 64 | print("Updating settings of Cluster") 65 | cluster.update(min_nodes=aml_settings["min_nodes"], 66 | max_nodes=aml_settings["max_nodes"], 67 | idle_seconds_before_scaledown=aml_settings["idle_seconds_before_scaledown"]) 68 | 69 | # Wait until the operation has completed 70 | cluster.wait_for_completion(show_output=True) 71 | 72 | print("Successfully updated Cluster definition") 73 | except ComputeTargetException: 74 | print("Loading failed") 75 | print("Creating new AML Compute resource") 76 | compute_config = AmlCompute.provisioning_configuration(vm_size=aml_settings["vm_size"], 77 | vm_priority=aml_settings["vm_priority"], 78 | min_nodes=aml_settings["min_nodes"], 79 | max_nodes=aml_settings["max_nodes"], 80 | idle_seconds_before_scaledown=aml_settings["idle_seconds_before_scaledown"], 81 | tags=aml_settings["tags"], 82 | description=aml_settings["description"]) 83 | 84 | # Deploy to VNET if provided 85 | if aml_settings["vnet_resource_group_name"] and aml_settings["vnet_name"] and aml_settings["subnet_name"]: 86 | compute_config.vnet_resourcegroup_name = aml_settings["vnet_resource_group_name"] 87 | compute_config.vnet_name = aml_settings["vnet_name"] 88 | compute_config.subnet_name = aml_settings["subnet_name"] 89 | 90 | # Set Credentials if provided 91 | if aml_settings["admin_username"] and aml_settings["admin_user_password"]: 92 | compute_config.admin_username = aml_settings["admin_username"] 93 | compute_config.admin_user_password = aml_settings["admin_user_password"] 94 | elif aml_settings["admin_username"] and aml_settings["admin_user_ssh_key"]: 95 | compute_config.admin_username = aml_settings["admin_username"] 96 | compute_config.admin_user_ssh_key = aml_settings["admin_user_ssh_key"] 97 | 98 | # Create Compute Target 99 | cluster = ComputeTarget.create(workspace=ws, name=aml_settings["name"], provisioning_configuration=compute_config) 100 | 101 | # Wait until the cluster is attached 102 | cluster.wait_for_completion(show_output=True) 103 | 104 | # Checking status of AMLCompute Cluster 105 | print("Checking status of AMLCompute Cluster") 106 | if cluster.provisioning_state == "Failed": 107 | cluster.delete() 108 | raise Exception( 109 | "Deployment of AMLCompute Cluster failed with the following status: {} and logs: \n{}".format( 110 | cluster.provisioning_state, cluster.provisioning_errors 111 | ) 112 | ) -------------------------------------------------------------------------------- /aml_service/ci_cd/02-AttachDSVM.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | 27 | import os, json 28 | from azureml.core import Workspace 29 | from azureml.core.compute import DsvmCompute 30 | from azureml.exceptions import ComputeTargetException 31 | from azureml.core.authentication import AzureCliAuthentication 32 | 33 | # Load the JSON settings file 34 | print("Loading settings") 35 | with open(os.path.join("aml_service", "settings.json")) as f: 36 | settings = json.load(f) 37 | dsvm_settings = settings["compute_target"]["training"]["dsvm"] 38 | 39 | # Get workspace 40 | print("Loading Workspace") 41 | cli_auth = AzureCliAuthentication() 42 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 43 | config_file_name = "aml_arm_config.json" 44 | ws = Workspace.from_config( 45 | path=config_file_path, 46 | auth=cli_auth, 47 | _file_name=config_file_name) 48 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 49 | 50 | try: 51 | print("Loading existing and attached DSVM") 52 | dsvm_compute = DsvmCompute(workspace=ws, name=dsvm_settings["name"]) 53 | print("Found existing VM") 54 | if dsvm_compute.vm_size != dsvm_settings["vm_size"] or dsvm_compute.location != dsvm_settings["location"]: 55 | dsvm_compute.delete() 56 | dsvm_compute.wait_for_completion(show_output=True) 57 | raise ComputeTargetException("VM is of incorrect size or was deployed in a different location. Deleting VM and provisioning a new one.") 58 | except ComputeTargetException: 59 | print("Loading failed") 60 | print("Creating and attaching new DSVM") 61 | dsvm_config = DsvmCompute.provisioning_configuration(vm_size=dsvm_settings["vm_size"]) 62 | if dsvm_settings["location"]: 63 | dsvm_config.location = dsvm_settings["location"] 64 | if dsvm_settings["ssh_port"]: 65 | dsvm_config.ssh_port = dsvm_settings["ssh_port"] 66 | 67 | # Create Compute Target 68 | dsvm_compute = DsvmCompute.create(workspace=ws, name=dsvm_settings["name"], provisioning_configuration=dsvm_config) 69 | 70 | # Wait until the VM is attached 71 | dsvm_compute.wait_for_completion(show_output=True) 72 | 73 | # Checking status of DSVM 74 | print("Checking status of DSVM") 75 | if dsvm_compute.provisioning_state == "Failed": 76 | dsvm_compute.delete() 77 | raise Exception( 78 | "Deployment of DSVM failed with the following status: {} and logs: \n{}".format( 79 | dsvm_compute.provisioning_state, dsvm_compute.provisioning_errors 80 | ) 81 | ) -------------------------------------------------------------------------------- /aml_service/ci_cd/03-AttachRemoteCompute.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | 27 | import os, json 28 | from azureml.core import Workspace 29 | from azureml.core.compute import ComputeTarget, RemoteCompute 30 | from azureml.exceptions import ComputeTargetException 31 | from azureml.core.authentication import AzureCliAuthentication 32 | 33 | # Load the JSON settings file 34 | print("Loading settings") 35 | with open(os.path.join("aml_service", "settings.json")) as f: 36 | settings = json.load(f) 37 | remotecompute_settings = settings["compute_target"]["training"]["remotecompute"] 38 | 39 | # Get workspace 40 | print("Loading Workspace") 41 | cli_auth = AzureCliAuthentication() 42 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 43 | config_file_name = "aml_arm_config.json" 44 | ws = Workspace.from_config( 45 | path=config_file_path, 46 | auth=cli_auth, 47 | _file_name=config_file_name) 48 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 49 | 50 | try: 51 | # Loading remote compute 52 | print("Loading existing and attached compute resource") 53 | remote_compute = RemoteCompute(workspace=ws, name=remotecompute_settings["name"]) 54 | print("Found existing VM") 55 | except ComputeTargetException: 56 | print("Loading failed") 57 | print("Trying to attach existing compute") 58 | 59 | # Create the compute config 60 | attach_config = RemoteCompute.attach_configuration( 61 | address=remotecompute_settings["address"], 62 | ssh_port=remotecompute_settings["ssh_port"], 63 | username=remotecompute_settings["address"] 64 | ) 65 | if remotecompute_settings["use_ssh_auth"]: 66 | # use ssh authentication 67 | attach_config.password = None 68 | attach_config.private_key_file = remotecompute_settings["private_key_file"] 69 | attach_config.private_key_passphrase = remotecompute_settings["private_key_passphrase"] 70 | else: 71 | # use username and password authentication 72 | attach_config.password = remotecompute_settings["password"] 73 | 74 | # Attach the compute 75 | remote_compute = ComputeTarget.attach(workspace=ws, name=remotecompute_settings["name"], attach_configuration=attach_config) 76 | 77 | # Wait until the VM is attached 78 | remote_compute.wait_for_completion(show_output=True) 79 | 80 | # Checking status of Remote Compute 81 | print("Checking status of Remote Compute") 82 | if remote_compute.provisioning_state == "Failed": 83 | remote_compute.detach() 84 | raise Exception( 85 | "Deployment of Remote Compute failed with the following status: {} and logs: \n{}".format( 86 | remote_compute.provisioning_state, remote_compute.provisioning_errors 87 | ) 88 | ) -------------------------------------------------------------------------------- /aml_service/ci_cd/10-Train.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | 27 | import os, json, azureml.core 28 | from azureml.core import Workspace, Experiment, ContainerRegistry, Environment 29 | from azureml.core.compute import ComputeTarget 30 | from azureml.core.runconfig import MpiConfiguration, TensorflowConfiguration 31 | from azureml.core.authentication import AzureCliAuthentication 32 | from azureml.train.dnn import Chainer, PyTorch, TensorFlow, Gloo, Nccl 33 | from azureml.train.sklearn import SKLearn 34 | from azureml.train.estimator import Estimator 35 | from azureml.train.hyperdrive import HyperDriveConfig, PrimaryMetricGoal 36 | from helper import utils 37 | 38 | # Load the JSON settings file and relevant section 39 | print("Loading settings") 40 | with open(os.path.join("aml_service", "settings.json")) as f: 41 | settings = json.load(f) 42 | experiment_settings = settings["experiment"] 43 | compute_target_to_use = settings["compute_target"]["compute_target_to_use_for_training"].strip().lower() 44 | compute_target_name = settings["compute_target"]["training"][compute_target_to_use]["name"] 45 | 46 | # Get workspace 47 | print("Loading Workspace") 48 | cli_auth = AzureCliAuthentication() 49 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 50 | config_file_name = "aml_arm_config.json" 51 | ws = Workspace.from_config( 52 | path=config_file_path, 53 | auth=cli_auth, 54 | _file_name=config_file_name) 55 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 56 | 57 | # Attach Experiment 58 | print("Loading Experiment") 59 | exp = Experiment(workspace=ws, name=experiment_settings["name"]) 60 | print(exp.name, exp.workspace.name, sep="\n") 61 | 62 | # Load compute target 63 | print("Loading Compute Target") 64 | compute_target = ComputeTarget(workspace=ws, name=compute_target_name) 65 | 66 | # Create image registry configuration 67 | if experiment_settings["docker"]["custom_image"]: 68 | container_registry = ContainerRegistry() 69 | container_registry.address = experiment_settings["docker"]["custom_image_registry_details"]["address"] 70 | container_registry.username = experiment_settings["docker"]["custom_image_registry_details"]["username"] 71 | container_registry.password = experiment_settings["docker"]["custom_image_registry_details"]["password"] 72 | else: 73 | container_registry = None 74 | 75 | # Create disributed training configuration 76 | if experiment_settings["distributed_training"]["backend_config"] == "mpi": 77 | distrib_training_backend = MpiConfiguration() 78 | distrib_training_backend.process_count_per_node = experiment_settings["distributed_training"]["mpi"]["process_count_per_node"] 79 | elif experiment_settings["distributed_training"]["backend_config"] == "parameter_server": 80 | distrib_training_backend = TensorflowConfiguration() 81 | distrib_training_backend.worker_count = experiment_settings["distributed_training"]["parameter_server"]["worker_count"] 82 | distrib_training_backend.parameter_server_count = experiment_settings["distributed_training"]["parameter_server"]["parameter_server_count"] 83 | elif experiment_settings["distributed_training"]["backend_config"] == "gloo": 84 | distrib_training_backend = Gloo() 85 | elif experiment_settings["distributed_training"]["backend_config"] == "nccl": 86 | distrib_training_backend = Nccl() 87 | else: 88 | distrib_training_backend = None 89 | 90 | # Create Estimator for Experiment 91 | print("Creating Estimator object according to settings") 92 | if experiment_settings["framework"]["name"] == "chainer": 93 | framework_version = experiment_settings["framework"]["chainer"]["framework_version"] 94 | enable_optimized_mode = experiment_settings["framework"]["chainer"]["_enable_optimized_mode"] 95 | 96 | estimator = Chainer( 97 | source_directory=experiment_settings["source_directory"], 98 | compute_target=compute_target, 99 | entry_script=experiment_settings["entry_script"], 100 | script_params=experiment_settings["script_parameters"], 101 | node_count=experiment_settings["distributed_training"]["node_count"], 102 | distributed_training=distrib_training_backend, 103 | use_docker=experiment_settings["docker"]["use_docker"], 104 | custom_docker_image=experiment_settings["docker"]["custom_image"], 105 | image_registry_details=container_registry, 106 | user_managed=experiment_settings["user_managed"], 107 | conda_packages=experiment_settings["dependencies"]["conda_packages"], 108 | pip_packages=experiment_settings["dependencies"]["pip_packages"], 109 | conda_dependencies_file=experiment_settings["dependencies"]["conda_dependencies_file"], 110 | pip_requirements_file=experiment_settings["dependencies"]["pip_requirements_file"], 111 | environment_variables=experiment_settings["environment_variables"], 112 | inputs=experiment_settings["data_references"], 113 | source_directory_data_store=experiment_settings["source_directory_datastore"], 114 | shm_size=experiment_settings["docker"]["shm_size"], 115 | max_run_duration_seconds=experiment_settings["max_run_duration_seconds"], 116 | framework_version=framework_version, 117 | _enable_optimized_mode=enable_optimized_mode) 118 | 119 | elif experiment_settings["framework"]["name"] == "pytorch": 120 | framework_version = experiment_settings["framework"]["pytorch"]["framework_version"] 121 | enable_optimized_mode = experiment_settings["framework"]["pytorch"]["_enable_optimized_mode"] 122 | 123 | estimator = PyTorch( 124 | source_directory=experiment_settings["source_directory"], 125 | compute_target=compute_target, 126 | entry_script=experiment_settings["entry_script"], 127 | script_params=experiment_settings["script_parameters"], 128 | node_count=experiment_settings["distributed_training"]["node_count"], 129 | distributed_training=distrib_training_backend, 130 | use_docker=experiment_settings["docker"]["use_docker"], 131 | custom_docker_image=experiment_settings["docker"]["custom_image"], 132 | image_registry_details=container_registry, 133 | user_managed=experiment_settings["user_managed"], 134 | conda_packages=experiment_settings["dependencies"]["conda_packages"], 135 | pip_packages=experiment_settings["dependencies"]["pip_packages"], 136 | conda_dependencies_file=experiment_settings["dependencies"]["conda_dependencies_file"], 137 | pip_requirements_file=experiment_settings["dependencies"]["pip_requirements_file"], 138 | environment_variables=experiment_settings["environment_variables"], 139 | inputs=experiment_settings["data_references"], 140 | source_directory_data_store=experiment_settings["source_directory_datastore"], 141 | shm_size=experiment_settings["docker"]["shm_size"], 142 | max_run_duration_seconds=experiment_settings["max_run_duration_seconds"], 143 | framework_version=framework_version, 144 | _enable_optimized_mode=enable_optimized_mode) 145 | 146 | elif experiment_settings["framework"]["name"] == "tensorflow": 147 | framework_version = experiment_settings["framework"]["tensorflow"]["framework_version"] 148 | enable_optimized_mode = experiment_settings["framework"]["tensorflow"]["_enable_optimized_mode"] 149 | 150 | estimator = TensorFlow( 151 | source_directory=experiment_settings["source_directory"], 152 | compute_target=compute_target, 153 | entry_script=experiment_settings["entry_script"], 154 | script_params=experiment_settings["script_parameters"], 155 | node_count=experiment_settings["distributed_training"]["node_count"], 156 | distributed_training=distrib_training_backend, 157 | use_docker=experiment_settings["docker"]["use_docker"], 158 | custom_docker_image=experiment_settings["docker"]["custom_image"], 159 | image_registry_details=container_registry, 160 | user_managed=experiment_settings["user_managed"], 161 | conda_packages=experiment_settings["dependencies"]["conda_packages"], 162 | pip_packages=experiment_settings["dependencies"]["pip_packages"], 163 | conda_dependencies_file=experiment_settings["dependencies"]["conda_dependencies_file"], 164 | pip_requirements_file=experiment_settings["dependencies"]["pip_requirements_file"], 165 | environment_variables=experiment_settings["environment_variables"], 166 | inputs=experiment_settings["data_references"], 167 | source_directory_data_store=experiment_settings["source_directory_datastore"], 168 | shm_size=experiment_settings["docker"]["shm_size"], 169 | max_run_duration_seconds=experiment_settings["max_run_duration_seconds"], 170 | framework_version=framework_version, 171 | _enable_optimized_mode=enable_optimized_mode) 172 | 173 | elif experiment_settings["framework"]["name"] == "sklearn": 174 | framework_version = experiment_settings["framework"]["sklearn"]["framework_version"] 175 | enable_optimized_mode = experiment_settings["framework"]["sklearn"]["_enable_optimized_mode"] 176 | 177 | estimator = SKLearn( 178 | source_directory=experiment_settings["source_directory"], 179 | compute_target=compute_target, 180 | entry_script=experiment_settings["entry_script"], 181 | script_params=experiment_settings["script_parameters"], 182 | use_docker=experiment_settings["docker"]["use_docker"], 183 | custom_docker_image=experiment_settings["docker"]["custom_image"], 184 | image_registry_details=container_registry, 185 | user_managed=experiment_settings["user_managed"], 186 | conda_packages=experiment_settings["dependencies"]["conda_packages"], 187 | pip_packages=experiment_settings["dependencies"]["pip_packages"], 188 | conda_dependencies_file=experiment_settings["dependencies"]["conda_dependencies_file"], 189 | pip_requirements_file=experiment_settings["dependencies"]["pip_requirements_file"], 190 | environment_variables=experiment_settings["environment_variables"], 191 | inputs=experiment_settings["data_references"], 192 | shm_size=experiment_settings["docker"]["shm_size"], 193 | max_run_duration_seconds=experiment_settings["max_run_duration_seconds"], 194 | framework_version=framework_version, 195 | _enable_optimized_mode=enable_optimized_mode) 196 | 197 | else: 198 | estimator = Estimator( 199 | source_directory=experiment_settings["source_directory"], 200 | compute_target=compute_target, 201 | entry_script=experiment_settings["entry_script"], 202 | script_params=experiment_settings["script_parameters"], 203 | node_count=experiment_settings["distributed_training"]["node_count"], 204 | process_count_per_node=experiment_settings["distributed_training"]["mpi"]["process_count_per_node"], 205 | distributed_training=distrib_training_backend, 206 | use_docker=experiment_settings["docker"]["use_docker"], 207 | custom_docker_image=experiment_settings["docker"]["custom_image"], 208 | image_registry_details=container_registry, 209 | user_managed=experiment_settings["user_managed"], 210 | conda_packages=experiment_settings["dependencies"]["conda_packages"], 211 | pip_packages=experiment_settings["dependencies"]["pip_packages"], 212 | conda_dependencies_file=experiment_settings["dependencies"]["conda_dependencies_file"], 213 | pip_requirements_file=experiment_settings["dependencies"]["pip_requirements_file"], 214 | environment_variables=experiment_settings["environment_variables"], 215 | inputs=experiment_settings["data_references"], 216 | source_directory_data_store=experiment_settings["source_directory_datastore"], 217 | shm_size=experiment_settings["docker"]["shm_size"], 218 | max_run_duration_seconds=experiment_settings["max_run_duration_seconds"]) 219 | 220 | # Use custom Environment and keep old environment variables 221 | if experiment_settings["use_custom_environment"]: 222 | print("Setting Custom Environment Definition") 223 | env = utils.get_environment() 224 | old_env_variables = estimator._estimator_config.environment.environment_variables 225 | env.environment_variables.update(old_env_variables) 226 | estimator.run_config.environment = env 227 | print(estimator.run_config) 228 | 229 | # Registering Environment 230 | print("Registering Environment") 231 | env = estimator.run_config.environment 232 | env.name = experiment_settings["name"] + "_training" 233 | registered_env = env.register(workspace=ws) 234 | print("Registered Environment") 235 | print(registered_env.name, "Version: " + registered_env.version, sep="\n") 236 | 237 | # Creating HyperDriveConfig for Hyperparameter Tuning 238 | if experiment_settings["hyperparameter_sampling"]["use_hyperparameter_sampling"]: 239 | print("Creating HyperDriveConfig for Hyperparameter Tuning") 240 | 241 | parameter_sampling = utils.get_parameter_sampling(experiment_settings["hyperparameter_sampling"]["method"], experiment_settings["hyperparameter_sampling"]["parameters"]) 242 | policy = utils.get_policy(experiment_settings["hyperparameter_sampling"]["policy"]) 243 | primary_metric_goal = PrimaryMetricGoal.MAXIMIZE if "max" in experiment_settings["hyperparameter_sampling"]["primary_metric_goal"] else PrimaryMetricGoal.MINIMIZE 244 | 245 | run_config = HyperDriveConfig(estimator=estimator, 246 | hyperparameter_sampling=parameter_sampling, 247 | policy=policy, 248 | primary_metric_name=experiment_settings["hyperparameter_sampling"]["primary_metric_name"], 249 | primary_metric_goal=primary_metric_goal, 250 | max_total_runs=experiment_settings["hyperparameter_sampling"]["max_total_runs"], 251 | max_concurrent_runs=experiment_settings["hyperparameter_sampling"]["max_concurrent_runs"], 252 | max_duration_minutes=experiment_settings["hyperparameter_sampling"]["max_duration_minutes"]) 253 | else: 254 | run_config = estimator 255 | 256 | # Submitting an Experiment and creating a Run 257 | print("Submitting an experiment and creating a run") 258 | run = exp.submit(run_config, tags=experiment_settings["run_tags"]) 259 | 260 | # Shows output of the run on stdout 261 | run.wait_for_completion(show_output=True, wait_post_processing=True) 262 | 263 | # Checking status of Run 264 | print("Checking status Run") 265 | if run.get_status() != "Completed": 266 | raise Exception( 267 | "Training on local failed with following run status: {} and logs: \n {}".format( 268 | run.get_status(), run.get_details_with_logs() 269 | ) 270 | ) 271 | 272 | # Writing the run id to /aml_service/run_id.json 273 | run_details = {} 274 | run_details["run_id"] = run.id 275 | run_details["experiment_name"] = run.experiment.name 276 | with open(os.path.join("aml_service", "run_details.json"), "w") as outfile: 277 | json.dump(run_details, outfile) -------------------------------------------------------------------------------- /aml_service/ci_cd/20-RegisterModel.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import os, json, sys, azureml.core 27 | from azureml.core import Workspace, Experiment, Run 28 | from azureml.core.model import Model 29 | from azureml.core.authentication import AzureCliAuthentication 30 | 31 | # Load the JSON settings file and relevant section 32 | print("Loading settings") 33 | with open(os.path.join("aml_service", "settings.json")) as f: 34 | settings = json.load(f) 35 | deployment_settings = settings["deployment"] 36 | 37 | # Get details from Run 38 | print("Loading Run Details") 39 | with open(os.path.join("aml_service", "run_details.json")) as f: 40 | run_details = json.load(f) 41 | 42 | # Get workspace 43 | print("Loading Workspace") 44 | cli_auth = AzureCliAuthentication() 45 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 46 | config_file_name = "aml_arm_config.json" 47 | ws = Workspace.from_config( 48 | path=config_file_path, 49 | auth=cli_auth, 50 | _file_name=config_file_name) 51 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 52 | 53 | # Loading Run 54 | print("Loading Run") 55 | experiment = Experiment(workspace=ws, name=run_details["experiment_name"]) 56 | run = Run(experiment=experiment, run_id=run_details["run_id"]) 57 | 58 | # Only register model, if it performs better than the production model 59 | print("Register model only if it performs better.") 60 | try: 61 | # Loading run of production model 62 | print("Loading Run of Production Model to evaluate new model") 63 | production_model = Model(workspace=ws, name=deployment_settings["model"]["name"]) 64 | production_model_run_id = production_model.tags.get(["run_id"]) 65 | production_model_run = Run(experiment=experiment, run_id=production_model_run_id) 66 | 67 | # Comparing models 68 | print("Comparing Metrics of production and newly trained model") 69 | promote_new_model = True 70 | for metric in deployment_settings["model"]["evaluation_parameters"]["larger_is_better"]: 71 | if not promote_new_model: 72 | break 73 | new_model_parameter = run.get_metrics().get(metric) 74 | production_model_parameter = production_model_run.get_metrics().get(metric) 75 | if new_model_parameter < production_model_parameter: 76 | promote_new_model = False 77 | for metric in deployment_settings["model"]["evaluation_parameters"]["smaller_is_better"]: 78 | if not promote_new_model: 79 | break 80 | new_model_parameter = run.get_metrics().get(metric) 81 | production_model_parameter = production_model_run.get_metrics().get(metric) 82 | if new_model_parameter > production_model_parameter: 83 | promote_new_model = False 84 | except Exception: 85 | promote_new_model = True 86 | print("This is the first model to be trained, thus nothing to evaluate for now") 87 | 88 | # TODO: Remove 89 | if promote_new_model: 90 | print("New model performs better, thus it will be registered") 91 | else: 92 | print("New model does not perform better.") 93 | print("Promote all models for now") 94 | promote_new_model = True 95 | 96 | # Registering new Model 97 | if promote_new_model: 98 | print("Registering new Model, because it performs better") 99 | tags = deployment_settings["model"]["tags"] 100 | tags["run_id"] = run.id 101 | model = run.register_model(model_name=deployment_settings["model"]["name"], 102 | model_path=deployment_settings["model"]["path"], 103 | tags=tags, 104 | properties=deployment_settings["model"]["properties"], 105 | model_framework=deployment_settings["model"]["model_framework"], 106 | model_framework_version=deployment_settings["model"]["model_framework_version"], 107 | description=deployment_settings["model"]["description"], 108 | datasets=deployment_settings["model"]["datasets"]) 109 | else: 110 | raise Exception("No new model to register as production model perform better") -------------------------------------------------------------------------------- /aml_service/ci_cd/30-ProfileModel.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import os, sys, json, azureml.core 27 | from azureml.core import Workspace, ContainerRegistry, Environment 28 | from azureml.core.model import Model, InferenceConfig 29 | from azureml.core.image import Image, ContainerImage 30 | from azureml.core.conda_dependencies import CondaDependencies 31 | from azureml.core.authentication import AzureCliAuthentication 32 | from helper import utils 33 | 34 | sys.path.insert(0, os.path.join("code", "testing")) 35 | import test_functions 36 | 37 | # Load the JSON settings file and relevant sections 38 | print("Loading settings") 39 | with open(os.path.join("aml_service", "settings.json")) as f: 40 | settings = json.load(f) 41 | deployment_settings = settings["deployment"] 42 | env_name = settings["experiment"]["name"] + "_deployment" 43 | 44 | # Get workspace 45 | print("Loading Workspace") 46 | cli_auth = AzureCliAuthentication() 47 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 48 | config_file_name = "aml_arm_config.json" 49 | ws = Workspace.from_config( 50 | path=config_file_path, 51 | auth=cli_auth, 52 | _file_name=config_file_name) 53 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 54 | 55 | # Loading Model 56 | print("Loading Model") 57 | model = Model(workspace=ws, name=deployment_settings["model"]["name"]) 58 | 59 | # Create image registry configuration 60 | if deployment_settings["image"]["docker"]["custom_image"]: 61 | container_registry = ContainerRegistry() 62 | container_registry.address = deployment_settings["image"]["docker"]["custom_image_registry_details"]["address"] 63 | container_registry.username = deployment_settings["image"]["docker"]["custom_image_registry_details"]["username"] 64 | container_registry.password = deployment_settings["image"]["docker"]["custom_image_registry_details"]["password"] 65 | else: 66 | container_registry = None 67 | 68 | # Creating dependencies 69 | print("Creating dependencies and registering environment") 70 | conda_dep = CondaDependencies.create(conda_packages=deployment_settings["image"]["dependencies"]["conda_packages"], 71 | pip_packages=deployment_settings["image"]["dependencies"]["pip_packages"], 72 | python_version=deployment_settings["image"]["dependencies"]["python_version"], 73 | pin_sdk_version=deployment_settings["image"]["dependencies"]["pin_sdk_version"]) 74 | dep_path = os.path.join("code", "scoring", "myenv.yml") 75 | conda_dep.save(path=dep_path) 76 | 77 | # Creating InferenceConfig 78 | print("Creating InferenceConfig") 79 | if deployment_settings["image"]["use_custom_environment"]: 80 | env = utils.get_environment(name_suffix="_deployment") 81 | inferenceConfig = InferenceConfig(entry_script=deployment_settings["image"]["entry_script"], 82 | source_directory=deployment_settings["image"]["source_directory"], 83 | runtime=deployment_settings["image"]["runtime"], 84 | environment=env) 85 | else: 86 | inference_config = InferenceConfig(entry_script=deployment_settings["image"]["entry_script"], 87 | source_directory=deployment_settings["image"]["source_directory"], 88 | runtime=deployment_settings["image"]["runtime"], 89 | conda_file=os.path.basename(dep_path), 90 | extra_docker_file_steps=deployment_settings["image"]["docker"]["extra_docker_file_steps"], 91 | enable_gpu=deployment_settings["image"]["docker"]["use_gpu"], 92 | description=deployment_settings["image"]["description"], 93 | base_image=deployment_settings["image"]["docker"]["custom_image"], 94 | base_image_registry=container_registry, 95 | cuda_version=deployment_settings["image"]["docker"]["cuda_version"]) 96 | 97 | # Registering Environment 98 | print("Registering Environment") 99 | if "env" not in locals(): 100 | env = Environment.from_conda_specification(name=env_name, file_path=dep_path) 101 | registered_env = env.register(workspace=ws) 102 | print("Registered Environment") 103 | print(registered_env.name, "Version: " + registered_env.version, sep="\n") 104 | 105 | # Profile model 106 | print("Profiling Model") 107 | test_sample = test_functions.get_test_data_sample() 108 | profile = Model.profile(workspace=ws, 109 | profile_name=deployment_settings["image"]["name"], 110 | models=[model], 111 | inference_config=inference_config, 112 | input_data=test_sample) 113 | profile.wait_for_profiling(show_output=True) 114 | print(profile.get_results(), profile.recommended_cpu, profile.recommended_cpu_latency, profile.recommended_memory, profile.recommended_memory_latency, sep="\n") 115 | 116 | # Writing the profiling results to /aml_service/profiling_result.json 117 | profiling_result = {} 118 | profiling_result["cpu"] = profile.recommended_cpu 119 | profiling_result["memory"] = profile.recommended_memory 120 | profiling_result["image_id"] = profile.image_id 121 | with open(os.path.join("aml_service", "profiling_result.json"), "w") as outfile: 122 | json.dump(profiling_result, outfile) -------------------------------------------------------------------------------- /aml_service/ci_cd/40-DevDeployment.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import os, sys, json 27 | from azureml.core import Workspace, Image 28 | from azureml.core.webservice import Webservice, AciWebservice 29 | from azureml.exceptions import WebserviceException 30 | from azureml.core.authentication import AzureCliAuthentication 31 | 32 | sys.path.insert(0, os.path.join("code", "testing")) 33 | import test_functions 34 | 35 | # Load the JSON settings file and relevant sections 36 | print("Loading settings") 37 | with open(os.path.join("aml_service", "settings.json")) as f: 38 | settings = json.load(f) 39 | deployment_settings = settings["deployment"] 40 | aci_settings = deployment_settings["dev_deployment"] 41 | 42 | # Loading Model Profile 43 | print("Loading Model Profile") 44 | with open(os.path.join("aml_service", "profiling_result.json")) as f: 45 | profiling_result = json.load(f) 46 | 47 | # Get workspace 48 | print("Loading Workspace") 49 | cli_auth = AzureCliAuthentication() 50 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 51 | config_file_name = "aml_arm_config.json" 52 | ws = Workspace.from_config( 53 | path=config_file_path, 54 | auth=cli_auth, 55 | _file_name=config_file_name) 56 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 57 | 58 | # Loading Image 59 | image_details = profiling_result["image_id"].split(":") 60 | image = Image(workspace=ws, 61 | name=image_details[0], 62 | version=image_details[1]) 63 | 64 | # Deploying model on ACI 65 | print("Deploying model on ACI") 66 | try: 67 | print("Trying to update existing ACI service") 68 | dev_service = AciWebservice(workspace=ws, name=aci_settings["name"]) 69 | dev_service.update(image=image, 70 | tags=deployment_settings["image"]["tags"], 71 | properties=deployment_settings["image"]["properties"], 72 | description=deployment_settings["image"]["description"], 73 | auth_enabled=aci_settings["auth_enabled"], 74 | ssl_enabled=aci_settings["ssl_enabled"], 75 | ssl_cert_pem_file=aci_settings["ssl_cert_pem_file"], 76 | ssl_key_pem_file=aci_settings["ssl_key_pem_file"], 77 | ssl_cname=aci_settings["ssl_cname"], 78 | enable_app_insights=aci_settings["enable_app_insights"]) 79 | print("Successfully updated existing ACI service") 80 | except WebserviceException: 81 | print("Failed to update ACI service... Creating new ACI instance") 82 | aci_config = AciWebservice.deploy_configuration(cpu_cores=profiling_result["cpu"], 83 | memory_gb=profiling_result["memory"], 84 | tags=deployment_settings["image"]["tags"], 85 | properties=deployment_settings["image"]["properties"], 86 | description=deployment_settings["image"]["description"], 87 | location=aci_settings["location"], 88 | auth_enabled=aci_settings["auth_enabled"], 89 | ssl_enabled=aci_settings["ssl_enabled"], 90 | ssl_cert_pem_file=aci_settings["ssl_cert_pem_file"], 91 | ssl_key_pem_file=aci_settings["ssl_key_pem_file"], 92 | ssl_cname=aci_settings["ssl_cname"], 93 | enable_app_insights=aci_settings["enable_app_insights"], 94 | dns_name_label=aci_settings["dns_name_label"]) 95 | 96 | # Deploying dev web service from image 97 | dev_service = Webservice.deploy_from_image(workspace=ws, 98 | name=aci_settings["name"], 99 | image=image, 100 | deployment_config=aci_config) 101 | 102 | # Show output of the deployment on stdout 103 | dev_service.wait_for_deployment(show_output=True) 104 | print("State of Service: {}".format(dev_service.state)) 105 | 106 | # Checking status of web service 107 | print("Checking status of ACI Dev Deployment") 108 | if dev_service.state != "Healthy": 109 | raise Exception( 110 | "Dev Deployment on ACI failed with the following status: {} and logs: \n{}".format( 111 | dev_service.state, dev_service.get_logs() 112 | ) 113 | ) 114 | 115 | # Testing ACI web service 116 | print("Testing ACI web service") 117 | test_sample = test_functions.get_test_data_sample() 118 | print("Test Sample: ", test_sample) 119 | test_sample_encoded = bytes(test_sample, encoding='utf8') 120 | try: 121 | prediction = dev_service.run(input_data=test_sample) 122 | print(prediction) 123 | except Exception as e: 124 | result = str(e) 125 | logs = dev_service.get_logs() 126 | dev_service.delete() 127 | raise Exception("ACI Dev web service is not working as expected: \n{} \nLogs: \n{}".format(result, logs)) 128 | 129 | # Delete aci after test 130 | print("Deleting ACI Dev web service after successful test") 131 | dev_service.delete() -------------------------------------------------------------------------------- /aml_service/ci_cd/50-TestDeployment.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import os, sys, json 27 | from azureml.core import Workspace, Image 28 | from azureml.core.webservice import Webservice, AksWebservice 29 | from azureml.exceptions import WebserviceException 30 | from azureml.core.authentication import AzureCliAuthentication 31 | from azureml.core.compute import AksCompute, ComputeTarget 32 | from azureml.exceptions import ComputeTargetException 33 | 34 | sys.path.insert(0, os.path.join("code", "testing")) 35 | import test_functions 36 | 37 | # Load the JSON settings file and relevant sections 38 | print("Loading settings") 39 | with open(os.path.join("aml_service", "settings.json")) as f: 40 | settings = json.load(f) 41 | deployment_settings = settings["deployment"] 42 | aks_service_settings = deployment_settings["test_deployment"] 43 | aks_compute_settings = settings["compute_target"]["deployment"]["aks_test"] 44 | 45 | # Loading Model Profile 46 | print("Loading Model Profile") 47 | with open(os.path.join("aml_service", "profiling_result.json")) as f: 48 | profiling_result = json.load(f) 49 | 50 | # Get workspace 51 | print("Loading Workspace") 52 | cli_auth = AzureCliAuthentication() 53 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 54 | config_file_name = "aml_arm_config.json" 55 | ws = Workspace.from_config( 56 | path=config_file_path, 57 | auth=cli_auth, 58 | _file_name=config_file_name) 59 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 60 | 61 | # Loading Image 62 | image_details = profiling_result["image_id"].split(":") 63 | image = Image(workspace=ws, 64 | name=image_details[0], 65 | version=image_details[1]) 66 | 67 | try: 68 | # Loading existing Test AKS Cluster 69 | print("Loading existing Test AKS Cluster") 70 | aks_test_cluster = AksCompute(workspace=ws, name=aks_compute_settings["name"]) 71 | 72 | # Check settings and redeploy if required settings have changed 73 | print("Found existing cluster") 74 | #aks_test_cluster.update() 75 | #print("Successfully updated Cluster definition") 76 | except ComputeTargetException: 77 | print("Loading failed ... Creating new Dev AKS Cluster") 78 | compute_config = AksCompute.provisioning_configuration(agent_count=aks_compute_settings["agent_count"], 79 | vm_size=aks_compute_settings["vm_size"], 80 | ssl_cname=aks_compute_settings["ssl_cname"], 81 | ssl_cert_pem_file=aks_compute_settings["ssl_cert_pem_file"], 82 | ssl_key_pem_file=aks_compute_settings["ssl_key_pem_file"], 83 | location=aks_compute_settings["location"], 84 | service_cidr=aks_compute_settings["service_cidr"], 85 | dns_service_ip=aks_compute_settings["dns_service_ip"], 86 | docker_bridge_cidr=aks_compute_settings["docker_bridge_cidr"], 87 | cluster_purpose=AksCompute.ClusterPurpose.DEV_TEST) 88 | # Deploy to VNET if provided 89 | if aks_compute_settings["vnet_resourcegroup_name"] and aks_compute_settings["vnet_name"] and aks_compute_settings["subnet_name"]: 90 | compute_config.vnet_resourcegroup_name = aks_compute_settings["vnet_resourcegroup_name"] 91 | compute_config.vnet_name = aks_compute_settings["vnet_name"] 92 | compute_config.subnet_name = aks_compute_settings["subnet_name"] 93 | 94 | # Create Compute Target 95 | aks_test_cluster = ComputeTarget.create(workspace=ws, name=aks_compute_settings["name"], provisioning_configuration=compute_config) 96 | 97 | # Wait until the cluster is attached 98 | aks_test_cluster.wait_for_completion(show_output=True) 99 | 100 | # Checking status of Test AKS Cluster 101 | print("Checking status of Test AKS Cluster") 102 | if aks_test_cluster.provisioning_state == "Failed": 103 | aks_test_cluster.delete() 104 | raise Exception( 105 | "Deployment of Test AKS Cluster failed with the following status: {} and logs: \n {}".format( 106 | aks_test_cluster.provisioning_state, aks_test_cluster.provisioning_errors 107 | ) 108 | ) 109 | 110 | # Deploying model on test AKS 111 | print("Deploying model on Test AKS") 112 | try: 113 | print("Trying to update existing AKS test service") 114 | test_service = AksWebservice(workspace=ws, name=aks_service_settings["name"]) 115 | test_service.update(image=image, 116 | autoscale_enabled=aks_service_settings["autoscale_enabled"], 117 | autoscale_min_replicas=aks_service_settings["autoscale_min_replicas"], 118 | autoscale_max_replicas=aks_service_settings["autoscale_max_replicas"], 119 | autoscale_refresh_seconds=aks_service_settings["autoscale_refresh_seconds"], 120 | autoscale_target_utilization=aks_service_settings["autoscale_target_utilization"], 121 | collect_model_data=aks_service_settings["collect_model_data"], 122 | auth_enabled=aks_service_settings["auth_enabled"], 123 | cpu_cores=profiling_result["cpu"], 124 | memory_gb=profiling_result["memory"], 125 | enable_app_insights=aks_service_settings["enable_app_insights"], 126 | scoring_timeout_ms=aks_service_settings["scoring_timeout_ms"], 127 | replica_max_concurrent_requests=aks_service_settings["replica_max_concurrent_requests"], 128 | max_request_wait_time=aks_service_settings["max_request_wait_time"], 129 | num_replicas=aks_service_settings["num_replicas"], 130 | tags=deployment_settings["image"]["tags"], 131 | properties=deployment_settings["image"]["properties"], 132 | description=deployment_settings["image"]["description"], 133 | gpu_cores=aks_service_settings["gpu_cores"], 134 | period_seconds=aks_service_settings["period_seconds"], 135 | initial_delay_seconds=aks_service_settings["initial_delay_seconds"], 136 | timeout_seconds=aks_service_settings["timeout_seconds"], 137 | success_threshold=aks_service_settings["success_threshold"], 138 | failure_threshold=aks_service_settings["failure_threshold"], 139 | namespace=aks_service_settings["namespace"], 140 | token_auth_enabled=aks_service_settings["token_auth_enabled"]) 141 | print("Successfully updated existing AKS test service") 142 | except WebserviceException: 143 | print("Failed to update AKS test service... Creating new AKS test service") 144 | aks_config = AksWebservice.deploy_configuration(autoscale_enabled=aks_service_settings["autoscale_enabled"], 145 | autoscale_min_replicas=aks_service_settings["autoscale_min_replicas"], 146 | autoscale_max_replicas=aks_service_settings["autoscale_max_replicas"], 147 | autoscale_refresh_seconds=aks_service_settings["autoscale_refresh_seconds"], 148 | autoscale_target_utilization=aks_service_settings["autoscale_target_utilization"], 149 | collect_model_data=aks_service_settings["collect_model_data"], 150 | auth_enabled=aks_service_settings["auth_enabled"], 151 | cpu_cores=profiling_result["cpu"], 152 | memory_gb=profiling_result["memory"], 153 | enable_app_insights=aks_service_settings["enable_app_insights"], 154 | scoring_timeout_ms=aks_service_settings["scoring_timeout_ms"], 155 | replica_max_concurrent_requests=aks_service_settings["replica_max_concurrent_requests"], 156 | max_request_wait_time=aks_service_settings["max_request_wait_time"], 157 | num_replicas=aks_service_settings["num_replicas"], 158 | primary_key=aks_service_settings["primary_key"], 159 | secondary_key=aks_service_settings["secondary_key"], 160 | tags=deployment_settings["image"]["tags"], 161 | properties=deployment_settings["image"]["properties"], 162 | description=deployment_settings["image"]["description"], 163 | gpu_cores=aks_service_settings["gpu_cores"], 164 | period_seconds=aks_service_settings["period_seconds"], 165 | initial_delay_seconds=aks_service_settings["initial_delay_seconds"], 166 | timeout_seconds=aks_service_settings["timeout_seconds"], 167 | success_threshold=aks_service_settings["success_threshold"], 168 | failure_threshold=aks_service_settings["failure_threshold"], 169 | namespace=aks_service_settings["namespace"], 170 | token_auth_enabled=aks_service_settings["token_auth_enabled"]) 171 | 172 | # Deploying test web service from image 173 | test_service = Webservice.deploy_from_image(workspace=ws, 174 | name=aks_service_settings["name"], 175 | image=image, 176 | deployment_config=aks_config, 177 | deployment_target=aks_test_cluster) 178 | # Show output of the deployment on stdout 179 | test_service.wait_for_deployment(show_output=True) 180 | print(test_service.state) 181 | 182 | # Checking status of test web service 183 | print("Checking status of AKS Test Deployment") 184 | if test_service.state != "Healthy": 185 | raise Exception( 186 | "Test Deployment on AKS failed with the following status: {} and logs: \n{}".format( 187 | test_service.state, test_service.get_logs() 188 | ) 189 | ) 190 | 191 | # Testing AKS web service 192 | print("Testing AKS test web service") 193 | test_sample = test_functions.get_test_data_sample() 194 | print("Test Sample: ", test_sample) 195 | test_sample_encoded = bytes(test_sample, encoding='utf8') 196 | try: 197 | prediction = test_service.run(input_data=test_sample) 198 | print(prediction) 199 | except Exception as e: 200 | result = str(e) 201 | logs = test_service.get_logs() 202 | test_service.delete() 203 | raise Exception("AKS Test web service is not working as expected: \n{} \nLogs: \n{}".format(result, logs)) 204 | 205 | # Delete test AKS service after test 206 | print("Deleting AKS Test web service after successful test") 207 | test_service.delete() -------------------------------------------------------------------------------- /aml_service/ci_cd/60-ProdDeployment.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import os, sys, json 27 | from azureml.core import Workspace, Image 28 | from azureml.core.webservice import Webservice, AksWebservice 29 | from azureml.exceptions import WebserviceException 30 | from azureml.core.authentication import AzureCliAuthentication 31 | from azureml.core.compute import AksCompute, ComputeTarget 32 | from azureml.exceptions import ComputeTargetException 33 | 34 | sys.path.insert(0, os.path.join("code", "testing")) 35 | import test_functions 36 | 37 | # Load the JSON settings file and relevant sections 38 | print("Loading settings") 39 | with open(os.path.join("aml_service", "settings.json")) as f: 40 | settings = json.load(f) 41 | deployment_settings = settings["deployment"] 42 | aks_service_settings = deployment_settings["prod_deployment"] 43 | aks_compute_settings = settings["compute_target"]["deployment"]["aks_prod"] 44 | 45 | # Loading Model Profile 46 | print("Loading Model Profile") 47 | with open(os.path.join("aml_service", "profiling_result.json")) as f: 48 | profiling_result = json.load(f) 49 | 50 | # Get workspace 51 | print("Loading Workspace") 52 | cli_auth = AzureCliAuthentication() 53 | config_file_path = os.environ.get("GITHUB_WORKSPACE", default="aml_service") 54 | config_file_name = "aml_arm_config.json" 55 | ws = Workspace.from_config( 56 | path=config_file_path, 57 | auth=cli_auth, 58 | _file_name=config_file_name) 59 | print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\n') 60 | 61 | # Loading Image 62 | image_details = profiling_result["image_id"].split(":") 63 | image = Image(workspace=ws, 64 | name=image_details[0], 65 | version=image_details[1]) 66 | 67 | try: 68 | # Loading existing Prod AKS Cluster 69 | print("Loading existing Prod AKS Cluster") 70 | aks_prod_cluster = AksCompute(workspace=ws, name=aks_compute_settings["name"]) 71 | 72 | # Check settings and redeploy if required settings have changed 73 | print("Found existing cluster") 74 | #aks_prod_cluster.update() 75 | #print("Successfully updated Cluster definition") 76 | except ComputeTargetException: 77 | print("Loading failed ... Creating new Prod AKS Cluster") 78 | compute_config = AksCompute.provisioning_configuration(agent_count=aks_compute_settings["agent_count"], 79 | vm_size=aks_compute_settings["vm_size"], 80 | ssl_cname=aks_compute_settings["ssl_cname"], 81 | ssl_cert_pem_file=aks_compute_settings["ssl_cert_pem_file"], 82 | ssl_key_pem_file=aks_compute_settings["ssl_key_pem_file"], 83 | location=aks_compute_settings["location"], 84 | service_cidr=aks_compute_settings["service_cidr"], 85 | dns_service_ip=aks_compute_settings["dns_service_ip"], 86 | docker_bridge_cidr=aks_compute_settings["docker_bridge_cidr"], 87 | cluster_purpose=AksCompute.ClusterPurpose.FAST_PROD) 88 | # Deploy to VNET if provided 89 | if aks_compute_settings["vnet_resourcegroup_name"] and aks_compute_settings["vnet_name"] and aks_compute_settings["subnet_name"]: 90 | compute_config.vnet_resourcegroup_name = aks_compute_settings["vnet_resourcegroup_name"] 91 | compute_config.vnet_name = aks_compute_settings["vnet_name"] 92 | compute_config.subnet_name = aks_compute_settings["subnet_name"] 93 | 94 | # Create Compute Target 95 | aks_prod_cluster = ComputeTarget.create(workspace=ws, name=aks_compute_settings["name"], provisioning_configuration=compute_config) 96 | 97 | # Wait until the cluster is attached 98 | aks_prod_cluster.wait_for_completion(show_output=True) 99 | 100 | # Checking status of Test AKS Cluster 101 | print("Checking status of Test AKS Cluster") 102 | if aks_prod_cluster.provisioning_state == "Failed": 103 | aks_prod_cluster.delete() 104 | raise Exception( 105 | "Deployment of Test AKS Cluster failed with the following status: {} and logs: \n {}".format( 106 | aks_prod_cluster.provisioning_state, aks_prod_cluster.provisioning_errors 107 | ) 108 | ) 109 | 110 | # Deploying model on prod AKS 111 | print("Deploying model on Prod AKS") 112 | try: 113 | print("Trying to update existing Prod web service") 114 | prod_service = AksWebservice(workspace=ws, name=aks_service_settings["name"]) 115 | prod_service.update(image=image, 116 | autoscale_enabled=aks_service_settings["autoscale_enabled"], 117 | autoscale_min_replicas=aks_service_settings["autoscale_min_replicas"], 118 | autoscale_max_replicas=aks_service_settings["autoscale_max_replicas"], 119 | autoscale_refresh_seconds=aks_service_settings["autoscale_refresh_seconds"], 120 | autoscale_target_utilization=aks_service_settings["autoscale_target_utilization"], 121 | collect_model_data=aks_service_settings["collect_model_data"], 122 | auth_enabled=aks_service_settings["auth_enabled"], 123 | cpu_cores=profiling_result["cpu"], 124 | memory_gb=profiling_result["memory"], 125 | enable_app_insights=aks_service_settings["enable_app_insights"], 126 | scoring_timeout_ms=aks_service_settings["scoring_timeout_ms"], 127 | replica_max_concurrent_requests=aks_service_settings["replica_max_concurrent_requests"], 128 | max_request_wait_time=aks_service_settings["max_request_wait_time"], 129 | num_replicas=aks_service_settings["num_replicas"], 130 | tags=deployment_settings["image"]["tags"], 131 | properties=deployment_settings["image"]["properties"], 132 | description=deployment_settings["image"]["description"], 133 | gpu_cores=aks_service_settings["gpu_cores"], 134 | period_seconds=aks_service_settings["period_seconds"], 135 | initial_delay_seconds=aks_service_settings["initial_delay_seconds"], 136 | timeout_seconds=aks_service_settings["timeout_seconds"], 137 | success_threshold=aks_service_settings["success_threshold"], 138 | failure_threshold=aks_service_settings["failure_threshold"], 139 | namespace=aks_service_settings["namespace"], 140 | token_auth_enabled=aks_service_settings["token_auth_enabled"]) 141 | print("Successfully updated existing AKS Prod service") 142 | except WebserviceException: 143 | print("Failed to update AKS test service... Creating new AKS Prod service") 144 | aks_config = AksWebservice.deploy_configuration(autoscale_enabled=aks_service_settings["autoscale_enabled"], 145 | autoscale_min_replicas=aks_service_settings["autoscale_min_replicas"], 146 | autoscale_max_replicas=aks_service_settings["autoscale_max_replicas"], 147 | autoscale_refresh_seconds=aks_service_settings["autoscale_refresh_seconds"], 148 | autoscale_target_utilization=aks_service_settings["autoscale_target_utilization"], 149 | collect_model_data=aks_service_settings["collect_model_data"], 150 | auth_enabled=aks_service_settings["auth_enabled"], 151 | cpu_cores=profiling_result["cpu"], 152 | memory_gb=profiling_result["memory"], 153 | enable_app_insights=aks_service_settings["enable_app_insights"], 154 | scoring_timeout_ms=aks_service_settings["scoring_timeout_ms"], 155 | replica_max_concurrent_requests=aks_service_settings["replica_max_concurrent_requests"], 156 | max_request_wait_time=aks_service_settings["max_request_wait_time"], 157 | num_replicas=aks_service_settings["num_replicas"], 158 | primary_key=aks_service_settings["primary_key"], 159 | secondary_key=aks_service_settings["secondary_key"], 160 | tags=deployment_settings["image"]["tags"], 161 | properties=deployment_settings["image"]["properties"], 162 | description=deployment_settings["image"]["description"], 163 | gpu_cores=aks_service_settings["gpu_cores"], 164 | period_seconds=aks_service_settings["period_seconds"], 165 | initial_delay_seconds=aks_service_settings["initial_delay_seconds"], 166 | timeout_seconds=aks_service_settings["timeout_seconds"], 167 | success_threshold=aks_service_settings["success_threshold"], 168 | failure_threshold=aks_service_settings["failure_threshold"], 169 | namespace=aks_service_settings["namespace"], 170 | token_auth_enabled=aks_service_settings["token_auth_enabled"]) 171 | 172 | # Deploying prod web service from image 173 | prod_service = Webservice.deploy_from_image(workspace=ws, 174 | name=aks_service_settings["name"], 175 | image=image, 176 | deployment_config=aks_config, 177 | deployment_target=aks_prod_cluster) 178 | # Show output of the deployment on stdout 179 | prod_service.wait_for_deployment(show_output=True) 180 | print(prod_service.state) 181 | 182 | # Checking status of prod web service 183 | print("Checking status of AKS Prod Deployment") 184 | if prod_service.state != "Healthy": 185 | raise Exception( 186 | "Prod Deployment on AKS failed with the following status: {} and logs: \n{}".format( 187 | prod_service.state, prod_service.get_logs() 188 | ) 189 | ) 190 | 191 | # Testing AKS web service 192 | print("Testing AKS prod web service") 193 | test_sample = test_functions.get_test_data_sample() 194 | print("Test Sample: ", test_sample) 195 | test_sample_encoded = bytes(test_sample, encoding='utf8') 196 | try: 197 | prediction = prod_service.run(input_data=test_sample) 198 | print(prediction) 199 | except Exception as e: 200 | result = str(e) 201 | logs = prod_service.get_logs() 202 | raise Exception("AKS Prod web service is not working as expected: \n{} \nLogs: \n{}".format(result, logs)) -------------------------------------------------------------------------------- /aml_service/ci_cd/helper/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marvinbuss/MLDevOps/43a4f9b7ab86b0540c206158d35f7bbf910aa6ed/aml_service/ci_cd/helper/__init__.py -------------------------------------------------------------------------------- /aml_service/ci_cd/helper/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import os, json, azureml.core 27 | from azureml.core import Environment 28 | from azureml.core.environment import CondaDependencies 29 | from azureml.train.hyperdrive import BanditPolicy, MedianStoppingPolicy, NoTerminationPolicy, TruncationSelectionPolicy 30 | from azureml.train.hyperdrive import RandomParameterSampling, GridParameterSampling, BayesianParameterSampling 31 | from azureml.train.hyperdrive import choice, randint, uniform, quniform, loguniform, qloguniform, normal, qnormal, lognormal, qlognormal 32 | from azureml.exceptions import RunConfigurationException 33 | 34 | 35 | def get_environment(name_suffix="_training"): 36 | # Load the JSON settings file 37 | print("Loading settings") 38 | with open(os.path.join("aml_config", "settings.json")) as f: 39 | settings = json.load(f) 40 | env_settings = settings["environment"] 41 | env_name = settings["experiment"]["name"] + name_suffix 42 | 43 | # Create Dependencies 44 | print("Defining Conda Dependencies") 45 | conda_dep = CondaDependencies().create( 46 | pip_indexurl=None, 47 | pip_packages=env_settings["pip_packages"], 48 | conda_packages=env_settings["conda_packages"], 49 | python_version=env_settings["python_version"], 50 | pin_sdk_version=env_settings["pin_sdk_version"] 51 | ) 52 | conda_dep.save(path=env_settings["dependencies_config"]["path"]) 53 | 54 | # Create Environment and setting parameters 55 | print("Creating Environment") 56 | env = Environment(name=env_name) 57 | env.python.conda_dependencies = conda_dep 58 | env.environment_variables = env_settings["env_variables"] 59 | 60 | if env_settings["user_managed_dependencies"]: 61 | print("Using existing user-managed Python environment for run") 62 | env.user_managed_dependencies = env_settings["user_managed_dependencies"] 63 | elif env_settings["docker"]["enabled"]: 64 | print("Using Docker run with system-built conda environment based on dependency specification") 65 | env.docker.enabled = env_settings["docker"]["enabled"] 66 | env.docker.gpu_support = env_settings["docker"]["gpu_support"] 67 | env.docker.arguments = env_settings["docker"]["arguments"] 68 | env.docker.shared_volumes = env_settings["docker"]["shared_volumes"] 69 | env.docker.shm_size = env_settings["docker"]["shm_size"] 70 | 71 | if env_settings["docker"]["gpu_support"] and env_settings["docker"]["mpi_image"]: 72 | env.docker.base_image = azureml.core.runconfig.MPI_GPU_IMAGE 73 | elif env_settings["docker"]["gpu_support"]: 74 | env.docker.base_image = azureml.core.runconfig.DEFAULT_GPU_IMAGE 75 | elif env_settings["docker"]["mpi_image"]: 76 | env.docker.base_image = azureml.core.runconfig.MPI_CPU_IMAGE 77 | 78 | env.docker.base_image = env_settings["docker"]["base_image"] 79 | env.docker.base_image_registry.address = env_settings["docker"]["base_image_registry"]["address"] 80 | env.docker.base_image_registry.username = env_settings["docker"]["base_image_registry"]["username"] 81 | env.docker.base_image_registry.password = env_settings["docker"]["base_image_registry"]["password"] 82 | else: 83 | print("Using system-build conda environment based on dependency specification") 84 | env.docker.enabled = False 85 | return env 86 | 87 | 88 | def get_parameter_sampling(sampling_method, parameter_settings): 89 | parameter_dict = {} 90 | for parameter_name, parameter_setting in parameter_settings.items(): 91 | parameter_distr = get_parameter_distribution(parameter_name, parameter_setting) 92 | parameter_dict["--{}".format(parameter_name)] = parameter_distr 93 | 94 | if "random" in sampling_method: 95 | ps = RandomParameterSampling(parameter_dict) 96 | elif "grid" in sampling_method: 97 | ps = GridParameterSampling(parameter_dict) 98 | elif "bayesian" in sampling_method: 99 | ps = BayesianParameterSampling(parameter_dict) 100 | else: 101 | ps = None 102 | raise RunConfigurationException("Parameter Sampling Method not defined in settings. Please choose between \'random\', \'grid\' and \'bayesian\'") 103 | return ps 104 | 105 | 106 | def get_parameter_distribution(parameter_name, parameter_setting): 107 | if "choice" in parameter_setting["distribution"]: 108 | parameter_distr = choice(parameter_setting["parameters"]["options"]) 109 | elif "randint" in parameter_setting["distribution"]: 110 | parameter_distr = randint(upper=parameter_setting["parameters"]["upper"]) 111 | elif "uniform" in parameter_setting["distribution"]: 112 | parameter_distr = uniform(min_value=parameter_setting["parameters"]["min_value"], max_value=parameter_setting["parameters"]["max_value"]) 113 | elif "quniform" in parameter_setting["distribution"]: 114 | parameter_distr = quniform(min_value=parameter_setting["parameters"]["min_value"], max_value=parameter_setting["parameters"]["max_value"], q=parameter_setting["parameters"]["q"]) 115 | elif "loguniform" in parameter_setting["distribution"]: 116 | parameter_distr = loguniform(min_value=parameter_setting["parameters"]["min_value"], max_value=parameter_setting["parameters"]["max_value"]) 117 | elif "qloguniform" in parameter_setting["distribution"]: 118 | parameter_distr = qloguniform(min_value=parameter_setting["parameters"]["min_value"], max_value=parameter_setting["parameters"]["max_value"], q=parameter_setting["parameters"]["q"]) 119 | elif "normal" in parameter_setting["distribution"]: 120 | parameter_distr = normal(mu=parameter_setting["parameters"]["mu"], sigma=parameter_setting["parameters"]["sigma"]) 121 | elif "qnormal" in parameter_setting["distribution"]: 122 | parameter_distr = qnormal(mu=parameter_setting["parameters"]["mu"], sigma=parameter_setting["parameters"]["sigma"], q=parameter_setting["parameters"]["q"]) 123 | elif "lognormal" in parameter_setting["distribution"]: 124 | parameter_distr = lognormal(mu=parameter_setting["parameters"]["mu"], sigma=parameter_setting["parameters"]["sigma"]) 125 | elif "qlognormal" in parameter_setting["distribution"]: 126 | parameter_distr = qlognormal(mu=parameter_setting["parameters"]["mu"], sigma=parameter_setting["parameters"]["sigma"], q=parameter_setting["parameters"]["q"]) 127 | else: 128 | parameter_distr = None 129 | raise RunConfigurationException("Parameter distribution for parameter {} not defined in settings. Please choose between \'choice\', \'randint\', \'uniform\', \'quniform\', \'loguniform\', \'qloguniform\', \'normal\', \'qnormal\', \'lognormal\' and \'qlognormal\'".format(parameter_name)) 130 | return parameter_distr 131 | 132 | def get_policy(policy_settings): 133 | if "bandit" in policy_settings["name"]: 134 | policy = BanditPolicy(evaluation_interval=policy_settings["evaluation_interval"], 135 | delay_evaluation=policy_settings["delay_evaluation"], 136 | slack_factor=policy_settings["bandit"]["slack_factor"], 137 | slack_amount=policy_settings["bandit"]["slack_amount"]) 138 | elif "medianstopping" in policy_settings["name"]: 139 | policy = MedianStoppingPolicy(evaluation_interval=policy_settings["evaluation_interval"], 140 | delay_evaluation=policy_settings["delay_evaluation"]) 141 | elif "noterminal" in policy_settings["name"]: 142 | policy = NoTerminationPolicy() 143 | elif "truncationselection" in policy_settings["name"]: 144 | policy = TruncationSelectionPolicy(evaluation_interval=policy_settings["evaluation_interval"], 145 | delay_evaluation=policy_settings["delay_evaluation"], 146 | truncation_percentage=policy_settings["truncationselection"]["truncation_percentage"]) 147 | else: 148 | policy = None 149 | return policy -------------------------------------------------------------------------------- /aml_service/ci_cd/requirements.txt: -------------------------------------------------------------------------------- 1 | azure-cli==2.1.0 2 | azureml-sdk==1.0.69 3 | -------------------------------------------------------------------------------- /aml_service/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "experiment":{ 3 | "name": "github-actions-ai-demo", 4 | "source_directory": "./code/training", 5 | "entry_script": "train.py", 6 | "script_parameters": {}, 7 | "user_managed": false, 8 | "environment_variables": {}, 9 | "source_directory_datastore": null, 10 | "dependencies": { 11 | "conda_packages": [], 12 | "pip_packages": [], 13 | "conda_dependencies_file": null, 14 | "pip_requirements_file": null 15 | }, 16 | "framework": { 17 | "name": "sklearn", 18 | "chainer": { 19 | "framework_version": "5.1.0", 20 | "_enable_optimized_mode": false 21 | }, 22 | "pytorch": { 23 | "framework_version": "1.1", 24 | "_enable_optimized_mode": false 25 | }, 26 | "sklearn": { 27 | "framework_version": "0.20.3", 28 | "_enable_optimized_mode": false 29 | }, 30 | "tensorflow": { 31 | "framework_version": "1.13", 32 | "_enable_optimized_mode": false 33 | } 34 | }, 35 | "distributed_training":{ 36 | "backend_config": null, 37 | "node_count": 1, 38 | "mpi": { 39 | "process_count_per_node": 1 40 | }, 41 | "parameter_server": { 42 | "worker_count": 1, 43 | "parameter_server_count": "1" 44 | } 45 | }, 46 | "docker": { 47 | "use_docker": true, 48 | "shm_size": "1g", 49 | "custom_image": null, 50 | "custom_image_registry_details": { 51 | "address": null, 52 | "username": null, 53 | "password": null 54 | } 55 | }, 56 | "hyperparameter_sampling": { 57 | "use_hyperparameter_sampling": false, 58 | "method": null, 59 | "parameters": { 60 | "value_name": { 61 | "distribution": "quniform", 62 | "parameters": { 63 | "min_value": 1.0, 64 | "max_value": 2.0, 65 | "q": 2 66 | } 67 | }, 68 | "value_name2": { 69 | "distribution": "uniform", 70 | "parameters": { 71 | "min_value": 1.0, 72 | "max_value": 2.0 73 | } 74 | } 75 | }, 76 | "policy": { 77 | "name": "bandit", 78 | "evaluation_interval": 1, 79 | "delay_evaluation": 0, 80 | "bandit": { 81 | "slack_factor": 0.15, 82 | "slack_amount": null 83 | }, 84 | "truncationselection": { 85 | "truncation_percentage": 5 86 | } 87 | }, 88 | "primary_metric_name": "", 89 | "primary_metric_goal": "max", 90 | "max_total_runs": 8, 91 | "max_concurrent_runs": 1, 92 | "max_duration_minutes": 10080 93 | }, 94 | "resume_state": { 95 | "resume_from_state": false, 96 | "data_reference_name": null, 97 | "datapath_compute_binding": null 98 | }, 99 | "history": { 100 | "output_collection": true, 101 | "snapshotProject": true, 102 | "directoriesToWatch": ["logs"] 103 | }, 104 | "run_tags": { 105 | "submitted": "GitHub Actions" 106 | }, 107 | "data_references": {}, 108 | "max_run_duration_seconds": null, 109 | "use_custom_environment": false 110 | }, 111 | "compute_target": { 112 | "compute_target_to_use_for_training": "amlcompute", 113 | "training": { 114 | "amlcompute":{ 115 | "name": "my-aml-cluster", 116 | "vm_size": "STANDARD_D2_V2", 117 | "vm_priority": "dedicated", 118 | "min_nodes": 0, 119 | "max_nodes": 4, 120 | "idle_seconds_before_scaledown": "300", 121 | "vnet_resource_group_name": null, 122 | "vnet_name": null, 123 | "subnet_name": null, 124 | "admin_username": null, 125 | "admin_user_password": null, 126 | "admin_user_ssh_key": null, 127 | "tags": { 128 | "Creator": "GitHub Actions" 129 | }, 130 | "description": "AMLCompute for GitHub Actions" 131 | }, 132 | "dsvm":{ 133 | "name": "my-vm", 134 | "vm_size": "Standard_D2_v2", 135 | "location": null, 136 | "ssh_port": null 137 | }, 138 | "remotecompute":{ 139 | "name": "my-remote-vm", 140 | "use_ssh_auth": false, 141 | "address": "", 142 | "username": "", 143 | "password": null, 144 | "ssh_port": 22, 145 | "private_key_file": null, 146 | "private_key_passphrase": null 147 | } 148 | }, 149 | "deployment": { 150 | "aci_dev": {}, 151 | "aks_test": { 152 | "name": "testAKS", 153 | "agent_count": 1, 154 | "vm_size": "Standard_D3_v2", 155 | "ssl_cname": null, 156 | "ssl_cert_pem_file": null, 157 | "ssl_key_pem_file": null, 158 | "location": null, 159 | "vnet_resourcegroup_name": null, 160 | "vnet_name": null, 161 | "subnet_name": null, 162 | "service_cidr": null, 163 | "dns_service_ip": null, 164 | "docker_bridge_cidr": null 165 | }, 166 | "aks_prod": { 167 | "name": "prodAKS", 168 | "agent_count": 3, 169 | "vm_size": "Standard_D3_v2", 170 | "ssl_cname": null, 171 | "ssl_cert_pem_file": null, 172 | "ssl_key_pem_file": null, 173 | "location": null, 174 | "vnet_resourcegroup_name": null, 175 | "vnet_name": null, 176 | "subnet_name": null, 177 | "service_cidr": null, 178 | "dns_service_ip": null, 179 | "docker_bridge_cidr": null 180 | } 181 | } 182 | }, 183 | "deployment": { 184 | "model": { 185 | "name": "mymodel", 186 | "path": "outputs/mymodel.pkl", 187 | "evaluation_parameters": { 188 | "larger_is_better": [], 189 | "smaller_is_better": ["mse"] 190 | }, 191 | "tags":{ 192 | "Creator": "GitHub Actions" 193 | }, 194 | "properties": { 195 | "Creator": "GitHub Actions" 196 | }, 197 | "description": "Model registered by GitHub Actions", 198 | "model_framework": null, 199 | "model_framework_version": null, 200 | "datasets": null 201 | }, 202 | "image": { 203 | "name": "myimage", 204 | "entry_script": "score.py", 205 | "source_directory": "code/scoring/", 206 | "runtime": "python", 207 | "dependencies": { 208 | "conda_packages": ["numpy","scikit-learn"], 209 | "pip_packages": ["azureml-defaults", "azureml-monitoring"], 210 | "python_version": "3.6.2", 211 | "pin_sdk_version": true 212 | }, 213 | "docker": { 214 | "use_gpu": false, 215 | "cuda_version": null, 216 | "custom_image": null, 217 | "custom_image_registry_details": { 218 | "address": null, 219 | "username": null, 220 | "password": null 221 | }, 222 | "extra_docker_file_steps": null 223 | }, 224 | "tags":{ 225 | "Creator":"GitHub Actions" 226 | }, 227 | "properties":{ 228 | "Creator":"GitHub Actions" 229 | }, 230 | "description": "Image registered by GitHub Actions", 231 | "use_custom_environment": false 232 | }, 233 | "dev_deployment": { 234 | "name": "dev-aci", 235 | "auth_enabled": false, 236 | "ssl_enabled": false, 237 | "ssl_cert_pem_file": null, 238 | "ssl_key_pem_file": null, 239 | "ssl_cname": null, 240 | "enable_app_insights": true, 241 | "location": null, 242 | "dns_name_label": null 243 | }, 244 | "test_deployment": { 245 | "name": "test-aks", 246 | "autoscale_enabled": true, 247 | "autoscale_min_replicas": 1, 248 | "autoscale_max_replicas": 10, 249 | "autoscale_refresh_seconds": 1, 250 | "autoscale_target_utilization": 70, 251 | "collect_model_data": true, 252 | "auth_enabled": true, 253 | "enable_app_insights": true, 254 | "scoring_timeout_ms": null, 255 | "replica_max_concurrent_requests": null, 256 | "max_request_wait_time": null, 257 | "num_replicas": null, 258 | "gpu_cores": null, 259 | "period_seconds": 10, 260 | "initial_delay_seconds": null, 261 | "timeout_seconds": 1, 262 | "success_threshold": 1, 263 | "failure_threshold": 3, 264 | "namespace": null, 265 | "token_auth_enabled": false, 266 | "primary_key": null, 267 | "secondary_key": null 268 | }, 269 | "prod_deployment": { 270 | "name": "prod-aks", 271 | "autoscale_enabled": true, 272 | "autoscale_min_replicas": 1, 273 | "autoscale_max_replicas": 10, 274 | "autoscale_refresh_seconds": 1, 275 | "autoscale_target_utilization": 70, 276 | "collect_model_data": true, 277 | "auth_enabled": true, 278 | "enable_app_insights": true, 279 | "scoring_timeout_ms": null, 280 | "replica_max_concurrent_requests": null, 281 | "max_request_wait_time": null, 282 | "num_replicas": null, 283 | "gpu_cores": null, 284 | "period_seconds": 10, 285 | "initial_delay_seconds": null, 286 | "timeout_seconds": 1, 287 | "success_threshold": 1, 288 | "failure_threshold": 3, 289 | "namespace": null, 290 | "token_auth_enabled": false, 291 | "primary_key": null, 292 | "secondary_key": null 293 | } 294 | } 295 | } -------------------------------------------------------------------------------- /code/scoring/score.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import pickle, json, time 27 | import numpy as np 28 | from sklearn.externals import joblib 29 | from sklearn.linear_model import Ridge 30 | from azureml.core.model import Model 31 | from azureml.monitoring import ModelDataCollector 32 | #from inference_schema.schema_decorators import input_schema, output_schema 33 | #from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType 34 | 35 | def init(): 36 | global model 37 | print("Model Initialized: " + time.strftime("%H:%M:%S")) 38 | # load the model from file into a global object 39 | model_path = Model.get_model_path(model_name="mymodel") 40 | model = joblib.load(model_path) 41 | print("Initialize Data Collectors") 42 | global inputs_dc, prediction_dc 43 | inputs_dc = ModelDataCollector(model_name="sklearn_regression_model", feature_names=["AGE", "SEX", "BMI", "BP", "S1", "S2", "S3", "S4", "S5", "S6"]) 44 | prediction_dc = ModelDataCollector(model_name="sklearn_regression_model", feature_names=["Y"]) 45 | 46 | #input_sample = np.array([[10.0,9.0,8.0,7.0,6.0,5.0,4.0,3.0,2.0,1.0]]) 47 | #output_sample = np.array([3726.995]) 48 | 49 | #@input_schema('data', NumpyParameterType(input_sample)) 50 | #@output_schema(NumpyParameterType(output_sample)) 51 | def run(raw_data): 52 | global inputs_dc, prediction_dc 53 | try: 54 | data = json.loads(raw_data)["data"] 55 | data = np.array(data) 56 | result = model.predict(data) 57 | 58 | print("Saving Data " + time.strftime("%H:%M:%S")) 59 | inputs_dc.collect(data) 60 | prediction_dc.collect(result) 61 | 62 | return json.dumps({"result": result.tolist()}) 63 | except Exception as e: 64 | error = str(e) 65 | print(error + time.strftime("%H:%M:%S")) 66 | return json.dumps({"error": error}) -------------------------------------------------------------------------------- /code/testing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marvinbuss/MLDevOps/43a4f9b7ab86b0540c206158d35f7bbf910aa6ed/code/testing/__init__.py -------------------------------------------------------------------------------- /code/testing/test_functions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import json 27 | 28 | def get_test_data_sample(): 29 | """ 30 | This function returns a single data sample in json format that can be sent 31 | to the deployed web service for testing purposes. Adjust this function to 32 | return the correct data sample. 33 | """ 34 | test_sample = {'data': [[1,2,3,4,5,6,7,8,9,10]]} 35 | return json.dumps(test_sample) -------------------------------------------------------------------------------- /code/training/train.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) Microsoft Corporation. All rights reserved.​ 3 | ​ 4 | Microsoft Corporation (“Microsoft”) grants you a nonexclusive, perpetual, 5 | royalty-free right to use, copy, and modify the software code provided by us 6 | ("Software Code"). You may not sublicense the Software Code or any use of it 7 | (except to your affiliates and to vendors to perform work on your behalf) 8 | through distribution, network access, service agreement, lease, rental, or 9 | otherwise. This license does not purport to express any claim of ownership over 10 | data you may have shared with Microsoft in the creation of the Software Code. 11 | Unless applicable law gives you more rights, Microsoft reserves all other 12 | rights not expressly granted herein, whether by implication, estoppel or 13 | otherwise. ​ 14 | ​ 15 | THE SOFTWARE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | MICROSOFT OR ITS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE CODE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | """ 26 | import pickle, os 27 | import numpy as np 28 | from azureml.core import Workspace 29 | from azureml.core.run import Run 30 | from sklearn.datasets import load_diabetes 31 | from sklearn.linear_model import Ridge 32 | from sklearn.metrics import mean_squared_error 33 | from sklearn.model_selection import train_test_split 34 | from sklearn.externals import joblib 35 | 36 | RANDOM_STATE = 42 37 | MODEL_NAME = "mymodel.pkl" 38 | 39 | print("Creating output folder") 40 | os.makedirs('./outputs', exist_ok=True) 41 | 42 | print("Getting Run context") 43 | run = Run.get_context() 44 | 45 | print("Loading data") 46 | X, y = load_diabetes(return_X_y=True) 47 | 48 | print("Creating train test split") 49 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=RANDOM_STATE) 50 | data = {"train": {"X": X_train, "y": y_train}, "test": {"X": X_test, "y": y_test}} 51 | 52 | print("Training a ridge regression model with sklearn and random alpha value") 53 | alphas = np.arange(0.0, 1.0, 0.05) 54 | alpha = alphas[np.random.choice(alphas.shape[0], 1, replace=False)][0] 55 | 56 | reg = Ridge(alpha=alpha) 57 | reg.fit(data["train"]["X"], data["train"]["y"]) 58 | preds = reg.predict(data["test"]["X"]) 59 | mse = mean_squared_error(preds, data["test"]["y"]) 60 | print("Alpha is {0:.2f}, and MSE is {1:0.2f}".format(alpha, mse)) 61 | 62 | print("Logging values") 63 | run.log("alpha", alpha) 64 | run.log("mse", mse) 65 | 66 | print("Saving model to output folder") 67 | with open(MODEL_NAME, "wb") as file: 68 | joblib.dump(value=reg, filename=os.path.join("./outputs/", MODEL_NAME)) 69 | 70 | print("Training successfully completed!") 71 | -------------------------------------------------------------------------------- /data/diabetes.csv: -------------------------------------------------------------------------------- 1 | AGE,SEX,BMI,BP,S1,S2,S3,S4,S5,S6,Y 2 | 0.0380759064334241,0.0506801187398187,0.0616962065186885,0.0218723549949558,-0.0442234984244464,-0.0348207628376986,-0.0434008456520269,-0.00259226199818282,0.0199084208763183,-0.0176461251598052,151.0 3 | -0.001882016527791,-0.044641636506989,-0.0514740612388061,-0.0263278347173518,-0.00844872411121698,-0.019163339748222,0.0744115640787594,-0.0394933828740919,-0.0683297436244215,-0.09220404962683,75.0 4 | 0.0852989062966783,0.0506801187398187,0.0444512133365941,-0.00567061055493425,-0.0455994512826475,-0.0341944659141195,-0.0323559322397657,-0.00259226199818282,0.00286377051894013,-0.0259303389894746,141.0 5 | -0.0890629393522603,-0.044641636506989,-0.0115950145052127,-0.0366564467985606,0.0121905687618,0.0249905933641021,-0.0360375700438527,0.0343088588777263,0.0226920225667445,-0.0093619113301358,206.0 6 | 0.00538306037424807,-0.044641636506989,-0.0363846922044735,0.0218723549949558,0.00393485161259318,0.0155961395104161,0.0081420836051921,-0.00259226199818282,-0.0319914449413559,-0.0466408735636482,135.0 7 | -0.0926954778032799,-0.044641636506989,-0.0406959404999971,-0.0194420933298793,-0.0689906498720667,-0.0792878444118122,0.0412768238419757,-0.076394503750001,-0.0411803851880079,-0.0963461565416647,97.0 8 | -0.0454724779400257,0.0506801187398187,-0.0471628129432825,-0.015999222636143,-0.040095639849843,-0.0248000120604336,0.000778807997017968,-0.0394933828740919,-0.0629129499162512,-0.0383566597339788,138.0 9 | 0.063503675590561,0.0506801187398187,-0.00189470584028465,0.0666296740135272,0.0906198816792644,0.108914381123697,0.0228686348215404,0.0177033544835672,-0.0358167281015492,0.00306440941436832,63.0 10 | 0.0417084448844436,0.0506801187398187,0.0616962065186885,-0.0400993174922969,-0.0139525355440215,0.00620168565673016,-0.0286742944356786,-0.00259226199818282,-0.0149564750249113,0.0113486232440377,110.0 11 | -0.0709002470971626,-0.044641636506989,0.0390621529671896,-0.0332135761048244,-0.0125765826858204,-0.034507614375909,-0.0249926566315915,-0.00259226199818282,0.0677363261102861,-0.0135040182449705,310.0 12 | -0.0963280162542995,-0.044641636506989,-0.0838084234552331,0.0081008722200108,-0.103389471327095,-0.0905611890362353,-0.0139477432193303,-0.076394503750001,-0.0629129499162512,-0.0342145528191441,101.0 13 | 0.0271782910803654,0.0506801187398187,0.0175059114895716,-0.0332135761048244,-0.00707277125301585,0.0459715403040008,-0.0654906724765493,0.0712099797536354,-0.096433222891784,-0.0590671943081523,69.0 14 | 0.0162806757273067,-0.044641636506989,-0.0288400076873072,-0.00911348124867051,-0.00432086553661359,-0.00976888589453599,0.0449584616460628,-0.0394933828740919,-0.0307512098645563,-0.0424987666488135,179.0 15 | 0.00538306037424807,0.0506801187398187,-0.00189470584028465,0.0081008722200108,-0.00432086553661359,-0.0157187066685371,-0.0029028298070691,-0.00259226199818282,0.0383932482116977,-0.0135040182449705,185.0 16 | 0.0453409833354632,-0.044641636506989,-0.0256065714656645,-0.0125563519424068,0.0176943801946045,-6.12835790604833e-05,0.0817748396869335,-0.0394933828740919,-0.0319914449413559,-0.0756356219674911,118.0 17 | -0.0527375548420648,0.0506801187398187,-0.0180618869484982,0.0804011567884723,0.0892439288210632,0.107661787276539,-0.0397192078479398,0.108111100629544,0.0360557900898319,-0.0424987666488135,171.0 18 | -0.00551455497881059,-0.044641636506989,0.0422955891888323,0.0494153205448459,0.0245741444856101,-0.0238605666750649,0.0744115640787594,-0.0394933828740919,0.0522799997967812,0.0279170509033766,166.0 19 | 0.0707687524926,0.0506801187398187,0.0121168511201671,0.0563010619323185,0.034205814493018,0.0494161733836856,-0.0397192078479398,0.0343088588777263,0.027367707542609,-0.00107769750046639,144.0 20 | -0.0382074010379866,-0.044641636506989,-0.0105172024313319,-0.0366564467985606,-0.0373437341334407,-0.0194764882100115,-0.0286742944356786,-0.00259226199818282,-0.0181182673078967,-0.0176461251598052,97.0 21 | -0.0273097856849279,-0.044641636506989,-0.0180618869484982,-0.0400993174922969,-0.00294491267841247,-0.0113346282034837,0.0375951860378887,-0.0394933828740919,-0.0089440189577978,-0.0549250873933176,168.0 22 | -0.0491050163910452,-0.044641636506989,-0.0568631216082106,-0.0435421881860331,-0.0455994512826475,-0.043275771306016,0.000778807997017968,-0.0394933828740919,-0.0119006848015081,0.0154907301588724,68.0 23 | -0.0854304009012408,0.0506801187398187,-0.0223731352440218,0.00121513083253827,-0.0373437341334407,-0.0263657543693812,0.0155053592133662,-0.0394933828740919,-0.072128454601956,-0.0176461251598052,49.0 24 | -0.0854304009012408,-0.044641636506989,-0.00405032998804645,-0.00911348124867051,-0.00294491267841247,0.00776742796567782,0.0228686348215404,-0.0394933828740919,-0.0611765950943345,-0.0135040182449705,68.0 25 | 0.0453409833354632,0.0506801187398187,0.0606183944448076,0.0310533436263482,0.0287020030602135,-0.0473467013092799,-0.0544457590642881,0.0712099797536354,0.133598980013008,0.135611830689079,245.0 26 | -0.0636351701951234,-0.044641636506989,0.0358287167455469,-0.0228849640236156,-0.0304639698424351,-0.0188501912864324,-0.00658446761115617,-0.00259226199818282,-0.0259524244351894,-0.0549250873933176,184.0 27 | -0.067267708646143,0.0506801187398187,-0.0126728265790937,-0.0400993174922969,-0.0153284884022226,0.0046359433477825,-0.0581273968683752,0.0343088588777263,0.0191990330785671,-0.0342145528191441,202.0 28 | -0.107225631607358,-0.044641636506989,-0.0773415510119477,-0.0263278347173518,-0.0896299427450836,-0.0961978613484469,0.0265502726256275,-0.076394503750001,-0.0425721049227942,-0.0052198044153011,137.0 29 | -0.0236772472339084,-0.044641636506989,0.0595405823709267,-0.0400993174922969,-0.0428475455662452,-0.0435889197678055,0.0118237214092792,-0.0394933828740919,-0.0159982677581387,0.0403433716478807,85.0 30 | 0.0526060602375023,-0.044641636506989,-0.0212953231701409,-0.0745280244296595,-0.040095639849843,-0.0376390989938044,-0.00658446761115617,-0.0394933828740919,-0.000609254186102297,-0.0549250873933176,131.0 31 | 0.0671362140415805,0.0506801187398187,-0.00620595413580824,0.063186803319791,-0.0428475455662452,-0.0958847128866574,0.052321737254237,-0.076394503750001,0.0594238004447941,0.0527696923923848,283.0 32 | -0.0600026317441039,-0.044641636506989,0.0444512133365941,-0.0194420933298793,-0.00982467696941811,-0.00757684666200928,0.0228686348215404,-0.0394933828740919,-0.0271286455543265,-0.0093619113301358,129.0 33 | -0.0236772472339084,-0.044641636506989,-0.0654856181992578,-0.081413765817132,-0.0387196869916418,-0.0536096705450705,0.0596850128624111,-0.076394503750001,-0.0371283460104736,-0.0424987666488135,59.0 34 | 0.0344433679824045,0.0506801187398187,0.125287118877662,0.0287580963824284,-0.0538551684318543,-0.0129003705124313,-0.10230705051742,0.108111100629544,0.000271485727907132,0.0279170509033766,341.0 35 | 0.030810829531385,-0.044641636506989,-0.0503962491649252,-0.00222773986119799,-0.0442234984244464,-0.0899348921126563,0.118591217727804,-0.076394503750001,-0.0181182673078967,0.00306440941436832,87.0 36 | 0.0162806757273067,-0.044641636506989,-0.063329994051496,-0.0573136709609782,-0.0579830270064577,-0.0489124436182275,0.0081420836051921,-0.0394933828740919,-0.0594726974107223,-0.0673514081378217,65.0 37 | 0.0489735217864827,0.0506801187398187,-0.030995631835069,-0.0492803060204031,0.0493412959332305,-0.00413221358232442,0.133317768944152,-0.0535158088069373,0.0213108465682448,0.0196328370737072,102.0 38 | 0.0126481372762872,-0.044641636506989,0.0228949718589761,0.0528581912385822,0.00806271018719657,-0.0285577936019079,0.0375951860378887,-0.0394933828740919,0.0547240033481791,-0.0259303389894746,265.0 39 | -0.00914709342983014,-0.044641636506989,0.0110390390462862,-0.0573136709609782,-0.0249601584096305,-0.0429626228442264,0.0302319104297145,-0.0394933828740919,0.01703713241478,-0.0052198044153011,276.0 40 | -0.00188201652779104,0.0506801187398187,0.0713965151836166,0.0976155102571536,0.0878679759628621,0.0754074957122168,-0.0213110188275045,0.0712099797536354,0.0714240327805764,0.0237749439885419,252.0 41 | -0.00188201652779104,0.0506801187398187,0.0142724752679289,-0.0745280244296595,0.00255889875439205,0.00620168565673016,-0.0139477432193303,-0.00259226199818282,0.0191990330785671,0.00306440941436832,90.0 42 | 0.00538306037424807,0.0506801187398187,-0.00836157828357004,0.0218723549949558,0.054845107366035,0.07321545647969,-0.0249926566315915,0.0343088588777263,0.0125531528133893,0.094190761540732,100.0 43 | -0.099960554705319,-0.044641636506989,-0.0676412423470196,-0.108956731367022,-0.0744944613048712,-0.072711726714232,0.0155053592133662,-0.0394933828740919,-0.0498684677352306,-0.0093619113301358,55.0 44 | -0.0600026317441039,0.0506801187398187,-0.0105172024313319,-0.0148515990830405,-0.0497273098572509,-0.0235474182132754,-0.0581273968683752,0.0158582984397717,-0.00991895736315477,-0.0342145528191441,61.0 45 | 0.0199132141783263,-0.044641636506989,-0.0234509473179027,-0.0710851537359232,0.0204462859110067,-0.0100820343563255,0.118591217727804,-0.076394503750001,-0.0425721049227942,0.0734802269665584,92.0 46 | 0.0453409833354632,0.0506801187398187,0.068163078961974,0.0081008722200108,-0.0167044412604238,0.0046359433477825,-0.0765355858888105,0.0712099797536354,0.0324332257796019,-0.0176461251598052,259.0 47 | 0.0271782910803654,0.0506801187398187,-0.0353068801305926,0.0322009670761646,-0.0112006298276192,0.00150445872988718,-0.0102661054152432,-0.00259226199818282,-0.0149564750249113,-0.0507829804784829,53.0 48 | -0.0563700932930843,-0.044641636506989,-0.0115950145052127,-0.0332135761048244,-0.0469754041408486,-0.0476598497710694,0.00446044580110504,-0.0394933828740919,-0.00797939755454164,-0.0880619427119953,190.0 49 | -0.0781653239992017,-0.044641636506989,-0.0730303027164241,-0.0573136709609782,-0.0841261313122791,-0.0742774690231797,-0.0249926566315915,-0.0394933828740919,-0.0181182673078967,-0.0839198357971606,142.0 50 | 0.0671362140415805,0.0506801187398187,-0.041773752573878,0.0115437429137471,0.00255889875439205,0.00588853719494063,0.0412768238419757,-0.0394933828740919,-0.0594726974107223,-0.0217882320746399,75.0 51 | -0.0418399394890061,0.0506801187398187,0.0142724752679289,-0.00567061055493425,-0.0125765826858204,0.00620168565673016,-0.0728539480847234,0.0712099797536354,0.0354619386607697,-0.0135040182449705,142.0 52 | 0.0344433679824045,-0.044641636506989,-0.00728376620968916,0.0149866136074833,-0.0442234984244464,-0.0373259505320149,-0.0029028298070691,-0.0394933828740919,-0.02139368094036,0.00720651632920303,155.0 53 | 0.0598711371395414,0.0506801187398187,0.0164280994156907,0.0287580963824284,-0.0414715927080441,-0.029184090525487,-0.0286742944356786,-0.00259226199818282,-0.00239668149341427,-0.0217882320746399,225.0 54 | -0.0527375548420648,-0.044641636506989,-0.00943939035745095,-0.00567061055493425,0.0397096259258226,0.0447189464568426,0.0265502726256275,-0.00259226199818282,-0.0181182673078967,-0.0135040182449705,59.0 55 | -0.00914709342983014,-0.044641636506989,-0.0159062628007364,0.0700725447072635,0.0121905687618,0.0221722572079963,0.0155053592133662,-0.00259226199818282,-0.0332487872476258,0.0486275854775501,104.0 56 | -0.0491050163910452,-0.044641636506989,0.0250505960067379,0.0081008722200108,0.0204462859110067,0.0177881787429428,0.052321737254237,-0.0394933828740919,-0.0411803851880079,0.00720651632920303,182.0 57 | -0.0418399394890061,-0.044641636506989,-0.0493184370910443,-0.0366564467985606,-0.00707277125301585,-0.0226079728279068,0.0854564774910206,-0.0394933828740919,-0.0664881482228354,0.00720651632920303,128.0 58 | -0.0418399394890061,-0.044641636506989,0.0412177771149514,-0.0263278347173518,-0.0318399227006362,-0.0304366843726451,-0.0360375700438527,0.00294290613320356,0.0336568129023847,-0.0176461251598052,52.0 59 | -0.0273097856849279,-0.044641636506989,-0.063329994051496,-0.0504279295735057,-0.0896299427450836,-0.104339721354975,0.052321737254237,-0.076394503750001,-0.0561575730950062,-0.0673514081378217,37.0 60 | 0.0417084448844436,-0.044641636506989,-0.064407806125377,0.0356438377699009,0.0121905687618,-0.057993749010124,0.181179060397284,-0.076394503750001,-0.000609254186102297,-0.0507829804784829,170.0 61 | 0.063503675590561,0.0506801187398187,-0.0256065714656645,0.0115437429137471,0.0644767773734429,0.048476727998317,0.0302319104297145,-0.00259226199818282,0.0383932482116977,0.0196328370737072,170.0 62 | -0.0709002470971626,-0.044641636506989,-0.00405032998804645,-0.0400993174922969,-0.0662387441556644,-0.0786615474882331,0.052321737254237,-0.076394503750001,-0.0514005352605825,-0.0342145528191441,61.0 63 | -0.0418399394890061,0.0506801187398187,0.00457216660300077,-0.0538708002672419,-0.0442234984244464,-0.0273051997547498,-0.0802172236928976,0.0712099797536354,0.0366457977933988,0.0196328370737072,144.0 64 | -0.0273097856849279,0.0506801187398187,-0.00728376620968916,-0.0400993174922969,-0.0112006298276192,-0.0138398158977999,0.0596850128624111,-0.0394933828740919,-0.0823814832581028,-0.0259303389894746,52.0 65 | -0.034574862586967,-0.044641636506989,-0.0374625042783544,-0.0607565416547144,0.0204462859110067,0.0434663526096845,-0.0139477432193303,-0.00259226199818282,-0.0307512098645563,-0.0714935150526564,128.0 66 | 0.0671362140415805,0.0506801187398187,-0.0256065714656645,-0.0400993174922969,-0.0634868384392622,-0.0598726397808612,-0.0029028298070691,-0.0394933828740919,-0.0191970476139445,0.0113486232440377,71.0 67 | -0.0454724779400257,0.0506801187398187,-0.0245287593917836,0.0597439326260547,0.00531080447079431,0.0149698425868371,-0.0544457590642881,0.0712099797536354,0.0423448954496075,0.0154907301588724,163.0 68 | -0.00914709342983014,0.0506801187398187,-0.0180618869484982,-0.0332135761048244,-0.0208322998350272,0.0121515064307313,-0.0728539480847234,0.0712099797536354,0.000271485727907132,0.0196328370737072,150.0 69 | 0.0417084448844436,0.0506801187398187,-0.0148284507268555,-0.0171468461892456,-0.00569681839481472,0.00839372488925688,-0.0139477432193303,-0.00185423958066465,-0.0119006848015081,0.00306440941436832,97.0 70 | 0.0380759064334241,0.0506801187398187,-0.0299178197611881,-0.0400993174922969,-0.0332158755588373,-0.0241737151368545,-0.0102661054152432,-0.00259226199818282,-0.0129079422541688,0.00306440941436832,160.0 71 | 0.0162806757273067,-0.044641636506989,-0.0460850008694016,-0.00567061055493425,-0.0758704141630723,-0.0614383820898088,-0.0139477432193303,-0.0394933828740919,-0.0514005352605825,0.0196328370737072,178.0 72 | -0.00188201652779104,-0.044641636506989,-0.0697968664947814,-0.0125563519424068,-0.000193006962010205,-0.00914258897095694,0.0707299262746723,-0.0394933828740919,-0.0629129499162512,0.0403433716478807,48.0 73 | -0.00188201652779104,-0.044641636506989,0.0336730925977851,0.125158475807044,0.0245741444856101,0.0262431872112602,-0.0102661054152432,-0.00259226199818282,0.0267142576335128,0.0610539062220542,270.0 74 | 0.063503675590561,0.0506801187398187,-0.00405032998804645,-0.0125563519424068,0.103003457403075,0.0487898764601065,0.056003375058324,-0.00259226199818282,0.0844952822124031,-0.0176461251598052,202.0 75 | 0.0126481372762872,0.0506801187398187,-0.02021751109626,-0.00222773986119799,0.0383336730676214,0.05317395492516,-0.00658446761115617,0.0343088588777263,-0.00514530798026311,-0.0093619113301358,111.0 76 | 0.0126481372762872,0.0506801187398187,0.00241654245523897,0.0563010619323185,0.0273260502020124,0.0171618818193638,0.0412768238419757,-0.0394933828740919,0.00371173823343597,0.0734802269665584,85.0 77 | -0.00914709342983014,0.0506801187398187,-0.030995631835069,-0.0263278347173518,-0.0112006298276192,-0.00100072896442909,-0.0213110188275045,-0.00259226199818282,0.0062093156165054,0.0279170509033766,42.0 78 | -0.0309423241359475,0.0506801187398187,0.0282840322283806,0.0700725447072635,-0.126780669916514,-0.106844909049291,-0.0544457590642881,-0.047980640675551,-0.0307512098645563,0.0154907301588724,170.0 79 | -0.0963280162542995,-0.044641636506989,-0.0363846922044735,-0.0745280244296595,-0.0387196869916418,-0.0276183482165393,0.0155053592133662,-0.0394933828740919,-0.0740888714915354,-0.00107769750046639,200.0 80 | 0.00538306037424807,-0.044641636506989,-0.0579409336820915,-0.0228849640236156,-0.0676146970138656,-0.0683276482491785,-0.0544457590642881,-0.00259226199818282,0.0428956878925287,-0.0839198357971606,252.0 81 | -0.103593093156339,-0.044641636506989,-0.0374625042783544,-0.0263278347173518,0.00255889875439205,0.0199802179754696,0.0118237214092792,-0.00259226199818282,-0.0683297436244215,-0.0259303389894746,113.0 82 | 0.0707687524926,-0.044641636506989,0.0121168511201671,0.0425295791573734,0.0713565416644485,0.0534871033869495,0.052321737254237,-0.00259226199818282,0.0253931349154494,-0.0052198044153011,143.0 83 | 0.0126481372762872,0.0506801187398187,-0.0223731352440218,-0.0297707054110881,0.0108146159035988,0.0284352264437869,-0.0213110188275045,0.0343088588777263,-0.00608024819631442,-0.00107769750046639,51.0 84 | -0.0164121703318693,-0.044641636506989,-0.0353068801305926,-0.0263278347173518,0.0328298616348169,0.0171618818193638,0.100183028707369,-0.0394933828740919,-0.0702093127286876,-0.0797777288823259,52.0 85 | -0.0382074010379866,-0.044641636506989,0.00996122697240527,-0.0469850588797694,-0.0593589798646588,-0.0529833736214915,-0.0102661054152432,-0.0394933828740919,-0.0159982677581387,-0.0424987666488135,210.0 86 | 0.00175052192322852,-0.044641636506989,-0.0396181284261162,-0.100923366426447,-0.0290880169842339,-0.0301235359108556,0.0449584616460628,-0.0501947079281055,-0.0683297436244215,-0.129483011860342,65.0 87 | 0.0453409833354632,-0.044641636506989,0.0713965151836166,0.00121513083253827,-0.00982467696941811,-0.00100072896442909,0.0155053592133662,-0.0394933828740919,-0.0411803851880079,-0.0714935150526564,141.0 88 | -0.0709002470971626,0.0506801187398187,-0.0751859268641859,-0.0400993174922969,-0.051103262715452,-0.015092409744958,-0.0397192078479398,-0.00259226199818282,-0.096433222891784,-0.0342145528191441,55.0 89 | 0.0453409833354632,-0.044641636506989,-0.00620595413580824,0.0115437429137471,0.0631008245152418,0.0162224364339952,0.0965013909032818,-0.0394933828740919,0.0428956878925287,-0.0383566597339788,134.0 90 | -0.0527375548420648,0.0506801187398187,-0.0406959404999971,-0.067642283042187,-0.0318399227006362,-0.0370128020702253,0.0375951860378887,-0.0394933828740919,-0.0345237153303495,0.0693381200517237,42.0 91 | -0.0454724779400257,-0.044641636506989,-0.0482406250171634,-0.0194420933298793,-0.000193006962010205,-0.0160318551303266,0.0670482884705852,-0.0394933828740919,-0.0247911874324607,0.0196328370737072,111.0 92 | 0.0126481372762872,-0.044641636506989,-0.0256065714656645,-0.0400993174922969,-0.0304639698424351,-0.0451546620767532,0.0780932018828464,-0.076394503750001,-0.072128454601956,0.0113486232440377,98.0 93 | 0.0453409833354632,-0.044641636506989,0.0519958978537604,-0.0538708002672419,0.0631008245152418,0.0647604480113727,-0.0102661054152432,0.0343088588777263,0.0372320112089689,0.0196328370737072,164.0 94 | -0.0200447087828888,-0.044641636506989,0.00457216660300077,0.0976155102571536,0.00531080447079431,-0.0207290820571696,0.0633666506664982,-0.0394933828740919,0.0125531528133893,0.0113486232440377,48.0 95 | -0.0491050163910452,-0.044641636506989,-0.064407806125377,-0.10207098997955,-0.00294491267841247,-0.0154055582067476,0.0633666506664982,-0.0472426182580328,-0.0332487872476258,-0.0549250873933176,96.0 96 | -0.0781653239992017,-0.044641636506989,-0.0169840748746173,-0.0125563519424068,-0.000193006962010205,-0.0135266674360104,0.0707299262746723,-0.0394933828740919,-0.0411803851880079,-0.09220404962683,90.0 97 | -0.0709002470971626,-0.044641636506989,-0.0579409336820915,-0.081413765817132,-0.0455994512826475,-0.0288709420636975,-0.0434008456520269,-0.00259226199818282,0.00114379737951254,-0.0052198044153011,162.0 98 | 0.0562385986885218,0.0506801187398187,0.00996122697240527,0.0494153205448459,-0.00432086553661359,-0.0122740735888523,-0.0434008456520269,0.0343088588777263,0.060787754150744,0.0320591578182113,150.0 99 | -0.0273097856849279,-0.044641636506989,0.088641508365711,-0.0251802111642493,0.0218222387692079,0.0425269072243159,-0.0323559322397657,0.0343088588777263,0.00286377051894013,0.0776223338813931,279.0 100 | 0.00175052192322852,0.0506801187398187,-0.00512814206192736,-0.0125563519424068,-0.0153284884022226,-0.0138398158977999,0.0081420836051921,-0.0394933828740919,-0.00608024819631442,-0.0673514081378217,92.0 101 | -0.00188201652779104,-0.044641636506989,-0.064407806125377,0.0115437429137471,0.0273260502020124,0.0375165318356834,-0.0139477432193303,0.0343088588777263,0.0117839003835759,-0.0549250873933176,83.0 102 | 0.0162806757273067,-0.044641636506989,0.0175059114895716,-0.0228849640236156,0.0603489187988395,0.0444057979950531,0.0302319104297145,-0.00259226199818282,0.0372320112089689,-0.00107769750046639,128.0 103 | 0.0162806757273067,0.0506801187398187,-0.0450071887955207,0.063186803319791,0.0108146159035988,-0.00037443204085002,0.0633666506664982,-0.0394933828740919,-0.0307512098645563,0.036201264733046,102.0 104 | -0.0926954778032799,-0.044641636506989,0.0282840322283806,-0.015999222636143,0.0369577202094203,0.0249905933641021,0.056003375058324,-0.0394933828740919,-0.00514530798026311,-0.00107769750046639,302.0 105 | 0.0598711371395414,0.0506801187398187,0.0412177771149514,0.0115437429137471,0.0410855787840237,0.0707102687853738,-0.0360375700438527,0.0343088588777263,-0.0109044358473771,-0.0300724459043093,198.0 106 | -0.0273097856849279,-0.044641636506989,0.0649296427403312,-0.00222773986119799,-0.0249601584096305,-0.0172844489774848,0.0228686348215404,-0.0394933828740919,-0.0611765950943345,-0.063209301222987,95.0 107 | 0.0235457526293458,0.0506801187398187,-0.0320734439089499,-0.0400993174922969,-0.0318399227006362,-0.0216685274425382,-0.0139477432193303,-0.00259226199818282,-0.0109044358473771,0.0196328370737072,53.0 108 | -0.0963280162542995,-0.044641636506989,-0.0762637389380668,-0.0435421881860331,-0.0455994512826475,-0.0348207628376986,0.0081420836051921,-0.0394933828740919,-0.0594726974107223,-0.0839198357971606,134.0 109 | 0.0271782910803654,-0.044641636506989,0.0498402737059986,-0.0550184238203444,-0.00294491267841247,0.0406480164535787,-0.0581273968683752,0.0527594193156808,-0.0529587932392004,-0.0052198044153011,144.0 110 | 0.0199132141783263,0.0506801187398187,0.045529025410475,0.0299057198322448,-0.062110885581061,-0.0558017097775973,-0.0728539480847234,0.0269286347025444,0.0456008084141249,0.0403433716478807,232.0 111 | 0.0380759064334241,0.0506801187398187,-0.00943939035745095,0.0023627543856408,0.00118294589619092,0.0375165318356834,-0.0544457590642881,0.0501763408543672,-0.0259524244351894,0.106617082285236,81.0 112 | 0.0417084448844436,0.0506801187398187,-0.0320734439089499,-0.0228849640236156,-0.0497273098572509,-0.0401442866881206,0.0302319104297145,-0.0394933828740919,-0.126097385560409,0.0154907301588724,104.0 113 | 0.0199132141783263,-0.044641636506989,0.00457216660300077,-0.0263278347173518,0.023198191627409,0.0102726156599941,0.0670482884705852,-0.0394933828740919,-0.0236445575721341,-0.0466408735636482,59.0 114 | -0.0854304009012408,-0.044641636506989,0.0207393477112143,-0.0263278347173518,0.00531080447079431,0.01966706951368,-0.0029028298070691,-0.00259226199818282,-0.0236445575721341,0.00306440941436832,246.0 115 | 0.0199132141783263,0.0506801187398187,0.0142724752679289,0.063186803319791,0.0149424744782022,0.0202933664372591,-0.0470824834561139,0.0343088588777263,0.0466607723568145,0.0900486546258972,297.0 116 | 0.0235457526293458,-0.044641636506989,0.110197749843329,0.063186803319791,0.0135665216200011,-0.0329418720669614,-0.0249926566315915,0.0206554441536399,0.09924022573399,0.0237749439885419,258.0 117 | -0.0309423241359475,0.0506801187398187,0.00133873038135806,-0.00567061055493425,0.0644767773734429,0.0494161733836856,-0.0470824834561139,0.108111100629544,0.0837967663655224,0.00306440941436832,229.0 118 | 0.0489735217864827,0.0506801187398187,0.0584627702970458,0.0700725447072635,0.0135665216200011,0.0206065148990486,-0.0213110188275045,0.0343088588777263,0.0220040504561505,0.0279170509033766,275.0 119 | 0.0598711371395414,-0.044641636506989,-0.0212953231701409,0.0872868981759448,0.0452134373586271,0.0315667110616823,-0.0470824834561139,0.0712099797536354,0.0791210813896579,0.135611830689079,281.0 120 | -0.0563700932930843,0.0506801187398187,-0.0105172024313319,0.0253152256886921,0.023198191627409,0.0400217195299996,-0.0397192078479398,0.0343088588777263,0.0206123307213641,0.0569117993072195,179.0 121 | 0.0162806757273067,-0.044641636506989,-0.0471628129432825,-0.00222773986119799,-0.019456346976826,-0.0429626228442264,0.0339135482338016,-0.0394933828740919,0.027367707542609,0.0279170509033766,200.0 122 | -0.0491050163910452,-0.044641636506989,0.00457216660300077,0.0115437429137471,-0.0373437341334407,-0.0185370428246429,-0.0176293810234174,-0.00259226199818282,-0.0398095943643375,-0.0217882320746399,200.0 123 | 0.063503675590561,-0.044641636506989,0.0175059114895716,0.0218723549949558,0.00806271018719657,0.0215459602844172,-0.0360375700438527,0.0343088588777263,0.0199084208763183,0.0113486232440377,173.0 124 | 0.0489735217864827,0.0506801187398187,0.0810968238485447,0.0218723549949558,0.0438374845004259,0.0641341510877936,-0.0544457590642881,0.0712099797536354,0.0324332257796019,0.0486275854775501,180.0 125 | 0.00538306037424807,0.0506801187398187,0.034750904671666,-0.00108011630809546,0.152537760298315,0.198787989657293,-0.0618090346724622,0.185234443260194,0.0155668445407018,0.0734802269665584,84.0 126 | -0.00551455497881059,-0.044641636506989,0.023972783932857,0.0081008722200108,-0.0345918284170385,-0.0388916928409625,0.0228686348215404,-0.0394933828740919,-0.0159982677581387,-0.0135040182449705,121.0 127 | -0.00551455497881059,0.0506801187398187,-0.00836157828357004,-0.00222773986119799,-0.0332158755588373,-0.0636304213223356,-0.0360375700438527,-0.00259226199818282,0.0805854642386665,0.00720651632920303,161.0 128 | -0.0890629393522603,-0.044641636506989,-0.0611743699037342,-0.0263278347173518,-0.0552311212900554,-0.0545491159304391,0.0412768238419757,-0.076394503750001,-0.0939356455087147,-0.0549250873933176,99.0 129 | 0.0344433679824045,0.0506801187398187,-0.00189470584028465,-0.0125563519424068,0.0383336730676214,0.0137172487396789,0.0780932018828464,-0.0394933828740919,0.00455189046612778,-0.0963461565416647,109.0 130 | -0.0527375548420648,-0.044641636506989,-0.0622521819776151,-0.0263278347173518,-0.00569681839481472,-0.005071658967693,0.0302319104297145,-0.0394933828740919,-0.0307512098645563,-0.0714935150526564,115.0 131 | 0.00901559882526763,-0.044641636506989,0.0164280994156907,0.00465800152627453,0.0094386630453977,0.0105857641217836,-0.0286742944356786,0.0343088588777263,0.0389683660308856,0.11904340302974,268.0 132 | -0.0636351701951234,0.0506801187398187,0.0961861928828773,0.104501251644626,-0.00294491267841247,-0.00475851050590347,-0.00658446761115617,-0.00259226199818282,0.0226920225667445,0.0734802269665584,274.0 133 | -0.0963280162542995,-0.044641636506989,-0.0697968664947814,-0.067642283042187,-0.019456346976826,-0.0107083312799046,0.0155053592133662,-0.0394933828740919,-0.0468794828442166,-0.0797777288823259,158.0 134 | 0.0162806757273067,0.0506801187398187,-0.0212953231701409,-0.00911348124867051,0.034205814493018,0.047850431074738,0.000778807997017968,-0.00259226199818282,-0.0129079422541688,0.0237749439885419,107.0 135 | -0.0418399394890061,0.0506801187398187,-0.0536296853865679,-0.0400993174922969,-0.0841261313122791,-0.0717722813288634,-0.0029028298070691,-0.0394933828740919,-0.072128454601956,-0.0300724459043093,83.0 136 | -0.0745327855481821,-0.044641636506989,0.0433734012627132,-0.0332135761048244,0.0121905687618,0.000251864882729031,0.0633666506664982,-0.0394933828740919,-0.0271286455543265,-0.0466408735636482,103.0 137 | -0.00551455497881059,-0.044641636506989,0.056307146149284,-0.0366564467985606,-0.0483513569990498,-0.0429626228442264,-0.0728539480847234,0.0379989709653172,0.0507815133629732,0.0569117993072195,272.0 138 | -0.0926954778032799,-0.044641636506989,-0.0816527993074713,-0.0573136709609782,-0.0607349327228599,-0.068014499787389,0.0486400994501499,-0.076394503750001,-0.0664881482228354,-0.0217882320746399,85.0 139 | 0.00538306037424807,-0.044641636506989,0.0498402737059986,0.0976155102571536,-0.0153284884022226,-0.0163450035921162,-0.00658446761115617,-0.00259226199818282,0.01703713241478,-0.0135040182449705,280.0 140 | 0.0344433679824045,0.0506801187398187,0.11127556191721,0.076958286094736,-0.0318399227006362,-0.03388131745233,-0.0213110188275045,-0.00259226199818282,0.028016506523264,0.0734802269665584,336.0 141 | 0.0235457526293458,-0.044641636506989,0.0616962065186885,0.0528581912385822,-0.0345918284170385,-0.0489124436182275,-0.0286742944356786,-0.00259226199818282,0.0547240033481791,-0.0052198044153011,281.0 142 | 0.0417084448844436,0.0506801187398187,0.0142724752679289,0.0425295791573734,-0.0304639698424351,-0.00131387742621863,-0.0434008456520269,-0.00259226199818282,-0.0332487872476258,0.0154907301588724,118.0 143 | -0.0273097856849279,-0.044641636506989,0.0476846495582368,-0.0469850588797694,0.034205814493018,0.0572448849284239,-0.0802172236928976,0.13025177315509,0.0450661683362615,0.131469723774244,317.0 144 | 0.0417084448844436,0.0506801187398187,0.0121168511201671,0.0390867084636372,0.054845107366035,0.0444057979950531,0.00446044580110504,-0.00259226199818282,0.0456008084141249,-0.00107769750046639,235.0 145 | -0.0309423241359475,-0.044641636506989,0.00564997867688165,-0.00911348124867051,0.0190703330528056,0.00682798258030921,0.0744115640787594,-0.0394933828740919,-0.0411803851880079,-0.0424987666488135,60.0 146 | 0.030810829531385,0.0506801187398187,0.0466068374843559,-0.015999222636143,0.0204462859110067,0.0506687672308438,-0.0581273968683752,0.0712099797536354,0.0062093156165054,0.00720651632920303,174.0 147 | -0.0418399394890061,-0.044641636506989,0.128520555099304,0.063186803319791,-0.0332158755588373,-0.0326287236051719,0.0118237214092792,-0.0394933828740919,-0.0159982677581387,-0.0507829804784829,259.0 148 | -0.0309423241359475,0.0506801187398187,0.0595405823709267,0.00121513083253827,0.0121905687618,0.0315667110616823,-0.0434008456520269,0.0343088588777263,0.0148227108412663,0.00720651632920303,178.0 149 | -0.0563700932930843,-0.044641636506989,0.0929527566612346,-0.0194420933298793,0.0149424744782022,0.0234248510551544,-0.0286742944356786,0.0254525898675081,0.0260560896336847,0.0403433716478807,128.0 150 | -0.0600026317441039,0.0506801187398187,0.0153502873418098,-0.0194420933298793,0.0369577202094203,0.0481635795365275,0.0191869970174533,-0.00259226199818282,-0.0307512098645563,-0.00107769750046639,96.0 151 | -0.0491050163910452,0.0506801187398187,-0.00512814206192736,-0.0469850588797694,-0.0208322998350272,-0.0204159335953801,-0.0691723102806364,0.0712099797536354,0.061237907519701,-0.0383566597339788,126.0 152 | 0.0235457526293458,-0.044641636506989,0.0703187031097357,0.0253152256886921,-0.0345918284170385,-0.014466112821379,-0.0323559322397657,-0.00259226199818282,-0.0191970476139445,-0.0093619113301358,288.0 153 | 0.00175052192322852,-0.044641636506989,-0.00405032998804645,-0.00567061055493425,-0.00844872411121698,-0.0238605666750649,0.052321737254237,-0.0394933828740919,-0.0089440189577978,-0.0135040182449705,88.0 154 | -0.034574862586967,0.0506801187398187,-0.000816893766403737,0.0700725447072635,0.0397096259258226,0.0669524872438994,-0.0654906724765493,0.108111100629544,0.0267142576335128,0.0734802269665584,292.0 155 | 0.0417084448844436,0.0506801187398187,-0.0439293767216398,0.063186803319791,-0.00432086553661359,0.0162224364339952,-0.0139477432193303,-0.00259226199818282,-0.0345237153303495,0.0113486232440377,71.0 156 | 0.0671362140415805,0.0506801187398187,0.0207393477112143,-0.00567061055493425,0.0204462859110067,0.0262431872112602,-0.0029028298070691,-0.00259226199818282,0.00864028293306308,0.00306440941436832,197.0 157 | -0.0273097856849279,0.0506801187398187,0.0606183944448076,0.0494153205448459,0.0851160702464598,0.0863676918748504,-0.0029028298070691,0.0343088588777263,0.0378144788263439,0.0486275854775501,186.0 158 | -0.0164121703318693,-0.044641636506989,-0.0105172024313319,0.00121513083253827,-0.0373437341334407,-0.0357602082230672,0.0118237214092792,-0.0394933828740919,-0.02139368094036,-0.0342145528191441,25.0 159 | -0.00188201652779104,0.0506801187398187,-0.0331512559828308,-0.0182944697767768,0.0314539087766158,0.0428400556861055,-0.0139477432193303,0.0199174217361217,0.0102256424049578,0.0279170509033766,84.0 160 | -0.0127796318808497,-0.044641636506989,-0.0654856181992578,-0.0699375301828207,0.00118294589619092,0.0168487333575743,-0.0029028298070691,-0.00702039650329191,-0.0307512098645563,-0.0507829804784829,96.0 161 | -0.00551455497881059,-0.044641636506989,0.0433734012627132,0.0872868981759448,0.0135665216200011,0.00714113104209875,-0.0139477432193303,-0.00259226199818282,0.0423448954496075,-0.0176461251598052,195.0 162 | -0.00914709342983014,-0.044641636506989,-0.0622521819776151,-0.0745280244296595,-0.0235842055514294,-0.0132135189742209,0.00446044580110504,-0.0394933828740919,-0.0358167281015492,-0.0466408735636482,53.0 163 | -0.0454724779400257,0.0506801187398187,0.0638518306664503,0.0700725447072635,0.133274420283499,0.131461070372543,-0.0397192078479398,0.108111100629544,0.0757375884575476,0.0859065477110625,217.0 164 | -0.0527375548420648,-0.044641636506989,0.0304396563761424,-0.0745280244296595,-0.0235842055514294,-0.0113346282034837,-0.0029028298070691,-0.00259226199818282,-0.0307512098645563,-0.00107769750046639,172.0 165 | 0.0162806757273067,0.0506801187398187,0.0724743272574975,0.076958286094736,-0.00844872411121698,0.00557538873315109,-0.00658446761115617,-0.00259226199818282,-0.0236445575721341,0.0610539062220542,131.0 166 | 0.0453409833354632,-0.044641636506989,-0.019139699022379,0.0218723549949558,0.0273260502020124,-0.0135266674360104,0.100183028707369,-0.0394933828740919,0.0177634778671173,-0.0135040182449705,214.0 167 | -0.0418399394890061,-0.044641636506989,-0.0665634302731387,-0.0469850588797694,-0.0373437341334407,-0.043275771306016,0.0486400994501499,-0.0394933828740919,-0.0561575730950062,-0.0135040182449705,59.0 168 | -0.0563700932930843,0.0506801187398187,-0.0600965578298533,-0.0366564467985606,-0.0882539898868825,-0.0708328359434948,-0.0139477432193303,-0.0394933828740919,-0.0781409106690696,-0.104630370371334,70.0 169 | 0.0707687524926,-0.044641636506989,0.0692408910358548,0.0379390850138207,0.0218222387692079,0.00150445872988718,-0.0360375700438527,0.0391060045915944,0.0776327891955595,0.106617082285236,220.0 170 | 0.00175052192322852,0.0506801187398187,0.0595405823709267,-0.00222773986119799,0.0617248716570406,0.063194705702425,-0.0581273968683752,0.108111100629544,0.0689822116363026,0.12732761685941,268.0 171 | -0.00188201652779104,-0.044641636506989,-0.0266843835395454,0.0494153205448459,0.0589729659406384,-0.0160318551303266,-0.0470824834561139,0.0712099797536354,0.133598980013008,0.0196328370737072,152.0 172 | 0.0235457526293458,0.0506801187398187,-0.02021751109626,-0.0366564467985606,-0.0139525355440215,-0.015092409744958,0.0596850128624111,-0.0394933828740919,-0.096433222891784,-0.0176461251598052,47.0 173 | -0.0200447087828888,-0.044641636506989,-0.0460850008694016,-0.0986281192858133,-0.0758704141630723,-0.0598726397808612,-0.0176293810234174,-0.0394933828740919,-0.0514005352605825,-0.0466408735636482,74.0 174 | 0.0417084448844436,0.0506801187398187,0.0713965151836166,0.0081008722200108,0.0383336730676214,0.0159092879722056,-0.0176293810234174,0.0343088588777263,0.0734100780491161,0.0859065477110625,295.0 175 | -0.0636351701951234,0.0506801187398187,-0.0794971751597095,-0.00567061055493425,-0.071742555588469,-0.0664487574784414,-0.0102661054152432,-0.0394933828740919,-0.0181182673078967,-0.0549250873933176,101.0 176 | 0.0162806757273067,0.0506801187398187,0.00996122697240527,-0.0435421881860331,-0.0965097070360893,-0.0946321190394993,-0.0397192078479398,-0.0394933828740919,0.01703713241478,0.00720651632920303,151.0 177 | 0.0671362140415805,-0.044641636506989,-0.0385403163522353,-0.0263278347173518,-0.0318399227006362,-0.0263657543693812,0.0081420836051921,-0.0394933828740919,-0.0271286455543265,0.00306440941436832,127.0 178 | 0.0453409833354632,0.0506801187398187,0.0196615356373334,0.0390867084636372,0.0204462859110067,0.0259300387494707,0.0081420836051921,-0.00259226199818282,-0.003303712578677,0.0196328370737072,237.0 179 | 0.0489735217864827,-0.044641636506989,0.0272062201544997,-0.0251802111642493,0.023198191627409,0.0184144756665219,-0.0618090346724622,0.0800662487638535,0.0722236508199124,0.0320591578182113,225.0 180 | 0.0417084448844436,-0.044641636506989,-0.00836157828357004,-0.0263278347173518,0.0245741444856101,0.0162224364339952,0.0707299262746723,-0.0394933828740919,-0.0483617248028919,-0.0300724459043093,81.0 181 | -0.0236772472339084,-0.044641636506989,-0.0159062628007364,-0.0125563519424068,0.0204462859110067,0.0412743133771578,-0.0434008456520269,0.0343088588777263,0.0140724525157685,-0.0093619113301358,151.0 182 | -0.0382074010379866,0.0506801187398187,0.00457216660300077,0.0356438377699009,-0.0112006298276192,0.00588853719494063,-0.0470824834561139,0.0343088588777263,0.0163049527999418,-0.00107769750046639,107.0 183 | 0.0489735217864827,-0.044641636506989,-0.0428515646477589,-0.0538708002672419,0.0452134373586271,0.0500424703072647,0.0339135482338016,-0.00259226199818282,-0.0259524244351894,-0.063209301222987,64.0 184 | 0.0453409833354632,0.0506801187398187,0.00564997867688165,0.0563010619323185,0.0644767773734429,0.0891860280309562,-0.0397192078479398,0.0712099797536354,0.0155668445407018,-0.0093619113301358,138.0 185 | 0.0453409833354632,0.0506801187398187,-0.0353068801305926,0.063186803319791,-0.00432086553661359,-0.00162702588800815,-0.0102661054152432,-0.00259226199818282,0.0155668445407018,0.0569117993072195,185.0 186 | 0.0162806757273067,-0.044641636506989,0.023972783932857,-0.0228849640236156,-0.0249601584096305,-0.0260526059075917,-0.0323559322397657,-0.00259226199818282,0.0372320112089689,0.0320591578182113,265.0 187 | -0.0745327855481821,0.0506801187398187,-0.0180618869484982,0.0081008722200108,-0.019456346976826,-0.0248000120604336,-0.0654906724765493,0.0343088588777263,0.0673172179146849,-0.0176461251598052,101.0 188 | -0.0817978624502212,0.0506801187398187,0.0422955891888323,-0.0194420933298793,0.0397096259258226,0.0575580333902134,-0.0691723102806364,0.108111100629544,0.0471861678860197,-0.0383566597339788,137.0 189 | -0.067267708646143,-0.044641636506989,-0.0547074974604488,-0.0263278347173518,-0.0758704141630723,-0.082106180567918,0.0486400994501499,-0.076394503750001,-0.0868289932162924,-0.104630370371334,143.0 190 | 0.00538306037424807,-0.044641636506989,-0.00297251791416553,0.0494153205448459,0.0741084473808508,0.0707102687853738,0.0449584616460628,-0.00259226199818282,-0.00149858682029207,-0.0093619113301358,141.0 191 | -0.00188201652779104,-0.044641636506989,-0.0665634302731387,0.00121513083253827,-0.00294491267841247,0.00307020103883484,0.0118237214092792,-0.00259226199818282,-0.0202887477516296,-0.0259303389894746,79.0 192 | 0.00901559882526763,-0.044641636506989,-0.0126728265790937,0.0287580963824284,-0.0180803941186249,-0.005071658967693,-0.0470824834561139,0.0343088588777263,0.0233748412798208,-0.0052198044153011,292.0 193 | -0.00551455497881059,0.0506801187398187,-0.041773752573878,-0.0435421881860331,-0.0799982727376757,-0.0761563597939169,-0.0323559322397657,-0.0394933828740919,0.0102256424049578,-0.0093619113301358,178.0 194 | 0.0562385986885218,0.0506801187398187,-0.030995631835069,0.0081008722200108,0.0190703330528056,0.0212328118226277,0.0339135482338016,-0.0394933828740919,-0.0295276227417736,-0.0590671943081523,91.0 195 | 0.00901559882526763,0.0506801187398187,-0.00512814206192736,-0.0641994123484507,0.0699805888062474,0.0838625041805342,-0.0397192078479398,0.0712099797536354,0.0395398780720242,0.0196328370737072,116.0 196 | -0.067267708646143,-0.044641636506989,-0.0590187457559724,0.0322009670761646,-0.051103262715452,-0.0495387405418066,-0.0102661054152432,-0.0394933828740919,0.00200784054982379,0.0237749439885419,86.0 197 | 0.0271782910803654,0.0506801187398187,0.0250505960067379,0.0149866136074833,0.0259500973438113,0.048476727998317,-0.0397192078479398,0.0343088588777263,0.00783714230182385,0.0237749439885419,122.0 198 | -0.0236772472339084,-0.044641636506989,-0.0460850008694016,-0.0332135761048244,0.0328298616348169,0.0362639379885253,0.0375951860378887,-0.00259226199818282,-0.0332487872476258,0.0113486232440377,72.0 199 | 0.0489735217864827,0.0506801187398187,0.00349435452911985,0.0700725447072635,-0.00844872411121698,0.0134041002778894,-0.0544457590642881,0.0343088588777263,0.0133159679089277,0.036201264733046,129.0 200 | -0.0527375548420648,-0.044641636506989,0.0541515220015222,-0.0263278347173518,-0.0552311212900554,-0.03388131745233,-0.0139477432193303,-0.0394933828740919,-0.0740888714915354,-0.0590671943081523,142.0 201 | 0.0417084448844436,-0.044641636506989,-0.0450071887955207,0.0344962143200845,0.0438374845004259,-0.0157187066685371,0.0375951860378887,-0.0144006206784737,0.089898693277671,0.00720651632920303,90.0 202 | 0.0562385986885218,-0.044641636506989,-0.0579409336820915,-0.00796585769556799,0.0520932016496327,0.0491030249218961,0.056003375058324,-0.0214118336448964,-0.0283202425479987,0.0444854785627154,158.0 203 | -0.034574862586967,0.0506801187398187,-0.0557853095343297,-0.015999222636143,-0.00982467696941811,-0.00788999512379879,0.0375951860378887,-0.0394933828740919,-0.0529587932392004,0.0279170509033766,39.0 204 | 0.0816663678456587,0.0506801187398187,0.00133873038135806,0.0356438377699009,0.126394655992494,0.0910649188016934,0.0191869970174533,0.0343088588777263,0.0844952822124031,-0.0300724459043093,196.0 205 | -0.00188201652779104,0.0506801187398187,0.0304396563761424,0.0528581912385822,0.0397096259258226,0.0566185880048449,-0.0397192078479398,0.0712099797536354,0.0253931349154494,0.0279170509033766,222.0 206 | 0.110726675453815,0.0506801187398187,0.00672779075076256,0.0287580963824284,-0.0277120641260328,-0.00726369820021974,-0.0470824834561139,0.0343088588777263,0.00200784054982379,0.0776223338813931,277.0 207 | -0.0309423241359475,-0.044641636506989,0.0466068374843559,0.0149866136074833,-0.0167044412604238,-0.0470335528474903,0.000778807997017968,-0.00259226199818282,0.0634559213720654,-0.0259303389894746,99.0 208 | 0.00175052192322852,0.0506801187398187,0.0261284080806188,-0.00911348124867051,0.0245741444856101,0.038455977221052,-0.0213110188275045,0.0343088588777263,0.00943640914607987,0.00306440941436832,196.0 209 | 0.00901559882526763,-0.044641636506989,0.045529025410475,0.0287580963824284,0.0121905687618,-0.0138398158977999,0.0265502726256275,-0.0394933828740919,0.0461323310394148,0.036201264733046,202.0 210 | 0.030810829531385,-0.044641636506989,0.0401399650410705,0.076958286094736,0.0176943801946045,0.0378296802974729,-0.0286742944356786,0.0343088588777263,-0.00149858682029207,0.11904340302974,155.0 211 | 0.0380759064334241,0.0506801187398187,-0.0180618869484982,0.0666296740135272,-0.051103262715452,-0.0166581520539057,-0.0765355858888105,0.0343088588777263,-0.0119006848015081,-0.0135040182449705,77.0 212 | 0.00901559882526763,-0.044641636506989,0.0142724752679289,0.0149866136074833,0.054845107366035,0.0472241341511589,0.0707299262746723,-0.0394933828740919,-0.0332487872476258,-0.0590671943081523,191.0 213 | 0.0925639831987174,-0.044641636506989,0.0369065288194278,0.0218723549949558,-0.0249601584096305,-0.0166581520539057,0.000778807997017968,-0.0394933828740919,-0.0225121719296605,-0.0217882320746399,70.0 214 | 0.0671362140415805,-0.044641636506989,0.00349435452911985,0.0356438377699009,0.0493412959332305,0.0312535625998928,0.0707299262746723,-0.0394933828740919,-0.000609254186102297,0.0196328370737072,73.0 215 | 0.00175052192322852,-0.044641636506989,-0.0708746785686623,-0.0228849640236156,-0.00156895982021134,-0.00100072896442909,0.0265502726256275,-0.0394933828740919,-0.0225121719296605,0.00720651632920303,49.0 216 | 0.030810829531385,-0.044641636506989,-0.0331512559828308,-0.0228849640236156,-0.0469754041408486,-0.0811667351825494,0.103864666511456,-0.076394503750001,-0.0398095943643375,-0.0549250873933176,65.0 217 | 0.0271782910803654,0.0506801187398187,0.0940305687351156,0.0976155102571536,-0.0345918284170385,-0.0320024266815928,-0.0434008456520269,-0.00259226199818282,0.0366457977933988,0.106617082285236,263.0 218 | 0.0126481372762872,0.0506801187398187,0.0358287167455469,0.0494153205448459,0.0534691545078339,0.0741549018650587,-0.0691723102806364,0.145012221505454,0.0456008084141249,0.0486275854775501,248.0 219 | 0.0744012909436196,-0.044641636506989,0.0315174684500233,0.10105838095089,0.0465893902168282,0.0368902349121043,0.0155053592133662,-0.00259226199818282,0.0336568129023847,0.0444854785627154,296.0 220 | -0.0418399394890061,-0.044641636506989,-0.0654856181992578,-0.0400993174922969,-0.00569681839481472,0.014343545663258,-0.0434008456520269,0.0343088588777263,0.00702686254915195,-0.0135040182449705,214.0 221 | -0.0890629393522603,-0.044641636506989,-0.041773752573878,-0.0194420933298793,-0.0662387441556644,-0.0742774690231797,0.0081420836051921,-0.0394933828740919,0.00114379737951254,-0.0300724459043093,185.0 222 | 0.0235457526293458,0.0506801187398187,-0.0396181284261162,-0.00567061055493425,-0.0483513569990498,-0.0332550205287509,0.0118237214092792,-0.0394933828740919,-0.101643547945512,-0.0673514081378217,78.0 223 | -0.0454724779400257,-0.044641636506989,-0.0385403163522353,-0.0263278347173518,-0.0153284884022226,0.000878161806308105,-0.0323559322397657,-0.00259226199818282,0.00114379737951254,-0.0383566597339788,93.0 224 | -0.0236772472339084,0.0506801187398187,-0.0256065714656645,0.0425295791573734,-0.0538551684318543,-0.0476598497710694,-0.0213110188275045,-0.0394933828740919,0.00114379737951254,0.0196328370737072,252.0 225 | -0.099960554705319,-0.044641636506989,-0.0234509473179027,-0.0641994123484507,-0.0579830270064577,-0.0601857882426507,0.0118237214092792,-0.0394933828740919,-0.0181182673078967,-0.0507829804784829,150.0 226 | -0.0273097856849279,-0.044641636506989,-0.0665634302731387,-0.112399602060758,-0.0497273098572509,-0.0413968805352788,0.000778807997017968,-0.0394933828740919,-0.0358167281015492,-0.0093619113301358,77.0 227 | 0.030810829531385,0.0506801187398187,0.0325952805239042,0.0494153205448459,-0.040095639849843,-0.0435889197678055,-0.0691723102806364,0.0343088588777263,0.0630166151147464,0.00306440941436832,208.0 228 | -0.103593093156339,0.0506801187398187,-0.0460850008694016,-0.0263278347173518,-0.0249601584096305,-0.0248000120604336,0.0302319104297145,-0.0394933828740919,-0.0398095943643375,-0.0549250873933176,77.0 229 | 0.0671362140415805,0.0506801187398187,-0.0299178197611881,0.0574486853821349,-0.000193006962010205,-0.0157187066685371,0.0744115640787594,-0.0505637191368646,-0.0384591123013538,0.00720651632920303,108.0 230 | -0.0527375548420648,-0.044641636506989,-0.0126728265790937,-0.0607565416547144,-0.000193006962010205,0.00808057642746734,0.0118237214092792,-0.00259226199818282,-0.0271286455543265,-0.0507829804784829,160.0 231 | -0.0273097856849279,0.0506801187398187,-0.0159062628007364,-0.0297707054110881,0.00393485161259318,-0.000687580502639557,0.0412768238419757,-0.0394933828740919,-0.0236445575721341,0.0113486232440377,53.0 232 | -0.0382074010379866,0.0506801187398187,0.0713965151836166,-0.0573136709609782,0.153913713156516,0.155886650392127,0.000778807997017968,0.0719480021711535,0.0502764933899896,0.0693381200517237,220.0 233 | 0.00901559882526763,-0.044641636506989,-0.030995631835069,0.0218723549949558,0.00806271018719657,0.00870687335104641,0.00446044580110504,-0.00259226199818282,0.00943640914607987,0.0113486232440377,154.0 234 | 0.0126481372762872,0.0506801187398187,0.000260918307477141,-0.0114087283893043,0.0397096259258226,0.0572448849284239,-0.0397192078479398,0.0560805201945126,0.024052583226893,0.0320591578182113,259.0 235 | 0.0671362140415805,-0.044641636506989,0.0369065288194278,-0.0504279295735057,-0.0235842055514294,-0.034507614375909,0.0486400994501499,-0.0394933828740919,-0.0259524244351894,-0.0383566597339788,90.0 236 | 0.0453409833354632,-0.044641636506989,0.0390621529671896,0.0459724498511097,0.00668675732899544,-0.0241737151368545,0.0081420836051921,-0.0125555646346783,0.0643282330236709,0.0569117993072195,246.0 237 | 0.0671362140415805,0.0506801187398187,-0.0148284507268555,0.0585963091762383,-0.0593589798646588,-0.034507614375909,-0.0618090346724622,0.012906208769699,-0.00514530798026311,0.0486275854775501,124.0 238 | 0.0271782910803654,-0.044641636506989,0.00672779075076256,0.0356438377699009,0.0796122588136553,0.0707102687853738,0.0155053592133662,0.0343088588777263,0.0406722637144977,0.0113486232440377,67.0 239 | 0.0562385986885218,-0.044641636506989,-0.0687190544209005,-0.0687899065952895,-0.000193006962010205,-0.00100072896442909,0.0449584616460628,-0.0376483268302965,-0.0483617248028919,-0.00107769750046639,72.0 240 | 0.0344433679824045,0.0506801187398187,-0.00943939035745095,0.0597439326260547,-0.0359677812752396,-0.00757684666200928,-0.0765355858888105,0.0712099797536354,0.0110081010458725,-0.0217882320746399,257.0 241 | 0.0235457526293458,-0.044641636506989,0.0196615356373334,-0.0125563519424068,0.0837401173882587,0.0387691256828415,0.0633666506664982,-0.00259226199818282,0.0660482061630984,0.0486275854775501,262.0 242 | 0.0489735217864827,0.0506801187398187,0.0746299514052593,0.0666296740135272,-0.00982467696941811,-0.00225332281158722,-0.0434008456520269,0.0343088588777263,0.0336568129023847,0.0196328370737072,275.0 243 | 0.030810829531385,0.0506801187398187,-0.00836157828357004,0.00465800152627453,0.0149424744782022,0.0274957810584184,0.0081420836051921,-0.00812743012956918,-0.0295276227417736,0.0569117993072195,177.0 244 | -0.103593093156339,0.0506801187398187,-0.0234509473179027,-0.0228849640236156,-0.0868780370286814,-0.0677013513255995,-0.0176293810234174,-0.0394933828740919,-0.0781409106690696,-0.0714935150526564,71.0 245 | 0.0162806757273067,0.0506801187398187,-0.0460850008694016,0.0115437429137471,-0.0332158755588373,-0.0160318551303266,-0.0102661054152432,-0.00259226199818282,-0.0439854025655911,-0.0424987666488135,47.0 246 | -0.0600026317441039,0.0506801187398187,0.0541515220015222,-0.0194420933298793,-0.0497273098572509,-0.0489124436182275,0.0228686348215404,-0.0394933828740919,-0.0439854025655911,-0.0052198044153011,187.0 247 | -0.0273097856849279,-0.044641636506989,-0.0353068801305926,-0.0297707054110881,-0.0566070741482565,-0.058620045933703,0.0302319104297145,-0.0394933828740919,-0.0498684677352306,-0.129483011860342,125.0 248 | 0.0417084448844436,-0.044641636506989,-0.0320734439089499,-0.061904165207817,0.0796122588136553,0.0509819156926333,0.056003375058324,-0.00997248617336464,0.0450661683362615,-0.0590671943081523,78.0 249 | -0.0817978624502212,-0.044641636506989,-0.0816527993074713,-0.0400993174922969,0.00255889875439205,-0.0185370428246429,0.0707299262746723,-0.0394933828740919,-0.0109044358473771,-0.09220404962683,51.0 250 | -0.0418399394890061,-0.044641636506989,0.0476846495582368,0.0597439326260547,0.127770608850695,0.128016437292858,-0.0249926566315915,0.108111100629544,0.0638931206368394,0.0403433716478807,258.0 251 | -0.0127796318808497,-0.044641636506989,0.0606183944448076,0.0528581912385822,0.0479653430750293,0.0293746718291555,-0.0176293810234174,0.0343088588777263,0.0702112981933102,0.00720651632920303,215.0 252 | 0.0671362140415805,-0.044641636506989,0.056307146149284,0.0735154154009998,-0.0139525355440215,-0.039204841302752,-0.0323559322397657,-0.00259226199818282,0.0757375884575476,0.036201264733046,303.0 253 | -0.0527375548420648,0.0506801187398187,0.098341817030639,0.0872868981759448,0.0603489187988395,0.0487898764601065,-0.0581273968683752,0.108111100629544,0.0844952822124031,0.0403433716478807,243.0 254 | 0.00538306037424807,-0.044641636506989,0.0595405823709267,-0.0561660474078757,0.0245741444856101,0.0528608064633705,-0.0434008456520269,0.0509143632718854,-0.00421985970694603,-0.0300724459043093,91.0 255 | 0.0816663678456587,-0.044641636506989,0.0336730925977851,0.0081008722200108,0.0520932016496327,0.0566185880048449,-0.0176293810234174,0.0343088588777263,0.0348641930961596,0.0693381200517237,150.0 256 | 0.030810829531385,0.0506801187398187,0.056307146149284,0.076958286094736,0.0493412959332305,-0.0122740735888523,-0.0360375700438527,0.0712099797536354,0.120053382001538,0.0900486546258972,310.0 257 | 0.00175052192322852,-0.044641636506989,-0.0654856181992578,-0.00567061055493425,-0.00707277125301585,-0.0194764882100115,0.0412768238419757,-0.0394933828740919,-0.003303712578677,0.00720651632920303,153.0 258 | -0.0491050163910452,-0.044641636506989,0.160854917315731,-0.0469850588797694,-0.0290880169842339,-0.019789636671801,-0.0470824834561139,0.0343088588777263,0.028016506523264,0.0113486232440377,346.0 259 | -0.0273097856849279,0.0506801187398187,-0.0557853095343297,0.0253152256886921,-0.00707277125301585,-0.0235474182132754,0.052321737254237,-0.0394933828740919,-0.00514530798026311,-0.0507829804784829,63.0 260 | 0.0780338293946392,0.0506801187398187,-0.0245287593917836,-0.0423945646329306,0.00668675732899544,0.0528608064633705,-0.0691723102806364,0.0808042711813717,-0.0371283460104736,0.0569117993072195,89.0 261 | 0.0126481372762872,-0.044641636506989,-0.0363846922044735,0.0425295791573734,-0.0139525355440215,0.0129343775852051,-0.0268334755336351,0.00515697338575809,-0.0439854025655911,0.00720651632920303,50.0 262 | 0.0417084448844436,-0.044641636506989,-0.00836157828357004,-0.0573136709609782,0.00806271018719657,-0.0313761297580137,0.151725957964588,-0.076394503750001,-0.0802365402489018,-0.0176461251598052,39.0 263 | 0.0489735217864827,-0.044641636506989,-0.041773752573878,0.104501251644626,0.0355817673512192,-0.0257394574458021,0.177497422593197,-0.076394503750001,-0.0129079422541688,0.0154907301588724,103.0 264 | -0.0164121703318693,0.0506801187398187,0.127442743025423,0.0976155102571536,0.0163184273364034,0.0174750302811533,-0.0213110188275045,0.0343088588777263,0.0348641930961596,0.00306440941436832,308.0 265 | -0.0745327855481821,0.0506801187398187,-0.0773415510119477,-0.0469850588797694,-0.0469754041408486,-0.0326287236051719,0.00446044580110504,-0.0394933828740919,-0.072128454601956,-0.0176461251598052,116.0 266 | 0.0344433679824045,0.0506801187398187,0.0282840322283806,-0.0332135761048244,-0.0455994512826475,-0.00976888589453599,-0.050764121260201,-0.00259226199818282,-0.0594726974107223,-0.0217882320746399,145.0 267 | -0.034574862586967,0.0506801187398187,-0.0256065714656645,-0.0171468461892456,0.00118294589619092,-0.00287961973516629,0.0081420836051921,-0.015507654304751,0.0148227108412663,0.0403433716478807,74.0 268 | -0.0527375548420648,0.0506801187398187,-0.0622521819776151,0.0115437429137471,-0.00844872411121698,-0.0366996536084358,0.122272855531891,-0.076394503750001,-0.0868289932162924,0.00306440941436832,45.0 269 | 0.0598711371395414,-0.044641636506989,-0.000816893766403737,-0.0848566365108683,0.075484400239052,0.0794784257154807,0.00446044580110504,0.0343088588777263,0.0233748412798208,0.0279170509033766,115.0 270 | 0.063503675590561,0.0506801187398187,0.088641508365711,0.0700725447072635,0.0204462859110067,0.0375165318356834,-0.050764121260201,0.0712099797536354,0.0293004132685869,0.0734802269665584,264.0 271 | 0.00901559882526763,-0.044641636506989,-0.0320734439089499,-0.0263278347173518,0.0424615316422248,-0.0103951828181151,0.159089233572762,-0.076394503750001,-0.0119006848015081,-0.0383566597339788,87.0 272 | 0.00538306037424807,0.0506801187398187,0.0304396563761424,0.0838440274822086,-0.0373437341334407,-0.0473467013092799,0.0155053592133662,-0.0394933828740919,0.00864028293306308,0.0154907301588724,202.0 273 | 0.0380759064334241,0.0506801187398187,0.00888341489852436,0.0425295791573734,-0.0428475455662452,-0.0210422305189592,-0.0397192078479398,-0.00259226199818282,-0.0181182673078967,0.00720651632920303,127.0 274 | 0.0126481372762872,-0.044641636506989,0.00672779075076256,-0.0561660474078757,-0.0758704141630723,-0.0664487574784414,-0.0213110188275045,-0.0376483268302965,-0.0181182673078967,-0.09220404962683,182.0 275 | 0.0744012909436196,0.0506801187398187,-0.02021751109626,0.0459724498511097,0.0741084473808508,0.0328193049088404,-0.0360375700438527,0.0712099797536354,0.106354276741726,0.036201264733046,241.0 276 | 0.0162806757273067,-0.044641636506989,-0.0245287593917836,0.0356438377699009,-0.00707277125301585,-0.00319276819695581,-0.0139477432193303,-0.00259226199818282,0.0155668445407018,0.0154907301588724,66.0 277 | -0.00551455497881059,0.0506801187398187,-0.0115950145052127,0.0115437429137471,-0.0222082526932283,-0.0154055582067476,-0.0213110188275045,-0.00259226199818282,0.0110081010458725,0.0693381200517237,94.0 278 | 0.0126481372762872,-0.044641636506989,0.0261284080806188,0.063186803319791,0.125018703134293,0.0916912157252725,0.0633666506664982,-0.00259226199818282,0.057572856202426,-0.0217882320746399,283.0 279 | -0.034574862586967,-0.044641636506989,-0.0590187457559724,0.00121513083253827,-0.0538551684318543,-0.078035250564654,0.0670482884705852,-0.076394503750001,-0.02139368094036,0.0154907301588724,64.0 280 | 0.0671362140415805,0.0506801187398187,-0.0363846922044735,-0.0848566365108683,-0.00707277125301585,0.01966706951368,-0.0544457590642881,0.0343088588777263,0.00114379737951254,0.0320591578182113,102.0 281 | 0.0380759064334241,0.0506801187398187,-0.0245287593917836,0.00465800152627453,-0.0263361112678317,-0.0263657543693812,0.0155053592133662,-0.0394933828740919,-0.0159982677581387,-0.0259303389894746,200.0 282 | 0.00901559882526763,0.0506801187398187,0.0185837235634525,0.0390867084636372,0.0176943801946045,0.0105857641217836,0.0191869970174533,-0.00259226199818282,0.0163049527999418,-0.0176461251598052,265.0 283 | -0.0926954778032799,0.0506801187398187,-0.0902752958985185,-0.0573136709609782,-0.0249601584096305,-0.0304366843726451,-0.00658446761115617,-0.00259226199818282,0.024052583226893,0.00306440941436832,94.0 284 | 0.0707687524926,-0.044641636506989,-0.00512814206192736,-0.00567061055493425,0.0878679759628621,0.102964560349696,0.0118237214092792,0.0343088588777263,-0.0089440189577978,0.0279170509033766,230.0 285 | -0.0164121703318693,-0.044641636506989,-0.052551873312687,-0.0332135761048244,-0.0442234984244464,-0.0363865051466462,0.0191869970174533,-0.0394933828740919,-0.0683297436244215,-0.0300724459043093,181.0 286 | 0.0417084448844436,0.0506801187398187,-0.0223731352440218,0.0287580963824284,-0.0662387441556644,-0.0451546620767532,-0.0618090346724622,-0.00259226199818282,0.00286377051894013,-0.0549250873933176,156.0 287 | 0.0126481372762872,-0.044641636506989,-0.02021751109626,-0.015999222636143,0.0121905687618,0.0212328118226277,-0.0765355858888105,0.108111100629544,0.0598807230654812,-0.0217882320746399,233.0 288 | -0.0382074010379866,-0.044641636506989,-0.0547074974604488,-0.0779708951233958,-0.0332158755588373,-0.0864902590329714,0.140681044552327,-0.076394503750001,-0.0191970476139445,-0.0052198044153011,60.0 289 | 0.0453409833354632,-0.044641636506989,-0.00620595413580824,-0.015999222636143,0.125018703134293,0.125198101136752,0.0191869970174533,0.0343088588777263,0.0324332257796019,-0.0052198044153011,219.0 290 | 0.0707687524926,0.0506801187398187,-0.0169840748746173,0.0218723549949558,0.0438374845004259,0.0563054395430553,0.0375951860378887,-0.00259226199818282,-0.0702093127286876,-0.0176461251598052,80.0 291 | -0.0745327855481821,0.0506801187398187,0.0552293340754031,-0.0400993174922969,0.0534691545078339,0.05317395492516,-0.0434008456520269,0.0712099797536354,0.061237907519701,-0.0342145528191441,68.0 292 | 0.0598711371395414,0.0506801187398187,0.0767855755530211,0.0253152256886921,0.00118294589619092,0.0168487333575743,-0.0544457590642881,0.0343088588777263,0.0299356483965325,0.0444854785627154,332.0 293 | 0.0744012909436196,-0.044641636506989,0.0185837235634525,0.063186803319791,0.0617248716570406,0.0428400556861055,0.0081420836051921,-0.00259226199818282,0.0580391276638951,-0.0590671943081523,248.0 294 | 0.00901559882526763,-0.044641636506989,-0.0223731352440218,-0.0320659525517218,-0.0497273098572509,-0.0686407967109681,0.0780932018828464,-0.0708593356186146,-0.0629129499162512,-0.0383566597339788,84.0 295 | -0.0709002470971626,-0.044641636506989,0.0929527566612346,0.0126913664668496,0.0204462859110067,0.0425269072243159,0.000778807997017968,0.000359827671889909,-0.0545441527110952,-0.00107769750046639,200.0 296 | 0.0235457526293458,0.0506801187398187,-0.030995631835069,-0.00567061055493425,-0.0167044412604238,0.0177881787429428,-0.0323559322397657,-0.00259226199818282,-0.0740888714915354,-0.0342145528191441,55.0 297 | -0.0527375548420648,0.0506801187398187,0.0390621529671896,-0.0400993174922969,-0.00569681839481472,-0.0129003705124313,0.0118237214092792,-0.0394933828740919,0.0163049527999418,0.00306440941436832,85.0 298 | 0.0671362140415805,-0.044641636506989,-0.0611743699037342,-0.0400993174922969,-0.0263361112678317,-0.024486863598644,0.0339135482338016,-0.0394933828740919,-0.0561575730950062,-0.0590671943081523,89.0 299 | 0.00175052192322852,-0.044641636506989,-0.00836157828357004,-0.0641994123484507,-0.0387196869916418,-0.024486863598644,0.00446044580110504,-0.0394933828740919,-0.0646830224644503,-0.0549250873933176,31.0 300 | 0.0235457526293458,0.0506801187398187,-0.0374625042783544,-0.0469850588797694,-0.0910058956032848,-0.0755300628703378,-0.0323559322397657,-0.0394933828740919,-0.0307512098645563,-0.0135040182449705,129.0 301 | 0.0380759064334241,0.0506801187398187,-0.0137506386529745,-0.015999222636143,-0.0359677812752396,-0.0219816759043277,-0.0139477432193303,-0.00259226199818282,-0.0259524244351894,-0.00107769750046639,83.0 302 | 0.0162806757273067,-0.044641636506989,0.0735521393313785,-0.0412469410453994,-0.00432086553661359,-0.0135266674360104,-0.0139477432193303,-0.00111621716314646,0.0428956878925287,0.0444854785627154,275.0 303 | -0.00188201652779104,0.0506801187398187,-0.0245287593917836,0.0528581912385822,0.0273260502020124,0.0300009687527346,0.0302319104297145,-0.00259226199818282,-0.02139368094036,0.036201264733046,65.0 304 | 0.0126481372762872,-0.044641636506989,0.0336730925977851,0.0333485905259811,0.0300779559184146,0.0271826325966288,-0.0029028298070691,0.00884708547334898,0.0311929907028023,0.0279170509033766,198.0 305 | 0.0744012909436196,-0.044641636506989,0.034750904671666,0.0941726395634173,0.0575970130824372,0.0202933664372591,0.0228686348215404,-0.00259226199818282,0.0738021469200488,-0.0217882320746399,236.0 306 | 0.0417084448844436,0.0506801187398187,-0.0385403163522353,0.0528581912385822,0.0768603530972531,0.116429944206646,-0.0397192078479398,0.0712099797536354,-0.0225121719296605,-0.0135040182449705,253.0 307 | -0.00914709342983014,0.0506801187398187,-0.0396181284261162,-0.0400993174922969,-0.00844872411121698,0.0162224364339952,-0.0654906724765493,0.0712099797536354,0.0177634778671173,-0.0673514081378217,124.0 308 | 0.00901559882526763,0.0506801187398187,-0.00189470584028465,0.0218723549949558,-0.0387196869916418,-0.0248000120604336,-0.00658446761115617,-0.0394933828740919,-0.0398095943643375,-0.0135040182449705,44.0 309 | 0.0671362140415805,0.0506801187398187,-0.030995631835069,0.00465800152627453,0.0245741444856101,0.0356376410649462,-0.0286742944356786,0.0343088588777263,0.0233748412798208,0.0817644407962278,172.0 310 | 0.00175052192322852,-0.044641636506989,-0.0460850008694016,-0.0332135761048244,-0.07311850844667,-0.0814798836443389,0.0449584616460628,-0.0693832907835783,-0.0611765950943345,-0.0797777288823259,114.0 311 | -0.00914709342983014,0.0506801187398187,0.00133873038135806,-0.00222773986119799,0.0796122588136553,0.0700839718617947,0.0339135482338016,-0.00259226199818282,0.0267142576335128,0.0817644407962278,142.0 312 | -0.00551455497881059,-0.044641636506989,0.0649296427403312,0.0356438377699009,-0.00156895982021134,0.0149698425868371,-0.0139477432193303,0.000728838880648992,-0.0181182673078967,0.0320591578182113,109.0 313 | 0.096196521649737,-0.044641636506989,0.0401399650410705,-0.0573136709609782,0.0452134373586271,0.0606895180081088,-0.0213110188275045,0.0361539149215217,0.0125531528133893,0.0237749439885419,180.0 314 | -0.0745327855481821,-0.044641636506989,-0.0234509473179027,-0.00567061055493425,-0.0208322998350272,-0.0141529643595894,0.0155053592133662,-0.0394933828740919,-0.0384591123013538,-0.0300724459043093,144.0 315 | 0.0598711371395414,0.0506801187398187,0.0530737099276413,0.0528581912385822,0.0328298616348169,0.01966706951368,-0.0102661054152432,0.0343088588777263,0.0552050380896167,-0.00107769750046639,163.0 316 | -0.0236772472339084,-0.044641636506989,0.0401399650410705,-0.0125563519424068,-0.00982467696941811,-0.00100072896442909,-0.0029028298070691,-0.00259226199818282,-0.0119006848015081,-0.0383566597339788,147.0 317 | 0.00901559882526763,-0.044641636506989,-0.02021751109626,-0.0538708002672419,0.0314539087766158,0.0206065148990486,0.056003375058324,-0.0394933828740919,-0.0109044358473771,-0.00107769750046639,97.0 318 | 0.0162806757273067,0.0506801187398187,0.0142724752679289,0.00121513083253827,0.00118294589619092,-0.0213553789807487,-0.0323559322397657,0.0343088588777263,0.0749683360277342,0.0403433716478807,220.0 319 | 0.0199132141783263,-0.044641636506989,-0.0342290680567117,0.055153438482502,0.0672286830898452,0.0741549018650587,-0.00658446761115617,0.0328328140426899,0.0247253233428045,0.0693381200517237,190.0 320 | 0.0889314447476978,-0.044641636506989,0.00672779075076256,0.0253152256886921,0.0300779559184146,0.00870687335104641,0.0633666506664982,-0.0394933828740919,0.00943640914607987,0.0320591578182113,109.0 321 | 0.0199132141783263,-0.044641636506989,0.00457216660300077,0.0459724498511097,-0.0180803941186249,-0.0545491159304391,0.0633666506664982,-0.0394933828740919,0.0286607203138089,0.0610539062220542,191.0 322 | -0.0236772472339084,-0.044641636506989,0.0304396563761424,-0.00567061055493425,0.0823641645300576,0.092004364187062,-0.0176293810234174,0.0712099797536354,0.0330470723549341,0.00306440941436832,122.0 323 | 0.096196521649737,-0.044641636506989,0.0519958978537604,0.0792535333386559,0.054845107366035,0.0365770864503148,-0.0765355858888105,0.141322109417863,0.098646374304928,0.0610539062220542,230.0 324 | 0.0235457526293458,0.0506801187398187,0.0616962065186885,0.0620391798699746,0.0245741444856101,-0.0360733566848567,-0.0912621371051588,0.155344535350708,0.133395733837469,0.0817644407962278,242.0 325 | 0.0707687524926,0.0506801187398187,-0.00728376620968916,0.0494153205448459,0.0603489187988395,-0.00444536204411395,-0.0544457590642881,0.108111100629544,0.129019411600168,0.0569117993072195,248.0 326 | 0.030810829531385,-0.044641636506989,0.00564997867688165,0.0115437429137471,0.0782363059554542,0.077912683406533,-0.0434008456520269,0.108111100629544,0.0660482061630984,0.0196328370737072,249.0 327 | -0.00188201652779104,-0.044641636506989,0.0541515220015222,-0.0664946594890845,0.0727324945226497,0.0566185880048449,-0.0434008456520269,0.0848633944777217,0.0844952822124031,0.0486275854775501,192.0 328 | 0.0453409833354632,0.0506801187398187,-0.00836157828357004,-0.0332135761048244,-0.00707277125301585,0.00119131026809764,-0.0397192078479398,0.0343088588777263,0.0299356483965325,0.0279170509033766,131.0 329 | 0.0744012909436196,-0.044641636506989,0.114508998138853,0.0287580963824284,0.0245741444856101,0.0249905933641021,0.0191869970174533,-0.00259226199818282,-0.000609254186102297,-0.0052198044153011,237.0 330 | -0.0382074010379866,-0.044641636506989,0.067085266888093,-0.0607565416547144,-0.0290880169842339,-0.0232342697514859,-0.0102661054152432,-0.00259226199818282,-0.00149858682029207,0.0196328370737072,78.0 331 | -0.0127796318808497,0.0506801187398187,-0.0557853095343297,-0.00222773986119799,-0.0277120641260328,-0.029184090525487,0.0191869970174533,-0.0394933828740919,-0.0170521046047435,0.0444854785627154,135.0 332 | 0.00901559882526763,0.0506801187398187,0.0304396563761424,0.0425295791573734,-0.00294491267841247,0.0368902349121043,-0.0654906724765493,0.0712099797536354,-0.0236445575721341,0.0154907301588724,244.0 333 | 0.0816663678456587,0.0506801187398187,-0.0256065714656645,-0.0366564467985606,-0.0703666027302678,-0.0464072559239113,-0.0397192078479398,-0.00259226199818282,-0.0411803851880079,-0.0052198044153011,199.0 334 | 0.030810829531385,-0.044641636506989,0.104808689473925,0.076958286094736,-0.0112006298276192,-0.0113346282034837,-0.0581273968683752,0.0343088588777263,0.0571041874478439,0.036201264733046,270.0 335 | 0.0271782910803654,0.0506801187398187,-0.00620595413580824,0.0287580963824284,-0.0167044412604238,-0.00162702588800815,-0.0581273968683752,0.0343088588777263,0.0293004132685869,0.0320591578182113,164.0 336 | -0.0600026317441039,0.0506801187398187,-0.0471628129432825,-0.0228849640236156,-0.071742555588469,-0.0576806005483345,-0.00658446761115617,-0.0394933828740919,-0.0629129499162512,-0.0549250873933176,72.0 337 | 0.00538306037424807,-0.044641636506989,-0.0482406250171634,-0.0125563519424068,0.00118294589619092,-0.00663740127664067,0.0633666506664982,-0.0394933828740919,-0.0514005352605825,-0.0590671943081523,96.0 338 | -0.0200447087828888,-0.044641636506989,0.0854080721440683,-0.0366564467985606,0.0919958345374655,0.0894991764927457,-0.0618090346724622,0.145012221505454,0.0809479135112756,0.0527696923923848,306.0 339 | 0.0199132141783263,0.0506801187398187,-0.0126728265790937,0.0700725447072635,-0.0112006298276192,0.00714113104209875,-0.0397192078479398,0.0343088588777263,0.00538436996854573,0.00306440941436832,91.0 340 | -0.0636351701951234,-0.044641636506989,-0.0331512559828308,-0.0332135761048244,0.00118294589619092,0.0240511479787335,-0.0249926566315915,-0.00259226199818282,-0.0225121719296605,-0.0590671943081523,214.0 341 | 0.0271782910803654,-0.044641636506989,-0.00728376620968916,-0.0504279295735057,0.075484400239052,0.0566185880048449,0.0339135482338016,-0.00259226199818282,0.0434431722527813,0.0154907301588724,95.0 342 | -0.0164121703318693,-0.044641636506989,-0.0137506386529745,0.132044217194516,-0.00982467696941811,-0.00381906512053488,0.0191869970174533,-0.0394933828740919,-0.0358167281015492,-0.0300724459043093,216.0 343 | 0.030810829531385,0.0506801187398187,0.0595405823709267,0.0563010619323185,-0.0222082526932283,0.00119131026809764,-0.0323559322397657,-0.00259226199818282,-0.0247911874324607,-0.0176461251598052,263.0 344 | 0.0562385986885218,0.0506801187398187,0.0218171597850952,0.0563010619323185,-0.00707277125301585,0.0181013272047324,-0.0323559322397657,-0.00259226199818282,-0.0236445575721341,0.0237749439885419,178.0 345 | -0.0200447087828888,-0.044641636506989,0.0185837235634525,0.090729768869681,0.00393485161259318,0.00870687335104641,0.0375951860378887,-0.0394933828740919,-0.0578000656756125,0.00720651632920303,113.0 346 | -0.107225631607358,-0.044641636506989,-0.0115950145052127,-0.0400993174922969,0.0493412959332305,0.0644472995495832,-0.0139477432193303,0.0343088588777263,0.00702686254915195,-0.0300724459043093,200.0 347 | 0.0816663678456587,0.0506801187398187,-0.00297251791416553,-0.0332135761048244,0.0424615316422248,0.057871181852003,-0.0102661054152432,0.0343088588777263,-0.000609254186102297,-0.00107769750046639,139.0 348 | 0.00538306037424807,0.0506801187398187,0.0175059114895716,0.0322009670761646,0.127770608850695,0.127390140369279,-0.0213110188275045,0.0712099797536354,0.062575181458056,0.0154907301588724,139.0 349 | 0.0380759064334241,0.0506801187398187,-0.0299178197611881,-0.0745280244296595,-0.0125765826858204,-0.0125872220506418,0.00446044580110504,-0.00259226199818282,0.00371173823343597,-0.0300724459043093,88.0 350 | 0.030810829531385,-0.044641636506989,-0.02021751109626,-0.00567061055493425,-0.00432086553661359,-0.0294972389872765,0.0780932018828464,-0.0394933828740919,-0.0109044358473771,-0.00107769750046639,148.0 351 | 0.00175052192322852,0.0506801187398187,-0.0579409336820915,-0.0435421881860331,-0.0965097070360893,-0.0470335528474903,-0.098625412713333,0.0343088588777263,-0.0611765950943345,-0.0714935150526564,88.0 352 | -0.0273097856849279,0.0506801187398187,0.0606183944448076,0.107944122338362,0.0121905687618,-0.0175975974392743,-0.0029028298070691,-0.00259226199818282,0.0702112981933102,0.135611830689079,243.0 353 | -0.0854304009012408,0.0506801187398187,-0.0406959404999971,-0.0332135761048244,-0.0813742255958769,-0.0695802420963367,-0.00658446761115617,-0.0394933828740919,-0.0578000656756125,-0.0424987666488135,71.0 354 | 0.0126481372762872,0.0506801187398187,-0.0719524906425432,-0.0469850588797694,-0.051103262715452,-0.0971373067338155,0.118591217727804,-0.076394503750001,-0.0202887477516296,-0.0383566597339788,77.0 355 | -0.0527375548420648,-0.044641636506989,-0.0557853095343297,-0.0366564467985606,0.0892439288210632,-0.00319276819695581,0.0081420836051921,0.0343088588777263,0.132372649338676,0.00306440941436832,109.0 356 | -0.0236772472339084,0.0506801187398187,0.045529025410475,0.0218723549949558,0.10988322169408,0.0888728795691667,0.000778807997017968,0.0343088588777263,0.0741925366900307,0.0610539062220542,272.0 357 | -0.0745327855481821,0.0506801187398187,-0.00943939035745095,0.0149866136074833,-0.0373437341334407,-0.0216685274425382,-0.0139477432193303,-0.00259226199818282,-0.0332487872476258,0.0113486232440377,60.0 358 | -0.00551455497881059,0.0506801187398187,-0.0331512559828308,-0.015999222636143,0.00806271018719657,0.0162224364339952,0.0155053592133662,-0.00259226199818282,-0.0283202425479987,-0.0756356219674911,54.0 359 | -0.0600026317441039,0.0506801187398187,0.0498402737059986,0.0184294843012196,-0.0167044412604238,-0.0301235359108556,-0.0176293810234174,-0.00259226199818282,0.049768659920749,-0.0590671943081523,221.0 360 | -0.0200447087828888,-0.044641636506989,-0.084886235529114,-0.0263278347173518,-0.0359677812752396,-0.0341944659141195,0.0412768238419757,-0.0516707527631419,-0.0823814832581028,-0.0466408735636482,90.0 361 | 0.0380759064334241,0.0506801187398187,0.00564997867688165,0.0322009670761646,0.00668675732899544,0.0174750302811533,-0.0249926566315915,0.0343088588777263,0.0148227108412663,0.0610539062220542,311.0 362 | 0.0162806757273067,-0.044641636506989,0.0207393477112143,0.0218723549949558,-0.0139525355440215,-0.0132135189742209,-0.00658446761115617,-0.00259226199818282,0.0133159679089277,0.0403433716478807,281.0 363 | 0.0417084448844436,-0.044641636506989,-0.00728376620968916,0.0287580963824284,-0.0428475455662452,-0.0482861466946485,0.052321737254237,-0.076394503750001,-0.072128454601956,0.0237749439885419,182.0 364 | 0.0199132141783263,0.0506801187398187,0.104808689473925,0.0700725447072635,-0.0359677812752396,-0.0266789028311707,-0.0249926566315915,-0.00259226199818282,0.00371173823343597,0.0403433716478807,321.0 365 | -0.0491050163910452,0.0506801187398187,-0.0245287593917836,6.75072794357462e-05,-0.0469754041408486,-0.0282446451401184,-0.0654906724765493,0.0284046795375808,0.0191990330785671,0.0113486232440377,58.0 366 | 0.00175052192322852,0.0506801187398187,-0.00620595413580824,-0.0194420933298793,-0.00982467696941811,0.00494909180957202,-0.0397192078479398,0.0343088588777263,0.0148227108412663,0.0983328684555666,262.0 367 | 0.0344433679824045,-0.044641636506989,-0.0385403163522353,-0.0125563519424068,0.0094386630453977,0.00526224027136155,-0.00658446761115617,-0.00259226199818282,0.0311929907028023,0.0983328684555666,206.0 368 | -0.0454724779400257,0.0506801187398187,0.137143051690352,-0.015999222636143,0.0410855787840237,0.0318798595234718,-0.0434008456520269,0.0712099797536354,0.0710215779459822,0.0486275854775501,233.0 369 | -0.00914709342983014,0.0506801187398187,0.17055522598066,0.0149866136074833,0.0300779559184146,0.033758750294209,-0.0213110188275045,0.0343088588777263,0.0336568129023847,0.0320591578182113,242.0 370 | -0.0164121703318693,0.0506801187398187,0.00241654245523897,0.0149866136074833,0.0218222387692079,-0.0100820343563255,-0.0249926566315915,0.0343088588777263,0.085533121187439,0.0817644407962278,123.0 371 | -0.00914709342983014,-0.044641636506989,0.0379843408933087,-0.0400993174922969,-0.0249601584096305,-0.00381906512053488,-0.0434008456520269,0.0158582984397717,-0.00514530798026311,0.0279170509033766,167.0 372 | 0.0199132141783263,-0.044641636506989,-0.0579409336820915,-0.0573136709609782,-0.00156895982021134,-0.0125872220506418,0.0744115640787594,-0.0394933828740919,-0.0611765950943345,-0.0756356219674911,63.0 373 | 0.0526060602375023,0.0506801187398187,-0.00943939035745095,0.0494153205448459,0.0507172487914316,-0.019163339748222,-0.0139477432193303,0.0343088588777263,0.119343994203787,-0.0176461251598052,197.0 374 | -0.0273097856849279,0.0506801187398187,-0.0234509473179027,-0.015999222636143,0.0135665216200011,0.0127778033543103,0.0265502726256275,-0.00259226199818282,-0.0109044358473771,-0.0217882320746399,71.0 375 | -0.0745327855481821,-0.044641636506989,-0.0105172024313319,-0.00567061055493425,-0.0662387441556644,-0.0570543036247554,-0.0029028298070691,-0.0394933828740919,-0.0425721049227942,-0.00107769750046639,168.0 376 | -0.107225631607358,-0.044641636506989,-0.0342290680567117,-0.067642283042187,-0.0634868384392622,-0.0705196874817053,0.0081420836051921,-0.0394933828740919,-0.000609254186102297,-0.0797777288823259,140.0 377 | 0.0453409833354632,0.0506801187398187,-0.00297251791416553,0.107944122338362,0.0355817673512192,0.0224854056697859,0.0265502726256275,-0.00259226199818282,0.028016506523264,0.0196328370737072,217.0 378 | -0.00188201652779104,-0.044641636506989,0.068163078961974,-0.00567061055493425,0.119514891701488,0.130208476525385,-0.0249926566315915,0.0867084505215172,0.0461323310394148,-0.00107769750046639,121.0 379 | 0.0199132141783263,0.0506801187398187,0.00996122697240527,0.0184294843012196,0.0149424744782022,0.0447189464568426,-0.0618090346724622,0.0712099797536354,0.00943640914607987,-0.063209301222987,235.0 380 | 0.0162806757273067,0.0506801187398187,0.00241654245523897,-0.00567061055493425,-0.00569681839481472,0.0108989125835731,-0.050764121260201,0.0343088588777263,0.0226920225667445,-0.0383566597339788,245.0 381 | -0.00188201652779104,-0.044641636506989,-0.0385403163522353,0.0218723549949558,-0.108893282759899,-0.115613065979398,0.0228686348215404,-0.076394503750001,-0.0468794828442166,0.0237749439885419,40.0 382 | 0.0162806757273067,-0.044641636506989,0.0261284080806188,0.0585963091762383,-0.0607349327228599,-0.0442152166913845,-0.0139477432193303,-0.0339582147427055,-0.0514005352605825,-0.0259303389894746,52.0 383 | -0.0709002470971626,0.0506801187398187,-0.0891974838246376,-0.0745280244296595,-0.0428475455662452,-0.0257394574458021,-0.0323559322397657,-0.00259226199818282,-0.0129079422541688,-0.0549250873933176,104.0 384 | 0.0489735217864827,-0.044641636506989,0.0606183944448076,-0.0228849640236156,-0.0235842055514294,-0.072711726714232,-0.0434008456520269,-0.00259226199818282,0.104137611358979,0.036201264733046,132.0 385 | 0.00538306037424807,0.0506801187398187,-0.0288400076873072,-0.00911348124867051,-0.0318399227006362,-0.0288709420636975,0.0081420836051921,-0.0394933828740919,-0.0181182673078967,0.00720651632920303,88.0 386 | 0.0344433679824045,0.0506801187398187,-0.0299178197611881,0.00465800152627453,0.0933717873956666,0.0869939887984295,0.0339135482338016,-0.00259226199818282,0.024052583226893,-0.0383566597339788,69.0 387 | 0.0235457526293458,0.0506801187398187,-0.019139699022379,0.0494153205448459,-0.0634868384392622,-0.0611252336280193,0.00446044580110504,-0.0394933828740919,-0.0259524244351894,-0.0135040182449705,219.0 388 | 0.0199132141783263,-0.044641636506989,-0.0406959404999971,-0.015999222636143,-0.00844872411121698,-0.0175975974392743,0.052321737254237,-0.0394933828740919,-0.0307512098645563,0.00306440941436832,72.0 389 | -0.0454724779400257,-0.044641636506989,0.0153502873418098,-0.0745280244296595,-0.0497273098572509,-0.0172844489774848,-0.0286742944356786,-0.00259226199818282,-0.104364820832166,-0.0756356219674911,201.0 390 | 0.0526060602375023,0.0506801187398187,-0.0245287593917836,0.0563010619323185,-0.00707277125301585,-0.005071658967693,-0.0213110188275045,-0.00259226199818282,0.0267142576335128,-0.0383566597339788,110.0 391 | -0.00551455497881059,0.0506801187398187,0.00133873038135806,-0.0848566365108683,-0.0112006298276192,-0.0166581520539057,0.0486400994501499,-0.0394933828740919,-0.0411803851880079,-0.0880619427119953,51.0 392 | 0.00901559882526763,0.0506801187398187,0.0692408910358548,0.0597439326260547,0.0176943801946045,-0.0232342697514859,-0.0470824834561139,0.0343088588777263,0.103292264911524,0.0734802269665584,277.0 393 | -0.0236772472339084,-0.044641636506989,-0.0697968664947814,-0.0641994123484507,-0.0593589798646588,-0.0504781859271752,0.0191869970174533,-0.0394933828740919,-0.0891368600793477,-0.0507829804784829,63.0 394 | -0.0418399394890061,0.0506801187398187,-0.0299178197611881,-0.00222773986119799,0.0218222387692079,0.0365770864503148,0.0118237214092792,-0.00259226199818282,-0.0411803851880079,0.065196013136889,118.0 395 | -0.0745327855481821,-0.044641636506989,-0.0460850008694016,-0.0435421881860331,-0.0290880169842339,-0.0232342697514859,0.0155053592133662,-0.0394933828740919,-0.0398095943643375,-0.0217882320746399,69.0 396 | 0.0344433679824045,-0.044641636506989,0.0185837235634525,0.0563010619323185,0.0121905687618,-0.0545491159304391,-0.0691723102806364,0.0712099797536354,0.130080609521753,0.00720651632920303,273.0 397 | -0.0600026317441039,-0.044641636506989,0.00133873038135806,-0.0297707054110881,-0.00707277125301585,-0.0216685274425382,0.0118237214092792,-0.00259226199818282,0.0318152175007986,-0.0549250873933176,258.0 398 | -0.0854304009012408,0.0506801187398187,-0.030995631835069,-0.0228849640236156,-0.0634868384392622,-0.0542359674686496,0.0191869970174533,-0.0394933828740919,-0.096433222891784,-0.0342145528191441,43.0 399 | 0.0526060602375023,-0.044641636506989,-0.00405032998804645,-0.0309183289641906,-0.0469754041408486,-0.0583068974719135,-0.0139477432193303,-0.0258399681500055,0.0360557900898319,0.0237749439885419,198.0 400 | 0.0126481372762872,-0.044641636506989,0.0153502873418098,-0.0332135761048244,0.0410855787840237,0.0321930079852613,-0.0029028298070691,-0.00259226199818282,0.0450661683362615,-0.0673514081378217,242.0 401 | 0.0598711371395414,0.0506801187398187,0.0228949718589761,0.0494153205448459,0.0163184273364034,0.0118383579689417,-0.0139477432193303,-0.00259226199818282,0.0395398780720242,0.0196328370737072,232.0 402 | -0.0236772472339084,-0.044641636506989,0.045529025410475,0.090729768869681,-0.0180803941186249,-0.0354470597612776,0.0707299262746723,-0.0394933828740919,-0.0345237153303495,-0.0093619113301358,175.0 403 | 0.0162806757273067,-0.044641636506989,-0.0450071887955207,-0.0573136709609782,-0.0345918284170385,-0.05392281900686,0.0744115640787594,-0.076394503750001,-0.0425721049227942,0.0403433716478807,93.0 404 | 0.110726675453815,0.0506801187398187,-0.0331512559828308,-0.0228849640236156,-0.00432086553661359,0.0202933664372591,-0.0618090346724622,0.0712099797536354,0.0155668445407018,0.0444854785627154,168.0 405 | -0.0200447087828888,-0.044641636506989,0.0972640049567582,-0.00567061055493425,-0.00569681839481472,-0.0238605666750649,-0.0213110188275045,-0.00259226199818282,0.0616858488238662,0.0403433716478807,275.0 406 | -0.0164121703318693,-0.044641636506989,0.0541515220015222,0.0700725447072635,-0.0332158755588373,-0.0279314966783289,0.0081420836051921,-0.0394933828740919,-0.0271286455543265,-0.0093619113301358,293.0 407 | 0.0489735217864827,0.0506801187398187,0.1231314947299,0.0838440274822086,-0.104765424185296,-0.10089508827529,-0.0691723102806364,-0.00259226199818282,0.0366457977933988,-0.0300724459043093,281.0 408 | -0.0563700932930843,-0.044641636506989,-0.0805749872335904,-0.0848566365108683,-0.0373437341334407,-0.0370128020702253,0.0339135482338016,-0.0394933828740919,-0.0561575730950062,-0.137767225690012,72.0 409 | 0.0271782910803654,-0.044641636506989,0.0929527566612346,-0.0527231767141394,0.00806271018719657,0.0397085710682101,-0.0286742944356786,0.021024455362399,-0.0483617248028919,0.0196328370737072,140.0 410 | 0.063503675590561,-0.044641636506989,-0.0503962491649252,0.107944122338362,0.0314539087766158,0.0193539210518905,-0.0176293810234174,0.0236075338237126,0.0580391276638951,0.0403433716478807,189.0 411 | -0.0527375548420648,0.0506801187398187,-0.0115950145052127,0.0563010619323185,0.0562210602242361,0.0729023080179005,-0.0397192078479398,0.0712099797536354,0.0305664873984148,-0.0052198044153011,181.0 412 | -0.00914709342983014,0.0506801187398187,-0.0277621956134263,0.0081008722200108,0.0479653430750293,0.0372033833738938,-0.0286742944356786,0.0343088588777263,0.0660482061630984,-0.0424987666488135,209.0 413 | 0.00538306037424807,-0.044641636506989,0.0584627702970458,-0.0435421881860331,-0.07311850844667,-0.0723985782524425,0.0191869970174533,-0.076394503750001,-0.0514005352605825,-0.0259303389894746,136.0 414 | 0.0744012909436196,-0.044641636506989,0.0854080721440683,0.063186803319791,0.0149424744782022,0.0130909518160999,0.0155053592133662,-0.00259226199818282,0.0062093156165054,0.0859065477110625,261.0 415 | -0.0527375548420648,-0.044641636506989,-0.000816893766403737,-0.0263278347173518,0.0108146159035988,0.00714113104209875,0.0486400994501499,-0.0394933828740919,-0.0358167281015492,0.0196328370737072,113.0 416 | 0.0816663678456587,0.0506801187398187,0.00672779075076256,-0.00452298700183173,0.10988322169408,0.117056241130225,-0.0323559322397657,0.0918746074441444,0.0547240033481791,0.00720651632920303,131.0 417 | -0.00551455497881059,-0.044641636506989,0.00888341489852436,-0.0504279295735057,0.0259500973438113,0.0472241341511589,-0.0434008456520269,0.0712099797536354,0.0148227108412663,0.00306440941436832,174.0 418 | -0.0273097856849279,-0.044641636506989,0.0800190117746638,0.09876313370697,-0.00294491267841247,0.0181013272047324,-0.0176293810234174,0.00331191734196264,-0.0295276227417736,0.036201264733046,257.0 419 | -0.0527375548420648,-0.044641636506989,0.0713965151836166,-0.0745280244296595,-0.0153284884022226,-0.00131387742621863,0.00446044580110504,-0.0214118336448964,-0.0468794828442166,0.00306440941436832,55.0 420 | 0.00901559882526763,-0.044641636506989,-0.0245287593917836,-0.0263278347173518,0.0988755988284711,0.0941964034195887,0.0707299262746723,-0.00259226199818282,-0.02139368094036,0.00720651632920303,84.0 421 | -0.0200447087828888,-0.044641636506989,-0.0547074974604488,-0.0538708002672419,-0.0662387441556644,-0.0573674520865449,0.0118237214092792,-0.0394933828740919,-0.0740888714915354,-0.0052198044153011,42.0 422 | 0.0235457526293458,-0.044641636506989,-0.0363846922044735,6.75072794357462e-05,0.00118294589619092,0.0346981956795776,-0.0434008456520269,0.0343088588777263,-0.0332487872476258,0.0610539062220542,146.0 423 | 0.0380759064334241,0.0506801187398187,0.0164280994156907,0.0218723549949558,0.0397096259258226,0.0450320949186321,-0.0434008456520269,0.0712099797536354,0.049768659920749,0.0154907301588724,212.0 424 | -0.0781653239992017,0.0506801187398187,0.077863387626902,0.0528581912385822,0.0782363059554542,0.0644472995495832,0.0265502726256275,-0.00259226199818282,0.0406722637144977,-0.0093619113301358,233.0 425 | 0.00901559882526763,0.0506801187398187,-0.0396181284261162,0.0287580963824284,0.0383336730676214,0.0735286049414796,-0.0728539480847234,0.108111100629544,0.0155668445407018,-0.0466408735636482,91.0 426 | 0.00175052192322852,0.0506801187398187,0.0110390390462862,-0.0194420933298793,-0.0167044412604238,-0.00381906512053488,-0.0470824834561139,0.0343088588777263,0.024052583226893,0.0237749439885419,111.0 427 | -0.0781653239992017,-0.044641636506989,-0.0406959404999971,-0.081413765817132,-0.100637565610693,-0.112794729823292,0.0228686348215404,-0.076394503750001,-0.0202887477516296,-0.0507829804784829,152.0 428 | 0.030810829531385,0.0506801187398187,-0.0342290680567117,0.0436772026071898,0.0575970130824372,0.0688313780146366,-0.0323559322397657,0.057556565029549,0.0354619386607697,0.0859065477110625,120.0 429 | -0.034574862586967,0.0506801187398187,0.00564997867688165,-0.00567061055493425,-0.07311850844667,-0.062690975936967,-0.00658446761115617,-0.0394933828740919,-0.045420957777041,0.0320591578182113,67.0 430 | 0.0489735217864827,0.0506801187398187,0.088641508365711,0.0872868981759448,0.0355817673512192,0.0215459602844172,-0.0249926566315915,0.0343088588777263,0.0660482061630984,0.131469723774244,310.0 431 | -0.0418399394890061,-0.044641636506989,-0.0331512559828308,-0.0228849640236156,0.0465893902168282,0.0415874618389473,0.056003375058324,-0.0247329345237283,-0.0259524244351894,-0.0383566597339788,94.0 432 | -0.00914709342983014,-0.044641636506989,-0.0568631216082106,-0.0504279295735057,0.0218222387692079,0.0453452433804217,-0.0286742944356786,0.0343088588777263,-0.00991895736315477,-0.0176461251598052,183.0 433 | 0.0707687524926,0.0506801187398187,-0.030995631835069,0.0218723549949558,-0.0373437341334407,-0.0470335528474903,0.0339135482338016,-0.0394933828740919,-0.0149564750249113,-0.00107769750046639,66.0 434 | 0.00901559882526763,-0.044641636506989,0.0552293340754031,-0.00567061055493425,0.0575970130824372,0.0447189464568426,-0.0029028298070691,0.0232385226149535,0.0556835477026737,0.106617082285236,173.0 435 | -0.0273097856849279,-0.044641636506989,-0.0600965578298533,-0.0297707054110881,0.0465893902168282,0.0199802179754696,0.122272855531891,-0.0394933828740919,-0.0514005352605825,-0.0093619113301358,72.0 436 | 0.0162806757273067,-0.044641636506989,0.00133873038135806,0.0081008722200108,0.00531080447079431,0.0108989125835731,0.0302319104297145,-0.0394933828740919,-0.045420957777041,0.0320591578182113,49.0 437 | -0.0127796318808497,-0.044641636506989,-0.0234509473179027,-0.0400993174922969,-0.0167044412604238,0.0046359433477825,-0.0176293810234174,-0.00259226199818282,-0.0384591123013538,-0.0383566597339788,64.0 438 | -0.0563700932930843,-0.044641636506989,-0.074108114790305,-0.0504279295735057,-0.0249601584096305,-0.0470335528474903,0.0928197530991947,-0.076394503750001,-0.0611765950943345,-0.0466408735636482,48.0 439 | 0.0417084448844436,0.0506801187398187,0.0196615356373334,0.0597439326260547,-0.00569681839481472,-0.00256647127337676,-0.0286742944356786,-0.00259226199818282,0.0311929907028023,0.00720651632920303,178.0 440 | -0.00551455497881059,0.0506801187398187,-0.0159062628007364,-0.067642283042187,0.0493412959332305,0.0791652772536912,-0.0286742944356786,0.0343088588777263,-0.0181182673078967,0.0444854785627154,104.0 441 | 0.0417084448844436,0.0506801187398187,-0.0159062628007364,0.0172818607481171,-0.0373437341334407,-0.0138398158977999,-0.0249926566315915,-0.0110795197996419,-0.0468794828442166,0.0154907301588724,132.0 442 | -0.0454724779400257,-0.044641636506989,0.0390621529671896,0.00121513083253827,0.0163184273364034,0.0152829910486266,-0.0286742944356786,0.0265596234937854,0.0445283740214053,-0.0259303389894746,220.0 443 | -0.0454724779400257,-0.044641636506989,-0.0730303027164241,-0.081413765817132,0.0837401173882587,0.0278089295202079,0.17381578478911,-0.0394933828740919,-0.00421985970694603,0.00306440941436832,57.0 444 | -------------------------------------------------------------------------------- /data/diabetes_bad_dist.csv: -------------------------------------------------------------------------------- 1 | AGE,SEX,BMI,BP,S1,S2,S3,S4,S5,S6,Y 2 | 100,0.0506801187398187,0.0616962065186885,0.0218723549949558,-0.0442234984244464,-0.0348207628376986,-0.0434008456520269,-0.00259226199818282,0.0199084208763183,-0.0176461251598052,151.0 3 | -0.0018820165277910,-0.044641636506989,-0.0514740612388061,-0.0263278347173518,-0.00844872411121698,-0.019163339748222,0.0744115640787594,-0.0394933828740919,-0.0683297436244215,-0.09220404962683,75.0 4 | -------------------------------------------------------------------------------- /data/diabetes_bad_schema.csv: -------------------------------------------------------------------------------- 1 | SEX,BMI,BP,S1,S2,S3,S4,S5,S6,Y 2 | 0.0506801187398187,0.0616962065186885,0.0218723549949558,-0.0442234984244464,-0.0348207628376986,-0.0434008456520269,-0.00259226199818282,0.0199084208763183,-0.0176461251598052,151.0 3 | -0.04464163650698,-0.0514740612388061,-0.0263278347173518,-0.00844872411121698,-0.019163339748222,0.0744115640787594,-0.0394933828740919,-0.0683297436244215,-0.09220404962683,75.0 4 | -------------------------------------------------------------------------------- /data/diabetes_missing_values.csv: -------------------------------------------------------------------------------- 1 | AGE,SEX,BMI,BP,S1,S2,S3,S4,S5,S6,Y 2 | ,,,0.0218723549949558,-0.0442234984244464,-0.0348207628376986,-0.0434008456520269,-0.00259226199818282,0.0199084208763183,-0.0176461251598052,151.0 3 | -0.001882016527791,-0.044641636506989,-0.0514740612388061,-0.0263278347173518,-0.00844872411121698,-0.019163339748222,0.0744115640787594,-0.0394933828740919,-0.0683297436244215,-0.09220404962683,75.0 4 | -------------------------------------------------------------------------------- /pictures/github-actions-azure-machine-learning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marvinbuss/MLDevOps/43a4f9b7ab86b0540c206158d35f7bbf910aa6ed/pictures/github-actions-azure-machine-learning.png -------------------------------------------------------------------------------- /pictures/ml-lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marvinbuss/MLDevOps/43a4f9b7ab86b0540c206158d35f7bbf910aa6ed/pictures/ml-lifecycle.png --------------------------------------------------------------------------------