{ "info": { "author": "Nishant Sinha", "author_email": "nishant@offnote.co", "bugtrack_url": null, "classifiers": [ "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development" ], "description": "# tsanley \n![experimental](https://img.shields.io/badge/stability-experimental-orange.svg)\n\nTsanley is a shape analyzer for tensor programs, using popular tensor libraries: `tensorflow`, `pytorch`, `numpy`. Plugs into your existing code seamlessly, with minimal changes.\n\nBuilds upon the library [tsalib](https://github.com/ofnote/tsalib) for specifying, annotating and transforming tensor shapes using **named dimensions**.\n\n### Quick Start\n\n`tsanley` discovers shape errors at runtime by checking the runtime tensor shapes against the user-specified shape annotations. Tensor shape annotations are specified in the `tsalib` shape shorthand notation, e.g., `x: 'btd'`.\n\nMore details on the shorthand format [here](https://github.com/ofnote/tsalib/blob/master/notebooks/shorthand.md).\n\n#### Example\n\nSuppose we have the following functions `foo` and `test_foo` in our existing code. To setup `tsanley` analyzer for shape checking in `foo`, we add a function `setup_named_dims` *before* calling `test_foo`, label tensor variables by their expected shorthand shapes (e.g., `b,d`) and then execute the code normally.\n\n\n```python\ndef foo(x):\n x: 'b,t,d' #shape check: ok! [line 36]\n y: 'b,d' = x.mean(dim=0) # error! [line 37]\n z: 'b,d' = x.mean(dim=1) #shape check: ok! [line 38]\n\ndef test_foo():\n import torch\n x = torch.Tensor(10, 100, 1024)\n foo(x)\n\ndef setup_named_dims():\n from tsalib import dim_vars\n #declare the named dimension variables using the tsalib api\n #e.g., 'b' stands for 'Batch' dimension with size 10\n dim_vars('Batch(b):10 Length(t):100 Hidden(d):1024')\n\n # initialize tsanley's dynamic shape analyzer\n from tsanley.dynamic import init_analyzer\n init_analyzer(trace_func_names=['foo'], show_updates=True) #check_tsa=True, debug=False\n\n\nif __name__ == '__main__': \n setup_named_dims()\n test_foo()\n```\n\nOn executing the above program, `tsanley` tracks shapes of tensor variables (`x`, `y`, `z`) in function `foo` and reports following shape check results.\n\n#### Output\n\n```bash\n> Analyzing function foo \n\nUpdate at line 36: actual shape of x = b,t,d \n >> shape check succeeded at line 36 \n\nUpdate at line 37: actual shape of y = t,d \n >> FAILED shape check at line 37 \n expected: (b:10, d:1024), actual: (100, 1024) \n\nUpdate at line 38: actual shape of z = b,d \n >> shape check succeeded at line 38 \nsaving shapes to /tmp/shape_log.json ..\n```\n\n#### What does setup_named_dims do?\n\n- Declare the named dimension variables (using `dim_vars`) -- using them we can specify the expected shape of tensor variables in the code. For example, here we declare 3 dimension variables, `Batch`, `Length` and `Hidden`, and refer to them via shorthand names `b`,`t`, `d`. \n- We use shorthand names to label tensor variables and check their shapes in one or more functions, e.g., `foo` here.\n- Initialize the `tsanley` analyzer by calling `init_analyzer`: parameter `trace_func_names` takes a list of function names as Unix shell-style wildcards (using the `fnmatch` library). We can specify names with wildcards, e.g., `Resnet.*` to track all functions in the `Resnet` class.\n\nSee examples in [models](models/) directory.\n\n### Installation\n\n```\npip install tsanley\n```\n\n### Annotation\n\n`tsanley` can also annotate tensor variables in existing *executable* code with shape labels. This is useful when trying to understand external open-source code or labeling one's own code.\n\nSuppose, we have some un-annotated code residing in file `model.py`.\n\n1. First, generate *shape logs* by adding `setup_named_dims` to the `model.py`.\n2. Execute `model.py`. The logs are stored in `/tmp/shape_log.json`.\n2. Use the logs to annotate `test.py`.\n\n#### Example\nLet's revisit the earlier example, without our manual annotations. Suppose it resides in `model.py`.\n\n```python\ndef foo(x):\n y = x.mean(dim=0) \n z = x.mean(dim=1) \n\ndef test_foo():\n import torch\n x = torch.Tensor(10, 100, 1024)\n foo(x)\n```\n\nWe add `setup_named_dims` to the code, and execute it.\n\n```python\ndef setup_named_dims():\n from tsalib import dim_vars\n #declare the named dimension variables using the tsalib api\n #e.g., 'b' stands for 'Batch' dimension with size 10\n dim_vars('Batch(b):10 Length(t):100 Hidden(d):1024')\n\n # initialize tsanley's dynamic shape analyzer\n from tsanley.dynamic import init_analyzer\n init_analyzer(trace_func_names=['foo'], show_updates=True, check_tsa=False) # debug=False\n\nif __name__ == '__main__': \n setup_named_dims()\n test_foo()\n```\n\nThis generates the shape logs in `/tmp/shape_log.json`. Flag `check_tsa=False` ensures no shape checks are performed by `tsanley`.\n\nNow, annotate `foo` with the command:\n\n> tsa annotate -f model.py\n\nThe output is a file `tsa_model.py` with `foo` updated as follows:\n\n```python\ndef foo(x):\n y: 't,d' = x.mean(dim=0) \n z: 'b,d' = x.mean(dim=1) \n```\n\n`tsanley` makes smart guesses to map runtime shape values (`100`) to the shorthand names (`t`). If we do not declare the dimension names using `dim_vars` in `setup_named_dims`, we get the following annotation:\n\n```python\ndef foo(x):\n y: '100,1024' = x.mean(dim=0) \n z: '10,1024' = x.mean(dim=1) \n```\n\n\n### Status: Experimental\n\n`tsanley` performs a best-effort shape tracking during program execution. Here are a few tricky scenarios:\n\n- calling same function multiple times -- shape values from only the last call are cached.\n- recursive calls -- not handled.\n\nTested with `pytorch` examples. `tensorflow` and `numpy` programs should also work (`tsalib` supported backends), but remain to be tested.\n\n\n\n\n", "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/ofnote/tsanley", "keywords": "", "license": "Apache 2.0", "maintainer": "", "maintainer_email": "", "name": "tsanley", "package_url": "https://pypi.org/project/tsanley/", "platform": "POSIX", "project_url": "https://pypi.org/project/tsanley/", "project_urls": { "Homepage": "https://github.com/ofnote/tsanley" }, "release_url": "https://pypi.org/project/tsanley/0.2.0/", "requires_dist": [ "sympy", "typed-ast", "typed-astunparse", "easydict", "astpretty", "tsalib" ], "requires_python": "", "summary": "Tsanley: Understanding Tensor Programs", "version": "0.2.0" }, "last_serial": 5951528, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "b9a828a640f472f9844c8ae0fa62d83f", "sha256": "a900c9a80df65eef62e9c702fcafd7f55b90a1e9f77caf9b5ee941c1031480e2" }, "downloads": -1, "filename": "tsanley-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "b9a828a640f472f9844c8ae0fa62d83f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13627, "upload_time": "2019-09-26T11:01:22", "url": "https://files.pythonhosted.org/packages/01/2d/387fb44141591e97ce51991ff1d95e6918879b0e9baecff97b692b74fcf0/tsanley-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7c80ab63ef6ee86c157f373db9216347", "sha256": "51134cad28c0c66d65de01bab57c8ece2d5faf4d5f07e3e9b95b2cd691f821c1" }, "downloads": -1, "filename": "tsanley-0.1.0.tar.gz", "has_sig": false, "md5_digest": "7c80ab63ef6ee86c157f373db9216347", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7778, "upload_time": "2019-09-26T11:01:25", "url": "https://files.pythonhosted.org/packages/bf/a7/c13a8c6680516d3c7f247dbc187efaafa6cc99d7e21d85bcf8f65482edcd/tsanley-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "e8d7af8f96872adb2a48a453f0077121", "sha256": "7f88d2cfcebb0a469a1fa8ecfa78bbc53ad168f649335072f72b02621980048d" }, "downloads": -1, "filename": "tsanley-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "e8d7af8f96872adb2a48a453f0077121", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14750, "upload_time": "2019-10-08T12:19:31", "url": "https://files.pythonhosted.org/packages/8b/cf/e12857674f84459d033ec90583df29a1d5e33e2b1eeaa9bea06d5440bf37/tsanley-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "bcefc124fd8ce72217bfb68d43961610", "sha256": "e3bbeb1d1e68ef2d2f1af53f038ae78c1012e50aafcb330b70ab96701de3ae6b" }, "downloads": -1, "filename": "tsanley-0.1.1.tar.gz", "has_sig": false, "md5_digest": "bcefc124fd8ce72217bfb68d43961610", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8910, "upload_time": "2019-10-08T12:19:33", "url": "https://files.pythonhosted.org/packages/4f/52/be7bd42d094b141667f8eb6e406cb57f428bb4b70c094fdf676832b5e4d1/tsanley-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "11b2e410836aa0c967e9bd6f88052cbd", "sha256": "10e140cafa42b10af2b659ad65cebca113edea48731cf627c6d3ef982d36b5cc" }, "downloads": -1, "filename": "tsanley-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "11b2e410836aa0c967e9bd6f88052cbd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 16272, "upload_time": "2019-10-09T19:12:48", "url": "https://files.pythonhosted.org/packages/63/8f/ad71ef5e215fa8304e7bdc20c48a332f26c1384965c6b7b4aaf4d5811ef5/tsanley-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7709f6a1f4a3da69dfd6b9de3b6bea16", "sha256": "491f47029fa27651766be6e5ca044d001242b9b4d42fe01d82b3ae931fa2bf80" }, "downloads": -1, "filename": "tsanley-0.2.0.tar.gz", "has_sig": false, "md5_digest": "7709f6a1f4a3da69dfd6b9de3b6bea16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12268, "upload_time": "2019-10-09T19:12:50", "url": "https://files.pythonhosted.org/packages/38/a9/46cd2e8615a74ff87fcc34a319e1f48bb2c1ab2968a41040caa579ecfc96/tsanley-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "11b2e410836aa0c967e9bd6f88052cbd", "sha256": "10e140cafa42b10af2b659ad65cebca113edea48731cf627c6d3ef982d36b5cc" }, "downloads": -1, "filename": "tsanley-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "11b2e410836aa0c967e9bd6f88052cbd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 16272, "upload_time": "2019-10-09T19:12:48", "url": "https://files.pythonhosted.org/packages/63/8f/ad71ef5e215fa8304e7bdc20c48a332f26c1384965c6b7b4aaf4d5811ef5/tsanley-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7709f6a1f4a3da69dfd6b9de3b6bea16", "sha256": "491f47029fa27651766be6e5ca044d001242b9b4d42fe01d82b3ae931fa2bf80" }, "downloads": -1, "filename": "tsanley-0.2.0.tar.gz", "has_sig": false, "md5_digest": "7709f6a1f4a3da69dfd6b9de3b6bea16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12268, "upload_time": "2019-10-09T19:12:50", "url": "https://files.pythonhosted.org/packages/38/a9/46cd2e8615a74ff87fcc34a319e1f48bb2c1ab2968a41040caa579ecfc96/tsanley-0.2.0.tar.gz" } ] }