pytensor-ml 0.2.2__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.github/workflows/run_tests.yml +11 -3
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/PKG-INFO +9 -7
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/README.md +5 -4
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/conda_envs/environment-docs.yml +1 -1
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/conda_envs/pytensor_ml-gpu_jax.yml +1 -1
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/conda_envs/pytensor_ml.yml +2 -1
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/activations.rst +1 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/layers.rst +3 -0
- pytensor_ml-0.3.0/docs/source/api/models.rst +34 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/optim.rst +19 -2
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/state.rst +2 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api.rst +1 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/dev/style_guide.rst +1 -1
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/index.rst +9 -2
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/references.bib +29 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/sharp_edges.rst +42 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/examples/gallery/mnist_feed_forward.ipynb +2 -2
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pyproject.toml +10 -3
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/__init__.py +1 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/_version.py +2 -2
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/activations.py +28 -2
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/base.py +69 -1
- pytensor_ml-0.3.0/pytensor_ml/checkpoint.py +350 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/jax/__init__.py +1 -0
- pytensor_ml-0.3.0/pytensor_ml/dispatch/jax/attention.py +36 -0
- pytensor_ml-0.3.0/pytensor_ml/dispatch/jax/line_search.py +41 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/mlx/__init__.py +2 -0
- pytensor_ml-0.3.0/pytensor_ml/dispatch/mlx/lbfgs.py +51 -0
- pytensor_ml-0.3.0/pytensor_ml/dispatch/mlx/line_search.py +261 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/__init__.py +10 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/attention.py +120 -29
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/conv.py +251 -80
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/dropout.py +3 -3
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/embedding.py +5 -4
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/linear.py +6 -4
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/norm.py +340 -22
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/padding.py +5 -3
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/recurrent.py +66 -38
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/transformer.py +44 -15
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/loss.py +39 -11
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/model.py +38 -14
- pytensor_ml-0.3.0/pytensor_ml/models/__init__.py +24 -0
- pytensor_ml-0.3.0/pytensor_ml/models/architectures/__init__.py +3 -0
- pytensor_ml-0.3.0/pytensor_ml/models/architectures/clip.py +190 -0
- pytensor_ml-0.3.0/pytensor_ml/models/architectures/gpt2.py +127 -0
- pytensor_ml-0.3.0/pytensor_ml/models/architectures/vae.py +343 -0
- pytensor_ml-0.3.0/pytensor_ml/models/blocks/__init__.py +4 -0
- pytensor_ml-0.3.0/pytensor_ml/models/blocks/attention.py +78 -0
- pytensor_ml-0.3.0/pytensor_ml/models/blocks/resnet.py +173 -0
- pytensor_ml-0.3.0/pytensor_ml/models/loading/__init__.py +17 -0
- pytensor_ml-0.3.0/pytensor_ml/models/loading/binding.py +28 -0
- pytensor_ml-0.3.0/pytensor_ml/models/loading/keys.py +224 -0
- pytensor_ml-0.3.0/pytensor_ml/models/loading/registry.py +120 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/__init__.py +9 -4
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/alias.py +191 -136
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/base.py +119 -184
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/clipping.py +2 -2
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/guards.py +24 -26
- pytensor_ml-0.3.0/pytensor_ml/optim/lbfgs.py +179 -0
- pytensor_ml-0.3.0/pytensor_ml/optim/line_search.py +586 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/policy.py +20 -11
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/rules.py +339 -63
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/schedules.py +93 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/train.py +19 -18
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/transform.py +21 -27
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/params.py +30 -6
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/pretrained.py +109 -21
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/pytensorf/__init__.py +2 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/pytensorf/collect.py +86 -19
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/pytensorf/compile.py +29 -15
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/pytensorf/rewrite.py +43 -3
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/pytensorf/rng.py +35 -5
- pytensor_ml-0.3.0/pytensor_ml/rewriting/layers.py +216 -0
- pytensor_ml-0.3.0/pytensor_ml/rewriting/scan.py +376 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/state.py +73 -9
- pytensor_ml-0.3.0/tests/conftest.py +153 -0
- pytensor_ml-0.3.0/tests/data/attention_block_2d.npz +0 -0
- pytensor_ml-0.3.0/tests/data/generate_reference_checkpoints.py +141 -0
- pytensor_ml-0.3.0/tests/data/generate_reference_layers.py +98 -0
- pytensor_ml-0.3.0/tests/data/resnet_block_2d.npz +0 -0
- pytensor_ml-0.3.0/tests/data/sdxl_vae.npz +0 -0
- pytensor_ml-0.3.0/tests/data/tiny_clip/config.json +23 -0
- pytensor_ml-0.3.0/tests/data/tiny_clip/expected_outputs.npz +0 -0
- pytensor_ml-0.3.0/tests/data/tiny_clip/model.safetensors +0 -0
- pytensor_ml-0.3.0/tests/data/tiny_clip_with_projection/config.json +23 -0
- pytensor_ml-0.3.0/tests/data/tiny_clip_with_projection/expected_outputs.npz +0 -0
- pytensor_ml-0.3.0/tests/data/tiny_clip_with_projection/model.safetensors +0 -0
- pytensor_ml-0.3.0/tests/data/tiny_gpt2/config.json +34 -0
- pytensor_ml-0.3.0/tests/data/tiny_gpt2/expected_outputs.npz +0 -0
- pytensor_ml-0.3.0/tests/data/tiny_gpt2/generation_config.json +9 -0
- pytensor_ml-0.3.0/tests/data/tiny_gpt2/model.safetensors +0 -0
- pytensor_ml-0.3.0/tests/data/tiny_vae/config.json +31 -0
- pytensor_ml-0.3.0/tests/data/tiny_vae/diffusion_pytorch_model.safetensors +0 -0
- pytensor_ml-0.3.0/tests/data/tiny_vae/expected_outputs.npz +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/jax/test_attention.py +15 -0
- pytensor_ml-0.3.0/tests/dispatch/jax/test_line_search.py +96 -0
- pytensor_ml-0.3.0/tests/dispatch/mlx/test_lbfgs.py +137 -0
- pytensor_ml-0.3.0/tests/dispatch/mlx/test_line_search.py +135 -0
- pytensor_ml-0.3.0/tests/dispatch/mlx/test_norm.py +33 -0
- pytensor_ml-0.3.0/tests/models/architectures/test_clip.py +189 -0
- pytensor_ml-0.3.0/tests/models/architectures/test_gpt2.py +121 -0
- pytensor_ml-0.3.0/tests/models/architectures/test_vae.py +119 -0
- pytensor_ml-0.3.0/tests/models/blocks/__init__.py +0 -0
- pytensor_ml-0.3.0/tests/models/blocks/test_attention.py +54 -0
- pytensor_ml-0.3.0/tests/models/blocks/test_resnet.py +117 -0
- pytensor_ml-0.3.0/tests/models/loading/__init__.py +0 -0
- pytensor_ml-0.3.0/tests/models/loading/test_binding.py +11 -0
- pytensor_ml-0.3.0/tests/models/loading/test_keys.py +197 -0
- pytensor_ml-0.3.0/tests/models/loading/test_registry.py +72 -0
- pytensor_ml-0.3.0/tests/optim/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/conftest.py +3 -1
- pytensor_ml-0.3.0/tests/optim/lbfgs_reference.py +34 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_composition.py +87 -4
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_guards.py +29 -17
- pytensor_ml-0.3.0/tests/optim/test_lbfgs.py +163 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_learning_rate.py +3 -16
- pytensor_ml-0.3.0/tests/optim/test_line_search.py +242 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_policy.py +15 -3
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_public_surface.py +1 -3
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_rules.py +456 -26
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_schedules.py +47 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_training.py +83 -24
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_transform.py +15 -43
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_update_space.py +3 -53
- pytensor_ml-0.3.0/tests/rewriting/__init__.py +0 -0
- pytensor_ml-0.3.0/tests/rewriting/test_layers.py +337 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/rewriting/test_scan.py +165 -7
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_activations.py +30 -4
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_attention.py +138 -4
- pytensor_ml-0.3.0/tests/test_checkpoint.py +661 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_collect.py +25 -11
- pytensor_ml-0.3.0/tests/test_conv.py +570 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_conv_transpose.py +56 -68
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_layers.py +439 -4
- pytensor_ml-0.3.0/tests/test_loss.py +134 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_model.py +75 -25
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_padding.py +12 -36
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_pool.py +43 -57
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_pretrained.py +254 -20
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_pytensorf.py +95 -4
- pytensor_ml-0.3.0/tests/test_recurrent.py +785 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_serialize.py +43 -7
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_state.py +31 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_transformer.py +38 -1
- pytensor_ml-0.3.0/tests/test_upsample.py +201 -0
- pytensor_ml-0.2.2/pytensor_ml/checkpoint.py +0 -171
- pytensor_ml-0.2.2/pytensor_ml/dispatch/jax/attention.py +0 -25
- pytensor_ml-0.2.2/pytensor_ml/rewriting/layers.py +0 -85
- pytensor_ml-0.2.2/pytensor_ml/rewriting/scan.py +0 -188
- pytensor_ml-0.2.2/tests/conftest.py +0 -61
- pytensor_ml-0.2.2/tests/rewriting/conftest.py +0 -23
- pytensor_ml-0.2.2/tests/rewriting/test_layers.py +0 -52
- pytensor_ml-0.2.2/tests/test_checkpoint.py +0 -223
- pytensor_ml-0.2.2/tests/test_conv.py +0 -897
- pytensor_ml-0.2.2/tests/test_loss.py +0 -72
- pytensor_ml-0.2.2/tests/test_recurrent.py +0 -1279
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.gitattributes +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.github/workflows/mypy.yml +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.github/workflows/pre-commit.yml +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.github/workflows/release.yml +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.github/workflows/rtd-preview.yml +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.gitignore +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.pre-commit-config.yaml +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/.readthedocs.yaml +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/LICENSE +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/.gitignore +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/Makefile +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/make.bat +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/_static/.gitkeep +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/_templates/autosummary/class.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/loss.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/model.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/pytensorf.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/serialization.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/api/util.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/conf.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/dev/contributing.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/dev/docs.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/dev/index.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/source/install.rst +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/docs/sphinxext/generate_gallery.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pixi.lock +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/jax/conv.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/jax/pooling.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/mlx/attention.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/mlx/conv.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/mlx/pooling.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/numba/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/numba/conv.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/pytorch/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/pytorch/conv.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/dispatch/pytorch/pooling.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/json_serialize.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/layers/combinators.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/optim/checks.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/rewriting/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/rewriting/conv.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/serialize/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/serialize/base.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/serialize/blockwise.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/serialize/builders.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/serialize/elemwise.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/serialize/scalar.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/serialize/scan.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/pytensor_ml/util.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/scripts/run_mypy.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/jax/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/jax/test_basic.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/jax/test_conv.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/jax/test_pool.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/mlx/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/mlx/test_attention.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/mlx/test_basic.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/mlx/test_conv.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/mlx/test_pool.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/pytorch/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/pytorch/test_conv.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/dispatch/pytorch/test_pool.py +0 -0
- {pytensor_ml-0.2.2/tests/optim → pytensor_ml-0.3.0/tests/models}/__init__.py +0 -0
- {pytensor_ml-0.2.2/tests/rewriting → pytensor_ml-0.3.0/tests/models/architectures}/__init__.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/optim/test_clipping.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_base.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_util.py +0 -0
- {pytensor_ml-0.2.2 → pytensor_ml-0.3.0}/tests/test_workflow_groups.py +0 -0
|
@@ -35,15 +35,24 @@ jobs:
|
|
|
35
35
|
paths: |
|
|
36
36
|
tests/test_transformer.py
|
|
37
37
|
tests/test_layers.py
|
|
38
|
+
- name: recurrent
|
|
39
|
+
paths: |
|
|
38
40
|
tests/test_recurrent.py
|
|
41
|
+
tests/rewriting/
|
|
42
|
+
- name: convolution
|
|
43
|
+
paths: |
|
|
39
44
|
tests/test_conv.py
|
|
40
45
|
tests/test_conv_transpose.py
|
|
41
46
|
tests/test_padding.py
|
|
42
47
|
tests/test_pool.py
|
|
43
|
-
tests/
|
|
48
|
+
tests/test_upsample.py
|
|
44
49
|
- name: optim
|
|
45
50
|
paths: |
|
|
46
51
|
tests/optim/
|
|
52
|
+
- name: models
|
|
53
|
+
paths: |
|
|
54
|
+
tests/test_pretrained.py
|
|
55
|
+
tests/models/
|
|
47
56
|
- name: rest
|
|
48
57
|
paths: |
|
|
49
58
|
tests/test_serialize.py
|
|
@@ -51,7 +60,6 @@ jobs:
|
|
|
51
60
|
tests/test_loss.py
|
|
52
61
|
tests/test_checkpoint.py
|
|
53
62
|
tests/test_model.py
|
|
54
|
-
tests/test_pretrained.py
|
|
55
63
|
tests/test_pytensorf.py
|
|
56
64
|
tests/test_state.py
|
|
57
65
|
tests/test_base.py
|
|
@@ -148,7 +156,7 @@ jobs:
|
|
|
148
156
|
run: |
|
|
149
157
|
conda activate pytensor_ml
|
|
150
158
|
if [[ $INSTALL_JAX == "1" ]]; then pip install "jax>=0.8,<0.9.1" jaxlib; fi
|
|
151
|
-
if [[ $INSTALL_MLX == "1" ]]; then pip install "mlx>=0.
|
|
159
|
+
if [[ $INSTALL_MLX == "1" ]]; then pip install "mlx>=0.32.2,<0.33"; fi
|
|
152
160
|
if [[ $INSTALL_TORCH == "1" ]]; then pip install torch --index-url https://download.pytorch.org/whl/cpu; fi
|
|
153
161
|
env:
|
|
154
162
|
INSTALL_JAX: ${{ matrix.install-jax }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pytensor_ml
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A(nother) deep learning library, built on top of Pytensor
|
|
5
5
|
Project-URL: Homepage, https://github.com/pymc-devs/pytensor-ml
|
|
6
6
|
Project-URL: Documentation, https://pytensor-ml.readthedocs.io
|
|
@@ -25,15 +25,16 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
25
25
|
Classifier: Topic :: Scientific/Engineering
|
|
26
26
|
Requires-Python: >=3.12
|
|
27
27
|
Requires-Dist: numpy
|
|
28
|
-
Requires-Dist: pytensor<4.0.0,>=3.
|
|
29
|
-
Requires-Dist: safetensors
|
|
28
|
+
Requires-Dist: pytensor<4.0.0,>=3.3.3
|
|
30
29
|
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: cloudpickle; extra == 'dev'
|
|
31
31
|
Requires-Dist: jax; extra == 'dev'
|
|
32
32
|
Requires-Dist: mypy; extra == 'dev'
|
|
33
33
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
34
34
|
Requires-Dist: pytest; extra == 'dev'
|
|
35
35
|
Requires-Dist: pytest-cov; extra == 'dev'
|
|
36
36
|
Requires-Dist: pyyaml; extra == 'dev'
|
|
37
|
+
Requires-Dist: safetensors; extra == 'dev'
|
|
37
38
|
Requires-Dist: scikit-learn; extra == 'dev'
|
|
38
39
|
Provides-Extra: examples
|
|
39
40
|
Requires-Dist: matplotlib; extra == 'examples'
|
|
@@ -61,8 +62,9 @@ any other PyTensor graph — a PyMC model included — as there is nothing else
|
|
|
61
62
|
pip install pytensor-ml
|
|
62
63
|
```
|
|
63
64
|
|
|
64
|
-
The only hard dependencies are `pytensor
|
|
65
|
-
`jax`, `torch`, `mlx`) is installed
|
|
65
|
+
The only hard dependencies are `pytensor` and `numpy`. Saving and loading weights needs `safetensors`
|
|
66
|
+
(`pip install safetensors`). A backend beyond the default (`numba`, `jax`, `torch`, `mlx`) is installed
|
|
67
|
+
separately, and only loads when you actually compile against it.
|
|
66
68
|
|
|
67
69
|
## Quickstart
|
|
68
70
|
|
|
@@ -93,11 +95,11 @@ network = Sequential(
|
|
|
93
95
|
ReLU(),
|
|
94
96
|
Linear("logits", n_in=128, n_out=10),
|
|
95
97
|
)
|
|
96
|
-
model = Model(
|
|
98
|
+
model = Model(network(X_in)).initialize(seed=0)
|
|
97
99
|
|
|
98
100
|
rule = chain(clip_by_global_norm(1.0), adam(learning_rate=cosine_schedule(1e-3, total_steps=500)))
|
|
99
101
|
loss_fn = CrossEntropy(expect_onehot_labels=True, expect_logits=True, reduction="mean")
|
|
100
|
-
step = model.compile_train(rule, loss_fn
|
|
102
|
+
step = model.compile_train(rule, loss_fn)
|
|
101
103
|
|
|
102
104
|
loader = DataLoader(X, y_onehot, batch_size=64, random_state=0)
|
|
103
105
|
for _ in range(500):
|
|
@@ -19,8 +19,9 @@ any other PyTensor graph — a PyMC model included — as there is nothing else
|
|
|
19
19
|
pip install pytensor-ml
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
The only hard dependencies are `pytensor
|
|
23
|
-
`jax`, `torch`, `mlx`) is installed
|
|
22
|
+
The only hard dependencies are `pytensor` and `numpy`. Saving and loading weights needs `safetensors`
|
|
23
|
+
(`pip install safetensors`). A backend beyond the default (`numba`, `jax`, `torch`, `mlx`) is installed
|
|
24
|
+
separately, and only loads when you actually compile against it.
|
|
24
25
|
|
|
25
26
|
## Quickstart
|
|
26
27
|
|
|
@@ -51,11 +52,11 @@ network = Sequential(
|
|
|
51
52
|
ReLU(),
|
|
52
53
|
Linear("logits", n_in=128, n_out=10),
|
|
53
54
|
)
|
|
54
|
-
model = Model(
|
|
55
|
+
model = Model(network(X_in)).initialize(seed=0)
|
|
55
56
|
|
|
56
57
|
rule = chain(clip_by_global_norm(1.0), adam(learning_rate=cosine_schedule(1e-3, total_steps=500)))
|
|
57
58
|
loss_fn = CrossEntropy(expect_onehot_labels=True, expect_logits=True, reduction="mean")
|
|
58
|
-
step = model.compile_train(rule, loss_fn
|
|
59
|
+
step = model.compile_train(rule, loss_fn)
|
|
59
60
|
|
|
60
61
|
loader = DataLoader(X, y_onehot, batch_size=64, random_state=0)
|
|
61
62
|
for _ in range(500):
|
|
@@ -8,7 +8,7 @@ channels:
|
|
|
8
8
|
dependencies:
|
|
9
9
|
- python>=3.12
|
|
10
10
|
# Runtime deps: autodoc imports pytensor_ml, so the full runtime stack has to be in scope.
|
|
11
|
-
- pytensor>=3.3.
|
|
11
|
+
- pytensor>=3.3.3,<3.4.0
|
|
12
12
|
- numpy
|
|
13
13
|
- safetensors
|
|
14
14
|
# The gallery extension renders notebook thumbnails with matplotlib.
|
|
@@ -5,12 +5,13 @@ channels:
|
|
|
5
5
|
|
|
6
6
|
dependencies:
|
|
7
7
|
- python>=3.12
|
|
8
|
-
- pytensor>=3.3.
|
|
8
|
+
- pytensor>=3.3.3,<3.4.0
|
|
9
9
|
- numpy
|
|
10
10
|
- safetensors
|
|
11
11
|
- scikit-learn
|
|
12
12
|
|
|
13
13
|
# For testing
|
|
14
|
+
- cloudpickle # tests/optim/test_composition.py ships a configured rule to a worker
|
|
14
15
|
- coveralls
|
|
15
16
|
- diff-cover
|
|
16
17
|
- pytest
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Pretrained models
|
|
2
|
+
=================
|
|
3
|
+
|
|
4
|
+
.. currentmodule:: pytensor_ml.models
|
|
5
|
+
|
|
6
|
+
Dispatch
|
|
7
|
+
--------
|
|
8
|
+
|
|
9
|
+
.. autosummary::
|
|
10
|
+
:toctree: generated/
|
|
11
|
+
|
|
12
|
+
architecture_name
|
|
13
|
+
build_from_config
|
|
14
|
+
register_builder
|
|
15
|
+
|
|
16
|
+
Blocks
|
|
17
|
+
------
|
|
18
|
+
|
|
19
|
+
.. autosummary::
|
|
20
|
+
:toctree: generated/
|
|
21
|
+
|
|
22
|
+
ResnetBlock2D
|
|
23
|
+
AttentionBlock2D
|
|
24
|
+
|
|
25
|
+
Binding weights
|
|
26
|
+
---------------
|
|
27
|
+
|
|
28
|
+
.. autosummary::
|
|
29
|
+
:toctree: generated/
|
|
30
|
+
|
|
31
|
+
KeyMap
|
|
32
|
+
bind_layer_norm
|
|
33
|
+
bind_linear
|
|
34
|
+
channels_last
|
|
@@ -26,6 +26,16 @@ Update rules
|
|
|
26
26
|
rprop
|
|
27
27
|
adagrad
|
|
28
28
|
adadelta
|
|
29
|
+
lbfgs
|
|
30
|
+
|
|
31
|
+
Line searches
|
|
32
|
+
-------------
|
|
33
|
+
|
|
34
|
+
.. autosummary::
|
|
35
|
+
:toctree: generated/
|
|
36
|
+
|
|
37
|
+
zoom_line_search
|
|
38
|
+
LineSearch
|
|
29
39
|
|
|
30
40
|
Transforms
|
|
31
41
|
----------
|
|
@@ -73,6 +83,7 @@ eliminated the value's last consumer.
|
|
|
73
83
|
|
|
74
84
|
constant_schedule
|
|
75
85
|
linear_schedule
|
|
86
|
+
linear_onecycle_schedule
|
|
76
87
|
cosine_schedule
|
|
77
88
|
exponential_schedule
|
|
78
89
|
polynomial_schedule
|
|
@@ -85,9 +96,7 @@ Building blocks
|
|
|
85
96
|
.. autosummary::
|
|
86
97
|
:toctree: generated/
|
|
87
98
|
|
|
88
|
-
counter
|
|
89
99
|
get_gradients
|
|
90
|
-
reuses_state
|
|
91
100
|
scalar_state
|
|
92
101
|
state_for
|
|
93
102
|
steps_of
|
|
@@ -131,3 +140,11 @@ Low-level update functions
|
|
|
131
140
|
rprop_updates
|
|
132
141
|
adagrad_updates
|
|
133
142
|
adadelta_updates
|
|
143
|
+
lbfgs_updates
|
|
144
|
+
|
|
145
|
+
.. currentmodule:: pytensor_ml.optim.lbfgs
|
|
146
|
+
|
|
147
|
+
.. autosummary::
|
|
148
|
+
:toctree: generated/
|
|
149
|
+
|
|
150
|
+
LBFGSDirection
|
|
@@ -180,7 +180,7 @@ Every public entrypoint carries an ``Examples`` section. Three rules:
|
|
|
180
180
|
from pytensor_ml.optim import adam, chain, clip_by_global_norm, compile_train
|
|
181
181
|
|
|
182
182
|
X = Input("X", shape=(None, 4))
|
|
183
|
-
loss, target = supervised_loss(Linear("fc", n_in=4, n_out=1)(X), SquaredError()
|
|
183
|
+
loss, target = supervised_loss(Linear("fc", n_in=4, n_out=1)(X), SquaredError())
|
|
184
184
|
|
|
185
185
|
step = compile_train(loss, chain(clip_by_global_norm(1.0), adam(1e-3)))
|
|
186
186
|
loss_value = step(np.zeros((8, 4)), np.zeros((8, 1)))
|
|
@@ -41,6 +41,9 @@ Quick example
|
|
|
41
41
|
|
|
42
42
|
import numpy as np
|
|
43
43
|
|
|
44
|
+
from pytensor import config
|
|
45
|
+
from sklearn.datasets import load_digits
|
|
46
|
+
|
|
44
47
|
from pytensor_ml.activations import ReLU
|
|
45
48
|
from pytensor_ml.layers import Input, Linear, Sequential
|
|
46
49
|
from pytensor_ml.loss import CrossEntropy
|
|
@@ -48,17 +51,21 @@ Quick example
|
|
|
48
51
|
from pytensor_ml.optim import adam, chain, clip_by_global_norm, cosine_schedule
|
|
49
52
|
from pytensor_ml.util import DataLoader
|
|
50
53
|
|
|
54
|
+
X, y = load_digits(return_X_y=True)
|
|
55
|
+
X = (X / 16.0).astype(config.floatX)
|
|
56
|
+
y_onehot = np.eye(10, dtype=config.floatX)[y]
|
|
57
|
+
|
|
51
58
|
X_in = Input("X_in", shape=(None, 64))
|
|
52
59
|
network = Sequential(
|
|
53
60
|
Linear("fc1", n_in=64, n_out=128),
|
|
54
61
|
ReLU(),
|
|
55
62
|
Linear("logits", n_in=128, n_out=10),
|
|
56
63
|
)
|
|
57
|
-
model = Model(
|
|
64
|
+
model = Model(network(X_in)).initialize(seed=0)
|
|
58
65
|
|
|
59
66
|
rule = chain(clip_by_global_norm(1.0), adam(learning_rate=cosine_schedule(1e-3, total_steps=500)))
|
|
60
67
|
loss_fn = CrossEntropy(expect_onehot_labels=True, expect_logits=True, reduction="mean")
|
|
61
|
-
step = model.compile_train(rule, loss_fn
|
|
68
|
+
step = model.compile_train(rule, loss_fn)
|
|
62
69
|
|
|
63
70
|
loader = DataLoader(X, y_onehot, batch_size=64, random_state=0)
|
|
64
71
|
for _ in range(500):
|
|
@@ -42,3 +42,32 @@
|
|
|
42
42
|
booktitle = {International Conference on Artificial Intelligence and Statistics},
|
|
43
43
|
year = {2010},
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
@book{nocedal2006numerical,
|
|
47
|
+
title = {Numerical Optimization},
|
|
48
|
+
author = {Nocedal, Jorge and Wright, Stephen J.},
|
|
49
|
+
edition = {2},
|
|
50
|
+
publisher = {Springer},
|
|
51
|
+
address = {New York},
|
|
52
|
+
year = {2006},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@article{liu1989lbfgs,
|
|
56
|
+
title = {On the Limited Memory {BFGS} Method for Large Scale Optimization},
|
|
57
|
+
author = {Liu, Dong C. and Nocedal, Jorge},
|
|
58
|
+
journal = {Mathematical Programming},
|
|
59
|
+
volume = {45},
|
|
60
|
+
number = {1--3},
|
|
61
|
+
pages = {503--528},
|
|
62
|
+
year = {1989},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@article{hager2005new,
|
|
66
|
+
title = {A New Conjugate Gradient Method with Guaranteed Descent and an Efficient Line Search},
|
|
67
|
+
author = {Hager, William W. and Zhang, Hongchao},
|
|
68
|
+
journal = {SIAM Journal on Optimization},
|
|
69
|
+
volume = {16},
|
|
70
|
+
number = {1},
|
|
71
|
+
pages = {170--192},
|
|
72
|
+
year = {2005},
|
|
73
|
+
}
|
|
@@ -173,6 +173,48 @@ because an endpoint above the starting rate is a legitimate warmup.
|
|
|
173
173
|
There is no ``warmup`` helper for the same reason: an endpoint above the start already is
|
|
174
174
|
one, and :func:`~pytensor_ml.optim.join_schedules` composes the phases.
|
|
175
175
|
|
|
176
|
+
Hyperparameters are keyword-only
|
|
177
|
+
--------------------------------
|
|
178
|
+
|
|
179
|
+
A layer takes its name first and every hyperparameter by keyword. There are no positional
|
|
180
|
+
hyperparameters anywhere in the library, so the torch and keras spelling raises rather than
|
|
181
|
+
binding a hyperparameter to ``name`` and leaving the real one at its default:
|
|
182
|
+
|
|
183
|
+
.. code-block:: python
|
|
184
|
+
|
|
185
|
+
Dropout(0.1) # TypeError: Dropout's `name` must be a string ... Dropout(p=0.1)
|
|
186
|
+
Conv2D("conv", 1, 16, 3) # TypeError: takes 2 positional arguments but 5 were given
|
|
187
|
+
|
|
188
|
+
Dropout("drop", p=0.1) # torch's nn.Dropout(0.1)
|
|
189
|
+
Conv2D("conv", in_channels=1, out_channels=16, kernel_size=3)
|
|
190
|
+
|
|
191
|
+
Only the first can tell you which parameter you meant. Once the name slot holds a string
|
|
192
|
+
the extra arguments are anonymous, and the error is the one Python writes.
|
|
193
|
+
|
|
194
|
+
Every layer's name is optional and falls back to its class, so ``BatchNorm(n_in=4)`` is named
|
|
195
|
+
``BatchNorm`` and a stack of unnamed layers offers several variables of one name. The
|
|
196
|
+
serialization boundary numbers those apart, keying them ``BatchNorm_1_scale``,
|
|
197
|
+
``BatchNorm_2_scale``, ... **in the order the variables are passed**. Collecting them from the
|
|
198
|
+
same graph gives the same order every time, so an unnamed stack round-trips across processes and
|
|
199
|
+
across rebuilds -- but a checkpoint saved from one ordering will not load under another:
|
|
200
|
+
|
|
201
|
+
.. code-block:: python
|
|
202
|
+
|
|
203
|
+
shared = collect_shared_variables(network(X))
|
|
204
|
+
save_state(shared, "weights.safetensors")
|
|
205
|
+
load_state(collect_shared_variables(network(X)), "weights.safetensors") # same order, loads
|
|
206
|
+
|
|
207
|
+
Name the layers you care about and the numbering never touches them; a name that appears once is
|
|
208
|
+
its own key. The ordinal numbers the layer, not the variable, so two unnamed
|
|
209
|
+
:class:`~pytensor_ml.layers.Linear` layers give ``Linear_1_W``, ``Linear_1_b``, ``Linear_2_W``,
|
|
210
|
+
``Linear_2_b``. Shared state no layer built -- a step counter, an optimizer's moments -- carries no
|
|
211
|
+
layer to number, so a repeat there is numbered at the end of its own name instead.
|
|
212
|
+
|
|
213
|
+
The only positional argument a layer takes is its name. The two that wrap other layers take those
|
|
214
|
+
instead, and their name by keyword: :class:`~pytensor_ml.layers.Recurrent` is
|
|
215
|
+
``Recurrent(cell, name=...)`` and :class:`~pytensor_ml.layers.Bidirectional` is
|
|
216
|
+
``Bidirectional(forward, backward, name=...)``.
|
|
217
|
+
|
|
176
218
|
Convolution inputs are channels-last
|
|
177
219
|
------------------------------------
|
|
178
220
|
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
")\n",
|
|
133
133
|
"\n",
|
|
134
134
|
"y_hat = prediction_network(X_in)\n",
|
|
135
|
-
"model = Model(
|
|
135
|
+
"model = Model(y_hat, compile_kwargs={\"mode\": \"NUMBA\"})\n",
|
|
136
136
|
"model"
|
|
137
137
|
]
|
|
138
138
|
},
|
|
@@ -170,7 +170,7 @@
|
|
|
170
170
|
"# `model.compile_train` is the training companion to `model.predict`: it builds the loss against a target,\n",
|
|
171
171
|
"# differentiates it, folds in the BatchNorm running-statistic updates, and compiles a one-step training\n",
|
|
172
172
|
"# function (reusing the model's NUMBA compile settings).\n",
|
|
173
|
-
"step = model.compile_train(adagrad(learning_rate=1e-3), loss_fn
|
|
173
|
+
"step = model.compile_train(adagrad(learning_rate=1e-3), loss_fn)"
|
|
174
174
|
]
|
|
175
175
|
},
|
|
176
176
|
{
|
|
@@ -35,9 +35,8 @@ keywords = [
|
|
|
35
35
|
]
|
|
36
36
|
|
|
37
37
|
dependencies = [
|
|
38
|
-
"pytensor>=3.
|
|
38
|
+
"pytensor>=3.3.3,<4.0.0",
|
|
39
39
|
"numpy",
|
|
40
|
-
"safetensors"
|
|
41
40
|
]
|
|
42
41
|
|
|
43
42
|
[project.urls]
|
|
@@ -48,6 +47,8 @@ Tracker = "https://github.com/pymc-devs/pytensor-ml/issues"
|
|
|
48
47
|
|
|
49
48
|
[project.optional-dependencies]
|
|
50
49
|
dev = [
|
|
50
|
+
"safetensors",
|
|
51
|
+
"cloudpickle",
|
|
51
52
|
"pre-commit",
|
|
52
53
|
"pytest",
|
|
53
54
|
"pytest-cov",
|
|
@@ -71,6 +72,12 @@ version-file = "pytensor_ml/_version.py"
|
|
|
71
72
|
[tool.pytest.ini_options]
|
|
72
73
|
minversion = "6.0"
|
|
73
74
|
xfail_strict=true
|
|
75
|
+
# A checkpoint test reads a published snapshot of several GB from disk, so it runs only when asked
|
|
76
|
+
# for: `pytest -m checkpoint`.
|
|
77
|
+
addopts = "-m 'not checkpoint'"
|
|
78
|
+
markers = [
|
|
79
|
+
"checkpoint: needs a full published checkpoint on disk, not a fixture",
|
|
80
|
+
]
|
|
74
81
|
filterwarnings = [
|
|
75
82
|
"error",
|
|
76
83
|
'ignore:\nArviZ is undergoing a major refactor.*:FutureWarning',
|
|
@@ -156,7 +163,7 @@ platforms = ["osx-arm64", "linux-64", "win-64"]
|
|
|
156
163
|
# the two lists have to move together.
|
|
157
164
|
[tool.pixi.feature.docs.dependencies]
|
|
158
165
|
python = ">=3.12"
|
|
159
|
-
pytensor = ">=3.3.
|
|
166
|
+
pytensor = ">=3.3.3,<3.4.0"
|
|
160
167
|
numpy = "*"
|
|
161
168
|
safetensors = "*"
|
|
162
169
|
# The gallery extension renders notebook thumbnails with matplotlib.
|
|
@@ -3,6 +3,7 @@ import sys
|
|
|
3
3
|
|
|
4
4
|
import pytensor_ml.dispatch # installs the lazy backend-dispatch registration hook
|
|
5
5
|
import pytensor_ml.rewriting.conv # registers the convolution rewrites into pytensor's databases
|
|
6
|
+
import pytensor_ml.rewriting.layers # registers the degenerate-dropout rewrite into pytensor's databases
|
|
6
7
|
|
|
7
8
|
from pytensor_ml._version import __version__
|
|
8
9
|
from pytensor_ml.checkpoint import load_state, save_state
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.3.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 3, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -151,7 +151,7 @@ class Tanh(Activation):
|
|
|
151
151
|
|
|
152
152
|
def __call__(self, x: pt.TensorLike) -> pt.TensorVariable:
|
|
153
153
|
out = pt.tanh(x)
|
|
154
|
-
out.name = "
|
|
154
|
+
out.name = "Tanh"
|
|
155
155
|
return out
|
|
156
156
|
|
|
157
157
|
|
|
@@ -319,10 +319,36 @@ class Swish(Activation):
|
|
|
319
319
|
def __call__(self, x: pt.TensorLike) -> pt.TensorVariable:
|
|
320
320
|
x = pt.as_tensor(x)
|
|
321
321
|
out = x * pt.sigmoid(_constant_like(self.beta, x) * x)
|
|
322
|
-
out.name =
|
|
322
|
+
out.name = type(self).__name__
|
|
323
323
|
return out
|
|
324
324
|
|
|
325
325
|
|
|
326
|
+
class QuickGELU(Swish):
|
|
327
|
+
r"""
|
|
328
|
+
Sigmoid approximation to GELU.
|
|
329
|
+
|
|
330
|
+
Compute :math:`\mathrm{QuickGELU}(x) = x \, \sigma(1.702 x)`, which is exactly :class:`Swish`
|
|
331
|
+
at :math:`\beta = 1.702`. Every OpenAI CLIP checkpoint was trained with it, and loading those
|
|
332
|
+
weights under :class:`GELU` gives quietly wrong activations rather than an error. Prefer
|
|
333
|
+
:class:`GELU` for anything new.
|
|
334
|
+
|
|
335
|
+
Examples
|
|
336
|
+
--------
|
|
337
|
+
Use it where a checkpoint was trained with it, such as a CLIP text encoder's MLP:
|
|
338
|
+
|
|
339
|
+
.. code-block:: python
|
|
340
|
+
|
|
341
|
+
from pytensor_ml.activations import QuickGELU
|
|
342
|
+
from pytensor_ml.layers import FeedForward, Input
|
|
343
|
+
|
|
344
|
+
X = Input("X", shape=(None, 77, 768))
|
|
345
|
+
activations = FeedForward("mlp", d_model=768, activation=QuickGELU())(X)
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
def __init__(self):
|
|
349
|
+
super().__init__(beta=1.702)
|
|
350
|
+
|
|
351
|
+
|
|
326
352
|
class Softmax(Activation):
|
|
327
353
|
r"""
|
|
328
354
|
Softmax activation.
|
|
@@ -4,6 +4,7 @@ from typing import Protocol, runtime_checkable
|
|
|
4
4
|
import pytensor.tensor as pt
|
|
5
5
|
|
|
6
6
|
from pytensor.compile.builders import SymbolicOp
|
|
7
|
+
from pytensor.graph.basic import Variable
|
|
7
8
|
from pytensor.tensor.variable import TensorVariable
|
|
8
9
|
|
|
9
10
|
|
|
@@ -16,6 +17,39 @@ def _check_input_rank(X: TensorVariable, name: str, n_spatial: int) -> None:
|
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
def _resolve_layer_name(
|
|
21
|
+
name: object, default: str, suggested_hyperparameter: str | None = None
|
|
22
|
+
) -> str:
|
|
23
|
+
"""
|
|
24
|
+
Return the layer's name, rejecting a hyperparameter passed where the name belongs.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
name : str or None
|
|
29
|
+
The name the caller passed, annotated as ``object`` because validating it is the point.
|
|
30
|
+
None selects ``default``.
|
|
31
|
+
default : str
|
|
32
|
+
The layer's own name, used when none is given and quoted in the error.
|
|
33
|
+
suggested_hyperparameter : str, optional
|
|
34
|
+
The parameter the error tells the caller to pass by keyword instead. Layers with no
|
|
35
|
+
hyperparameter a name could displace omit it, and the error only reports the bad name.
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
resolved : str
|
|
40
|
+
``name`` when it is a non-empty string, otherwise ``default``.
|
|
41
|
+
"""
|
|
42
|
+
if name is not None and not isinstance(name, str):
|
|
43
|
+
message = f"{default}'s `name` must be a string, but got {type(name).__name__} {name!r}."
|
|
44
|
+
if suggested_hyperparameter is not None:
|
|
45
|
+
message += (
|
|
46
|
+
f" Hyperparameters are keyword-only, so pass it by name: "
|
|
47
|
+
f"{default}({suggested_hyperparameter}={name!r})."
|
|
48
|
+
)
|
|
49
|
+
raise TypeError(message)
|
|
50
|
+
return name if name else default
|
|
51
|
+
|
|
52
|
+
|
|
19
53
|
class Layer(ABC):
|
|
20
54
|
"""
|
|
21
55
|
Base class for the objects that build layer graphs. Defined here, not in ``pytensor_ml.layers``, so
|
|
@@ -89,4 +123,38 @@ class StatefulOp(Protocol):
|
|
|
89
123
|
"""Map each output index to the index of the input that output updates."""
|
|
90
124
|
|
|
91
125
|
|
|
92
|
-
|
|
126
|
+
def update_chain_root(variable: Variable) -> tuple[Variable, int] | None:
|
|
127
|
+
"""
|
|
128
|
+
Trace a stateful op's update input back to the value it ultimately writes, and count the applications
|
|
129
|
+
behind it.
|
|
130
|
+
|
|
131
|
+
Applying one layer object again feeds it what the previous application produced, so the input is the
|
|
132
|
+
written value itself only at the head of that chain. The depth orders the chain, and the deepest
|
|
133
|
+
application is the one holding every earlier contribution.
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
variable : Variable
|
|
138
|
+
The input a stateful op declares itself to update.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
root : Variable or None
|
|
143
|
+
The value written at the head of the chain, or None if the chain breaks at an op that declares no
|
|
144
|
+
update for the output it reaches.
|
|
145
|
+
depth : int
|
|
146
|
+
How many applications separate ``variable`` from ``root``.
|
|
147
|
+
"""
|
|
148
|
+
depth = 0
|
|
149
|
+
while True:
|
|
150
|
+
node = variable.owner
|
|
151
|
+
if node is None or not isinstance(node.op, StatefulOp):
|
|
152
|
+
return variable, depth
|
|
153
|
+
input_index = node.op.update_map().get(node.outputs.index(variable))
|
|
154
|
+
if input_index is None:
|
|
155
|
+
return None
|
|
156
|
+
variable = node.inputs[input_index]
|
|
157
|
+
depth += 1
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
__all__ = ["Layer", "LayerOp", "StatefulOp", "UnaryLayerOp", "update_chain_root"]
|