diff --git a/deployment/tfhub/object-detection-base64.ipynb b/deployment/tfhub/object-detection-base64.ipynb new file mode 100644 index 0000000..12b29a5 --- /dev/null +++ b/deployment/tfhub/object-detection-base64.ipynb @@ -0,0 +1,603 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "rKn_w61SNijN" + }, + "source": [ + "# Object Detection - SSD Mobilenet V2 from TensorFlow Hub (Base64 Images)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DF3TUJI2VfYt" + }, + "source": [ + "This model identifies objects present in images, returning its scores, labels and bounding boxes.\n", + "\n", + "We are using a dataset from [UCF](https://www.crcv.ucf.edu/data/GMCP_Geolocalization/#Dataset) and the model [SSD Mobilenet V2](https://tfhub.dev/google/openimages_v4/ssd/mobilenet_v2/1) from [TensorFlow Hub](https://www.tensorflow.org/hub)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vTeFMlSIVic0" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wvqC2djzNijQ" + }, + "source": [ + "## 1. Dependencies" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0flMWU41BY2W" + }, + "source": [ + "This notebook has been tested with **Python 3.8.15** and the following package versions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2T-GZ3zUNijQ" + }, + "outputs": [], + "source": [ + "%%capture\n", + "!pip install beautifulsoup4==4.6.3\n", + "!pip install dill==0.3.6\n", + "!pip install numpy==1.23.5\n", + "!pip install Pillow==7.1.2\n", + "!pip install requests==2.28.1\n", + "!pip install tensorflow==2.11.0\n", + "!pip install tensorflow-hub==0.12.0\n", + "!pip install verta==0.21.1\n", + "!pip install wget==3.2" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CtIgsA4aB2ga" + }, + "source": [ + "## 2. Imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7SuugL_lOuaN" + }, + "outputs": [], + "source": [ + "import base64\n", + "import concurrent.futures\n", + "import io\n", + "import numpy as np\n", + "import os\n", + "import pandas as pd\n", + "import requests\n", + "import tempfile\n", + "import tensorflow as tf\n", + "import tensorflow_hub as hub\n", + "import time\n", + "import wget\n", + "\n", + "from bs4 import BeautifulSoup\n", + "from PIL import Image, ImageOps\n", + "from verta import Client\n", + "from verta.endpoint.autoscaling import Autoscaling\n", + "from verta.endpoint.autoscaling.metrics import CpuUtilizationTarget, MemoryUtilizationTarget, RequestsPerWorkerTarget\n", + "from verta.endpoint.resources import Resources\n", + "from verta.endpoint.update import DirectUpdateStrategy\n", + "from verta.environment import Python\n", + "from verta.registry import VertaModelBase, verify_io\n", + "from verta.utils import ModelAPI" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LB20pSYuXcCD" + }, + "source": [ + "## 3. Verta Set Up" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hGwbnFGlXgJh" + }, + "outputs": [], + "source": [ + "os.environ['VERTA_HOST'] = ''\n", + "os.environ['VERTA_EMAIL'] = ''\n", + "os.environ['VERTA_DEV_KEY'] = ''" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wVcbn1_3Xhtm", + "outputId": "5846dfc7-3243-4784-d2bc-672d25dc6af7" + }, + "outputs": [], + "source": [ + "client = Client(os.environ['VERTA_HOST'])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5bBHXvKnX_Je" + }, + "source": [ + "## 4. Model Class" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "o3YNlqVMEi6c" + }, + "outputs": [], + "source": [ + "class DetectObject(VertaModelBase):\n", + " def __init__(self, artifacts=None):\n", + " module_handle = 'https://tfhub.dev/google/openimages_v4/ssd/mobilenet_v2/1'\n", + " self.detector = hub.load(module_handle).signatures['default']\n", + " \n", + " def handle_img(self, img, width=640, height=480):\n", + " _, path = tempfile.mkstemp(suffix='.jpg')\n", + " img_encoded = img.encode('utf-8')\n", + " img_bytes = io.BytesIO(base64.b64decode(img_encoded))\n", + " img_arr = np.array(Image.open(img_bytes), dtype=np.uint8)\n", + " img = Image.fromarray(img_arr)\n", + " img = ImageOps.grayscale(img)\n", + " img.thumbnail((width, height), Image.LANCZOS)\n", + " img.save(path)\n", + "\n", + " return path\n", + "\n", + " def load_img(self, path):\n", + " img = tf.io.read_file(path)\n", + " img = tf.image.decode_jpeg(img, channels=3)\n", + " \n", + " return img\n", + "\n", + " def filter_results(self, file_name, response, entity='Car', min_score=.2):\n", + " unused_keys = ['detection_class_labels', 'detection_class_names']\n", + " response = {key: value.numpy().tolist() for key, value in response.items()}\n", + " response = {key: val for key, val in response.items() if key not in unused_keys}\n", + " response['detection_class_entities'] = [v.decode() for v in response['detection_class_entities']]\n", + "\n", + " entities = response['detection_class_entities']\n", + " scores = response['detection_scores']\n", + " bboxes = response['detection_boxes']\n", + " result = {}\n", + "\n", + " for i in range(len(entities)):\n", + " if entities[i] == entity and scores[i] >= min_score:\n", + " ymin, xmin, ymax, xmax = bboxes[i]\n", + " result = {\n", + " 'file_name': file_name,\n", + " 'has_car': True,\n", + " 'score': scores[i],\n", + " 'bboxes': {'ymin': ymin, 'xmin': xmin, 'ymax': ymax, 'xmax': xmax}\n", + " }\n", + " break\n", + "\n", + " if len(result) == 0:\n", + " result = {\n", + " 'file_name': file_name,\n", + " 'has_car': False,\n", + " 'score': 0,\n", + " 'bboxes': {'ymin': 0, 'xmin': 0, 'ymax': 0, 'xmax': 0}\n", + " }\n", + " \n", + " return result\n", + "\n", + " def run_detector(self, file_name, image_path):\n", + " img = self.load_img(image_path)\n", + " img = tf.image.convert_image_dtype(img, tf.float32)[tf.newaxis, ...]\n", + " \n", + " response = self.detector(img)\n", + " result = self.filter_results(file_name, response)\n", + " \n", + " return result\n", + "\n", + " def detect_objects(self, file_name, img):\n", + " start_time = time.time()\n", + " image_path = self.handle_img(img)\n", + " result = self.run_detector(file_name, image_path)\n", + " end_time = time.time()\n", + "\n", + " return result\n", + "\n", + " @verify_io\n", + " def predict(self, data):\n", + " file_name, img = data\n", + " result = self.detect_objects(file_name, img)\n", + "\n", + " return result" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5SvthV9gd4lk" + }, + "source": [ + "## 5. Model Register" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "UR7XtPNOHTgO", + "outputId": "13f00122-72ab-4ba5-b4c1-e518bfbe04b3" + }, + "outputs": [], + "source": [ + "registered_model = client.get_or_create_registered_model(name='Object Detection - TF Hub')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "vFlrCL2EWnJR", + "outputId": "ccb50cb2-2080-4ba3-b41e-d3d0be4db0a8" + }, + "outputs": [], + "source": [ + "model = registered_model.create_standard_model(\n", + " name = 'base64',\n", + " model_cls = DetectObject,\n", + " model_api = ModelAPI(\n", + " [{'file_name': '', 'img': ''}],\n", + " [{\n", + " 'file_name': '',\n", + " 'has_car': False,\n", + " 'score': 0,\n", + " 'bboxes': {\n", + " 'ymin': 0,\n", + " 'xmin': 0,\n", + " 'ymax': 0,\n", + " 'xmax': 0\n", + " }\n", + " }]\n", + " ),\n", + " environment = Python(requirements = ['tensorflow', 'tensorflow_hub', 'dill', 'Pillow', 'wget'])\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "60NCs0j8KHvg" + }, + "source": [ + "## 6. Auto Scaling and Resources" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "LBLEtVauKBNP" + }, + "outputs": [], + "source": [ + "autoscaling = Autoscaling(min_replicas=1, max_replicas=20, min_scale=0.1, max_scale=10)\n", + "autoscaling.add_metric(CpuUtilizationTarget(0.6))\n", + "autoscaling.add_metric(MemoryUtilizationTarget(0.7))\n", + "autoscaling.add_metric(RequestsPerWorkerTarget(1))\n", + "resources = Resources(cpu=1., memory='4Gi') " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Y0gm6fOse6BP" + }, + "source": [ + "## 7. Model Endpoint" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wZi8X-LoCORa" + }, + "outputs": [], + "source": [ + "endpoint = client.get_or_create_endpoint('object-detection-base64')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "F4-9M2_xKF7R", + "outputId": "cc97b5dc-b66f-45d5-862c-fb66670f2742" + }, + "outputs": [], + "source": [ + "%%time\n", + "endpoint.update(\n", + " model, \n", + " strategy = DirectUpdateStrategy(),\n", + " autoscaling = autoscaling,\n", + " resources = resources,\n", + " wait = True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0Zgc18ocXbCE" + }, + "outputs": [], + "source": [ + "deployed_model = endpoint.get_deployed_model()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NbxYiJJsX5oL" + }, + "source": [ + "## 8. Predictions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "p7x7dfWoCNxK" + }, + "outputs": [], + "source": [ + "url = 'http://www.cs.ucf.edu/~aroshan/index_files/Dataset_PitOrlManh/images/'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4nS6rzzyK58c" + }, + "outputs": [], + "source": [ + "req = requests.get(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gH_5iPC84jmu" + }, + "outputs": [], + "source": [ + "soup = BeautifulSoup(req.text, 'lxml')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Hl_MzSFXX2oo" + }, + "outputs": [], + "source": [ + "urls = []\n", + "\n", + "for link in soup.find_all('a'):\n", + " href = link.get('href')\n", + " \n", + " if href.endswith('.jpg'):\n", + " image_url = f\"{url}/{href}\"\n", + " urls.append(image_url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ifi5nJeBX_1G" + }, + "outputs": [], + "source": [ + "urls = urls[:10]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6puNawPEYBJl" + }, + "outputs": [], + "source": [ + "def process_image(url):\n", + " file_name = os.path.basename(url)\n", + " wget.download(url, file_name)\n", + "\n", + " with open(file_name, 'rb') as img:\n", + " img_encoded = base64.b64encode(img.read())\n", + " img = img_encoded.decode('utf-8')\n", + " \n", + " return deployed_model.predict([file_name, img])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5msNtuwt8AXa", + "outputId": "5df1b40c-45bd-4eb3-ba54-72bd16b75e65" + }, + "outputs": [], + "source": [ + "results = []\n", + "start_time = time.time()\n", + "\n", + "with concurrent.futures.ThreadPoolExecutor() as executor:\n", + " for result in executor.map(process_image, urls):\n", + " results.append(result)\n", + "\n", + "end_time = time.time()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jGY1FLwWYBXq" + }, + "outputs": [], + "source": [ + "total_time = end_time - start_time\n", + "total_time = time.strftime('%Hh %Mm %Ss', time.gmtime(total_time))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-k2mErxvYBdZ", + "outputId": "0ec4f897-0495-45b3-c8af-25d808dad3a7" + }, + "outputs": [], + "source": [ + "print(f\"Processing Time: {total_time} for {len(urls)} images.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sy8guzzgA5df" + }, + "outputs": [], + "source": [ + "results_rows = []\n", + "\n", + "for img_result in results:\n", + " img_result = img_result.copy()\n", + " img_result.update(img_result.pop('bboxes'))\n", + " results_rows.append(pd.Series(img_result))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XOKZr5qBJqup" + }, + "outputs": [], + "source": [ + "df = pd.concat(results_rows, axis=1).T" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 363 + }, + "id": "pi546PBJJqj9", + "outputId": "6f599bef-50e3-4a03-d4ed-340a8f6e2606" + }, + "outputs": [], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VeV_oVzddA0m" + }, + "outputs": [], + "source": [ + "endpoint.delete()" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]" + }, + "vscode": { + "interpreter": { + "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1" + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/deployment/tfhub/object-detection-url.ipynb b/deployment/tfhub/object-detection-url.ipynb new file mode 100644 index 0000000..79b1ab9 --- /dev/null +++ b/deployment/tfhub/object-detection-url.ipynb @@ -0,0 +1,628 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "rKn_w61SNijN" + }, + "source": [ + "# Object Detection - SSD Mobilenet V2 from TensorFlow Hub (Image URLS)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DF3TUJI2VfYt" + }, + "source": [ + "This model identifies objects present in images, returning its scores, labels and bounding boxes.\n", + "\n", + "We are using a dataset from [UCF](https://www.crcv.ucf.edu/data/GMCP_Geolocalization/#Dataset) and the model [SSD Mobilenet V2](https://tfhub.dev/google/openimages_v4/ssd/mobilenet_v2/1) from [TensorFlow Hub](https://www.tensorflow.org/hub)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vTeFMlSIVic0" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wvqC2djzNijQ" + }, + "source": [ + "## 1. Dependencies" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0flMWU41BY2W" + }, + "source": [ + "This notebook has been tested with **Python 3.8.15** and the following package versions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2T-GZ3zUNijQ" + }, + "outputs": [], + "source": [ + "%%capture\n", + "!pip install beautifulsoup4==4.6.3\n", + "!pip install dill==0.3.6\n", + "!pip install Pillow==7.1.2\n", + "!pip install requests==2.28.1\n", + "!pip install tensorflow==2.11.0\n", + "!pip install tensorflow-hub==0.12.0\n", + "!pip install verta==0.21.1\n", + "!pip install wget==3.2" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CtIgsA4aB2ga" + }, + "source": [ + "## 2. Imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7SuugL_lOuaN" + }, + "outputs": [], + "source": [ + "import concurrent.futures\n", + "import os\n", + "import pandas as pd\n", + "import requests\n", + "import tempfile\n", + "import tensorflow as tf\n", + "import tensorflow_hub as hub\n", + "import time\n", + "import wget\n", + "\n", + "from bs4 import BeautifulSoup\n", + "from PIL import Image, ImageOps\n", + "from verta import Client\n", + "from verta.endpoint.autoscaling import Autoscaling\n", + "from verta.endpoint.autoscaling.metrics import CpuUtilizationTarget, MemoryUtilizationTarget, RequestsPerWorkerTarget\n", + "from verta.endpoint.resources import Resources\n", + "from verta.endpoint.update import DirectUpdateStrategy\n", + "from verta.environment import Python\n", + "from verta.registry import VertaModelBase, verify_io\n", + "from verta.utils import ModelAPI" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LB20pSYuXcCD" + }, + "source": [ + "## 3. Verta Set Up" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hGwbnFGlXgJh" + }, + "outputs": [], + "source": [ + "os.environ['VERTA_HOST'] = ''\n", + "os.environ['VERTA_EMAIL'] = ''\n", + "os.environ['VERTA_DEV_KEY'] = ''" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wVcbn1_3Xhtm", + "outputId": "f14f925f-7a48-4832-f95e-fc4de209514f" + }, + "outputs": [], + "source": [ + "client = Client(os.environ['VERTA_HOST'])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5bBHXvKnX_Je" + }, + "source": [ + "## 4. Model Class" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "o3YNlqVMEi6c" + }, + "outputs": [], + "source": [ + "class DetectObject(VertaModelBase):\n", + " def __init__(self, artifacts=None):\n", + " module_handle = 'https://tfhub.dev/google/openimages_v4/ssd/mobilenet_v2/1'\n", + " self.detector = hub.load(module_handle).signatures['default']\n", + " \n", + " def handle_img(self, file_name, url, width=640, height=480):\n", + " wget.download(url, file_name)\n", + " img = Image.open(file_name)\n", + " img = ImageOps.grayscale(img)\n", + " img.thumbnail((width, height), Image.LANCZOS)\n", + " img.save(file_name)\n", + "\n", + " def load_img(self, path):\n", + " img = tf.io.read_file(path)\n", + " img = tf.image.decode_jpeg(img, channels=3)\n", + " \n", + " return img\n", + "\n", + " def filter_results(self, file_name, response, entity='Car', min_score=.2):\n", + " unused_keys = ['detection_class_labels', 'detection_class_names']\n", + " response = {key: value.numpy().tolist() for key, value in response.items()}\n", + " response = {key: val for key, val in response.items() if key not in unused_keys}\n", + " response['detection_class_entities'] = [v.decode() for v in response['detection_class_entities']]\n", + "\n", + " entities = response['detection_class_entities']\n", + " scores = response['detection_scores']\n", + " bboxes = response['detection_boxes']\n", + " result = {}\n", + "\n", + " for i in range(len(entities)):\n", + " if entities[i] == entity and scores[i] >= min_score:\n", + " ymin, xmin, ymax, xmax = bboxes[i]\n", + " result = {\n", + " 'file_name': file_name,\n", + " 'has_car': True,\n", + " 'score': scores[i],\n", + " 'bboxes': {'ymin': ymin, 'xmin': xmin, 'ymax': ymax, 'xmax': xmax}\n", + " }\n", + " break\n", + "\n", + " if len(result) == 0:\n", + " result = {\n", + " 'file_name': file_name,\n", + " 'has_car': False,\n", + " 'score': 0,\n", + " 'bboxes': {'ymin': 0, 'xmin': 0, 'ymax': 0, 'xmax': 0}\n", + " }\n", + " \n", + " return result\n", + "\n", + " def run_detector(self, file_name):\n", + " img = self.load_img(file_name)\n", + " img = tf.image.convert_image_dtype(img, tf.float32)[tf.newaxis, ...]\n", + " \n", + " response = self.detector(img)\n", + " result = self.filter_results(file_name, response)\n", + " \n", + " return result\n", + "\n", + " def detect_objects(self, file_name, url):\n", + " start_time = time.time()\n", + " self.handle_img(file_name, url)\n", + " result = self.run_detector(file_name)\n", + " end_time = time.time()\n", + " \n", + " return result\n", + "\n", + " @verify_io\n", + " def predict(self, data):\n", + " result = []\n", + "\n", + " for item in data:\n", + " file_name, url = item['file_name'], item['url']\n", + " result.append(self.detect_objects(file_name, url))\n", + "\n", + " return result\n", + "\n", + " def example(self):\n", + " return [{\n", + " 'file_name': '000001_1.jpg',\n", + " 'url': 'http://www.cs.ucf.edu/~aroshan/index_files/Dataset_PitOrlManh/images/000001_1.jpg',\n", + " }]\n", + "\n", + " def describe(self):\n", + " return {\n", + " 'method': 'predict',\n", + " 'args': f\"{self.example()}\",\n", + " 'returns': \"\"\"\n", + " [\n", + " [{\n", + " 'file_name': '',\n", + " 'has_car': False,\n", + " 'score': 0,\n", + " 'bboxes': {\n", + " 'ymin': 0, \n", + " 'xmin': 0, \n", + " 'ymax': 0,\n", + " 'xmax': 0 \n", + " }\n", + " }]\n", + " ]\n", + " \"\"\",\n", + " 'description': 'Identify whether a given object is present in the image URL.',\n", + " 'input_description': 'Image URL.',\n", + " 'output_description': \"\"\"\n", + " A JSON object containing the image file name, a boolean value indicating \n", + " if the object was found in the image, its score and bounding box\n", + " \"\"\"\n", + " }" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5SvthV9gd4lk" + }, + "source": [ + "## 5. Model Register" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "UR7XtPNOHTgO", + "outputId": "99b78ecb-a7e8-452a-91dc-8c9ef7ab0faf" + }, + "outputs": [], + "source": [ + "registered_model = client.get_or_create_registered_model(name='Object Detection - TF Hub')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "vFlrCL2EWnJR", + "outputId": "976ab8fc-9343-4ff9-b127-7c3153943a7c" + }, + "outputs": [], + "source": [ + "model = registered_model.create_standard_model(\n", + " name = 'url',\n", + " model_cls = DetectObject,\n", + " model_api = ModelAPI(\n", + " [{'file_name': '', 'url': ''}],\n", + " [{\n", + " 'file_name': '',\n", + " 'has_car': False,\n", + " 'score': 0,\n", + " 'bboxes': {\n", + " 'ymin': 0,\n", + " 'xmin': 0,\n", + " 'ymax': 0,\n", + " 'xmax': 0\n", + " }\n", + " }]\n", + " ),\n", + " environment = Python(requirements = ['tensorflow', 'tensorflow_hub', 'dill', 'Pillow', 'wget'])\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "60NCs0j8KHvg" + }, + "source": [ + "## 6. Auto Scaling and Resources" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "LBLEtVauKBNP" + }, + "outputs": [], + "source": [ + "autoscaling = Autoscaling(min_replicas=1, max_replicas=20, min_scale=0.1, max_scale=10)\n", + "autoscaling.add_metric(CpuUtilizationTarget(0.6))\n", + "autoscaling.add_metric(MemoryUtilizationTarget(0.7))\n", + "autoscaling.add_metric(RequestsPerWorkerTarget(1))\n", + "resources = Resources(cpu=1., memory='4Gi')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Y0gm6fOse6BP" + }, + "source": [ + "## 7. Model Endpoint" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wZi8X-LoCORa" + }, + "outputs": [], + "source": [ + "endpoint = client.get_or_create_endpoint('object-detection-url')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "F4-9M2_xKF7R", + "outputId": "acf0965c-da8b-442b-f170-a9af8c2255bf" + }, + "outputs": [], + "source": [ + "%%time\n", + "endpoint.update(\n", + " model, \n", + " strategy = DirectUpdateStrategy(),\n", + " autoscaling = autoscaling,\n", + " resources = resources,\n", + " wait = True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0Zgc18ocXbCE" + }, + "outputs": [], + "source": [ + "deployed_model = endpoint.get_deployed_model()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NbxYiJJsX5oL" + }, + "source": [ + "## 8. Predictions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "p7x7dfWoCNxK" + }, + "outputs": [], + "source": [ + "url = 'http://www.cs.ucf.edu/~aroshan/index_files/Dataset_PitOrlManh/images/'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4nS6rzzyK58c" + }, + "outputs": [], + "source": [ + "req = requests.get(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gH_5iPC84jmu" + }, + "outputs": [], + "source": [ + "soup = BeautifulSoup(req.text, 'lxml')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Hl_MzSFXX2oo" + }, + "outputs": [], + "source": [ + "urls = []\n", + "\n", + "for link in soup.find_all('a'):\n", + " href = link.get('href')\n", + " \n", + " if href.endswith('.jpg'):\n", + " image_url = f\"{url}/{href}\"\n", + " urls.append(image_url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ifi5nJeBX_1G" + }, + "outputs": [], + "source": [ + "urls = urls[:10]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "urls = [{'file_name': os.path.basename(url), 'url': url} for url in urls]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6puNawPEYBJl" + }, + "outputs": [], + "source": [ + "def process_image(url):\n", + " return deployed_model.predict([url])[0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "twDxykU5YBSp" + }, + "outputs": [], + "source": [ + "results = []\n", + "start_time = time.time()\n", + "\n", + "with concurrent.futures.ThreadPoolExecutor() as executor:\n", + " for result in executor.map(process_image, urls):\n", + " results.append(result)\n", + " \n", + "end_time = time.time()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jGY1FLwWYBXq" + }, + "outputs": [], + "source": [ + "total_time = end_time - start_time\n", + "total_time = time.strftime('%Hh %Mm %Ss', time.gmtime(total_time))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-k2mErxvYBdZ", + "outputId": "0991b3d4-f6e0-42ea-cf3e-b1769dbed44c" + }, + "outputs": [], + "source": [ + "print(f\"Processing Time: {total_time} for {len(urls)} images.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fqs3kM3D8v7t" + }, + "outputs": [], + "source": [ + "results_rows = []\n", + "\n", + "for img_result in results:\n", + " img_result = img_result.copy()\n", + " img_result.update(img_result.pop('bboxes'))\n", + " results_rows.append(pd.Series(img_result))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "W-B6TQLCBJkJ" + }, + "outputs": [], + "source": [ + "df = pd.concat(results_rows, axis=1).T" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 363 + }, + "id": "aDZ4yL5ABJ_y", + "outputId": "2ef798ff-d4a2-411d-c274-e7f0cd8ae1ed" + }, + "outputs": [], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VeV_oVzddA0m" + }, + "outputs": [], + "source": [ + "endpoint.delete()" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]" + }, + "vscode": { + "interpreter": { + "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1" + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/deployment/tfhub/object-detection/base64/.gitignore b/deployment/tfhub/object-detection/base64/.gitignore deleted file mode 100644 index a2a8dea..0000000 --- a/deployment/tfhub/object-detection/base64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.env/ diff --git a/deployment/tfhub/object-detection/base64/object-detection-base64-deploy.ipynb b/deployment/tfhub/object-detection/base64/object-detection-base64-deploy.ipynb deleted file mode 100644 index e4d5e0f..0000000 --- a/deployment/tfhub/object-detection/base64/object-detection-base64-deploy.ipynb +++ /dev/null @@ -1,391 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Object Identification (TensorFlow Hub) - Base64 Images" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook identifies whether a given object is present in a set of images. If the object is found, it returns a dataframe with the file name, score and bounding boxes.\n", - "We are using a dataset from [UCF](https://www.crcv.ucf.edu/data/GMCP_Geolocalization/#Dataset) that contains 62,058 high quality Google Street View images, and [TensorFlow Hub](https://www.tensorflow.org/hub), a library and platform for transfer learning." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dependencies" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook has been tested with Python 3.10.6 and the following package versions:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pip install dill==0.3.6\n", - "!pip install Pillow==9.3.0\n", - "!pip install tensorflow==2.11.0\n", - "!pip install tensorflow-hub==0.12.0\n", - "!pip install verta==0.21.1\n", - "!pip install wget==3.2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Imports" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import base64\n", - "import io\n", - "import json\n", - "import numpy as np\n", - "import os\n", - "import tempfile\n", - "import tensorflow as tf\n", - "import tensorflow_hub as hub\n", - "import time\n", - "import wget\n", - "\n", - "from PIL import Image, ImageOps\n", - "from verta import Client\n", - "from verta.endpoint.autoscaling import Autoscaling\n", - "from verta.endpoint.autoscaling.metrics import CpuUtilizationTarget, MemoryUtilizationTarget, RequestsPerWorkerTarget\n", - "from verta.endpoint.resources import Resources\n", - "from verta.endpoint.update import DirectUpdateStrategy\n", - "from verta.environment import Python\n", - "from verta.registry import VertaModelBase, verify_io\n", - "from verta.utils import ModelAPI" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Model Class" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class DetectObject(VertaModelBase):\n", - " def __init__(self, artifacts=None):\n", - " module_handle = 'https://tfhub.dev/google/openimages_v4/ssd/mobilenet_v2/1'\n", - " self.detector = hub.load(module_handle).signatures['default']\n", - " \n", - " def handle_img(self, img, width=640, height=480):\n", - " _, path = tempfile.mkstemp(suffix='.jpg')\n", - " img_str = json.loads(img)\n", - " img_bytes = img_str.encode('utf-8')\n", - " img_bytes = io.BytesIO(base64.b64decode(img_bytes))\n", - " img_arr = np.array(Image.open(img_bytes), dtype=np.uint8)\n", - " img = Image.fromarray(img_arr)\n", - " img = ImageOps.grayscale(img)\n", - " img.thumbnail((width, height), Image.Resampling.LANCZOS)\n", - " img.save(path, format = 'JPEG', quality = 90)\n", - " \n", - " print(f\"Image downloaded to {path}.\")\n", - " return path\n", - "\n", - " def load_img(self, path):\n", - " img = tf.io.read_file(path)\n", - " img = tf.image.decode_jpeg(img, channels=3)\n", - " \n", - " return img\n", - "\n", - " def filter_results(self, file, response, entity='Car', min_score=.2):\n", - " unused_keys = ['detection_class_labels', 'detection_class_names']\n", - " response = {key: value.numpy().tolist() for key, value in response.items()}\n", - " response = {key: val for key, val in response.items() if key not in unused_keys}\n", - " response['detection_class_entities'] = [v.decode() for v in response['detection_class_entities']]\n", - "\n", - " entities = response['detection_class_entities']\n", - " scores = response['detection_scores']\n", - " bboxes = response['detection_boxes']\n", - " result = {}\n", - "\n", - " for i in range(len(entities)):\n", - " if entities[i] == entity and scores[i] >= min_score:\n", - " ymin, xmin, ymax, xmax = bboxes[i]\n", - " result = {\n", - " 'file': file,\n", - " 'has_car': True,\n", - " 'score': scores[i],\n", - " 'bboxes': {'ymin': ymin, 'xmin': xmin, 'ymax': ymax, 'xmax': xmax}\n", - " }\n", - " break\n", - "\n", - " if len(result) == 0:\n", - " result = {\n", - " 'file': file,\n", - " 'has_car': False,\n", - " 'score': 0,\n", - " 'bboxes': {'ymin': 0, 'xmin': 0, 'ymax': 0, 'xmax': 0}\n", - " }\n", - " \n", - " print(f\"Found {result['has_car']} object(s).\")\n", - " return result\n", - "\n", - " def run_detector(self, file, image_path):\n", - " img = self.load_img(image_path)\n", - " img = tf.image.convert_image_dtype(img, tf.float32)[tf.newaxis, ...]\n", - " \n", - " response = self.detector(img)\n", - " result = self.filter_results(file, response)\n", - " \n", - " return result\n", - "\n", - " def detect_objects(self, file, img_arr):\n", - " start_time = time.time()\n", - " image_path = self.handle_img(img_arr)\n", - " result = self.run_detector(file, image_path)\n", - " end_time = time.time()\n", - "\n", - " print(f\"Inference time: {end_time - start_time}.\")\n", - " return result\n", - "\n", - " @verify_io\n", - " def predict(self, data):\n", - " file, img_arr = data\n", - " result = self.detect_objects(file, img_arr)\n", - "\n", - " return result\n", - "\n", - " def describe(self):\n", - " \"\"\"Return a description of the service.\"\"\" \n", - " return {\n", - " \"method\": \"predict\",\n", - " \"args\": f\"{self.example()}\",\n", - " \"returns\": \"file, has_car, score, ymin, xmin, ymax, xmax\",\n", - " \"description\": \"\"\"\n", - " Identify whether a given object is present in the image, with its score and bounding boxes.\n", - " \"\"\",\n", - " \"input_description\": \"\"\"\n", - " A list with base64 images.\n", - " \"\"\",\n", - " \"output_description\": \"\"\"\n", - " A CSV file with information about all the processed images.\n", - " The columns presents the file names, if the object was found (boolean), its score and bounding boxes.\n", - " \"\"\"\n", - " }\n", - " \n", - " def example(self):\n", - " \"\"\"Return example input json-serializable data.\"\"\"\n", - " url = 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_0.jpg'\n", - " file = url.split('/')[-1]\n", - " wget.download(url, file)\n", - "\n", - " with open(file, 'rb') as img:\n", - " img_bytes = base64.b64encode(img.read())\n", - " img_str = img_bytes.decode('utf-8')\n", - " img_str = json.dumps(img_str)\n", - " \n", - " return [\"000001_0.jpg\", img_str]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Verta Set Up" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "VERTA_HOST = 'app.verta.ai'\n", - "PROJECT_NAME = 'Object Detection V1'\n", - "MODEL_NAME = 'base64'\n", - "ENDPOINT_NAME = 'object-detection-base64'\n", - "\n", - "os.environ['VERTA_EMAIL'] = ''\n", - "os.environ['VERTA_DEV_KEY'] = ''" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Model Registration " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client = Client(VERTA_HOST)\n", - "project = client.set_project(PROJECT_NAME)\n", - "registered_model = client.get_or_create_registered_model(\n", - " name = PROJECT_NAME, \n", - " labels = ['object-detection']\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "input = {\n", - " \"file_name\": \"\",\n", - " \"image_str\": \"\"\n", - "}\n", - "output = {\n", - " \"file_name\": \"\",\n", - " \"has_car\": False,\n", - " \"score\": 0,\n", - " \"ymin\": 0,\n", - " \"xmin\": 0,\n", - " \"ymax\": 0,\n", - " \"xmax\": 0\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "model = registered_model.create_standard_model(\n", - " model_cls = DetectObject,\n", - " environment = Python(requirements = ['tensorflow', 'tensorflow_hub', 'dill', 'Pillow', 'wget']),\n", - " model_api = ModelAPI([input], [output]),\n", - " name = MODEL_NAME\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## VM Auto Scaling and Resources Configuration" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "autoscaling = Autoscaling(min_replicas = 1, max_replicas = 20, min_scale = 0.1, max_scale = 10)\n", - "autoscaling.add_metric(CpuUtilizationTarget(0.6))\n", - "autoscaling.add_metric(MemoryUtilizationTarget(0.7))\n", - "autoscaling.add_metric(RequestsPerWorkerTarget(1))\n", - "resources = Resources(cpu = 2., memory = '12Gi')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Endpoint Creation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "endpoint = client.get_or_create_endpoint(ENDPOINT_NAME)\n", - "status = endpoint.update(\n", - " model, \n", - " strategy = DirectUpdateStrategy(),\n", - " autoscaling = autoscaling,\n", - " resources = resources,\n", - " wait = True\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Prediction Test" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert status['status'] == \"active\"\n", - "url = 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_0.jpg'\n", - "file = url.split('/')[-1]\n", - "wget.download(url, file)\n", - "\n", - "with open(file, 'rb') as img:\n", - " img_bytes = base64.b64encode(img.read())\n", - " img_str = img_bytes.decode('utf-8')\n", - " img_str = json.dumps(img_str)\n", - "\n", - "endpoint.get_deployed_model().predict([file, img_str])\n", - "print(status)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "vscode": { - "interpreter": { - "hash": "2bb62b3221a3e8eb4d56ef3abf33b59c1166039d4d316f70559cb86bddd6b450" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/deployment/tfhub/object-detection/base64/object-detection-base64-predict.ipynb b/deployment/tfhub/object-detection/base64/object-detection-base64-predict.ipynb deleted file mode 100644 index 1acd850..0000000 --- a/deployment/tfhub/object-detection/base64/object-detection-base64-predict.ipynb +++ /dev/null @@ -1,241 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Object Identification (TensorFlow Hub) - Base64 Images" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook identifies whether a given object is present in a set of images. If the object is found, it returns a dataframe with the file name, score and bounding boxes.\n", - "We are using a dataset from [UCF](https://www.crcv.ucf.edu/data/GMCP_Geolocalization/#Dataset) that contains 62,058 high quality Google Street View images, and [TensorFlow Hub](https://www.tensorflow.org/hub), a library and platform for transfer learning." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dependencies" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook has been tested with Python 3.10.6 and the following package versions:\n", - "\n", - "- pandas==1.5.2\n", - "- verta==0.21.1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pip install pandas==1.5.2\n", - "!pip install verta==0.21.1\n", - "!pip install wget==3.2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Imports" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import base64\n", - "import multiprocessing as mp\n", - "import numpy as np\n", - "import os\n", - "import pandas as pd\n", - "import time\n", - "import json\n", - "import wget\n", - "\n", - "from verta import Client" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Helper Functions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def load_imgs(n_imgs):\n", - " urls = [\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_0.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_1.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_2.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_3.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_4.jpg'\n", - " ]\n", - " urls = urls[:n_imgs]\n", - " data = []\n", - "\n", - " for url in urls:\n", - " file = url.split('/')[-1]\n", - " wget.download(url, file)\n", - " \n", - " with open(file, 'rb') as img:\n", - " img_bytes = base64.b64encode(img.read())\n", - " img_str = img_bytes.decode('utf-8')\n", - " img_str = json.dumps(img_str)\n", - " \n", - " data.append([file, img_str])\n", - "\n", - " return data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def show_metrics(n_imgs, n_threads, start_time, end_time):\n", - " total_time = end_time - start_time\n", - " total_time = time.strftime('%Mm %Ss', time.gmtime(total_time))\n", - " \n", - " print(f'Images processed: {n_imgs}.')\n", - " print(f'Threads: {n_threads}.')\n", - " print(f'Total time: {total_time}.')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def show_results(results):\n", - " cols = list(results[0].keys())[:-1]\n", - " cols.extend(list(results[0]['bboxes'].keys()))\n", - " data = []\n", - "\n", - " for item in results:\n", - " values = list(item.values())[0:3]\n", - " values.extend(list(item['bboxes'].values()))\n", - " data.append(values)\n", - "\n", - " df = pd.DataFrame(data, columns=cols)\n", - " print(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Main Function\n", - "After setting up Verta, it processes the images in parallel, presents metrics and saves the result to a CSV file." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def main():\n", - " VERTA_HOST = 'app.verta.ai'\n", - " ENDPOINT_NAME = 'object-detection-base64'\n", - "\n", - " os.environ['VERTA_EMAIL'] = ''\n", - " os.environ['VERTA_DEV_KEY'] = ''\n", - "\n", - " client = Client(VERTA_HOST, debug=True)\n", - " endpoint = client.get_or_create_endpoint(ENDPOINT_NAME)\n", - " model = endpoint.get_deployed_model()\n", - "\n", - " n_threads = int(mp.cpu_count())\n", - " n_imgs = 1\n", - " imgs = load_imgs(n_imgs)\n", - " \n", - " start_time = time.time()\n", - " pool = mp.Pool(n_threads)\n", - " map_results = pool.map_async(model.predict, imgs, chunksize=1)\n", - "\n", - " while not map_results.ready():\n", - " print(f\"Images remaining: {map_results._number_left}\")\n", - " time.sleep(5)\n", - "\n", - " results = map_results.get()\n", - " pool.close()\n", - " pool.join()\n", - " end_time = time.time()\n", - "\n", - " show_metrics(n_imgs, n_threads, start_time, end_time)\n", - " show_results(results)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Execution" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if __name__ == '__main__':\n", - " main()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "vscode": { - "interpreter": { - "hash": "2bb62b3221a3e8eb4d56ef3abf33b59c1166039d4d316f70559cb86bddd6b450" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/deployment/tfhub/object-detection/url/.gitignore b/deployment/tfhub/object-detection/url/.gitignore deleted file mode 100644 index a2a8dea..0000000 --- a/deployment/tfhub/object-detection/url/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.env/ diff --git a/deployment/tfhub/object-detection/url/object-detection-url-deploy.ipynb b/deployment/tfhub/object-detection/url/object-detection-url-deploy.ipynb deleted file mode 100644 index 3df4927..0000000 --- a/deployment/tfhub/object-detection/url/object-detection-url-deploy.ipynb +++ /dev/null @@ -1,367 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Object Identification (TensorFlow Hub) - Images URLs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook identifies whether a given object is present in a set of images. If the object is found, it returns a dataframe with the file name, score and bounding boxes.\n", - "We are using a dataset from [UCF](https://www.crcv.ucf.edu/data/GMCP_Geolocalization/#Dataset) that contains 62,058 high quality Google Street View images, and [TensorFlow Hub](https://www.tensorflow.org/hub), a library and platform for transfer learning." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dependencies" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook has been tested with Python 3.10.6 and the following package versions:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pip install dill==0.3.6\n", - "!pip install Pillow==9.3.0\n", - "!pip install tensorflow==2.11.0\n", - "!pip install tensorflow-hub==0.12.0\n", - "!pip install verta==0.21.1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Imports" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import tempfile\n", - "import tensorflow as tf\n", - "import tensorflow_hub as hub\n", - "import time\n", - "import urllib.request\n", - "\n", - "from PIL import Image, ImageOps\n", - "from verta import Client\n", - "from verta.endpoint.autoscaling import Autoscaling\n", - "from verta.endpoint.autoscaling.metrics import CpuUtilizationTarget, MemoryUtilizationTarget, RequestsPerWorkerTarget\n", - "from verta.endpoint.resources import Resources\n", - "from verta.endpoint.update import DirectUpdateStrategy\n", - "from verta.environment import Python\n", - "from verta.registry import VertaModelBase, verify_io\n", - "from verta.utils import ModelAPI" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Model Class" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class DetectObject(VertaModelBase):\n", - " def __init__(self, artifacts=None):\n", - " module_handle = 'https://tfhub.dev/google/openimages_v4/ssd/mobilenet_v2/1'\n", - " self.detector = hub.load(module_handle).signatures['default']\n", - " \n", - " def handle_img(self, data, width=640, height=480):\n", - " _, path = tempfile.mkstemp(suffix='.jpg')\n", - " file_path = f\"{tempfile.gettempdir()}/tmp-{data[0].split('/')[-1]}\"\n", - " urllib.request.urlretrieve(data[1], file_path)\n", - " img = Image.open(file_path)\n", - " img = ImageOps.grayscale(img)\n", - " img.thumbnail((width, height), Image.Resampling.LANCZOS)\n", - " img.save(path, format='JPEG', quality=90)\n", - " \n", - " print(f\"Image downloaded to {path}.\")\n", - " return path\n", - "\n", - " def load_img(self, path):\n", - " img = tf.io.read_file(path)\n", - " img = tf.image.decode_jpeg(img, channels=3)\n", - " \n", - " return img\n", - "\n", - " def filter_results(self, file, response, entity='Car', min_score=.2):\n", - " unused_keys = ['detection_class_labels', 'detection_class_names']\n", - " response = {key: value.numpy().tolist() for key, value in response.items()}\n", - " response = {key: val for key, val in response.items() if key not in unused_keys}\n", - " response['detection_class_entities'] = [v.decode() for v in response['detection_class_entities']]\n", - "\n", - " entities = response['detection_class_entities']\n", - " scores = response['detection_scores']\n", - " bboxes = response['detection_boxes']\n", - " result = {}\n", - "\n", - " for i in range(len(entities)):\n", - " if entities[i] == entity and scores[i] >= min_score:\n", - " ymin, xmin, ymax, xmax = bboxes[i]\n", - " result = {\n", - " 'file': file,\n", - " 'has_car': True,\n", - " 'score': scores[i],\n", - " 'bboxes': {'ymin': ymin, 'xmin': xmin, 'ymax': ymax, 'xmax': xmax}\n", - " }\n", - " break\n", - "\n", - " if len(result) == 0:\n", - " result = {\n", - " 'file': file,\n", - " 'has_car': False,\n", - " 'score': 0,\n", - " 'bboxes': {'ymin': 0, 'xmin': 0, 'ymax': 0, 'xmax': 0}\n", - " }\n", - " \n", - " print(f\"Found {result['has_car']} object(s).\")\n", - " return result\n", - "\n", - " def run_detector(self, file, image_path):\n", - " img = self.load_img(image_path)\n", - " img = tf.image.convert_image_dtype(img, tf.float32)[tf.newaxis, ...]\n", - " \n", - " response = self.detector(img)\n", - " result = self.filter_results(file, response)\n", - " \n", - " return result\n", - "\n", - " def detect_objects(self, data):\n", - " start_time = time.time()\n", - " image_path = self.handle_img(data)\n", - " result = self.run_detector(data[0], image_path)\n", - " end_time = time.time()\n", - "\n", - " print(f\"Inference time: {end_time - start_time}.\")\n", - " return result\n", - "\n", - " @verify_io\n", - " def predict(self, data):\n", - " result = self.detect_objects(data)\n", - "\n", - " return result\n", - "\n", - " def describe(self):\n", - " \"\"\"Return a description of the service.\"\"\"\n", - " return {\n", - " \"method\": \"predict\",\n", - " \"args\": f\"{self.example()}\",\n", - " \"returns\": \"file, has_car, score, ymin, xmin, ymax, xmax\",\n", - " \"description\": \"\"\"\n", - " Identify whether a given object is present in the URL image, with its score and bounding boxes.\n", - " \"\"\",\n", - " \"input_description\": \"\"\"\n", - " A list with image URLs.\n", - " \"\"\",\n", - " \"output_description\": \"\"\"\n", - " A CSV file with information about all the processed images.\n", - " The columns presents the file names, if the object was found (boolean), its score and bounding boxes.\n", - " \"\"\"\n", - " }\n", - " \n", - " def example(self):\n", - " \"\"\"Return example input json-serializable data.\"\"\"\n", - " return [\"000001_0.jpg\", \"http://s3.amazonaws.com/verta-starter/street-view-images/000001_0.jpg\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Verta Set Up" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "VERTA_HOST = 'app.verta.ai'\n", - "PROJECT_NAME = 'Object Detection V1'\n", - "MODEL_NAME = 'url'\n", - "ENDPOINT_NAME = 'object-detection-url'\n", - "\n", - "os.environ['VERTA_EMAIL'] = ''\n", - "os.environ['VERTA_DEV_KEY'] = ''" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Model Registration" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client = Client(VERTA_HOST)\n", - "project = client.set_project(PROJECT_NAME)\n", - "registered_model = client.get_or_create_registered_model(\n", - " name = PROJECT_NAME, \n", - " labels = ['object-detection']\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "input = {\n", - " \"file_name\": \"\",\n", - " \"image_str\": \"\"\n", - "}\n", - "output = {\n", - " \"file_name\": \"\",\n", - " \"has_car\": False,\n", - " \"score\": 0,\n", - " \"ymin\": 0,\n", - " \"xmin\": 0,\n", - " \"ymax\": 0,\n", - " \"xmax\": 0\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "model = registered_model.create_standard_model(\n", - " model_cls = DetectObject,\n", - " environment = Python(requirements = ['tensorflow', 'tensorflow_hub', 'dill', 'Pillow']),\n", - " model_api = ModelAPI([input], [output]),\n", - " name = MODEL_NAME\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## VM Auto Scaling and Resources Configuration" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "autoscaling = Autoscaling(min_replicas = 1, max_replicas = 20, min_scale = 0.1, max_scale = 10)\n", - "autoscaling.add_metric(CpuUtilizationTarget(0.6))\n", - "autoscaling.add_metric(MemoryUtilizationTarget(0.7))\n", - "autoscaling.add_metric(RequestsPerWorkerTarget(1))\n", - "resources = Resources(cpu = 2., memory = '12Gi')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Endpoint Creation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "endpoint = client.get_or_create_endpoint(ENDPOINT_NAME)\n", - "status = endpoint.update(\n", - " model, \n", - " strategy = DirectUpdateStrategy(),\n", - " autoscaling = autoscaling,\n", - " resources = resources,\n", - " wait = True\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Prediction Test" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert status['status'] == \"active\"\n", - "url = 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_0.jpg'\n", - "file = url.split('/')[-1]\n", - "endpoint.get_deployed_model().predict([file, url])\n", - "print(status)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "vscode": { - "interpreter": { - "hash": "a88be0c350f3368d00cb8cbcc8a29525670c96bbb38149ff34103f663f5a90a2" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/deployment/tfhub/object-detection/url/object-detection-url-predict.ipynb b/deployment/tfhub/object-detection/url/object-detection-url-predict.ipynb deleted file mode 100644 index edac5e3..0000000 --- a/deployment/tfhub/object-detection/url/object-detection-url-predict.ipynb +++ /dev/null @@ -1,228 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Object Identification (TensorFlow Hub) - Images URLs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook identifies whether a given object is present in a set of images. If the object is found, it returns a dataframe with the file name, score and bounding boxes.\n", - "We are using a dataset from [UCF](https://www.crcv.ucf.edu/data/GMCP_Geolocalization/#Dataset) that contains 62,058 high quality Google Street View images, and [TensorFlow Hub](https://www.tensorflow.org/hub), a library and platform for transfer learning." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dependencies" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook has been tested with Python 3.10.6 and the following package versions:\n", - "\n", - "- pandas==1.5.2\n", - "- verta==0.21.1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pip install pandas==1.5.2\n", - "!pip install verta==0.21.1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Imports" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import multiprocessing as mp\n", - "import os\n", - "import pandas as pd\n", - "import time\n", - "\n", - "from verta import Client" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Helper Functions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def load_urls():\n", - " urls = [\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_0.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_1.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_2.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_3.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_4.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000001_5.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000002_0.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000002_1.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000002_2.jpg',\n", - " 'http://s3.amazonaws.com/verta-starter/street-view-images/000002_3.jpg'\n", - " ]\n", - " \n", - " return [[url.strip().split('/')[-1], url.strip()] for url in urls]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def show_metrics(n_urls, n_threads, start_time, end_time):\n", - " total_time = end_time - start_time\n", - " total_time = time.strftime('%Mm %Ss', time.gmtime(total_time))\n", - " \n", - " print(f'URLs processed: {n_urls}.')\n", - " print(f'Threads: {n_threads}.')\n", - " print(f'Total time: {total_time}.')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def show_results(results):\n", - " cols = list(results[0].keys())[:-1]\n", - " cols.extend(list(results[0]['bboxes'].keys()))\n", - " data = []\n", - "\n", - " for item in results:\n", - " values = list(item.values())[0:3]\n", - " values.extend(list(item['bboxes'].values()))\n", - " data.append(values)\n", - "\n", - " df = pd.DataFrame(data, columns = cols)\n", - " print(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Main Function\n", - "After setting up Verta, it processes the images in parallel, presents metrics and saves the result to a CSV file." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def main():\n", - " VERTA_HOST = 'app.verta.ai'\n", - " ENDPOINT_NAME = 'object-detection-url'\n", - "\n", - " os.environ['VERTA_EMAIL'] = ''\n", - " os.environ['VERTA_DEV_KEY'] = ''\n", - "\n", - " client = Client(VERTA_HOST, debug=True)\n", - " endpoint = client.get_or_create_endpoint(ENDPOINT_NAME)\n", - " model = endpoint.get_deployed_model()\n", - "\n", - " n_threads = int(mp.cpu_count())\n", - " n_urls = 5\n", - " urls = load_urls()[:n_urls]\n", - "\n", - " start_time = time.time()\n", - " pool = mp.Pool(n_threads)\n", - " map_results = pool.map_async(model.predict, urls, chunksize=1)\n", - "\n", - " while not map_results.ready():\n", - " print(f\"URLs remaining: {map_results._number_left}\")\n", - " time.sleep(1.5)\n", - "\n", - " results = map_results.get()\n", - " pool.close()\n", - " pool.join()\n", - " end_time = time.time()\n", - "\n", - " show_metrics(n_urls, n_threads, start_time, end_time)\n", - " show_results(results)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Execution" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if __name__ == '__main__':\n", - " main()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "vscode": { - "interpreter": { - "hash": "a88be0c350f3368d00cb8cbcc8a29525670c96bbb38149ff34103f663f5a90a2" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}