Compare commits

...
@@ -3,7 +3,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "d3069d95",
"metadata": {
"cellView": "form",
"id": "d3069d95"
@@ -11,7 +10,7 @@
"outputs": [],
"source": [
"# @title Copyright & License (click to expand)\n",
"# Copyright 2021 Google LLC\n",
"# Copyright 2022 Google LLC\n",
"#\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -28,7 +27,6 @@
},
{
"cell_type": "markdown",
"id": "546c53de",
"metadata": {
"id": "546c53de"
},
@@ -46,13 +44,16 @@
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
" View on GitHub\n",
" </a>\n",
" </td>\n",
" </td><td>\n",
" <a href=\"https://console.cloud.google.com/ai-platform/notebooks/deploy-notebook?name=Model%20Monitoring&download_url=https%3A%2F%2Fraw.githubusercontent.com%2FGoogleCloudPlatform%2Fvertex-ai-samples%2Fmain%2Fnotebooks%2Fcommunity%2Fmodel_monitoring%2Fbatch_prediction_model_monitoring.ipynb\">\n",
" <img src=\"https://www.gstatic.com/cloud/images/navigation/vertex-ai.svg\" alt=\"Google Cloud Notebooks\">Open in Workbench AI Notebook\n",
" </a>\n",
" </td> \n",
"</table>"
]
},
{
"cell_type": "markdown",
"id": "53fd1070",
"metadata": {
"id": "53fd1070"
},
@@ -64,7 +65,6 @@
},
{
"cell_type": "markdown",
"id": "8b26c855",
"metadata": {
"id": "8b26c855"
},
@@ -98,7 +98,6 @@
},
{
"cell_type": "markdown",
"id": "d52ba95b",
"metadata": {
"id": "d52ba95b"
},
@@ -110,7 +109,6 @@
},
{
"cell_type": "markdown",
"id": "e64fb18a",
"metadata": {
"id": "e64fb18a"
},
@@ -123,7 +121,6 @@
},
{
"cell_type": "markdown",
"id": "9d839347",
"metadata": {
"id": "9d839347"
},
@@ -142,7 +139,6 @@
},
{
"cell_type": "markdown",
"id": "738fce1f",
"metadata": {
"id": "738fce1f"
},
@@ -155,7 +151,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "4536fe4e",
"metadata": {
"id": "4536fe4e"
},
@@ -178,14 +173,13 @@
" USER_FLAG = \"--user\"\n",
"\n",
"# Install Python package dependencies.\n",
"! pip3 install -q tensorflow-data-validation $USER_FLAG\n",
"! pip3 install -q google-api-core $USER_FLAG\n",
"! pip3 install -q google-cloud-aiplatform $USER_FLAG"
"! pip3 install -q {USER_FLAG} tensorflow-data-validation \\\n",
" google-api-core \\\n",
" google-cloud-aiplatform"
]
},
{
"cell_type": "markdown",
"id": "6e98402b",
"metadata": {
"id": "6e98402b"
},
@@ -198,7 +192,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "9775c9ff",
"metadata": {
"id": "9775c9ff"
},
@@ -217,7 +210,6 @@
},
{
"cell_type": "markdown",
"id": "d5737134",
"metadata": {
"id": "d5737134"
},
@@ -242,7 +234,6 @@
},
{
"cell_type": "markdown",
"id": "cfb1a1d5",
"metadata": {
"id": "cfb1a1d5"
},
@@ -255,50 +246,33 @@
{
"cell_type": "code",
"execution_count": null,
"id": "cf8535e4",
"metadata": {
"id": "cf8535e4"
},
"outputs": [],
"source": [
"import os\n",
"\n",
"PROJECT_ID = \"\"\n",
"\n",
"# Get your Google Cloud project ID from gcloud\n",
"if not os.getenv(\"IS_TESTING\"):\n",
" shell_output = ! gcloud config list --format 'value(core.project)' 2>/dev/null\n",
" PROJECT_ID = shell_output[0]\n",
" print(\"Project ID: \", PROJECT_ID)"
]
},
{
"cell_type": "markdown",
"id": "05a2d397",
"metadata": {
"id": "05a2d397"
},
"source": [
"Otherwise, set your project ID here.\n"
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1c2be4bd",
"metadata": {
"id": "1c2be4bd"
},
"outputs": [],
"source": [
"if PROJECT_ID == \"\" or PROJECT_ID is None:\n",
" PROJECT_ID = \"python-docs-samples-tests\" # @param {type:\"string\"}"
"if PROJECT_ID == \"\" or not PROJECT_ID or PROJECT_ID == \"[your-project-id]\":\n",
" PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}\n",
" # Get your GCP project id from gcloud\n",
" shell_output = ! gcloud config list --format 'value(core.project)' 2>/dev/null\n",
" PROJECT_ID = shell_output[0]\n",
" print(\"Project ID:\", PROJECT_ID)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c129705c",
"metadata": {
"id": "c129705c"
},
@@ -309,32 +283,6 @@
},
{
"cell_type": "markdown",
"id": "71404c9f",
"metadata": {
"id": "71404c9f"
},
"source": [
"#### Set your email address\n",
"This is used for delivering model monitoring notifications.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4b1d2b69",
"metadata": {
"id": "4b1d2b69"
},
"outputs": [],
"source": [
"EMAIL_ADDRESS = \"[your-email-address]\" # @param {type:\"string\"}\n",
"if not EMAIL_ADDRESS or EMAIL_ADDRESS == \"[your-email-address]\":\n",
" print(\"EMAIL_ADDRESS not specified, please correct before proceeding.\")"
]
},
{
"cell_type": "markdown",
"id": "83340af4",
"metadata": {
"id": "83340af4"
},
@@ -356,18 +304,73 @@
{
"cell_type": "code",
"execution_count": null,
"id": "4814ea21",
"metadata": {
"id": "4814ea21"
},
"outputs": [],
"source": [
"REGION = \"us-central1\" # @param {type: \"string\"}"
"REGION = \"[your-region]\" # @param {type: \"string\"}\n",
"\n",
"if REGION == \"[your-region]\":\n",
" REGION = \"us-central1\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "06571eb4063b"
},
"source": [
"#### UUID\n",
"\n",
"If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a uuid for each instance session, and append it onto the name of resources you create in this tutorial."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4e166d927e36"
},
"outputs": [],
"source": [
"import random\n",
"import string\n",
"\n",
"\n",
"# Generate a uuid of a specifed length(default=8)\n",
"def generate_uuid(length: int = 8) -> str:\n",
" return \"\".join(random.choices(string.ascii_lowercase + string.digits, k=length))\n",
"\n",
"\n",
"UUID = generate_uuid()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "71404c9f"
},
"source": [
"#### Set your email address\n",
"This is used for delivering model monitoring notifications.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4b1d2b69"
},
"outputs": [],
"source": [
"EMAIL_ADDRESS = \"[your-email-address]\" # @param {type:\"string\"}\n",
"if not EMAIL_ADDRESS or EMAIL_ADDRESS == \"[your-email-address]\":\n",
" print(\"EMAIL_ADDRESS not specified, please correct before proceeding.\")"
]
},
{
"cell_type": "markdown",
"id": "20a546c3",
"metadata": {
"id": "20a546c3"
},
@@ -375,16 +378,35 @@
"### Authenticate your Google Cloud account\n",
"\n",
"**If you are using Vertex AI Workbench notebooks**, your environment is already\n",
"authenticated. Skip this step.\n",
"authenticated.\n",
"\n",
"**If you are using Colab**, run the cell below and follow the instructions\n",
"when prompted to authenticate your account via oAuth.\n"
"when prompted to authenticate your account via oAuth.\n",
"\n",
"**Otherwise**, follow these steps:\n",
"\n",
"1. In the Cloud Console, go to the [**Create service account key**\n",
" page](https://console.cloud.google.com/apis/credentials/serviceaccountkey).\n",
"\n",
"2. Click **Create service account**.\n",
"\n",
"3. In the **Service account name** field, enter a name, and\n",
" click **Create**.\n",
"\n",
"4. In the **Grant this service account access to project** section, click the **Role** drop-down list. Type \"Vertex AI\"\n",
"into the filter box, and select\n",
" **Vertex AI Administrator**. Type \"Storage Object Admin\" into the filter box, and select **Storage Object Admin**.\n",
"\n",
"5. Click **Create**. A JSON file that contains your key downloads to your\n",
"local environment.\n",
"\n",
"6. Enter the path to your service account key as the\n",
"`GOOGLE_APPLICATION_CREDENTIALS` variable in the cell below and run the cell."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "06c51076",
"metadata": {
"id": "06c51076"
},
@@ -421,73 +443,284 @@
},
{
"cell_type": "markdown",
"id": "6b01af18",
"metadata": {
"id": "6b01af18"
"id": "bucket:custom"
},
"source": [
"### Upload the model\n",
"### Create a Cloud Storage bucket\n",
"\n",
"The churn propensity model you'll be using in this notebook has been trained in BigQuery ML and exported to a Google Cloud Storage bucket. This illustrates how you can easily export a trained model and move a model from one cloud service to another. \n",
"**The following steps are required, regardless of your notebook environment.**\n",
"\n",
"Next, import the model. **If you've already imported your model, you can skip this step.**"
]
},
{
"cell_type": "markdown",
"id": "9638ad2c",
"metadata": {
"id": "9638ad2c"
},
"source": [
"<span id=\"papermill-error-cell\" style=\"color:red; font-family:Helvetica Neue, Helvetica, Arial, sans-serif; font-size:2em;\">Execution using papermill encountered an exception here and stopped:</span>"
"Set the name of your Cloud Storage bucket below, which you use in this tutorial to upload the `input schema` for the monitoring service.\n",
"\n",
"Bucket names must be globally unique across all Google Cloud projects, including those outside of your organization."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "926e3ba8",
"metadata": {
"id": "926e3ba8"
"id": "bucket"
},
"outputs": [],
"source": [
"from datetime import datetime\n",
"import json\n",
"import time\n",
"import re\n",
"import tensorflow as tf\n",
"BUCKET_NAME = \"[your-bucket-name]\" # @param {type:\"string\"}\n",
"BUCKET_URI = f\"gs://{BUCKET_NAME}\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "autoset_bucket"
},
"outputs": [],
"source": [
"if BUCKET_NAME == \"\" or BUCKET_NAME is None or BUCKET_NAME == \"[your-bucket-name]\":\n",
" BUCKET_NAME = PROJECT_ID + \"aip-\" + UUID\n",
" BUCKET_URI = \"gs://\" + BUCKET_NAME"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "create_bucket"
},
"source": [
"**Only if your bucket doesn't already exist**: Run the following cell to create your Cloud Storage bucket."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "create_bucket"
},
"outputs": [],
"source": [
"! gsutil mb -l $REGION $BUCKET_URI"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "validate_bucket"
},
"source": [
"Finally, validate access to your Cloud Storage bucket by examining its contents:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "validate_bucket"
},
"outputs": [],
"source": [
"! gsutil ls -al $BUCKET_URI"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "a0d294ff6d10"
},
"source": [
"### Import libraries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bd7a633296eb"
},
"outputs": [],
"source": [
"import google.cloud.aiplatform as aiplatform\n",
"import tensorflow_data_validation as tfdv\n",
"from tensorflow_data_validation.utils import io_util \n",
"from tensorflow_metadata.proto.v0 import statistics_pb2\n",
"\n",
"MODEL_DISPLAY_NAME=f\"batch_prediction_monitoring_test_model_{datetime.now().strftime('%Y%m%d%H%M%S')}\"\n",
"CONTAINER_IMAGE_URI=\"us-docker.pkg.dev/cloud-aiplatform/prediction/tf2-cpu.2-4:latest\"\n",
"ARTIFACT_URI=\"gs://mco-mm/churn\"\n",
"\n",
"output = ! gcloud ai models upload \\\n",
" --region=$REGION \\\n",
" --display-name=$MODEL_DISPLAY_NAME \\\n",
" --artifact-uri=$ARTIFACT_URI \\\n",
" --container-image-uri=$CONTAINER_IMAGE_URI \\\n",
" --format=\"value(model)\"\n",
"MODEL_ID = output[1].split(\"/\")[5]\n",
"print(f\"Model {MODEL_ID} created.\")"
"from tensorflow_data_validation.utils import io_util\n",
"from tensorflow_metadata.proto.v0 import statistics_pb2"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "init_aip:mbsdk,all"
},
"source": [
"### Initialize Vertex AI SDK for Python\n",
"\n",
"Initialize the Vertex AI SDK for Python for your project and corresponding bucket."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "init_aip:mbsdk,all"
},
"outputs": [],
"source": [
"aiplatform.init(project=PROJECT_ID, location=REGION)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "accelerators:training,prediction"
},
"source": [
"#### Set hardware accelerators\n",
"\n",
"You can set hardware accelerators for prediction (e.g., GPUs) or choose not to use any (CPU). Hardware accelertors lower the latency response for a prediction request. When choosing a hardware accelerators, consider the additional cost trade-off over latency.\n",
"\n",
"Set the variables `DEPLOY_GPU/DEPLOY_NGPU` to use a container image supporting a GPU and the number of GPUs allocated to the virtual machine (VM) instance. For example, to use a GPU container image with 4 Nvidia Tesla K80 GPUs allocated to each VM, you would specify:\n",
"\n",
" (aiplatform.gapic.AcceleratorType.NVIDIA_TESLA_K80, 4)\n",
"\n",
"See the [locations where accelerators are available](https://cloud.google.com/vertex-ai/docs/general/locations#accelerators).\n",
"\n",
"Otherwise specify `(None, None)` to use a container image to run on a CPU."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xd5PLXDTlugv"
},
"outputs": [],
"source": [
"GPU = False\n",
"if GPU:\n",
" DEPLOY_GPU, DEPLOY_NGPU = (aiplatform.gapic.AcceleratorType.NVIDIA_TESLA_K80, 1)\n",
"else:\n",
" DEPLOY_GPU, DEPLOY_NGPU = (None, None)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "container:training,prediction"
},
"source": [
"#### Set pre-built containers\n",
"\n",
"Set the pre-built Docker container image for prediction.\n",
"\n",
"For the latest list, see [Pre-built containers for prediction](https://cloud.google.com/ai-platform-unified/docs/predictions/pre-built-containers)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1u1mr18jlugv"
},
"outputs": [],
"source": [
"if GPU:\n",
" DEPLOY_VERSION = \"tf2-gpu.2-5\"\n",
"else:\n",
" DEPLOY_VERSION = \"tf2-cpu.2-5\"\n",
"\n",
"DEPLOY_IMAGE = \"{}-docker.pkg.dev/vertex-ai/prediction/{}:latest\".format(\n",
" REGION.split(\"-\")[0], DEPLOY_VERSION\n",
")\n",
"\n",
"print(\"Deployment:\", DEPLOY_IMAGE, DEPLOY_GPU, DEPLOY_NGPU)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "machine:training,prediction"
},
"source": [
"#### Set machine types\n",
"\n",
"Next, set the machine types to use for training and prediction.\n",
"\n",
"- Set the variable `DEPLOY_COMPUTE` to configure your compute resources for prediction.\n",
" - `machine type`\n",
" - `n1-standard`: 3.75GB of memory per vCPU\n",
" - `n1-highmem`: 6.5GB of memory per vCPU\n",
" - `n1-highcpu`: 0.9 GB of memory per vCPU\n",
" - `vCPUs`: number of \\[2, 4, 8, 16, 32, 64, 96 \\]\n",
"\n",
"*Note: You may also use n2 and e2 machine types for training and deployment, but they do not support GPUs*."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YAXwbqKKlugv"
},
"outputs": [],
"source": [
"MACHINE_TYPE = \"n1-standard\"\n",
"\n",
"VCPU = \"4\"\n",
"TRAIN_COMPUTE = MACHINE_TYPE + \"-\" + VCPU\n",
"print(\"Train machine type\", TRAIN_COMPUTE)\n",
"\n",
"MACHINE_TYPE = \"n1-standard\"\n",
"\n",
"VCPU = \"4\"\n",
"DEPLOY_COMPUTE = MACHINE_TYPE + \"-\" + VCPU\n",
"print(\"Deploy machine type\", DEPLOY_COMPUTE)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "9bf06cd476e9"
},
"source": [
"### Upload the model artifacts as a `Vertex AI Model` resource\n",
"\n",
"First, you upload the pre-trained custom tabular model artifacts as a `Vertex AI Model` resource using the `upload()` method, with the following parameters:\n",
"\n",
"- `display_name`: The human readable name for the `Model` resource.\n",
"- `artifact_uri`: The Cloud Storage location of the model artifacts.\n",
"- `serving_container_image`: The serving container image to use when the model is deployed to a `Vertex AI Endpoint` resource.\n",
"- `sync`: Whether to wait for the process to complete, or return immediately (async)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0193f247e216"
},
"outputs": [],
"source": [
"MODEL_ARTIFACT_URI = \"gs://mco-mm/churn\"\n",
"\n",
"model = aiplatform.Model.upload(\n",
" display_name=\"churn_\" + UUID,\n",
" artifact_uri=MODEL_ARTIFACT_URI,\n",
" serving_container_image_uri=DEPLOY_IMAGE,\n",
" sync=True,\n",
")\n",
"\n",
"print(model)"
]
},
{
"cell_type": "markdown",
"id": "a4305ddf",
"metadata": {
"id": "a4305ddf"
},
"source": [
"## Submit a batch prediction request with model monitoring enabled"
"## Submit a batch prediction request with model monitoring enabled\n"
]
},
{
"cell_type": "markdown",
"id": "053fde99",
"metadata": {
"id": "053fde99"
},
@@ -503,7 +736,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "b832ad31",
"metadata": {
"id": "b832ad31"
},
@@ -511,20 +743,17 @@
"source": [
"# Copy files to your projects gs bucket to avoid permission issues.\n",
"# Ignore any error(s) for bucket already exists.\n",
"OUTPUT_GS_PATH = f\"gs://{PROJECT_ID.replace('-', '_')}_bp_mm_output\"\n",
"INPUT_GS_PATH = f\"gs://{PROJECT_ID.replace('-', '_')}_bp_mm_input\"\n",
"OUTPUT_GS_PATH = f\"{BUCKET_URI}/bp_mm_output\"\n",
"INPUT_GS_PATH = f\"{BUCKET_URI}/bp_mm_input\"\n",
"PUBLIC_TRAINING_DATASET = \"gs://bp_mm_public_data/churn/churn_bp_insample.csv\"\n",
"TRAINING_DATASET = f\"{INPUT_GS_PATH}/churn_bp_insample.csv\"\n",
"TRAINING_DATASET_FORMAT = \"csv\"\n",
"\n",
"! gsutil mb -p {PROJECT_ID} -l {REGION} -b on {INPUT_GS_PATH}\n",
"! gsutil mb -p {PROJECT_ID} -l {REGION} -b on {OUTPUT_GS_PATH}\n",
"! gsutil copy $PUBLIC_TRAINING_DATASET $INPUT_GS_PATH"
]
},
{
"cell_type": "markdown",
"id": "34c95126",
"metadata": {
"id": "34c95126"
},
@@ -541,21 +770,18 @@
{
"cell_type": "code",
"execution_count": null,
"id": "3a54368a",
"metadata": {
"id": "3a54368a"
},
"outputs": [],
"source": [
"now = datetime.now()\n",
"INPUT_URI = \"gs://bp_mm_public_data/churn/churn_bp_outsample.jsonl\"\n",
"OUTPUT_URI = OUTPUT_GS_PATH\n",
"INSTANCES_FORMAT = \"jsonl\"\n",
"PREDICTIONS_FORMAT = \"jsonl\"\n",
"JOB_NAME_PREFIX = \"bp_mm_demo\"\n",
"MODEL_NAME = f\"projects/{PROJECT_ID}/locations/{REGION}/models/{MODEL_ID}\"\n",
"MACHINE_TYPE = \"n1-standard-8\"\n",
"BATCH_PREDICTION_JOB_NAME = JOB_NAME_PREFIX + \"_\" + now.strftime(\"%Y%m%d%H%M%S\")\n",
"MODEL_NAME = model.resource_name\n",
"BATCH_PREDICTION_JOB_NAME = JOB_NAME_PREFIX + \"_\" + UUID\n",
"\n",
"from google.cloud.aiplatform_v1beta1.types import (\n",
" BatchDedicatedResources, BatchPredictionJob, GcsDestination, GcsSource,\n",
@@ -573,7 +799,7 @@
" gcs_destination=GcsDestination(output_uri_prefix=OUTPUT_URI),\n",
" ),\n",
" dedicated_resources=BatchDedicatedResources(\n",
" machine_spec=MachineSpec(machine_type=MACHINE_TYPE),\n",
" machine_spec=MachineSpec(machine_type=DEPLOY_COMPUTE),\n",
" starting_replica_count=1,\n",
" max_replica_count=1,\n",
" ),\n",
@@ -604,7 +830,6 @@
},
{
"cell_type": "markdown",
"id": "cae39778",
"metadata": {
"id": "cae39778"
},
@@ -617,7 +842,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "bcdd4a47",
"metadata": {
"id": "bcdd4a47"
},
@@ -638,7 +862,6 @@
},
{
"cell_type": "markdown",
"id": "49ec90a0",
"metadata": {
"id": "49ec90a0"
},
@@ -651,7 +874,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "c30496b5",
"metadata": {
"id": "c30496b5"
},
@@ -664,7 +886,6 @@
},
{
"cell_type": "markdown",
"id": "831651c2",
"metadata": {
"id": "831651c2"
},
@@ -684,7 +905,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "a705c10b",
"metadata": {
"id": "a705c10b"
},
@@ -695,7 +915,6 @@
},
{
"cell_type": "markdown",
"id": "2bbdddac",
"metadata": {
"id": "2bbdddac"
},
@@ -708,7 +927,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "f6c674e9",
"metadata": {
"id": "f6c674e9"
},
@@ -746,7 +964,6 @@
},
{
"cell_type": "markdown",
"id": "233b1266",
"metadata": {
"id": "233b1266"
},
@@ -759,7 +976,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "4e8c00a7",
"metadata": {
"id": "4e8c00a7"
},
@@ -774,7 +990,6 @@
},
{
"cell_type": "markdown",
"id": "497a0016",
"metadata": {
"id": "497a0016"
},
@@ -790,7 +1005,6 @@
{
"cell_type": "code",
"execution_count": null,
"id": "eabc3f81",
"metadata": {
"id": "eabc3f81"
},
@@ -806,7 +1020,6 @@
},
{
"cell_type": "markdown",
"id": "0aa0219d",
"metadata": {
"id": "0aa0219d"
},