Initial working version of TF model
This commit is contained in:
Родитель
790750dea5
Коммит
d2dbf59063
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
42
LICENSE
42
LICENSE
|
@ -1,21 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
|
34
README.md
34
README.md
|
@ -1,20 +1,22 @@
|
|||
# Introduction
|
||||
TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.
|
||||
### Authors: Mathew Salvaris and Ilia Karmanov
|
||||
|
||||
# Getting Started
|
||||
TODO: Guide users through getting your code up and running on their own system. In this section you can talk about:
|
||||
1. Installation process
|
||||
2. Software dependencies
|
||||
3. Latest releases
|
||||
4. API references
|
||||
# Deploy ML on ACS
|
||||
Deploying machine learning models can often be tricky due to their numerous dependencies, deep learning models often even more so. One of the ways to overcome this is to use Docker containers. Unfortunately, it is rarely straight-forward. In this tutorial, we will demonstrate how to deploy a pre-trained deep learning model using Azure Container Services, which allows us to orchestrate a number of containers using DC/OS. By using Azure Container Services, we can ensure that it is performant, scalable and flexible enough to accommodate any deep learning framework.
|
||||
The Docker image we will be deploying can be found [here](https://hub.docker.com/r/masalvar/cntkresnet/). It contains a simple Flask web application with Nginx web server. The deep learning framework we will use is the Microsoft Cognitive Toolkit (CNTK) and we will be using a pre-trained model; specifically the ResNet 152 model.
|
||||
|
||||
# Build and Test
|
||||
TODO: Describe and show how to build your code and run the tests.
|
||||
Azure Container Services enables you to configure, construct and manage a cluster of virtual machines pre-configured to run containerized applications. Once the cluster is set up you can use a number of open-source scheduling and orchestration tools, such as Kubernetes and DC/OS. This is ideal for machine learning application since we can use Docker containers which enable us to have ultimate flexibility in the libraries we use and allows us to easily scale up based on demand. While always ensuring that our application remains performant. You can create an ACS through the Azure portal but in this tutorial we will be constructing it using the Azure CLI.
|
||||
|
||||
# Contribute
|
||||
TODO: Explain how other users and developers can contribute to make your code better.
|
||||
The application will be a simple image classification service, where we will submit an image and get back what class the image belongs to. We have split the process into five sections.
|
||||
* [Create Docker image of our application](00_BuildImage.ipynb)
|
||||
* [Test the application locally](01_TestLocally.ipynb)
|
||||
* [Create an ACS cluster and deploy our web app](02_DeployOnACS.ipynb)
|
||||
* [Test our web app](03_TestWebApp.ipynb)
|
||||
* [Load Test our web app](04_SpeedTestWebApp.ipynb)
|
||||
|
||||
Each section is accompanied by a Jupyter notebook which contains step-by-step instructions on how to create, deploy and test a web application.
|
||||
|
||||
If you already have a Docker image that you would like to deploy you can skip the first two notebooks.
|
||||
|
||||
# Contributing
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
If you want to learn more about creating good readme files then refer the following [guidelines](https://www.visualstudio.com/en-us/docs/git/create-a-readme). You can also seek inspiration from the below readme files:
|
||||
- [ASP.NET Core](https://github.com/aspnet/Home)
|
||||
- [Visual Studio Code](https://github.com/Microsoft/vscode)
|
||||
- [Chakra Core](https://github.com/Microsoft/ChakraCore)
|
|
@ -0,0 +1,332 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from PIL import Image\n",
|
||||
"import numpy as np\n",
|
||||
"import tensorflow as tf\n",
|
||||
"from tensorflow.contrib.slim.nets import resnet_v1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"--2018-03-19 13:53:02-- https://upload.wikimedia.org/wikipedia/commons/thumb/6/68/Lynx_lynx_poing.jpg/220px-Lynx_lynx_poing.jpg\n",
|
||||
"Resolving upload.wikimedia.org (upload.wikimedia.org)... 208.80.153.240, 2620:0:860:ed1a::2:b\n",
|
||||
"Connecting to upload.wikimedia.org (upload.wikimedia.org)|208.80.153.240|:443... connected.\n",
|
||||
"HTTP request sent, awaiting response... 200 OK\n",
|
||||
"Length: 27183 (27K) [image/jpeg]\n",
|
||||
"Saving to: ‘220px-Lynx_lynx_poing.jpg.1’\n",
|
||||
"\n",
|
||||
"220px-Lynx_lynx_poi 100%[===================>] 26.55K --.-KB/s in 0.01s \n",
|
||||
"\n",
|
||||
"2018-03-19 13:53:02 (2.44 MB/s) - ‘220px-Lynx_lynx_poing.jpg.1’ saved [27183/27183]\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!wget https://upload.wikimedia.org/wikipedia/commons/thumb/6/68/Lynx_lynx_poing.jpg/220px-Lynx_lynx_poing.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 40,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"im = Image.open(\"220px-Lynx_lynx_poing.jpg\").resize((224,224))\n",
|
||||
"im = np.array(im)\n",
|
||||
"im = np.expand_dims(im, 0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"--2018-03-19 13:53:11-- http://download.tensorflow.org/models/resnet_v1_152_2016_08_28.tar.gz\n",
|
||||
"Resolving download.tensorflow.org (download.tensorflow.org)... 172.217.9.16, 2607:f8b0:4000:812::2010\n",
|
||||
"Connecting to download.tensorflow.org (download.tensorflow.org)|172.217.9.16|:80... connected.\n",
|
||||
"HTTP request sent, awaiting response... 200 OK\n",
|
||||
"Length: 224342140 (214M) [application/x-tar]\n",
|
||||
"Saving to: ‘resnet_v1_152_2016_08_28.tar.gz.1’\n",
|
||||
"\n",
|
||||
"resnet_v1_152_2016_ 100%[===================>] 213.95M 106MB/s in 2.0s \n",
|
||||
"\n",
|
||||
"2018-03-19 13:53:14 (106 MB/s) - ‘resnet_v1_152_2016_08_28.tar.gz.1’ saved [224342140/224342140]\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!wget http://download.tensorflow.org/models/resnet_v1_152_2016_08_28.tar.gz"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"resnet_v1_152.ckpt\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!tar xvf resnet_v1_152_2016_08_28.tar.gz"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Placeholders\n",
|
||||
"input_tensor = tf.placeholder(tf.float32, shape=(None,224,224,3), name='input_image')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load the model\n",
|
||||
"sess = tf.Session()\n",
|
||||
"arg_scope = resnet_v1.resnet_arg_scope()\n",
|
||||
"with tf.contrib.slim.arg_scope(arg_scope):\n",
|
||||
" logits, _ = resnet_v1.resnet_v1_152(input_tensor, num_classes=1000, is_training=False)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"probabilities = tf.nn.softmax(logits)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"INFO:tensorflow:Restoring parameters from resnet_v1_152.ckpt\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"checkpoint_file = 'resnet_v1_152.ckpt'\n",
|
||||
"saver = tf.train.Saver()\n",
|
||||
"saver.restore(sess, checkpoint_file)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 41,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ValueError",
|
||||
"evalue": "Cannot feed value of shape (224, 224, 3) for Tensor 'input_image:0', which has shape '(?, 224, 224, 3)'",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
|
||||
"\u001b[1;32m<ipython-input-41-31b809ab445e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mpred\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpred_proba\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msess\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mlogits\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mprobabilities\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfeed_dict\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m{\u001b[0m\u001b[0minput_tensor\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mim\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
|
||||
"\u001b[1;32m/anaconda/envs/py35/lib/python3.5/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36mrun\u001b[1;34m(self, fetches, feed_dict, options, run_metadata)\u001b[0m\n\u001b[0;32m 887\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 888\u001b[0m result = self._run(None, fetches, feed_dict, options_ptr,\n\u001b[1;32m--> 889\u001b[1;33m run_metadata_ptr)\n\u001b[0m\u001b[0;32m 890\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mrun_metadata\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 891\u001b[0m \u001b[0mproto_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtf_session\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTF_GetBuffer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mrun_metadata_ptr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
|
||||
"\u001b[1;32m/anaconda/envs/py35/lib/python3.5/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36m_run\u001b[1;34m(self, handle, fetches, feed_dict, options, run_metadata)\u001b[0m\n\u001b[0;32m 1094\u001b[0m \u001b[1;34m'Cannot feed value of shape %r for Tensor %r, '\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1095\u001b[0m \u001b[1;34m'which has shape %r'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1096\u001b[1;33m % (np_val.shape, subfeed_t.name, str(subfeed_t.get_shape())))\n\u001b[0m\u001b[0;32m 1097\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgraph\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mis_feedable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msubfeed_t\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1098\u001b[0m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Tensor %s may not be fed.'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0msubfeed_t\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
|
||||
"\u001b[1;31mValueError\u001b[0m: Cannot feed value of shape (224, 224, 3) for Tensor 'input_image:0', which has shape '(?, 224, 224, 3)'"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pred, pred_proba = sess.run([logits,probabilities], feed_dict={input_tensor: im})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(1, 1, 1, 1000)"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pred_proba.shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"array([282, 285, 287])"
|
||||
]
|
||||
},
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"np.argsort(pred.squeeze())[-3:]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"array([282, 285, 287])"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"np.argsort(pred_proba.squeeze())[-3:]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def create_label_lookup():\n",
|
||||
" with open('synset.txt', 'r') as f:\n",
|
||||
" label_list = [l.rstrip() for l in f]\n",
|
||||
" def _label_lookup(*label_locks):\n",
|
||||
" return [label_list[l] for l in label_locks]\n",
|
||||
" return _label_lookup"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"label_lookup = create_label_lookup()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 38,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"labels=label_lookup(*np.flip(np.argsort(pred.squeeze()), 0)[:3])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 43,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'n02123159 tiger cat': 11.609917,\n",
|
||||
" 'n02124075 Egyptian cat': 11.695245,\n",
|
||||
" 'n02127052 lynx, catamount': 18.750937}"
|
||||
]
|
||||
},
|
||||
"execution_count": 43,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"dict(zip(labels, np.flip(np.sort(pred.squeeze()), 0)[:3]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3.5",
|
||||
"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.5.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
import base64
|
||||
import urllib
|
||||
import requests
|
||||
import json
|
||||
from PIL import Image, ImageOps
|
||||
from io import BytesIO
|
||||
import toolz
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.gridspec as gridspec
|
||||
|
||||
|
||||
def read_image_from(url):
|
||||
return toolz.pipe(url,
|
||||
urllib.request.urlopen,
|
||||
lambda x: x.read(),
|
||||
BytesIO)
|
||||
|
||||
|
||||
def to_rgb(img_bytes):
|
||||
return Image.open(img_bytes).convert('RGB')
|
||||
|
||||
|
||||
@toolz.curry
|
||||
def resize(img_file, new_size=(100, 100)):
|
||||
return ImageOps.fit(img_file, new_size, Image.ANTIALIAS)
|
||||
|
||||
|
||||
def to_base64(img):
|
||||
imgio = BytesIO()
|
||||
img.save(imgio, 'PNG')
|
||||
imgio.seek(0)
|
||||
dataimg = base64.b64encode(imgio.read())
|
||||
return dataimg.decode('utf-8')
|
||||
|
||||
|
||||
def to_img(img_url):
|
||||
return toolz.pipe(img_url,
|
||||
read_image_from,
|
||||
to_rgb,
|
||||
resize(new_size=(224,224)))
|
||||
|
||||
|
||||
def img_url_to_json(url):
|
||||
img_data = toolz.pipe(url,
|
||||
to_img,
|
||||
to_base64)
|
||||
return json.dumps({'input':'[\"{0}\"]'.format(img_data)})
|
||||
|
||||
|
||||
def _plot_image(ax, img):
|
||||
ax.imshow(to_img(img))
|
||||
ax.tick_params(axis='both',
|
||||
which='both',
|
||||
bottom='off',
|
||||
top='off',
|
||||
left='off',
|
||||
right='off',
|
||||
labelleft='off',
|
||||
labelbottom='off')
|
||||
return ax
|
||||
|
||||
|
||||
def _plot_prediction_bar(ax, r):
|
||||
perf = list(c[1] for c in r.json()['result'][0][0])
|
||||
ax.barh(range(3, 0, -1), perf, align='center', color='#55DD55')
|
||||
ax.tick_params(axis='both',
|
||||
which='both',
|
||||
bottom='off',
|
||||
top='off',
|
||||
left='off',
|
||||
right='off',
|
||||
labelbottom='off')
|
||||
tick_labels = reversed(list(' '.join(c[0].split()[1:]).split(',')[0] for c in r.json()['result'][0][0]))
|
||||
ax.yaxis.set_ticks([1,2,3])
|
||||
ax.yaxis.set_ticklabels(tick_labels, position=(0.5,0), minor=False, horizontalalignment='center')
|
||||
|
||||
|
||||
def plot_predictions(images, classification_results):
|
||||
if len(images)!=6:
|
||||
raise Exception('This method is only designed for 6 images')
|
||||
gs = gridspec.GridSpec(2, 3)
|
||||
fig = plt.figure(figsize=(12, 9))
|
||||
gs.update(hspace=0.1, wspace=0.001)
|
||||
|
||||
for gg,r, img in zip(gs, classification_results, images):
|
||||
gg2 = gridspec.GridSpecFromSubplotSpec(4, 10, subplot_spec=gg)
|
||||
ax = fig.add_subplot(gg2[0:3, :])
|
||||
_plot_image(ax, img)
|
||||
ax = fig.add_subplot(gg2[3, 1:9])
|
||||
_plot_prediction_bar(ax, r)
|
||||
|
||||
|
Загрузка…
Ссылка в новой задаче