├── graphpipe_tf ├── __init__.py ├── layers.py └── ops.py ├── remote_op ├── .gitignore ├── Makefile ├── remote_op.cc └── graphpipe │ └── cpp │ └── graphpipe_generated.h ├── tools └── h5topb │ ├── .gitignore │ ├── h5topb.sh │ ├── Makefile │ └── Dockerfile ├── examples ├── .gitignore ├── az4 │ ├── az4.000001.pb │ ├── az4.000003.pb │ ├── az4.000005.pb │ ├── az4.000007.pb │ ├── az4.000010.pb │ ├── az4.000020.pb │ ├── az4.000050.pb │ ├── README.md │ └── az4.py ├── simple_request.py ├── tf_graph.py ├── call_remote_op.py ├── convert.py ├── model_server.py └── RemoteModelWithGraphPipe.ipynb ├── MANIFEST.in ├── requirements.txt ├── test-requirements.txt ├── CONTRIBUTING.md ├── Makefile ├── tox.ini ├── README.md ├── setup.py ├── LICENSE.txt └── .gitignore /graphpipe_tf/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /remote_op/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | -------------------------------------------------------------------------------- /tools/h5topb/.gitignore: -------------------------------------------------------------------------------- 1 | convert.py 2 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | /*.jpg 2 | /*.h5 3 | /*.pb 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements.txt 2 | include LICENSE.txt 3 | -------------------------------------------------------------------------------- /examples/az4/az4.000001.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle/graphpipe-tf-py/HEAD/examples/az4/az4.000001.pb -------------------------------------------------------------------------------- /examples/az4/az4.000003.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle/graphpipe-tf-py/HEAD/examples/az4/az4.000003.pb -------------------------------------------------------------------------------- /examples/az4/az4.000005.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle/graphpipe-tf-py/HEAD/examples/az4/az4.000005.pb -------------------------------------------------------------------------------- /examples/az4/az4.000007.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle/graphpipe-tf-py/HEAD/examples/az4/az4.000007.pb -------------------------------------------------------------------------------- /examples/az4/az4.000010.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle/graphpipe-tf-py/HEAD/examples/az4/az4.000010.pb -------------------------------------------------------------------------------- /examples/az4/az4.000020.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle/graphpipe-tf-py/HEAD/examples/az4/az4.000020.pb -------------------------------------------------------------------------------- /examples/az4/az4.000050.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle/graphpipe-tf-py/HEAD/examples/az4/az4.000050.pb -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy>=1.13.3 2 | requests==2.18.4 3 | tensorflow>=1.4.0 4 | graphpipe>=1.0.1 5 | flatbuffers==1.9.0 6 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | flake8==2.5.0 2 | hacking<0.11,>=0.10.0 3 | pytest-cov==2.4.0 4 | testtools>=1.4.0 5 | numpy>=1.13.3 6 | requests==2.18.4 7 | tensorflow>=1.4.0 8 | -e git+https://github.com/oracle/graphpipe-py#egg=graphpipe 9 | flatbuffers==1.9.0 10 | -------------------------------------------------------------------------------- /tools/h5topb/h5topb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Licensed under the Universal Permissive License v 1.0 as shown at 6 | # http://oss.oracle.com/licenses/upl. 7 | 8 | cd /tmp/ 9 | source /py36env/bin/activate && python3.6 /convert.py $@ 10 | -------------------------------------------------------------------------------- /tools/h5topb/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at 4 | # http://oss.oracle.com/licenses/upl. 5 | 6 | IMAGE=graphpipe-h5topb 7 | 8 | all: 9 | cp ../../examples/convert.py . 10 | docker build -t ${IMAGE} \ 11 | --build-arg http_proxy=$(http_proxy) \ 12 | --build-arg https_proxy=$(https_proxy) \ 13 | . 14 | -------------------------------------------------------------------------------- /tools/h5topb/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at 4 | # http://oss.oracle.com/licenses/upl. 5 | 6 | FROM oraclelinux:7-slim 7 | RUN yum install -y yum-utils 8 | RUN yum-config-manager --enable ol7_developer_EPEL 9 | RUN yum install -y python36 10 | RUN python3.6 -m venv py36env 11 | RUN source py36env/bin/activate && pip install tensorflow==1.8.0 12 | RUN source py36env/bin/activate && pip install h5py 13 | COPY convert.py /convert.py 14 | COPY h5topb.sh /h5topb.sh 15 | ENTRYPOINT ["/h5topb.sh"] 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Graphpipe-Tf-Py # 2 | 3 | *Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.* 4 | 5 | Pull requests can be made under 6 | [The Oracle Contributor Agreement](https://www.oracle.com/technetwork/community/oca-486395.html) (OCA). 7 | 8 | For pull requests to be accepted, the bottom of 9 | your commit message must have the following line using your name and 10 | e-mail address as it appears in the OCA Signatories list. 11 | 12 | ``` 13 | Signed-off-by: Your Name 14 | ``` 15 | 16 | This can be automatically added to pull requests by committing with: 17 | 18 | ``` 19 | git commit --signoff 20 | ``` 21 | 22 | Only pull requests from committers that can be verified as having 23 | signed the OCA can be accepted. 24 | -------------------------------------------------------------------------------- /examples/simple_request.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Licensed under the Universal Permissive License v 1.0 as shown at 6 | # http://oss.oracle.com/licenses/upl. 7 | 8 | """ 9 | Serves a simple model with model_server.py and makes a request to it 10 | """ 11 | 12 | import subprocess 13 | import time 14 | 15 | import numpy as np 16 | 17 | from graphpipe import remote 18 | 19 | # create a simple protobuf model that squares its input 20 | process = subprocess.Popen(["./tf_graph.py"]) 21 | process.wait() 22 | 23 | port = "4242" 24 | process = subprocess.Popen(["./model_server.py", "--port", port, "--model", "tf_graph.pb"]) 25 | # make sure the process has time to start 26 | time.sleep(3) 27 | 28 | # send a request 29 | x = np.array(0.42) 30 | y = remote.execute("http://127.0.0.1:" + port, x) 31 | # print the response 32 | print(y) 33 | 34 | # kill the server 35 | process.kill() 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at 4 | # http://oss.oracle.com/licenses/upl. 5 | 6 | ifeq ($(OS),Windows_NT) 7 | $(error Windows builds are not yet supported :() 8 | else 9 | detected_OS := $(shell uname -s) 10 | endif 11 | 12 | ifeq ($(detected_OS),Linux) 13 | BUILD_SCRIPT := build_linux.sh 14 | test: 15 | docker run -it --rm \ 16 | -v $(PWD):/src \ 17 | -e http_proxy=$(http_proxy) \ 18 | -e https_proxy=$(https_proxy) \ 19 | themattrix/tox-base \ 20 | /app/build_linux.sh 21 | #/bin/sh 22 | 23 | build: 24 | docker run -it --rm \ 25 | -v $(PWD):/app \ 26 | -w /app \ 27 | -e http_proxy=$(http_proxy) \ 28 | -e https_proxy=$(https_proxy) \ 29 | python:3.5 \ 30 | /app/build_linux.sh $$(id -u):$$(id -g) 31 | #/bin/sh 32 | endif 33 | 34 | ifeq ($(detected_OS),Darwin) # Mac OS X 35 | BUILD_SCRIPT := build_darwin.sh 36 | build: 37 | ./build_darwin.sh 38 | endif 39 | 40 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py{3.5,3.6},pep8 3 | skipsdist = True 4 | 5 | [testenv] 6 | basepython = 7 | pep8: python 8 | py3.5: python3.5 9 | py3.6: python3.6 10 | 11 | passenv = 12 | DOCKER_HOST 13 | API_URL 14 | setenv = VIRTUAL_ENV={envdir} 15 | usedevelop = True 16 | install_command = pip install -U {opts} {packages} 17 | deps = -r{toxinidir}/test-requirements.txt 18 | commands = find . -type f -name "*.pyc" -delete 19 | whitelist_externals = find 20 | rm 21 | go 22 | docker 23 | [testenv:pep8] 24 | commands = flake8 25 | 26 | [testenv:venv] 27 | commands = {posargs} 28 | 29 | [testenv:py3.5] 30 | commands = pytest -vv --tb=long --capture=sys --cov=graphpipe_tf --capture=fd {toxinidir}/tests 31 | 32 | [testenv:py3.6] 33 | commands = pytest -vv --tb=long --capture=sys --cov=graphpipe_tf --capture=fd {toxinidir}/tests 34 | 35 | [flake8] 36 | ignore = H405,H404,H403,H401 37 | show-source = True 38 | exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,docs,venv,.venv 39 | -------------------------------------------------------------------------------- /remote_op/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at 4 | # http://oss.oracle.com/licenses/upl. 5 | 6 | TARGET = ../graphpipe_tf/remote_op.so 7 | 8 | PYTHON = python 9 | 10 | TF_LIB = $(shell $(PYTHON) -c 'import tensorflow as tf; print(tf.sysconfig.get_lib())') 11 | TF_INC = $(shell $(PYTHON) -c 'import tensorflow as tf; print(tf.sysconfig.get_include())') 12 | 13 | CC = g++ 14 | 15 | INCLUDES = -Igraphpipe/cpp -Iflatbuffers/include -I$(TF_INC) -I$(TF_INC)/external/nsync/public 16 | 17 | LIBS = -ltensorflow_framework -lcurl -lssl -lcrypto 18 | 19 | FLAGS = -std=c++11 \ 20 | -shared \ 21 | -fPIC \ 22 | -O2 \ 23 | -L$(TF_LIB) \ 24 | $(INCLUDES) \ 25 | $(LIBS) \ 26 | $(EXTRA_FLAGS) \ 27 | -D_GLIBCXX_USE_CXX11_ABI=0 28 | 29 | FILES = remote_op.cc 30 | 31 | all: $(TARGET) 32 | 33 | $(TARGET) : $(FILES) graphpipe/cpp/graphpipe_generated.h 34 | $(CC) -o $(TARGET) $(FILES) $(FLAGS) 35 | 36 | %.so : %.cc 37 | $(CC) $(CFLAGS) $< -o $@ 38 | 39 | clean: 40 | rm -f $(TARGET) 41 | -------------------------------------------------------------------------------- /examples/tf_graph.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Licensed under the Universal Permissive License v 1.0 as shown at 6 | # http://oss.oracle.com/licenses/upl. 7 | 8 | """ 9 | This example illustrates how to write a tensorflow graph as a constantized 10 | graph_def protobuf so it can be served by ./model_server.py 11 | """ 12 | 13 | import os 14 | import tensorflow as tf 15 | 16 | from tensorflow.python.framework import graph_io 17 | from tensorflow.python.framework import graph_util 18 | 19 | g = tf.Graph() 20 | with g.as_default(): 21 | x = tf.placeholder(tf.float32) 22 | 23 | mul = tf.multiply(x, x) 24 | 25 | fname = "tf_graph.pb" 26 | 27 | graph_def = g.as_graph_def(add_shapes=True) 28 | 29 | # this conversion is not necessary because there are no trainable 30 | # parameters, but it is included because it is important for more 31 | # complex models 32 | output_names = [mul.op.name] 33 | graph_def = graph_util.convert_variables_to_constants( 34 | tf.Session(), graph_def, output_names) 35 | 36 | d, f = os.path.split(os.path.abspath(fname)) 37 | graph_io.write_graph(graph_def, d, f, as_text=False) 38 | -------------------------------------------------------------------------------- /examples/az4/README.md: -------------------------------------------------------------------------------- 1 | # AZ Four inference 2 | 3 | This directory contains a few versions of a convolutional model trained with 4 | the AlphaZero algorithm to evaluate four-in-a-row positions. The model expects 5 | inputs of the shape [?, 2, 6, 7] where each [2, 6, 7] represents a single board 6 | position. The first [6, 7] array is a binary representation of the pieces for 7 | the current player, and the second [6,7] is a binary representation of the 8 | pieces for the opposing player. In this binary representation, an empty square 9 | is represented by a 0.0, and a piece is represented by a 1.0. 10 | 11 | The model returns two outputs. The first output, called the policy output, is a 12 | [?, 7] array representing the softmax representation of the value of a move in 13 | each of the seven columns starting from the left for each of the input 14 | positions. For example, an evaluation might look like the following: 15 | 16 | [0.0, 0.0, 0.1, 0.8, 0.1, 0.0, 0.0] 17 | 18 | This means that the agent things going in the center is the optimal move, and 19 | column 3 and 5 are also reasonable choices. 20 | 21 | The second output, called the value output, is a single floating point value 22 | representing the expectation of the result of the game from the perspective of 23 | the current player. A value of 1.0 means it is a certainty the player will win, 24 | and a value -1.0 means it is a certainty the player will lose. A value close to 25 | 0.0 represents a draw. 26 | 27 | See [az4.py](az4.py) for an example of how to query the model using GraphPipe. 28 | -------------------------------------------------------------------------------- /examples/call_remote_op.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Licensed under the Universal Permissive License v 1.0 as shown at 6 | # http://oss.oracle.com/licenses/upl. 7 | 8 | """This example illustrates using remote_ops in a tensorflow graph 9 | 10 | In this example, we use two calls to the same VGG graph. We collect 11 | the output of the last fully connected layer and then send that as 12 | input through the rest of the graph to get class predictions. 13 | 14 | This illustrates how one might extract bottleneck features from a 15 | trained model and use them as input to another model. 16 | """ 17 | 18 | import argparse 19 | 20 | import numpy as np 21 | from graphpipe_tf import ops 22 | import tensorflow as tf 23 | 24 | if __name__ == "__main__": 25 | parser = argparse.ArgumentParser() 26 | parser.add_argument('-i', '--inputs', nargs='+', 27 | help='inputs to send to model') 28 | 29 | args = parser.parse_args() 30 | inputs = [] 31 | for fname in args.inputs: 32 | with open(fname, mode='rb') as f: 33 | inputs.append([f.read()]) 34 | 35 | g1 = tf.Graph() 36 | with g1.as_default(): 37 | x = tf.placeholder(tf.string, shape=(None, 1)) 38 | bottle = ops.remote_op_multi( 39 | "http://localhost:9000", 40 | [x], 41 | ["import/input"], 42 | ["import/fc2/Relu:0"], 43 | output_types=[tf.float32] 44 | ) 45 | y = ops.remote_op( 46 | "http://localhost:9000", 47 | bottle[0], 48 | "import/fc2/Relu:0" 49 | ) 50 | with tf.Session(graph=g1) as sess: 51 | res = sess.run(y, feed_dict={x: inputs}) 52 | print(res) 53 | -------------------------------------------------------------------------------- /graphpipe_tf/layers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at 4 | # http://oss.oracle.com/licenses/upl. 5 | 6 | from tensorflow.python.keras._impl.keras import engine 7 | 8 | from . import ops 9 | 10 | 11 | class Remote(engine.Layer): 12 | """Remote Layer allows a Keras model to include a remote GraphPipe model. 13 | 14 | The keras layer uses a tensorflow remote_op plugin to make a request to an 15 | external model. The only required parameter to the constructor is the uri 16 | of the remote model. If output_type and and output_shape are not specified, 17 | they will be inferred using the GraphPipe metadata api. 18 | 19 | The layer is created with trainable=False, because it is not possible to 20 | train the remote model. It is possible to use a remote layer with 21 | additional trainable layers on top to fine-tune the output of a remote 22 | model or to create an ensemble. 23 | """ 24 | 25 | def __init__(self, name=None, uri=None, input_name=None, output_name=None, 26 | output_type=None, output_shape=None, config=None, **kwargs): 27 | self.uri = uri 28 | self.iname = input_name or "" 29 | self.oname = output_name or "" 30 | self.otype = output_type 31 | self.oshape = output_shape 32 | self.config = config or "" 33 | super(Remote, self).__init__(name=name, trainable=False, **kwargs) 34 | 35 | def call(self, x): 36 | return ops.remote_op(self.uri, 37 | x, 38 | self.iname, 39 | self.oname, 40 | self.otype, 41 | self.oshape, 42 | self.config) 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraphPipe helpers for TensorFlow 2 | 3 | This package contains helpers and examples for using GraphPipe with tensorflow. 4 | It contains a new plug-in operation for tensorflow that makes a call to a 5 | GraphPipe remote model from within a local tensorflow graph. The new operation 6 | is called remote_op and communicates with the remote model using libcurl and 7 | the GraphPipe protocol. 8 | 9 | Additionaly, a new keras layer is included based on the remote operation. This 10 | allows you to include a layer in a keras model that makes a remote call. 11 | 12 | Finally, various examples are included of serving tensorflow models in python. 13 | For production, a more performant server like 14 | [`graphpipe-tf`](https://github.com/oracle/graphpipe-go/cmd/graphpipe-tf) is 15 | recommended, but the python server is useful for experimentation. 16 | 17 | ## List Of Examples 18 | 19 | * [Jupyter Notebook: serving and querying VGG with 20 | GraphPipe](examples/RemoteModelWithGraphPipe.ipynb) 21 | * [Complete client/server example](examples/simple_request.py) 22 | * [Simple tensorflow model server](examples/model_server.py) 23 | * [Keras to GraphDef](examples/convert.py) 24 | * [Using a remote operation](examples/call_remote_op.py) 25 | * [Tensorflow graph to GraphDef](examples/tf_graph.py) 26 | 27 | ## Build 28 | 29 | Building manually requires a few libraries to be installed, but the Makefile 30 | will happily run a build for you in a docker container. 31 | ``` 32 | make build 33 | ``` 34 | 35 | See `build_linux.sh` for the additional headers besides libcurl that you will 36 | need to build the C library. (From tensorflow and flatbuffers) 37 | 38 | If you've successfully built the C library, to build installation packages: 39 | 40 | python setup.py bdist_wheel 41 | 42 | Note that these are not manylinux wheels and depend on libcurl being installed 43 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at 4 | # http://oss.oracle.com/licenses/upl. 5 | 6 | import subprocess 7 | 8 | import setuptools 9 | 10 | from codecs import open 11 | from os import path 12 | 13 | 14 | 15 | class BinaryDistribution(setuptools.Distribution): 16 | """Distribution which always forces a binary package with platform name""" 17 | def has_ext_modules(self): 18 | return True 19 | 20 | 21 | subprocess.call(['make', '-C', 'remote_op']) 22 | 23 | here = path.abspath(path.dirname(__file__)) 24 | with open(path.join(here, 'README.md'), encoding='utf-8') as f: 25 | long_description = f.read() 26 | 27 | requirements = None 28 | with open('requirements.txt') as f: 29 | requirements = f.read().splitlines() 30 | 31 | setuptools.setup( 32 | name='graphpipe_tf', 33 | version='1.0.4', 34 | description='Graphpipe helpers for TensorFlow remote ops', 35 | long_description=long_description, 36 | long_description_content_type="text/markdown", 37 | author='OCI ML Team', 38 | install_requires=requirements, 39 | author_email='vish.ishaya@oracle.com', 40 | url='https://oracle.github.io/graphpipe', 41 | classifier=[ 42 | 'Intended Audience :: Information Technology', 43 | 'Intended Audience :: System Administrators', 44 | 'Operating System :: POSIX :: Linux', 45 | 'License :: OSI Approved :: Universal Permissive License (UPL)', 46 | 'Programming Language :: Python', 47 | 'Programming Language :: Python :: 3', 48 | 'Programming Language :: Python :: 3.5', 49 | 'Programming Language :: Python :: 3.6', 50 | ], 51 | packages=['graphpipe_tf'], 52 | package_data={'graphpipe_tf': ['remote_op.so']}, 53 | distclass=BinaryDistribution, 54 | ) 55 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | 3 | This software is licensed to you under the Universal Permissive License (UPL). See below for license terms. 4 | ____________________________ 5 | The Universal Permissive License (UPL), Version 1.0 6 | Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 7 | 8 | Subject to the condition set forth below, permission is hereby granted to any person obtaining a copy of this software, associated documentation and/or data (collectively the "Software"), free of charge and under any and all copyright rights in the Software, and any and all patent rights owned or freely licensable by each licensor hereunder covering either (i) the unmodified Software as contributed to or provided by such licensor, or (ii) the Larger Works (as defined below), to deal in both 9 | 10 | (a) the Software, and 11 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if one is included with the Software (each a "Larger Work" to which the Software is contributed by such licensors), 12 | 13 | without restriction, including without limitation the rights to copy, create derivative works of, display, perform, and distribute the Software and make, use, sell, offer for sale, import, export, have made, and have sold the Software and the Larger Work(s), and to sublicense the foregoing rights on either these or other terms. 14 | 15 | This license is subject to the following condition: 16 | 17 | The above copyright notice and either this complete permission notice or at a minimum a reference to the UPL must be included in all copies or substantial portions of the Software. 18 | 19 | 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. 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | remote_op/flatbuffers 2 | src/ 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # dotenv 86 | .env 87 | 88 | # virtualenv 89 | .venv 90 | venv/ 91 | ENV/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | *.pyc 106 | .testrepository 107 | .tox/* 108 | dist/* 109 | build/* 110 | html/* 111 | *.egg* 112 | cover/* 113 | .coverage 114 | rdserver.txt 115 | python-troveclient.iml 116 | 117 | # Files created by releasenotes build 118 | releasenotes/build 119 | .coverage.* 120 | *.json 121 | .cache 122 | *.log* 123 | *.csv 124 | venv 125 | .venv 126 | ChangeLog 127 | AUTHORS 128 | -------------------------------------------------------------------------------- /examples/convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Licensed under the Universal Permissive License v 1.0 as shown at 6 | # http://oss.oracle.com/licenses/upl. 7 | 8 | 9 | import collections 10 | import os.path 11 | import os 12 | import stat 13 | 14 | import tensorflow as tf 15 | 16 | from tensorflow.contrib.keras import backend as K 17 | from tensorflow.contrib.keras import models 18 | from tensorflow.python.framework import graph_io 19 | from tensorflow.python.framework import graph_util 20 | 21 | 22 | def write_graph(graph, fname): 23 | d, f = os.path.split(os.path.abspath(fname)) 24 | graph_io.write_graph(graph, d, f, as_text=False) 25 | 26 | 27 | def constantize(fname): 28 | K.clear_session() 29 | tf.reset_default_graph() 30 | K.set_learning_phase(False) 31 | mod = models.load_model(fname) 32 | outputs = mod.output 33 | if not isinstance(outputs, collections.Sequence): 34 | outputs = [outputs] 35 | output_names = [] 36 | for output in outputs: 37 | output_names.append(output.name.split(':')[0]) 38 | sess = K.get_session() 39 | cg = graph_util.convert_variables_to_constants( 40 | sess, sess.graph.as_graph_def(add_shapes=True), output_names) 41 | K.clear_session() 42 | return cg 43 | 44 | 45 | def h5_to_pb(h5, pb): 46 | write_graph(constantize(h5), pb) 47 | 48 | 49 | def copy_perms(source, target): 50 | st = os.stat(source) 51 | os.chown(target, st[stat.ST_UID], st[stat.ST_GID]) 52 | 53 | 54 | if __name__ == "__main__": 55 | # disable gpu for conversion 56 | config = tf.ConfigProto(allow_soft_placement=True, 57 | device_count={'CPU': 1, 'GPU': 0}) 58 | session = tf.Session(config=config) 59 | K.set_session(session) 60 | 61 | import sys 62 | if len(sys.argv) < 3: 63 | print('usage: {} '.format(sys.argv[0])) 64 | sys.exit(1) 65 | h5_to_pb(sys.argv[1], sys.argv[2]) 66 | copy_perms(sys.argv[1], sys.argv[2]) 67 | print('saved the constant graph (ready for inference) at: ', sys.argv[2]) 68 | -------------------------------------------------------------------------------- /graphpipe_tf/ops.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at 4 | # http://oss.oracle.com/licenses/upl. 5 | 6 | import os 7 | 8 | import tensorflow as tf 9 | 10 | from graphpipe import remote 11 | 12 | 13 | def load_op_library(): 14 | dir_path = os.path.dirname(os.path.realpath(__file__)) 15 | return tf.load_op_library(os.path.join(dir_path, 'remote_op.so')) 16 | 17 | 18 | _remote_op = load_op_library() 19 | 20 | 21 | def remote_op(uri, inp, input_name=None, output_name=None, output_type=None, 22 | output_shape=None, config=""): 23 | res = remote_op_multi(uri, 24 | [inp], 25 | None if input_name is None else [input_name], 26 | None if output_name is None else [output_name], 27 | None if output_type is None else [output_type], 28 | None if output_shape is None else [output_shapes], 29 | config) 30 | if len(res) == 1: 31 | res = res[0] 32 | return res 33 | 34 | 35 | def remote_op_multi(uri, inputs, input_names, output_names, output_types=None, 36 | output_shapes=None, config=""): 37 | if not output_types or not output_shapes: 38 | all_names = remote.get_output_names(uri) 39 | all_types = remote.get_output_types(uri) 40 | all_shapes = remote.get_output_shapes(uri) 41 | if not output_names: 42 | output_names = [all_names[-1]] 43 | actual_types = [] 44 | actual_shapes = [] 45 | for i in range(len(output_names)): 46 | for j in range(len(all_names)): 47 | if all_names[j] == output_names[i]: 48 | actual_types.append(all_types[j]) 49 | actual_shapes.append(all_shapes[j]) 50 | if not output_types: 51 | output_types = actual_types 52 | if not output_shapes: 53 | output_shapes = actual_shapes 54 | return _remote_op.remote(uri, 55 | config, 56 | inputs, 57 | input_names, 58 | output_names, 59 | output_types, 60 | output_shapes) 61 | -------------------------------------------------------------------------------- /examples/az4/az4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Licensed under the Universal Permissive License v 1.0 as shown at 6 | # http://oss.oracle.com/licenses/upl. 7 | 8 | """Example of making requests to the AlphaZero four model 9 | 10 | The model convolutions are in channels first order. This 11 | means they must be served with the gpu version of libtensorflow 12 | or one that was built with MKL. If you have one, you can 13 | serve the model using model_server.py: 14 | 15 | ../model_server.py --model az4.000050.pb 16 | 17 | Or you can serve it using a community provided docker container: 18 | 19 | docker run -it --rm \ 20 | -v "$PWD:/models/" \ 21 | -p 9000:9000 \ 22 | sleepsonthefloor/graphpipe-tf:cpu \ 23 | --model=/models/az4.000050.pb \ 24 | --listen=0.0.0.0:9000 25 | """ 26 | 27 | from graphpipe import remote 28 | 29 | import numpy as np 30 | 31 | 32 | def parse_board(s): 33 | s = s.strip() 34 | boardx = np.zeros((1, 6, 7), dtype=np.float32) 35 | boardo = np.zeros((1, 6, 7), dtype=np.float32) 36 | empty = 0 37 | for x, line in enumerate(s.split("\n")): 38 | line = line.replace(" ", "") 39 | for y, char in enumerate(line): 40 | if char == 'X': 41 | boardx[0, x, y] = 1 42 | elif char == 'O': 43 | boardo[0, x, y] = 1 44 | else: 45 | empty += 1 46 | if empty % 2 == 1: 47 | return np.concatenate((boardo, boardx)) 48 | return np.concatenate((boardx, boardo)) 49 | 50 | 51 | def print_board(board): 52 | x, o = 0, 1 53 | if (np.count_nonzero(board) % 2) == 1: 54 | x, o = o, x 55 | display = np.chararray((6, 7), 3) 56 | display[:] = ' - ' 57 | display[board[x] == 1] = ' X ' 58 | display[board[o] == 1] = ' O ' 59 | 60 | dtype = 'S' + str(7 * 3) 61 | strs = display.transpose().view(dtype).ravel() 62 | print(b'\n'.join(strs).decode("utf8")) 63 | 64 | 65 | def print_weights(w): 66 | print("{:02.0f} {:02.0f} {:02.0f} {:02.0f} {:02.0f} {:02.0f} {:02.0f}".format( 67 | w[0]*100, w[1]*100, w[2]*100, w[3]*100, w[4]*100, w[5]*100, w[6]*100)) 68 | 69 | 70 | MODEL = "http://127.0.0.1:9000" 71 | 72 | 73 | def evaluate(boards): 74 | 75 | x = np.concatenate([parse_board(board)[np.newaxis, :] for board in boards]) 76 | weights, values = remote.execute(MODEL, x) 77 | for i in range(len(weights)): 78 | weight = weights[i] 79 | value = values[i][0] 80 | move = int(x[i].sum()) 81 | player = move % 2 82 | print("Move {}: {} to play".format(move, "O" if player else "X")) 83 | print_board(x[i]) 84 | print_weights(weight) 85 | if player: 86 | value = -value 87 | if value > 0: 88 | print("Evaluation: X wins {:02.0f}%".format(value * 100)) 89 | else: 90 | print("Evaluation: O wins {:02.0f}%".format(value * -100)) 91 | print() 92 | 93 | 94 | boards = [] 95 | boards.append(""" 96 | - - - - - - - 97 | - - - - - - - 98 | - - - - - - - 99 | - - - - - - - 100 | - - - - - - - 101 | - - - - - - - 102 | """) 103 | 104 | boards.append(""" 105 | - - - - - - - 106 | - - - - - - - 107 | - - - - - - - 108 | - - - - - - - 109 | - - - - - - - 110 | - - - X - - - 111 | """) 112 | 113 | boards.append(""" 114 | - - - - - - - 115 | - - - - - - - 116 | - - - - - - - 117 | - - - - - - - 118 | - - - - X X - 119 | X - - - O O - 120 | """) 121 | 122 | evaluate(boards) 123 | -------------------------------------------------------------------------------- /examples/model_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Licensed under the Universal Permissive License v 1.0 as shown at 6 | # http://oss.oracle.com/licenses/upl. 7 | 8 | """ 9 | Extremely simple tensorflow graphpipe model server 10 | """ 11 | 12 | import argparse 13 | from http import server 14 | 15 | import numpy as np 16 | import tensorflow as tf 17 | 18 | from graphpipe import convert 19 | from graphpipe.graphpipefb.Type import Type 20 | 21 | 22 | def serve(host, port, model): 23 | with tf.Graph().as_default() as graph: 24 | graph_def = tf.GraphDef() 25 | with tf.gfile.GFile(model, "rb") as f: 26 | graph_def.ParseFromString(f.read()) 27 | tf.import_graph_def(graph_def) 28 | g = graph 29 | 30 | inputs = [] 31 | outputs = [] 32 | ops = g.get_operations() 33 | for op in ops: 34 | for tensor in op.outputs: 35 | shape = tensor.get_shape() 36 | if shape._dims is None: 37 | shape = [] 38 | else: 39 | shape = [-1 if x is None else x for x in shape.as_list()] 40 | try: 41 | typ = convert.to_type(tensor.dtype.as_numpy_dtype) 42 | except KeyError: 43 | typ = Type.Null 44 | t = { 45 | "name": tensor.name, 46 | "shape": shape, 47 | "type": typ, 48 | } 49 | inputs.append(t) 50 | outputs.append(t) 51 | 52 | metadata = { 53 | "name": model, 54 | "version": "1.2", 55 | "server": "example python model server", 56 | "inputs": inputs, 57 | "outputs": outputs, 58 | } 59 | 60 | 61 | class MyHandler(server.BaseHTTPRequestHandler): 62 | def do_POST(self): 63 | req_enc = self.rfile.read(int(self.headers['Content-Length'])) 64 | 65 | req = convert.deserialize_request(req_enc) 66 | if req is None: 67 | # Return metadata response 68 | output_enc = convert.serialize_metadata_response(metadata) 69 | else: 70 | feed_dict = {} 71 | y = [] 72 | if req.input_names == []: 73 | req.input_names = [b""] 74 | if req.output_names == []: 75 | req.output_names = [b""] 76 | for name in req.output_names: 77 | name = name.decode() 78 | # default output_name to the last op 79 | if name == "": 80 | name = ops[-1].name 81 | if ':' not in name: 82 | name += ':0' 83 | y.append(g.get_tensor_by_name(name)) 84 | if not y: 85 | y = [g.get_operations()[-1].outputs[0]] 86 | for i, t in enumerate(req.input_tensors): 87 | name = req.input_names[i].decode() 88 | # default input name to the first op 89 | if name == "": 90 | name = ops[i].name 91 | if ':' not in name: 92 | name += ':0' 93 | x = g.get_tensor_by_name(name) 94 | feed_dict[x] = t 95 | outputs = sess.run(y, feed_dict=feed_dict) 96 | output_enc = convert.serialize_infer_response(outputs) 97 | 98 | self.send_response(200) 99 | self.end_headers() 100 | self.wfile.write(output_enc) 101 | 102 | server_address = (host, port) 103 | httpd = server.HTTPServer(server_address, MyHandler) 104 | 105 | config = tf.ConfigProto() 106 | config.gpu_options.allow_growth = True 107 | with tf.Session(graph=g, config=config) as sess: 108 | print('Starting httpd on %s:%d...' % (host, port)) 109 | httpd.serve_forever() 110 | 111 | 112 | 113 | if __name__ == "__main__": 114 | # Parse CLI args 115 | parser = argparse.ArgumentParser() 116 | parser.add_argument("--host", default='', help="Serving host/ip") 117 | parser.add_argument("--port", default=9000, help="Serving port", type=int) 118 | parser.add_argument("--model", required=True, help="Model file (.pb)") 119 | args = parser.parse_args() 120 | serve(args.host, args.port, args.model) 121 | 122 | -------------------------------------------------------------------------------- /remote_op/remote_op.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 2 | // 3 | // Licensed under the Universal Permissive License v 1.0 as shown at 4 | // http://oss.oracle.com/licenses/upl. 5 | 6 | #include 7 | 8 | #include "tensorflow/core/framework/op.h" 9 | #include "tensorflow/core/framework/op_kernel.h" 10 | #include "tensorflow/core/framework/common_shape_fns.h" 11 | #include "flatbuffers/flatbuffers.h" 12 | #include "graphpipe_generated.h" 13 | 14 | using namespace tensorflow; 15 | using graphpipe::CreateInferRequest; 16 | using graphpipe::Req_InferRequest; 17 | using graphpipe::CreateRequest; 18 | using graphpipe::CreateTensor; 19 | using graphpipe::InferResponse; 20 | 21 | REGISTER_OP("Remote") 22 | .Input("uri: string") 23 | .Input("config: string") 24 | .Input("inputs: input_types") 25 | .Input("input_names: string") 26 | .Input("output_names: string") 27 | .Output("outputs: output_types") 28 | .Attr("input_types: list(type) >= 0") 29 | .Attr("output_types: list(type) >= 1") 30 | .Attr("output_shapes: list(shape) >= 1") 31 | .SetShapeFn([](shape_inference::InferenceContext* c) { 32 | shape_inference::ShapeHandle unused; 33 | TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); 34 | std::vector output_shapes; 35 | TF_RETURN_IF_ERROR(c->GetAttr("output_shapes", &output_shapes)); 36 | if (output_shapes.size() != c->num_outputs()) { 37 | return errors::InvalidArgument( 38 | "`output_shapes` must be the same length as `output_types` (", 39 | output_shapes.size(), " vs. ", c->num_outputs()); 40 | } 41 | for (size_t i = 0; i < output_shapes.size(); ++i) { 42 | shape_inference::ShapeHandle output_shape_handle; 43 | TF_RETURN_IF_ERROR(c->MakeShapeFromPartialTensorShape( 44 | output_shapes[i], &output_shape_handle)); 45 | c->set_output(static_cast(i), output_shape_handle); 46 | } 47 | return Status::OK(); 48 | }) 49 | .Doc(R"doc( 50 | Execute a remote model. 51 | )doc"); 52 | 53 | 54 | struct Reader { 55 | const char * pos; 56 | const char * end; 57 | }; 58 | 59 | static size_t ReadCallback(void *dest, size_t size, size_t nmemb, void *userp) 60 | { 61 | auto r = (Reader*)userp; 62 | size_t to_read = std::min(size * nmemb, (size_t)(r->end - r->pos)); 63 | if (to_read) { 64 | memcpy(dest, r->pos, to_read); 65 | r->pos += to_read; 66 | } 67 | return to_read; 68 | } 69 | 70 | static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) 71 | { 72 | ((std::string*)userp)->append((char*)contents, size * nmemb); 73 | return size * nmemb; 74 | } 75 | 76 | static constexpr graphpipe::Type conv2flat[] = { 77 | graphpipe::Type_Null, // DT_INVALID = 0; 78 | graphpipe::Type_Float32, // DT_FLOAT = 1; 79 | graphpipe::Type_Float64, // DT_DOUBLE = 2; 80 | graphpipe::Type_Int32, // DT_INT32 = 3; 81 | graphpipe::Type_Uint8, // DT_UINT8 = 4; 82 | graphpipe::Type_Int16, // DT_INT16 = 5; 83 | graphpipe::Type_Int8, // DT_INT8 = 6; 84 | graphpipe::Type_String, // DT_STRING = 7; 85 | graphpipe::Type_Null, // DT_COMPLEX64 = 8; // Single-precision complex 86 | graphpipe::Type_Int64, // DT_INT64 = 9; 87 | graphpipe::Type_Null, // DT_BOOL = 10; 88 | graphpipe::Type_Null, // DT_QINT8 = 11; // Quantized int8 89 | graphpipe::Type_Null, // DT_QUINT8 = 12; // Quantized uint8 90 | graphpipe::Type_Null, // DT_QINT32 = 13; // Quantized int32 91 | graphpipe::Type_Null, // DT_BFLOAT16 = 14; // Float32 truncated to 16 bits. Only for cast ops. 92 | graphpipe::Type_Null, // DT_QINT16 = 15; // Quantized int16 93 | graphpipe::Type_Null, // DT_QUINT16 = 16; // Quantized uint16 94 | graphpipe::Type_Uint16, // DT_UINT16 = 17; 95 | graphpipe::Type_Null, // DT_COMPLEX128 = 18; // Double-precision complex 96 | graphpipe::Type_Float16, // DT_HALF = 19; 97 | graphpipe::Type_Null, // DT_RESOURCE = 20; 98 | graphpipe::Type_Null, // DT_VARIANT = 21; // Arbitrary C++ data types 99 | graphpipe::Type_Uint32, // DT_UINT32 = 22; 100 | graphpipe::Type_Uint64, // DT_UINT64 = 23; 101 | }; 102 | 103 | static constexpr DataType conv2tf[] = { 104 | DT_INVALID, // Type_Null = 0, 105 | DT_UINT8, // Type_Uint8 = 1, 106 | DT_INT8, // Type_Int8 = 2, 107 | DT_UINT16, // Type_Uint16 = 3, 108 | DT_INT16, // Type_Int16 = 4, 109 | DT_UINT32, // Type_Uint32 = 5, 110 | DT_INT32, // Type_Int32 = 6, 111 | DT_UINT64, // Type_Uint64 = 7, 112 | DT_INT64, // Type_Int64 = 8, 113 | DT_HALF, // Type_Float16 = 9, 114 | DT_FLOAT, // Type_Float32 = 10, 115 | DT_DOUBLE, // Type_Float64 = 11, 116 | DT_STRING, // Type_String = 12, 117 | }; 118 | 119 | inline graphpipe::Type to_flat_dtype(DataType dt) { 120 | return conv2flat[dt]; 121 | } 122 | 123 | inline DataType to_tf_dtype(graphpipe::Type dt) { 124 | return conv2tf[dt]; 125 | } 126 | 127 | flatbuffers::Offset to_flat(flatbuffers::FlatBufferBuilder &builder, const Tensor *tensor) { 128 | std::vector s; 129 | for (int d = 0; d < tensor->dims(); d++) { 130 | s.push_back(tensor->dim_size(d)); 131 | } 132 | auto shape = builder.CreateVector(s); 133 | auto type = to_flat_dtype(tensor->dtype()); 134 | 135 | flatbuffers::Offset> data = 0; 136 | flatbuffers::Offset>> string_val = 0; 137 | if (type == graphpipe::Type_String) { 138 | auto num_vals = tensor->NumElements(); 139 | auto vals = tensor->flat(); 140 | std::vector valvec; 141 | for (int i = 0; i < num_vals; ++i) { 142 | valvec.push_back(vals(i)); 143 | } 144 | string_val = builder.CreateVectorOfStrings(valvec); 145 | } else { 146 | data = builder.CreateVector((const uint8_t*)tensor->tensor_data().data(), tensor->tensor_data().size()); 147 | } 148 | return CreateTensor(builder, type, shape, data, string_val); 149 | } 150 | 151 | bool from_flat(Tensor *tensor, const graphpipe::Tensor *flat_tensor) { 152 | TensorShape shape; 153 | for (int i = 0; i < flat_tensor->shape()->Length(); ++i) { 154 | shape.AddDim(flat_tensor->shape()->Get(i)); 155 | } 156 | auto type = to_tf_dtype(flat_tensor->type()); 157 | *tensor = Tensor(type, shape); 158 | if (type == DT_STRING) { 159 | auto dstarray = tensor->flat(); 160 | for (int i = 0; i < flat_tensor->string_val()->Length(); ++i) { 161 | dstarray(i).assign(flat_tensor->string_val()->Get(i)->c_str()); 162 | } 163 | } else { 164 | memcpy((void *)tensor->tensor_data().data(), flat_tensor->data()->data(), tensor->tensor_data().size()); 165 | } 166 | return true; 167 | } 168 | 169 | class RemoteOp : public OpKernel { 170 | public: 171 | explicit RemoteOp(OpKernelConstruction* context) : OpKernel(context) {} 172 | 173 | void Compute(OpKernelContext* context) override { 174 | const Tensor* tmp; 175 | OP_REQUIRES_OK(context, context->input("uri", &tmp)); 176 | const string uri = tmp->scalar()(); 177 | OP_REQUIRES_OK(context, context->input("config", &tmp)); 178 | const string config = tmp->scalar()(); 179 | OP_REQUIRES_OK(context, context->input("input_names", &tmp)); 180 | int num_inputs = tmp->NumElements(); 181 | auto input_names = tmp->flat(); 182 | OP_REQUIRES_OK(context, context->input("output_names", &tmp)); 183 | int num_outputs = tmp->NumElements(); 184 | auto output_names = tmp->flat(); 185 | 186 | flatbuffers::FlatBufferBuilder builder(1024); 187 | 188 | int start, stop; 189 | context->op_kernel().InputRange("inputs", &start, &stop); 190 | std::vector> inputs_vector; 191 | for (int i = start; i < stop; ++i) { 192 | inputs_vector.push_back(to_flat(builder, &context->input(i))); 193 | } 194 | 195 | std::vector invec; 196 | std::vector outvec; 197 | for (int i = 0; i < num_inputs; ++i) { 198 | invec.push_back(input_names(i)); 199 | } 200 | for (int i = 0; i < num_outputs; ++i) { 201 | outvec.push_back(output_names(i)); 202 | } 203 | auto inputs = builder.CreateVector(inputs_vector); 204 | auto inp = builder.CreateVectorOfStrings(invec); 205 | auto outp = builder.CreateVectorOfStrings(outvec); 206 | auto conf = builder.CreateString(config); 207 | auto infer_req = CreateInferRequest(builder, conf, inp, inputs, outp); 208 | auto req = CreateRequest(builder, Req_InferRequest, infer_req.Union()); 209 | builder.Finish(req); 210 | const char *buf = (const char *)builder.GetBufferPointer(); 211 | int size = builder.GetSize(); 212 | 213 | std::string out; 214 | 215 | CURL *curl; 216 | CURLcode response; 217 | long http_code = 0; 218 | 219 | curl_global_init(CURL_GLOBAL_ALL); 220 | curl = curl_easy_init(); 221 | if(curl) { 222 | curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); 223 | curl_easy_setopt(curl, CURLOPT_POST, 1); 224 | Reader r = Reader{buf, buf + size}; 225 | curl_easy_setopt(curl, CURLOPT_READDATA, &r); 226 | curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadCallback); 227 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); 228 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); 229 | std::ostringstream clen; 230 | clen << "Content-Length: " << size; 231 | struct curl_slist *headerlist = NULL; 232 | headerlist = curl_slist_append(headerlist, clen.str().c_str()); 233 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); 234 | response = curl_easy_perform(curl); 235 | if (response != CURLE_OK) { 236 | LOG(ERROR) << "curl error: " << curl_easy_strerror(response); 237 | } 238 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); 239 | curl_easy_cleanup(curl); 240 | } 241 | curl_global_cleanup(); 242 | if (http_code != 200) { 243 | LOG(ERROR) << "Request failed with code " << http_code << ": " << out; 244 | return; 245 | } 246 | 247 | auto res = flatbuffers::GetRoot(out.c_str()); 248 | // iterate through res->output_tensors() and convert 249 | auto output_tensors = res->output_tensors(); 250 | for (int i = 0; i < output_tensors->Length(); ++i) { 251 | Tensor tensor; 252 | if (!from_flat(&tensor, output_tensors->Get(i))) { 253 | LOG(ERROR) << "Tensor parsing error"; 254 | return; 255 | } 256 | context->set_output(i, tensor); 257 | } 258 | } 259 | }; 260 | 261 | REGISTER_KERNEL_BUILDER(Name("Remote").Device(DEVICE_CPU), RemoteOp); 262 | -------------------------------------------------------------------------------- /remote_op/graphpipe/cpp/graphpipe_generated.h: -------------------------------------------------------------------------------- 1 | // automatically generated by the FlatBuffers compiler, do not modify 2 | 3 | 4 | #ifndef FLATBUFFERS_GENERATED_MUGATU_MUGATU_H_ 5 | #define FLATBUFFERS_GENERATED_MUGATU_MUGATU_H_ 6 | 7 | #include "flatbuffers/flatbuffers.h" 8 | 9 | namespace graphpipe { 10 | 11 | struct Tensor; 12 | 13 | struct Request; 14 | 15 | struct InferRequest; 16 | 17 | struct Error; 18 | 19 | struct InferResponse; 20 | 21 | struct MetadataRequest; 22 | 23 | struct IOMetadata; 24 | 25 | struct MetadataResponse; 26 | 27 | enum Type { 28 | Type_Null = 0, 29 | Type_Uint8 = 1, 30 | Type_Int8 = 2, 31 | Type_Uint16 = 3, 32 | Type_Int16 = 4, 33 | Type_Uint32 = 5, 34 | Type_Int32 = 6, 35 | Type_Uint64 = 7, 36 | Type_Int64 = 8, 37 | Type_Float16 = 9, 38 | Type_Float32 = 10, 39 | Type_Float64 = 11, 40 | Type_String = 12, 41 | Type_MIN = Type_Null, 42 | Type_MAX = Type_String 43 | }; 44 | 45 | inline Type (&EnumValuesType())[13] { 46 | static Type values[] = { 47 | Type_Null, 48 | Type_Uint8, 49 | Type_Int8, 50 | Type_Uint16, 51 | Type_Int16, 52 | Type_Uint32, 53 | Type_Int32, 54 | Type_Uint64, 55 | Type_Int64, 56 | Type_Float16, 57 | Type_Float32, 58 | Type_Float64, 59 | Type_String 60 | }; 61 | return values; 62 | } 63 | 64 | inline const char **EnumNamesType() { 65 | static const char *names[] = { 66 | "Null", 67 | "Uint8", 68 | "Int8", 69 | "Uint16", 70 | "Int16", 71 | "Uint32", 72 | "Int32", 73 | "Uint64", 74 | "Int64", 75 | "Float16", 76 | "Float32", 77 | "Float64", 78 | "String", 79 | nullptr 80 | }; 81 | return names; 82 | } 83 | 84 | inline const char *EnumNameType(Type e) { 85 | const size_t index = static_cast(e); 86 | return EnumNamesType()[index]; 87 | } 88 | 89 | enum Req { 90 | Req_NONE = 0, 91 | Req_InferRequest = 1, 92 | Req_MetadataRequest = 2, 93 | Req_MIN = Req_NONE, 94 | Req_MAX = Req_MetadataRequest 95 | }; 96 | 97 | inline Req (&EnumValuesReq())[3] { 98 | static Req values[] = { 99 | Req_NONE, 100 | Req_InferRequest, 101 | Req_MetadataRequest 102 | }; 103 | return values; 104 | } 105 | 106 | inline const char **EnumNamesReq() { 107 | static const char *names[] = { 108 | "NONE", 109 | "InferRequest", 110 | "MetadataRequest", 111 | nullptr 112 | }; 113 | return names; 114 | } 115 | 116 | inline const char *EnumNameReq(Req e) { 117 | const size_t index = static_cast(e); 118 | return EnumNamesReq()[index]; 119 | } 120 | 121 | template struct ReqTraits { 122 | static const Req enum_value = Req_NONE; 123 | }; 124 | 125 | template<> struct ReqTraits { 126 | static const Req enum_value = Req_InferRequest; 127 | }; 128 | 129 | template<> struct ReqTraits { 130 | static const Req enum_value = Req_MetadataRequest; 131 | }; 132 | 133 | bool VerifyReq(flatbuffers::Verifier &verifier, const void *obj, Req type); 134 | bool VerifyReqVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); 135 | 136 | struct Tensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { 137 | enum { 138 | VT_TYPE = 4, 139 | VT_SHAPE = 6, 140 | VT_DATA = 8, 141 | VT_STRING_VAL = 10 142 | }; 143 | Type type() const { 144 | return static_cast(GetField(VT_TYPE, 0)); 145 | } 146 | const flatbuffers::Vector *shape() const { 147 | return GetPointer *>(VT_SHAPE); 148 | } 149 | const flatbuffers::Vector *data() const { 150 | return GetPointer *>(VT_DATA); 151 | } 152 | const flatbuffers::Vector> *string_val() const { 153 | return GetPointer> *>(VT_STRING_VAL); 154 | } 155 | bool Verify(flatbuffers::Verifier &verifier) const { 156 | return VerifyTableStart(verifier) && 157 | VerifyField(verifier, VT_TYPE) && 158 | VerifyOffset(verifier, VT_SHAPE) && 159 | verifier.Verify(shape()) && 160 | VerifyOffset(verifier, VT_DATA) && 161 | verifier.Verify(data()) && 162 | VerifyOffset(verifier, VT_STRING_VAL) && 163 | verifier.Verify(string_val()) && 164 | verifier.VerifyVectorOfStrings(string_val()) && 165 | verifier.EndTable(); 166 | } 167 | }; 168 | 169 | struct TensorBuilder { 170 | flatbuffers::FlatBufferBuilder &fbb_; 171 | flatbuffers::uoffset_t start_; 172 | void add_type(Type type) { 173 | fbb_.AddElement(Tensor::VT_TYPE, static_cast(type), 0); 174 | } 175 | void add_shape(flatbuffers::Offset> shape) { 176 | fbb_.AddOffset(Tensor::VT_SHAPE, shape); 177 | } 178 | void add_data(flatbuffers::Offset> data) { 179 | fbb_.AddOffset(Tensor::VT_DATA, data); 180 | } 181 | void add_string_val(flatbuffers::Offset>> string_val) { 182 | fbb_.AddOffset(Tensor::VT_STRING_VAL, string_val); 183 | } 184 | explicit TensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) 185 | : fbb_(_fbb) { 186 | start_ = fbb_.StartTable(); 187 | } 188 | TensorBuilder &operator=(const TensorBuilder &); 189 | flatbuffers::Offset Finish() { 190 | const auto end = fbb_.EndTable(start_); 191 | auto o = flatbuffers::Offset(end); 192 | return o; 193 | } 194 | }; 195 | 196 | inline flatbuffers::Offset CreateTensor( 197 | flatbuffers::FlatBufferBuilder &_fbb, 198 | Type type = Type_Null, 199 | flatbuffers::Offset> shape = 0, 200 | flatbuffers::Offset> data = 0, 201 | flatbuffers::Offset>> string_val = 0) { 202 | TensorBuilder builder_(_fbb); 203 | builder_.add_string_val(string_val); 204 | builder_.add_data(data); 205 | builder_.add_shape(shape); 206 | builder_.add_type(type); 207 | return builder_.Finish(); 208 | } 209 | 210 | inline flatbuffers::Offset CreateTensorDirect( 211 | flatbuffers::FlatBufferBuilder &_fbb, 212 | Type type = Type_Null, 213 | const std::vector *shape = nullptr, 214 | const std::vector *data = nullptr, 215 | const std::vector> *string_val = nullptr) { 216 | return graphpipe::CreateTensor( 217 | _fbb, 218 | type, 219 | shape ? _fbb.CreateVector(*shape) : 0, 220 | data ? _fbb.CreateVector(*data) : 0, 221 | string_val ? _fbb.CreateVector>(*string_val) : 0); 222 | } 223 | 224 | struct Request FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { 225 | enum { 226 | VT_REQ_TYPE = 4, 227 | VT_REQ = 6 228 | }; 229 | Req req_type() const { 230 | return static_cast(GetField(VT_REQ_TYPE, 0)); 231 | } 232 | const void *req() const { 233 | return GetPointer(VT_REQ); 234 | } 235 | template const T *req_as() const; 236 | const InferRequest *req_as_InferRequest() const { 237 | return req_type() == Req_InferRequest ? static_cast(req()) : nullptr; 238 | } 239 | const MetadataRequest *req_as_MetadataRequest() const { 240 | return req_type() == Req_MetadataRequest ? static_cast(req()) : nullptr; 241 | } 242 | bool Verify(flatbuffers::Verifier &verifier) const { 243 | return VerifyTableStart(verifier) && 244 | VerifyField(verifier, VT_REQ_TYPE) && 245 | VerifyOffset(verifier, VT_REQ) && 246 | VerifyReq(verifier, req(), req_type()) && 247 | verifier.EndTable(); 248 | } 249 | }; 250 | 251 | template<> inline const InferRequest *Request::req_as() const { 252 | return req_as_InferRequest(); 253 | } 254 | 255 | template<> inline const MetadataRequest *Request::req_as() const { 256 | return req_as_MetadataRequest(); 257 | } 258 | 259 | struct RequestBuilder { 260 | flatbuffers::FlatBufferBuilder &fbb_; 261 | flatbuffers::uoffset_t start_; 262 | void add_req_type(Req req_type) { 263 | fbb_.AddElement(Request::VT_REQ_TYPE, static_cast(req_type), 0); 264 | } 265 | void add_req(flatbuffers::Offset req) { 266 | fbb_.AddOffset(Request::VT_REQ, req); 267 | } 268 | explicit RequestBuilder(flatbuffers::FlatBufferBuilder &_fbb) 269 | : fbb_(_fbb) { 270 | start_ = fbb_.StartTable(); 271 | } 272 | RequestBuilder &operator=(const RequestBuilder &); 273 | flatbuffers::Offset Finish() { 274 | const auto end = fbb_.EndTable(start_); 275 | auto o = flatbuffers::Offset(end); 276 | return o; 277 | } 278 | }; 279 | 280 | inline flatbuffers::Offset CreateRequest( 281 | flatbuffers::FlatBufferBuilder &_fbb, 282 | Req req_type = Req_NONE, 283 | flatbuffers::Offset req = 0) { 284 | RequestBuilder builder_(_fbb); 285 | builder_.add_req(req); 286 | builder_.add_req_type(req_type); 287 | return builder_.Finish(); 288 | } 289 | 290 | struct InferRequest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { 291 | enum { 292 | VT_CONFIG = 4, 293 | VT_INPUT_NAMES = 6, 294 | VT_INPUT_TENSORS = 8, 295 | VT_OUTPUT_NAMES = 10 296 | }; 297 | const flatbuffers::String *config() const { 298 | return GetPointer(VT_CONFIG); 299 | } 300 | const flatbuffers::Vector> *input_names() const { 301 | return GetPointer> *>(VT_INPUT_NAMES); 302 | } 303 | const flatbuffers::Vector> *input_tensors() const { 304 | return GetPointer> *>(VT_INPUT_TENSORS); 305 | } 306 | const flatbuffers::Vector> *output_names() const { 307 | return GetPointer> *>(VT_OUTPUT_NAMES); 308 | } 309 | bool Verify(flatbuffers::Verifier &verifier) const { 310 | return VerifyTableStart(verifier) && 311 | VerifyOffset(verifier, VT_CONFIG) && 312 | verifier.Verify(config()) && 313 | VerifyOffset(verifier, VT_INPUT_NAMES) && 314 | verifier.Verify(input_names()) && 315 | verifier.VerifyVectorOfStrings(input_names()) && 316 | VerifyOffset(verifier, VT_INPUT_TENSORS) && 317 | verifier.Verify(input_tensors()) && 318 | verifier.VerifyVectorOfTables(input_tensors()) && 319 | VerifyOffset(verifier, VT_OUTPUT_NAMES) && 320 | verifier.Verify(output_names()) && 321 | verifier.VerifyVectorOfStrings(output_names()) && 322 | verifier.EndTable(); 323 | } 324 | }; 325 | 326 | struct InferRequestBuilder { 327 | flatbuffers::FlatBufferBuilder &fbb_; 328 | flatbuffers::uoffset_t start_; 329 | void add_config(flatbuffers::Offset config) { 330 | fbb_.AddOffset(InferRequest::VT_CONFIG, config); 331 | } 332 | void add_input_names(flatbuffers::Offset>> input_names) { 333 | fbb_.AddOffset(InferRequest::VT_INPUT_NAMES, input_names); 334 | } 335 | void add_input_tensors(flatbuffers::Offset>> input_tensors) { 336 | fbb_.AddOffset(InferRequest::VT_INPUT_TENSORS, input_tensors); 337 | } 338 | void add_output_names(flatbuffers::Offset>> output_names) { 339 | fbb_.AddOffset(InferRequest::VT_OUTPUT_NAMES, output_names); 340 | } 341 | explicit InferRequestBuilder(flatbuffers::FlatBufferBuilder &_fbb) 342 | : fbb_(_fbb) { 343 | start_ = fbb_.StartTable(); 344 | } 345 | InferRequestBuilder &operator=(const InferRequestBuilder &); 346 | flatbuffers::Offset Finish() { 347 | const auto end = fbb_.EndTable(start_); 348 | auto o = flatbuffers::Offset(end); 349 | return o; 350 | } 351 | }; 352 | 353 | inline flatbuffers::Offset CreateInferRequest( 354 | flatbuffers::FlatBufferBuilder &_fbb, 355 | flatbuffers::Offset config = 0, 356 | flatbuffers::Offset>> input_names = 0, 357 | flatbuffers::Offset>> input_tensors = 0, 358 | flatbuffers::Offset>> output_names = 0) { 359 | InferRequestBuilder builder_(_fbb); 360 | builder_.add_output_names(output_names); 361 | builder_.add_input_tensors(input_tensors); 362 | builder_.add_input_names(input_names); 363 | builder_.add_config(config); 364 | return builder_.Finish(); 365 | } 366 | 367 | inline flatbuffers::Offset CreateInferRequestDirect( 368 | flatbuffers::FlatBufferBuilder &_fbb, 369 | const char *config = nullptr, 370 | const std::vector> *input_names = nullptr, 371 | const std::vector> *input_tensors = nullptr, 372 | const std::vector> *output_names = nullptr) { 373 | return graphpipe::CreateInferRequest( 374 | _fbb, 375 | config ? _fbb.CreateString(config) : 0, 376 | input_names ? _fbb.CreateVector>(*input_names) : 0, 377 | input_tensors ? _fbb.CreateVector>(*input_tensors) : 0, 378 | output_names ? _fbb.CreateVector>(*output_names) : 0); 379 | } 380 | 381 | struct Error FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { 382 | enum { 383 | VT_CODE = 4, 384 | VT_MESSAGE = 6 385 | }; 386 | int64_t code() const { 387 | return GetField(VT_CODE, 0); 388 | } 389 | const flatbuffers::String *message() const { 390 | return GetPointer(VT_MESSAGE); 391 | } 392 | bool Verify(flatbuffers::Verifier &verifier) const { 393 | return VerifyTableStart(verifier) && 394 | VerifyField(verifier, VT_CODE) && 395 | VerifyOffset(verifier, VT_MESSAGE) && 396 | verifier.Verify(message()) && 397 | verifier.EndTable(); 398 | } 399 | }; 400 | 401 | struct ErrorBuilder { 402 | flatbuffers::FlatBufferBuilder &fbb_; 403 | flatbuffers::uoffset_t start_; 404 | void add_code(int64_t code) { 405 | fbb_.AddElement(Error::VT_CODE, code, 0); 406 | } 407 | void add_message(flatbuffers::Offset message) { 408 | fbb_.AddOffset(Error::VT_MESSAGE, message); 409 | } 410 | explicit ErrorBuilder(flatbuffers::FlatBufferBuilder &_fbb) 411 | : fbb_(_fbb) { 412 | start_ = fbb_.StartTable(); 413 | } 414 | ErrorBuilder &operator=(const ErrorBuilder &); 415 | flatbuffers::Offset Finish() { 416 | const auto end = fbb_.EndTable(start_); 417 | auto o = flatbuffers::Offset(end); 418 | return o; 419 | } 420 | }; 421 | 422 | inline flatbuffers::Offset CreateError( 423 | flatbuffers::FlatBufferBuilder &_fbb, 424 | int64_t code = 0, 425 | flatbuffers::Offset message = 0) { 426 | ErrorBuilder builder_(_fbb); 427 | builder_.add_code(code); 428 | builder_.add_message(message); 429 | return builder_.Finish(); 430 | } 431 | 432 | inline flatbuffers::Offset CreateErrorDirect( 433 | flatbuffers::FlatBufferBuilder &_fbb, 434 | int64_t code = 0, 435 | const char *message = nullptr) { 436 | return graphpipe::CreateError( 437 | _fbb, 438 | code, 439 | message ? _fbb.CreateString(message) : 0); 440 | } 441 | 442 | struct InferResponse FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { 443 | enum { 444 | VT_OUTPUT_TENSORS = 4, 445 | VT_ERRORS = 6 446 | }; 447 | const flatbuffers::Vector> *output_tensors() const { 448 | return GetPointer> *>(VT_OUTPUT_TENSORS); 449 | } 450 | const flatbuffers::Vector> *errors() const { 451 | return GetPointer> *>(VT_ERRORS); 452 | } 453 | bool Verify(flatbuffers::Verifier &verifier) const { 454 | return VerifyTableStart(verifier) && 455 | VerifyOffset(verifier, VT_OUTPUT_TENSORS) && 456 | verifier.Verify(output_tensors()) && 457 | verifier.VerifyVectorOfTables(output_tensors()) && 458 | VerifyOffset(verifier, VT_ERRORS) && 459 | verifier.Verify(errors()) && 460 | verifier.VerifyVectorOfTables(errors()) && 461 | verifier.EndTable(); 462 | } 463 | }; 464 | 465 | struct InferResponseBuilder { 466 | flatbuffers::FlatBufferBuilder &fbb_; 467 | flatbuffers::uoffset_t start_; 468 | void add_output_tensors(flatbuffers::Offset>> output_tensors) { 469 | fbb_.AddOffset(InferResponse::VT_OUTPUT_TENSORS, output_tensors); 470 | } 471 | void add_errors(flatbuffers::Offset>> errors) { 472 | fbb_.AddOffset(InferResponse::VT_ERRORS, errors); 473 | } 474 | explicit InferResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb) 475 | : fbb_(_fbb) { 476 | start_ = fbb_.StartTable(); 477 | } 478 | InferResponseBuilder &operator=(const InferResponseBuilder &); 479 | flatbuffers::Offset Finish() { 480 | const auto end = fbb_.EndTable(start_); 481 | auto o = flatbuffers::Offset(end); 482 | return o; 483 | } 484 | }; 485 | 486 | inline flatbuffers::Offset CreateInferResponse( 487 | flatbuffers::FlatBufferBuilder &_fbb, 488 | flatbuffers::Offset>> output_tensors = 0, 489 | flatbuffers::Offset>> errors = 0) { 490 | InferResponseBuilder builder_(_fbb); 491 | builder_.add_errors(errors); 492 | builder_.add_output_tensors(output_tensors); 493 | return builder_.Finish(); 494 | } 495 | 496 | inline flatbuffers::Offset CreateInferResponseDirect( 497 | flatbuffers::FlatBufferBuilder &_fbb, 498 | const std::vector> *output_tensors = nullptr, 499 | const std::vector> *errors = nullptr) { 500 | return graphpipe::CreateInferResponse( 501 | _fbb, 502 | output_tensors ? _fbb.CreateVector>(*output_tensors) : 0, 503 | errors ? _fbb.CreateVector>(*errors) : 0); 504 | } 505 | 506 | struct MetadataRequest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { 507 | bool Verify(flatbuffers::Verifier &verifier) const { 508 | return VerifyTableStart(verifier) && 509 | verifier.EndTable(); 510 | } 511 | }; 512 | 513 | struct MetadataRequestBuilder { 514 | flatbuffers::FlatBufferBuilder &fbb_; 515 | flatbuffers::uoffset_t start_; 516 | explicit MetadataRequestBuilder(flatbuffers::FlatBufferBuilder &_fbb) 517 | : fbb_(_fbb) { 518 | start_ = fbb_.StartTable(); 519 | } 520 | MetadataRequestBuilder &operator=(const MetadataRequestBuilder &); 521 | flatbuffers::Offset Finish() { 522 | const auto end = fbb_.EndTable(start_); 523 | auto o = flatbuffers::Offset(end); 524 | return o; 525 | } 526 | }; 527 | 528 | inline flatbuffers::Offset CreateMetadataRequest( 529 | flatbuffers::FlatBufferBuilder &_fbb) { 530 | MetadataRequestBuilder builder_(_fbb); 531 | return builder_.Finish(); 532 | } 533 | 534 | struct IOMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { 535 | enum { 536 | VT_NAME = 4, 537 | VT_DESCRIPTION = 6, 538 | VT_SHAPE = 8, 539 | VT_TYPE = 10 540 | }; 541 | const flatbuffers::String *name() const { 542 | return GetPointer(VT_NAME); 543 | } 544 | const flatbuffers::String *description() const { 545 | return GetPointer(VT_DESCRIPTION); 546 | } 547 | const flatbuffers::Vector *shape() const { 548 | return GetPointer *>(VT_SHAPE); 549 | } 550 | Type type() const { 551 | return static_cast(GetField(VT_TYPE, 0)); 552 | } 553 | bool Verify(flatbuffers::Verifier &verifier) const { 554 | return VerifyTableStart(verifier) && 555 | VerifyOffset(verifier, VT_NAME) && 556 | verifier.Verify(name()) && 557 | VerifyOffset(verifier, VT_DESCRIPTION) && 558 | verifier.Verify(description()) && 559 | VerifyOffset(verifier, VT_SHAPE) && 560 | verifier.Verify(shape()) && 561 | VerifyField(verifier, VT_TYPE) && 562 | verifier.EndTable(); 563 | } 564 | }; 565 | 566 | struct IOMetadataBuilder { 567 | flatbuffers::FlatBufferBuilder &fbb_; 568 | flatbuffers::uoffset_t start_; 569 | void add_name(flatbuffers::Offset name) { 570 | fbb_.AddOffset(IOMetadata::VT_NAME, name); 571 | } 572 | void add_description(flatbuffers::Offset description) { 573 | fbb_.AddOffset(IOMetadata::VT_DESCRIPTION, description); 574 | } 575 | void add_shape(flatbuffers::Offset> shape) { 576 | fbb_.AddOffset(IOMetadata::VT_SHAPE, shape); 577 | } 578 | void add_type(Type type) { 579 | fbb_.AddElement(IOMetadata::VT_TYPE, static_cast(type), 0); 580 | } 581 | explicit IOMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) 582 | : fbb_(_fbb) { 583 | start_ = fbb_.StartTable(); 584 | } 585 | IOMetadataBuilder &operator=(const IOMetadataBuilder &); 586 | flatbuffers::Offset Finish() { 587 | const auto end = fbb_.EndTable(start_); 588 | auto o = flatbuffers::Offset(end); 589 | return o; 590 | } 591 | }; 592 | 593 | inline flatbuffers::Offset CreateIOMetadata( 594 | flatbuffers::FlatBufferBuilder &_fbb, 595 | flatbuffers::Offset name = 0, 596 | flatbuffers::Offset description = 0, 597 | flatbuffers::Offset> shape = 0, 598 | Type type = Type_Null) { 599 | IOMetadataBuilder builder_(_fbb); 600 | builder_.add_shape(shape); 601 | builder_.add_description(description); 602 | builder_.add_name(name); 603 | builder_.add_type(type); 604 | return builder_.Finish(); 605 | } 606 | 607 | inline flatbuffers::Offset CreateIOMetadataDirect( 608 | flatbuffers::FlatBufferBuilder &_fbb, 609 | const char *name = nullptr, 610 | const char *description = nullptr, 611 | const std::vector *shape = nullptr, 612 | Type type = Type_Null) { 613 | return graphpipe::CreateIOMetadata( 614 | _fbb, 615 | name ? _fbb.CreateString(name) : 0, 616 | description ? _fbb.CreateString(description) : 0, 617 | shape ? _fbb.CreateVector(*shape) : 0, 618 | type); 619 | } 620 | 621 | struct MetadataResponse FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { 622 | enum { 623 | VT_NAME = 4, 624 | VT_VERSION = 6, 625 | VT_SERVER = 8, 626 | VT_DESCRIPTION = 10, 627 | VT_INPUTS = 12, 628 | VT_OUTPUTS = 14 629 | }; 630 | const flatbuffers::String *name() const { 631 | return GetPointer(VT_NAME); 632 | } 633 | const flatbuffers::String *version() const { 634 | return GetPointer(VT_VERSION); 635 | } 636 | const flatbuffers::String *server() const { 637 | return GetPointer(VT_SERVER); 638 | } 639 | const flatbuffers::String *description() const { 640 | return GetPointer(VT_DESCRIPTION); 641 | } 642 | const flatbuffers::Vector> *inputs() const { 643 | return GetPointer> *>(VT_INPUTS); 644 | } 645 | const flatbuffers::Vector> *outputs() const { 646 | return GetPointer> *>(VT_OUTPUTS); 647 | } 648 | bool Verify(flatbuffers::Verifier &verifier) const { 649 | return VerifyTableStart(verifier) && 650 | VerifyOffset(verifier, VT_NAME) && 651 | verifier.Verify(name()) && 652 | VerifyOffset(verifier, VT_VERSION) && 653 | verifier.Verify(version()) && 654 | VerifyOffset(verifier, VT_SERVER) && 655 | verifier.Verify(server()) && 656 | VerifyOffset(verifier, VT_DESCRIPTION) && 657 | verifier.Verify(description()) && 658 | VerifyOffset(verifier, VT_INPUTS) && 659 | verifier.Verify(inputs()) && 660 | verifier.VerifyVectorOfTables(inputs()) && 661 | VerifyOffset(verifier, VT_OUTPUTS) && 662 | verifier.Verify(outputs()) && 663 | verifier.VerifyVectorOfTables(outputs()) && 664 | verifier.EndTable(); 665 | } 666 | }; 667 | 668 | struct MetadataResponseBuilder { 669 | flatbuffers::FlatBufferBuilder &fbb_; 670 | flatbuffers::uoffset_t start_; 671 | void add_name(flatbuffers::Offset name) { 672 | fbb_.AddOffset(MetadataResponse::VT_NAME, name); 673 | } 674 | void add_version(flatbuffers::Offset version) { 675 | fbb_.AddOffset(MetadataResponse::VT_VERSION, version); 676 | } 677 | void add_server(flatbuffers::Offset server) { 678 | fbb_.AddOffset(MetadataResponse::VT_SERVER, server); 679 | } 680 | void add_description(flatbuffers::Offset description) { 681 | fbb_.AddOffset(MetadataResponse::VT_DESCRIPTION, description); 682 | } 683 | void add_inputs(flatbuffers::Offset>> inputs) { 684 | fbb_.AddOffset(MetadataResponse::VT_INPUTS, inputs); 685 | } 686 | void add_outputs(flatbuffers::Offset>> outputs) { 687 | fbb_.AddOffset(MetadataResponse::VT_OUTPUTS, outputs); 688 | } 689 | explicit MetadataResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb) 690 | : fbb_(_fbb) { 691 | start_ = fbb_.StartTable(); 692 | } 693 | MetadataResponseBuilder &operator=(const MetadataResponseBuilder &); 694 | flatbuffers::Offset Finish() { 695 | const auto end = fbb_.EndTable(start_); 696 | auto o = flatbuffers::Offset(end); 697 | return o; 698 | } 699 | }; 700 | 701 | inline flatbuffers::Offset CreateMetadataResponse( 702 | flatbuffers::FlatBufferBuilder &_fbb, 703 | flatbuffers::Offset name = 0, 704 | flatbuffers::Offset version = 0, 705 | flatbuffers::Offset server = 0, 706 | flatbuffers::Offset description = 0, 707 | flatbuffers::Offset>> inputs = 0, 708 | flatbuffers::Offset>> outputs = 0) { 709 | MetadataResponseBuilder builder_(_fbb); 710 | builder_.add_outputs(outputs); 711 | builder_.add_inputs(inputs); 712 | builder_.add_description(description); 713 | builder_.add_server(server); 714 | builder_.add_version(version); 715 | builder_.add_name(name); 716 | return builder_.Finish(); 717 | } 718 | 719 | inline flatbuffers::Offset CreateMetadataResponseDirect( 720 | flatbuffers::FlatBufferBuilder &_fbb, 721 | const char *name = nullptr, 722 | const char *version = nullptr, 723 | const char *server = nullptr, 724 | const char *description = nullptr, 725 | const std::vector> *inputs = nullptr, 726 | const std::vector> *outputs = nullptr) { 727 | return graphpipe::CreateMetadataResponse( 728 | _fbb, 729 | name ? _fbb.CreateString(name) : 0, 730 | version ? _fbb.CreateString(version) : 0, 731 | server ? _fbb.CreateString(server) : 0, 732 | description ? _fbb.CreateString(description) : 0, 733 | inputs ? _fbb.CreateVector>(*inputs) : 0, 734 | outputs ? _fbb.CreateVector>(*outputs) : 0); 735 | } 736 | 737 | inline bool VerifyReq(flatbuffers::Verifier &verifier, const void *obj, Req type) { 738 | switch (type) { 739 | case Req_NONE: { 740 | return true; 741 | } 742 | case Req_InferRequest: { 743 | auto ptr = reinterpret_cast(obj); 744 | return verifier.VerifyTable(ptr); 745 | } 746 | case Req_MetadataRequest: { 747 | auto ptr = reinterpret_cast(obj); 748 | return verifier.VerifyTable(ptr); 749 | } 750 | default: return false; 751 | } 752 | } 753 | 754 | inline bool VerifyReqVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types) { 755 | if (values->size() != types->size()) return false; 756 | for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { 757 | if (!VerifyReq( 758 | verifier, values->Get(i), types->GetEnum(i))) { 759 | return false; 760 | } 761 | } 762 | return true; 763 | } 764 | 765 | inline const graphpipe::Request *GetRequest(const void *buf) { 766 | return flatbuffers::GetRoot(buf); 767 | } 768 | 769 | inline bool VerifyRequestBuffer( 770 | flatbuffers::Verifier &verifier) { 771 | return verifier.VerifyBuffer(nullptr); 772 | } 773 | 774 | inline void FinishRequestBuffer( 775 | flatbuffers::FlatBufferBuilder &fbb, 776 | flatbuffers::Offset root) { 777 | fbb.Finish(root); 778 | } 779 | 780 | } // namespace graphpipe 781 | 782 | #endif // FLATBUFFERS_GENERATED_MUGATU_MUGATU_H_ 783 | -------------------------------------------------------------------------------- /examples/RemoteModelWithGraphPipe.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.\n", 8 | "\n", 9 | "### Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "### How to deploy a vgg16 model for inference using GraphPipe" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "First, we download an image that we can use to test our model" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 1, 36 | "metadata": { 37 | "scrolled": true 38 | }, 39 | "outputs": [ 40 | { 41 | "name": "stdout", 42 | "output_type": "stream", 43 | "text": [ 44 | "File `shepherd.jpg' already there; not retrieving.\r\n" 45 | ] 46 | } 47 | ], 48 | "source": [ 49 | "img_path = \"shepherd.jpg\"\n", 50 | "!wget -nc https://farm8.staticflickr.com/7457/16344626067_1e89d648a6_o_d.jpg -O {img_path}" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "Next, we display the image:" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 2, 63 | "metadata": {}, 64 | "outputs": [ 65 | { 66 | "name": "stderr", 67 | "output_type": "stream", 68 | "text": [ 69 | "/usr/local/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n", 70 | " from ._conv import register_converters as _register_converters\n" 71 | ] 72 | }, 73 | { 74 | "data": { 75 | "text/plain": [ 76 | "" 77 | ] 78 | }, 79 | "execution_count": 2, 80 | "metadata": {}, 81 | "output_type": "execute_result" 82 | }, 83 | { 84 | "data": { 85 | "image/png": "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\n", 86 | "text/plain": [ 87 | "
" 88 | ] 89 | }, 90 | "metadata": {}, 91 | "output_type": "display_data" 92 | } 93 | ], 94 | "source": [ 95 | "from tensorflow.python.keras.preprocessing import image\n", 96 | "img = image.load_img(img_path, target_size=(224, 224), interpolation='bicubic')\n", 97 | "%matplotlib inline\n", 98 | "import matplotlib.pyplot as plt\n", 99 | "plt.imshow(img)" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "Now we preprocess the image to make it ready for vgg. We convert the image\n", 107 | "to an array and use the handy preprocess_input to do the standard vgg conversions.\n", 108 | "Finally, we add a new axis to the dimension because we will be sending the image\n", 109 | "in a batch of one to our model." 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 3, 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "data": { 119 | "text/plain": [ 120 | "(1, 224, 224, 3)" 121 | ] 122 | }, 123 | "execution_count": 3, 124 | "metadata": {}, 125 | "output_type": "execute_result" 126 | } 127 | ], 128 | "source": [ 129 | "from tensorflow.python.keras.applications.vgg16 import preprocess_input\n", 130 | "import numpy as np\n", 131 | "\n", 132 | "x = image.img_to_array(img)\n", 133 | "x = preprocess_input(x)\n", 134 | "x = x[np.newaxis, :]\n", 135 | "x.shape" 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "metadata": {}, 141 | "source": [ 142 | "Next we instantiate the vgg16 model from the keras api using the pretrained imagenet weights" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 4, 148 | "metadata": {}, 149 | "outputs": [ 150 | { 151 | "data": { 152 | "text/plain": [ 153 | "TensorShape([Dimension(None), Dimension(224), Dimension(224), Dimension(3)])" 154 | ] 155 | }, 156 | "execution_count": 4, 157 | "metadata": {}, 158 | "output_type": "execute_result" 159 | } 160 | ], 161 | "source": [ 162 | "from tensorflow.python.keras.applications.vgg16 import VGG16\n", 163 | "\n", 164 | "model = VGG16(weights=\"imagenet\")\n", 165 | "model.input.shape" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "metadata": {}, 171 | "source": [ 172 | "The model correctly predicts our image as a german shepherd!" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": 5, 178 | "metadata": {}, 179 | "outputs": [ 180 | { 181 | "data": { 182 | "text/plain": [ 183 | "('n02106662', 'German_shepherd', 0.9768744)" 184 | ] 185 | }, 186 | "execution_count": 5, 187 | "metadata": {}, 188 | "output_type": "execute_result" 189 | } 190 | ], 191 | "source": [ 192 | "from tensorflow.python.keras.applications.vgg16 import decode_predictions\n", 193 | "\n", 194 | "y = model.predict(x)\n", 195 | "local_predictions = decode_predictions(y)\n", 196 | "local_predictions[0][0]" 197 | ] 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "metadata": {}, 202 | "source": [ 203 | "In order to use our model with the example graphpipe server, it must be saved\n", 204 | "as a graphdef pb. There is some helper code in the examples directory to do\n", 205 | "the conversion. **Note that you can also convert by running the script directly:\n", 206 | "`./convert.py test.h5 test.pb`**" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": 6, 212 | "metadata": {}, 213 | "outputs": [ 214 | { 215 | "name": "stdout", 216 | "output_type": "stream", 217 | "text": [ 218 | "WARNING:tensorflow:No training configuration found in save file: the model was *not* compiled. Compile it manually.\n", 219 | "INFO:tensorflow:Froze 32 variables.\n", 220 | "Converted 32 variables to const ops.\n" 221 | ] 222 | } 223 | ], 224 | "source": [ 225 | "from convert import h5_to_pb\n", 226 | "h5 = \"test.h5\"\n", 227 | "pb = \"test.pb\"\n", 228 | "port = 9000\n", 229 | "model.save(h5)\n", 230 | "h5_to_pb(h5, pb)" 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": {}, 236 | "source": [ 237 | "In order to make requests and serve requests in the same notebook,\n", 238 | "we have to serve the model in the background. In a regular script,\n", 239 | "you could do something like `model_server.py --model test.pb`, but\n", 240 | "in this case we'll be using the backgroundjobs lib. **Note that you\n", 241 | "can't kill the background job once it has started, so you'll have to\n", 242 | "restart the jupyter kernel if you want to change the model that you\n", 243 | "are serving**" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 7, 249 | "metadata": {}, 250 | "outputs": [ 251 | { 252 | "data": { 253 | "text/plain": [ 254 | ">" 255 | ] 256 | }, 257 | "execution_count": 7, 258 | "metadata": {}, 259 | "output_type": "execute_result" 260 | }, 261 | { 262 | "name": "stdout", 263 | "output_type": "stream", 264 | "text": [ 265 | "Starting httpd on :9000...\n" 266 | ] 267 | } 268 | ], 269 | "source": [ 270 | "from IPython.lib import backgroundjobs as bg\n", 271 | "from model_server import serve\n", 272 | "jobs = bg.BackgroundJobManager()\n", 273 | "jobs.new(serve, kw={\"host\": \"\", \"port\": 9000, \"model\": pb})" 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "If something goes wrong, you can run the following cell to check\n", 281 | "the traceback from the background job." 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 8, 287 | "metadata": {}, 288 | "outputs": [ 289 | { 290 | "name": "stdout", 291 | "output_type": "stream", 292 | "text": [ 293 | "Running jobs:\n", 294 | "0 : \n", 295 | "\n" 296 | ] 297 | } 298 | ], 299 | "source": [ 300 | "jobs.status()\n", 301 | "jobs.traceback()" 302 | ] 303 | }, 304 | { 305 | "cell_type": "markdown", 306 | "metadata": {}, 307 | "source": [ 308 | "Let's try doing a prediction using the remote model. If we omit\n", 309 | "the input and output names, it uses the first and last operation\n", 310 | "in the model. **Note that if you want to retrieve output from a\n", 311 | "different layer of the model, the operation name is prefixed with\n", 312 | "\"import/\", so if you wanted the output of the last fully connected\n", 313 | "layer instead of the predictions, you could add\n", 314 | "`output_name=\"import/fc2/Relu\"` to the call to `remote.execute`**" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": 9, 320 | "metadata": {}, 321 | "outputs": [ 322 | { 323 | "name": "stderr", 324 | "output_type": "stream", 325 | "text": [ 326 | "127.0.0.1 - - [12/Jul/2018 13:47:49] \"POST / HTTP/1.1\" 200 -\n" 327 | ] 328 | } 329 | ], 330 | "source": [ 331 | "from graphpipe import remote\n", 332 | "y = remote.execute(\"http://127.0.0.1:9000\", x)\n", 333 | "remote_predictions = decode_predictions(y)" 334 | ] 335 | }, 336 | { 337 | "cell_type": "markdown", 338 | "metadata": {}, 339 | "source": [ 340 | "Finally, we verify that the remote predictions are the same as those given by the local model" 341 | ] 342 | }, 343 | { 344 | "cell_type": "code", 345 | "execution_count": 10, 346 | "metadata": {}, 347 | "outputs": [ 348 | { 349 | "data": { 350 | "text/plain": [ 351 | "True" 352 | ] 353 | }, 354 | "execution_count": 10, 355 | "metadata": {}, 356 | "output_type": "execute_result" 357 | } 358 | ], 359 | "source": [ 360 | "remote_predictions == local_predictions" 361 | ] 362 | } 363 | ], 364 | "metadata": { 365 | "kernelspec": { 366 | "display_name": "Python 3", 367 | "language": "python", 368 | "name": "python3" 369 | }, 370 | "language_info": { 371 | "codemirror_mode": { 372 | "name": "ipython", 373 | "version": 3 374 | }, 375 | "file_extension": ".py", 376 | "mimetype": "text/x-python", 377 | "name": "python", 378 | "nbconvert_exporter": "python", 379 | "pygments_lexer": "ipython3", 380 | "version": "3.6.4" 381 | } 382 | }, 383 | "nbformat": 4, 384 | "nbformat_minor": 2 385 | } 386 | --------------------------------------------------------------------------------