Showing preview only (1,022K chars total). Download the full file or copy to clipboard to get everything.
Repository: arogozhnikov/einops
Branch: main
Commit: 451e16ff3ebf
Files: 67
Total size: 987.0 KB
Directory structure:
gitextract_7syaalsv/
├── .devcontainer/
│ ├── devcontainer.json
│ └── einops.Dockerfile
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── extensions--introducing-new-operation---improve-notion.md
│ └── workflows/
│ ├── deploy_docs.yml
│ ├── deploy_to_pypi.yml
│ ├── run_tests.yml
│ └── test_notebooks.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CITATION.cff
├── LICENSE
├── README.md
├── docs/
│ ├── 1-einops-basics.ipynb
│ ├── 2-einops-for-deep-learning.ipynb
│ ├── 3-einmix-layer.ipynb
│ ├── 4-pack-and-unpack.ipynb
│ ├── README.md
│ ├── pytorch-examples.html
│ ├── resources/
│ │ └── test_images.npy
│ └── utils/
│ └── __init__.py
├── docs_src/
│ ├── CNAME
│ ├── api/
│ │ ├── asnumpy.md
│ │ ├── einsum.md
│ │ ├── pack_unpack.md
│ │ ├── parse_shape.md
│ │ ├── rearrange.md
│ │ ├── reduce.md
│ │ └── repeat.md
│ ├── css/
│ │ ├── codehilite.css
│ │ └── mkdocs.css
│ └── pages/
│ ├── projects.md
│ └── testimonials.md
├── einops/
│ ├── __init__.py
│ ├── _backends.py
│ ├── _torch_specific.py
│ ├── array_api.py
│ ├── einops.py
│ ├── experimental/
│ │ ├── __init__.py
│ │ └── indexing.py
│ ├── layers/
│ │ ├── __init__.py
│ │ ├── _einmix.py
│ │ ├── flax.py
│ │ ├── keras.py
│ │ ├── oneflow.py
│ │ ├── paddle.py
│ │ ├── tensorflow.py
│ │ └── torch.py
│ ├── packing.py
│ ├── parsing.py
│ ├── py.typed
│ └── tests/
│ ├── __init__.py
│ ├── run_tests.py
│ ├── test_einsum.py
│ ├── test_examples.py
│ ├── test_layers.py
│ ├── test_ops.py
│ ├── test_other.py
│ ├── test_packing.py
│ └── test_parsing.py
├── mkdocs.yml
├── pyproject.toml
└── scripts/
├── convert_readme.py
├── pytorch_examples_source/
│ ├── Pytorch.ipynb
│ └── converter.py
├── setup.py
└── test_notebooks.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .devcontainer/devcontainer.json
================================================
{
"name": "EinopsDev",
"build": {
"context": "..",
"dockerfile": "./einops.Dockerfile",
"target": "einops-devimage",
},
"runArgs": [
// to use GPUs in container uncomment next line
// "--gpus=all",
"--name=einops-devbox",
],
"shutdownAction": "none",
"postCreateCommand": "uv pip install --system -e . && pre-commit install -f",
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "/opt/venv/bin/python"
},
"extensions": [
"ms-azuretools.vscode-docker",
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.mypy-type-checker",
"charliermarsh.ruff",
"ms-toolsai.jupyter",
// very optional git-specific stuff
"arturock.gitstash",
"mhutchie.git-graph",
]
}
}
}
================================================
FILE: .devcontainer/einops.Dockerfile
================================================
FROM python:3.11-bookworm AS einops-devimage
# note this will pull aarch64 or x86 depending on machine it is running on.
RUN pip install uv \
&& uv pip install --system pre-commit hatch
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Reproduction steps**
Steps to reproduce the behavior:
**Expected behavior**
What you expected to happen.
**Your platform**
Version of einops, python and DL package that you used
================================================
FILE: .github/ISSUE_TEMPLATE/extensions--introducing-new-operation---improve-notion.md
================================================
---
name: 'Extensions: Introducing new operation / improve notion'
about: 'You want to suggest a new operation or extend an existing one? '
title: "[Feature suggestion]"
labels: feature suggestion
assignees: ''
---
Einops sparks a lot of interest to introduce new operations that either meet specific requirements or look like a plausible extension of existing ones.
Einops is not a purely experimental thing, it's already used in a number of large projects, so there are high expectations for any introduced improvement. Let's see which are they and how to check them?
1. Try to collect **use-cases**
2. **Implementation**. (optional) Implementing a sketch of your proposal in a code allows detecting possible conflicts and realize possible caveats.
3. **Integrity** - does it interplay well with existing operations and notation in einops?
4. **Readability**. This is harder to check, but give it a try. A simple but usable test is to write an exercise sheet with several examples of your extension explained, for others meaning of operation should be guessed. Send this test to a couple of your friends to collect the feedback and see how your notion will be understood. This should also help to improve your ideas to make them more digestible.
================================================
FILE: .github/workflows/deploy_docs.yml
================================================
name: deploy-docs
on:
push:
branches:
# triggers on new commits / merged PRs to main or a special branch
- main
- docs-deploy-testing
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Configure Git Credentials
# credentials of GitHub's public bot, so that commits 'belonged' to bot
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- uses: actions/setup-python@v5
with:
python-version: 3.12
## Switched off cache, deployment is fast anyway.
# - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
# - uses: actions/cache@v4
# with:
# key: mkdocs-material-${{ env.cache_id }}
# path: .cache
# restore-keys: |
# mkdocs-material-
## original deploy instruction has --force
# - run: mkdocs gh-deploy --force
- run: pip install hatch && hatch run docs:deploy_force
================================================
FILE: .github/workflows/deploy_to_pypi.yml
================================================
name: Deploy to pypi
on:
release:
types: [created]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
pip install . && pip install hatch
- name: Publish einops to PyPi
env:
HATCH_INDEX_USER: "__token__"
HATCH_INDEX_AUTH: ${{ secrets.PYPI_TOKEN }}
run: |
hatch run pypi:deploy
================================================
FILE: .github/workflows/run_tests.yml
================================================
name: Run tests
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
# do not fail other jobs if one framework / version misbehaves
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.13']
# there was (and likely still is) conflict between tf, oneflow and paddle in protobuf versions.
# cupy is not tested because it demands gpu
# oneflow testing is dropped, see details at https://github.com/Oneflow-Inc/oneflow/issues/10340
# paddle testing is dropped because of divergence with numpy in py3.10, paddle==2.6.1
frameworks: ['numpy pytorch tensorflow jax mlx.core']
include:
- python-version: '3.10'
frameworks: 'pytensor'
- python-version: '3.13'
frameworks: 'pytensor'
steps:
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Check for ruff compliance
run: |
pip install ruff==0.11.7 && ruff check . && ruff format . --check
- name: Run tests
run: |
pip install -e . && python -m einops.tests.run_tests ${{ matrix.frameworks }} --pip-install
================================================
FILE: .github/workflows/test_notebooks.yml
================================================
name: Test notebooks
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10', '3.13']
steps:
- uses: actions/checkout@v5
- name: Install uv
uses: astral-sh/setup-uv@v7
- run: uv venv --python ${{ matrix.python-version }}
- name: Install dependencies to run/test notebooks
run: |
uv pip install nbformat nbconvert jupyter pillow pytest numpy tensorflow
uv pip install torch --index-url https://download.pytorch.org/whl/cpu
- name: Testing notebooks
run: |
uv pip install -e . && uv run pytest scripts/test_notebooks.py
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# pycharm
.idea
# design-document
design-einops.txt
# logo and video generation
logo
# any local explorations
*.personal*
# oneflow's output trash
log
# this file is auto-generated
docs_src/index.md
# vs code
*.code-workspace
# macos system files
.DS_Store
================================================
FILE: .pre-commit-config.yaml
================================================
---
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version, synced with CI
rev: v0.11.7
hooks:
# Run the linter.
- id: ruff
types_or: [ python, pyi, jupyter ]
# Run the formatter.
- id: ruff-format
types_or: [ python, pyi, jupyter ]
================================================
FILE: CITATION.cff
================================================
cff-version: 1.2.0
title: einops
message: >-
If you use this software, please cite it using the
metadata from this file.
type: software
authors:
- given-names: Alex
family-names: Rogozhnikov
repository-code: 'https://github.com/arogozhnikov/einops'
abstract: >-
Flexible and powerful tensor operations for readable and reliable code (for pytorch, jax, TF and others)
license: MIT
preferred-citation:
type: article
authors:
- given-names: Alex
family-names: Rogozhnikov
journal: "International Conference on Learning Representations"
title: "Einops: Clear and Reliable Tensor Manipulations with Einstein-like Notation"
year: 2022
url: https://openreview.net/forum?id=oapKSVM2bc
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 Alex Rogozhnikov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
================================================
FILE: README.md
================================================
<!--
<a href='http://arogozhnikov.github.io/images/einops/einops_video.mp4' >
<div align="center">
<img src="http://arogozhnikov.github.io/images/einops/einops_video.gif" alt="einops package examples" />
<br>
<small><a href='http://arogozhnikov.github.io/images/einops/einops_video.mp4'>This video in high quality (mp4)</a></small>
<br><br>
</div>
</a>
-->
<!-- this link magically rendered as video on github readme, unfortunately not in docs -->
https://user-images.githubusercontent.com/6318811/177030658-66f0eb5d-e136-44d8-99c9-86ae298ead5b.mp4
# einops
[](https://github.com/arogozhnikov/einops/actions/workflows/run_tests.yml)
[](https://badge.fury.io/py/einops)
[](https://einops.rocks/)

Flexible and powerful tensor operations for readable and reliable code. <br />
Supports numpy, pytorch, jax, mlx and [others](#supported-frameworks).
## Recent updates:
- [einops playground](https://arogozhnikov.github.io/jupyterlite/lab/index.html?download_github_folder=arogozhnikov/einops/docs) can run 2 of 4 example notebooks right in your browser
- 0.8.2: MLX backend added
- 0.8.0: tinygrad backend added, small fixes
- 0.7.0: no-hassle `torch.compile`, support of [array api standard](https://data-apis.org/array-api/latest/API_specification/index.html) and more
- 10'000🎉: github reports that more than 10k project use einops
- einops 0.6.1: paddle backend added
- einops 0.6 introduces [packing and unpacking](https://github.com/arogozhnikov/einops/blob/main/docs/4-pack-and-unpack.ipynb)
- einops 0.5: einsum is now a part of einops
- [Einops paper](https://openreview.net/pdf?id=oapKSVM2bcj) is accepted for oral presentation at ICLR 2022 (yes, it worth reading).
Talk recordings are [available](https://iclr.cc/virtual/2022/oral/6603)
<details markdown="1">
<summary>Previous updates</summary>
- flax and oneflow backend added
- torch.jit.script is supported for pytorch layers
- powerful EinMix added to einops. [Einmix tutorial notebook](https://github.com/arogozhnikov/einops/blob/main/docs/3-einmix-layer.ipynb)
</details>
<!--<div align="center">
<img src="http://arogozhnikov.github.io/images/einops/einops_logo_350x350.png"
alt="einops package logo" width="250" height="250" />
<br><br>
</div> -->
## Tweets
> In case you need convincing arguments for setting aside time to learn about einsum and einops...
[Tim Rocktäschel](https://twitter.com/_rockt/status/1230818967205425152)
> Writing better code with PyTorch and einops 👌
[Andrej Karpathy](https://twitter.com/karpathy/status/1290826075916779520)
> Slowly but surely, einops is seeping in to every nook and cranny of my code. If you find yourself shuffling around bazillion dimensional tensors, this might change your life
[Nasim Rahaman](https://twitter.com/nasim_rahaman/status/1216022614755463169)
[More testimonials](https://einops.rocks/pages/testimonials/)
## Contents
- [Installation](#Installation)
- [Documentation](https://einops.rocks/)
- [Tutorial](#Tutorials)
- [API micro-reference](#API)
- [Why use einops](#Why-use-einops-notation)
- [Supported frameworks](#Supported-frameworks)
- [Citing](#Citing)
- [Repository](https://github.com/arogozhnikov/einops) and [discussions](https://github.com/arogozhnikov/einops/discussions)
## Installation <a name="Installation"></a>
Plain and simple:
```bash
pip install einops
```
(`uv pip install einops` works as well)
## Tutorials <a name="Tutorials"></a>
Tutorials are the most convenient way to see `einops` in action
- part 1: [einops fundamentals](https://github.com/arogozhnikov/einops/blob/main/docs/1-einops-basics.ipynb)
- part 2: [einops for deep learning](https://github.com/arogozhnikov/einops/blob/main/docs/2-einops-for-deep-learning.ipynb)
- part 3: [packing and unpacking](https://github.com/arogozhnikov/einops/blob/main/docs/4-pack-and-unpack.ipynb)
- part 4: [improve pytorch code with einops](http://einops.rocks/pytorch-examples.html)
Kapil Sachdeva recorded a small [intro to einops](https://www.youtube.com/watch?v=xGy75Pjsqzo).
## API <a name="API"></a>
`einops` has a minimalistic yet powerful API.
Three core operations provided ([einops tutorial](https://github.com/arogozhnikov/einops/blob/main/docs/)
shows those cover stacking, reshape, transposition, squeeze/unsqueeze, repeat, tile, concatenate, view and numerous reductions)
```python
from einops import rearrange, reduce, repeat
# rearrange elements according to the pattern
output_tensor = rearrange(input_tensor, 't b c -> b c t')
# combine rearrangement and reduction
output_tensor = reduce(input_tensor, 'b c (h h2) (w w2) -> b h w c', 'mean', h2=2, w2=2)
# copy along a new axis
output_tensor = repeat(input_tensor, 'h w -> h w c', c=3)
```
Later additions to the family are `pack` and `unpack` functions (better than stack/split/concatenate):
```python
from einops import pack, unpack
# pack and unpack allow reversibly 'packing' multiple tensors into one.
# Packed tensors may be of different dimensionality:
packed, ps = pack([class_token_bc, image_tokens_bhwc, text_tokens_btc], 'b * c')
class_emb_bc, image_emb_bhwc, text_emb_btc = unpack(transformer(packed), ps, 'b * c')
```
Finally, einops provides einsum with a support of multi-lettered names:
```python
from einops import einsum, pack, unpack
# einsum is like ... einsum, generic and flexible dot-product
# but 1) axes can be multi-lettered 2) pattern goes last 3) works with multiple frameworks
C = einsum(A, B, 'b t1 head c, b t2 head c -> b head t1 t2')
```
### EinMix
`EinMix` is a generic linear layer, perfect for MLP Mixers and similar architectures.
### Layers
Einops provides layers (`einops` keeps a separate version for each framework) that reflect corresponding functions
```python
from einops.layers.torch import Rearrange, Reduce
from einops.layers.tensorflow import Rearrange, Reduce
from einops.layers.flax import Rearrange, Reduce
from einops.layers.paddle import Rearrange, Reduce
```
<details markdown="1">
<summary>Example of using layers within a pytorch model</summary>
Example given for pytorch, but code in other frameworks is almost identical
```python
from torch.nn import Sequential, Conv2d, MaxPool2d, Linear, ReLU
from einops.layers.torch import Rearrange
model = Sequential(
...,
Conv2d(6, 16, kernel_size=5),
MaxPool2d(kernel_size=2),
# flattening without need to write forward
Rearrange('b c h w -> b (c h w)'),
Linear(16*5*5, 120),
ReLU(),
Linear(120, 10),
)
```
No more flatten needed!
Additionally, torch layers as those are script-able and compile-able.
Operations [are torch.compile-able](https://github.com/arogozhnikov/einops/wiki/Using-torch.compile-with-einops),
but not script-able due to limitations of torch.jit.script.
</details>
## Naming <a name="Naming"></a>
`einops` stands for Einstein-Inspired Notation for operations
(though "Einstein operations" is more attractive and easier to remember).
Notation was loosely inspired by Einstein summation (in particular by `numpy.einsum` operation).
## Why use `einops` notation?! <a name="Why-use-einops-notation"></a>
### Semantic information (being verbose in expectations)
```python
y = x.view(x.shape[0], -1)
y = rearrange(x, 'b c h w -> b (c h w)')
```
While these two lines are doing the same job in *some* context,
the second one provides information about the input and output.
In other words, `einops` focuses on interface: *what is the input and output*, not *how* the output is computed.
The next operation looks similar:
```python
y = rearrange(x, 'time c h w -> time (c h w)')
```
but it gives the reader a hint:
this is not an independent batch of images we are processing,
but rather a sequence (video).
Semantic information makes the code easier to read and maintain.
### Convenient checks
Reconsider the same example:
```python
y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
y = rearrange(x, 'b c h w -> b (c h w)')
```
The second line checks that the input has four dimensions,
but you can also specify particular dimensions.
That's opposed to just writing comments about shapes since comments don't prevent mistakes,
not tested, and without code review tend to be outdated
```python
y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
y = rearrange(x, 'b c h w -> b (c h w)', c=256, h=19, w=19)
```
### Result is strictly determined
Below we have at least two ways to define the depth-to-space operation
```python
# depth-to-space
rearrange(x, 'b c (h h2) (w w2) -> b (c h2 w2) h w', h2=2, w2=2)
rearrange(x, 'b c (h h2) (w w2) -> b (h2 w2 c) h w', h2=2, w2=2)
```
There are at least four more ways to do it. Which one is used by the framework?
These details are ignored, since *usually* it makes no difference,
but it can make a big difference (e.g. if you use grouped convolutions in the next stage),
and you'd like to specify this in your code.
### Uniformity
```python
reduce(x, 'b c (x dx) -> b c x', 'max', dx=2)
reduce(x, 'b c (x dx) (y dy) -> b c x y', 'max', dx=2, dy=3)
reduce(x, 'b c (x dx) (y dy) (z dz) -> b c x y z', 'max', dx=2, dy=3, dz=4)
```
These examples demonstrated that we don't use separate operations for 1d/2d/3d pooling,
those are all defined in a uniform way.
Space-to-depth and depth-to space are defined in many frameworks but how about width-to-height? Here you go:
```python
rearrange(x, 'b c h (w w2) -> b c (h w2) w', w2=2)
```
### Framework independent behavior
Even simple functions are defined differently by different frameworks
```python
y = x.flatten() # or flatten(x)
```
Suppose `x`'s shape was `(3, 4, 5)`, then `y` has shape ...
- numpy, pytorch, cupy, chainer, jax: `(60,)`
- keras, tensorflow.layers, gluon: `(3, 20)`
`einops` works the same way in all frameworks.
### Independence of framework terminology
Example: `tile` vs `repeat` causes lots of confusion. To copy image along width:
```python
np.tile(image, (1, 2)) # in numpy
image.repeat(1, 2) # pytorch's repeat ~ numpy's tile
```
With einops you don't need to decipher which axis was repeated:
```python
repeat(image, 'h w -> h (tile w)', tile=2) # in numpy
repeat(image, 'h w -> h (tile w)', tile=2) # in pytorch
repeat(image, 'h w -> h (tile w)', tile=2) # in tf
repeat(image, 'h w -> h (tile w)', tile=2) # in jax
repeat(image, 'h w -> h (tile w)', tile=2) # in cupy
... (etc.)
```
[Testimonials](https://einops.rocks/pages/testimonials/) provide users' perspective on the same question.
## Supported frameworks <a name="Supported-frameworks"></a>
Einops works with ...
- [numpy](http://www.numpy.org/)
- [pytorch](https://pytorch.org/)
- [tensorflow](https://www.tensorflow.org/)
- [jax](https://github.com/google/jax)
- [cupy](https://github.com/cupy/cupy)
- [flax](https://github.com/google/flax) (community)
- [paddle](https://github.com/PaddlePaddle/Paddle) (community)
- [oneflow](https://github.com/Oneflow-Inc/oneflow) (community)
- [tinygrad](https://github.com/tinygrad/tinygrad) (community)
- [pytensor](https://github.com/pymc-devs/pytensor) (community)
```python
from einops import rearrange
=> from einops.array_api import rearrange
```
But actually it is even better: einops can be used with *any* framework that supports
[Python array API standard](https://data-apis.org/array-api/latest/API_specification/index.html),
to name a few:
- numpy >= 2.0
- [MLX](https://github.com/ml-explore/mlx) # yes, einops works with apple's framework
- [pydata/sparse](https://github.com/pydata/sparse) >= 0.15 # and works with sparse tensors
- [cubed](https://github.com/cubed-dev/cubed) # and with distributed tensors too
- [quantco/ndonnx](https://github.com/Quantco/ndonnx)
- jax
- cupy
- dask is supported via [array-api-compat](https://github.com/data-apis/array-api-compat)
## Development
Devcontainer is provided, this environment can be used locally, or on your server,
or within github codespaces.
To start with devcontainers in vs code, clone repo, and click 'Reopen in Devcontainer'.
Starting from einops 0.8.1, einops distributes tests as a part of package.
```bash
# pip install einops pytest
python -m einops.tests.run_tests numpy pytorch jax --pip-install
```
`numpy pytorch jax` is an _example_, any subset of testable frameworks can be provided.
Every framework is tested against numpy, so it is a requirement for tests.
Specifying `--pip-install` will install requirements in current virtualenv,
and should be omitted if dependencies are installed locally.
To build/test docs:
```bash
hatch run docs:serve # Serving on http://localhost:8000/
```
## Citing einops <a name="Citing"></a>
Please use the following bibtex record
```text
@inproceedings{
rogozhnikov2022einops,
title={Einops: Clear and Reliable Tensor Manipulations with Einstein-like Notation},
author={Alex Rogozhnikov},
booktitle={International Conference on Learning Representations},
year={2022},
url={https://openreview.net/forum?id=oapKSVM2bcj}
}
```
## Supported python versions
`einops` works with python 3.10 or later.
================================================
FILE: docs/1-einops-basics.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Einops tutorial, part 1: basics\n",
"\n",
"<!-- <img src='http://arogozhnikov.github.io/images/einops/einops_logo_350x350.png' height=\"80\" /> -->\n",
"\n",
"## Welcome to einops-land!\n",
"\n",
"We don't write \n",
"```python\n",
"y = x.transpose(0, 2, 3, 1)\n",
"```\n",
"We write comprehensible code\n",
"```python\n",
"y = rearrange(x, 'b c h w -> b h w c')\n",
"```\n",
"\n",
"\n",
"`einops` supports widely used tensor packages (such as `numpy`, `pytorch`, `jax`, `tensorflow`), and extends them.\n",
"\n",
"## What's in this tutorial?\n",
"\n",
"- fundamentals: reordering, composition and decomposition of axes\n",
"- operations: `rearrange`, `reduce`, `repeat`\n",
"- how much you can do with a single operation!\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Preparations"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"# we need some libraries for this demo\n",
"%pip install einops numpy pillow -q"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Examples are given for numpy. This code also setups ipython/jupyter/jupyterlite\n",
"# so that numpy arrays in the output are displayed as images\n",
"import numpy\n",
"from utils import display_np_arrays_as_images\n",
"\n",
"display_np_arrays_as_images()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Load a batch of images to play with"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(6, 96, 96, 3) float64\n"
]
}
],
"source": [
"ims = numpy.load(\"./resources/test_images.npy\", allow_pickle=False)\n",
"# There are 6 images of shape 96x96 with 3 color channels packed into tensor\n",
"print(ims.shape, ims.dtype)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# display the first image (whole 4d tensor can't be rendered)\n",
"ims[0]"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAIAAABt+uBvAAAE8ElEQVR4Ae2cW0gUURjHW68Vrkn3vKSsVj6skS6ZlUahWBop5KXIaiGqh97KfPAlWfApCI2eIovA1Jd60oQiK+/hmqmIZUW0ubtBeemibqWrfbIkC+p8Z3TmnE0+Xxzm/58z5/vtf44z456jsU/Zl9HP/AS85pdImSbgIwTDu9fvKssqG+sarRbrL8evNevWxMTFHMo8lHUyy9fPV0iX5juphvMl9uf3n6KLReU3yycnJ2f3KWRzSOnd0r0H9s6WRO3hCgjCkpuS297SLlGtt7f3tdvXco25Eh6eEtcxKP9svjQdqNzpdBacKzA3m3lSkDgXvwR1mjvT49MluuIu7di5o7at1n2PqG1+Caq4VcFeJNDsedXD7lfPyQ9Q89NmWWU0PGmQ5VfJzA+Q7ZNNVg3Wj1ZZfpXMnACNjY6Nj4/LquHb8DdZfpXMnACtWLnCx0feTWngqkCVapbVLCdAGo1mU+gmWT0LDQ+V5VfJzAkQ9D4xOVFWDUkpSbL8Kpn5ATpx9gR7DfBott2wnd2vnpMfIEOCIeNYBkslMFqZSkxwVbKY1fbwAwSVlNwpidsVJ12Sl5fX1ZtXE/YlSNu4qVwBwd+y+8/u553LAwpzVggDedWjquNnjs+pCtnJ71nMvby3vW/hyaPpaZPNYnM4HNPvg2JjDmYezD6V7efv5+4Uvi0GkPCy2Tswd9TZj1/yTgKEfMQEiAAhBBCZEoQAkveELdHYZ+tnQ5hBwrAAqbq1Gu6/F3CggodQghCYBIgAIQQQmRJEgBACiEwJIkAIAUSmBBEghAAiU4IQQIo9asDbUsbvYg0NDOnX6ZF+eYxMCUI+CgJEgBACiEwJIkAIAUSmBBEghAAiU4IIEEIAkSlBBAghgMiUIAKEEEBkShABQgggMiWIACEEEFlAgjzk+70ImH+yAEAw6fLf2f+D3wIA+fiyvgh3TjiFIxQAyH+5P2PZoyOjjE71bAIAwSUWoA1gKWngywCLTVWPAEBQT9DqIJaq+nr6WGyqesQA2hC8gaWqluctLDZVPWIAMU6Wg7nP79+8V7V+tHExgHRbdGjPXAZTvonRqZJNDKDomGjGeupq6wovFKITgicmJuof1xecLzAeMTK2zGgTM5kFFn2Jj4hn7CLYIiIjjBeMSclJwWHB2lVaWAPk5/eftn4bTB3v7e7teNEBF6PrnkAbqO37ruTQLgYQ1Lw7crflg4WdEbuzw9qxMWQju1/aKeYSgz6lZqRK92zBKkxGW/Cxsw8UBijndM7s3iiyZ4kA0sfqVZqYCstbKQLa1YiwBMHpL5suK1jJTFNLJEFQz579e2CS6kxhSm0sHUBApPhGcVR0lFJoXO0MDw4Pfh1Uqk2RlxjUACuYlD8sh7sbpepxtaNgiAQDgnrCdeE1rTUKLkQBCw0q+CJJPCBgBPd1MHcOxmxYeWAxUYIkXrpyyWwxpxxOWUw77scKu5N278TMNrwhK7te9uDeA1nLVYVFhAGRtKNpMOrPt6bDzCnkbngWIFfvp6amul92tzW1dbV3weOIvd8+8mPEMeaAf4cEBAbA09ba9Wt1W3WR2yJhgI+Nj1V8CHOH6ImA3PsnfNsjxiDhFCQ6QIAk4ExLBIgAIQQQmRJEgBACiEwJIkAIAUSmBBEghAAiU4IIEEIAkSlBBAghgMiUIAKEEEBkShABQggg8l9ITjYwKjepmgAAAABJRU5ErkJggg==",
"text/plain": []
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# second image in a batch\n",
"ims[1]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"# we'll use three operations\n",
"from einops import rearrange, reduce, repeat"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# rearrange, as the name suggests, rearranges elements\n",
"# below we swapped height and width.\n",
"# In other words, transposed first two axes (dimensions)\n",
"rearrange(ims[0], \"h w c -> w h c\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# we could use more verbose names for axes, and result is the same:\n",
"rearrange(ims[0], \"height width color -> width height color\")\n",
"# when you operate on same set of axes many times,\n",
"# you usually come up with short names.\n",
"# That's what we do throughout tutorial - we'll use b (for batch), h, w, and c"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Composition of axes\n",
"transposition is very common and useful, but let's move to other capabilities provided by einops"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# einops allows seamlessly composing batch and height to a new height dimension\n",
"# We just rendered all images by collapsing to 3d tensor!\n",
"rearrange(ims, \"b h w c -> (b h) w c\")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# or compose a new dimension of batch and width\n",
"rearrange(ims, \"b h w c -> h (b w) c\")"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(96, 576, 3)"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# resulting dimensions are computed very simply\n",
"# length of newly composed axis is a product of components\n",
"# [6, 96, 96, 3] -> [96, (6 * 96), 3]\n",
"rearrange(ims, \"b h w c -> h (b w) c\").shape"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(165888,)"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# we can compose more than two axes.\n",
"# let's flatten 4d array into 1d, resulting array has as many elements as the original\n",
"rearrange(ims, \"b h w c -> (b h w c)\").shape"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"## Decomposition of axis"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(2, 3, 96, 96, 3)"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# decomposition is the inverse process - represent an axis as a combination of new axes\n",
"# several decompositions possible, so b1=2 is to decompose 6 to b1=2 and b2=3\n",
"rearrange(ims, \"(b1 b2) h w c -> b1 b2 h w c \", b1=2).shape"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# finally, combine composition and decomposition:\n",
"rearrange(ims, \"(b1 b2) h w c -> (b1 h) (b2 w) c \", b1=2)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# slightly different composition: b1 is merged with width, b2 with height\n",
"# ... so letters are ordered by w then by h\n",
"rearrange(ims, \"(b1 b2) h w c -> (b2 h) (b1 w) c \", b1=2)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# move part of width dimension to height.\n",
"# we should call this width-to-height as image width shrunk by 2 and height doubled.\n",
"# but all pixels are the same!\n",
"# Can you write reverse operation (height-to-width)?\n",
"rearrange(ims, \"b h (w w2) c -> (h w2) (b w) c\", w2=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Order of axes matters"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# compare with the next example\n",
"rearrange(ims, \"b h w c -> h (b w) c\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# order of axes in composition is different\n",
"# rule is just as for digits in the number: leftmost digit is the most significant,\n",
"# while neighboring numbers differ in the rightmost axis.\n",
"\n",
"# you can also think of this as lexicographic sort\n",
"rearrange(ims, \"b h w c -> h (w b) c\")"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# what if b1 and b2 are reordered before composing to width?\n",
"rearrange(ims, \"(b1 b2) h w c -> h (b1 b2 w) c \", b1=2) # produces 'einops'\n",
"rearrange(ims, \"(b1 b2) h w c -> h (b2 b1 w) c \", b1=2) # produces 'eoipns'"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"## Meet einops.reduce\n",
"\n",
"In einops-land you don't need to guess what happened\n",
"```python\n",
"x.mean(-1)\n",
"```\n",
"Because you write what the operation does\n",
"```python\n",
"reduce(x, 'b h w c -> b h w', 'mean')\n",
"```\n",
"\n",
"if axis is not present in the output — you guessed it — axis was reduced."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# average over batch\n",
"reduce(ims, \"b h w c -> h w c\", \"mean\")"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# the previous is identical to familiar:\n",
"ims.mean(axis=0)\n",
"# but is so much more readable"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAAAAADH8yjkAAADw0lEQVR4Ae2ZT0hUURTGz5vUHFEhrcxpsFIrQoS0IM0/ERS6qZWQ5KJlQW2DdiLYojZF0KbaRFkEQYuoXSFqUZAgQYYWkaXVGKlhjiNjU9b43tx73v3uu+OMu3Hzzvfdc77fvDtv3jwZa5BW98+3uvFEWYaAX3f6xyPF1a0HDPudNstsi67cisVHNl8ud2aNCrMtOnlzOZ8m2vuNcp0mI0D3K6effp8dTwiDygQQeiAGRTtF5VmbAHrklKEfstYrE8AzFtHHtFaaACZYQlJvggkgygAzTGulCYB/GAu1iWzRBFDKZoJMa6UJoJElNDGtlSaA43JC9UZZ65UJIHBUzMjqEpVnbQKgztpEju/iloQwqIwAdL3D7iu9m+QN2/B2TbM9AxPzxdUtBw1etNRiCpCGkhH2qSczk1RvBuC5XfxGphpYGPs6Gfoeml5YiEQWrT9ZuX5/XmkwGKwsUnUzD19Fe1inQgZq6/d73VpTAiwxsxva6iwF27FSvYqivWceOmGqIlXAUmaZKtfx0gCocMJUReqAkgJVruOlDihyspRF6oC3l5TBtpk6gG6P2GGqYxoA1B1TJS976QAMP1oRYHBwn2ZOWrrGn/2EVc0ZvH4p9Ellm6SIvjxmhiA1gHtCm1yeaJY13WdakBjw84nQxsoL7P42jC8kDOjVbGxOAyM+ZTohNYBEk7s6xKw+phMSAmLCP36Jdrvi30ajM/YKP0LAhzBvFXVAFP/qYW7YGgLe2B3q4zpmQwD80v/EEkR5RBTx+rPbijvwDL6hCbUP2yEgpA5C7iRagADte+xOm3dbcQcCImhC7cN2CFhUByEXfuwhYC2KUvuwPV2AXDWXCALy0YTah+0QUKIOQi5sh4BNKErtw3YI2KYOQu5WtAABu9DEkr/DvVbltuIOBJTBt43o9Hn+PLpmZ9IAqw6NEI203mDX/W4/6oZnQE1ohOg5VbbIqzWyFBQGNOcIbXI5NBebkp29shQU/MKhwsP4ibBrw4CQQZSPzwAD6BgG8EemehyDt4iq+MOP9KIl8UJSktAA6JTUqROzeFEHwFOulXcuxzZ0gGm7yfs4Clt0APyyXHG4NU2AlZ3Be9cLhcaKAItjMM+1gN8uzRaFFXdlV7JtfLQLftQACs/xZqyz59Aa/oyjCYUfaO9QuHFLcwZwxrXQiPONfwkk2j4ViUZ9vpifwlZeXnjeyi9YX15RWWO5eJJhvkVXi6VBU5GWLdLBMgDd7vxfy2xRZos8d8CzIXMVZbbIcwc8G/BvOJ6jZg2rfpn+BUFLlGkzaXw/AAAAAElFTkSuQmCC",
"text/plain": []
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Example of reducing of several axes\n",
"# besides mean, there are also min, max, sum, prod\n",
"reduce(ims, \"b h w c -> h w\", \"min\")"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# this is mean-pooling with 2x2 kernel\n",
"# image is split into 2x2 patches, each patch is averaged\n",
"reduce(ims, \"b (h h2) (w w2) c -> h (b w) c\", \"mean\", h2=2, w2=2)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# max-pooling is similar\n",
"# result is not as smooth as for mean-pooling\n",
"reduce(ims, \"b (h h2) (w w2) c -> h (b w) c\", \"max\", h2=2, w2=2)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# yet another example. Can you compute result shape?\n",
"reduce(ims, \"(b1 b2) h w c -> (b2 h) (b1 w)\", \"mean\", b1=2)"
]
},
{
"cell_type": "markdown",
"metadata": {
"jupyter": {
"outputs_hidden": false
},
"pycharm": {
"name": "#%%\n"
}
},
"source": [
"## Stack and concatenate"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'list'> with 6 tensors of shape (96, 96, 3)\n"
]
},
{
"data": {
"text/plain": [
"(6, 96, 96, 3)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# rearrange can also take care of lists of arrays with the same shape\n",
"x = list(ims)\n",
"print(type(x), \"with\", len(x), \"tensors of shape\", x[0].shape)\n",
"# that's how we can stack inputs\n",
"# \"list axis\" becomes first (\"b\" in this case), and we left it there\n",
"rearrange(x, \"b h w c -> b h w c\").shape"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(96, 96, 3, 6)"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# but new axis can appear in the other place:\n",
"rearrange(x, \"b h w c -> h w c b\").shape"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
},
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# that's equivalent to numpy stacking, but written more explicitly\n",
"numpy.array_equal(rearrange(x, \"b h w c -> h w c b\"), numpy.stack(x, axis=3))"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(96, 576, 3)"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# ... or we can concatenate along axes\n",
"rearrange(x, \"b h w c -> h (b w) c\").shape"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# which is equivalent to concatenation\n",
"numpy.array_equal(rearrange(x, \"b h w c -> h (b w) c\"), numpy.concatenate(x, axis=1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Addition or removal of axes\n",
"\n",
"You can write 1 to create a new axis of length 1. Similarly you can remove such axis.\n",
"\n",
"There is also a synonym `()` that you can use. That's a composition of zero axes and it also has a unit length."
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(6, 1, 96, 96, 1, 3)\n",
"(6, 96, 96, 3)\n"
]
}
],
"source": [
"x = rearrange(ims, \"b h w c -> b 1 h w 1 c\") # functionality of numpy.expand_dims\n",
"print(x.shape)\n",
"print(rearrange(x, \"b 1 h w 1 c -> b h w c\").shape) # functionality of numpy.squeeze"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAABgCAIAAAB6y1p+AAAfBElEQVR4Ae2dB1QU1/fHfxTp4IpUqSpdBERUFAVRREFQUYgVC0aTKLYYNbbYY4wtthhTJEZjFxWiIDYkCBoEUcDQpEtTem/6f7/D73D8LyzcXWZmZ5fr4Xhm3nzfffd+ZuHuzLy57z//wX9IAAkgASSABJAAEkACSAAJIAEkwAwBCWaGwVH4ImBsZjxnyZwx48foGujKycuVvC1JiEsIvRF67c9rTY1NfJlCMRJAAkgACSABJgjIyMrs/XFvXkte/of89j8x2TEOzg5M+IFjIAEkgARYTwCvwFh0iuTk5C7fv2w3yq4Tn1paWtYuXnv5zOVONHgICSABJNATCGACY9FZPnHuhNdcry4dampq8h7rHRMV06USBUgACSABMSaACYwtJ9dmmM3tf24DvYmPiXcf7g4UowwJIAEkIJYEJMUyKlEMau6SuXC3SbaztLGE61GJBJAAEhA/ApjA2HJOHcbxNzvDcYIjW1xHP5AAEkACwiCACUwY1DsaU0dfp6Nmnm1khj3PY3gACSABJNADCGACY8VJlleQ79WrF1+ucFQ5fOlRjASQABIQMwKYwFhxQutq65qbm/lypbKiki89ipEAEkACYkYAExhbTmhBXgFfruRl5/GlRzESQAJIQMwIYAJjywmNvB/Jlyt/3/ubLz2KkQASQAJiRgATGFtO6Plfz8NdIaURXzx7AdejEgkgASQgfgQwgbHlnMY+iQ26FATxhjwt27ZmG0SJGiSABJCAGBPABMaik7t60eq4p3GdO/T+/fv1S9c/iXjSuQyPIgEkgASQABJglACp57v/5/28qtHH5saOcRnDqEM4GBJAAkiArQSwFiIbz4yJucncpXNHjxutY6AjLy//3/XAnieE3gy9dvZaY0MjGz1Gn5AAEkACSAAJIAEkgASQABJAAkgACSABJIAEkAASQAJIAAkgASSABJAAEkACSAAJIAEkgASQABJAAkigJxIQ5ixEWRmZEba2jvb2VubmxgMG9NPUVFJUJI119fW1dXXvSkszcnIys7NjXrx4/OxZRlZWTzw/GPNHBDQ1tfX1++vqGujoGLT+r6amLi+vICdHpmr+93/yIyEhUVdXW19f9+5dcV5edk5ORnx8TGxsVFZWxkeWesSmjqHhUGdni6FD9U1MdAcOVOZw5BQVJSUl62pqaquqCrOzc9LT016+jA0PT42Pf//hg3hDkZOVMzUwNdA20NHQ0dPU01HX0dXUVe+jLi8rT34U5BTk5eRlpGXqGsinp7a0sjS7IJv8PE95Hv0yOjE9sbmFv1rbYgDTyEjP3n6whcUAMzNDbW01TU1VDkdZTk5WVrZXU1NzTU19TQ35KNVVV9cSUq9f55Gf9PS8pKT0oqJSxsIXTgKb5Ow8d/r0aZMmkYwFDDUtM/NSUNAfly6liWYm09LVisvt4iVlIIo2medIT1K/o21XzDZIKjI1HWRtPczKytbCwtrcfLCKCkfgGNPTk2/cuHD+/OnCQjEvgtzP0NDd19d93jwDExMgroqSkruXLwefOZP49CmwC/tlygrKI61GjrAcMcRsiLWJtaG2IUnegrldUV1xM/zmpbuXQqJCPrwX80w/duzQmTNdPTzG6OpqCoYrKys/IiIuNDQ6JCSqvLxSMCPAXowmMPInab6Pz4bly82NjYH+cclIHYprt25tP3ToVUoK1yGW72ICA54gkqUWLPhi1KixQ4eOVFJSBvYCypqaGi9cOH3gwDZyfQbsIkKyAebmizdvdp01S1JKSjC34yMjf9658+ndu4J1Z0MvjjLHf6b/5NGThw0aJiUpIAdegaTnph84e+D0zdNNzU28NCLa3quXtJ/f1DVr5pqaGlAVQmNj0+3bj3/66cqdO3RVDmIugY0YMuTE3r1Dray6T6epqengqVM7Dh6sb2jovjVmLGACA3K2trYLCYkBigWTlZWVbNrkf/PmRcG6s7CXnILCF7t2zVm1SuDU9XFQj4KC9vn7F+XmftwoKtt2FnYxZ+n9/CS+Tlz+3fKIuAhRYdKlny4uI44f30Bh6uIa0c9vR0BAEFcjJbsCXlPzNTa58NqyevXjoCBKshcZmixe/LW//983buhqafHlCYqRACHQp0/fkycvrF+/SzxomA0Zcjkxcd6XX1KSvQgTpylTriYluXh7iwcfyqOwHGgZ/nP47uW7JSSZuwCgPIpWgxISkt99tyIs7AR92YsMlJaWQ5P/tCcw8mA9+I8/dq1fLyXobQ1ekdtZW8eEhpoOHMhLgO1IoBMCq1dv2bjx204EInFo0uzZAVFROv37U+utgrLyvitXlu/eTa1ZsbFGvpRv9tsc/EMwmRsiukFJS0tduLBnw4aFJBxao0hMfE2TfXoTGKd37/tXrkweP54m77U0NIh9Q319muyjWfEmsGLFRh+f+aIb4zQ/v13nzsnI0fU31G/z5vXHjokuH7o9n+wwOfiwCOewU6c2k/kadFPKyysqL6+iaRQaExiZb0nmNY0cOpQm11vN6mhpBQUEkCLutI6CxsWVwO7dx7S0dEUxuomzZm359VeBZ9YBQ57p77/q+++B4h4ocxnh8ufuP0Ux8CVLvMisDQY8p+/yizhPYwI7e+zY6OHDGQA02Nz8yM6dDAyEQ4gfAWVlle3bD4hcXBZ2dttOn6b7zk8rlvnr1nnMF+HrVLpP7vRx079e+DXdo1BrX0ND9eDBL6m1ycuaSCawZYsWeXt48AqJ8val8+aNGjaMcrNosCcQ8PT8xMyMgsmxjLFSUFL6/upV8gIuYyNuPnXKwNSUseFEbiAyocPG1EaE3N6wYYGysgIzDicmptM3EC1XYGZGRge2bqXP6Q4tH9+zp8N2bEQCnRMg1zGLF/t3rmHV0dUHDmgbUPayDiQ08piNXPBJ0vyoH+IJOzXkhbNftvxC9+1cqmKXlZVZtGgKVda6tJOQIGoJ7MiuXWTyYZeBUSsYYmnpMWECtTbRWg8hMHXqLFKGSiSCNbO1nb50KfOuWo8aNXnBAubHFZURyftnvu6+IuHtuHHD+vRRYcZVUnri1atM+saSptw0ySKuTk5ws5VVVddu374bEfE8IaGkrKy8srK3kpJa376WZmbu48d7ublxVKCs133xxV9sLSJQmFfYT6IfBEsftT5Jb5Mgyh6u+eab1a9fpxQU5JeVFdfV1ZMSiOQrsJqahp6eoYuLx/Tpc7S0dICISMkPB4ex9++HAPVClK3ct4+vR18NdXV///VX2MWLWcnJxfn5TQ0N6jo6mnp6jp6erjNnqvcDfSZb4126bVvo+fNNjY1CDJ/CodccXJOak1pcWlxSUUKq+lXVVpEKCcqKyib6Jo62jvPc51kZ83djeZPfprO3z5I/2RQ6SYcpUiwKbra0tPLChTuRkc9TU7PfvCkmJRBra+ulpCTl5GSUlBR1dNR1dTUGDzaysTF1dLRVU+NwWc7IeFNfT2O5Ceqn/z8LDQW+sNzS0rL/5Ml9J06UV1Rwhd22Sybib1m1as3SpcDLc+NRo9JFs1hiW8jwBCaWtRDhlThsbLSLiwvbuHFtkNkZe/Yc9/aGfin+7bejW7eu4jLCtl0re/uA6Gi4V9F37uxYtOhtQUGHXaSkpUlO8tu4Ef4G9E4/v5sBAR1aY0kjvBKHtqt2YQnPzw8JZ/r46Se/PqmhqgEPbfpX068/vA7XC0V5+/ZRNzcHyNCkfMbKlftJuV6ImGhsbc2mTXOeNm0sSWmtXW7cCPfyWgvsLoCM4mdgzqNHA7NXVXX1ZF/fjd9+20n2IvGQo1/t3Om9ZAmwatSsadMEoIBdxI9AVVXlqlULIiLuAkMbPNgWqBSijExqh49+9sAB/0mTeGUvYqelufnk1q2rPT3ft7QAzXovWwZUioEs8H6g3Tw7Uv8QHovfVD+4WFhKHR1QSg4KekRKQMGzFwknLi75m29OWlnNHDhw6pdfHiYlfePjU2gNk+IEttIPdP4+fPgwz9//Tng4MLbrISHLNm6EiMktR4gMNT2BAPmYbdjwGfkfEqyJiQVEJkRNb1XV8T4+QAfuX7v2w7p1EPHjkJAj69dDlERDpu+b2tgAxWIgyy3KdV3uSqrRA2Nxc3BT56gDxcKSKSrKQ4Y+fz4UIutQk5GRd/jwOSenJTt2/NyhgKpGKhNYbxUVt3HjIJ798uefQWFhEGWbJuDixbBHj9p2eW3YDBpE3OB1FNt7GoHs7MzHjx9AouZwVMnzM4hSWJqxU6f2kpGBjF5ZWrpz8WKIslVz7tCh5Lg4oH7cjBlApXjIMt9krvsB9FWAxEumI04YOYHlgTc0NEI8HDhQDyITrobKBEbW9yLLUXYZT0Nj47aDB7uUtRfs//HH9o1cLeRRmQMjb09zjYu7rCVw794toG9GRuZApVBkY728gOP+tnt3Ne/nyh0a+QVcCoDM/ujQghg3BgQFpGanAgOcaD8RqBSWDFjY6auv5hkaQqdBCSsWKhPYBNjkw9v37xcWFQkQcHh0dHVNTZcd7ahYsaXLUVAgKgRiY6GzHgwNB7A2KPIOlp2zM8S92urqKydPQpQfa8Jv3izMyfm4hde2ibU1R02N11GxbCfLMe85vQcYmoMNaH4E0BodsuTkLIhZMtX+yZPfXV3tIWJhaahMYA52dpAwyAMtiKy9prm5OS4hoX07V4sFeCFaro64K5YEkpLigXEpK/cGKpmXDbC0JAU4IONGBAc31NdDlFwaksO4WnjtkidhvA6Ja3vgg8D6RhDVAToDyGLQbObw9Gki0D1NTdU7d07cuHFwxAhLYBeGZZQlME11dUM90D3TmBcvBA6y6O3bLvsKvNxzl5ZRIIoE6uvryQqWEM8VFUEZAmKKcs0gcM54cPWqYKOT18WAHXtgAquurQ55DPrmTd7SG2Q0CEhSKDIyvZCvl9WmTh375MmZZ8/Off65t6oqu77kSVNF0Ay8Lte/gLkY3fGK1KfvTnfsK34ECgvfkEUsu4yLvM7cpUZYAn3wfYWk2FjBnEyNjwd21DMyAirFSfbw2UMvZ9BjSENtwycvn7A29sLCkkuXwmbPnsSXh0OHmpOfo0fX3b//z/XrD2/eDC8qKuXLAh1iyq7A2LMolyqHQ5ZspgMW2hRRAqWloCswBQVF1gaoBSt+SOZuFGZnCxZFaXFx+bt3kL5aPXIFvoS0rp9ftNLrp94PglGImk2bTgCncnA52auX9KRJo8hCYm/e3AkL+3HhQk8VFWH+1lCXwGD3D7lw0LFLLuHVVFXpsIw2RZRAY2MDxHN5eWH+KnbuoaaubueC1qPZqdDJch1ay01P77Cdq1ED5gxXL1HffZEGffahrabN8mCzsvIXLNgGfEWyw1hINakJE0YEBGwvKrp39er3Xl7jSI3gDpW0NlKWwPr0ZtG9USUGV5qg9fSgcUoINDSAHr/zVWOQEsfgRoAzOKrLy+E22ytrKivbN7ZvkVdkb6Zv7y1VLWWVZU3NTRBriiz+JtTmP3kStnPnL227Am+QoogzZowPDNyfm3t7x47PybwPgU0J0JGyBKbAppyBCzQL8FEQ4y7AKzA2E5BTUIC4Vw3LQLxM1VRV8Tr0cTvQmY+7iMc2KfgLCUReVh4iE7pm+/ZTK1Z839LynhJP1NX7fPPNkuzsW8eObeBwVCix2aURyhIY8+undBKbrKxsJ0fxEBIQOQLSsMe6pPZ8d0IDdgcWBOmOJ+zsW1FVAXFMhJ7BHz9+ycNjVUEB6NknJHZyI9Hf/5PU1EBmlhyjLIFBYkMNEkACghEAvtrVzWWagTcqgXlOsEjZ3At4k5ksy8LmKLh8Cw2NMjX1OnToXFNTM9chgXfJ1djp09v++GOnjAy98+koS2C13fvqJzCpDjs2NoAe2nfYFxuRAAsJAHMGMAPxClARVkeUrL3Gy4J4tyspKEECbIBNGoKYYkZTVVW7du1hCwvv48cv81V+vnP3fH0nh4Wd4HBofDuFsgRWJ9DL/53HL/DRxmbKvkoI7AN2RAIUEgDWNlTmcLozKLB7N6eKdMdD4fYFzs4gy2MK10/BRk9Pz12xYp+envuqVfujol50Z45imwNOTkMvXPi2bZfyDcoS2LtS4b/U1kanBlAysU3Mto0P70HLf7DNbfSHVgJFeXkQ+/rGxhAZL42BqSmvQx+3A535uIsYbJMCUcDZGcVlxaIbL3k/7OjRiw4Ofrq67qtXH4iM7G4mI++NbdiwkCYglCWwbNgvGE1hcJkt6d5kYi5rDO/yVeWFYd9wOGERAFbaVVFVVdXUFMxJUl8DOD8e6IxgbrC2l6khKLsT/4tLRTiBtfHPzy8+cuTCmDF+Ojpuy5fvu3fvqcAPyXbvXta2RnObfUo2KCsllZWbC3RIy9oaUtIQaE38ZE2N0CfAUtJS4hc+RtQhgcxXrzpsb99obmtL1qhs395ly6Bhw7rUtAqykpOBSnGSGetDr26zCrLEKfCCgrc//niZ/PTureTuPtrLy9nDY4y8vCw8RmlpKTLD3sdnA7wLUEnZFVhiSgpwyP49sg4NEA6RNdY3AsWKSopAJcpEncC/4AUnx0yeLFiwLuDlnpNiYgQbQqR7Odk6Af1PyYb+MQQaZImsoqL6woXQTz7ZoKnpsmTJrhcvUuGOkYrAdLwcRlkCKysvT83IgMQzcexYiKzHalret1RXVUPCV9NQg8hQIwYEslNSgPM4HKdMESBeBWVlBzc3SMeW5mb48s0Qg6KicR/tDnGVvOycX5wPUYquhsxa/PXXGzY2s+fM2QysqUiKKE6caE95yJQlMOJZFOx72bIFC5RhKxtRHq2oGCwvLYe4amoJvSkPsYYalhN4cvcuxENNPT1n8NrNbQbnrF4tIyfXttvJRnxkZH1tbScCsTw00nqknqYeJLSYpB50eUouyBwdP62rA722ZG1tAgHIl4bKBBYUFgYZW0NN7eS+fRBlj9UU5RdBYh81dhREhhrxIPB3cDAwkCVbtwKVrTKywvL8r74CdokICgIqxUm2efFmYDhRL6KASmHJJCSo/LOfkJB+6tQ1SCz9+/eDyPjSUBlJyIMHVdWge19zvbx+O3RIhAqu8MW0++K87DyIEZthNkZmRhAlasSAAMkcjbC3LU2HDJm/bh0wZEkJiR0BAcBXmMkU2XuBgUDLYiNzGeEy2WEyMJwHzx4AlcKSjRw5OC3txtatnxoYaFHiQ3x8CsSOsjLoNXCIqTYNlQmsvqHhMvhLot+sWTEhIY723borKikl5erkdObIkW1r17aFJAYbGWmgp4kk0m0HtolBvBgChEBlefndK1cgSqJZsXcv8JnW2iNHRnt4AM1Gh4QIvN4YcAi2yQz7GV7cexHoVUV1ReTzSKBYWDIrK2MjI72dO7/IzPzr4cOfyTrL3Swhb2SkL6xYqExgJIYDP/0Ef3/b2sLiUWDg3zdueLm58VULuLeKyvTJk3//4Yfily/vXLgw38fHdvBgYRGkY9zkhGSg2fGTx+/9cW+X17LS0tJOrk77f95/JvgM0DLKWEjg0vHjQK/Id7sfgoO/2LVLSlqaVxeyxtjJe/dmrVjBS9C+nUymbt8ooi1H1x+1HGjZufMT7SdG/x7dt3ffzmVtR4P/DgYuudLWhfkNS8v/3bYhpR3Hjh168uTG/Pw7jx79snLlLJLY+PXHzc1hzZo5kF7A6R4QU20anh/uNgVfG8lpaddDQqa7u8N7jR4+nPyQq7f7kZEx8fGvUlNT0tLelZfX1NZW1dQoyMlxlEmBG05fDmeQufkwKys7a2tzY2Mpqf/3CpTpwIHwEdmvfP7Pc7iTC75YQJLTmRNnIh5EFOQUVFVUySnIKaso6+jr6BrqWlhZ2NrbkpuNrXPuqyqr4JZRyTYCSf/88/jWLQfYRHmSwz7dsmWqn1/YpUsRwcHkyultfn4vWVmNfv36m5u7zprl6OkJnLjRyuHVs2eRt2+zjYnA/viQ9wZcfF5lvLoVeSsuOe5l+svikmJyCUXqRWmraw+3GD7Pfd744eOBBXxb3Th987TA/jDW0dqa+4U2SUlJR0db8nPkyLrs7AJSfePFi5SkpIy8vKL8/LfV1aRQYAPRyMhIKyjIk9qGWlp9DQy0bWxMXF3tbWygU8kyM/Moj1GCcouG+vqvwsP5uqLqvg/Nzc3yAwaQ/7tviiUWol9HGwwwoMMZWx3bwvxCOixTYtPa2i4kBDSPy8ZGu7gYFMhPP12cMmVml+5dvnxm9eqFXcqEKzC1sTkXG0v+mjDvxvJJk57cucP8uHyNaGdhF3MW9PnhyyxEnJaTZuJF/UQ7yNB8acrKwmktsMvLmalTvySraPI6Klg79b8GWTk5u48cEcwbgXuRW2QD9Pi++BV4OAY6hgWF0TSKySAR+B2jKXYxMJsSH3/p2DHmAyHrxrM/ezGP5eMR9/6+9+Nddm7r6WkKJXs1NjY9ehRLORPqExhx8bvjxx9ERlLua+cGTY3+d2O3c5moHL1yBvq4nt+ITCwwgfHLjF3645s25b1+zaRPlaWl+/z9mRxR5MZKz00/+9dZ9rvd9gCMYVeDgyNIIQ/KB6Ulgb1vaZm9bFnOmzeUu9uJQTFLYInxiU8innQSr8CHjM2574ALbAo7CoUAeY943YwZdUwtuUB+nTfOnl1aBHo3UShA2DCo/3f+zS0i8AiDTEEUCq59+87QMS4tCYw4WvzunbOPz5tC0CMKSgITs3kchMn+bfspIcNlBK/AuICI4m7qixff+Poys3DBkXXrnsBqFIgiSUp8Pnvr7J0nbH862Brp4MFCSGABAUExMUmUoOYyQlcCI8NkZGU5T5+enpXFNSRNu+KXwKLDo6+evUo5LkxglCMVisEH168zkMNObd9+7vBhoQQoKoMmpCd8/u3nouKtlRXTj1pIqY6VK2n5Lk6Y05jAiPW0rKxhbm53wsMZOLvil8AItC0rtqQnp1NLr0/fPn3V+1JrE60JhUDI+fNf+/jQdC+RXN4d3bDh5x07hBKaqAyaU5gzZc2U2vpakXCYVNQ1NaVlbjOv8F+9ynB1XVZdTRcfehMYiaq8omLSnDnLNm2qrKriFSQl7aTEIkdFhRJT7DFSWVHp6+6bn5tPrUvGFkK4jUBtCGitlcD9wMBFo0blplP8LaeyrGyNp+eZ779Hzp0QeJ332mmJU1Z+VicaVh1SUlLgaw2Ubjp/40b4yJELCwtLummnk+60J7DWsU/+/ru5k9Mvf/7Z1NTUiTfdPCSWF2HZmdke9h4vY192E05bd7JgppKiUtsubog6gbSXL2dZWZ07dIjMtqAklgeBgd4WFuL0zjIlWLiMBEcE282zE6HsRfwvK6scPny+vf0C8lCqpqaOKyIKd3NyCslKK15eaysrayg0294UQwmMDJxfWLh03TpjB4dDp06RKR7tXRG45W1Jya/nz5PrvNiEBIGNsLkjee/Yc6TngW0H6mq79ZkjV3KHdh4aZjDs3u17bI4XfeOXQH1d3eG1a2cOHnz38mV4Lbf2o5ClUj4bN45McSxhcPpVezeYabn79K5g8wYL3hX4bvUldw7Lq8qZcZXaUZ4+TfTz26Gt7bp48a6IiLjufGDaO0YK+3722R5j42lkpZX2RylvkaDcIsQgee94krOzh4sLKcUr2ALNDY2N0c+ePYyKIi+cRcXGUvXdE+K8EDVkBctPV346w3cGKRMFdyM3K/feX/dCAkMehz+m9sMK9wGuxEoccFYdKvWMjKYsXOju66sFXvqc3DAkmS8oICDx6dMObYpQI7wSh7artoSkxKdTP/V28bYytoLESOpOHb98nBQUFZWHXpCg9PW1vL1dPD0dHRysyUMySBcuTUvLe5K3bt2KvH79IbAyPZcFgXeFk8A+dldPW9vG0tJ60CCTAQN0tLR0tLX79O5NKlGRH1KFjFRErCY/NTVkoRbyYllyOpnTkE4qLr78919SPvFjOz1q29rOmlSQtBpqZTjQsJ9ePyUVJXkFeZKcqiurSbXDd8XvMlIzXie/JrDiYuIKcgt6FBwMtpWAoZnZUCcnM1tbfWPjfv37K5FfK0VFUoOKTPqora4uzMnJSU0ltx/jIiLICsvMzMhn4NTwlcAKS/73ng9ZrNLF3sXWzNba2FpfS5+jzFFSUKpvqCfLK+cV5f2b+W/sv7GhUaEp2SkMhCCsIZSVFYYMMSMVDgcNGkgKdujoaGhoqCooyMnK9pKR6UWyFKmmUV/fSGryvntXXlRUkpmZn56em5CQ9s8/SbW19UJxW/gJTChh46BIAAmIJQHBEphYougJQTH3DKwn0MQYkQASQAJIgDECmMAYQ40DIQEkgASQAJUEMIFRSRNtIQEkgASQAGMEMIExhhoHQgJIAAkgASoJYAKjkibaQgJIAAkgAcYIYAJjDDUOhASQABJAAlQSwARGJU20hQSQABJAAowRwATGGGocCAkgASSABKgkgAmMSppoCwkgASSABBgjgAmMMdQ4EBJAAkgACVBJABMYlTTRFhJAAkgACTBGABMYY6hxICSABJAAEqCSACYwKmmiLSSABJAAEmCMACYwxlDjQEgACSABJEAlAUxgVNJEW0gACSABJMAYAUxgjKHGgZAAEkACSAAJIAEkgASQABJAAkgACSABJIAEkIAoEvg/u1KxSzV+aO4AAAAASUVORK5CYII=",
"text/plain": []
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# compute max in each image individually, then show a difference\n",
"x = reduce(ims, \"b h w c -> b () () c\", \"max\") - ims\n",
"rearrange(x, \"b h w c -> h (b w) c\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Repeating elements\n",
"\n",
"Third operation we introduce is `repeat`"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(96, 5, 96, 3)"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# repeat along a new axis. New axis can be placed anywhere\n",
"repeat(ims[0], \"h w c -> h new_axis w c\", new_axis=5).shape"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(96, 5, 96, 3)"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# shortcut\n",
"repeat(ims[0], \"h w c -> h 5 w c\").shape"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# repeat along w (existing axis)\n",
"repeat(ims[0], \"h w c -> h (repeat w) c\", repeat=3)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": []
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# repeat along two existing axes\n",
"repeat(ims[0], \"h w c -> (2 h) (2 w) c\")"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
gitextract_7syaalsv/
├── .devcontainer/
│ ├── devcontainer.json
│ └── einops.Dockerfile
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── extensions--introducing-new-operation---improve-notion.md
│ └── workflows/
│ ├── deploy_docs.yml
│ ├── deploy_to_pypi.yml
│ ├── run_tests.yml
│ └── test_notebooks.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CITATION.cff
├── LICENSE
├── README.md
├── docs/
│ ├── 1-einops-basics.ipynb
│ ├── 2-einops-for-deep-learning.ipynb
│ ├── 3-einmix-layer.ipynb
│ ├── 4-pack-and-unpack.ipynb
│ ├── README.md
│ ├── pytorch-examples.html
│ ├── resources/
│ │ └── test_images.npy
│ └── utils/
│ └── __init__.py
├── docs_src/
│ ├── CNAME
│ ├── api/
│ │ ├── asnumpy.md
│ │ ├── einsum.md
│ │ ├── pack_unpack.md
│ │ ├── parse_shape.md
│ │ ├── rearrange.md
│ │ ├── reduce.md
│ │ └── repeat.md
│ ├── css/
│ │ ├── codehilite.css
│ │ └── mkdocs.css
│ └── pages/
│ ├── projects.md
│ └── testimonials.md
├── einops/
│ ├── __init__.py
│ ├── _backends.py
│ ├── _torch_specific.py
│ ├── array_api.py
│ ├── einops.py
│ ├── experimental/
│ │ ├── __init__.py
│ │ └── indexing.py
│ ├── layers/
│ │ ├── __init__.py
│ │ ├── _einmix.py
│ │ ├── flax.py
│ │ ├── keras.py
│ │ ├── oneflow.py
│ │ ├── paddle.py
│ │ ├── tensorflow.py
│ │ └── torch.py
│ ├── packing.py
│ ├── parsing.py
│ ├── py.typed
│ └── tests/
│ ├── __init__.py
│ ├── run_tests.py
│ ├── test_einsum.py
│ ├── test_examples.py
│ ├── test_layers.py
│ ├── test_ops.py
│ ├── test_other.py
│ ├── test_packing.py
│ └── test_parsing.py
├── mkdocs.yml
├── pyproject.toml
└── scripts/
├── convert_readme.py
├── pytorch_examples_source/
│ ├── Pytorch.ipynb
│ └── converter.py
├── setup.py
└── test_notebooks.py
SYMBOL INDEX (422 symbols across 26 files)
FILE: docs/utils/__init__.py
function display_np_arrays_as_images (line 7) | def display_np_arrays_as_images():
function guess (line 37) | def guess(x):
FILE: einops/__init__.py
class EinopsError (line 8) | class EinopsError(RuntimeError):
FILE: einops/_backends.py
function get_backend (line 22) | def get_backend(tensor) -> "AbstractBackend":
class AbstractBackend (line 65) | class AbstractBackend:
method is_appropriate_type (line 70) | def is_appropriate_type(self, tensor):
method from_numpy (line 74) | def from_numpy(self, x):
method to_numpy (line 77) | def to_numpy(self, x):
method create_symbol (line 80) | def create_symbol(self, shape):
method eval_symbol (line 83) | def eval_symbol(self, symbol, symbol_value_pairs):
method arange (line 87) | def arange(self, start, stop):
method shape (line 91) | def shape(self, x):
method reshape (line 95) | def reshape(self, x, shape):
method transpose (line 98) | def transpose(self, x, axes):
method reduce (line 101) | def reduce(self, x, operation, axes):
method stack_on_zeroth_dimension (line 104) | def stack_on_zeroth_dimension(self, tensors: list):
method add_axis (line 107) | def add_axis(self, x, new_position):
method add_axes (line 110) | def add_axes(self, x, n_axes, pos2len):
method tile (line 117) | def tile(self, x, repeats):
method concat (line 121) | def concat(self, tensors, axis: int):
method is_float_type (line 126) | def is_float_type(self, x):
method layers (line 131) | def layers(self):
method __repr__ (line 134) | def __repr__(self):
method einsum (line 137) | def einsum(self, pattern, *x):
class UnknownSize (line 141) | class UnknownSize:
method __floordiv__ (line 144) | def __floordiv__(self, other):
method __eq__ (line 147) | def __eq__(self, other):
method __mul__ (line 150) | def __mul__(self, other):
method __rmul__ (line 153) | def __rmul__(self, other):
method __hash__ (line 156) | def __hash__(self):
class NumpyBackend (line 160) | class NumpyBackend(AbstractBackend):
method __init__ (line 163) | def __init__(self):
method is_appropriate_type (line 168) | def is_appropriate_type(self, tensor):
method from_numpy (line 171) | def from_numpy(self, x):
method to_numpy (line 174) | def to_numpy(self, x):
method arange (line 177) | def arange(self, start, stop):
method stack_on_zeroth_dimension (line 180) | def stack_on_zeroth_dimension(self, tensors: list):
method tile (line 183) | def tile(self, x, repeats):
method concat (line 186) | def concat(self, tensors, axis: int):
method is_float_type (line 189) | def is_float_type(self, x):
method add_axis (line 192) | def add_axis(self, x, new_position):
method einsum (line 195) | def einsum(self, pattern, *x):
class JaxBackend (line 199) | class JaxBackend(NumpyBackend):
method __init__ (line 202) | def __init__(self):
method from_numpy (line 210) | def from_numpy(self, x):
method to_numpy (line 213) | def to_numpy(self, x):
class TorchBackend (line 217) | class TorchBackend(AbstractBackend):
method __init__ (line 220) | def __init__(self):
method is_appropriate_type (line 227) | def is_appropriate_type(self, tensor):
method from_numpy (line 230) | def from_numpy(self, x):
method to_numpy (line 237) | def to_numpy(self, x):
method arange (line 240) | def arange(self, start, stop):
method reduce (line 243) | def reduce(self, x, operation, reduced_axes):
method transpose (line 260) | def transpose(self, x, axes):
method stack_on_zeroth_dimension (line 263) | def stack_on_zeroth_dimension(self, tensors: list):
method add_axes (line 266) | def add_axes(self, x, n_axes, pos2len):
method tile (line 273) | def tile(self, x, repeats):
method concat (line 276) | def concat(self, tensors, axis: int):
method add_axis (line 279) | def add_axis(self, x, new_position):
method is_float_type (line 282) | def is_float_type(self, x):
method layers (line 285) | def layers(self):
method einsum (line 290) | def einsum(self, pattern, *x):
class CupyBackend (line 294) | class CupyBackend(AbstractBackend):
method __init__ (line 297) | def __init__(self):
method is_appropriate_type (line 302) | def is_appropriate_type(self, tensor):
method from_numpy (line 305) | def from_numpy(self, x):
method to_numpy (line 308) | def to_numpy(self, x):
method arange (line 311) | def arange(self, start, stop):
method stack_on_zeroth_dimension (line 314) | def stack_on_zeroth_dimension(self, tensors: list):
method tile (line 317) | def tile(self, x, repeats):
method concat (line 320) | def concat(self, tensors, axis: int):
method add_axis (line 323) | def add_axis(self, x, new_position):
method is_float_type (line 326) | def is_float_type(self, x):
method einsum (line 329) | def einsum(self, pattern, *x):
class HashableTuple (line 333) | class HashableTuple:
method __init__ (line 336) | def __init__(self, elements: tuple):
method __iter__ (line 339) | def __iter__(self):
method __len__ (line 342) | def __len__(self):
method __getitem__ (line 345) | def __getitem__(self, item):
class TensorflowBackend (line 351) | class TensorflowBackend(AbstractBackend):
method __init__ (line 354) | def __init__(self):
method is_appropriate_type (line 359) | def is_appropriate_type(self, tensor):
method from_numpy (line 362) | def from_numpy(self, x):
method to_numpy (line 366) | def to_numpy(self, x):
method arange (line 370) | def arange(self, start, stop):
method shape (line 373) | def shape(self, x):
method reduce (line 388) | def reduce(self, x, operation, axes):
method reshape (line 391) | def reshape(self, x, shape):
method transpose (line 394) | def transpose(self, x, axes):
method stack_on_zeroth_dimension (line 397) | def stack_on_zeroth_dimension(self, tensors: list):
method tile (line 400) | def tile(self, x, repeats):
method concat (line 403) | def concat(self, tensors, axis: int):
method add_axis (line 406) | def add_axis(self, x, new_position):
method is_float_type (line 409) | def is_float_type(self, x):
method layers (line 412) | def layers(self):
method einsum (line 417) | def einsum(self, pattern, *x):
class TFKerasBackend (line 421) | class TFKerasBackend(AbstractBackend):
method __init__ (line 424) | def __init__(self):
method is_appropriate_type (line 431) | def is_appropriate_type(self, tensor):
method create_symbol (line 434) | def create_symbol(self, shape):
method eval_symbol (line 437) | def eval_symbol(self, symbol, symbol_value_pairs):
method arange (line 441) | def arange(self, start, stop):
method shape (line 444) | def shape(self, x):
method reduce (line 448) | def reduce(self, x, operation, axes):
method reshape (line 451) | def reshape(self, x, shape):
method transpose (line 454) | def transpose(self, x, axes):
method stack_on_zeroth_dimension (line 457) | def stack_on_zeroth_dimension(self, tensors: list):
method tile (line 460) | def tile(self, x, repeats):
method concat (line 463) | def concat(self, tensors, axis: int):
method add_axis (line 466) | def add_axis(self, x, new_position):
method is_float_type (line 469) | def is_float_type(self, x):
method layers (line 472) | def layers(self):
class OneFlowBackend (line 478) | class OneFlowBackend(AbstractBackend):
method __init__ (line 481) | def __init__(self):
method is_appropriate_type (line 486) | def is_appropriate_type(self, tensor):
method from_numpy (line 489) | def from_numpy(self, x):
method to_numpy (line 496) | def to_numpy(self, x):
method arange (line 499) | def arange(self, start, stop):
method reduce (line 502) | def reduce(self, x, operation, reduced_axes):
method transpose (line 514) | def transpose(self, x, axes):
method stack_on_zeroth_dimension (line 517) | def stack_on_zeroth_dimension(self, tensors: list):
method add_axes (line 520) | def add_axes(self, x, n_axes, pos2len):
method tile (line 527) | def tile(self, x, repeats):
method concat (line 530) | def concat(self, tensors, axis: int):
method add_axis (line 533) | def add_axis(self, x, new_position):
method is_float_type (line 536) | def is_float_type(self, x):
method layers (line 539) | def layers(self):
method einsum (line 544) | def einsum(self, pattern, *x):
class PaddleBackend (line 548) | class PaddleBackend(AbstractBackend):
method __init__ (line 551) | def __init__(self):
method is_appropriate_type (line 556) | def is_appropriate_type(self, tensor):
method from_numpy (line 559) | def from_numpy(self, x):
method to_numpy (line 564) | def to_numpy(self, x):
method arange (line 567) | def arange(self, start, stop):
method reduce (line 570) | def reduce(self, x, operation, axes):
method transpose (line 577) | def transpose(self, x, axes):
method add_axes (line 580) | def add_axes(self, x, n_axes, pos2len):
method stack_on_zeroth_dimension (line 587) | def stack_on_zeroth_dimension(self, tensors: list):
method reshape (line 590) | def reshape(self, x, shape):
method tile (line 593) | def tile(self, x, repeats):
method concat (line 596) | def concat(self, tensors, axis: int):
method add_axis (line 599) | def add_axis(self, x, new_position):
method is_float_type (line 602) | def is_float_type(self, x):
method layers (line 605) | def layers(self):
method einsum (line 610) | def einsum(self, pattern, *x):
method shape (line 613) | def shape(self, x):
class TinygradBackend (line 617) | class TinygradBackend(AbstractBackend):
method __init__ (line 620) | def __init__(self):
method is_appropriate_type (line 625) | def is_appropriate_type(self, tensor):
method from_numpy (line 628) | def from_numpy(self, x):
method to_numpy (line 631) | def to_numpy(self, x):
method arange (line 634) | def arange(self, start, stop):
method shape (line 637) | def shape(self, x):
method reshape (line 640) | def reshape(self, x, shape):
method transpose (line 643) | def transpose(self, x, axes):
method reduce (line 646) | def reduce(self, x, operation, axes):
method stack_on_zeroth_dimension (line 651) | def stack_on_zeroth_dimension(self, tensors: list):
method add_axis (line 654) | def add_axis(self, x, new_position):
method tile (line 657) | def tile(self, x, repeats):
method concat (line 660) | def concat(self, tensors, axis: int):
method is_float_type (line 663) | def is_float_type(self, x):
method einsum (line 666) | def einsum(self, pattern, *x):
class PyTensorBackend (line 670) | class PyTensorBackend(AbstractBackend):
method __init__ (line 673) | def __init__(self):
method is_appropriate_type (line 678) | def is_appropriate_type(self, tensor):
method is_float_type (line 681) | def is_float_type(self, x):
method from_numpy (line 684) | def from_numpy(self, x):
method to_numpy (line 687) | def to_numpy(self, x):
method create_symbol (line 690) | def create_symbol(self, shape):
method eval_symbol (line 695) | def eval_symbol(self, symbol, symbol_value_pairs):
method arange (line 698) | def arange(self, start, stop):
method shape (line 701) | def shape(self, x):
method stack_on_zeroth_dimension (line 708) | def stack_on_zeroth_dimension(self, tensors: list):
method tile (line 711) | def tile(self, x, repeats):
method concat (line 714) | def concat(self, tensors, axis: int):
method add_axis (line 717) | def add_axis(self, x, new_position):
method einsum (line 720) | def einsum(self, pattern, *x):
class MLXBackend (line 724) | class MLXBackend(AbstractBackend):
method __init__ (line 729) | def __init__(self):
method is_appropriate_type (line 736) | def is_appropriate_type(self, tensor):
method from_numpy (line 739) | def from_numpy(self, x):
method to_numpy (line 742) | def to_numpy(self, x):
method arange (line 747) | def arange(self, start, stop):
method stack_on_zeroth_dimension (line 750) | def stack_on_zeroth_dimension(self, tensors: list):
method add_axis (line 753) | def add_axis(self, x, new_position):
method tile (line 756) | def tile(self, x, repeats):
method concat (line 759) | def concat(self, tensors, axis: int):
method is_float_type (line 762) | def is_float_type(self, x):
method einsum (line 765) | def einsum(self, pattern, *x):
FILE: einops/_torch_specific.py
class TorchJitBackend (line 20) | class TorchJitBackend:
method reduce (line 27) | def reduce(x: torch.Tensor, operation: str, reduced_axes: list[int]):
method transpose (line 44) | def transpose(x, axes: list[int]):
method stack_on_zeroth_dimension (line 48) | def stack_on_zeroth_dimension(tensors: list[torch.Tensor]):
method tile (line 52) | def tile(x, repeats: list[int]):
method add_axes (line 56) | def add_axes(x, n_axes: int, pos2len: dict[int, int]):
method is_float_type (line 64) | def is_float_type(x):
method shape (line 68) | def shape(x):
method reshape (line 72) | def reshape(x, shape: list[int]):
function apply_for_scriptable_torch (line 77) | def apply_for_scriptable_torch(
function allow_ops_in_compiled_graph (line 102) | def allow_ops_in_compiled_graph():
FILE: einops/array_api.py
function reduce (line 7) | def reduce(tensor: Tensor, pattern: str, reduction: Reduction, **axes_le...
function repeat (line 35) | def repeat(tensor: Tensor, pattern: str, **axes_lengths) -> Tensor:
function rearrange (line 39) | def rearrange(tensor: Tensor, pattern: str, **axes_lengths) -> Tensor:
function asnumpy (line 43) | def asnumpy(tensor: Tensor):
function pack (line 52) | def pack(tensors: Sequence[Tensor], pattern: str) -> tuple[Tensor, list[...
function unpack (line 72) | def unpack(tensor: Tensor, packed_shapes: list[Shape], pattern: str) -> ...
FILE: einops/einops.py
function _product (line 29) | def _product(sequence: list[int]) -> int:
function _reduce_axes (line 37) | def _reduce_axes(tensor, reduction_type: Reduction, reduced_axes: list[i...
function _optimize_transformation (line 50) | def _optimize_transformation(init_shapes, reduced_axes, axes_reordering,...
class TransformRecipe (line 114) | class TransformRecipe:
method __init__ (line 123) | def __init__(
function _reconstruct_from_shape_uncached (line 155) | def _reconstruct_from_shape_uncached(
function _apply_recipe (line 230) | def _apply_recipe(
function _apply_recipe_array_api (line 255) | def _apply_recipe_array_api(
function _prepare_transformation_recipe (line 290) | def _prepare_transformation_recipe(
function _prepare_recipes_for_all_dims (line 445) | def _prepare_recipes_for_all_dims(
function reduce (line 461) | def reduce(tensor: list[Tensor], pattern: str, reduction: Reduction, **a...
function reduce (line 465) | def reduce(tensor: Tensor, pattern: str, reduction: Reduction, **axes_le...
function reduce (line 468) | def reduce(tensor: Union[Tensor, list[Tensor]], pattern: str, reduction:...
function rearrange (line 554) | def rearrange(tensor: list[Tensor], pattern: str, **axes_lengths: Size) ...
function rearrange (line 558) | def rearrange(tensor: Tensor, pattern: str, **axes_lengths: Size) -> Ten...
function rearrange (line 561) | def rearrange(tensor: Union[Tensor, list[Tensor]], pattern: str, **axes_...
function repeat (line 620) | def repeat(tensor: list[Tensor], pattern: str, **axes_lengths: Size) -> ...
function repeat (line 624) | def repeat(tensor: Tensor, pattern: str, **axes_lengths: Size) -> Tensor...
function repeat (line 627) | def repeat(tensor: Union[Tensor, list[Tensor]], pattern: str, **axes_len...
function parse_shape (line 677) | def parse_shape(x: Tensor, pattern: str) -> dict:
function _enumerate_directions (line 740) | def _enumerate_directions(x):
function asnumpy (line 766) | def asnumpy(tensor: Tensor) -> np_ndarray:
function _validate_einsum_axis_name (line 779) | def _validate_einsum_axis_name(axis_name):
function _compactify_pattern_for_einsum (line 796) | def _compactify_pattern_for_einsum(pattern: str) -> str:
function einsum (line 850) | def einsum(tensor: Tensor, pattern: str, /) -> Tensor: ...
function einsum (line 854) | def einsum(tensor1: Tensor, tensor2: Tensor, pattern: str, /) -> Tensor:...
function einsum (line 858) | def einsum(tensor1: Tensor, tensor2: Tensor, tensor3: Tensor, pattern: s...
function einsum (line 862) | def einsum(tensor1: Tensor, tensor2: Tensor, tensor3: Tensor, tensor4: T...
function einsum (line 865) | def einsum(*tensors_and_pattern: Union[Tensor, str]) -> Tensor:
FILE: einops/layers/__init__.py
class RearrangeMixin (line 9) | class RearrangeMixin:
method __init__ (line 19) | def __init__(self, pattern: str, **axes_lengths: Any) -> None:
method __repr__ (line 27) | def __repr__(self) -> str:
method multirecipe (line 33) | def multirecipe(self) -> dict[int, TransformRecipe]:
method _apply_recipe (line 41) | def _apply_recipe(self, x):
method __getstate__ (line 51) | def __getstate__(self):
method __setstate__ (line 54) | def __setstate__(self, state):
class ReduceMixin (line 58) | class ReduceMixin:
method __init__ (line 69) | def __init__(self, pattern: str, reduction: str, **axes_lengths: Any):
method __repr__ (line 77) | def __repr__(self):
method multirecipe (line 83) | def multirecipe(self) -> dict[int, TransformRecipe]:
method _apply_recipe (line 91) | def _apply_recipe(self, x):
method __getstate__ (line 101) | def __getstate__(self):
method __setstate__ (line 104) | def __setstate__(self, state):
FILE: einops/layers/_einmix.py
function _report_axes (line 10) | def _report_axes(axes: set, report_message: str):
class _EinmixMixin (line 15) | class _EinmixMixin:
method __init__ (line 16) | def __init__(self, pattern: str, weight_shape: str, bias_shape: Option...
method initialize_einmix (line 67) | def initialize_einmix(self, pattern: str, weight_shape: str, bias_shap...
method _create_rearrange_layers (line 187) | def _create_rearrange_layers(
method _create_parameters (line 196) | def _create_parameters(self, weight_shape, weight_bound, bias_shape, b...
method __repr__ (line 200) | def __repr__(self):
class _EinmixDebugger (line 210) | class _EinmixDebugger(_EinmixMixin):
method _create_rearrange_layers (line 213) | def _create_rearrange_layers(
method _create_parameters (line 225) | def _create_parameters(self, weight_shape, weight_bound, bias_shape, b...
FILE: einops/layers/flax.py
class Reduce (line 14) | class Reduce(nn.Module):
method setup (line 19) | def setup(self):
method __call__ (line 22) | def __call__(self, input):
class Rearrange (line 26) | class Rearrange(nn.Module):
method setup (line 30) | def setup(self):
method __call__ (line 33) | def __call__(self, input):
class EinMix (line 37) | class EinMix(nn.Module, _EinmixMixin):
method setup (line 43) | def setup(self):
method _create_parameters (line 51) | def _create_parameters(self, weight_shape, weight_bound, bias_shape, b...
method _create_rearrange_layers (line 59) | def _create_rearrange_layers(
method __call__ (line 74) | def __call__(self, input):
FILE: einops/layers/oneflow.py
class Rearrange (line 11) | class Rearrange(RearrangeMixin, flow.nn.Module):
method forward (line 12) | def forward(self, input):
class Reduce (line 16) | class Reduce(ReduceMixin, flow.nn.Module):
method forward (line 17) | def forward(self, input):
class EinMix (line 21) | class EinMix(_EinmixMixin, flow.nn.Module):
method _create_parameters (line 22) | def _create_parameters(self, weight_shape, weight_bound, bias_shape, b...
method _create_rearrange_layers (line 31) | def _create_rearrange_layers(
method forward (line 46) | def forward(self, input):
FILE: einops/layers/paddle.py
class Rearrange (line 11) | class Rearrange(RearrangeMixin, paddle.nn.Layer):
method forward (line 12) | def forward(self, input):
class Reduce (line 16) | class Reduce(ReduceMixin, paddle.nn.Layer):
method forward (line 17) | def forward(self, input):
class EinMix (line 21) | class EinMix(_EinmixMixin, paddle.nn.Layer):
method _create_parameters (line 22) | def _create_parameters(self, weight_shape, weight_bound, bias_shape, b...
method _create_rearrange_layers (line 34) | def _create_rearrange_layers(
method forward (line 49) | def forward(self, input):
FILE: einops/layers/tensorflow.py
class Rearrange (line 25) | class Rearrange(RearrangeMixin, Layer):
method build (line 26) | def build(self, input_shape):
method call (line 29) | def call(self, inputs):
method get_config (line 32) | def get_config(self):
class Reduce (line 36) | class Reduce(ReduceMixin, Layer):
method build (line 37) | def build(self, input_shape):
method call (line 40) | def call(self, inputs):
method get_config (line 43) | def get_config(self):
class EinMix (line 47) | class EinMix(_EinmixMixin, Layer):
method _create_parameters (line 48) | def _create_parameters(self, weight_shape, weight_bound, bias_shape, b...
method _create_rearrange_layers (line 53) | def _create_rearrange_layers(
method build (line 68) | def build(self, input_shape):
method call (line 85) | def call(self, inputs):
method get_config (line 95) | def get_config(self):
FILE: einops/layers/torch.py
class Rearrange (line 13) | class Rearrange(RearrangeMixin, torch.nn.Module):
method forward (line 14) | def forward(self, input):
method _apply_recipe (line 18) | def _apply_recipe(self, x):
class Reduce (line 23) | class Reduce(ReduceMixin, torch.nn.Module):
method forward (line 24) | def forward(self, input):
method _apply_recipe (line 28) | def _apply_recipe(self, x):
class EinMix (line 33) | class EinMix(_EinmixMixin, torch.nn.Module):
method _create_parameters (line 34) | def _create_parameters(self, weight_shape, weight_bound, bias_shape, b...
method _create_rearrange_layers (line 45) | def _create_rearrange_layers(
method forward (line 60) | def forward(self, input):
FILE: einops/packing.py
function analyze_pattern (line 15) | def analyze_pattern(pattern: str, opname: str) -> tuple[int, int, int]:
function pack (line 34) | def pack(tensors: Sequence[Tensor], pattern: str) -> tuple[Tensor, list[...
function prod (line 91) | def prod(x: Shape) -> int:
function unpack (line 98) | def unpack(tensor: Tensor, packed_shapes: list[Shape], pattern: str) -> ...
FILE: einops/parsing.py
class AnonymousAxis (line 10) | class AnonymousAxis:
method __init__ (line 13) | def __init__(self, value: str):
method __repr__ (line 21) | def __repr__(self):
class ParsedExpression (line 25) | class ParsedExpression:
method __init__ (line 31) | def __init__(self, expression: str, *, allow_underscore: bool = False,...
method flat_axes_order (line 113) | def flat_axes_order(self) -> list:
method has_composed_axes (line 121) | def has_composed_axes(self) -> bool:
method check_axis_name_return_reason (line 129) | def check_axis_name_return_reason(name: str, allow_underscore: bool = ...
method check_axis_name (line 152) | def check_axis_name(name: str) -> bool:
FILE: einops/tests/__init__.py
function find_names_of_all_frameworks (line 23) | def find_names_of_all_frameworks() -> list[str]:
function unparse_backends (line 36) | def unparse_backends(backend_names: list[str]) -> tuple[str, str]:
function parse_backends_to_test (line 45) | def parse_backends_to_test() -> list[str]:
function is_backend_tested (line 57) | def is_backend_tested(backend: str) -> bool:
function collect_test_backends (line 64) | def collect_test_backends(symbolic=False, layers=False) -> list[_backend...
FILE: einops/tests/run_tests.py
function run (line 13) | def run(cmd, **env):
function main (line 22) | def main():
FILE: einops/tests/test_einsum.py
class Arguments (line 11) | class Arguments:
method __init__ (line 12) | def __init__(self, *args: Any, **kargs: Any):
method __call__ (line 16) | def __call__(self, function: Callable):
function test_layer (line 169) | def test_layer():
function test_functional (line 198) | def test_functional():
function test_functional_symbolic (line 233) | def test_functional_symbolic():
function test_functional_errors (line 265) | def test_functional_errors():
FILE: einops/tests/test_examples.py
function test_rearrange_examples (line 9) | def test_rearrange_examples():
function tensor_train_example_numpy (line 153) | def tensor_train_example_numpy():
function test_pytorch_yolo_fragment (line 194) | def test_pytorch_yolo_fragment():
FILE: einops/tests/test_layers.py
function test_rearrange_imperative (line 37) | def test_rearrange_imperative():
function test_rearrange_symbolic (line 69) | def test_rearrange_symbolic():
function test_reduce_imperative (line 110) | def test_reduce_imperative():
function test_reduce_symbolic (line 151) | def test_reduce_symbolic():
function create_torch_model (line 177) | def create_torch_model(use_reduce=False, add_scripted_layer=False):
function test_torch_layer (line 204) | def test_torch_layer():
function test_torch_layers_scripting (line 230) | def test_torch_layers_scripting():
function test_keras_layer (line 244) | def test_keras_layer():
function test_flax_layers (line 308) | def test_flax_layers():
function test_einmix_decomposition (line 359) | def test_einmix_decomposition():
function test_einmix_restrictions (line 449) | def test_einmix_restrictions():
FILE: einops/tests/test_ops.py
function test_collapsed_ellipsis_errors_out (line 44) | def test_collapsed_ellipsis_errors_out():
function test_ellipsis_ops_numpy (line 55) | def test_ellipsis_ops_numpy():
function check_op_against_numpy (line 73) | def check_op_against_numpy(backend, numpy_input, pattern, axes_lengths, ...
function test_ellipsis_ops_imperative (line 100) | def test_ellipsis_ops_imperative():
function test_rearrange_array_api (line 117) | def test_rearrange_array_api():
function test_reduce_array_api (line 132) | def test_reduce_array_api():
function test_rearrange_consistency_numpy (line 148) | def test_rearrange_consistency_numpy():
function test_rearrange_permutations_numpy (line 186) | def test_rearrange_permutations_numpy():
function test_reduction_imperatives (line 214) | def test_reduction_imperatives():
function test_reduction_symbolic (line 250) | def test_reduction_symbolic():
function test_reduction_stress_imperatives (line 303) | def test_reduction_stress_imperatives():
function test_reduction_with_callable_imperatives (line 335) | def test_reduction_with_callable_imperatives():
function test_enumerating_directions (line 386) | def test_enumerating_directions():
function test_concatenations_and_stacking (line 400) | def test_concatenations_and_stacking():
function test_gradients_imperatives (line 419) | def test_gradients_imperatives():
function test_tiling_imperatives (line 446) | def test_tiling_imperatives():
function test_tiling_symbolic (line 463) | def test_tiling_symbolic():
function check_reversion (line 497) | def check_reversion(x, repeat_pattern, **sizes):
function test_repeat_numpy (line 508) | def test_repeat_numpy():
function test_repeat_imperatives (line 517) | def test_repeat_imperatives():
function test_repeat_symbolic (line 530) | def test_repeat_symbolic():
function test_repeat_array_api (line 544) | def test_repeat_array_api():
function test_anonymous_axes (line 572) | def test_anonymous_axes():
function test_list_inputs (line 578) | def test_list_inputs():
function test_torch_compile_with_dynamic_shape (line 595) | def test_torch_compile_with_dynamic_shape():
function bit_count (line 624) | def bit_count(x):
function test_reduction_imperatives_booleans (line 628) | def test_reduction_imperatives_booleans():
FILE: einops/tests/test_other.py
function test_doctests_examples (line 20) | def test_doctests_examples():
function test_backends_installed (line 26) | def test_backends_installed():
function test_optimize_transformations_numpy (line 56) | def test_optimize_transformations_numpy():
function test_parse_shape_imperative (line 93) | def test_parse_shape_imperative():
function test_underscore (line 102) | def test_underscore():
function test_underscore_one (line 109) | def test_underscore_one():
function test_underscore_several (line 116) | def test_underscore_several():
function test_repeating (line 123) | def test_repeating():
function test_ellipsis (line 132) | def test_ellipsis():
function test_parse_with_anonymous_axes (line 153) | def test_parse_with_anonymous_axes():
function test_failures (line 166) | def test_failures():
function test_parse_shape_symbolic (line 193) | def test_parse_shape_symbolic(backend):
function test_parse_shape_symbolic_ellipsis (line 221) | def test_parse_shape_symbolic_ellipsis(backend):
function test_is_float_type (line 246) | def test_is_float_type():
function test_torch_compile_for_functions (line 257) | def test_torch_compile_for_functions():
function test_torch_compile_for_layers (line 308) | def test_torch_compile_for_layers():
function test_einops_threading (line 353) | def test_einops_threading():
FILE: einops/tests/test_packing.py
function pack_unpack (line 12) | def pack_unpack(xs, pattern):
function unpack_and_pack (line 20) | def unpack_and_pack(x, ps, pattern: str):
function unpack_and_pack_against_numpy (line 28) | def unpack_and_pack_against_numpy(x, ps, pattern: str):
class CaptureException (line 54) | class CaptureException:
method __enter__ (line 55) | def __enter__(self):
method __exit__ (line 58) | def __exit__(self, exc_type, exc_val, exc_tb):
function test_numpy_trivial (line 63) | def test_numpy_trivial(H=13, W=17):
class UnpackTestCase (line 123) | class UnpackTestCase:
method dim (line 127) | def dim(self):
method selfcheck (line 130) | def selfcheck(self):
function test_pack_unpack_with_numpy (line 146) | def test_pack_unpack_with_numpy():
function test_pack_unpack_against_numpy (line 209) | def test_pack_unpack_against_numpy():
function test_pack_unpack_array_api (line 273) | def test_pack_unpack_array_api():
FILE: einops/tests/test_parsing.py
class AnonymousAxisPlaceholder (line 9) | class AnonymousAxisPlaceholder:
method __init__ (line 10) | def __init__(self, value: int):
method __eq__ (line 14) | def __eq__(self, other):
method __hash__ (line 17) | def __hash__(self):
function test_anonymous_axes (line 21) | def test_anonymous_axes():
function test_elementary_axis_name (line 30) | def test_elementary_axis_name():
function test_invalid_expressions (line 51) | def test_invalid_expressions():
function test_parse_expression (line 84) | def test_parse_expression():
FILE: scripts/convert_readme.py
function replace_with_video_tag (line 10) | def replace_with_video_tag(line: str):
FILE: scripts/test_notebooks.py
function render_notebook (line 21) | def render_notebook(filename: Path, replacements: dict[str, str]) -> str:
function test_notebook_1 (line 42) | def test_notebook_1():
function test_notebook_2_with_all_backends (line 47) | def test_notebook_2_with_all_backends():
function test_notebook_3 (line 58) | def test_notebook_3():
function test_notebook_4 (line 63) | def test_notebook_4():
Condensed preview — 67 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,063K chars).
[
{
"path": ".devcontainer/devcontainer.json",
"chars": 998,
"preview": "{\n \"name\": \"EinopsDev\",\n \"build\": {\n \"context\": \"..\",\n \"dockerfile\": \"./einops.Dockerfile\",\n "
},
{
"path": ".devcontainer/einops.Dockerfile",
"chars": 186,
"preview": "FROM python:3.11-bookworm AS einops-devimage\n# note this will pull aarch64 or x86 depending on machine it is running on."
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 366,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG]\"\nlabels: bug\nassignees: ''\n\n---\n\n**Describe"
},
{
"path": ".github/ISSUE_TEMPLATE/extensions--introducing-new-operation---improve-notion.md",
"chars": 1252,
"preview": "---\nname: 'Extensions: Introducing new operation / improve notion'\nabout: 'You want to suggest a new operation or extend"
},
{
"path": ".github/workflows/deploy_docs.yml",
"chars": 1091,
"preview": "name: deploy-docs\non:\n push:\n branches:\n # triggers on new commits / merged PRs to main or a special branch\n "
},
{
"path": ".github/workflows/deploy_to_pypi.yml",
"chars": 696,
"preview": "name: Deploy to pypi\n\non:\n release:\n types: [created]\n\njobs:\n publish:\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/run_tests.yml",
"chars": 1334,
"preview": "name: Run tests\n\non: [push, pull_request]\n\njobs:\n build:\n\n runs-on: ubuntu-latest\n strategy:\n # do not fail "
},
{
"path": ".github/workflows/test_notebooks.yml",
"chars": 683,
"preview": "name: Test notebooks\n\non: [push, pull_request]\n\njobs:\n build:\n\n runs-on: ubuntu-latest\n strategy:\n matrix:\n "
},
{
"path": ".gitignore",
"chars": 1468,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
},
{
"path": ".pre-commit-config.yaml",
"chars": 306,
"preview": "---\nrepos:\n - repo: https://github.com/astral-sh/ruff-pre-commit\n # Ruff version, synced with CI\n rev: v0.11.7\n "
},
{
"path": "CITATION.cff",
"chars": 706,
"preview": "cff-version: 1.2.0\ntitle: einops\nmessage: >-\n If you use this software, please cite it using the\n metadata from this f"
},
{
"path": "LICENSE",
"chars": 1073,
"preview": "MIT License\n\nCopyright (c) 2018 Alex Rogozhnikov\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "README.md",
"chars": 13377,
"preview": "\n<!--\n<a href='http://arogozhnikov.github.io/images/einops/einops_video.mp4' >\n<div align=\"center\">\n <img src=\"http://a"
},
{
"path": "docs/1-einops-basics.ipynb",
"chars": 321834,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Einops tutorial, part 1: basics\\n"
},
{
"path": "docs/2-einops-for-deep-learning.ipynb",
"chars": 29251,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Einops tutorial, part 2: deep lea"
},
{
"path": "docs/3-einmix-layer.ipynb",
"chars": 17621,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"0c6e8fa3-2900-4879-a610-3c038f8c8d23\",\n \"metadata\": {},\n \"so"
},
{
"path": "docs/4-pack-and-unpack.ipynb",
"chars": 17383,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# einops.pack and einops.unpack\\n\","
},
{
"path": "docs/README.md",
"chars": 781,
"preview": "# Einops tutorial\n\nYou can read notebooks from github by clicking on files above.\n\nIf you prefer nbviewer, use the links"
},
{
"path": "docs/pytorch-examples.html",
"chars": 259151,
"preview": "\n<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n \n<meta property=\"og:title\" content=\"Writing be"
},
{
"path": "docs/utils/__init__.py",
"chars": 1141,
"preview": "import numpy as np\nfrom IPython import get_ipython\nfrom IPython.display import display_html\nfrom PIL.Image import fromar"
},
{
"path": "docs_src/CNAME",
"chars": 12,
"preview": "einops.rocks"
},
{
"path": "docs_src/api/asnumpy.md",
"chars": 36,
"preview": "# einops.asnumpy\n\n::: einops.asnumpy"
},
{
"path": "docs_src/api/einsum.md",
"chars": 34,
"preview": "# einops.einsum\n\n::: einops.einsum"
},
{
"path": "docs_src/api/pack_unpack.md",
"chars": 109,
"preview": "# einops.pack and einops.unpack\n\n## einops.pack\n\n::: einops.pack\n\n<br />\n\n## einops.unpack\n\n::: einops.unpack"
},
{
"path": "docs_src/api/parse_shape.md",
"chars": 44,
"preview": "# einops.parse_shape\n\n::: einops.parse_shape"
},
{
"path": "docs_src/api/rearrange.md",
"chars": 40,
"preview": "# einops.rearrange\n\n::: einops.rearrange"
},
{
"path": "docs_src/api/reduce.md",
"chars": 34,
"preview": "# einops.reduce\n\n::: einops.reduce"
},
{
"path": "docs_src/api/repeat.md",
"chars": 34,
"preview": "# einops.repeat\n\n::: einops.repeat"
},
{
"path": "docs_src/css/codehilite.css",
"chars": 4209,
"preview": "/*, .codehilite pre*/\n.codehilite code{\n color:#3F3F3F;\n background-color:#F7F7F7;\n overflow-x: scroll;\n\n bo"
},
{
"path": "docs_src/css/mkdocs.css",
"chars": 689,
"preview": "div.highlight>pre {\n padding: 3px;\n}\n\n.md-typeset ul li,\n.md-typeset ol li {\n /*original padding makes lists huge*"
},
{
"path": "docs_src/pages/projects.md",
"chars": 3475,
"preview": "## Tools for einops users\n\n- [Ein Color](https://marketplace.visualstudio.com/items?itemName=MarcinJachmann.vscode-einco"
},
{
"path": "docs_src/pages/testimonials.md",
"chars": 5098,
"preview": "<style>\n.md-typeset blockquote {\n background-color: rgba(128, 128, 128, 0.04);\n border-color: #002ee380;\n color"
},
{
"path": "einops/__init__.py",
"chars": 441,
"preview": "# imports can use EinopsError class\n# ruff: noqa: E402\n\n__author__ = \"Alex Rogozhnikov\"\n__version__ = \"0.9.0dev\"\n\n\nclass"
},
{
"path": "einops/_backends.py",
"chars": 22641,
"preview": "\"\"\"\nBackends in `einops` are organized to meet the following requirements\n- backends are not imported unless those are a"
},
{
"path": "einops/_torch_specific.py",
"chars": 4292,
"preview": "\"\"\"\nSpecialization of einops for torch.\n\nUnfortunately, torch's jit scripting mechanism isn't strong enough,\nand to have"
},
{
"path": "einops/array_api.py",
"chars": 5232,
"preview": "from collections.abc import Sequence\n\nfrom .einops import EinopsError, Reduction, Tensor, _apply_recipe_array_api, _prep"
},
{
"path": "einops/einops.py",
"chars": 38047,
"preview": "import functools\nimport itertools\nimport string\nimport typing\nfrom collections import OrderedDict\nfrom typing import Any"
},
{
"path": "einops/experimental/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "einops/experimental/indexing.py",
"chars": 121,
"preview": "\"\"\"\nThis file contained some thoughts on indexing.\n\nThese ideas were developed further in eindex (separate package).\n\"\"\""
},
{
"path": "einops/layers/__init__.py",
"chars": 3699,
"preview": "__author__ = \"Alex Rogozhnikov\"\n\nfrom typing import Any\n\nfrom einops import EinopsError\nfrom einops.einops import Transf"
},
{
"path": "einops/layers/_einmix.py",
"chars": 11063,
"preview": "import string\nimport warnings\nfrom typing import Any, Optional\n\nfrom einops import EinopsError\nfrom einops.einops import"
},
{
"path": "einops/layers/flax.py",
"chars": 2512,
"preview": "from dataclasses import field\nfrom typing import Optional, cast\n\nimport flax.linen as nn\nimport jax\nimport jax.numpy as "
},
{
"path": "einops/layers/keras.py",
"chars": 217,
"preview": "__author__ = \"Alex Rogozhnikov\"\n\nfrom einops.layers.tensorflow import EinMix, Rearrange, Reduce\n\nkeras_custom_objects = "
},
{
"path": "einops/layers/oneflow.py",
"chars": 1858,
"preview": "from typing import Optional, cast\n\nimport oneflow as flow\n\nfrom . import RearrangeMixin, ReduceMixin\nfrom ._einmix impor"
},
{
"path": "einops/layers/paddle.py",
"chars": 1901,
"preview": "from typing import Optional, cast\n\nimport paddle\n\nfrom . import RearrangeMixin, ReduceMixin\nfrom ._einmix import _Einmix"
},
{
"path": "einops/layers/tensorflow.py",
"chars": 3316,
"preview": "\"\"\"\nComment about tensorflow layers:\nunfortunately instructions on creation of TF layers change constantly,\nand changed "
},
{
"path": "einops/layers/torch.py",
"chars": 2399,
"preview": "from typing import Optional, cast\n\nimport torch\n\nfrom einops._torch_specific import apply_for_scriptable_torch\n\nfrom . i"
},
{
"path": "einops/packing.py",
"chars": 7674,
"preview": "from collections.abc import Sequence\nfrom functools import lru_cache\nfrom typing import TypeVar, Union\n\nfrom einops impo"
},
{
"path": "einops/parsing.py",
"chars": 6785,
"preview": "import keyword\nimport warnings\nfrom typing import Optional, Union\n\nfrom einops import EinopsError\n\n_ellipsis: str = \"…\" "
},
{
"path": "einops/py.typed",
"chars": 0,
"preview": ""
},
{
"path": "einops/tests/__init__.py",
"chars": 3500,
"preview": "\"\"\"\nCommon utils for testing.\nThese functions allow testing only some frameworks, not all.\n\"\"\"\n\nimport logging\nimport os"
},
{
"path": "einops/tests/run_tests.py",
"chars": 3082,
"preview": "\"\"\"\nRuns tests that are appropriate for framework.\n\"\"\"\n\nimport os\nimport sys\nfrom pathlib import Path\nfrom subprocess im"
},
{
"path": "einops/tests/test_einsum.py",
"chars": 11038,
"preview": "import string\nfrom typing import Any, Callable\n\nimport numpy as np\nimport pytest\n\nfrom einops.einops import EinopsError,"
},
{
"path": "einops/tests/test_examples.py",
"chars": 11510,
"preview": "import numpy as np\nimport pytest\n\nfrom einops import parse_shape, rearrange, reduce\nfrom einops.tests import is_backend_"
},
{
"path": "einops/tests/test_layers.py",
"chars": 18667,
"preview": "import pickle\nfrom collections import namedtuple\n\nimport numpy as np\nimport pytest\n\nfrom einops import EinopsError, rear"
},
{
"path": "einops/tests/test_ops.py",
"chars": 26884,
"preview": "import itertools\n\nimport numpy as np\nimport pytest\n\nfrom einops import EinopsError\nfrom einops.einops import _enumerate_"
},
{
"path": "einops/tests/test_other.py",
"chars": 13521,
"preview": "import subprocess\nimport tempfile\nfrom doctest import testmod\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest"
},
{
"path": "einops/tests/test_packing.py",
"chars": 10387,
"preview": "import dataclasses\n\nimport numpy as np\nimport pytest\n\nfrom einops import EinopsError, asnumpy, pack, unpack\nfrom einops."
},
{
"path": "einops/tests/test_parsing.py",
"chars": 4470,
"preview": "import pytest\n\nfrom einops import EinopsError\nfrom einops.parsing import AnonymousAxis, ParsedExpression, _ellipsis\n\n__a"
},
{
"path": "mkdocs.yml",
"chars": 1417,
"preview": "site_name: Einops\nrepo_name: arogozhnikov/einops\nrepo_url: https://github.com/arogozhnikov/einops\nsite_url: https://eino"
},
{
"path": "pyproject.toml",
"chars": 3666,
"preview": "[build-system]\nrequires = [\"hatchling>=1.10.0\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"einops\"\ndescription"
},
{
"path": "scripts/convert_readme.py",
"chars": 939,
"preview": "\"\"\"\nConverts readme from github repo page to mkdocs-friendly\n\"\"\"\n\nfrom pathlib import Path\n\noriginal_text = Path(__file_"
},
{
"path": "scripts/pytorch_examples_source/Pytorch.ipynb",
"chars": 97541,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<div align=\\\"center\\\">\\n\",\n \" "
},
{
"path": "scripts/pytorch_examples_source/converter.py",
"chars": 4339,
"preview": "\"\"\"\njust run this script with python converter.py .\nIt will convert pytorch.ipynb to html page docs/pytorch-examples.htm"
},
{
"path": "scripts/setup.py",
"chars": 883,
"preview": "\"\"\"\nThis is a fake script, it is not used.\nGithub does not count dependent python projects unless you have a setup.py\n\"\""
},
{
"path": "scripts/test_notebooks.py",
"chars": 2091,
"preview": "\"\"\"\nScript assumes torch, tf and numpy are already installed.\nAlso needs:\n \"nbformat\",\n \"nbconvert\",\n \"jupyter\",\n \"p"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the arogozhnikov/einops GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 67 files (987.0 KB), approximately 418.6k tokens, and a symbol index with 422 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.