updated threading so that concurrency issues are resolved and killing the main thread kills the others

This commit is contained in:
Abubakar Abid 2019-03-09 17:47:21 -08:00
parent 077b663d2a
commit ca2d44319d
5 changed files with 58 additions and 77 deletions

View File

@ -1,26 +1,5 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"ename": "ModuleNotFoundError",
"evalue": "No module named 'torchvision'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-5-82bc70f8d29b>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mimport\u001b[0m \u001b[0mtorchvision\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmodels\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mmodels\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'torchvision'"
]
}
],
"source": [
"import torchvision.models as models\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
@ -30,6 +9,7 @@
"%load_ext autoreload\n",
"%autoreload 2\n",
"\n",
"import numpy as np\n",
"import tensorflow as tf\n",
"import gradio"
]
@ -40,7 +20,7 @@
"metadata": {},
"outputs": [],
"source": [
"model = tf.keras.applications.inception_v3.InceptionV3()"
"# model = tf.keras.applications.inception_v3.InceptionV3()"
]
},
{
@ -50,12 +30,17 @@
"outputs": [],
"source": [
"inp = gradio.inputs.ImageUpload(image_width=299, image_height=299)\n",
"out = gradio.outputs.Label(label_names='imagenet1000', max_label_length=8, num_top_classes=5)\n",
"out = gradio.outputs.Label(label_names='imagenet1000', max_label_length=8, num_top_classes=8)\n",
"\n",
"iface = gradio.Interface(inputs=inp, \n",
" outputs=out,\n",
" model=model, \n",
" model_type='keras')"
" model=lambda x: np.array(1), \n",
" model_type='function')\n",
"\n",
"# iface = gradio.Interface(inputs=inp, \n",
"# outputs=out,\n",
"# model=model, \n",
"# model_type='keras')"
]
},
{
@ -70,8 +55,8 @@
"output_type": "stream",
"text": [
"NOTE: Gradio is in beta stage, please report all bugs to: a12d@stanford.edu\n",
"Model is running locally at: http://localhost:7861/interface.html\n",
"Model available publicly for 8 hours at: http://f0cf4515.ngrok.io/interface.html\n"
"Model is running locally at: http://localhost:7860/interface.html\n",
"To create a public link, set `share=True` in the argument to `launch()`\n"
]
},
{
@ -81,52 +66,22 @@
" <iframe\n",
" width=\"1000\"\n",
" height=\"500\"\n",
" src=\"http://localhost:7861/interface.html\"\n",
" src=\"http://localhost:7860/interface.html\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.IFrame at 0x1f4f871aa90>"
"<IPython.lib.display.IFrame at 0x26c5900fba8>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"127.0.0.1 - - [07/Mar/2019 12:46:05] \"GET /interface.html HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:05] \"GET /interface.html HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:05] \"GET /static/css/style.css HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:05] \"GET /static/css/gradio.css HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:05] \"GET /static/js/utils.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:05] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:05] \"GET /static/js/image-upload-input.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:05] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:06] \"GET /static/js/class-output.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:06] \"GET /static/img/logo_inline.png HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:06] code 404, message File not found\n",
"127.0.0.1 - - [07/Mar/2019 12:46:06] \"GET /favicon.ico HTTP/1.1\" 404 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:27] \"GET /interface.html HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 12:46:27] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:34] \"GET /interface.html HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:34] \"GET /static/css/style.css HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:34] \"GET /static/css/gradio.css HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:34] \"GET /static/js/utils.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:34] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:34] \"GET /static/img/logo_inline.png HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:34] \"GET /static/js/image-upload-input.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:35] \"GET /static/js/class-output.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [07/Mar/2019 13:02:35] code 404, message File not found\n",
"127.0.0.1 - - [07/Mar/2019 13:02:35] \"GET /favicon.ico HTTP/1.1\" 404 -\n"
]
}
],
"source": [
"iface.launch(inline=True, browser=True, share=True);"
"iface.launch(inline=True, browser=False, share=False);"
]
}
],

View File

@ -1,6 +1,8 @@
from argparse import ArgumentParser
import gradio
import numpy as np
import signal
import time
parser = ArgumentParser(description='Arguments for Building Interface')
parser.add_argument('-i', '--inputs', type=str, help="name of input interface")
@ -14,13 +16,29 @@ args = parser.parse_args()
def launch_interface(args):
io = gradio.Interface(inputs=args.inputs, outputs=args.outputs, model=lambda x:np.array(1), model_type='function')
io.launch(share=args.share)
# input_interface = gradio.inputs.registry[args.inputs.lower()]()
# output_interface = gradio.outputs.registry[args.outputs.lower()]()
# temp_dir = tempfile.mkdtemp()
# gradio.networking.build_template(temp_dir, input_interface, output_interface)
# print('Open this path in your browser to access the input interface: {}'.format(
# os.path.join(temp_dir, INDEX_FILE_NAME)))
httpd, _, _ = io.launch(share=args.share)
class ServiceExit(Exception):
"""
Custom exception which is used to trigger the clean exit
of all running threads and the main program.
"""
pass
def service_shutdown(signum, frame):
print('Shutting server down due to signal %d' % signum)
httpd.shutdown()
raise ServiceExit
signal.signal(signal.SIGTERM, service_shutdown)
signal.signal(signal.SIGINT, service_shutdown)
try:
# Keep the main thread running, otherwise signals are ignored.
while True:
time.sleep(0.5)
except ServiceExit:
pass
if __name__ == "__main__":

View File

@ -59,7 +59,7 @@ class Sketchpad(AbstractInput):
image_encoded = content.split(',')[1]
im = Image.open(BytesIO(base64.b64decode(image_encoded))).convert('L')
im = preprocessing_utils.resize_and_crop(im, (self.image_width, self.image_height))
array = np.array(im).flatten().reshape(1, self.image_width, self.image_height, 1)
array = np.array(im).flatten().reshape(1, self.image_width, self.image_height)
return array

View File

@ -11,6 +11,7 @@ import gradio.inputs
import gradio.outputs
from gradio import networking
import tempfile
import threading
nest_asyncio.apply()
@ -140,7 +141,7 @@ class Interface:
output_directory = tempfile.mkdtemp()
# Set up a port to serve the directory containing the static files with interface.
server_port = networking.start_simple_server(output_directory)
server_port, httpd = networking.start_simple_server(output_directory)
path_to_server = 'http://localhost:{}/'.format(server_port)
networking.build_template(output_directory, self.input_interface, self.output_interface)
@ -170,9 +171,10 @@ class Interface:
# Keep the server running in the background.
asyncio.get_event_loop().run_until_complete(start_server)
try:
asyncio.get_event_loop().run_forever()
except RuntimeError: # Runtime errors are thrown in jupyter notebooks because of async.
pass
_ = get_ipython()
except NameError: # Runtime errors are thrown in jupyter notebooks because of async.
t = threading.Thread(target=asyncio.get_event_loop().run_forever, daemon=True)
t.start()
if inline is None:
try: # Check if running interactively using ipython.
@ -193,4 +195,4 @@ class Interface:
from IPython.display import IFrame
display(IFrame(path_to_server + networking.TEMPLATE_TEMP, width=1000, height=500))
return path_to_server + networking.TEMPLATE_TEMP, site_ngrok_url
return httpd, path_to_server + networking.TEMPLATE_TEMP, site_ngrok_url

View File

@ -147,6 +147,9 @@ def serve_files_in_background(port, directory_to_serve=None):
fullpath = os.path.join(self.server.base_path, relpath)
return fullpath
def log_message(self, format, *args):
return
class HTTPServer(BaseHTTPServer):
"""The main server, you pass in base_path which is the path you want to serve requests from"""
@ -154,25 +157,28 @@ def serve_files_in_background(port, directory_to_serve=None):
self.base_path = base_path
BaseHTTPServer.__init__(self, server_address, RequestHandlerClass)
httpd = HTTPServer(directory_to_serve, (LOCALHOST_NAME, port))
# Now loop forever
def serve_forever():
try:
while True:
sys.stdout.flush()
# sys.stdout.flush()
httpd.serve_forever()
except KeyboardInterrupt:
httpd.server_close()
thread = threading.Thread(target=serve_forever)
thread = threading.Thread(target=serve_forever, daemon=True)
thread.start()
return httpd
def start_simple_server(directory_to_serve=None):
port = get_first_available_port(INITIAL_PORT_VALUE, INITIAL_PORT_VALUE + TRY_NUM_PORTS)
serve_files_in_background(port, directory_to_serve)
return port
httpd = serve_files_in_background(port, directory_to_serve)
return port, httpd
def download_ngrok():