{ "info": { "author": "Olav Nymoen", "author_email": "olav@olavnymoen.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.6", "Topic :: Software Development :: Build Tools" ], "description": "# tfweb\n\nWeb server for Tensorflow model inference in python.\n\n## Quickstart\n\n```\n$ pip install tensorflow\n$ pip install tfweb\n$ tfweb --model s3://tfweb-models/hotdog --batch_transpose\n$ curl -d '{\"image\": {\"url\": \"https://i.imgur.com/H37kxPH.jpg\"}}' localhost:8080/predict\n{\n \"class\": [\"no hotdog\"],\n \"prediction\": [0.7314095497131348]\n}\n```\n\nMight take some time to download the model from `s3://tfweb-models`.\n\n```\n$ tfweb -h\n\nusage: tfweb [-h] [--model MODEL] [--tags TAGS] [--batch_size BATCH_SIZE]\n [--static_path STATIC_PATH] [--batch_transpose] [--no_cors]\n [--request_size REQUEST_SIZE] [--grpc_port GRPC_PORT]\n\ntfweb\n\noptional arguments:\n -h, --help show this help message and exit\n --model MODEL path to saved_model directory (can also be S3, GCS or hdfs)\n --tags TAGS Comma separated SavedModel tags. Defaults to `serve`\n --batch_size BATCH_SIZE\n Maximum batch size for batchable methods\n --static_path STATIC_PATH\n Path to static content, eg. html files served on GET\n --batch_transpose Provide and return each example in batches separately\n --no_cors Accept HTTP requests from all domains\n --request_size REQUEST_SIZE\n Max size per request\n --grpc_port GRPC_PORT\n Port accepting grpc requests\n```\n\n## Why?\n\ntfweb aims to be easier to setup, easier to tinker with and easier to integrate with than tf-serving. Thanks to being written in pure python 3 it's possible to interact with tensorflow though it's flexible python bindings.\n\n## Usage\n\nTensorflow has a standard format for persisting models called SavedModel. Any model persisted in this format which specifies it signatures can then automatically be exposed as a web service with tfweb.\n\nCreate a SavedModel that contains signature_defs (Look in the `examples` folder) then start a server exposing the model over JSON with `$ tfweb --model s3://tfweb-models/openimages --batch_transpose`\n\nTo see what sort of APIs the model exposes one can query it to get its type information:\n\n`$ curl localhost:8080 | python -m json.tool`\n```\n[\n {\n \"name\": \"features\",\n \"inputs\": {\n \"image\": {\n \"type\": \"string\",\n \"shape\": [\n -1\n ]\n }\n },\n \"outputs\": {\n \"features\": {\n \"type\": \"float32\",\n \"shape\": [\n -1,\n 2048\n ]\n }\n }\n },\n {\n \"name\": \"names\",\n \"inputs\": {\n \"image\": {\n \"type\": \"string\",\n \"shape\": [\n -1\n ]\n }\n },\n \"outputs\": {\n \"names\": {\n \"type\": \"string\",\n \"shape\": [\n -1,\n 5\n ]\n }\n }\n }\n]\n```\n\nHere we see the model has exposed two methods, `features` and `names` which accepts batches of strings. The model is in fact Inception v3 trained on OpenImages, meaning those batches of strings are batches of JPEG images. We cannot encode JPEG data as JSON, so we can either let the server fetch the data from a URL or we can base64 encode the image data before sending.\n\nThus we can query the method `names` like this:\n\n`curl -d '{\"image\": {\"url\": \"https://i.imgur.com/ekNNNjN.jpg\"}}' localhost:8080/names | python -m json.tool`\n```\n{\n \"names\": [\n \"mammal\",\n \"animal\",\n \"pet\",\n \"cat\",\n \"vertebrate\"\n ]\n}\n```\n\nAnd we received 5 strings corresponding to the best inception matches.\n\n## Batching\n\nBy default tfweb doesn't do any batching, but if a method (signature definition) has a variable outer dimension for all inputs and outputs (i.e. shape is [-1, ..]) then the method is assumed to be batchable and tfweb will optimistically queue up requests for batching while the tensorflow session is busy doing other stuff (like running the previous batch).\n\nIf a method accepts batches we can also send multiple queries in the same request:\n\n`curl -d '[{\"image\": {\"url\": \"https://i.imgur.com/ekNNNjN.jpg\"}}, {\"image\": {\"url\": \"https://i.imgur.com/JNo5tHj.jpg\"}}]' localhost:8080/names | python -m json.tool`\n```\n[\n {\n \"names\": [\n \"mammal\",\n \"animal\",\n \"pet\",\n \"cat\",\n \"vertebrate\"\n ]\n },\n {\n \"names\": [\n \"mammal\",\n \"animal\",\n \"pet\",\n \"vertebrate\",\n \"dog\"\n ]\n }\n]\n```\n\n## Functionality\n\n- Pure python - same as the most mature tensorflow API!\n- Reads tensorflow saved_model and exposes a HTTP API based on type information in the signature definitions\n- Batches across multiple requests for GPU utilization without delay\n- Can read binary data over JSON either wrapped in `{\"b64\": \"...\"}` or `{\"url\": \"...\"}`\n- Also base64 encodes JSON results that aren't valid UTF-8\n- Also accepts the Predict gRPC signature. Check out `test.py` for an example.\n\n## TODO\n- More tests (both coded and real world!)\n- Drop requests when\n- expose metrics for auto scaling\n- when downloading URLs, keep track of content size", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/olavhn/tfweb", "keywords": "serving,tensorflow,asyncio,aiohttp,grpc", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "tfweb", "package_url": "https://pypi.org/project/tfweb/", "platform": "", "project_url": "https://pypi.org/project/tfweb/", "project_urls": { "Homepage": "https://github.com/olavhn/tfweb" }, "release_url": "https://pypi.org/project/tfweb/0.4.11/", "requires_dist": null, "requires_python": ">=3.5", "summary": "Server for exposing tensorflow models though HTTP JSON API", "version": "0.4.11" }, "last_serial": 5381417, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "5c8860dea80951f6b45b40c1477d9577", "sha256": "b957544682b9046e90ae8bcd2239878d2e39726b7ddf9a5b0945286a8b55492c" }, "downloads": -1, "filename": "tfweb-0.1.tar.gz", "has_sig": false, "md5_digest": "5c8860dea80951f6b45b40c1477d9577", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7252, "upload_time": "2018-02-19T15:17:37", "url": "https://files.pythonhosted.org/packages/99/d9/7cc22e484510020a24b4f530c373ee98184d9b5b45a230a780c34d5a88fe/tfweb-0.1.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "afb89a1c713729bbcec192fb89504cf7", "sha256": "60c86bfde4b9a44a7638bc89a0997686f8a875299b8684bb78d378a540ac0882" }, "downloads": -1, "filename": "tfweb-0.3.tar.gz", "has_sig": false, "md5_digest": "afb89a1c713729bbcec192fb89504cf7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7257, "upload_time": "2018-02-19T15:30:25", "url": "https://files.pythonhosted.org/packages/45/e3/70884d4bcf91d70710e671c4b00b7c4187cccfad8bfde16ddeaf6095f886/tfweb-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "238adeb7ab1041d26fdd8c0cadaf65c4", "sha256": "4085c495ecdf8cbebf452310d9f601ef547e09ca3159945b868484a1e95069d8" }, "downloads": -1, "filename": "tfweb-0.4.tar.gz", "has_sig": false, "md5_digest": "238adeb7ab1041d26fdd8c0cadaf65c4", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 9793, "upload_time": "2018-02-20T11:59:24", "url": "https://files.pythonhosted.org/packages/a1/45/bde0ea5f4e391ca0a13521ab2582d2639408e73194bfa2b22951a257dc26/tfweb-0.4.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "44790f56bc219a556ea57a5cbef0c4f9", "sha256": "506dbf8f4c4fe4629bf7701d3493a57ce411396d5c713939a9e369076eec5c4a" }, "downloads": -1, "filename": "tfweb-0.4.1.tar.gz", "has_sig": false, "md5_digest": "44790f56bc219a556ea57a5cbef0c4f9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12642, "upload_time": "2018-12-18T11:14:33", "url": "https://files.pythonhosted.org/packages/08/f8/d8e5481220c9ddc78e2dcda8a9f6e1838ac52005ef87bfb14f55836d5784/tfweb-0.4.1.tar.gz" } ], "0.4.10": [ { "comment_text": "", "digests": { "md5": "7d45a8ca4adabfd66706567c163e3d68", "sha256": "7dff562692b99ab1870c5d333807692a826443d5deceda4f97308390c722c154" }, "downloads": -1, "filename": "tfweb-0.4.10.tar.gz", "has_sig": false, "md5_digest": "7d45a8ca4adabfd66706567c163e3d68", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12955, "upload_time": "2019-06-07T22:10:01", "url": "https://files.pythonhosted.org/packages/b5/40/1ff626e6848cb14930aa7b79dd852a66932584b5ea4b8c979d71ac479155/tfweb-0.4.10.tar.gz" } ], "0.4.11": [ { "comment_text": "", "digests": { "md5": "fa3c2d0972ed091cd02cccf738a9db59", "sha256": "6ed2b9868f461c685f7b2fc4e405a8b505d2028cd0e99c665f3061dce99b1dd6" }, "downloads": -1, "filename": "tfweb-0.4.11.tar.gz", "has_sig": false, "md5_digest": "fa3c2d0972ed091cd02cccf738a9db59", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12965, "upload_time": "2019-06-10T15:10:56", "url": "https://files.pythonhosted.org/packages/dc/95/4b763e184110b27e14ea80fa73d2cfad3fc64faf49633464f2b5f4d92de7/tfweb-0.4.11.tar.gz" } ], "0.4.2": [ { "comment_text": "", "digests": { "md5": "34fe3a45daf59079592552a47f9679a0", "sha256": "cf049ebc8149faabb447bd5c0e22e48efe337abf9379ab9e9393d21a76911a0e" }, "downloads": -1, "filename": "tfweb-0.4.2.tar.gz", "has_sig": false, "md5_digest": "34fe3a45daf59079592552a47f9679a0", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12638, "upload_time": "2018-05-08T06:47:11", "url": "https://files.pythonhosted.org/packages/f3/d6/e842bd59d1698fa97c4ebc567b9994d4337f6254e62c004c8ae0fda2e90b/tfweb-0.4.2.tar.gz" } ], "0.4.3": [ { "comment_text": "", "digests": { "md5": "e14758663e2bdabe5e820268f5f200b1", "sha256": "423463f2cea2f91cadce3c143e18811528a04c83bcff084ffa1323f6cee4ed42" }, "downloads": -1, "filename": "tfweb-0.4.3-py3.6.egg", "has_sig": false, "md5_digest": "e14758663e2bdabe5e820268f5f200b1", "packagetype": "bdist_egg", "python_version": "3.6", "requires_python": ">=3.5", "size": 24777, "upload_time": "2018-12-18T11:14:36", "url": "https://files.pythonhosted.org/packages/ae/30/6bb27ae04ae2ccca8f4bcd84df2d0802d17f8e4f975dcbd1b6b3ca8e0d8f/tfweb-0.4.3-py3.6.egg" }, { "comment_text": "", "digests": { "md5": "6445d824f179b1b4df661fca05f1d75a", "sha256": "66da39aceb7ac5a00c51563220a079d0e180868f1829c5d03adaf9864e320f44" }, "downloads": -1, "filename": "tfweb-0.4.3.tar.gz", "has_sig": false, "md5_digest": "6445d824f179b1b4df661fca05f1d75a", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12594, "upload_time": "2018-05-08T10:37:45", "url": "https://files.pythonhosted.org/packages/85/f4/e4be1e85f3529ffe7ac026db65f16ef97f8cd6bbb142b3a014f63982a9c9/tfweb-0.4.3.tar.gz" } ], "0.4.4": [ { "comment_text": "", "digests": { "md5": "4d43ded1ef687b44d0f4700199f5522a", "sha256": "b4e9d7b51077ff7e78f898392ce1c9c7a078a5cf63861c700d0ead804f5a809a" }, "downloads": -1, "filename": "tfweb-0.4.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "4d43ded1ef687b44d0f4700199f5522a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=3.5", "size": 12245, "upload_time": "2018-12-18T11:13:15", "url": "https://files.pythonhosted.org/packages/b8/6e/23081efd08765265a4cfe2721a369dda997561aa98f0800043af416e65d4/tfweb-0.4.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cf8062864226679bb141ecccc9bb0a8c", "sha256": "499fe99204054c74225f3c76f20d3958f3bb0f3b2f974cd44c6a3dba92f24180" }, "downloads": -1, "filename": "tfweb-0.4.4.tar.gz", "has_sig": false, "md5_digest": "cf8062864226679bb141ecccc9bb0a8c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12553, "upload_time": "2018-12-18T11:14:38", "url": "https://files.pythonhosted.org/packages/c0/72/00659b12d9a6e5c4a123952457f5818347c33e49e8e590c97ff5c221216a/tfweb-0.4.4.tar.gz" } ], "0.4.5": [ { "comment_text": "", "digests": { "md5": "fb6584208a5bbd4e9251957b9d1239c4", "sha256": "c2a26242226bec26716b8833cee14c011f5d631da82797343d430b65b34a47f6" }, "downloads": -1, "filename": "tfweb-0.4.5.tar.gz", "has_sig": false, "md5_digest": "fb6584208a5bbd4e9251957b9d1239c4", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12493, "upload_time": "2019-02-08T09:49:00", "url": "https://files.pythonhosted.org/packages/32/20/2ea0a9abaa70ea8729d34c06a1d9a11bc6675e1860e2b9a858d31eec870f/tfweb-0.4.5.tar.gz" } ], "0.4.6": [ { "comment_text": "", "digests": { "md5": "decebce93b7cf00793b0d7bc912bd19b", "sha256": "06d772ebc9e3bcc5e4020b5043e55e7535e57ecf348649eecf5ed27d16b22f96" }, "downloads": -1, "filename": "tfweb-0.4.6.tar.gz", "has_sig": false, "md5_digest": "decebce93b7cf00793b0d7bc912bd19b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12518, "upload_time": "2019-02-08T10:01:08", "url": "https://files.pythonhosted.org/packages/04/30/e4c93d4112dbd40e98b81cf7d0c46b8badeb2f1426b0b77e3cdaad99062f/tfweb-0.4.6.tar.gz" } ], "0.4.7": [ { "comment_text": "", "digests": { "md5": "11418eec07167ccbd10b852d4d59be2f", "sha256": "0fc725578484a461bb9dbf94b8f5f6782c18e2a20f21aeefca8f6f4f9192a35d" }, "downloads": -1, "filename": "tfweb-0.4.7.tar.gz", "has_sig": false, "md5_digest": "11418eec07167ccbd10b852d4d59be2f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12695, "upload_time": "2019-06-04T12:09:01", "url": "https://files.pythonhosted.org/packages/db/c9/e9ba04b2a8aee1abfe748ad984445967e66159a92b4db90fb5b8aff2119c/tfweb-0.4.7.tar.gz" } ], "0.4.8": [ { "comment_text": "", "digests": { "md5": "542d79bc0d2faba1c08ebce90da296b5", "sha256": "e5654796031590665528479d4569b4c736c198619b48546d52ee9326bcb3d283" }, "downloads": -1, "filename": "tfweb-0.4.8.tar.gz", "has_sig": false, "md5_digest": "542d79bc0d2faba1c08ebce90da296b5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12713, "upload_time": "2019-06-04T12:40:07", "url": "https://files.pythonhosted.org/packages/2d/66/983b1ce8168ad0907c92ad29785a4de297e96f99d677b17dc3427d2093a6/tfweb-0.4.8.tar.gz" } ], "0.4.9": [ { "comment_text": "", "digests": { "md5": "89cfbf33879e65231ed47c46b43be0da", "sha256": "169ae951522a8418cc2a118971ec40a130c0bbd454b22b9d43127ea6d89ff277" }, "downloads": -1, "filename": "tfweb-0.4.9.tar.gz", "has_sig": false, "md5_digest": "89cfbf33879e65231ed47c46b43be0da", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12920, "upload_time": "2019-06-07T22:05:33", "url": "https://files.pythonhosted.org/packages/0e/18/4608ce3f467224215d2c949e6de47dea7e6563a439ee588c961a4538cc93/tfweb-0.4.9.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "fa3c2d0972ed091cd02cccf738a9db59", "sha256": "6ed2b9868f461c685f7b2fc4e405a8b505d2028cd0e99c665f3061dce99b1dd6" }, "downloads": -1, "filename": "tfweb-0.4.11.tar.gz", "has_sig": false, "md5_digest": "fa3c2d0972ed091cd02cccf738a9db59", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12965, "upload_time": "2019-06-10T15:10:56", "url": "https://files.pythonhosted.org/packages/dc/95/4b763e184110b27e14ea80fa73d2cfad3fc64faf49633464f2b5f4d92de7/tfweb-0.4.11.tar.gz" } ] }