Module tensorboardY

tensorboardY

The easier it is to interact with ML models, the faster we can determine their current limitations. This library seeks to automate the creation of cool ML demo websites like

Documentation is here (generated using pdoc3). The github repo is here.

Install

pip install tensorboardY

Examples

  • python examples/simple_example.py
import tensorboardY as ty
import matplotlib.pyplot as plt

def forward(x, title):
    plt.imshow(x)
    plt.title(title)
    return plt.gcf()

inputs = [ty.Image(var='x', exs=['imgs/curve.jpg']),
          ty.Text(var='title', exs=["EXAMPLE"])]

ty.show(forward, inputs)

  • python examples/full_example.py
import tensorboardY as ty
import os

def forward(z):
    return z

inputs = [ty.Widget("z", name="Choose your input",
                    camera=True,
                    image_upload=True,
                    image_list=['imgs/curve.jpg'], image_names=['Curve example'],
                    text_input=True,
                    text_list=['This is an example text!'], text_names=['Random'],
                    option_list=["This is an example option!"], option_names=['Resnet50'],
                    boolean=True,
                    slider=(5, 20, 0.5), slider_default=10.3)]

ty.show(forward, inputs)

Source code
"""
.. include:: ../README.md
"""

from .server import show
from .widgets import Widget, Text, Image
from .__version__ import __version__

__all__ = ['show', 'Widget', 'Text', 'Image', '__version__']

Sub-modules

tensorboardY.output
tensorboardY.server
tensorboardY.tools
tensorboardY.widgets

Functions

def show(forward, inputs, port=5000, debug=True, title='Run', github_url=None)

Starts a server at port that visualizes the function forward.

Args

forward : callable
The function to be visualized. forward should return a string of html, a PIL.Image.Image, or a matplotlib figure.
inputs : list
List of ty.Widgets (one ty.Widget for each argument to forward) that dictate how the user is able to feed inputs to the function
port : int
The port where the model is served
debug : bool
Run the server in debug mode
title : str
Submit button text
github_url : str
url to link to a github page
Source code
def show(forward, inputs, port=5000, debug=True, title='Run',
         github_url=None):
    r"""
    Starts a server at `port` that visualizes the function `forward`.
    Args:
        forward (callable): The function to be visualized. `forward` should
            return a string of html, a PIL.Image.Image, or a matplotlib figure.
        inputs (list): List of `ty.Widget`s (one `ty.Widget` for each argument
            to `forward`) that dictate how the user is able to feed inputs
            to the function
        port (int): The port where the model is served
        debug (bool): Run the server in debug mode
        title (str): Submit button text
        github_url (str): url to link to a github page
    """
    check_type(inputs, Widget, islist=True)
    check_type(title, str)
    assert(callable(forward)), '{} is not callable'.format(forward)
    loop = ioloop.IOLoop.instance()
    app = web.Application([
            (r"/", MainHandler, {'forward': forward,
                                 'inputs': inputs, 'title': title,
                                 'github_url': github_url}),
            (r"/(.*)", NoCacheStaticFileHandler, {
                "path":
                os.path.join(os.path.dirname(__file__), "./frontend/")})
            ], debug=debug)
    print('view @ http://localhost:{}'.format(port))
    app.listen(port)
    loop.start()

Classes

class Image (var, name='Image', camera=True, image_upload=True, exs=[], ex_names=None, **kwargs)

A template to build a ty.Widget for arguments that you know should always be images.

Args

var : str
The name of the argument that this widget represents
name : str
The title the user sees for this widget
camera : bool
Allow the user to take pictures
image_upload : bool
Allow user to upload images
exs : list[str]
List of file paths to images
ex_names : list[str]
The names for the images that the user sees
Source code
class Image(Widget):
    r"""
    A template to build a `ty.Widget` for arguments that you know should
    always be images.
    Args:
        var (str): The name of the argument that this widget represents
        name (str): The title the user sees for this widget
        camera (bool): Allow the user to take pictures
        image_upload (bool): Allow user to upload images
        exs (list[str]): List of file paths to images
        ex_names (list[str]): The names for the images that the user sees
    """
    def __init__(self, var, name="Image",
                 camera=True,
                 image_upload=True,
                 exs=[], ex_names=None, **kwargs):
        super(Image, self).__init__(var=var, name=name,
                                    camera=camera, image_upload=image_upload,
                                    image_list=exs, image_names=ex_names,
                                    **kwargs)

Ancestors

class Text (var, name='Text', text_input=True, exs=[], ex_names=None, **kwargs)

A template to build arguments that you know should always be text.

Args

var : str
The function variable name this widget represents
name : str
The title the user sees for this widget
text_input : bool
Allow the user to input text
exs : list[str]
List of example strings
ex_names : list[str]
The names for the texts that the user sees
Source code
class Text(Widget):
    r"""
    A template to build arguments that you know should always be text.
    Args:
        var (str): The function variable name this widget represents
        name (str): The title the user sees for this widget
        text_input (bool): Allow the user to input text
        exs (list[str]): List of example strings
        ex_names (list[str]): The names for the texts that the user sees
    """
    def __init__(self, var, name="Text",
                 text_input=True,
                 exs=[], ex_names=None, **kwargs):
        super(Text, self).__init__(var=var, name=name,
                                   text_input=text_input,
                                   text_list=exs, text_names=ex_names,
                                   **kwargs)

Ancestors

class Widget (var, name='Widget', camera=False, image_upload=False, image_list=[], image_names=None, text_input=False, text_list=[], text_names=None, option_list=[], option_names=None, boolean=False, slider=None, slider_default=None)

Base class for function input forms.

Args

var : str
The function variable name this widget represents
name : str
The title of this widget
camera : bool
Allow the user to take pictures
image_upload : bool
Allow user to upload images
image_list : list[str]
List of file paths to images
image_names : list[str]
List of names the client will see
text_input : bool
Allow the user to input text
text_list : list[str]
List of example strings
text_names : list[str]
The names the client will see
option_list : list[str]
List of options. "Options" differ from "texts" in that they won't be previewed to the client
option_names : list[str]
List of names the client will see
boolean : bool
Allow the user to input a boolean
slider : tuple
Tuple (min, max, increment) so for instance (0,1,.1) would allow the user to choose 0, 0.1, 0.2, …, 1.0.
slider_default : float
The initial position of the slider
Source code
class Widget(object):
    r"""
    Base class for function input forms.
    Args:
        var (str): The function variable name this widget represents
        name (str): The title of this widget
        camera (bool): Allow the user to take pictures
        image_upload (bool): Allow user to upload images
        image_list (list[str]): List of file paths to images
        image_names (list[str]): List of names the client will see
        text_input (bool): Allow the user to input text
        text_list (list[str]): List of example strings
        text_names (list[str]): The names the client will see
        option_list (list[str]): List of options. "Options" differ from "texts"
            in that they won't be previewed to the client
        option_names (list[str]): List of names the client will see
        boolean (bool): Allow the user to input a boolean
        slider (tuple): Tuple (min, max, increment) so for instance (0,1,.1)
            would allow the user to choose 0, 0.1, 0.2, ..., 1.0.
        slider_default (float): The initial position of the slider
    """
    def __init__(self, var, name="Widget",
                 camera=False,
                 image_upload=False,
                 image_list=[], image_names=None,
                 text_input=False,
                 text_list=[], text_names=None,
                 option_list=[], option_names=None,
                 boolean=False,
                 slider=None, slider_default=None):
        check_type(var, str)
        self.var = var

        self.name = name

        check_type(camera, bool)
        self.camera = camera

        check_type(image_upload, bool)
        self.image_upload = image_upload

        self.image_list = [ex for ex in check_type(image_list,
                                                   str, islist=True)]

        if image_names is None:
            image_names = ["Image {}".format(i)
                           for i in range(len(self.image_list))]
        self.image_names = [name for name in image_names]
        assert(len(self.image_list) == len(self.image_names)),\
            "{} != {}".format(len(self.image_list),
                              len(self.image_names))

        check_type(text_input, bool)
        self.text_input = text_input

        self.text_list = [ex for ex in text_list]

        if text_names is None:
            len_limit = 35
            text_names = [ex for ex in self.text_list]
            for i, ex in enumerate(text_names):
                if len(ex) > len_limit:
                    text_names[i] = "{}...".format(ex[:(len_limit - 3)])
        self.text_names = [name for name in text_names]
        assert(len(self.text_list) == len(self.text_names)),\
            "{} != {}".format(len(self.text_list),
                              len(self.text_names))

        self.option_list = [ex for ex in option_list]

        if option_names is None:
            option_names = ["Option {}".format(i)
                            for i in range(len(self.option_list))]
        self.option_names = [name for name in option_names]
        assert(len(self.option_list) == len(self.option_names)),\
            "{} != {}".format(len(self.option_list),
                              len(self.option_names))

        check_type(boolean, bool)
        self.boolean = boolean

        if slider is not None:
            assert(len(slider) == 3), "slider {} not length 3"\
                   .format(len(slider))
        self.slider = slider

        self.slider_default = slider_default

    def get_data(self, gui, opt_id):
        if gui == 'upload_img':
            assert(0 <= opt_id < len(self.image_list)),\
                "opt_id {} not in [0,{})".format(opt_id, len(self.image_list))
            img = PILImage.open(self.image_list[opt_id]).convert('RGB')
            b64 = pil_to_b64(img)
            return b64
        if gui == 'upload_txt':
            assert(0 <= opt_id < len(self.text_list)),\
                "opt_id {} not in [0,{})".format(opt_id, len(self.text_list))
            return self.text_list[opt_id]

    def decode(self, arg):
        if arg['kind'] == 'ignore':
            return arg['data']
        if arg['kind'] == 'opt_id':
            return self.option_list[arg['data']]
        if arg['kind'] == 'img':
            return b64_to_pil(arg['data'])
        if arg['kind'] == 'bool':
            if arg['data'] == 'True':
                return True
            return False
        assert(False), 'arg kind {} not understood'.format(arg['kind'])

Subclasses

Methods

def decode(self, arg)
Source code
def decode(self, arg):
    if arg['kind'] == 'ignore':
        return arg['data']
    if arg['kind'] == 'opt_id':
        return self.option_list[arg['data']]
    if arg['kind'] == 'img':
        return b64_to_pil(arg['data'])
    if arg['kind'] == 'bool':
        if arg['data'] == 'True':
            return True
        return False
    assert(False), 'arg kind {} not understood'.format(arg['kind'])
def get_data(self, gui, opt_id)
Source code
def get_data(self, gui, opt_id):
    if gui == 'upload_img':
        assert(0 <= opt_id < len(self.image_list)),\
            "opt_id {} not in [0,{})".format(opt_id, len(self.image_list))
        img = PILImage.open(self.image_list[opt_id]).convert('RGB')
        b64 = pil_to_b64(img)
        return b64
    if gui == 'upload_txt':
        assert(0 <= opt_id < len(self.text_list)),\
            "opt_id {} not in [0,{})".format(opt_id, len(self.text_list))
        return self.text_list[opt_id]