From 41a297275b36aa79ff52a719c2f92463e4a603a5 Mon Sep 17 00:00:00 2001 From: Eric Golinko Date: Mon, 26 Feb 2024 08:55:56 -0500 Subject: [PATCH 1/2] Add ML Code --- .github/workflows/README.md | 7 + .../mlops_stacks_gcp_fs-bundle-cd-prod.yml | 34 +++ .../mlops_stacks_gcp_fs-bundle-cd-staging.yml | 34 +++ .../mlops_stacks_gcp_fs-bundle-ci.yml | 93 ++++++ ...stacks_gcp_fs-lint-cicd-workflow-files.yml | 19 ++ .../mlops_stacks_gcp_fs-run-tests-fs.yml | 59 ++++ mlops_stacks_gcp_fs/README.md | 5 + mlops_stacks_gcp_fs/__init__.py | 0 .../assets/batch-inference-workflow-asset.yml | 41 +++ .../feature-engineering-workflow-asset.yml | 64 ++++ .../assets/ml-artifacts-asset.yml | 54 ++++ .../assets/model-workflow-asset.yml | 99 ++++++ .../assets/monitoring-workflow-asset.yml | 1 + mlops_stacks_gcp_fs/databricks.yml | 38 +++ .../deployment/batch_inference/README.md | 42 +++ .../notebooks/BatchInference.py | 99 ++++++ .../deployment/batch_inference/predict.py | 32 ++ .../deployment/model_deployment/deploy.py | 34 +++ .../notebooks/ModelDeployment.py | 52 ++++ .../feature_engineering/README.md | 4 + .../feature_engineering/__init__.py | 0 .../feature_engineering/features/__init__.py | 0 .../features/dropoff_features.py | 64 ++++ .../features/pickup_features.py | 63 ++++ .../notebooks/GenerateAndWriteFeatures.py | 139 +++++++++ mlops_stacks_gcp_fs/monitoring/README.md | 5 + mlops_stacks_gcp_fs/pytest.ini | 4 + mlops_stacks_gcp_fs/requirements.txt | 8 + mlops_stacks_gcp_fs/tests/__init__.py | 0 .../tests/feature_engineering/__init__.py | 0 .../dropoff_features_test.py | 44 +++ .../pickup_features_test.py | 42 +++ .../tests/training/__init__.py | 0 .../tests/training/test_notebooks.py | 9 + mlops_stacks_gcp_fs/training/__init__.py | 0 .../training/data/sample.parquet | Bin 0 -> 232389 bytes .../notebooks/TrainWithFeatureStore.py | 280 +++++++++++++++++ .../training/steps/__init__.py | 0 .../training/steps/custom_metrics.py | 47 +++ mlops_stacks_gcp_fs/training/steps/ingest.py | 40 +++ mlops_stacks_gcp_fs/training/steps/split.py | 37 +++ mlops_stacks_gcp_fs/training/steps/train.py | 17 ++ .../training/steps/transform.py | 62 ++++ mlops_stacks_gcp_fs/utils.py | 21 ++ mlops_stacks_gcp_fs/validation/README.md | 2 + .../validation/notebooks/ModelValidation.py | 283 ++++++++++++++++++ mlops_stacks_gcp_fs/validation/validation.py | 41 +++ test-requirements.txt | 2 + 48 files changed, 2021 insertions(+) create mode 100644 .github/workflows/README.md create mode 100644 .github/workflows/mlops_stacks_gcp_fs-bundle-cd-prod.yml create mode 100644 .github/workflows/mlops_stacks_gcp_fs-bundle-cd-staging.yml create mode 100644 .github/workflows/mlops_stacks_gcp_fs-bundle-ci.yml create mode 100644 .github/workflows/mlops_stacks_gcp_fs-lint-cicd-workflow-files.yml create mode 100644 .github/workflows/mlops_stacks_gcp_fs-run-tests-fs.yml create mode 100644 mlops_stacks_gcp_fs/README.md create mode 100644 mlops_stacks_gcp_fs/__init__.py create mode 100644 mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml create mode 100644 mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml create mode 100644 mlops_stacks_gcp_fs/assets/ml-artifacts-asset.yml create mode 100644 mlops_stacks_gcp_fs/assets/model-workflow-asset.yml create mode 100644 mlops_stacks_gcp_fs/assets/monitoring-workflow-asset.yml create mode 100644 mlops_stacks_gcp_fs/databricks.yml create mode 100644 mlops_stacks_gcp_fs/deployment/batch_inference/README.md create mode 100644 mlops_stacks_gcp_fs/deployment/batch_inference/notebooks/BatchInference.py create mode 100644 mlops_stacks_gcp_fs/deployment/batch_inference/predict.py create mode 100644 mlops_stacks_gcp_fs/deployment/model_deployment/deploy.py create mode 100644 mlops_stacks_gcp_fs/deployment/model_deployment/notebooks/ModelDeployment.py create mode 100644 mlops_stacks_gcp_fs/feature_engineering/README.md create mode 100644 mlops_stacks_gcp_fs/feature_engineering/__init__.py create mode 100644 mlops_stacks_gcp_fs/feature_engineering/features/__init__.py create mode 100644 mlops_stacks_gcp_fs/feature_engineering/features/dropoff_features.py create mode 100644 mlops_stacks_gcp_fs/feature_engineering/features/pickup_features.py create mode 100644 mlops_stacks_gcp_fs/feature_engineering/notebooks/GenerateAndWriteFeatures.py create mode 100644 mlops_stacks_gcp_fs/monitoring/README.md create mode 100644 mlops_stacks_gcp_fs/pytest.ini create mode 100644 mlops_stacks_gcp_fs/requirements.txt create mode 100644 mlops_stacks_gcp_fs/tests/__init__.py create mode 100644 mlops_stacks_gcp_fs/tests/feature_engineering/__init__.py create mode 100644 mlops_stacks_gcp_fs/tests/feature_engineering/dropoff_features_test.py create mode 100644 mlops_stacks_gcp_fs/tests/feature_engineering/pickup_features_test.py create mode 100644 mlops_stacks_gcp_fs/tests/training/__init__.py create mode 100644 mlops_stacks_gcp_fs/tests/training/test_notebooks.py create mode 100644 mlops_stacks_gcp_fs/training/__init__.py create mode 100644 mlops_stacks_gcp_fs/training/data/sample.parquet create mode 100644 mlops_stacks_gcp_fs/training/notebooks/TrainWithFeatureStore.py create mode 100644 mlops_stacks_gcp_fs/training/steps/__init__.py create mode 100644 mlops_stacks_gcp_fs/training/steps/custom_metrics.py create mode 100644 mlops_stacks_gcp_fs/training/steps/ingest.py create mode 100644 mlops_stacks_gcp_fs/training/steps/split.py create mode 100644 mlops_stacks_gcp_fs/training/steps/train.py create mode 100644 mlops_stacks_gcp_fs/training/steps/transform.py create mode 100644 mlops_stacks_gcp_fs/utils.py create mode 100644 mlops_stacks_gcp_fs/validation/README.md create mode 100644 mlops_stacks_gcp_fs/validation/notebooks/ModelValidation.py create mode 100644 mlops_stacks_gcp_fs/validation/validation.py create mode 100644 test-requirements.txt diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..04356c8 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,7 @@ +# CI/CD Workflow Definitions +This directory contains CI/CD workflow definitions using [GitHub Actions](https://docs.github.com/en/actions), +under ``workflows``. These workflows cover testing and deployment of both ML code (for model training, batch inference, etc) and the +Databricks ML asset definitions under ``mlops_stacks_gcp_fs/assets``. + +To set up CI/CD for a new project, +please refer to [ML asset config - set up CI CD](../../mlops_stacks_gcp_fs/assets/README.md#set-up-ci-and-cd). diff --git a/.github/workflows/mlops_stacks_gcp_fs-bundle-cd-prod.yml b/.github/workflows/mlops_stacks_gcp_fs-bundle-cd-prod.yml new file mode 100644 index 0000000..c8c8168 --- /dev/null +++ b/.github/workflows/mlops_stacks_gcp_fs-bundle-cd-prod.yml @@ -0,0 +1,34 @@ +# This GitHub workflow deploys Bundle assets (ML asset config and more) +# defined under mlops_stacks_gcp_fs/assets/* +# and mlops_stacks_gcp_fs/databricks.yml with prod deployment target configs, +# when PRs are merged into the release branch +name: Bundle Deployment for mlops_stacks_gcp_fs Prod + +on: + push: + branches: + - 'release' + workflow_dispatch: + +defaults: + run: + working-directory: ./mlops_stacks_gcp_fs + +env: + DATABRICKS_TOKEN: ${{ secrets.PROD_WORKSPACE_TOKEN }} + +jobs: + prod: + concurrency: mlops_stacks_gcp_fs-prod-bundle-job + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: databricks/setup-cli@v0.211.0 + - name: Validate Bundle For Prod + id: validate + run: | + databricks bundle validate -t prod + - name: Deploy Bundle to Prod + id: deploy + run: | + databricks bundle deploy -t prod diff --git a/.github/workflows/mlops_stacks_gcp_fs-bundle-cd-staging.yml b/.github/workflows/mlops_stacks_gcp_fs-bundle-cd-staging.yml new file mode 100644 index 0000000..e3cb067 --- /dev/null +++ b/.github/workflows/mlops_stacks_gcp_fs-bundle-cd-staging.yml @@ -0,0 +1,34 @@ +# This GitHub workflow deploys Bundle assets (ML asset config and more) +# defined under mlops_stacks_gcp_fs/assets/* +# and mlops_stacks_gcp_fs/databricks.yml with staging deployment target configs, +# when PRs are merged into the default branch +name: Bundle Deployment for mlops_stacks_gcp_fs Staging + +on: + push: + branches: + - 'main' + workflow_dispatch: + +defaults: + run: + working-directory: ./mlops_stacks_gcp_fs + +env: + DATABRICKS_TOKEN: ${{ secrets.STAGING_WORKSPACE_TOKEN }} + +jobs: + staging: + concurrency: mlops_stacks_gcp_fs-staging-bundle-job + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: databricks/setup-cli@v0.211.0 + - name: Validate Bundle For Staging + id: validate + run: | + databricks bundle validate -t staging + - name: Deploy Bundle to Staging + id: deploy + run: | + databricks bundle deploy -t staging diff --git a/.github/workflows/mlops_stacks_gcp_fs-bundle-ci.yml b/.github/workflows/mlops_stacks_gcp_fs-bundle-ci.yml new file mode 100644 index 0000000..02ac728 --- /dev/null +++ b/.github/workflows/mlops_stacks_gcp_fs-bundle-ci.yml @@ -0,0 +1,93 @@ +# This GitHub workflow validates Bundle config (ML asset config and more) +# defined under mlops_stacks_gcp_fs/assets/* +# and mlops_stacks_gcp_fs/databricks.yml, when PRs are merged into the main branch +name: Bundle validation for mlops_stacks_gcp_fs + +on: + workflow_dispatch: + pull_request_target: + +defaults: + run: + working-directory: ./mlops_stacks_gcp_fs/ + +env: + STAGING_WORKSPACE_TOKEN: ${{ secrets.STAGING_WORKSPACE_TOKEN }} + PROD_WORKSPACE_TOKEN: ${{ secrets.PROD_WORKSPACE_TOKEN }} + +jobs: + staging: + concurrency: mlops_stacks_gcp_fs-staging-bundle-job + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: databricks/setup-cli@v0.211.0 + - name: Validate Bundle For Staging + id: validate + env: + DATABRICKS_TOKEN: ${{ env.STAGING_WORKSPACE_TOKEN }} + run: | + databricks bundle validate -t staging > ../validate_output.txt + - name: Create Comment with Bundle Configuration + uses: actions/github-script@v6 + id: comment + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const fileContents = fs.readFileSync('validate_output.txt', 'utf8'); + const output = `#### Bundle Staging Config Validated 🖌 +
Staging Validation Output + + \`\`\`\n + ${fileContents} + \`\`\` + +
` + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: output + }) + + prod: + concurrency: mlops_stacks_gcp_fs-prod-bundle-job + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: databricks/setup-cli@v0.211.0 + - name: Validate Bundle For Prod + id: validate + env: + DATABRICKS_TOKEN: ${{ env.PROD_WORKSPACE_TOKEN }} + run: | + databricks bundle validate -t prod > ../validate_output.txt + - name: Create Comment with Bundle Configuration + uses: actions/github-script@v6 + id: comment + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const fileContents = fs.readFileSync('validate_output.txt', 'utf8'); + const output = `#### Bundle Prod Config Validated 🖌 +
Prod Validation Output + + \`\`\`\n + ${fileContents} + \`\`\` + +
` + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: output + }) diff --git a/.github/workflows/mlops_stacks_gcp_fs-lint-cicd-workflow-files.yml b/.github/workflows/mlops_stacks_gcp_fs-lint-cicd-workflow-files.yml new file mode 100644 index 0000000..59a5c5b --- /dev/null +++ b/.github/workflows/mlops_stacks_gcp_fs-lint-cicd-workflow-files.yml @@ -0,0 +1,19 @@ +name: Lint CI/CD workflow files +on: + pull_request: + paths: + - '.github/workflows/**' + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Download actionlint + id: get_actionlint + run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) + shell: bash + - name: Check workflow files + run: ${{ steps.get_actionlint.outputs.executable }} -color + shell: bash diff --git a/.github/workflows/mlops_stacks_gcp_fs-run-tests-fs.yml b/.github/workflows/mlops_stacks_gcp_fs-run-tests-fs.yml new file mode 100644 index 0000000..7156cfc --- /dev/null +++ b/.github/workflows/mlops_stacks_gcp_fs-run-tests-fs.yml @@ -0,0 +1,59 @@ +name: Feature and Training Integration Tests for mlops_stacks_gcp_fs +on: + workflow_dispatch: + pull_request: + +defaults: + run: + working-directory: ./mlops_stacks_gcp_fs/ + +env: + DATABRICKS_TOKEN: ${{ secrets.STAGING_WORKSPACE_TOKEN }} + +concurrency: mlops_stacks_gcp_fs-feature-training-integration-test-staging + +jobs: + unit_tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.8 + # Feature store tests bring up a local Spark session, so Java is required. + - uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '11' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install -r ../test-requirements.txt + - name: Run tests with pytest + run: | + pytest + + integration_test: + needs: unit_tests + runs-on: ubuntu-22.04 + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - uses: databricks/setup-cli@v0.211.0 + - name: Validate Bundle For Test Deployment Target in Staging Workspace + id: validate + run: | + databricks bundle validate -t test + - name: Deploy Bundle to Test Deployment Target in Staging Workspace + id: deploy + run: | + databricks bundle deploy -t test + - name: Run Feature Engineering Workflow for Test Deployment Target in Staging Workspace + id: feature_engineering + run: | + databricks bundle run write_feature_table_job -t test + - name: Run Training Workflow for Test Deployment Target in Staging Workspace + id: training + run: | + databricks bundle run model_training_job -t test diff --git a/mlops_stacks_gcp_fs/README.md b/mlops_stacks_gcp_fs/README.md new file mode 100644 index 0000000..a7a72e9 --- /dev/null +++ b/mlops_stacks_gcp_fs/README.md @@ -0,0 +1,5 @@ +# mlops_stacks_gcp_fs + +This directory contains python code, notebooks and ML asset configs related to one ML project. + +See the [Project overview](../docs/project-overview.md) for details on code structure of project directory. \ No newline at end of file diff --git a/mlops_stacks_gcp_fs/__init__.py b/mlops_stacks_gcp_fs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml b/mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml new file mode 100644 index 0000000..3a556c8 --- /dev/null +++ b/mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml @@ -0,0 +1,41 @@ +new_cluster: &new_cluster + new_cluster: + num_workers: 3 + spark_version: 13.3.x-cpu-ml-scala2.12 + node_type_id: n2-highmem-4 + custom_tags: + clusterSource: mlops-stack/0.2 + +common_permissions: &permissions + permissions: + - level: CAN_VIEW + group_name: users + +resources: + jobs: + batch_inference_job: + name: ${bundle.target}-mlops_stacks_gcp_fs-batch-inference-job + tasks: + - task_key: batch_inference_job + <<: *new_cluster + notebook_task: + notebook_path: ../deployment/batch_inference/notebooks/BatchInference.py + base_parameters: + env: ${bundle.target} + input_table_name: hive_metastore.default.taxi_scoring_sample_feature_store_inference_input + output_table_name: ${bundle.target}_mlops_stacks_gcp_fs_predictions + model_name: ${var.model_name} + # git source information of current ML asset deployment. It will be persisted as part of the workflow run + git_source_info: url:${bundle.git.origin_url}; branch:${bundle.git.branch}; commit:${bundle.git.commit} + + schedule: + quartz_cron_expression: "0 0 11 * * ?" # daily at 11am + timezone_id: UTC + <<: *permissions + # If you want to turn on notifications for this job, please uncomment the below code, + # and provide a list of emails to the on_failure argument. + # + # email_notifications: + # on_failure: + # - first@company.com + # - second@company.com diff --git a/mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml b/mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml new file mode 100644 index 0000000..4dece72 --- /dev/null +++ b/mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml @@ -0,0 +1,64 @@ +new_cluster: &new_cluster + new_cluster: + num_workers: 3 + spark_version: 13.3.x-cpu-ml-scala2.12 + node_type_id: n2-highmem-4 + custom_tags: + clusterSource: mlops-stack/0.2 + +common_permissions: &permissions + permissions: + - level: CAN_VIEW + group_name: users + +resources: + jobs: + write_feature_table_job: + name: ${bundle.target}-mlops_stacks_gcp_fs-write-feature-table-job + job_clusters: + - job_cluster_key: write_feature_table_job_cluster + <<: *new_cluster + tasks: + - task_key: PickupFeatures + job_cluster_key: write_feature_table_job_cluster + notebook_task: + notebook_path: ../feature_engineering/notebooks/GenerateAndWriteFeatures.py + base_parameters: + # TODO modify these arguments to reflect your setup. + input_table_path: /databricks-datasets/nyctaxi-with-zipcodes/subsampled + # TODO: Empty start/end dates will process the whole range. Update this as needed to process recent data. + input_start_date: "" + input_end_date: "" + timestamp_column: tpep_pickup_datetime + output_table_name: feature_store_taxi_example.${bundle.target}_mlops_stacks_gcp_fs_trip_pickup_features + features_transform_module: pickup_features + primary_keys: zip + # git source information of current ML asset deployment. It will be persisted as part of the workflow run + git_source_info: url:${bundle.git.origin_url}; branch:${bundle.git.branch}; commit:${bundle.git.commit} + - task_key: DropoffFeatures + job_cluster_key: write_feature_table_job_cluster + notebook_task: + notebook_path: ../feature_engineering/notebooks/GenerateAndWriteFeatures.py + base_parameters: + # TODO: modify these arguments to reflect your setup. + input_table_path: /databricks-datasets/nyctaxi-with-zipcodes/subsampled + # TODO: Empty start/end dates will process the whole range. Update this as needed to process recent data. + input_start_date: "" + input_end_date: "" + timestamp_column: tpep_dropoff_datetime + output_table_name: feature_store_taxi_example.${bundle.target}_mlops_stacks_gcp_fs_trip_dropoff_features + features_transform_module: dropoff_features + primary_keys: zip + # git source information of current ML asset deployment. It will be persisted as part of the workflow run + git_source_info: url:${bundle.git.origin_url}; branch:${bundle.git.branch}; commit:${bundle.git.commit} + schedule: + quartz_cron_expression: "0 0 7 * * ?" # daily at 7am + timezone_id: UTC + <<: *permissions + # If you want to turn on notifications for this job, please uncomment the below code, + # and provide a list of emails to the on_failure argument. + # + # email_notifications: + # on_failure: + # - first@company.com + # - second@company.com diff --git a/mlops_stacks_gcp_fs/assets/ml-artifacts-asset.yml b/mlops_stacks_gcp_fs/assets/ml-artifacts-asset.yml new file mode 100644 index 0000000..3b3b305 --- /dev/null +++ b/mlops_stacks_gcp_fs/assets/ml-artifacts-asset.yml @@ -0,0 +1,54 @@ +# Deployment target specific values +targets: + dev: + resources: + models: + model: + description: MLflow registered model for the "mlops_stacks_gcp_fs" ML Project for ${bundle.target} deployment target. + + test: + resources: + models: + model: + description: MLflow registered model for the "mlops_stacks_gcp_fs" ML Project for ${bundle.target} deployment target. + + staging: + resources: + models: + model: + description: MLflow registered model for the "mlops_stacks_gcp_fs" ML Project for ${bundle.target} deployment target. + + prod: + resources: + models: + model: + description: | + MLflow registered model for the "mlops_stacks_gcp_fs" ML Project. See the corresponding [Git repo]($#{var.git_repo_url}) for details on the project. + + Links: + * [Recurring model training job](https://416411475796958.8.gcp.databricks.com#job/${resources.jobs.model_training_job.id}): trains fresh model versions using the latest ML code. + * [Recurring batch inference job](https://416411475796958.8.gcp.databricks.com#job/${resources.jobs.batch_inference_job.id}): applies the latest ${bundle.target} model version for batch inference. + +# Allow users to read the experiment and the model +common_permissions: &permissions + permissions: + - level: CAN_READ + group_name: users + + + +# Defines model and experiments +resources: + models: + model: + name: ${var.model_name} + <<: *permissions + depends_on: + - resources.jobs.model_training_job.id + - resources.jobs.batch_inference_job.id + + experiments: + experiment: + name: ${var.experiment_name} + <<: *permissions + description: MLflow Experiment used to track runs for mlops_stacks_gcp_fs project. diff --git a/mlops_stacks_gcp_fs/assets/model-workflow-asset.yml b/mlops_stacks_gcp_fs/assets/model-workflow-asset.yml new file mode 100644 index 0000000..8b920ef --- /dev/null +++ b/mlops_stacks_gcp_fs/assets/model-workflow-asset.yml @@ -0,0 +1,99 @@ +new_cluster: &new_cluster + new_cluster: + num_workers: 3 + spark_version: 13.3.x-cpu-ml-scala2.12 + node_type_id: n2-highmem-4 + custom_tags: + clusterSource: mlops-stack/0.2 + +common_permissions: &permissions + permissions: + - level: CAN_VIEW + group_name: users + +resources: + jobs: + model_training_job: + name: ${bundle.target}-mlops_stacks_gcp_fs-model-training-job + job_clusters: + - job_cluster_key: model_training_job_cluster + <<: *new_cluster + tasks: + - task_key: Train + job_cluster_key: model_training_job_cluster + notebook_task: + notebook_path: ../training/notebooks/TrainWithFeatureStore.py + base_parameters: + env: ${bundle.target} + # TODO: Update training_data_path + training_data_path: /databricks-datasets/nyctaxi-with-zipcodes/subsampled + experiment_name: ${var.experiment_name} + model_name: ${var.model_name} + pickup_features_table: feature_store_taxi_example.${bundle.target}_mlops_stacks_gcp_fs_trip_pickup_features + dropoff_features_table: feature_store_taxi_example.${bundle.target}_mlops_stacks_gcp_fs_trip_dropoff_features + # git source information of current ML asset deployment. It will be persisted as part of the workflow run + git_source_info: url:${bundle.git.origin_url}; branch:${bundle.git.branch}; commit:${bundle.git.commit} + - task_key: ModelValidation + job_cluster_key: model_training_job_cluster + depends_on: + - task_key: Train + notebook_task: + notebook_path: ../validation/notebooks/ModelValidation.py + base_parameters: + experiment_name: ${var.experiment_name} + # The `run_mode` defines whether model validation is enabled or not. + # It can be one of the three values: + # `disabled` : Do not run the model validation notebook. + # `dry_run` : Run the model validation notebook. Ignore failed model validation rules and proceed to move + # model to Production stage. + # `enabled` : Run the model validation notebook. Move model to Production stage only if all model validation + # rules are passing. + # TODO: update run_mode + run_mode: dry_run + # Whether to load the current registered "Production" stage model as baseline. + # Baseline model is a requirement for relative change and absolute change validation thresholds. + # TODO: update enable_baseline_comparison + enable_baseline_comparison: "false" + # Please refer to data parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate + # TODO: update validation_input + validation_input: SELECT * FROM delta.`dbfs:/databricks-datasets/nyctaxi-with-zipcodes/subsampled` + # A string describing the model type. The model type can be either "regressor" and "classifier". + # Please refer to model_type parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate + # TODO: update model_type + model_type: regressor + # The string name of a column from data that contains evaluation labels. + # Please refer to targets parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate + # TODO: targets + targets: fare_amount + # Specifies the name of the function in mlops_stacks_gcp_fs/training_validation_deployment/validation/validation.py that returns custom metrics. + # TODO(optional): custom_metrics_loader_function + custom_metrics_loader_function: custom_metrics + # Specifies the name of the function in mlops_stacks_gcp_fs/training_validation_deployment/validation/validation.py that returns model validation thresholds. + # TODO(optional): validation_thresholds_loader_function + validation_thresholds_loader_function: validation_thresholds + # Specifies the name of the function in mlops_stacks_gcp_fs/training_validation_deployment/validation/validation.py that returns evaluator_config. + # TODO(optional): evaluator_config_loader_function + evaluator_config_loader_function: evaluator_config + # git source information of current ML asset deployment. It will be persisted as part of the workflow run + git_source_info: url:${bundle.git.origin_url}; branch:${bundle.git.branch}; commit:${bundle.git.commit} + - task_key: ModelDeployment + job_cluster_key: model_training_job_cluster + depends_on: + - task_key: ModelValidation + notebook_task: + notebook_path: ../deployment/model_deployment/notebooks/ModelDeployment.py + base_parameters: + env: ${bundle.target} + # git source information of current ML asset deployment. It will be persisted as part of the workflow run + git_source_info: url:${bundle.git.origin_url}; branch:${bundle.git.branch}; commit:${bundle.git.commit} + schedule: + quartz_cron_expression: "0 0 9 * * ?" # daily at 9am + timezone_id: UTC + <<: *permissions + # If you want to turn on notifications for this job, please uncomment the below code, + # and provide a list of emails to the on_failure argument. + # + # email_notifications: + # on_failure: + # - first@company.com + # - second@company.com diff --git a/mlops_stacks_gcp_fs/assets/monitoring-workflow-asset.yml b/mlops_stacks_gcp_fs/assets/monitoring-workflow-asset.yml new file mode 100644 index 0000000..a4d505d --- /dev/null +++ b/mlops_stacks_gcp_fs/assets/monitoring-workflow-asset.yml @@ -0,0 +1 @@ +# TODO: Add data monitoring support for mlops diff --git a/mlops_stacks_gcp_fs/databricks.yml b/mlops_stacks_gcp_fs/databricks.yml new file mode 100644 index 0000000..fee3f77 --- /dev/null +++ b/mlops_stacks_gcp_fs/databricks.yml @@ -0,0 +1,38 @@ +# The name of the bundle. run `databricks bundle schema` to see the full bundle settings schema. +bundle: + name: mlops_stacks_gcp_fs + +variables: + experiment_name: + description: Experiment name for the model training. + default: /Users/${workspace.current_user.userName}/${bundle.target}-mlops_stacks_gcp_fs-experiment + model_name: + description: Model name for the model training. + default: ${bundle.target}-mlops_stacks_gcp_fs-model + +include: + # Assets folder contains ML artifact assets for the ml project that defines model and experiment + # And workflows assets for the ml project including model training -> validation -> deployment, + # feature engineering, batch inference, data monitoring, metric refresh, alerts and triggering retraining + - ./assets/*.yml + +# Deployment Target specific values for workspace +targets: + dev: + default: true + workspace: + # TODO: add dev workspace URL + host: + + staging: + workspace: + host: https://416411475796958.8.gcp.databricks.com + + prod: + workspace: + host: https://416411475796958.8.gcp.databricks.com + + test: + workspace: + host: https://416411475796958.8.gcp.databricks.com + diff --git a/mlops_stacks_gcp_fs/deployment/batch_inference/README.md b/mlops_stacks_gcp_fs/deployment/batch_inference/README.md new file mode 100644 index 0000000..b801e10 --- /dev/null +++ b/mlops_stacks_gcp_fs/deployment/batch_inference/README.md @@ -0,0 +1,42 @@ +# Batch Inference +To set up batch inference job via scheduled Databricks workflow, please refer to [mlops_stacks_gcp_fs/assets/README.md](../../assets/README.md) + +## Prepare the batch inference input table for the example Project +Please run the following code in a notebook to generate the example batch inference input table. + +``` +from pyspark.sql.functions import to_timestamp, lit +from pyspark.sql.types import IntegerType +import math +from datetime import timedelta, timezone + +def rounded_unix_timestamp(dt, num_minutes=15): + """ + Ceilings datetime dt to interval num_minutes, then returns the unix timestamp. + """ + nsecs = dt.minute * 60 + dt.second + dt.microsecond * 1e-6 + delta = math.ceil(nsecs / (60 * num_minutes)) * (60 * num_minutes) - nsecs + return int((dt + timedelta(seconds=delta)).replace(tzinfo=timezone.utc).timestamp()) + + +rounded_unix_timestamp_udf = udf(rounded_unix_timestamp, IntegerType()) + +df = spark.table("delta.`dbfs:/databricks-datasets/nyctaxi-with-zipcodes/subsampled`") +df.withColumn( + "rounded_pickup_datetime", + to_timestamp(rounded_unix_timestamp_udf(df["tpep_pickup_datetime"], lit(15))), +).withColumn( + "rounded_dropoff_datetime", + to_timestamp(rounded_unix_timestamp_udf(df["tpep_dropoff_datetime"], lit(30))), +).drop( + "tpep_pickup_datetime" +).drop( + "tpep_dropoff_datetime" +).drop( + "fare_amount" +).write.mode( + "overwrite" +).saveAsTable( + name="hive_metastore.default.taxi_scoring_sample_feature_store_inference_input" +) +``` diff --git a/mlops_stacks_gcp_fs/deployment/batch_inference/notebooks/BatchInference.py b/mlops_stacks_gcp_fs/deployment/batch_inference/notebooks/BatchInference.py new file mode 100644 index 0000000..73d26bd --- /dev/null +++ b/mlops_stacks_gcp_fs/deployment/batch_inference/notebooks/BatchInference.py @@ -0,0 +1,99 @@ +# Databricks notebook source +################################################################################## +# Batch Inference Notebook +# +# This notebook is an example of applying a model for batch inference against an input delta table, +# It is configured and can be executed as the batch_inference_job in the batch_inference_job workflow defined under +# ``mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml`` +# +# Parameters: +# +# * env (optional) - String name of the current environment (dev, staging, or prod). Defaults to "dev" +# * input_table_name (required) - Delta table name containing your input data. +# * output_table_name (required) - Delta table name where the predictions will be written to. +# Note that this will create a new version of the Delta table if +# the table already exists +# * model_name (required) - The name of the model to be used in batch inference. +################################################################################## + + +# List of input args needed to run the notebook as a job. +# Provide them via DB widgets or notebook arguments. +# +# Name of the current environment +dbutils.widgets.dropdown("env", "dev", ["dev", "staging", "prod"], "Environment Name") +# A Hive-registered Delta table containing the input features. +dbutils.widgets.text("input_table_name", "", label="Input Table Name") +# Delta table to store the output predictions. +dbutils.widgets.text("output_table_name", "", label="Output Table Name") +# Batch inference model name +dbutils.widgets.text( + "model_name", "dev-mlops_stacks_gcp_fs-model", label="Model Name" +) + + +# COMMAND ---------- + +import os + +notebook_path = '/Workspace/' + os.path.dirname(dbutils.notebook.entry_point.getDbutils().notebook().getContext().notebookPath().get()) +%cd $notebook_path + +# COMMAND ---------- + +# MAGIC %pip install -r ../../../requirements.txt + +# COMMAND ---------- + +dbutils.library.restartPython() + +# COMMAND ---------- + +import sys +import os +notebook_path = '/Workspace/' + os.path.dirname(dbutils.notebook.entry_point.getDbutils().notebook().getContext().notebookPath().get()) +%cd $notebook_path +%cd .. +sys.path.append("../..") + +# COMMAND ---------- + +# DBTITLE 1,Define input and output variables +from utils import get_deployed_model_stage_for_env + +env = dbutils.widgets.get("env") +input_table_name = dbutils.widgets.get("input_table_name") +output_table_name = dbutils.widgets.get("output_table_name") +model_name = dbutils.widgets.get("model_name") +assert input_table_name != "", "input_table_name notebook parameter must be specified" +assert output_table_name != "", "output_table_name notebook parameter must be specified" +assert model_name != "", "model_name notebook parameter must be specified" +stage = get_deployed_model_stage_for_env(env) +model_uri = f"models:/{model_name}/{stage}" + +# COMMAND ---------- + +from mlflow import MlflowClient + +# Get model version from stage +model_version_infos = MlflowClient().search_model_versions("name = '%s'" % model_name) +model_version = max( + int(version.version) + for version in model_version_infos + if version.current_stage == stage +) + +# COMMAND ---------- + +# Get datetime +from datetime import datetime + +ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + +# COMMAND ---------- +# DBTITLE 1,Load model and run inference + +from predict import predict_batch + +predict_batch(spark, model_uri, input_table_name, output_table_name, model_version, ts) +dbutils.notebook.exit(output_table_name) diff --git a/mlops_stacks_gcp_fs/deployment/batch_inference/predict.py b/mlops_stacks_gcp_fs/deployment/batch_inference/predict.py new file mode 100644 index 0000000..d9d2975 --- /dev/null +++ b/mlops_stacks_gcp_fs/deployment/batch_inference/predict.py @@ -0,0 +1,32 @@ +import mlflow +from pyspark.sql.functions import struct, lit, to_timestamp + + +def predict_batch( + spark_session, model_uri, input_table_name, output_table_name, model_version, ts +): + """ + Apply the model at the specified URI for batch inference on the table with name input_table_name, + writing results to the table with name output_table_name + """ + + table = spark_session.table(input_table_name) + + from databricks.feature_store import FeatureStoreClient + + fs_client = FeatureStoreClient() + + prediction_df = fs_client.score_batch( + model_uri, + table + ) + output_df = ( + prediction_df.withColumn("prediction", prediction_df["prediction"]) + .withColumn("model_version", lit(model_version)) + .withColumn("inference_timestamp", to_timestamp(lit(ts))) + ) + + output_df.display() + # Model predictions are written to the Delta table provided as input. + # Delta is the default format in Databricks Runtime 8.0 and above. + output_df.write.format("delta").mode("overwrite").saveAsTable(output_table_name) \ No newline at end of file diff --git a/mlops_stacks_gcp_fs/deployment/model_deployment/deploy.py b/mlops_stacks_gcp_fs/deployment/model_deployment/deploy.py new file mode 100644 index 0000000..a5f3616 --- /dev/null +++ b/mlops_stacks_gcp_fs/deployment/model_deployment/deploy.py @@ -0,0 +1,34 @@ +import sys +import pathlib + +sys.path.append(str(pathlib.Path(__file__).parent.parent.parent.resolve())) +from utils import get_deployed_model_stage_for_env +from mlflow.tracking import MlflowClient + + +def deploy(model_uri, env): + """ + Deploys an already-registered model produced by moving it into the appropriate stage for model deployment. + + :param model_uri: URI of the model to deploy. Must be in the format "models://", as described in + https://www.mlflow.org/docs/latest/model-registry.html#fetching-an-mlflow-model-from-the-model-registry + :param env: name of the environment in which we're performing deployment, i.e one of "dev", "staging", "prod". + Defaults to "dev" + :return: + """ + _, model_name, version = model_uri.split("/") + client = MlflowClient() + mv = client.get_model_version(model_name, version) + target_stage = get_deployed_model_stage_for_env(env) + if mv.current_stage != target_stage: + client.transition_model_version_stage( + name=model_name, + version=version, + stage=target_stage, + archive_existing_versions=True, + ) + print(f"Successfully deployed model with URI {model_uri} to {env}") + + +if __name__ == "__main__": + deploy(model_uri=sys.argv[1], env=sys.argv[2]) diff --git a/mlops_stacks_gcp_fs/deployment/model_deployment/notebooks/ModelDeployment.py b/mlops_stacks_gcp_fs/deployment/model_deployment/notebooks/ModelDeployment.py new file mode 100644 index 0000000..cc769ad --- /dev/null +++ b/mlops_stacks_gcp_fs/deployment/model_deployment/notebooks/ModelDeployment.py @@ -0,0 +1,52 @@ +# Databricks notebook source +################################################################################## +# Helper notebook to transition the model stage. This notebook is run +# after the Train.py notebook as part of a multi-task job, in order to transition model +# to target stage after training completes. +# +# Note that we deploy the model to the stage in MLflow Model Registry equivalent to the +# environment in which the multi-task job is executed (e.g deploy the trained model to +# stage=Production if triggered in the prod environment). In a practical setting, we would +# recommend enabling the model validation step between model training and automatically +# registering the model to the Production stage in prod. +# +# This notebook has the following parameters: +# +# * env (required) - String name of the current environment for model deployment, which decides the target stage. +# * model_uri (required) - URI of the model to deploy. Must be in the format "models://", as described in +# https://www.mlflow.org/docs/latest/model-registry.html#fetching-an-mlflow-model-from-the-model-registry +# This parameter is read as a task value +# (https://docs.databricks.com/dev-tools/databricks-utils.html#get-command-dbutilsjobstaskvaluesget), +# rather than as a notebook widget. That is, we assume a preceding task (the Train.py +# notebook) has set a task value with key "model_uri". +################################################################################## + +# List of input args needed to run the notebook as a job. +# Provide them via DB widgets or notebook arguments. +# +# Name of the current environment +dbutils.widgets.dropdown("env", "None", ["None", "staging", "prod"], "Environment Name") + +# COMMAND ---------- + +import os +import sys +notebook_path = '/Workspace/' + os.path.dirname(dbutils.notebook.entry_point.getDbutils().notebook().getContext().notebookPath().get()) +%cd $notebook_path +%cd .. +sys.path.append("../..") + +# COMMAND ---------- + +from deploy import deploy + +model_uri = dbutils.jobs.taskValues.get("Train", "model_uri", debugValue="") +env = dbutils.widgets.get("env") +assert env != "None", "env notebook parameter must be specified" +assert model_uri != "", "model_uri notebook parameter must be specified" +deploy(model_uri, env) + +# COMMAND ---------- +print( + f"Successfully completed model deployment for {model_uri}" +) diff --git a/mlops_stacks_gcp_fs/feature_engineering/README.md b/mlops_stacks_gcp_fs/feature_engineering/README.md new file mode 100644 index 0000000..b44d39c --- /dev/null +++ b/mlops_stacks_gcp_fs/feature_engineering/README.md @@ -0,0 +1,4 @@ +# Feature Engineering +To set up the feature engineering job via scheduled Databricks workflow, please refer to [mlops_stacks_gcp_fs/assets/README.md](../assets/README.md) + +For additional details on using the feature store, please refer to [mlops_stacks_gcp_fs/docs/ml-developer-guide-fs.md](../../docs/ml-developer-guide-fs.md). \ No newline at end of file diff --git a/mlops_stacks_gcp_fs/feature_engineering/__init__.py b/mlops_stacks_gcp_fs/feature_engineering/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlops_stacks_gcp_fs/feature_engineering/features/__init__.py b/mlops_stacks_gcp_fs/feature_engineering/features/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlops_stacks_gcp_fs/feature_engineering/features/dropoff_features.py b/mlops_stacks_gcp_fs/feature_engineering/features/dropoff_features.py new file mode 100644 index 0000000..c1d93c6 --- /dev/null +++ b/mlops_stacks_gcp_fs/feature_engineering/features/dropoff_features.py @@ -0,0 +1,64 @@ +""" +This sample module contains features logic that can be used to generate and populate tables in Feature Store. +You should plug in your own features computation logic in the compute_features_fn method below. +""" +import pyspark.sql.functions as F +from pyspark.sql.types import IntegerType, StringType, TimestampType +from pytz import timezone + + +@F.udf(returnType=IntegerType()) +def _is_weekend(dt): + tz = "America/New_York" + return int(dt.astimezone(timezone(tz)).weekday() >= 5) # 5 = Saturday, 6 = Sunday + + +@F.udf(returnType=StringType()) +def _partition_id(dt): + # datetime -> "YYYY-MM" + return f"{dt.year:04d}-{dt.month:02d}" + + +def _filter_df_by_ts(df, ts_column, start_date, end_date): + if ts_column and start_date: + df = df.filter(F.col(ts_column) >= start_date) + if ts_column and end_date: + df = df.filter(F.col(ts_column) < end_date) + return df + + +def compute_features_fn(input_df, timestamp_column, start_date, end_date): + """Contains logic to compute features. + + Given an input dataframe and time ranges, this function should compute features, populate an output dataframe and + return it. This method will be called from a Feature Store pipeline job and the output dataframe will be written + to a Feature Store table. You should update this method with your own feature computation logic. + + The timestamp_column, start_date, end_date args are optional but strongly recommended for time-series based + features. + + TODO: Update and adapt the sample code for your use case + + :param input_df: Input dataframe. + :param timestamp_column: Column containing the timestamp. This column is used to limit the range of feature + computation. It is also used as the timestamp key column when populating the feature table, so it needs to be + returned in the output. + :param start_date: Start date of the feature computation interval. + :param end_date: End date of the feature computation interval. + :return: Output dataframe containing computed features given the input arguments. + """ + df = _filter_df_by_ts(input_df, timestamp_column, start_date, end_date) + dropoffzip_features = ( + df.groupBy("dropoff_zip", F.window(timestamp_column, "30 minute")) + .agg(F.count("*").alias("count_trips_window_30m_dropoff_zip")) + .select( + F.col("dropoff_zip").alias("zip"), + F.unix_timestamp(F.col("window.end")) + .alias(timestamp_column) + .cast(TimestampType()), + _partition_id(F.to_timestamp(F.col("window.end"))).alias("yyyy_mm"), + F.col("count_trips_window_30m_dropoff_zip").cast(IntegerType()), + _is_weekend(F.col("window.end")).alias("dropoff_is_weekend"), + ) + ) + return dropoffzip_features diff --git a/mlops_stacks_gcp_fs/feature_engineering/features/pickup_features.py b/mlops_stacks_gcp_fs/feature_engineering/features/pickup_features.py new file mode 100644 index 0000000..895a9b8 --- /dev/null +++ b/mlops_stacks_gcp_fs/feature_engineering/features/pickup_features.py @@ -0,0 +1,63 @@ +""" +This sample module contains features logic that can be used to generate and populate tables in Feature Store. +You should plug in your own features computation logic in the compute_features_fn method below. +""" +import pyspark.sql.functions as F +from pyspark.sql.types import FloatType, IntegerType, StringType, TimestampType +from pytz import timezone + + +@F.udf(returnType=StringType()) +def _partition_id(dt): + # datetime -> "YYYY-MM" + return f"{dt.year:04d}-{dt.month:02d}" + + +def _filter_df_by_ts(df, ts_column, start_date, end_date): + if ts_column and start_date: + df = df.filter(F.col(ts_column) >= start_date) + if ts_column and end_date: + df = df.filter(F.col(ts_column) < end_date) + return df + + +def compute_features_fn(input_df, timestamp_column, start_date, end_date): + """Contains logic to compute features. + + Given an input dataframe and time ranges, this function should compute features, populate an output dataframe and + return it. This method will be called from a Feature Store pipeline job and the output dataframe will be written + to a Feature Store table. You should update this method with your own feature computation logic. + + The timestamp_column, start_date, end_date args are optional but strongly recommended for time-series based + features. + + TODO: Update and adapt the sample code for your use case + + :param input_df: Input dataframe. + :param timestamp_column: Column containing a timestamp. This column is used to limit the range of feature + computation. It is also used as the timestamp key column when populating the feature table, so it needs to be + returned in the output. + :param start_date: Start date of the feature computation interval. + :param end_date: End date of the feature computation interval. + :return: Output dataframe containing computed features given the input arguments. + """ + df = _filter_df_by_ts(input_df, timestamp_column, start_date, end_date) + pickupzip_features = ( + df.groupBy( + "pickup_zip", F.window(timestamp_column, "1 hour", "15 minutes") + ) # 1 hour window, sliding every 15 minutes + .agg( + F.mean("fare_amount").alias("mean_fare_window_1h_pickup_zip"), + F.count("*").alias("count_trips_window_1h_pickup_zip"), + ) + .select( + F.col("pickup_zip").alias("zip"), + F.unix_timestamp(F.col("window.end")) + .alias(timestamp_column) + .cast(TimestampType()), + _partition_id(F.to_timestamp(F.col("window.end"))).alias("yyyy_mm"), + F.col("mean_fare_window_1h_pickup_zip").cast(FloatType()), + F.col("count_trips_window_1h_pickup_zip").cast(IntegerType()), + ) + ) + return pickupzip_features diff --git a/mlops_stacks_gcp_fs/feature_engineering/notebooks/GenerateAndWriteFeatures.py b/mlops_stacks_gcp_fs/feature_engineering/notebooks/GenerateAndWriteFeatures.py new file mode 100644 index 0000000..1c6fce7 --- /dev/null +++ b/mlops_stacks_gcp_fs/feature_engineering/notebooks/GenerateAndWriteFeatures.py @@ -0,0 +1,139 @@ +# Databricks notebook source +################################################################################## +# Generate and Write Features Notebook +# +# This notebook can be used to generate and write features to a Databricks Feature Store table. +# It is configured and can be executed as the tasks in the write_feature_table_job workflow defined under +# ``mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml`` +# +# Parameters: +# +# * input_table_path (required) - Path to input data. +# * output_table_name (required) - Fully qualified schema + Delta table name for the feature table where the features +# * will be written to. Note that this will create the Feature table if it does not +# * exist. +# * primary_keys (required) - A comma separated string of primary key columns of the output feature table. +# * +# * timestamp_column (optional) - Timestamp column of the input data. Used to limit processing based on +# * date ranges. This column is used as the timestamp_key column in the feature table. +# * input_start_date (optional) - Used to limit feature computations based on timestamp_column values. +# * input_end_date (optional) - Used to limit feature computations based on timestamp_column values. +# * +# * features_transform_module (required) - Python module containing the feature transform logic. +################################################################################## + + +# List of input args needed to run this notebook as a job. +# Provide them via DB widgets or notebook arguments. +# +# A Hive-registered Delta table containing the input data. +dbutils.widgets.text( + "input_table_path", + "/databricks-datasets/nyctaxi-with-zipcodes/subsampled", + label="Input Table Name", +) +# Input start date. +dbutils.widgets.text("input_start_date", "", label="Input Start Date") +# Input end date. +dbutils.widgets.text("input_end_date", "", label="Input End Date") +# Timestamp column. Will be used to filter input start/end dates. +# This column is also used as a timestamp key of the feature table. +dbutils.widgets.text( + "timestamp_column", "tpep_pickup_datetime", label="Timestamp column" +) + +# Feature table to store the computed features. +dbutils.widgets.text( + "output_table_name", + "feature_store_taxi_example.trip_pickup_features", + label="Output Feature Table Name", +) + +# Feature transform module name. +dbutils.widgets.text( + "features_transform_module", "pickup_features", label="Features transform file." +) +# Primary Keys columns for the feature table; +dbutils.widgets.text( + "primary_keys", + "zip", + label="Primary keys columns for the feature table, comma separated.", +) + +# COMMAND ---------- + +import os +notebook_path = '/Workspace/' + os.path.dirname(dbutils.notebook.entry_point.getDbutils().notebook().getContext().notebookPath().get()) +%cd $notebook_path +%cd ../features + + +# COMMAND ---------- +# DBTITLE 1,Define input and output variables + +input_table_path = dbutils.widgets.get("input_table_path") +output_table_name = dbutils.widgets.get("output_table_name") +input_start_date = dbutils.widgets.get("input_start_date") +input_end_date = dbutils.widgets.get("input_end_date") +ts_column = dbutils.widgets.get("timestamp_column") +features_module = dbutils.widgets.get("features_transform_module") +pk_columns = dbutils.widgets.get("primary_keys") + +assert input_table_path != "", "input_table_path notebook parameter must be specified" +assert output_table_name != "", "output_table_name notebook parameter must be specified" + +# Extract database name. Needs to be updated for Unity Catalog. +output_database = output_table_name.split(".")[0] + +# COMMAND ---------- +# DBTITLE 1,Create database. + +spark.sql("CREATE DATABASE IF NOT EXISTS " + output_database) + +# COMMAND ---------- +# DBTITLE 1, Read input data. + +raw_data = spark.read.format("delta").load(input_table_path) + + +# COMMAND ---------- +# DBTITLE 1,Compute features. + +# Compute the features. This is done by dynamically loading the features module. +from importlib import import_module + +mod = import_module(features_module) +compute_features_fn = getattr(mod, "compute_features_fn") + +features_df = compute_features_fn( + input_df=raw_data, + timestamp_column=ts_column, + start_date=input_start_date, + end_date=input_end_date, +) + +# COMMAND ---------- +# DBTITLE 1, Write computed features. + +from databricks import feature_store + +fs = feature_store.FeatureStoreClient() + + +# Create the feature table if it does not exist first. +# Note that this is a no-op if a table with the same name and schema already exists. +fs.create_table( + name=output_table_name, + primary_keys=[x.strip() for x in pk_columns.split(",")], + timestamp_keys=[ts_column], + df=features_df, +) + +# Write the computed features dataframe. +fs.write_table( + name=output_table_name, + df=features_df, + mode="merge", +) + +dbutils.notebook.exit(0) diff --git a/mlops_stacks_gcp_fs/monitoring/README.md b/mlops_stacks_gcp_fs/monitoring/README.md new file mode 100644 index 0000000..909eb5e --- /dev/null +++ b/mlops_stacks_gcp_fs/monitoring/README.md @@ -0,0 +1,5 @@ +# Monitoring + +Databricks Data Monitoring is currently in Private Preview. + +Please contact a Databricks representative for more information. diff --git a/mlops_stacks_gcp_fs/pytest.ini b/mlops_stacks_gcp_fs/pytest.ini new file mode 100644 index 0000000..04680e7 --- /dev/null +++ b/mlops_stacks_gcp_fs/pytest.ini @@ -0,0 +1,4 @@ +# Configure pytest to detect local modules in the current directory +# See https://docs.pytest.org/en/7.1.x/reference/reference.html#confval-pythonpath for details +[pytest] +pythonpath = . diff --git a/mlops_stacks_gcp_fs/requirements.txt b/mlops_stacks_gcp_fs/requirements.txt new file mode 100644 index 0000000..286a0f6 --- /dev/null +++ b/mlops_stacks_gcp_fs/requirements.txt @@ -0,0 +1,8 @@ +mlflow==2.7.1 +numpy>=1.23.0 +pandas>=1.4.3 +scikit-learn>=1.1.1 +matplotlib>=3.5.2 +Jinja2==3.0.3 +pyspark~=3.3.0 +pytz~=2022.2.1 diff --git a/mlops_stacks_gcp_fs/tests/__init__.py b/mlops_stacks_gcp_fs/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlops_stacks_gcp_fs/tests/feature_engineering/__init__.py b/mlops_stacks_gcp_fs/tests/feature_engineering/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlops_stacks_gcp_fs/tests/feature_engineering/dropoff_features_test.py b/mlops_stacks_gcp_fs/tests/feature_engineering/dropoff_features_test.py new file mode 100644 index 0000000..832748c --- /dev/null +++ b/mlops_stacks_gcp_fs/tests/feature_engineering/dropoff_features_test.py @@ -0,0 +1,44 @@ +import pyspark.sql +import pytest +import pandas as pd +from datetime import datetime +from pyspark.sql import SparkSession + +from mlops_stacks_gcp_fs.feature_engineering.features.dropoff_features import ( + compute_features_fn, +) + + +@pytest.fixture(scope="session") +def spark(request): + """fixture for creating a spark session + Args: + request: pytest.FixtureRequest object + """ + spark = ( + SparkSession.builder.master("local[1]") + .appName("pytest-pyspark-local-testing") + .getOrCreate() + ) + request.addfinalizer(lambda: spark.stop()) + + return spark + + +@pytest.mark.usefixtures("spark") +def test_dropoff_features_fn(spark): + input_df = pd.DataFrame( + { + "tpep_pickup_datetime": [datetime(2022, 1, 10)], + "tpep_dropoff_datetime": [datetime(2022, 1, 10)], + "dropoff_zip": [94400], + "trip_distance": [2], + "fare_amount": [100], + } + ) + spark_df = spark.createDataFrame(input_df) + output_df = compute_features_fn( + spark_df, "tpep_pickup_datetime", datetime(2022, 1, 1), datetime(2022, 1, 15) + ) + assert isinstance(output_df, pyspark.sql.DataFrame) + assert output_df.count() == 1 diff --git a/mlops_stacks_gcp_fs/tests/feature_engineering/pickup_features_test.py b/mlops_stacks_gcp_fs/tests/feature_engineering/pickup_features_test.py new file mode 100644 index 0000000..01e4d16 --- /dev/null +++ b/mlops_stacks_gcp_fs/tests/feature_engineering/pickup_features_test.py @@ -0,0 +1,42 @@ +import pyspark.sql +import pytest +import pandas as pd +from datetime import datetime +from pyspark.sql import SparkSession + +from mlops_stacks_gcp_fs.feature_engineering.features.pickup_features import compute_features_fn + + +@pytest.fixture(scope="session") +def spark(request): + """fixture for creating a spark session + Args: + request: pytest.FixtureRequest object + """ + spark = ( + SparkSession.builder.master("local[1]") + .appName("pytest-pyspark-local-testing") + .getOrCreate() + ) + request.addfinalizer(lambda: spark.stop()) + + return spark + + +@pytest.mark.usefixtures("spark") +def test_pickup_features_fn(spark): + input_df = pd.DataFrame( + { + "tpep_pickup_datetime": [datetime(2022, 1, 12)], + "tpep_dropoff_datetime": [datetime(2022, 1, 12)], + "pickup_zip": [94400], + "trip_distance": [2], + "fare_amount": [100], + } + ) + spark_df = spark.createDataFrame(input_df) + output_df = compute_features_fn( + spark_df, "tpep_pickup_datetime", datetime(2022, 1, 1), datetime(2022, 1, 15) + ) + assert isinstance(output_df, pyspark.sql.DataFrame) + assert output_df.count() == 4 # 4 15-min intervals over 1 hr window. diff --git a/mlops_stacks_gcp_fs/tests/training/__init__.py b/mlops_stacks_gcp_fs/tests/training/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlops_stacks_gcp_fs/tests/training/test_notebooks.py b/mlops_stacks_gcp_fs/tests/training/test_notebooks.py new file mode 100644 index 0000000..7293b1b --- /dev/null +++ b/mlops_stacks_gcp_fs/tests/training/test_notebooks.py @@ -0,0 +1,9 @@ +import pathlib + + +def test_notebook_format(): + # Verify that all Databricks notebooks have the required header + paths = list(pathlib.Path("./notebooks").glob("**/*.py")) + for f in paths: + notebook_str = open(str(f)).read() + assert notebook_str.startswith("# Databricks notebook source") diff --git a/mlops_stacks_gcp_fs/training/__init__.py b/mlops_stacks_gcp_fs/training/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlops_stacks_gcp_fs/training/data/sample.parquet b/mlops_stacks_gcp_fs/training/data/sample.parquet new file mode 100644 index 0000000000000000000000000000000000000000..4efd17122087414513aeb1c1134e184f344fba0f GIT binary patch literal 232389 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%0D?O5!58{+*=|jKTgW66G5eMcJ2ew`EK8( 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

PD`_Y7*UgDHw?jyeoBa>3(90yl_eJ>x^Lkv|T_- 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

H6yUI8?*YFjjc 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 latest_version: + latest_version = version_int + return latest_version + + +# COMMAND ---------- +# DBTITLE 1, Read taxi data for training + +taxi_data = rounded_taxi_data(raw_data) +taxi_data.display() + +# COMMAND ---------- +# DBTITLE 1, Create FeatureLookups + +from databricks.feature_store import FeatureLookup +import mlflow + +pickup_features_table = dbutils.widgets.get("pickup_features_table") +dropoff_features_table = dbutils.widgets.get("dropoff_features_table") + +pickup_feature_lookups = [ + FeatureLookup( + table_name=pickup_features_table, + feature_names=[ + "mean_fare_window_1h_pickup_zip", + "count_trips_window_1h_pickup_zip", + ], + lookup_key=["pickup_zip"], + timestamp_lookup_key=["rounded_pickup_datetime"], + ), +] + +dropoff_feature_lookups = [ + FeatureLookup( + table_name=dropoff_features_table, + feature_names=["count_trips_window_30m_dropoff_zip", "dropoff_is_weekend"], + lookup_key=["dropoff_zip"], + timestamp_lookup_key=["rounded_dropoff_datetime"], + ), +] + +# COMMAND ---------- +# DBTITLE 1, Create Training Dataset + +from databricks import feature_store + +# End any existing runs (in the case this notebook is being run for a second time) +mlflow.end_run() + +# Start an mlflow run, which is needed for the feature store to log the model +mlflow.start_run() + +# Since the rounded timestamp columns would likely cause the model to overfit the data +# unless additional feature engineering was performed, exclude them to avoid training on them. +exclude_columns = ["rounded_pickup_datetime", "rounded_dropoff_datetime"] + +fs = feature_store.FeatureStoreClient() + +# Create the training set that includes the raw input data merged with corresponding features from both feature tables +training_set = fs.create_training_set( + taxi_data, + feature_lookups=pickup_feature_lookups + dropoff_feature_lookups, + label="fare_amount", + exclude_columns=exclude_columns, +) + +# Load the TrainingSet into a dataframe which can be passed into sklearn for training a model +training_df = training_set.load_df() + +# COMMAND ---------- + +# Display the training dataframe, and note that it contains both the raw input data and the features from the Feature Store, like `dropoff_is_weekend` +training_df.display() + +# COMMAND ---------- + +# MAGIC %md +# MAGIC Train a LightGBM model on the data returned by `TrainingSet.to_df`, then log the model with `FeatureStoreClient.log_model`. The model will be packaged with feature metadata. + +# COMMAND ---------- +# DBTITLE 1, Train model + +import lightgbm as lgb +from sklearn.model_selection import train_test_split +import mlflow.lightgbm +from mlflow.tracking import MlflowClient + + +features_and_label = training_df.columns + +# Collect data into a Pandas array for training +data = training_df.toPandas()[features_and_label] + +train, test = train_test_split(data, random_state=123) +X_train = train.drop(["fare_amount"], axis=1) +X_test = test.drop(["fare_amount"], axis=1) +y_train = train.fare_amount +y_test = test.fare_amount + +mlflow.lightgbm.autolog() +train_lgb_dataset = lgb.Dataset(X_train, label=y_train.values) +test_lgb_dataset = lgb.Dataset(X_test, label=y_test.values) + +param = {"num_leaves": 32, "objective": "regression", "metric": "rmse"} +num_rounds = 100 + +# Train a lightGBM model +model = lgb.train(param, train_lgb_dataset, num_rounds) + +# COMMAND ---------- +# DBTITLE 1, Log model and return output. + +# Log the trained model with MLflow and package it with feature lookup information. +fs.log_model( + model, + artifact_path="model_packaged", + flavor=mlflow.lightgbm, + training_set=training_set, + registered_model_name=model_name, +) + +# The returned model URI is needed by the model deployment notebook. +model_version = get_latest_model_version(model_name) +model_uri = f"models:/{model_name}/{model_version}" +dbutils.jobs.taskValues.set("model_uri", model_uri) +dbutils.jobs.taskValues.set("model_name", model_name) +dbutils.jobs.taskValues.set("model_version", model_version) +dbutils.notebook.exit(model_uri) diff --git a/mlops_stacks_gcp_fs/training/steps/__init__.py b/mlops_stacks_gcp_fs/training/steps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlops_stacks_gcp_fs/training/steps/custom_metrics.py b/mlops_stacks_gcp_fs/training/steps/custom_metrics.py new file mode 100644 index 0000000..23d5eb2 --- /dev/null +++ b/mlops_stacks_gcp_fs/training/steps/custom_metrics.py @@ -0,0 +1,47 @@ +""" +This module defines custom metric functions that are invoked during the 'train' and 'evaluate' +steps to provide model performance insights. Custom metric functions defined in this module are +referenced in the ``metrics`` section of ``recipe.yaml``, for example: + +.. code-block:: yaml + :caption: Example custom metrics definition in ``recipe.yaml`` + + metrics: + custom: + - name: weighted_mean_squared_error + function: weighted_mean_squared_error + greater_is_better: False +""" + +from typing import Dict + +from pandas import DataFrame +from sklearn.metrics import mean_squared_error + + +def weighted_mean_squared_error( + eval_df: DataFrame, + builtin_metrics: Dict[str, int], # pylint: disable=unused-argument +) -> int: + """ + Computes the weighted mean squared error (MSE) metric. + + :param eval_df: A Pandas DataFrame containing the following columns: + + - ``"prediction"``: Predictions produced by submitting input data to the model. + - ``"target"``: Ground truth values corresponding to the input data. + + :param builtin_metrics: A dictionary containing the built-in metrics that are calculated + automatically during model evaluation. The keys are the names of the + metrics and the values are the scalar values of the metrics. For more + information, see + https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate. + :return: A single-entry dictionary containing the MSE metric. The key is the metric name and + the value is the scalar metric value. Note that custom metric functions can return + dictionaries with multiple metric entries as well. + """ + return mean_squared_error( + eval_df["prediction"], + eval_df["target"], + sample_weight=1 / eval_df["prediction"].values, + ) diff --git a/mlops_stacks_gcp_fs/training/steps/ingest.py b/mlops_stacks_gcp_fs/training/steps/ingest.py new file mode 100644 index 0000000..7dfa89f --- /dev/null +++ b/mlops_stacks_gcp_fs/training/steps/ingest.py @@ -0,0 +1,40 @@ +""" +This module defines the following routines used by the 'ingest' step of the regression recipe: + +- ``load_file_as_dataframe``: Defines customizable logic for parsing dataset formats that are not + natively parsed by MLflow Recipes (i.e. formats other than Parquet, Delta, and Spark SQL). +""" + +import logging + +from pandas import DataFrame + +_logger = logging.getLogger(__name__) + + +def load_file_as_dataframe(file_path: str, file_format: str) -> DataFrame: + """ + Load content from the specified dataset file as a Pandas DataFrame. + + This method is used to load dataset types that are not natively managed by MLflow Recipes + (datasets that are not in Parquet, Delta Table, or Spark SQL Table format). This method is + called once for each file in the dataset, and MLflow Recipes automatically combines the + resulting DataFrames together. + + :param file_path: The path to the dataset file. + :param file_format: The file format string, such as "csv". + :return: A Pandas DataFrame representing the content of the specified file. + """ + + if file_format == "csv": + import pandas + + _logger.warning( + "Loading dataset CSV using `pandas.read_csv()` with default arguments and assumed index" + " column 0 which may not produce the desired schema. If the schema is not correct, you" + " can adjust it by modifying the `load_file_as_dataframe()` function in" + " `steps/ingest.py`" + ) + return pandas.read_csv(file_path, index_col=0) + else: + raise NotImplementedError diff --git a/mlops_stacks_gcp_fs/training/steps/split.py b/mlops_stacks_gcp_fs/training/steps/split.py new file mode 100644 index 0000000..5fa7f92 --- /dev/null +++ b/mlops_stacks_gcp_fs/training/steps/split.py @@ -0,0 +1,37 @@ +""" +This module defines the following routines used by the 'split' step of the regression recipe: + +- ``process_splits``: Defines customizable logic for processing & cleaning the training, validation, + and test datasets produced by the data splitting procedure. +""" + +from pandas import DataFrame + + +def process_splits( + train_df: DataFrame, validation_df: DataFrame, test_df: DataFrame +) -> (DataFrame, DataFrame, DataFrame): + """ + Perform additional processing on the split datasets. + + :param train_df: The training dataset produced by the data splitting procedure. + :param validation_df: The validation dataset produced by the data splitting procedure. + :param test_df: The test dataset produced by the data splitting procedure. + :return: A tuple containing, in order: the processed training dataset, the processed + validation dataset, and the processed test dataset. + """ + + def process(df: DataFrame): + # Drop invalid data points + cleaned = df.dropna() + # Filter out invalid fare amounts and trip distance + cleaned = cleaned[ + (cleaned["fare_amount"] > 0) + & (cleaned["trip_distance"] < 400) + & (cleaned["trip_distance"] > 0) + & (cleaned["fare_amount"] < 1000) + ] + + return cleaned + + return process(train_df), process(validation_df), process(test_df) diff --git a/mlops_stacks_gcp_fs/training/steps/train.py b/mlops_stacks_gcp_fs/training/steps/train.py new file mode 100644 index 0000000..c61b2bd --- /dev/null +++ b/mlops_stacks_gcp_fs/training/steps/train.py @@ -0,0 +1,17 @@ +""" +This module defines the following routines used by the 'train' step of the regression recipe: + +- ``estimator_fn``: Defines the customizable estimator type and parameters that are used + during training to produce a model pipeline. +""" + + +def estimator_fn(): + """ + Returns an *unfitted* estimator that defines ``fit()`` and ``predict()`` methods. + The estimator's input and output signatures should be compatible with scikit-learn + estimators. + """ + from sklearn.linear_model import SGDRegressor + + return SGDRegressor(random_state=42) diff --git a/mlops_stacks_gcp_fs/training/steps/transform.py b/mlops_stacks_gcp_fs/training/steps/transform.py new file mode 100644 index 0000000..7851b89 --- /dev/null +++ b/mlops_stacks_gcp_fs/training/steps/transform.py @@ -0,0 +1,62 @@ +""" +This module defines the following routines used by the 'transform' step of the regression recipe: + +- ``transformer_fn``: Defines customizable logic for transforming input data before it is passed + to the estimator during model inference. +""" + +from pandas import DataFrame +from sklearn.compose import ColumnTransformer +from sklearn.pipeline import Pipeline +from sklearn.preprocessing import OneHotEncoder, StandardScaler, FunctionTransformer + + +def calculate_features(df: DataFrame): + """ + Extend the input dataframe with pickup day of week and hour, and trip duration. + Drop the now-unneeded pickup datetime and dropoff datetime columns. + """ + df["pickup_dow"] = df["tpep_pickup_datetime"].dt.dayofweek + df["pickup_hour"] = df["tpep_pickup_datetime"].dt.hour + trip_duration = df["tpep_dropoff_datetime"] - df["tpep_pickup_datetime"] + df["trip_duration"] = trip_duration.map(lambda x: x.total_seconds() / 60) + df.drop(columns=["tpep_pickup_datetime", "tpep_dropoff_datetime"], inplace=True) + return df + + +def transformer_fn(): + """ + Returns an *unfitted* transformer that defines ``fit()`` and ``transform()`` methods. + The transformer's input and output signatures should be compatible with scikit-learn + transformers. + """ + return Pipeline( + steps=[ + ( + "calculate_time_and_duration_features", + FunctionTransformer(calculate_features, feature_names_out="one-to-one"), + ), + ( + "encoder", + ColumnTransformer( + transformers=[ + ( + "hour_encoder", + OneHotEncoder(categories="auto", sparse=False), + ["pickup_hour"], + ), + ( + "day_encoder", + OneHotEncoder(categories="auto", sparse=False), + ["pickup_dow"], + ), + ( + "std_scaler", + StandardScaler(), + ["trip_distance", "trip_duration"], + ), + ] + ), + ), + ] + ) diff --git a/mlops_stacks_gcp_fs/utils.py b/mlops_stacks_gcp_fs/utils.py new file mode 100644 index 0000000..aa30820 --- /dev/null +++ b/mlops_stacks_gcp_fs/utils.py @@ -0,0 +1,21 @@ +"""This module contains utils shared between different notebooks""" + +def get_deployed_model_stage_for_env(env): + """ + Get the model version stage under which the latest deployed model version can be found + for the current environment + :param env: Current environment + :return: Model version stage + """ + # For a registered model version to be served, it needs to be in either the Staging or Production + # model registry stage + # (https://docs.databricks.com/applications/machine-learning/manage-model-lifecycle/index.html#transition-a-model-stage). + # For models in dev and staging environments, we deploy the model to the "Staging" stage, and in prod we deploy to the + # "Production" stage + _MODEL_STAGE_FOR_ENV = { + "dev": "Staging", + "staging": "Staging", + "prod": "Production", + "test": "Production", + } + return _MODEL_STAGE_FOR_ENV[env] diff --git a/mlops_stacks_gcp_fs/validation/README.md b/mlops_stacks_gcp_fs/validation/README.md new file mode 100644 index 0000000..539107e --- /dev/null +++ b/mlops_stacks_gcp_fs/validation/README.md @@ -0,0 +1,2 @@ +# Model Validation +To enable model validation as part of scheduled databricks workflow, please refer to [mlops_stacks_gcp_fs/assets/README.md](../assets/README.md) \ No newline at end of file diff --git a/mlops_stacks_gcp_fs/validation/notebooks/ModelValidation.py b/mlops_stacks_gcp_fs/validation/notebooks/ModelValidation.py new file mode 100644 index 0000000..5441846 --- /dev/null +++ b/mlops_stacks_gcp_fs/validation/notebooks/ModelValidation.py @@ -0,0 +1,283 @@ +# Databricks notebook source +################################################################################## +# Model Validation Notebook +## +# This notebook uses mlflow model validation API to run mode validation after training and registering a model +# in model registry, before deploying it to the"Production" stage. +# +# It runs as part of CD and by an automated model training job -> validation -> deployment job defined under ``mlops_stacks_gcp_fs/assets/model-workflow-asset.yml`` +# +# +# Parameters: +# +# * env - Name of the environment the notebook is run in (staging, or prod). Defaults to "prod". +# * `run_mode` - The `run_mode` defines whether model validation is enabled or not. It can be one of the three values: +# * `disabled` : Do not run the model validation notebook. +# * `dry_run` : Run the model validation notebook. Ignore failed model validation rules and proceed to move +# model to the"Production" stage. +# * `enabled` : Run the model validation notebook. Move model to the "Production" stage only if all model validation +# rules are passing. +# * enable_baseline_comparison - Whether to load the current registered "Production" stage model as baseline. +# Baseline model is a requirement for relative change and absolute change validation thresholds. +# * validation_input - Validation input. Please refer to data parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate +# * model_type - A string describing the model type. The model type can be either "regressor" and "classifier". +# Please refer to model_type parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate +# * targets - The string name of a column from data that contains evaluation labels. +# Please refer to targets parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate +# * custom_metrics_loader_function - Specifies the name of the function in mlops_stacks_gcp_fs/validation/validation.py that returns custom metrics. +# * validation_thresholds_loader_function - Specifies the name of the function in mlops_stacks_gcp_fs/validation/validation.py that returns model validation thresholds. +# +# For details on mlflow evaluate API, see doc https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate +# For details and examples about performing model validation, see the Model Validation documentation https://mlflow.org/docs/latest/models.html#model-validation +# +################################################################################## + +# COMMAND ---------- + +# MAGIC %load_ext autoreload +# MAGIC %autoreload 2 + +# COMMAND ---------- + +import os +notebook_path = '/Workspace/' + os.path.dirname(dbutils.notebook.entry_point.getDbutils().notebook().getContext().notebookPath().get()) +%cd $notebook_path + +# COMMAND ---------- + +# MAGIC %pip install -r ../../requirements.txt + +# COMMAND ---------- + +dbutils.library.restartPython() + +# COMMAND ---------- + +import os +notebook_path = '/Workspace/' + os.path.dirname(dbutils.notebook.entry_point.getDbutils().notebook().getContext().notebookPath().get()) +%cd $notebook_path +%cd ../ + +# COMMAND ---------- + +dbutils.widgets.text( + "experiment_name", + "/dev-mlops_stacks_gcp_fs-experiment", + "Experiment Name", +) +dbutils.widgets.dropdown("run_mode", "disabled", ["disabled", "dry_run", "enabled"], "Run Mode") +dbutils.widgets.dropdown("enable_baseline_comparison", "false", ["true", "false"], "Enable Baseline Comparison") +dbutils.widgets.text("validation_input", "SELECT * FROM delta.`dbfs:/databricks-datasets/nyctaxi-with-zipcodes/subsampled`", "Validation Input") + +dbutils.widgets.text("model_type", "regressor", "Model Type") +dbutils.widgets.text("targets", "fare_amount", "Targets") +dbutils.widgets.text("custom_metrics_loader_function", "custom_metrics", "Custom Metrics Loader Function") +dbutils.widgets.text("validation_thresholds_loader_function", "validation_thresholds", "Validation Thresholds Loader Function") +dbutils.widgets.text("evaluator_config_loader_function", "evaluator_config", "Evaluator Config Loader Function") +dbutils.widgets.text("model_name", "dev-mlops_stacks_gcp_fs-model", "Model Name") +dbutils.widgets.text("model_version", "", "Candidate Model Version") + +# COMMAND ---------- + +print( + "Currently model validation is not supported for models registered with feature store. Please refer to " + "issue https://github.com/databricks/mlops-stacks/issues/70 for more details." +) +dbutils.notebook.exit(0) +run_mode = dbutils.widgets.get("run_mode").lower() +assert run_mode == "disabled" or run_mode == "dry_run" or run_mode == "enabled" + +if run_mode == "disabled": + print( + "Model validation is in DISABLED mode. Exit model validation without blocking model deployment." + ) + dbutils.notebook.exit(0) +dry_run = run_mode == "dry_run" + +if dry_run: + print( + "Model validation is in DRY_RUN mode. Validation threshold validation failures will not block model deployment." + ) +else: + print( + "Model validation is in ENABLED mode. Validation threshold validation failures will block model deployment." + ) + +# COMMAND ---------- + +import importlib +import mlflow +import os +import tempfile +import traceback + +from mlflow.tracking.client import MlflowClient + +client = MlflowClient() + +# set experiment +experiment_name = dbutils.widgets.get("experiment_name") +mlflow.set_experiment(experiment_name) + +# set model evaluation parameters that can be inferred from the job +model_uri = dbutils.jobs.taskValues.get("Train", "model_uri", debugValue="") +model_name = dbutils.jobs.taskValues.get("Train", "model_name", debugValue="") +model_version = dbutils.jobs.taskValues.get("Train", "model_version", debugValue="") + +if model_uri == "": + model_name = dbutils.widgets.get("model_name") + model_version = dbutils.widgets.get("model_version") + model_uri = "models:/" + model_name + "/" + model_version + +baseline_model_uri = "models:/" + model_name + "/Production" + +evaluators = "default" +assert model_uri != "", "model_uri notebook parameter must be specified" +assert model_name != "", "model_name notebook parameter must be specified" +assert model_version != "", "model_version notebook parameter must be specified" + +# COMMAND ---------- + +# take input +enable_baseline_comparison = dbutils.widgets.get("enable_baseline_comparison") +assert enable_baseline_comparison == "true" or enable_baseline_comparison == "false" +enable_baseline_comparison = enable_baseline_comparison == "true" + +validation_input = dbutils.widgets.get("validation_input") +assert validation_input +data = spark.sql(validation_input) + +model_type = dbutils.widgets.get("model_type") +targets = dbutils.widgets.get("targets") + +assert model_type +assert targets + +custom_metrics_loader_function_name = dbutils.widgets.get("custom_metrics_loader_function") +validation_thresholds_loader_function_name = dbutils.widgets.get("validation_thresholds_loader_function") +evaluator_config_loader_function_name = dbutils.widgets.get("evaluator_config_loader_function") +assert custom_metrics_loader_function_name +assert validation_thresholds_loader_function_name +assert evaluator_config_loader_function_name +custom_metrics_loader_function = getattr( + importlib.import_module("validation"), custom_metrics_loader_function_name +) +validation_thresholds_loader_function = getattr( + importlib.import_module("validation"), validation_thresholds_loader_function_name +) +evaluator_config_loader_function = getattr( + importlib.import_module("validation"), evaluator_config_loader_function_name +) +custom_metrics = custom_metrics_loader_function() +validation_thresholds = validation_thresholds_loader_function() +evaluator_config = evaluator_config_loader_function() + +# COMMAND ---------- + +# helper methods +def get_run_link(run_info): + return "[Run](#mlflow/experiments/{0}/runs/{1})".format( + run_info.experiment_id, run_info.run_id + ) + + +def get_training_run(model_name, model_version): + version = client.get_model_version(model_name, model_version) + return mlflow.get_run(run_id=version.run_id) + + +def generate_run_name(training_run): + return None if not training_run else training_run.info.run_name + "-validation" + + +def generate_description(training_run): + return ( + None + if not training_run + else "Model Training Details: {0}\n".format(get_run_link(training_run.info)) + ) + + +def log_to_model_description(run, success): + run_link = get_run_link(run.info) + description = client.get_model_version(model_name, model_version).description + status = "SUCCESS" if success else "FAILURE" + if description != "": + description += "\n\n---\n\n" + description += "Model Validation Status: {0}\nValidation Details: {1}".format( + status, run_link + ) + client.update_model_version( + name=model_name, version=model_version, description=description + ) + +# COMMAND ---------- + +training_run = get_training_run(model_name, model_version) + +# run evaluate +with mlflow.start_run( + run_name=generate_run_name(training_run), + description=generate_description(training_run), +) as run, tempfile.TemporaryDirectory() as tmp_dir: + validation_thresholds_file = os.path.join(tmp_dir, "validation_thresholds.txt") + with open(validation_thresholds_file, "w") as f: + if validation_thresholds: + for metric_name in validation_thresholds: + f.write( + "{0:30} {1}\n".format( + metric_name, str(validation_thresholds[metric_name]) + ) + ) + mlflow.log_artifact(validation_thresholds_file) + + try: + eval_result = mlflow.evaluate( + model=model_uri, + data=data, + targets=targets, + model_type=model_type, + evaluators=evaluators, + validation_thresholds=validation_thresholds, + custom_metrics=custom_metrics, + baseline_model=None + if not enable_baseline_comparison + else baseline_model_uri, + evaluator_config=evaluator_config, + ) + metrics_file = os.path.join(tmp_dir, "metrics.txt") + with open(metrics_file, "w") as f: + f.write( + "{0:30} {1:30} {2}\n".format("metric_name", "candidate", "baseline") + ) + for metric in eval_result.metrics: + candidate_metric_value = str(eval_result.metrics[metric]) + baseline_metric_value = "N/A" + if metric in eval_result.baseline_model_metrics: + mlflow.log_metric( + "baseline_" + metric, eval_result.baseline_model_metrics[metric] + ) + baseline_metric_value = str( + eval_result.baseline_model_metrics[metric] + ) + f.write( + "{0:30} {1:30} {2}\n".format( + metric, candidate_metric_value, baseline_metric_value + ) + ) + mlflow.log_artifact(metrics_file) + log_to_model_description(run, True) + + except Exception as err: + log_to_model_description(run, False) + error_file = os.path.join(tmp_dir, "error.txt") + with open(error_file, "w") as f: + f.write("Validation failed : " + str(err) + "\n") + f.write(traceback.format_exc()) + mlflow.log_artifact(error_file) + if not dry_run: + raise err + else: + print( + "Model validation failed in DRY_RUN. It will not block model deployment." + ) diff --git a/mlops_stacks_gcp_fs/validation/validation.py b/mlops_stacks_gcp_fs/validation/validation.py new file mode 100644 index 0000000..ac4f2ea --- /dev/null +++ b/mlops_stacks_gcp_fs/validation/validation.py @@ -0,0 +1,41 @@ +import numpy as np +from mlflow.models import make_metric, MetricThreshold + +# Custom metrics to be included. Return empty list if custom metrics are not needed. +# Please refer to custom_metrics parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate +# TODO(optional) : custom_metrics +def custom_metrics(): + + # TODO(optional) : define custom metric function to be included in custom_metrics. + def squared_diff_plus_one(eval_df, _builtin_metrics): + """ + This example custom metric function creates a metric based on the ``prediction`` and + ``target`` columns in ``eval_df`. + """ + return np.sum(np.abs(eval_df["prediction"] - eval_df["target"] + 1) ** 2) + + return [make_metric(eval_fn=squared_diff_plus_one, greater_is_better=False)] + + +# Define model validation rules. Return empty dict if validation rules are not needed. +# Please refer to validation_thresholds parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate +# TODO(optional) : validation_thresholds +def validation_thresholds(): + return { + "max_error": MetricThreshold( + threshold=500, higher_is_better=False # max_error should be <= 500 + ), + "mean_squared_error": MetricThreshold( + threshold=20, # mean_squared_error should be <= 20 + # min_absolute_change=0.01, # mean_squared_error should be at least 0.01 greater than baseline model accuracy + # min_relative_change=0.01, # mean_squared_error should be at least 1 percent greater than baseline model accuracy + higher_is_better=False, + ), + } + + +# Define evaluator config. Return empty dict if validation rules are not needed. +# Please refer to evaluator_config parameter in mlflow.evaluate documentation https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate +# TODO(optional) : evaluator_config +def evaluator_config(): + return {} diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..296b56e --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +pytest>=7.1.2 +pandas==1.5.3 \ No newline at end of file From 21de3147362b9c949d16769b7c7c4d6d22163b87 Mon Sep 17 00:00:00 2001 From: Eric Golinko Date: Mon, 26 Feb 2024 09:03:56 -0500 Subject: [PATCH 2/2] cluster types --- mlops_stacks_gcp_fs/assets/README.md | 4 ++-- mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml | 2 +- .../assets/feature-engineering-workflow-asset.yml | 2 +- mlops_stacks_gcp_fs/assets/model-workflow-asset.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mlops_stacks_gcp_fs/assets/README.md b/mlops_stacks_gcp_fs/assets/README.md index ce30069..7788f48 100644 --- a/mlops_stacks_gcp_fs/assets/README.md +++ b/mlops_stacks_gcp_fs/assets/README.md @@ -134,7 +134,7 @@ new_cluster: &new_cluster spark_version: 13.3.x-cpu-ml-scala2.12 node_type_id: n2-highmem-4 custom_tags: - clusterSource: mlops-stack/0.2 + clusterSource: mlops-stack resources: jobs: @@ -189,7 +189,7 @@ new_cluster: &new_cluster spark_version: 13.3.x-cpu-ml-scala2.12 node_type_id: n2-highmem-4 custom_tags: - clusterSource: mlops-stack/0.2 + clusterSource: mlops-stack resources: jobs: diff --git a/mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml b/mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml index 3a556c8..9fe6e29 100644 --- a/mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml +++ b/mlops_stacks_gcp_fs/assets/batch-inference-workflow-asset.yml @@ -4,7 +4,7 @@ new_cluster: &new_cluster spark_version: 13.3.x-cpu-ml-scala2.12 node_type_id: n2-highmem-4 custom_tags: - clusterSource: mlops-stack/0.2 + clusterSource: mlops-stack common_permissions: &permissions permissions: diff --git a/mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml b/mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml index 4dece72..a8f8669 100644 --- a/mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml +++ b/mlops_stacks_gcp_fs/assets/feature-engineering-workflow-asset.yml @@ -4,7 +4,7 @@ new_cluster: &new_cluster spark_version: 13.3.x-cpu-ml-scala2.12 node_type_id: n2-highmem-4 custom_tags: - clusterSource: mlops-stack/0.2 + clusterSource: mlops-stack common_permissions: &permissions permissions: diff --git a/mlops_stacks_gcp_fs/assets/model-workflow-asset.yml b/mlops_stacks_gcp_fs/assets/model-workflow-asset.yml index 8b920ef..f7fcc37 100644 --- a/mlops_stacks_gcp_fs/assets/model-workflow-asset.yml +++ b/mlops_stacks_gcp_fs/assets/model-workflow-asset.yml @@ -4,7 +4,7 @@ new_cluster: &new_cluster spark_version: 13.3.x-cpu-ml-scala2.12 node_type_id: n2-highmem-4 custom_tags: - clusterSource: mlops-stack/0.2 + clusterSource: mlops-stack common_permissions: &permissions permissions: