{"id":17030045,"url":"https://github.com/alvarobartt/serving-tensorflow-models","last_synced_at":"2025-04-12T12:11:47.114Z","repository":{"id":44778920,"uuid":"318902808","full_name":"alvarobartt/serving-tensorflow-models","owner":"alvarobartt","description":"Serving TensorFlow models with TensorFlow Serving :orange_book:","archived":false,"fork":false,"pushed_at":"2022-01-25T11:16:08.000Z","size":20543,"stargazers_count":44,"open_issues_count":0,"forks_count":9,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-26T06:51:14.552Z","etag":null,"topics":["image-classification","machine-learning","mlops","model-deployment","model-serving","serve-tensorflow-models","tensorflow","tensorflow-serving"],"latest_commit_sha":null,"homepage":"https://www.tensorflow.org/tfx/guide/serving","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alvarobartt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-05T22:33:45.000Z","updated_at":"2024-10-05T04:06:36.000Z","dependencies_parsed_at":"2022-08-15T08:50:11.289Z","dependency_job_id":null,"html_url":"https://github.com/alvarobartt/serving-tensorflow-models","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarobartt%2Fserving-tensorflow-models","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarobartt%2Fserving-tensorflow-models/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarobartt%2Fserving-tensorflow-models/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarobartt%2Fserving-tensorflow-models/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alvarobartt","download_url":"https://codeload.github.com/alvarobartt/serving-tensorflow-models/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248565074,"owners_count":21125417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["image-classification","machine-learning","mlops","model-deployment","model-serving","serve-tensorflow-models","tensorflow","tensorflow-serving"],"created_at":"2024-10-14T08:03:45.062Z","updated_at":"2025-04-12T12:11:47.095Z","avatar_url":"https://github.com/alvarobartt.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Serving TensorFlow models with TensorFlow Serving :orange_book:\n\n![TensorFlow Logo](https://inletlabs.com/assets/images/logo_stack/tensorflow-logo.png)\n\n__TensorFlow Serving is a flexible, high-performance serving system for machine learning models, \ndesigned for production environments. TensorFlow Serving makes it easy to deploy new algorithms \nand experiments, while keeping the same server architecture and APIs. TensorFlow Serving \nprovides out-of-the-box integration with TensorFlow models, but can be easily extended to \nserve other types of models and data.__\n\nThis repository is a guide on how to train, save, deploy and interact with TensorFlow ML models in production\nenvironments for TensorFlow models. Along with this repository, we will prepare and train a custom CNN model\nfor image classification over [The Simpsons Characters Dataset](https://www.kaggle.com/alexattia/the-simpsons-characters-dataset), \nthat will be later deployed using [TensorFlow Serving](https://www.tensorflow.org/tfx/guide/serving).\n\n![sanity-checks](https://github.com/alvarobartt/serving-tensorflow-models/workflows/sanity-checks/badge.svg?branch=master)\n[![](https://img.shields.io/static/v1?label=Read%20it%20on\u0026message=Medium\u0026color=informational\u0026logo=Medium)](https://towardsdatascience.com/serving-tensorflow-models-with-tensorflow-serving-9f1058ac7140)\n\n---\n\n__:sparkles: :framed_picture: STREAMLIT UI AVAILABLE AT [tensorflow-serving-streamlit](https://github.com/alvarobartt/tensorflow-serving-streamlit)!__\n\n![](https://raw.githubusercontent.com/alvarobartt/serving-tensorflow-models/master/images/ui-demo.gif)\n\n---\n\n## :hammer_and_wrench: Requirements\n\nFirst of all, you need to make sure that you have all the requirements installed, but before proceeding\nyou should keep in mind that TF-Serving is not available for Windows or macOS, which means that if you \ndon't have an Ubuntu VM you will need to proceed with the Docker deployment, that requires you to have\nDocker installed.\n\n__:warning: Warning!__ In case you don't have Ubuntu, but still want to deploy TF-Serving via Docker, you \ndon't need to install TF-Serving with APT-GET, just run the Dockerfile (go to the section [Docker](#whale2-docker)).\n\nThat said, if you didn't jump to the Docker section, now you need to install `tensorflow-model-server`, \nwhich requires you to add the TF-Serving distribution URI as a package source as it follows:\n\n```\necho \"deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal\" | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list \u0026\u0026 \\\ncurl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | sudo apt-key add -\n```\n\nSo that then you can install `tensorflow-model-server` using APT-GET as it follows:\n\n```\napt-get update \u0026\u0026 apt-get install tensorflow-model-server\n```\n\nFinally, for the client side of the deployment you need install the Python package `tensorflow-serving-api`, \nin case you want to use the gRPC API, which is faster than the REST API regarding the latency and inference time.\n\n```\npip install tensorflow-serving-api==2.5.2\n```\n\nYou will also need to install the `tensorflow`'s matching version with the `tensorflow-serving-api` (we will be using\nthe latest version on the date that this repository is being published) with the following command:\n\n```\npip install tensorflow==2.5.1\n```\n\n:pushpin: __Update__: in this concrete case the versions do not match according to the comments in\nhttps://github.com/tensorflow/serving/releases/tag/2.5.2, but the usual scenario should be matching\nversions between both `tensorflow` and `tensorflow-serving-api`. Also the versions have been updated in\nthis repository due to a Dependabot Alert as it can be seen at https://github.com/advisories/GHSA-cmgw-8vpc-rc59.\n\nOr you can also avoid the manual installation of each requirement and just install them all at once with the\nfollowing command, that will install all the requirements specified in the `requirements/requirements.txt` file:\n\n```\npip install -r requirements/requirements.txt\n```\n\nIf you have any problems regarding the TensorFlow installation, visit [Installation | TensorFlow](https://www.tensorflow.org/install?hl=es-419).\n\n---\n\n## :open_file_folder: Dataset\n\nThe dataset that is going to be used to train the image classification model is \n\"[The Simpsons Characters Data](https://www.kaggle.com/alexattia/the-simpsons-characters-dataset)\", which is a big Kaggle \ndataset that contains RGB images of some of the main The Simpsons characters including Homer, Marge, Bart, Lisa, \nBarney, and much more.\n\nThe original dataset contains 42 classes of The Simpsons characters, with an unbalanced number of samples per \nclass, and a total of 20,935 training images and 990 test images in JPG format, and the images in different \nsizes, but as all of them are small, we will be resizing them to 64x64px when training the model.\n\nAnyway, we will create a custom slice of the original dataset keeping just the training set, and using a \nrandom 80/20 train-test split and removing the classes with less than 50 images. So on, we will be have 32 \nclasses, with 13,210 training images, 3,286 validation images, and 4,142 testing images.\n\nFind all the information about the dataset in [dataset/README.md](https://github.com/alvarobartt/serving-tensorflow-models/tree/master/dataset).\n\n![](https://raw.githubusercontent.com/alvarobartt/serving-tensorflow-models/master/images/data.jpg)\n\n---\n\n## :robot: Modelling\n\nOnce the data has been explored, we are going to proceed with the definition of the ML model, which in this case \nwill be a __CNN (Convolutional Neural Network)__ as we are facing an image classification problem.\n\nThe created model architecture consists of an initial `Conv2D` layer (that also indicates the input_shape of the \nnet), which is a 2D convolutional layer that produces 16 filters as the output of windows of 3x3 convolutions, \nfollowed by a `MaxPooling2D` to downsample the Tensor resulting from the previous convolutional layer. Usually, \nyou will find this layer after two consecutive convolutions, but for the sake of simplicity, here we will be \ndownsampling the data after each convolution, as this is a simple CNN with a relatively small dataset (less \nthan 20k images).\n\nThen we will include another combination of `Conv2D` and `MaxPooling2D` layers as increasing the number of \nconvolutional filters means that we will provide more data to the CNN as it is capturing more combinations \nof pixel values from the input image Tensor.\n\nAfter applying the convolutional operations, we will include a `Flatten` layer to transform the image Tensor into \na 1D Tensor which prepares the data that goes through the CNN to include a few fully connected layers after it.\n\nFinally, we will include some `Dense` fully connected layers to assign the final weights of the net, and some \nDropout layers to avoid overfitting during the training phase. You also need to take into consideration that\nthe latest `Dense` layer contains as many units as the total labels to predict, which in this case is the number \nof The Simpsons characters available in the training set.\n\nThe trained model has been named __SimpsonsNet__ (this name will be used later while serving the model as its \nidentifier) and its architecture looks like this:\n\n```python\nimport tensorflow as tf\n\nmodel = tf.keras.models.Sequential([\n    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(224, 224, 3)),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(units=512, activation='relu'),\n    tf.keras.layers.Dropout(.2),\n    tf.keras.layers.Dense(units=256, activation='relu'),\n    tf.keras.layers.Dropout(.1),\n    tf.keras.layers.Dense(len(MAP_CHARACTERS), activation='softmax')\n])\n```\n\nFinally, once trained we will need to dump the model (not the weights) in `SavedModel` format, which is the universal serialization\nformat for the TensorFlow models. This format provides a language-neutral format to save ML models that is recoverable and hermetic. \nIt enables higher-level systems and tools to produce, consume and transform TensorFlow models.\n\n```python\nimport tensorflow as tf\nimport os\n\nsave_path = os.path.join(\"/home/saved_models/saved_model/1/\")\ntf.saved_model.save(trained_model, save_path)\n```\n\nThe resulting `SavedModel`'s directory should look like the following:\n\n```\nassets/\nassets.extra/\nvariables/\n    variables.data-?????-of-?????\n    variables.index\nsaved_model.pb\n```\n\nMore information regarding the `SavedModel` format at \n[TensorFlow SavedModel](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md).\n\n__Note__: the model has been trained on an NVIDIA GeForce GTX 1070 8GB GPU using CUDA 11. If you want to get your GPU specs, \njust use the `nvidia-smi` command on your console, but make sure that you have your NVIDIA drivers properly installed. \nYou also need to check that both CUDA and the cuDNN SDK get the GPU training working with TensorFlow. The code \nprovided below explains how to make sure that the TensorFlow build is detecting and using your GPU.\n\n```python\nimport tensorflow as tf\ntf.config.list_physical_devices('GPU')\ntf.test.is_built_with_cuda()\n```\n\nMore information available at [TensorFlow GPU Install](https://www.tensorflow.org/install/gpu).\n\n---\n\nFinally, as a personal recommendation you should check/keep an eye on the following courses:\n\n- :fire: [Laurence Moroney](https://github.com/lmoroney)'s TensorFlow Proffesional Certificate (previously Specialization) \nat Coursera for learning the basics of TensorFlow as you playaround with some common Deep Learning scenarios like \nCNNs, Time Series and NLP. So feel free to check it at [Coursera | TensorFlow in Practice](https://www.coursera.org/professional-certificates/tensorflow-in-practice), \nand the course's resources at [lmoroney/dlaicourse](https://github.com/lmoroney/dlaicourse).\n\n- :star: [Daniel Bourke](https://github.com/mrdbourke)'s TensorFlow Zero to Mastery course he is currently \ndeveloping and it will be completely free including a lot of resources. So feel free to check it at \n[mrdbourke/tensorflow-deep-learning](https://github.com/mrdbourke/tensorflow-deep-learning).\n\n- :sparkles: [Andrew Ng](https://twitter.com/andrewyng)'s CNN course/explanation freely available on YouTube\nat [Convolutional Neural Networks - Course 4 of the Deep Learning Specialization](https://www.youtube.com/watch?v=ArPaAX_PhIs\u0026list=PLkDaE6sCZn6Gl29AoE31iwdVwSG-KnDzF)\nthat contains clear explanations on how the convolutional operations work, to help you get introduced to the\nComputer Vision field.\n\n__If you have some TensorFlow free learning material made by you that you want to share, feel free to\ncreate a PR including it in this list, and I'll be glad to feature your work!__\n\n---\n\n## :rocket: Deployment\n\nOnce the model has been saved using `SavedModel` format, it is pretty straightforward to get TF-Serving working, \nif the installation succeeded. Unlike [TorchServe](https://pytorch.org/serve/), serving ML models in TF-Serving\nis simpler as you just need to have `tensorflow-model-server` installed and a model in the specified format.\n\nBut regarding the TF-Serving documentation (at least from my point of view) is not that clear, so the deployment\nprocess may be tedious and then the usage too. Anyway, the following command is the one you need to use to deploy \nany TensorFlow's ML model into TF-Serving:\n\n```\ntensorflow_model_server --port=8500 --rest_api_port=8501 \\\n                        --model_name=simpsonsnet \\\n                        --model_base_path=/home/saved_models/simpsonsnet\n```\n\nNow, even though the command is clear and self-explanatory, a more detailed explanation of the flags used is presented:\n\n- `--port`: this is the port to listen on for the gRPC API, the default value is 8500, but it's a common practice to still\ndefine this flag's value to always know the configuration of the deployed TF-Serving Server.\n- `--rest_api_port`: this is the REST API port, which is set to zero by default, which means that the REST API will not be\ndeployed/exposed unless you manually set a port. There's no default value, it just needs to be different than the gRPC \nport, so we will set it to 8501.\n- `--model_name`: this is the name of the ML model to serve, which is the one that will be exposed in the endpoint.\n- `--model_base_path`: this is the base path where the ML model that is going to be served is placed in. Note that it's\nan absolute path, do not use relative paths.\n\nMore information about the TF-Serving CLI available at \n[Train and serve a TensorFlow model with TensorFlow Serving](https://www.tensorflow.org/tfx/tutorials/serving/rest_simple#start_running_tensorflow_serving).\nEven though the official documenation is not that helpful, you can also check `tensorflow_model_server --help`.\n\nOnce TF-Serving has been successfully deployed, you can send a sample HTTP GET request to the REST API available at \nhttp://localhost:8501/v1/models/simpsonsnet; to do so use the following command, which sends this\nrequest to the _Model Status API_ that returns the served ML model basic information:\n\n```\ncurl http://localhost:8501/v1/models/simpsonsnet\n```\n\nThat should output something similar to the following if everything is OK:\n\n```json\n{\n \"model_version_status\": [\n  {\n   \"version\": \"1\",\n   \"state\": \"AVAILABLE\",\n   \"status\": {\n    \"error_code\": \"OK\",\n    \"error_message\": \"\"\n   }\n  }\n ]\n}\n```\n\nThere is no way to gracefully stop the server, check [this issue](https://github.com/tensorflow/serving/issues/356) for updates,\nso you will need to either `CTRL+C` in the terminal where you launched `tensorflow_model_server`, kill the running process from \nthe terminal or just stop the running container.\n\nTo look for the PID of the running `tensorflow_model_server` process and then kill it, you can use the following\nset of commands:\n\n```\nps aux | grep -i \"tensorflow_model_server\"\nkill -9 PID\n```\n\nTo look for the running Docker Container ID and then stop it, you can just use the following set of commands:\n\n```\ndocker ps # Retrieve the CONTAINER_ID\ndocker kill CONTAINER_ID\n```\n\n---\n\n## :whale2: Docker\n\nIn order to reproduce the TF-Serving deployment in an Ubuntu Docker image, you can use the following set of commands:\n\n```bash\ndocker build -t ubuntu-tfserving:latest deployment/\ndocker run --rm --name tfserving_docker -p8500:8500 -p8501:8501 -d ubuntu-tfserving:latest\n```\n\n__Note__: make sure that you use the `-d` flag in `docker run` so that the container runs in the background\nand does not block your terminal.\n\nFor more information regarding the Docker deployment, you should check TensorFlow's \nexplanation and notes available at [TF-Serving with Docker](https://www.tensorflow.org/tfx/serving/docker?hl=en), \nas it also explains how to use their Docker image (instead of a clear Ubuntu one) and\nsome tips regarding the production deployment of the models using TF-Serving.\n\nAlso, if you go through the [deployment/Dockerfile](https://github.com/alvarobartt/serving-tensorflow-models/blob/master/deployment/Dockerfile) \nyou will see that there's a comment per Dockerfile line explaining what is it doing. So that you can also take that Dockerfile\nas a template, making it easier to prepare the deployment file for your custom model.\n\n---\n\n## :mage_man: Usage\n\nAlong this section we will see how to interact with the deployed APIs (REST and gRPC) via Python, so as to send sample requests\nto the Prediction APIs to classify images from \"The Simpsons Characters Dataset\".\n\n__Note__: as the model is pretty simple the accuracy is not perfect, but that's part of any ML project lifecycle so that\nthe model improves with iterations and retraining processes. Feel free to update/improve the model!\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"400\" height=\"275\" src=\"https://raw.githubusercontent.com/alvarobartt/serving-tensorflow-models/master/images/meme.jpg\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ci\u003eSource: \u003ca href=\"https://www.reddit.com/r/TheSimpsons/comments/ffhufz/lenny_white_carl_black/\"\u003eReddit - r/TheSimpsons\u003c/a\u003e\u003c/i\u003e\n\u003c/p\u003e\n\nBefore proceeding with the Python usage, just to mention that as the mapping between the labels and the predicted Tensor is a future\ntask (see the [Future Tasks](#crystal_ball-future-tasks) section), we will be using the following dictionary so as to go from the\npredicted Tensor highest probability index to the matching label on \"The Simpsons Characters Dataset\".\n\n```python\n{\n    0: \"abraham_grampa_simpson\", 1: \"apu_nahasapeemapetilon\", 2: \"barney_gumble\", 3: \"bart_simpson\",\n    4: \"carl_carlson\", 5: \"charles_montgomery_burns\", 6: \"chief_wiggum\", 7: \"comic_book_guy\",\n    8: \"disco_stu\", 9: \"edna_krabappel\", 10: \"groundskeeper_willie\", 11: \"homer_simpson\",\n    12: \"kent_brockman\", 13: \"krusty_the_clown\", 14: \"lenny_leonard\", 15: \"lisa_simpson\",\n    16: \"maggie_simpson\", 17: \"marge_simpson\", 18: \"martin_prince\", 19: \"mayor_quimby\",\n    20: \"milhouse_van_houten\", 21: \"moe_szyslak\", 22: \"ned_flanders\", 23: \"nelson_muntz\",\n    24: \"patty_bouvier\", 25: \"principal_skinner\", 26: \"professor_john_frink\", 27: \"ralph_wiggum\",\n    28: \"selma_bouvier\", 29: \"sideshow_bob\", 30: \"snake_jailbird\", 31: \"waylon_smithers\"\n}\n```\n\n  ---\n\nIf you want to interact with the deployed API from Python you can either use the [tensorflow-serving-api](https://github.com/tensorflow/serving) \nPython package that easily lets you send gRPC requests or otherwise, you can use the [requests](https://requests.readthedocs.io/en/master/) Python \nlibrary to send the request to the REST API instead.\n\n### __REST API requests using `requests`__:\n\nRegarding the REST requests to the deployed TF-Serving Prediction API you need to install the requirements as\nit follows:\n\n```\npip install -r requirements/requirements-rest.txt\n```\n\nAnd then use the following script which will send a sample The Simpsons image to be classified using the deployed model:\n\n```python\nimport requests\n\nimport tensorflow as tf\n\n# Apply the same preprocessing as during training (resize and rescale)\nimage = tf.io.decode_image(open('../images/sample.jpg', 'rb').read(), channels=3)\nimage = tf.image.resize(image, [224, 224])\nimage = image/255.\n\n# Convert the Tensor to a batch of Tensors and then to a list\nimage_tensor = tf.expand_dims(image, 0)\nimage_tensor = image_tensor.numpy().tolist()\n\n# Define the endpoint with the format: http://localhost:8501/v1/models/MODEL_NAME:predict\nendpoint = \"http://localhost:8501/v1/models/simpsonsnet:predict\"\n\n# Prepare the data that is going to be sent in the POST request\njson_data = {\n  \"instances\": image_tensor\n}\n\n# Send the request to the Prediction API\nresponse = requests.post(endpoint, json=json_data)\n\n# Retrieve the highest probablity index of the Tensor (actual prediction)\nprediction = tf.argmax(response.json()['predictions'][0])\nprint(MAP_CHARACTERS[prediction.numpy()])\n\u003e\u003e\u003e \"homer_simpson\"\n```\n\n### __gRPC API requests using `tensorflow-serving-api`__:\n\nNow, regarding the gRPC requests to the deployed TF-Serving Prediction API you need to install the requirements as\nit follows:\n\n```\npip install -r requirements/requirements-grpc.txt\n```\n\nAnd then use the following script which will send a sample The Simpsons image to be classified using the deployed model:\n\n```python\nimport grpc\n\nimport tensorflow as tf\nfrom tensorflow_serving.apis import predict_pb2, prediction_service_pb2_grpc\n\n# Apply the same preprocessing as during training (resize and rescale)\nimage = tf.io.decode_image(open('../images/sample.jpg', 'rb').read(), channels=3)\nimage = tf.image.resize(img, [224, 224])\nimage = image/255.\n\n# Convert the Tensor to a batch of Tensors and then to a list\nimage_tensor = tf.expand_dims(image, 0)\nimage_tensor = image_tensor.numpy().tolist()\n\n# Optional: define a custom message lenght in bytes\nMAX_MESSAGE_LENGTH = 20000000\n\n# Optional: define a request timeout in seconds\nREQUEST_TIMEOUT = 5\n\n# Open a gRPC insecure channel\nchannel = grpc.insecure_channel(\n    \"localhost:8500\",\n    options=[\n        (\"grpc.max_send_message_length\", MAX_MESSAGE_LENGTH),\n        (\"grpc.max_receive_message_length\", MAX_MESSAGE_LENGTH),\n    ],\n)\n\n# Create the PredictionServiceStub\nstub = prediction_service_pb2_grpc.PredictionServiceStub(channel)\n\n# Create the PredictRequest and set its values\nreq = predict_pb2.PredictRequest()\nreq.model_spec.name = 'simpsonsnet'\nreq.model_spec.signature_name = ''\n\n# Convert to Tensor Proto and send the request\n# Note that shape is in NHWC (num_samples x height x width x channels) format\ntensor = tf.make_tensor_proto(image_tensor)\nreq.inputs[\"conv2d_input\"].CopyFrom(tensor)  # Available at /metadata\n\n# Send request\nresponse = stub.Predict(req, REQUEST_TIMEOUT)\n\n# Handle request's response\noutput_tensor_proto = response.outputs[\"dense_2\"]  # Available at /metadata\nshape = tf.TensorShape(output_tensor_proto.tensor_shape)\n\nresult = tf.reshape(output_tensor_proto.float_val, shape)\nresult = tf.argmax(result, 1).numpy()[0]\nprint(MAP_CHARACTERS[result])\n\u003e\u003e\u003e \"homer_simpson\"\n```\n\n---\n\n## :computer: Credits\n\nCredits for the dataset to [Alexandre Attia](https://github.com/alexattia) for creating it, as well as the Kaggle\ncommunity that made it possible, as they included a lot of images to the original dataset (from 20 characters to \nup to 42).\n\n---\n\n## :crystal_ball: Future Tasks\n\n- Include label-prediction mapping using [this solution](https://stackoverflow.com/questions/53530354/tensorflow-serving-predictions-mapped-to-labels).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falvarobartt%2Fserving-tensorflow-models","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falvarobartt%2Fserving-tensorflow-models","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falvarobartt%2Fserving-tensorflow-models/lists"}