{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "Firebase ML API Tutorial", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "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.7.7" } }, "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ZRvF80bJ1imr" }, "source": [ "```\n", "# Copyright 2020 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", "# You may obtain a copy of the License at\n", "#\n", "#     https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License.\n", "```" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "XK1TC6JmaSo5" }, "source": [ "This Colab demonstrates how you can use the Firebase Admin Python SDK from a Jupyter notebook to manage your Firebase-hosted ML models." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ThfwN5km4l7X" }, "source": [ "# **1. Install the Admin SDK and TensorFlow** " ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "x4qsJu_y4onY" }, "source": [ "Install the Firebase Admin SDK and TensorFlow. If you're running this notebook in a Google Colab environment, you can skip this step." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "1sTVOhJC20Ce", "colab": {} }, "source": [ "%pip install 'firebase_admin>=4.1.0'\n", "%pip install 'tensorflow>=2.1.0'" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "xTklrznZYR_F" }, "source": [ "# **2. Set up a Firebase project**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "CHjogYcnYcgb" }, "source": [ "Before you can continue, you need to set up a Firebase project:\n", "\n", "1. If you don't already have a Firebase project, create a new project in the [Firebase console](https://console.firebase.google.com/). Then, open your project and do the following:\n", "\n", " 1. On the [Settings](https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk) page, create a service account and download the service account key file. Keep this file safe, since it grants administrator access to your project.\n", "\n", " 1. On the [Storage](https://console.firebase.google.com/project/_/storage) page, enable Cloud Storage. Take note of your bucket name.\n", "\n", " You need a Storage bucket to temporarily store model files while adding them to your Firebase project. If you are on the Blaze plan, you can create and use a bucket other than the default for this purpose.\n", "\n", " 1. On the [ML Kit](https://console.firebase.google.com/project/_/ml) page, click **Get started** if you haven't yet enabled ML Kit.\n", "\n", "1. In the [Google APIs console](https://console.developers.google.com/apis/library/firebaseml.googleapis.com?project=_), open your Firebase project and enable the Firebase ML API.\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "qJ07z89GsNqh" }, "source": [ "# **3. Upload the json service account key file for your project to the runtime**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "A9w5FJ0cXia2" }, "source": [ "Then, upload the service account key file you got in the previous step:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "8OeMQU9az4gh", "colab": {} }, "source": [ "import ipywidgets\n", "\n", "uploader = ipywidgets.FileUpload(\n", " accept='.json',\n", " multiple=False\n", ")\n", "service_acct_file = {}\n", "def handle_upload(change):\n", " service_acct_file['name'] = next(iter(change['owner'].value))\n", " service_acct_file['data'] = change['owner'].value[service_acct_file['name']]['content']\n", " with open(service_acct_file['name'], 'wb') as f:\n", " f.write(service_acct_file['data'])\n", " print('Uploaded {}'.format(service_acct_file['name']))\n", "uploader.observe(handle_upload, names='data')\n", "display(uploader)\n" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "HEVNf2rxwgfo" }, "source": [ "# **4. Set your Google Application Credentials location**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "39qaiVVqeA51" }, "source": [ "Set the `GOOGLE_APPLICATION_CREDENTIALS` environmental variable to the location of the key file:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "fdGKEWCH1SsT", "colab": {} }, "source": [ "import os\n", "os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"] = os.path.realpath(service_acct_file['name'])" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ma-McTrY0cGE" }, "source": [ "# **5. Initialize Firebase Admin**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "X9xyubP_ekA5" }, "source": [ "Import the `firebase_admin` module and initialize the SDK with the name of your Storage bucket. Be sure the Storage bucket is in the same Firebase project as your service account. Your project's default bucket looks like `your-project-id.appspot.com`." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "2sLO335O7IIF", "colab": {} }, "source": [ "storage_bucket = input('Storage bucket (no \"gs://\"): ')" ], "execution_count": 0, "outputs": [] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "YxYkdFBs0oS1", "colab": {} }, "source": [ "import firebase_admin\n", "from firebase_admin import ml\n", "\n", "firebase_admin.initialize_app(options={'storageBucket': storage_bucket})" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "DLOmPtM77wMI" }, "source": [ "# **6. Train your model**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "oNEyKOO_ivrO" }, "source": [ "Next, train your model.\n", "\n", "In a real notebook, you'd use a model architecture designed for your use case and provide your own training data. For this demo, just train a trivial model:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "6lrYxa4Z70Xp", "colab": {} }, "source": [ "import tensorflow as tf\n", "\n", "# Create a simple Keras model.\n", "x = [-1, 0, 1, 2, 3, 4]\n", "y = [-3, -1, 1, 3, 5, 7]\n", "\n", "model_binary = tf.keras.models.Sequential(\n", " [tf.keras.layers.Dense(units=1, input_shape=[1])])\n", "model_binary.compile(optimizer='sgd', loss='mean_squared_error')\n", "model_binary.fit(x, y, epochs=3)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "1LK9d37xYDet" }, "source": [ "# **7. Convert & upload your model**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "mGe3os8Xkf7F" }, "source": [ "Now that you have a trained model, you can upload it to Firebase and make it available to your iOS and Android apps.\n", "\n", "First, convert the model to TensorFlow Lite and upload it to Cloud Storage. With the Admin SDK, this is a single call:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "SLZvUStHa7T3", "colab": {} }, "source": [ "# This takes the Keras model, converts it to a TFLite model, and uploads it to\n", "# your bucket as my_model.tflite\n", "source = ml.TFLiteGCSModelSource.from_keras_model(model_binary, 'my_model.tflite')\n", "print(source.gcs_tflite_uri)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "NpZMyCUzGTbU", "colab_type": "text" }, "source": [ "If you get a `toco_from_protos: command not found` error, make sure the Python binary directory is in your `PATH`, then try again." ] }, { "cell_type": "code", "metadata": { "id": "qR3s7s5BGTbU", "colab_type": "code", "colab": {} }, "source": [ "import os\n", "import sys\n", "py_bin_dir = os.path.dirname(sys.executable)\n", "os.environ['PATH'] = '{}:{}'.format(os.environ['PATH'], py_bin_dir)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "RRA56_U9o2P9" }, "source": [ "# **8. Create a Model object**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "HzB_CV5yo9Ms" }, "source": [ "Next, create a `Model` object, specifying the model's Cloud Storage source and the name of your model. (You will use the name you specify here to download the model in your iOS and Android apps.)" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "rljlmVwgo1dk", "colab": {} }, "source": [ "model_format = ml.TFLiteFormat(model_source=source)\n", "sdk_model_1 = ml.Model(display_name=\"my_model_1\", model_format=model_format)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "0Hd7aZrpdOqm" }, "source": [ "# **9. Add the model to your Firebase project**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ZEMJ-B2LqhPt" }, "source": [ "Add the model to your Firebase project by calling `create_model()`. When you do so, the model gets copied from Cloud Storage.\n", "\n", "Note that this step will fail if your project already has a model named `my_model_1`. If this happens, [delete the model with the Firebase console](https://console.firebase.google.com/project/_/ml/custom) and try again." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "AOjQVSU2eG8v", "colab": {} }, "source": [ "firebase_model_1 = ml.create_model(sdk_model_1)\n", "if firebase_model_1.validation_error:\n", " raise Exception(firebase_model_1.validation_error)\n", "print(firebase_model_1.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "lMthadQ4qU32" }, "source": [ "# **10. Publish the model**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "oNTN-XEFvd7g" }, "source": [ "Finally, publish your model:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "qK2S0KD7qbIB", "colab": {} }, "source": [ "model_id = firebase_model_1.model_id\n", "firebase_model_1 = ml.publish_model(model_id)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "IpxBS8HzvvWm" }, "source": [ "Now that you've published the model, you can [use it in your apps](https://firebase.google.com/docs/ml-kit/use-custom-models)." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ZHSN6vM7b_pH" }, "source": [ "# **11. Create a second model (so we can update)**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "lhuuTNtHwduW" }, "source": [ "You can update a published model with a new model file. When you do so, client apps automatically download and use the new model.\n", "\n", "For demonstration purposes, first save one of Keras's prepackaged models to a saved model directory:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "1pLVpHi4cF6e", "colab": {} }, "source": [ "tf.saved_model.save(tf.keras.applications.MobileNet(), '/tmp/saved_model/1')" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "veOOV0ZxjMf-" }, "source": [ "# **12. Create a second model source and model format from the new model**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "XIyAhNEFGNIN" }, "source": [ "Now, convert the saved model to TensorFlow Lite and upload it to Cloud Storage. This time, you're converting a TensorFlow saved model to TensorFlow Lite, but you could also convert a Keras model like you did earlier, or convert a Keras model saved as an HDF5 (`.h5`) file." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "hn5IgonpjWmy", "colab": {} }, "source": [ "# This takes the saved model directory, converts it to TFLite and writes it to your bucket as my_model_2.tflite\n", "source2 = ml.TFLiteGCSModelSource.from_saved_model('/tmp/saved_model/1', 'my_model_2.tflite')" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "wtXV_x7ko1Dz" }, "source": [ "# **13. Modify the local model and then call the API Update**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "m2WyUn4SJWEC" }, "source": [ "Change the original `Model` object's model source and (optionally) metadata, then call `update_model()`:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "MiRQi2Iqo8PK", "colab": {} }, "source": [ "model_format2 = ml.TFLiteFormat(model_source=source2)\n", "firebase_model_1.model_format = model_format2\n", "firebase_model_1.tags = ['tag1', 'tag2'] # replaces any existing tags with these tags.\n", "\n", "firebase_model_2 = ml.update_model(firebase_model_1)\n", "if firebase_model_2.validation_error:\n", " raise Exception(firebase_model_2.validation_error)\n", "print(firebase_model_2.as_dict())\n" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "uZzu3k5EXMma" }, "source": [ "# **14. Publish the model_format2 model**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "XaiWqq4EkWBU" }, "source": [ "After you update the model, re-publish it:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "iGsNmx2oXUFS", "colab": {} }, "source": [ "firebase_model_2 = ml.publish_model(model_id)\n", "print(firebase_model_2.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "m2YmhA4Ab1DH" }, "source": [ "# **15. Get the model**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "_01adxyEk0JN" }, "source": [ "If you need to get a `Model` object from one of your project's models, use `get_model()`:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "9Q1jQXYJb4qx", "colab": {} }, "source": [ "firebase_model_get = ml.get_model(model_id)\n", "print(firebase_model_get.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "OphmZAVdcqxO" }, "source": [ "# **16. List the models**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "kOIjFLyGlpyq" }, "source": [ "To list your project's models, iterate over the result of `list_models()`:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "ebJBI9NVcwjp", "colab": {} }, "source": [ "firebase_models_list = ml.list_models()\n", "iterator = firebase_models_list.iterate_all()\n", "for m in iterator:\n", " print(m.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "p_4yAHeFg7BA" }, "source": [ "# **17. Make more models so we can show lists better**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "9vOkbq1lmA2B" }, "source": [ "The Admin SDK can help you manage projects with many models.\n", "\n", "To demonstrate this, create some more models:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "ce3zB3HLhCTf", "colab": {} }, "source": [ "list_model_1 = ml.create_model(ml.Model(display_name='my_model_2', tags=['tag2', 'tag3'], model_format=model_format))\n", "list_model_2 = ml.create_model(ml.Model(display_name='my_model_3', tags=['tag3'], model_format=model_format))\n", "list_model_3 = ml.create_model(ml.Model(display_name='cat_model_1', tags=['cat'], model_format=model_format))\n", "list_model_4 = ml.create_model(ml.Model(display_name='cat_model_2', tags=['cat'], model_format=model_format))\n", "list_model_5 = ml.create_model(ml.Model(display_name='new_cat_model_007', tags=['cat'], model_format=model_format))" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "QmxpYBsQnua4" }, "source": [ "# **18. Publish some of them**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "OvYY0orEmtsT" }, "source": [ "And publish some of them:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "x6kzkhWjnyXr", "colab": {} }, "source": [ "list_model_2 = ml.publish_model(list_model_2.model_id)\n", "list_model_4 = ml.publish_model(list_model_4.model_id)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "aAIAexOTpkVu" }, "source": [ "# **19. Listing with page size**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "BZC1dbfnm43F" }, "source": [ "You can specify how many results to return at a time:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "kf3rUxE0pqzJ", "colab": {} }, "source": [ "firebase_models_list_2 = ml.list_models(page_size=3)\n", "for m in firebase_models_list_2.models:\n", " print (m.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "V0WpL3UarTlA" }, "source": [ "# **20. Listing the next page**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "iPh886g2nNm9" }, "source": [ "Get the next page of results:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "iodXtP_XrYGT", "colab": {} }, "source": [ "firebase_models_list_3 = firebase_models_list_2.get_next_page()\n", "for m in firebase_models_list_3.models:\n", " print (m.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "LJwxO53KnYHA" }, "source": [ "When you retrieve the final page, `get_next_page()` returns `None`." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Xbv-NAm5tT_5" }, "source": [ "# **21. Filtering lists**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "-aNfitPHoF9P" }, "source": [ "You can also filter the results.\n", "\n", "Filter by display name:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "9eS1kVSwtgwJ", "colab": {} }, "source": [ "firebase_models_list = ml.list_models(list_filter='display_name=cat_model_1')\n", "for m in firebase_models_list.models:\n", " print (m.as_dict())\n" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "mLNhAGtjuxqF" }, "source": [ "Filter by display name prefix (note that only prefix matching is supported; you can't do general wildcard matching):" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "YpihoJvnu1PU", "colab": {} }, "source": [ "firebase_models_list = ml.list_models(list_filter='display_name:cat_*')\n", "for m in firebase_models_list.models:\n", " print (m.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "e54EB4ngwBM6" }, "source": [ "Filter by tag:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "woK9u8P0wJ0a", "colab": {} }, "source": [ "firebase_models_list = ml.list_models(list_filter='tags: cat')\n", "for m in firebase_models_list.models:\n", " print (m.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ZrSJImzSyRoI" }, "source": [ "Filter by publish state:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "G2xmcFuMyXRX", "colab": {} }, "source": [ "firebase_models_list = ml.list_models(list_filter='state.published = true')\n", "for m in firebase_models_list.models:\n", " print (m.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "-EagFFnwzyI5" }, "source": [ "Combine filters:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "3U40mUaQz9KE", "colab": {} }, "source": [ "firebase_models_list = ml.list_models(list_filter='(display_name: cat_* OR tags: tag3) AND NOT state.published = true')\n", "for m in firebase_models_list.models:\n", " print (m.as_dict())" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "sYur7GCQBVas" }, "source": [ "# **22. Clean up**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "v1BKMU30Blnr" }, "source": [ "That's it!\n", "\n", "Clean up by deleting the example models:" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "wGRXAfFiCHOF", "colab": {} }, "source": [ "ml.delete_model(model_id)\n", "ml.delete_model(list_model_1.model_id)\n", "ml.delete_model(list_model_2.model_id)\n", "ml.delete_model(list_model_3.model_id)\n", "ml.delete_model(list_model_4.model_id)\n", "ml.delete_model(list_model_5.model_id)" ], "execution_count": 0, "outputs": [] } ] }