{ "info": { "author": "Alex Rogozhnikov", "author_email": "", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Science/Research", "Programming Language :: Python :: 3" ], "description": "
\n \"einops\n

\n
\n\n# einops\n\nA new flavour of deep learning ops for numpy, pytorch, tensorflow, chainer, gluon, and [others](#supported-frameworks).\n\n`einops` introduces a new way to manipulate tensors, \nproviding safer, more readable and semantically richer code.\n\n\n
\n

\n \"einops\n

\n
\n
\n\n[This video in better quality.](http://arogozhnikov.github.io/images/einops/einops_video.mp4)\n\n- [Tutorials](#Documentation--tutorials) \n- [API micro-reference](#API)\n- [Installation](#Installation)\n- [Naming](#Naming-and-terminology)\n- [Why using einops](#Why-using-einops-notation)\n- [Contributing](#Contributing)\n- [github repository](https://github.com/arogozhnikov/einops)\n\n\n## Documentation / Tutorials\n\nTutorials are the most convenient way to see `einops` in action\n\n- part1: [einops fundamentals](https://github.com/arogozhnikov/einops/blob/master/docs/1-einops-basics.ipynb) \n- part2: [einops for deep learning](https://github.com/arogozhnikov/einops/blob/master/docs/2-einops-for-deep-learning.ipynb)\n- part3: TBD \n\n(Tutorials are working as a documentation too.)\n\n## Installation\n\n`einops` has no mandatory dependencies.\n\nTo obtain the latest github version \n```bash\npip install https://github.com/arogozhnikov/einops/archive/master.zip\n```\n\npypi release will follow soon.\n\n\n\n\n\n## API \n\nMicro-reference on public API.\n\n`einops` API is very minimalistic and powerful.\n\nTwo operations provided (see the guide to `einops` fundamentals)\n```python\nfrom einops import rearrange, reduce\n\n# rearrange elements according to pattern\noutput_tensor = rearrange(input_tensor, pattern, **axes_lengths)\n\n# rearrange elements according to pattern\noutput_tensor = reduce(input_tensor, pattern, reduction, **axes_lengths)\n```\n\nTwo auxiliary functions\n```python\nfrom einops import asnumpy, parse_shape\n\n# einops.asnumpy converts tensors of imperative frameworks to numpy\nnumpy_tensor = asnumpy(input_tensor)\n\n# einops.parse_shape returns a shape in the form of a dictionary, axis name mapped to its length \nparse_shape(input_tensor, pattern)\n```\n\nAnd two layers (separate version for each framework) with the same API.\n\n```python\nfrom einops.layers.chainer import Rearrange, Reduce\nfrom einops.layers.gluon import Rearrange, Reduce\nfrom einops.layers.keras import Rearrange, Reduce\nfrom einops.layers.torch import Rearrange, Reduce\n```\n\n`Einops` layers are behaving in the same way as operations, and have same parameters \n(for the exception of first argument, which should be passed during call)\n\n```python\nlayer = Rearrange(pattern, **axes_lengths)\n# applying to tensor\nx = layer(x)\n\nlayer = Reduce(pattern, reduction, **axes_lengths)\n# applying to tensor\nx = layer(x)\n```\n\nUsually it is more convenient to use layers, not operations, to build models\n```python\n# example given for pytorch, but code in other frameworks is almost identical \nfrom torch.nn import Sequential, Conv2d, MaxPool2d, Linear, ReLU\nfrom einops.layers.torch import Reduce\n\nmodel = Sequential(\n Conv2d(3, 6, kernel_size=5),\n MaxPool2d(kernel_size=2),\n Conv2d(6, 16, kernel_size=5),\n Reduce('b c (h h2) (w w2) -> b (c h w)', 'max', h2=2, w2=2), # combined pooling and flattening\n Linear(16*5*5, 120), \n ReLU(),\n Linear(120, 10), \n)\n```\n\nLayers are available for `chainer`, `gluon`, `keras` and `torch`. \n\n## Naming and terminology\n\n`einops` stays for Einstein-Inspired Notation for operations \n(though \"Einstein operations\" sounds simpler and more attractive).\n\nNotation was loosely inspired by Einstein summation (in particular by `numpy.einsum` operation).\n\n- Terms `tensor` and `ndarray` are equivalently used and refer to multidimensional array \n- Terms `axis` and `dimension` are also equivalent\n\n\n## Why using `einops` notation\n\n\n### Semantic information:\n\n```python\ny = x.view(x.shape[0], -1)\ny = rearrange(x, 'b c h w -> b (c h w)')\n```\nwhile these two lines are doing the same job in some context,\nsecond one provides information about input and output.\nIn other words, `einops` focuses on interface: *what is input and output*, not *how* output is computed.\n\nThe next operation looks similar to previous two:\n```python\ny = rearrange(x, 'time c h w -> time (c h w)')\n```\nIt gives reader a hint: \nthis is not an independent batch of images we are processing, \nbut rather a sequence (video). \n\nSemantic information makes code easier to read and maintain. \n\n### More checks\n\nBack to the same example:\n```python\ny = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)\ny = rearrange(x, 'b c h w -> b (c h w)')\n```\nsecond line checks that there are four dimensions in input, \nbut you can also specify particular dimensions. \nThat's opposed to just writing comments about shapes since \n[comments don't work](https://medium.freecodecamp.org/code-comments-the-good-the-bad-and-the-ugly-be9cc65fbf83)\nas we know \n```python\ny = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)\ny = rearrange(x, 'b c h w -> b (c h w)', c=256, h=19, w=19)\n```\n\n### Result is strictly determined\n\nBelow we have at least two ways to define depth-to-space operation\n```python\n# depth to space\nrearrange(x, 'b c (h h2) (w w2) -> b (c h2 w2) h w', h2=2, w2=2)\nrearrange(x, 'b c (h h2) (w w2) -> b (h2 w2 c) h w', h2=2, w2=2)\n```\nthere are at least four more ways to do it. Which one is used by the framework?\n\nThese details are ignored, since usually it makes no difference, \nbut it can make a big difference (e.g. if you use grouped convolutions on the next stage), \nand you'd like to specify this in your code.\n\n\n\n### Uniformity\n\n```python\nreduce(x, 'b c (x dx) -> b c x', 'max', dx=2)\nreduce(x, 'b c (x dx) (y dx) -> b c x y', 'max', dx=2, dy=3)\nreduce(x, 'b c (x dx) (y dx) (z dz)-> b c x y z', 'max', dx=2, dy=3, dz=4)\n```\nThese examples demonstrated that we don't use separate operations for 1d/2d/3d pooling, \nthose all are defined in a uniform way. \n\nSpace-to-depth and depth-to space are defined in many frameworks. But how about width-to-height?\n```python\nrearrange(x, 'b c h (w w2) -> b c (h w2) w', w2=2)\n```\n\n### Framework independent behavior\n\nEven simple functions may be understood differently within different frameworks\n\n```python\ny = x.flatten() # or flatten(x)\n```\n\nSuppose `x` shape was `(3, 4, 5)`, then `y` has shape ...\n- numpy, cupy, chainer: `(60,)`\n- keras, tensorflow.layers, mxnet and gluon: `(3, 20)`\n- pytorch: no such function\n\n\n## Supported frameworks\n\nEinops works with ...\n\n- [numpy](http://www.numpy.org/)\n- [pytorch](https://pytorch.org/)\n- [tensorflow eager](https://www.tensorflow.org/guide/eager)\n- [cupy](https://cupy.chainer.org/)\n- [chainer](https://chainer.org/)\n- [gluon](https://mxnet.apache.org/)\n- [tensorflow](https://www.tensorflow.org/)\n- [mxnet](https://gluon.mxnet.io/) (experimental)\n- and [keras](https://keras.io/) (experimental)\n\n## Contributing \n\nBest ways to contribute are\n\n- spread the word about `einops`\n- **prepare a guide/post/tutorial** for your favorite deep learning framework\n- translating examples in languages other than English is also a good idea \n- use `einops` notation in your papers to strictly define an operation you're using\n\n## Supported python versions\n\n`einops` works with python 3.5 or later. \n\nThere is nothing specific to python 3 in the code, \nwe simply [need to move further](http://github.com/arogozhnikov/python3_with_pleasure) \nand I decided not to support python 2.\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/arogozhnikov/einops", "keywords": "deep learning,neural networks,tensor manipulation,scientific computations", "license": "", "maintainer": "", "maintainer_email": "", "name": "einops", "package_url": "https://pypi.org/project/einops/", "platform": "", "project_url": "https://pypi.org/project/einops/", "project_urls": { "Homepage": "https://github.com/arogozhnikov/einops" }, "release_url": "https://pypi.org/project/einops/0.1.0/", "requires_dist": null, "requires_python": "", "summary": "A new flavour of deep learning operations", "version": "0.1.0" }, "last_serial": 4430531, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "489ed693686d3b474d44e2959f0e9025", "sha256": "4ab512fe059c0841e1a315449ca9d7f35eaa05c8c095a14f2c1b92b2b77684d2" }, "downloads": -1, "filename": "einops-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "489ed693686d3b474d44e2959f0e9025", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 16829, "upload_time": "2018-10-30T08:07:28", "url": "https://files.pythonhosted.org/packages/36/1f/a5e6496a167b6e892123b201ccce251184457ce7a1b6c8e06662c09bfbab/einops-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9ab814121e666c0cf50944dd1a892ee3", "sha256": "4fd64864fcb8159074da3213b9327c242536784416cbf423745ef8579850d30b" }, "downloads": -1, "filename": "einops-0.1.0.tar.gz", "has_sig": false, "md5_digest": "9ab814121e666c0cf50944dd1a892ee3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15083, "upload_time": "2018-10-30T08:07:30", "url": "https://files.pythonhosted.org/packages/32/d3/efa7cd2f496ebe32b7b7e17bb0d91f2fb216b032ce572e63bab767f46e32/einops-0.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "489ed693686d3b474d44e2959f0e9025", "sha256": "4ab512fe059c0841e1a315449ca9d7f35eaa05c8c095a14f2c1b92b2b77684d2" }, "downloads": -1, "filename": "einops-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "489ed693686d3b474d44e2959f0e9025", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 16829, "upload_time": "2018-10-30T08:07:28", "url": "https://files.pythonhosted.org/packages/36/1f/a5e6496a167b6e892123b201ccce251184457ce7a1b6c8e06662c09bfbab/einops-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9ab814121e666c0cf50944dd1a892ee3", "sha256": "4fd64864fcb8159074da3213b9327c242536784416cbf423745ef8579850d30b" }, "downloads": -1, "filename": "einops-0.1.0.tar.gz", "has_sig": false, "md5_digest": "9ab814121e666c0cf50944dd1a892ee3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15083, "upload_time": "2018-10-30T08:07:30", "url": "https://files.pythonhosted.org/packages/32/d3/efa7cd2f496ebe32b7b7e17bb0d91f2fb216b032ce572e63bab767f46e32/einops-0.1.0.tar.gz" } ] }