{"id":14977840,"url":"https://github.com/ofnote/tsanley","last_synced_at":"2025-08-01T00:07:04.397Z","repository":{"id":62585377,"uuid":"211066525","full_name":"ofnote/tsanley","owner":"ofnote","description":"A runtime shape checker and auto-annotator for tensor programs (pronounced \"stanley\")","archived":false,"fork":false,"pushed_at":"2019-11-09T11:01:21.000Z","size":45,"stargazers_count":39,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-08T16:55:10.745Z","etag":null,"topics":["deep-learning","deep-neural-networks","neural-networks","numpy","pytorch","tensorflow"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ofnote.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-26T10:50:05.000Z","updated_at":"2024-01-04T16:38:08.000Z","dependencies_parsed_at":"2022-11-03T22:03:55.892Z","dependency_job_id":null,"html_url":"https://github.com/ofnote/tsanley","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ofnote/tsanley","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofnote%2Ftsanley","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofnote%2Ftsanley/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofnote%2Ftsanley/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofnote%2Ftsanley/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ofnote","download_url":"https://codeload.github.com/ofnote/tsanley/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofnote%2Ftsanley/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261986654,"owners_count":23240680,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deep-learning","deep-neural-networks","neural-networks","numpy","pytorch","tensorflow"],"created_at":"2024-09-24T13:56:25.215Z","updated_at":"2025-06-26T02:33:18.275Z","avatar_url":"https://github.com/ofnote.png","language":"Python","readme":"# tsanley \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\u003e Analyzing function foo \n  \nUpdate at line 36: actual shape of x = b,t,d \n  \u003e\u003e shape check succeeded at line 36 \n  \nUpdate at line 37: actual shape of y = t,d \n  \u003e\u003e 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  \u003e\u003e 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 `model.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\u003e 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: Work-In-Progress\n\n`tsanley` is a work in progress. It 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\nTry it out and open an issue if you spot a missing feature or run into problems.\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fofnote%2Ftsanley","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fofnote%2Ftsanley","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fofnote%2Ftsanley/lists"}