diff --git a/packages/google-cloud-automl/samples/beta/automl_vision_create_model_test.py b/packages/google-cloud-automl/samples/beta/automl_vision_create_model_test.py new file mode 100644 index 000000000000..bcb6c323e1e4 --- /dev/null +++ b/packages/google-cloud-automl/samples/beta/automl_vision_create_model_test.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +from google.cloud import automl_v1beta1 as automl +import pytest + +project_id = os.environ["GOOGLE_CLOUD_PROJECT"] +compute_region = "us-central1" + + +@pytest.mark.skip(reason="creates too many models") +def test_model_create_status_delete(capsys): + # create model + client = automl.AutoMlClient() + model_name = "test_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + project_location = client.location_path(project_id, compute_region) + my_model = { + "display_name": model_name, + "dataset_id": "3946265060617537378", + "image_classification_model_metadata": {"train_budget": 24}, + } + response = client.create_model(project_location, my_model) + operation_name = response.operation.name + assert operation_name + + # cancel operation + response.cancel() diff --git a/packages/google-cloud-automl/samples/beta/automl_vision_model.py b/packages/google-cloud-automl/samples/beta/automl_vision_model.py new file mode 100755 index 000000000000..04aa4c9476e4 --- /dev/null +++ b/packages/google-cloud-automl/samples/beta/automl_vision_model.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This application demonstrates how to perform basic operations on model +with the Google AutoML Vision API. + +For more information, the documentation at +https://cloud.google.com/vision/automl/docs. +""" + +import argparse +import os + + +def create_model( + project_id, compute_region, dataset_id, model_name, train_budget=24 +): + """Create a model.""" + # [START automl_vision_create_model] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # dataset_id = 'DATASET_ID_HERE' + # model_name = 'MODEL_NAME_HERE' + # train_budget = integer amount for maximum cost of model + + from google.cloud import automl_v1beta1 as automl + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = client.location_path(project_id, compute_region) + + # Set model name and model metadata for the image dataset. + my_model = { + "display_name": model_name, + "dataset_id": dataset_id, + "image_classification_model_metadata": {"train_budget": train_budget} + if train_budget + else {}, + } + + # Create a model with the model metadata in the region. + response = client.create_model(project_location, my_model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") + + # [END automl_vision_create_model] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + subparsers = parser.add_subparsers(dest="command") + + create_model_parser = subparsers.add_parser( + "create_model", help=create_model.__doc__ + ) + create_model_parser.add_argument("dataset_id") + create_model_parser.add_argument("model_name") + create_model_parser.add_argument( + "train_budget", type=int, nargs="?", default=0 + ) + + project_id = os.environ["PROJECT_ID"] + compute_region = os.environ["REGION_NAME"] + + args = parser.parse_args() + + if args.command == "create_model": + create_model( + project_id, + compute_region, + args.dataset_id, + args.model_name, + args.train_budget, + ) diff --git a/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/Dockerfile b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/Dockerfile new file mode 100644 index 000000000000..d447bcc57544 --- /dev/null +++ b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/Dockerfile @@ -0,0 +1,29 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG TF_SERVING_IMAGE_TAG +FROM tensorflow/serving:${TF_SERVING_IMAGE_TAG} + +ENV GCS_READ_CACHE_MAX_STALENESS 300 +ENV GCS_STAT_CACHE_MAX_AGE 300 +ENV GCS_MATCHING_PATHS_CACHE_MAX_AGE 300 + +EXPOSE 8500 +EXPOSE 8501 +ENTRYPOINT /usr/bin/tensorflow_model_server \ + --port=8500 \ + --rest_api_port=8501 \ + --model_base_path=/tmp/mounted_model/ \ + --tensorflow_session_parallelism=0 \ + --file_system_poll_wait_seconds=31540000 diff --git a/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/README.md b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/README.md new file mode 100644 index 000000000000..da8cc50ed66f --- /dev/null +++ b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/README.md @@ -0,0 +1,78 @@ +# AutoML Vision Edge Container Prediction + +This is an example to show how to predict with AutoML Vision Edge Containers. +The test (automl_vision_edge_container_predict_test.py) shows an automatical way +to run the prediction. + +If you want to try the test manually with a sample model, please install +[gsutil tools](https://cloud.google.com/storage/docs/gsutil_install) and +[Docker CE](https://docs.docker.com/install/) first, and then follow the steps +below. All the following instructions with commands assume you are in this +folder with system variables as + +```bash +$ CONTAINER_NAME=AutomlVisionEdgeContainerPredict +$ PORT=8505 +``` + ++ Step 1. Pull the Docker image. + +```bash +# This is a CPU TFServing 1.14.0 with some default settings compiled from +# https://hub.docker.com/r/tensorflow/serving. +$ DOCKER_GCS_DIR=gcr.io/cloud-devrel-public-resources +$ CPU_DOCKER_GCS_PATH=${DOCKER_GCS_DIR}/gcloud-container-1.14.0:latest +$ sudo docker pull ${CPU_DOCKER_GCS_PATH} +``` + ++ Step 2. Get a sample saved model. + +```bash +$ MODEL_GCS_DIR=gs://cloud-samples-data/vision/edge_container_predict +$ SAMPLE_SAVED_MODEL=${MODEL_GCS_DIR}/saved_model.pb +$ mkdir model_path +$ YOUR_MODEL_PATH=$(realpath model_path) +$ gsutil -m cp ${SAMPLE_SAVED_MODEL} ${YOUR_MODEL_PATH} +``` + ++ Step 3. Run the Docker container. + +```bash +$ sudo docker run --rm --name ${CONTAINER_NAME} -p ${PORT}:8501 -v \ + ${YOUR_MODEL_PATH}:/tmp/mounted_model/0001 -t ${CPU_DOCKER_GCS_PATH} +``` + ++ Step 4. Send a prediction request. + +```bash +$ python automl_vision_edge_container_predict.py --image_file_path=./test.jpg \ + --image_key=1 --port_number=${PORT} +``` + +The outputs are + +``` +{ + 'predictions': + [ + { + 'scores': [0.0914393, 0.458942, 0.027604, 0.386767, 0.0352474], + labels': ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips'], + 'key': '1' + } + ] +} +``` + ++ Step 5. Stop the container. + +```bash +sudo docker stop ${CONTAINER_NAME} +``` + +Note: The docker image is uploaded with the following command. + +```bash +gcloud builds --project=cloud-devrel-public-resources \ + submit --config cloudbuild.yaml +``` diff --git a/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/automl_vision_edge_container_predict.py b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/automl_vision_edge_container_predict.py new file mode 100644 index 000000000000..a5b1ed9f2d44 --- /dev/null +++ b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/automl_vision_edge_container_predict.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +r"""This is an example to call REST API from TFServing docker containers. + +Examples: + python automl_vision_edge_container_predict.py \ + --image_file_path=./test.jpg --image_key=1 --port_number=8051 + +""" + +import argparse +# [START automl_vision_edge_container_predict] +import base64 +import io +import json + +import requests + + +def container_predict(image_file_path, image_key, port_number=8501): + """Sends a prediction request to TFServing docker container REST API. + + Args: + image_file_path: Path to a local image for the prediction request. + image_key: Your chosen string key to identify the given image. + port_number: The port number on your device to accept REST API calls. + Returns: + The response of the prediction request. + """ + + with io.open(image_file_path, 'rb') as image_file: + encoded_image = base64.b64encode(image_file.read()).decode('utf-8') + + # The example here only shows prediction with one image. You can extend it + # to predict with a batch of images indicated by different keys, which can + # make sure that the responses corresponding to the given image. + instances = { + 'instances': [ + {'image_bytes': {'b64': str(encoded_image)}, + 'key': image_key} + ] + } + + # This example shows sending requests in the same server that you start + # docker containers. If you would like to send requests to other servers, + # please change localhost to IP of other servers. + url = 'http://localhost:{}/v1/models/default:predict'.format(port_number) + + response = requests.post(url, data=json.dumps(instances)) + print(response.json()) + # [END automl_vision_edge_container_predict] + return response.json() + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--image_file_path', type=str) + parser.add_argument('--image_key', type=str, default='1') + parser.add_argument('--port_number', type=int, default=8501) + args = parser.parse_args() + + container_predict(args.image_file_path, args.image_key, args.port_number) + + +if __name__ == '__main__': + main() diff --git a/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/automl_vision_edge_container_predict_test.py b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/automl_vision_edge_container_predict_test.py new file mode 100644 index 000000000000..327513c034b7 --- /dev/null +++ b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/automl_vision_edge_container_predict_test.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for automl_vision_edge_container_predict. + +The test will automatically start a container with a sample saved_model.pb, +send a request with one image, verify the response and delete the started +container. + +If you want to try the test, please install +[gsutil tools](https://cloud.google.com/storage/docs/gsutil_install) and +[Docker CE](https://docs.docker.com/install/) first. + +Examples: +sudo python -m pytest automl_vision_edge_container_predict_test.py +""" + +import os +import subprocess +import tempfile +import time + +import pytest + +import automl_vision_edge_container_predict as predict # noqa + + +IMAGE_FILE_PATH = os.path.join(os.path.dirname(__file__), 'test.jpg') +# The cpu docker gcs path is from 'Edge container tutorial'. +CPU_DOCKER_GCS_PATH = '{}'.format( + 'gcr.io/cloud-devrel-public-resources/gcloud-container-1.14.0:latest') +# The path of a sample saved model. +SAMPLE_SAVED_MODEL = '{}'.format( + 'gs://cloud-samples-data/vision/edge_container_predict/saved_model.pb') +# Container Name. +NAME = 'AutomlVisionEdgeContainerPredictTest' +# Port Number. +PORT_NUMBER = 8505 + + +@pytest.fixture +def edge_container_predict_server_port(): + # set up + # Pull the CPU docker. + subprocess.check_output( + ['docker', 'pull', CPU_DOCKER_GCS_PATH], + env={'DOCKER_API_VERSION': '1.38'}) + + if os.environ.get('TRAMPOLINE_VERSION'): + # Use /tmp + model_path = tempfile.TemporaryDirectory() + else: + # Use project directory with Trampoline V1. + model_path = tempfile.TemporaryDirectory(dir=os.path.dirname(__file__)) + print("Using model_path: {}".format(model_path)) + # Get the sample saved model. + subprocess.check_output( + ['gsutil', '-m', 'cp', SAMPLE_SAVED_MODEL, model_path.name]) + + # Start the CPU docker. + subprocess.Popen(['docker', 'run', '--rm', '--name', NAME, '-v', + model_path.name + ':/tmp/mounted_model/0001', '-p', + str(PORT_NUMBER) + ':8501', '-t', + CPU_DOCKER_GCS_PATH], + env={'DOCKER_API_VERSION': '1.38'}) + # Sleep a few seconds to wait for the container running. + time.sleep(10) + + yield PORT_NUMBER + + # tear down + # Stop the container. + subprocess.check_output( + ['docker', 'stop', NAME], env={'DOCKER_API_VERSION': '1.38'}) + # Remove the docker image. + subprocess.check_output( + ['docker', 'rmi', CPU_DOCKER_GCS_PATH], + env={'DOCKER_API_VERSION': '1.38'}) + # Remove the temporery directory. + model_path.cleanup() + + +def test_edge_container_predict(capsys, edge_container_predict_server_port): + # If you send requests with one image each time, the key value does not + # matter. If you send requests with multiple images, please used different + # keys to indicated different images, which can make sure that the + # responses corresponding to the given image. + image_key = '1' + # Send a request. + response = predict.container_predict( + IMAGE_FILE_PATH, image_key, PORT_NUMBER) + # Verify the response. + assert 'predictions' in response + assert 'key' in response['predictions'][0] + assert image_key == response['predictions'][0]['key'] diff --git a/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/cloudbuild.yaml b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/cloudbuild.yaml new file mode 100644 index 000000000000..5b0760254b4b --- /dev/null +++ b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/cloudbuild.yaml @@ -0,0 +1,26 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +timeout: 3600s + +steps: + - name: 'gcr.io/cloud-builders/docker' + args: ['build', '-t', 'gcr.io/$PROJECT_ID/gcloud-container-1.14.0', + '--build-arg', 'TF_SERVING_IMAGE_TAG=1.14.0', '.'] + - name: 'gcr.io/cloud-builders/docker' + args: ['build', '-t', 'gcr.io/$PROJECT_ID/gcloud-container-1.14.0-gpu', + '--build-arg', 'TF_SERVING_IMAGE_TAG=1.14.0-gpu', '.'] +images: + - 'gcr.io/$PROJECT_ID/gcloud-container-1.14.0' + - 'gcr.io/$PROJECT_ID/gcloud-container-1.14.0-gpu' diff --git a/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/test.jpg b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/test.jpg new file mode 100644 index 000000000000..4873e8d1b523 Binary files /dev/null and b/packages/google-cloud-automl/samples/vision_edge/edge_container_predict/test.jpg differ diff --git a/packages/google-cloud-automl/samples/vision_edge/resources/test.png b/packages/google-cloud-automl/samples/vision_edge/resources/test.png new file mode 100644 index 000000000000..653342a46e58 Binary files /dev/null and b/packages/google-cloud-automl/samples/vision_edge/resources/test.png differ