JianZhangAI commited on
Commit
7dcaded
·
verified ·
1 Parent(s): 4b80e61

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. pi05_twotasks_pytorch/code/openpi-main/README.md +323 -0
  2. pi05_twotasks_pytorch/code/openpi-main/pyproject.toml +140 -0
  3. pi05_twotasks_pytorch/code/openpi-main/scripts/compute_norm_stats.py +214 -0
  4. pi05_twotasks_pytorch/code/openpi-main/scripts/train.py +390 -0
  5. pi05_twotasks_pytorch/code/openpi-main/src/openpi/__init__.py +0 -0
  6. pi05_twotasks_pytorch/code/openpi-main/src/openpi/__pycache__/__init__.cpython-311.pyc +0 -0
  7. pi05_twotasks_pytorch/code/openpi-main/src/openpi/__pycache__/transforms.cpython-311.pyc +0 -0
  8. pi05_twotasks_pytorch/code/openpi-main/src/openpi/conftest.py +17 -0
  9. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__init__.py +0 -0
  10. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/__init__.cpython-311.pyc +0 -0
  11. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/gemma.cpython-311.pyc +0 -0
  12. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/gemma_fast.cpython-311.pyc +0 -0
  13. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/lora.cpython-311.pyc +0 -0
  14. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/model.cpython-311.pyc +0 -0
  15. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/pi0.cpython-311.pyc +0 -0
  16. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/pi0_config.cpython-311.pyc +0 -0
  17. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/pi0_fast.cpython-311.pyc +0 -0
  18. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/siglip.cpython-311.pyc +0 -0
  19. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/tokenizer.cpython-311.pyc +0 -0
  20. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/gemma.py +459 -0
  21. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/gemma_fast.py +437 -0
  22. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/lora.py +148 -0
  23. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/lora_test.py +94 -0
  24. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/model.py +332 -0
  25. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/model_test.py +94 -0
  26. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/pi0.py +279 -0
  27. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/pi0_config.py +117 -0
  28. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/pi0_fast.py +313 -0
  29. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/pi0_test.py +46 -0
  30. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/siglip.py +373 -0
  31. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/tokenizer.py +371 -0
  32. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/tokenizer_test.py +27 -0
  33. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/utils/__pycache__/fsq_tokenizer.cpython-311.pyc +0 -0
  34. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/utils/fsq_tokenizer.py +472 -0
  35. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/vit.py +307 -0
  36. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/__pycache__/gemma_pytorch.cpython-311.pyc +0 -0
  37. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/__pycache__/pi0_pytorch.cpython-311.pyc +0 -0
  38. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/__pycache__/preprocessing_pytorch.cpython-311.pyc +0 -0
  39. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/gemma_pytorch.py +280 -0
  40. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/pi0_pytorch.py +462 -0
  41. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/preprocessing_pytorch.py +173 -0
  42. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/gemma/configuration_gemma.py +173 -0
  43. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/gemma/modeling_gemma.py +862 -0
  44. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/paligemma/modeling_paligemma.py +622 -0
  45. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/siglip/check.py +4 -0
  46. pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/siglip/modeling_siglip.py +1237 -0
  47. pi05_twotasks_pytorch/code/openpi-main/src/openpi/policies/__pycache__/aloha_policy.cpython-311.pyc +0 -0
  48. pi05_twotasks_pytorch/code/openpi-main/src/openpi/policies/__pycache__/droid_policy.cpython-311.pyc +0 -0
  49. pi05_twotasks_pytorch/code/openpi-main/src/openpi/policies/__pycache__/franka_ee_policy.cpython-310.pyc +0 -0
  50. pi05_twotasks_pytorch/code/openpi-main/src/openpi/policies/__pycache__/franka_ee_policy.cpython-311.pyc +0 -0
pi05_twotasks_pytorch/code/openpi-main/README.md ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # openpi
2
+
3
+ openpi holds open-source models and packages for robotics, published by the [Physical Intelligence team](https://www.physicalintelligence.company/).
4
+
5
+ Currently, this repo contains three types of models:
6
+ - the [π₀ model](https://www.physicalintelligence.company/blog/pi0), a flow-based vision-language-action model (VLA).
7
+ - the [π₀-FAST model](https://www.physicalintelligence.company/research/fast), an autoregressive VLA, based on the FAST action tokenizer.
8
+ - the [π₀.₅ model](https://www.physicalintelligence.company/blog/pi05), an upgraded version of π₀ with better open-world generalization trained with [knowledge insulation](https://www.physicalintelligence.company/research/knowledge_insulation). Note that, in this repository, we currently only support the flow matching head for both $\pi_{0.5}$ training and inference.
9
+
10
+ For all models, we provide _base model_ checkpoints, pre-trained on 10k+ hours of robot data, and examples for using them out of the box or fine-tuning them to your own datasets.
11
+
12
+ This is an experiment: $\pi_0$ was developed for our own robots, which differ from the widely used platforms such as [ALOHA](https://tonyzhaozh.github.io/aloha/) and [DROID](https://droid-dataset.github.io/), and though we are optimistic that researchers and practitioners will be able to run creative new experiments adapting $\pi_0$ to their own platforms, we do not expect every such attempt to be successful. All this is to say: $\pi_0$ may or may not work for you, but you are welcome to try it and see!
13
+
14
+ ## Updates
15
+
16
+ - [Sept 2025] We released PyTorch support in openpi.
17
+ - [Sept 2025] We released pi05, an upgraded version of pi0 with better open-world generalization.
18
+ - [Sept 2025]: We have added an [improved idle filter](examples/droid/README_train.md#data-filtering) for DROID training.
19
+ - [Jun 2025]: We have added [instructions](examples/droid/README_train.md) for using `openpi` to train VLAs on the full [DROID dataset](https://droid-dataset.github.io/). This is an approximate open-source implementation of the training pipeline used to train pi0-FAST-DROID.
20
+
21
+
22
+ ## Requirements
23
+
24
+ To run the models in this repository, you will need an NVIDIA GPU with at least the following specifications. These estimations assume a single GPU, but you can also use multiple GPUs with model parallelism to reduce per-GPU memory requirements by configuring `fsdp_devices` in the training config. Please also note that the current training script does not yet support multi-node training.
25
+
26
+ | Mode | Memory Required | Example GPU |
27
+ | ------------------ | --------------- | ------------------ |
28
+ | Inference | > 8 GB | RTX 4090 |
29
+ | Fine-Tuning (LoRA) | > 22.5 GB | RTX 4090 |
30
+ | Fine-Tuning (Full) | > 70 GB | A100 (80GB) / H100 |
31
+
32
+ The repo has been tested with Ubuntu 22.04, we do not currently support other operating systems.
33
+
34
+ ## Installation
35
+
36
+ When cloning this repo, make sure to update submodules:
37
+
38
+ ```bash
39
+ git clone --recurse-submodules git@github.com:Physical-Intelligence/openpi.git
40
+
41
+ # Or if you already cloned the repo:
42
+ git submodule update --init --recursive
43
+ ```
44
+
45
+ We use [uv](https://docs.astral.sh/uv/) to manage Python dependencies. See the [uv installation instructions](https://docs.astral.sh/uv/getting-started/installation/) to set it up. Once uv is installed, run the following to set up the environment:
46
+
47
+ ```bash
48
+ GIT_LFS_SKIP_SMUDGE=1 uv sync
49
+ GIT_LFS_SKIP_SMUDGE=1 uv pip install -e .
50
+ ```
51
+
52
+ NOTE: `GIT_LFS_SKIP_SMUDGE=1` is needed to pull LeRobot as a dependency.
53
+
54
+ **Docker**: As an alternative to uv installation, we provide instructions for installing openpi using Docker. If you encounter issues with your system setup, consider using Docker to simplify installation. See [Docker Setup](docs/docker.md) for more details.
55
+
56
+
57
+
58
+
59
+ ## Model Checkpoints
60
+
61
+ ### Base Models
62
+ We provide multiple base VLA model checkpoints. These checkpoints have been pre-trained on 10k+ hours of robot data, and can be used for fine-tuning.
63
+
64
+ | Model | Use Case | Description | Checkpoint Path |
65
+ | ------------ | ----------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
66
+ | $\pi_0$ | Fine-Tuning | Base [π₀ model](https://www.physicalintelligence.company/blog/pi0) for fine-tuning | `gs://openpi-assets/checkpoints/pi0_base` |
67
+ | $\pi_0$-FAST | Fine-Tuning | Base autoregressive [π₀-FAST model](https://www.physicalintelligence.company/research/fast) for fine-tuning | `gs://openpi-assets/checkpoints/pi0_fast_base` |
68
+ | $\pi_{0.5}$ | Fine-Tuning | Base [π₀.₅ model](https://www.physicalintelligence.company/blog/pi05) for fine-tuning | `gs://openpi-assets/checkpoints/pi05_base` |
69
+
70
+ ### Fine-Tuned Models
71
+ We also provide "expert" checkpoints for various robot platforms and tasks. These models are fine-tuned from the base models above and intended to run directly on the target robot. These may or may not work on your particular robot. Since these checkpoints were fine-tuned on relatively small datasets collected with more widely available robots, such as ALOHA and the DROID Franka setup, they might not generalize to your particular setup, though we found some of these, especially the DROID checkpoint, to generalize quite broadly in practice.
72
+
73
+ | Model | Use Case | Description | Checkpoint Path |
74
+ | ------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
75
+ | $\pi_0$-FAST-DROID | Inference | $\pi_0$-FAST model fine-tuned on the [DROID dataset](https://droid-dataset.github.io/): can perform a wide range of simple table-top manipulation tasks 0-shot in new scenes on the DROID robot platform | `gs://openpi-assets/checkpoints/pi0_fast_droid` |
76
+ | $\pi_0$-DROID | Fine-Tuning | $\pi_0$ model fine-tuned on the [DROID dataset](https://droid-dataset.github.io/): faster inference than $\pi_0$-FAST-DROID, but may not follow language commands as well | `gs://openpi-assets/checkpoints/pi0_droid` |
77
+ | $\pi_0$-ALOHA-towel | Inference | $\pi_0$ model fine-tuned on internal [ALOHA](https://tonyzhaozh.github.io/aloha/) data: can fold diverse towels 0-shot on ALOHA robot platforms | `gs://openpi-assets/checkpoints/pi0_aloha_towel` |
78
+ | $\pi_0$-ALOHA-tupperware | Inference | $\pi_0$ model fine-tuned on internal [ALOHA](https://tonyzhaozh.github.io/aloha/) data: can unpack food from a tupperware container | `gs://openpi-assets/checkpoints/pi0_aloha_tupperware` |
79
+ | $\pi_0$-ALOHA-pen-uncap | Inference | $\pi_0$ model fine-tuned on public [ALOHA](https://dit-policy.github.io/) data: can uncap a pen | `gs://openpi-assets/checkpoints/pi0_aloha_pen_uncap` |
80
+ | $\pi_{0.5}$-LIBERO | Inference | $\pi_{0.5}$ model fine-tuned for the [LIBERO](https://libero-project.github.io/datasets) benchmark: gets state-of-the-art performance (see [LIBERO README](examples/libero/README.md)) | `gs://openpi-assets/checkpoints/pi05_libero` |
81
+ | $\pi_{0.5}$-DROID | Inference / Fine-Tuning | $\pi_{0.5}$ model fine-tuned on the [DROID dataset](https://droid-dataset.github.io/) with [knowledge insulation](https://www.physicalintelligence.company/research/knowledge_insulation): fast inference and good language-following | `gs://openpi-assets/checkpoints/pi05_droid` |
82
+
83
+
84
+ By default, checkpoints are automatically downloaded from `gs://openpi-assets` and are cached in `~/.cache/openpi` when needed. You can overwrite the download path by setting the `OPENPI_DATA_HOME` environment variable.
85
+
86
+
87
+
88
+
89
+ ## Running Inference for a Pre-Trained Model
90
+
91
+ Our pre-trained model checkpoints can be run with a few lines of code (here our $\pi_0$-FAST-DROID model):
92
+ ```python
93
+ from openpi.training import config as _config
94
+ from openpi.policies import policy_config
95
+ from openpi.shared import download
96
+
97
+ config = _config.get_config("pi05_droid")
98
+ checkpoint_dir = download.maybe_download("gs://openpi-assets/checkpoints/pi05_droid")
99
+
100
+ # Create a trained policy.
101
+ policy = policy_config.create_trained_policy(config, checkpoint_dir)
102
+
103
+ # Run inference on a dummy example.
104
+ example = {
105
+ "observation/exterior_image_1_left": ...,
106
+ "observation/wrist_image_left": ...,
107
+ ...
108
+ "prompt": "pick up the fork"
109
+ }
110
+ action_chunk = policy.infer(example)["actions"]
111
+ ```
112
+ You can also test this out in the [example notebook](examples/inference.ipynb).
113
+
114
+ We provide detailed step-by-step examples for running inference of our pre-trained checkpoints on [DROID](examples/droid/README.md) and [ALOHA](examples/aloha_real/README.md) robots.
115
+
116
+ **Remote Inference**: We provide [examples and code](docs/remote_inference.md) for running inference of our models **remotely**: the model can run on a different server and stream actions to the robot via a websocket connection. This makes it easy to use more powerful GPUs off-robot and keep robot and policy environments separate.
117
+
118
+ **Test inference without a robot**: We provide a [script](examples/simple_client/README.md) for testing inference without a robot. This script will generate a random observation and run inference with the model. See [here](examples/simple_client/README.md) for more details.
119
+
120
+
121
+
122
+
123
+
124
+ ## Fine-Tuning Base Models on Your Own Data
125
+
126
+ We will fine-tune the $\pi_{0.5}$ model on the [LIBERO dataset](https://libero-project.github.io/datasets) as a running example for how to fine-tune a base model on your own data. We will explain three steps:
127
+ 1. Convert your data to a LeRobot dataset (which we use for training)
128
+ 2. Defining training configs and running training
129
+ 3. Spinning up a policy server and running inference
130
+
131
+ ### 1. Convert your data to a LeRobot dataset
132
+
133
+ We provide a minimal example script for converting LIBERO data to a LeRobot dataset in [`examples/libero/convert_libero_data_to_lerobot.py`](examples/libero/convert_libero_data_to_lerobot.py). You can easily modify it to convert your own data! You can download the raw LIBERO dataset from [here](https://huggingface.co/datasets/openvla/modified_libero_rlds), and run the script with:
134
+
135
+ ```bash
136
+ uv run examples/libero/convert_libero_data_to_lerobot.py --data_dir /path/to/your/libero/data
137
+ ```
138
+
139
+ **Note:** If you just want to fine-tune on LIBERO, you can skip this step, because our LIBERO fine-tuning configs point to a pre-converted LIBERO dataset. This step is merely an example that you can adapt to your own data.
140
+
141
+ ### 2. Defining training configs and running training
142
+
143
+ To fine-tune a base model on your own data, you need to define configs for data processing and training. We provide example configs with detailed comments for LIBERO below, which you can modify for your own dataset:
144
+
145
+ - [`LiberoInputs` and `LiberoOutputs`](src/openpi/policies/libero_policy.py): Defines the data mapping from the LIBERO environment to the model and vice versa. Will be used for both, training and inference.
146
+ - [`LeRobotLiberoDataConfig`](src/openpi/training/config.py): Defines how to process raw LIBERO data from LeRobot dataset for training.
147
+ - [`TrainConfig`](src/openpi/training/config.py): Defines fine-tuning hyperparameters, data config, and weight loader.
148
+
149
+ We provide example fine-tuning configs for [π₀](src/openpi/training/config.py), [π₀-FAST](src/openpi/training/config.py), and [π₀.₅](src/openpi/training/config.py) on LIBERO data.
150
+
151
+ Before we can run training, we need to compute the normalization statistics for the training data. Run the script below with the name of your training config:
152
+
153
+ ```bash
154
+ uv run scripts/compute_norm_stats.py --config-name pi05_libero
155
+ ```
156
+
157
+ Now we can kick off training with the following command (the `--overwrite` flag is used to overwrite existing checkpoints if you rerun fine-tuning with the same config):
158
+
159
+ ```bash
160
+ XLA_PYTHON_CLIENT_MEM_FRACTION=0.9 uv run scripts/train.py pi05_libero --exp-name=my_experiment --overwrite
161
+ ```
162
+
163
+ The command will log training progress to the console and save checkpoints to the `checkpoints` directory. You can also monitor training progress on the Weights & Biases dashboard. For maximally using the GPU memory, set `XLA_PYTHON_CLIENT_MEM_FRACTION=0.9` before running training -- this enables JAX to use up to 90% of the GPU memory (vs. the default of 75%).
164
+
165
+ **Note:** We provide functionality for *reloading* normalization statistics for state / action normalization from pre-training. This can be beneficial if you are fine-tuning to a new task on a robot that was part of our pre-training mixture. For more details on how to reload normalization statistics, see the [norm_stats.md](docs/norm_stats.md) file.
166
+
167
+ ### 3. Spinning up a policy server and running inference
168
+
169
+ Once training is complete, we can run inference by spinning up a policy server and then querying it from a LIBERO evaluation script. Launching a model server is easy (we use the checkpoint for iteration 20,000 for this example, modify as needed):
170
+
171
+ ```bash
172
+ uv run scripts/serve_policy.py policy:checkpoint --policy.config=pi05_libero --policy.dir=checkpoints/pi05_libero/my_experiment/20000
173
+ ```
174
+
175
+ This will spin up a server that listens on port 8000 and waits for observations to be sent to it. We can then run an evaluation script (or robot runtime) that queries the server.
176
+
177
+ For running the LIBERO eval in particular, we provide (and recommend using) a Dockerized workflow that handles both the policy server and the evaluation script together. See the [LIBERO README](examples/libero/README.md) for more details.
178
+
179
+ If you want to embed a policy server call in your own robot runtime, we have a minimal example of how to do so in the [remote inference docs](docs/remote_inference.md).
180
+
181
+
182
+
183
+ ### More Examples
184
+
185
+ We provide more examples for how to fine-tune and run inference with our models on the ALOHA platform in the following READMEs:
186
+ - [ALOHA Simulator](examples/aloha_sim)
187
+ - [ALOHA Real](examples/aloha_real)
188
+ - [UR5](examples/ur5)
189
+
190
+ ## PyTorch Support
191
+
192
+ openpi now provides PyTorch implementations of π₀ and π₀.₅ models alongside the original JAX versions! The PyTorch implementation has been validated on the LIBERO benchmark (both inference and finetuning). A few features are currently not supported (this may change in the future):
193
+
194
+ - The π₀-FAST model
195
+ - Mixed precision training
196
+ - FSDP (fully-sharded data parallelism) training
197
+ - LoRA (low-rank adaptation) training
198
+ - EMA (exponential moving average) weights during training
199
+
200
+ ### Setup
201
+ 1. Make sure that you have the latest version of all dependencies installed: `uv sync`
202
+
203
+ 2. Double check that you have transformers 4.53.2 installed: `uv pip show transformers`
204
+
205
+ 3. Apply the transformers library patches:
206
+ ```bash
207
+ cp -r ./src/openpi/models_pytorch/transformers_replace/* .venv/lib/python3.11/site-packages/transformers/
208
+ ```
209
+
210
+ This overwrites several files in the transformers library with necessary model changes: 1) supporting AdaRMS, 2) correctly controlling the precision of activations, and 3) allowing the KV cache to be used without being updated.
211
+
212
+ **WARNING**: With the default uv link mode (hardlink), this will permanently affect the transformers library in your uv cache, meaning the changes will survive reinstallations of transformers and could even propagate to other projects that use transformers. To fully undo this operation, you must run `uv cache clean transformers`.
213
+
214
+ ### Converting JAX Models to PyTorch
215
+
216
+ To convert a JAX model checkpoint to PyTorch format:
217
+
218
+ ```bash
219
+ uv run examples/convert_jax_model_to_pytorch.py \
220
+ --checkpoint_dir /path/to/jax/checkpoint \
221
+ --config_name <config name> \
222
+ --output_path /path/to/converted/pytorch/checkpoint
223
+ ```
224
+
225
+ ### Running Inference with PyTorch
226
+
227
+ The PyTorch implementation uses the same API as the JAX version - you only need to change the checkpoint path to point to the converted PyTorch model:
228
+
229
+ ```python
230
+ from openpi.training import config as _config
231
+ from openpi.policies import policy_config
232
+ from openpi.shared import download
233
+
234
+ config = _config.get_config("pi05_droid")
235
+ checkpoint_dir = "/path/to/converted/pytorch/checkpoint"
236
+
237
+ # Create a trained policy (automatically detects PyTorch format)
238
+ policy = policy_config.create_trained_policy(config, checkpoint_dir)
239
+
240
+ # Run inference (same API as JAX)
241
+ action_chunk = policy.infer(example)["actions"]
242
+ ```
243
+
244
+ ### Policy Server with PyTorch
245
+
246
+ The policy server works identically with PyTorch models - just point to the converted checkpoint directory:
247
+
248
+ ```bash
249
+ uv run scripts/serve_policy.py policy:checkpoint \
250
+ --policy.config=pi05_droid \
251
+ --policy.dir=/path/to/converted/pytorch/checkpoint
252
+ ```
253
+
254
+ ### Finetuning with PyTorch
255
+
256
+ To finetune a model in PyTorch:
257
+
258
+ 1. Convert the JAX base model to PyTorch format:
259
+ ```bash
260
+ uv run examples/convert_jax_model_to_pytorch.py \
261
+ --config_name <config name> \
262
+ --checkpoint_dir /path/to/jax/base/model \
263
+ --output_path /path/to/pytorch/base/model
264
+ ```
265
+
266
+ 2. Specify the converted PyTorch model path in your config using `pytorch_weight_path`
267
+
268
+ 3. Launch training using one of these modes:
269
+
270
+ ```bash
271
+ # Single GPU training:
272
+ uv run scripts/train_pytorch.py <config_name> --exp_name <run_name> --save_interval <interval>
273
+
274
+ # Example:
275
+ uv run scripts/train_pytorch.py debug --exp_name pytorch_test
276
+ uv run scripts/train_pytorch.py debug --exp_name pytorch_test --resume # Resume from latest checkpoint
277
+
278
+ # Multi-GPU training (single node):
279
+ uv run torchrun --standalone --nnodes=1 --nproc_per_node=<num_gpus> scripts/train_pytorch.py <config_name> --exp_name <run_name>
280
+
281
+ # Example:
282
+ uv run torchrun --standalone --nnodes=1 --nproc_per_node=2 scripts/train_pytorch.py pi0_aloha_sim --exp_name pytorch_ddp_test
283
+ uv run torchrun --standalone --nnodes=1 --nproc_per_node=2 scripts/train_pytorch.py pi0_aloha_sim --exp_name pytorch_ddp_test --resume
284
+
285
+ # Multi-Node Training:
286
+ uv run torchrun \
287
+ --nnodes=<num_nodes> \
288
+ --nproc_per_node=<gpus_per_node> \
289
+ --node_rank=<rank_of_node> \
290
+ --master_addr=<master_ip> \
291
+ --master_port=<port> \
292
+ scripts/train_pytorch.py <config_name> --exp_name=<run_name> --save_interval <interval>
293
+ ```
294
+
295
+ ### Precision Settings
296
+
297
+ JAX and PyTorch implementations handle precision as follows:
298
+
299
+ **JAX:**
300
+ 1. Inference: most weights and computations in bfloat16, with a few computations in float32 for stability
301
+ 2. Training: defaults to mixed precision: weights and gradients in float32, (most) activations and computations in bfloat16. You can change to full float32 training by setting `dtype` to float32 in the config.
302
+
303
+ **PyTorch:**
304
+ 1. Inference: matches JAX -- most weights and computations in bfloat16, with a few weights converted to float32 for stability
305
+ 2. Training: supports either full bfloat16 (default) or full float32. You can change it by setting `pytorch_training_precision` in the config. bfloat16 uses less memory but exhibits higher losses compared to float32. Mixed precision is not yet supported.
306
+
307
+ With torch.compile, inference speed is comparable between JAX and PyTorch.
308
+
309
+ ## Troubleshooting
310
+
311
+ We will collect common issues and their solutions here. If you encounter an issue, please check here first. If you can't find a solution, please file an issue on the repo (see [here](CONTRIBUTING.md) for guidelines).
312
+
313
+ | Issue | Resolution |
314
+ | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
315
+ | `uv sync` fails with dependency conflicts | Try removing the virtual environment directory (`rm -rf .venv`) and running `uv sync` again. If issues persist, check that you have the latest version of `uv` installed (`uv self update`). |
316
+ | Training runs out of GPU memory | Make sure you set `XLA_PYTHON_CLIENT_MEM_FRACTION=0.9` (or higher) before running training to allow JAX to use more GPU memory. You can also use `--fsdp-devices <n>` where `<n>` is your number of GPUs, to enable [fully-sharded data parallelism](https://engineering.fb.com/2021/07/15/open-source/fsdp/), which reduces memory usage in exchange for slower training (the amount of slowdown depends on your particular setup). If you are still running out of memory, you may want to consider disabling EMA. |
317
+ | Policy server connection errors | Check that the server is running and listening on the expected port. Verify network connectivity and firewall settings between client and server. |
318
+ | Missing norm stats error when training | Run `scripts/compute_norm_stats.py` with your config name before starting training. |
319
+ | Dataset download fails | Check your internet connection. For HuggingFace datasets, ensure you're logged in (`huggingface-cli login`). |
320
+ | CUDA/GPU errors | Verify NVIDIA drivers are installed correctly. For Docker, ensure nvidia-container-toolkit is installed. Check GPU compatibility. You do NOT need CUDA libraries installed at a system level --- they will be installed via uv. You may even want to try *uninstalling* system CUDA libraries if you run into CUDA issues, since system libraries can sometimes cause conflicts. |
321
+ | Import errors when running examples | Make sure you've installed all dependencies with `uv sync`. Some examples may have additional requirements listed in their READMEs. |
322
+ | Action dimensions mismatch | Verify your data processing transforms match the expected input/output dimensions of your robot. Check the action space definitions in your policy classes. |
323
+ | Diverging training loss | Check the `q01`, `q99`, and `std` values in `norm_stats.json` for your dataset. Certain dimensions that are rarely used can end up with very small `q01`, `q99`, or `std` values, leading to huge states and actions after normalization. You can manually adjust the norm stats as a workaround. |
pi05_twotasks_pytorch/code/openpi-main/pyproject.toml ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "openpi"
3
+ version = "0.1.0"
4
+ description = "Physical Intelligence open source repo"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = { file = "LICENSE" }
8
+ dependencies = [
9
+ "augmax>=0.3.4",
10
+ "dm-tree>=0.1.8",
11
+ "einops>=0.8.0",
12
+ "equinox>=0.11.8",
13
+ "flatbuffers>=24.3.25",
14
+ "flax==0.10.2",
15
+ "fsspec[gcs]>=2024.6.0",
16
+ "gym-aloha>=0.1.1",
17
+ "imageio>=2.36.1",
18
+ "jax[cuda12]==0.5.3",
19
+ "jaxtyping==0.2.36",
20
+ "lerobot",
21
+ "ml_collections==1.0.0",
22
+ "numpy>=1.22.4,<2.0.0",
23
+ "numpydantic>=1.6.6",
24
+ "opencv-python-headless>=4.10.0.84",
25
+ "openpi-client",
26
+ "orbax-checkpoint==0.11.13",
27
+ "pillow>=11.0.0",
28
+ "sentencepiece>=0.2.0",
29
+ "torch==2.7.1",
30
+ "tqdm-loggable>=0.2",
31
+ "typing-extensions>=4.12.2",
32
+ "tyro>=0.9.5",
33
+ "wandb>=0.26.1",
34
+ "filelock>=3.16.1",
35
+ "beartype==0.19.0",
36
+ "chex==0.1.90",
37
+ "treescope>=0.1.7",
38
+ "transformers==4.53.2",
39
+ "rich>=14.0.0",
40
+ "polars>=1.30.0",
41
+ ]
42
+
43
+
44
+ [project.urls]
45
+ Repository = "https://github.com/Physical-Intelligence/openpi"
46
+
47
+ [dependency-groups]
48
+ dev = [
49
+ "pytest>=8.3.4",
50
+ "ruff>=0.8.6",
51
+ "pre-commit>=4.0.1",
52
+ "ipykernel>=6.29.5",
53
+ "ipywidgets>=8.1.5",
54
+ "matplotlib>=3.10.0",
55
+ "pynvml>=12.0.0",
56
+ ]
57
+ rlds = [
58
+ # NOTE: tensorflow-cpu 2.15.0 only ships cp311 wheels on PyPI.
59
+ # Use `uv venv --python 3.11` before `uv sync --group rlds`.
60
+ "dlimp",
61
+ "tensorflow-cpu==2.15.0",
62
+ "tensorflow-datasets==4.9.9",
63
+ ]
64
+
65
+ [tool.uv]
66
+ override-dependencies = ["ml-dtypes==0.4.1", "tensorstore==0.1.74"]
67
+
68
+ [tool.uv.sources]
69
+ openpi-client = { workspace = true }
70
+ lerobot = { git = "https://github.com/huggingface/lerobot", rev = "0cf864870cf29f4738d3ade893e6fd13fbd7cdb5" }
71
+ dlimp = { git = "https://github.com/kvablack/dlimp", rev = "ad72ce3a9b414db2185bc0b38461d4101a65477a" }
72
+
73
+ [tool.uv.workspace]
74
+ members = ["packages/*"]
75
+
76
+ [tool.ruff]
77
+ line-length = 120
78
+ target-version = "py311"
79
+ extend-exclude = ["docker", "third_party", "src/openpi/models_pytorch/transformers_replace/*"]
80
+
81
+ [tool.ruff.lint]
82
+ # https://docs.astral.sh/ruff/rules/
83
+ select = [
84
+ "B",
85
+ "C4",
86
+ "DTZ",
87
+ "E4",
88
+ "E7",
89
+ "E9",
90
+ "F",
91
+ "FBT",
92
+ "FURB",
93
+ "I",
94
+ "ICN",
95
+ "ISC",
96
+ "LOG",
97
+ "N",
98
+ "PD",
99
+ "PERF",
100
+ "PIE",
101
+ "PLC",
102
+ "PLE",
103
+ "PLR1",
104
+ "PLR5",
105
+ "PLW",
106
+ "PT",
107
+ "Q",
108
+ "RET",
109
+ "RUF",
110
+ "SIM",
111
+ "SLF",
112
+ "T10",
113
+ "T20",
114
+ "UP",
115
+ "W",
116
+ ]
117
+ ignore = [
118
+ "F722", # Conflicts with array typing.
119
+ "T201", # We use print statements.
120
+ "PD008", # Lots of false positives.
121
+ "ISC001", # Disabling to support ruff format.
122
+ "LOG015", # Use logger.info.
123
+ ]
124
+ unfixable = [
125
+ "B905", # Fix defaults to strict=False, which is not what we want.
126
+ ]
127
+
128
+ [tool.ruff.lint.isort]
129
+ force-single-line = true
130
+ force-sort-within-sections = true
131
+ single-line-exclusions = ["collections.abc", "typing", "typing_extensions"]
132
+ known-third-party = ["wandb"]
133
+
134
+ [build-system]
135
+ requires = ["hatchling"]
136
+ build-backend = "hatchling.build"
137
+
138
+ [tool.pytest.ini_options]
139
+ markers = ["manual: should be run manually."]
140
+ testpaths = ["src", "scripts", "packages"]
pi05_twotasks_pytorch/code/openpi-main/scripts/compute_norm_stats.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Compute normalization statistics for a config.
2
+
3
+ This script is used to compute the normalization statistics for a given config. It
4
+ will compute the mean and standard deviation of the data in the dataset and save it
5
+ to the config assets directory.
6
+ """
7
+
8
+ import os
9
+
10
+ import numpy as np
11
+ import tqdm
12
+ import tyro
13
+
14
+ import openpi.models.model as _model
15
+ import openpi.shared.normalize as normalize
16
+ import openpi.training.config as _config
17
+ import openpi.training.data_loader as _data_loader
18
+ import openpi.transforms as transforms
19
+
20
+
21
+ class RemoveStrings(transforms.DataTransformFn):
22
+ def __call__(self, x: dict) -> dict:
23
+ return {k: v for k, v in x.items() if not np.issubdtype(np.asarray(v).dtype, np.str_)}
24
+
25
+
26
+ class KeepNormKeys(transforms.DataTransformFn):
27
+ def __call__(self, x: dict) -> dict:
28
+ return {"state": np.asarray(x["state"], dtype=np.float32), "actions": np.asarray(x["actions"], dtype=np.float32)}
29
+
30
+
31
+ def create_torch_dataloader(
32
+ data_config: _config.DataConfig,
33
+ action_horizon: int,
34
+ batch_size: int,
35
+ model_config: _model.BaseModelConfig,
36
+ num_workers: int,
37
+ max_frames: int | None = None,
38
+ fast_state_action_only: bool = False,
39
+ ) -> tuple[_data_loader.Dataset, int]:
40
+ if data_config.repo_id is None:
41
+ raise ValueError("Data config must have a repo_id")
42
+ dataset = _data_loader.create_torch_dataset(data_config, action_horizon, model_config)
43
+ if fast_state_action_only:
44
+ transform_fns = [
45
+ *data_config.repack_transforms.inputs,
46
+ KeepNormKeys(),
47
+ ]
48
+ else:
49
+ transform_fns = [
50
+ *data_config.repack_transforms.inputs,
51
+ *data_config.data_transforms.inputs,
52
+ # Remove strings since they are not supported by JAX and are not needed to compute norm stats.
53
+ RemoveStrings(),
54
+ ]
55
+ dataset = _data_loader.TransformedDataset(dataset, transform_fns)
56
+ if max_frames is not None and max_frames < len(dataset):
57
+ num_batches = max_frames // batch_size
58
+ shuffle = True
59
+ else:
60
+ num_batches = len(dataset) // batch_size
61
+ shuffle = False
62
+ data_loader = _data_loader.TorchDataLoader(
63
+ dataset,
64
+ local_batch_size=batch_size,
65
+ num_workers=num_workers,
66
+ shuffle=shuffle,
67
+ num_batches=num_batches,
68
+ )
69
+ return data_loader, num_batches
70
+
71
+
72
+ def create_rlds_dataloader(
73
+ data_config: _config.DataConfig,
74
+ action_horizon: int,
75
+ batch_size: int,
76
+ max_frames: int | None = None,
77
+ ) -> tuple[_data_loader.Dataset, int]:
78
+ dataset = _data_loader.create_rlds_dataset(data_config, action_horizon, batch_size, shuffle=False)
79
+ dataset = _data_loader.IterableTransformedDataset(
80
+ dataset,
81
+ [
82
+ *data_config.repack_transforms.inputs,
83
+ *data_config.data_transforms.inputs,
84
+ # Remove strings since they are not supported by JAX and are not needed to compute norm stats.
85
+ RemoveStrings(),
86
+ ],
87
+ is_batched=True,
88
+ )
89
+ if max_frames is not None and max_frames < len(dataset):
90
+ num_batches = max_frames // batch_size
91
+ else:
92
+ # NOTE: this length is currently hard-coded for DROID.
93
+ num_batches = len(dataset) // batch_size
94
+ data_loader = _data_loader.RLDSDataLoader(
95
+ dataset,
96
+ num_batches=num_batches,
97
+ )
98
+ return data_loader, num_batches
99
+
100
+
101
+
102
+
103
+ def _repo_ids(repo_id) -> list[str]:
104
+ if isinstance(repo_id, (tuple, list)):
105
+ return [str(x) for x in repo_id]
106
+ return [str(repo_id)]
107
+
108
+
109
+ def _write_norm_stats(config: _config.TrainConfig, data_config: _config.DataConfig, norm_stats: dict[str, normalize.NormStats]) -> None:
110
+ asset_id = data_config.asset_id or data_config.repo_id
111
+ if not isinstance(asset_id, str):
112
+ raise ValueError("Multi-dataset configs must set assets.asset_id before computing norm stats.")
113
+ output_path = config.assets_dirs / asset_id
114
+ print(f"Writing stats to: {output_path}")
115
+ normalize.save(output_path, norm_stats)
116
+
117
+
118
+ def compute_parquet_state_action_norm_stats(
119
+ config: _config.TrainConfig,
120
+ data_config: _config.DataConfig,
121
+ max_frames: int | None = None,
122
+ state_key: str = "observation.state",
123
+ action_key: str = "action",
124
+ ) -> None:
125
+ import pathlib
126
+ import pyarrow.parquet as pq
127
+
128
+ stats = {"state": normalize.RunningStats(), "actions": normalize.RunningStats()}
129
+ total_frames = 0
130
+ parquet_files = []
131
+ for root in _repo_ids(data_config.repo_id):
132
+ root_path = os.path.abspath(root)
133
+ if not os.path.exists(os.path.join(root_path, "meta", "info.json")):
134
+ raise ValueError(f"parquet_state_action_only requires local LeRobot roots, got: {root}")
135
+ files = sorted(str(p) for p in pathlib.Path(root_path).glob("data/chunk-*/episode_*.parquet"))
136
+ parquet_files.extend(files)
137
+ print(f"Using parquet state/action-only norm stats path over {len(parquet_files)} parquet files.")
138
+ for parquet_path in tqdm.tqdm(parquet_files, desc="Reading parquet stats"):
139
+ table = pq.read_table(parquet_path, columns=[state_key, action_key])
140
+ state = np.asarray(table[state_key].to_pylist(), dtype=np.float32)
141
+ action = np.asarray(table[action_key].to_pylist(), dtype=np.float32)
142
+ if max_frames is not None:
143
+ remaining = max_frames - total_frames
144
+ if remaining <= 0:
145
+ break
146
+ state = state[:remaining]
147
+ action = action[:remaining]
148
+ if len(state) == 0:
149
+ continue
150
+ stats["state"].update(state)
151
+ stats["actions"].update(action)
152
+ total_frames += len(state)
153
+ if max_frames is not None and total_frames >= max_frames:
154
+ break
155
+ if total_frames == 0:
156
+ raise ValueError("No frames were read for norm stats.")
157
+ print(f"Read {total_frames} frames for norm stats.")
158
+ norm_stats = {key: stat.get_statistics() for key, stat in stats.items()}
159
+ _write_norm_stats(config, data_config, norm_stats)
160
+
161
+
162
+ def main(
163
+ config_name: str,
164
+ max_frames: int | None = None,
165
+ fast_state_action_only: bool = False,
166
+ parquet_state_action_only: bool = False,
167
+ state_key: str = "observation.state",
168
+ action_key: str = "action",
169
+ ):
170
+ config = _config.get_config(config_name)
171
+ data_config = config.data.create(config.assets_dirs, config.model)
172
+
173
+ if parquet_state_action_only:
174
+ compute_parquet_state_action_norm_stats(config, data_config, max_frames, state_key, action_key)
175
+ return
176
+
177
+ if data_config.rlds_data_dir is not None:
178
+ if fast_state_action_only:
179
+ raise ValueError("fast_state_action_only is only implemented for torch/LeRobot datasets.")
180
+ data_loader, num_batches = create_rlds_dataloader(
181
+ data_config, config.model.action_horizon, config.batch_size, max_frames
182
+ )
183
+ else:
184
+ if fast_state_action_only:
185
+ print("Using fast state/action-only norm stats path; image/video transforms are skipped.")
186
+ data_loader, num_batches = create_torch_dataloader(
187
+ data_config,
188
+ config.model.action_horizon,
189
+ config.batch_size,
190
+ config.model,
191
+ config.num_workers,
192
+ max_frames,
193
+ fast_state_action_only=fast_state_action_only,
194
+ )
195
+
196
+ keys = ["state", "actions"]
197
+ stats = {key: normalize.RunningStats() for key in keys}
198
+
199
+ for batch in tqdm.tqdm(data_loader, total=num_batches, desc="Computing stats"):
200
+ for key in keys:
201
+ stats[key].update(np.asarray(batch[key]))
202
+
203
+ norm_stats = {key: stats.get_statistics() for key, stats in stats.items()}
204
+
205
+ asset_id = data_config.asset_id or data_config.repo_id
206
+ if not isinstance(asset_id, str):
207
+ raise ValueError("Multi-dataset configs must set assets.asset_id before computing norm stats.")
208
+ output_path = config.assets_dirs / asset_id
209
+ print(f"Writing stats to: {output_path}")
210
+ normalize.save(output_path, norm_stats)
211
+
212
+
213
+ if __name__ == "__main__":
214
+ tyro.cli(main)
pi05_twotasks_pytorch/code/openpi-main/scripts/train.py ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import dataclasses
2
+ import functools
3
+ import logging
4
+ import os
5
+ import platform
6
+ import struct
7
+ import time
8
+ from typing import Any
9
+
10
+ import etils.epath as epath
11
+ import flax.nnx as nnx
12
+ from flax.training import common_utils
13
+ import flax.traverse_util as traverse_util
14
+ import jax
15
+ import jax.experimental
16
+ import jax.numpy as jnp
17
+ import numpy as np
18
+ import optax
19
+ import tqdm_loggable.auto as tqdm
20
+ import wandb
21
+
22
+ import openpi.models.model as _model
23
+ import openpi.shared.array_typing as at
24
+ import openpi.shared.nnx_utils as nnx_utils
25
+ import openpi.training.checkpoints as _checkpoints
26
+ import openpi.training.config as _config
27
+ import openpi.training.data_loader as _data_loader
28
+ import openpi.training.optimizer as _optimizer
29
+ import openpi.training.sharding as sharding
30
+ import openpi.training.utils as training_utils
31
+ import openpi.training.weight_loaders as _weight_loaders
32
+
33
+
34
+ def init_logging():
35
+ """Custom logging format for better readability."""
36
+ level_mapping = {"DEBUG": "D", "INFO": "I", "WARNING": "W", "ERROR": "E", "CRITICAL": "C"}
37
+
38
+ class CustomFormatter(logging.Formatter):
39
+ def format(self, record):
40
+ record.levelname = level_mapping.get(record.levelname, record.levelname)
41
+ return super().format(record)
42
+
43
+ formatter = CustomFormatter(
44
+ fmt="%(asctime)s.%(msecs)03d [%(levelname)s] %(message)-80s (%(process)d:%(filename)s:%(lineno)s)",
45
+ datefmt="%H:%M:%S",
46
+ )
47
+
48
+ logger = logging.getLogger()
49
+ logger.setLevel(logging.INFO)
50
+ logger.handlers[0].setFormatter(formatter)
51
+
52
+
53
+ _CRC32C_TABLE = None
54
+
55
+
56
+ def _crc32c(data: bytes) -> int:
57
+ global _CRC32C_TABLE
58
+ if _CRC32C_TABLE is None:
59
+ table = []
60
+ for i in range(256):
61
+ crc = i
62
+ for _ in range(8):
63
+ if crc & 1:
64
+ crc = (crc >> 1) ^ 0x82F63B78
65
+ else:
66
+ crc >>= 1
67
+ table.append(crc & 0xFFFFFFFF)
68
+ _CRC32C_TABLE = table
69
+
70
+ crc = 0xFFFFFFFF
71
+ for byte in data:
72
+ crc = (crc >> 8) ^ _CRC32C_TABLE[(crc ^ byte) & 0xFF]
73
+ return crc ^ 0xFFFFFFFF
74
+
75
+
76
+ def _masked_crc32c(data: bytes) -> int:
77
+ crc = _crc32c(data)
78
+ return (((crc >> 15) | ((crc << 17) & 0xFFFFFFFF)) + 0xA282EAD8) & 0xFFFFFFFF
79
+
80
+
81
+ def _varint(value: int) -> bytes:
82
+ out = bytearray()
83
+ while value > 0x7F:
84
+ out.append((value & 0x7F) | 0x80)
85
+ value >>= 7
86
+ out.append(value)
87
+ return bytes(out)
88
+
89
+
90
+ def _bytes_field(field: int, value: bytes) -> bytes:
91
+ return _varint((field << 3) | 2) + _varint(len(value)) + value
92
+
93
+
94
+ def _event_file_version_record() -> bytes:
95
+ wall_time = time.time()
96
+ return _varint((1 << 3) | 1) + struct.pack("<d", wall_time) + _bytes_field(3, b"brain.Event:2")
97
+
98
+
99
+ def _scalar_event_record(tag: str, value: float, step: int) -> bytes:
100
+ tag_bytes = tag.encode("utf-8")
101
+ scalar_value = _bytes_field(1, tag_bytes) + _varint((2 << 3) | 5) + struct.pack("<f", float(value))
102
+ summary = _bytes_field(1, scalar_value)
103
+ return (
104
+ _varint((1 << 3) | 1)
105
+ + struct.pack("<d", time.time())
106
+ + _varint((2 << 3) | 0)
107
+ + _varint(int(step))
108
+ + _bytes_field(5, summary)
109
+ )
110
+
111
+
112
+ class _TensorBoardEventWriter:
113
+ """Minimal TensorBoard scalar event writer.
114
+
115
+ It writes TFRecord event files with scalar summaries, avoiding an extra runtime
116
+ dependency on tensorboard inside the training environment.
117
+ """
118
+
119
+ def __init__(self, log_dir: str):
120
+ os.makedirs(log_dir, exist_ok=True)
121
+ filename = f"events.out.tfevents.{int(time.time())}.{platform.node()}.{os.getpid()}.0"
122
+ self.path = os.path.join(log_dir, filename)
123
+ self._file = open(self.path, "wb")
124
+ self._write_record(_event_file_version_record())
125
+ self.flush()
126
+
127
+ def _write_record(self, payload: bytes):
128
+ length = struct.pack("<Q", len(payload))
129
+ self._file.write(length)
130
+ self._file.write(struct.pack("<I", _masked_crc32c(length)))
131
+ self._file.write(payload)
132
+ self._file.write(struct.pack("<I", _masked_crc32c(payload)))
133
+
134
+ def add_scalar(self, tag: str, value: float, step: int):
135
+ self._write_record(_scalar_event_record(tag, float(value), int(step)))
136
+
137
+ def flush(self):
138
+ self._file.flush()
139
+
140
+ def close(self):
141
+ self._file.close()
142
+
143
+
144
+ def init_tensorboard(config: _config.TrainConfig):
145
+ if not config.tensorboard_enabled:
146
+ return None
147
+ log_dir = config.tensorboard_log_dir or str(config.checkpoint_dir / "tensorboard")
148
+ writer = _TensorBoardEventWriter(log_dir)
149
+ logging.info("TensorBoard logging enabled: %s", log_dir)
150
+ logging.info("TensorBoard event file: %s", writer.path)
151
+ return writer
152
+
153
+ def init_wandb(config: _config.TrainConfig, *, resuming: bool, log_code: bool = False, enabled: bool = True):
154
+ if not enabled:
155
+ wandb.init(mode="disabled")
156
+ return
157
+
158
+ ckpt_dir = config.checkpoint_dir
159
+ if not ckpt_dir.exists():
160
+ raise FileNotFoundError(f"Checkpoint directory {ckpt_dir} does not exist.")
161
+ if resuming:
162
+ run_id = (ckpt_dir / "wandb_id.txt").read_text().strip()
163
+ wandb.init(id=run_id, resume="must", project=config.project_name)
164
+ else:
165
+ wandb.init(
166
+ name=config.exp_name,
167
+ config=dataclasses.asdict(config),
168
+ project=config.project_name,
169
+ )
170
+ (ckpt_dir / "wandb_id.txt").write_text(wandb.run.id)
171
+
172
+ if log_code:
173
+ wandb.run.log_code(epath.Path(__file__).parent.parent)
174
+
175
+
176
+ def _load_weights_and_validate(loader: _weight_loaders.WeightLoader, params_shape: at.Params) -> at.Params:
177
+ """Loads and validates the weights. Returns a loaded subset of the weights."""
178
+ loaded_params = loader.load(params_shape)
179
+ at.check_pytree_equality(expected=params_shape, got=loaded_params, check_shapes=True, check_dtypes=True)
180
+
181
+ # Remove jax.ShapeDtypeStruct from the loaded params. This makes sure that only the loaded params are returned.
182
+ return traverse_util.unflatten_dict(
183
+ {k: v for k, v in traverse_util.flatten_dict(loaded_params).items() if not isinstance(v, jax.ShapeDtypeStruct)}
184
+ )
185
+
186
+
187
+ @at.typecheck
188
+ def init_train_state(
189
+ config: _config.TrainConfig, init_rng: at.KeyArrayLike, mesh: jax.sharding.Mesh, *, resume: bool
190
+ ) -> tuple[training_utils.TrainState, Any]:
191
+ tx = _optimizer.create_optimizer(config.optimizer, config.lr_schedule, weight_decay_mask=None)
192
+
193
+ def init(rng: at.KeyArrayLike, partial_params: at.Params | None = None) -> training_utils.TrainState:
194
+ rng, model_rng = jax.random.split(rng)
195
+ # initialize the model (and its parameters).
196
+ model = config.model.create(model_rng)
197
+
198
+ # Merge the partial params into the model.
199
+ if partial_params is not None:
200
+ graphdef, state = nnx.split(model)
201
+ # This will produce an error if the partial params are not a subset of the state.
202
+ state.replace_by_pure_dict(partial_params)
203
+ model = nnx.merge(graphdef, state)
204
+
205
+ params = nnx.state(model)
206
+ # Convert frozen params to bfloat16.
207
+ params = nnx_utils.state_map(params, config.freeze_filter, lambda p: p.replace(p.value.astype(jnp.bfloat16)))
208
+
209
+ return training_utils.TrainState(
210
+ step=0,
211
+ params=params,
212
+ model_def=nnx.graphdef(model),
213
+ tx=tx,
214
+ opt_state=tx.init(params.filter(config.trainable_filter)),
215
+ ema_decay=config.ema_decay,
216
+ ema_params=None if config.ema_decay is None else params,
217
+ )
218
+
219
+ train_state_shape = jax.eval_shape(init, init_rng)
220
+ state_sharding = sharding.fsdp_sharding(train_state_shape, mesh, log=True)
221
+
222
+ if resume:
223
+ return train_state_shape, state_sharding
224
+
225
+ partial_params = _load_weights_and_validate(config.weight_loader, train_state_shape.params.to_pure_dict())
226
+ replicated_sharding = jax.sharding.NamedSharding(mesh, jax.sharding.PartitionSpec())
227
+
228
+ # Initialize the train state and mix in the partial params.
229
+ train_state = jax.jit(
230
+ init,
231
+ donate_argnums=(1,), # donate the partial params buffer.
232
+ in_shardings=replicated_sharding,
233
+ out_shardings=state_sharding,
234
+ )(init_rng, partial_params)
235
+
236
+ return train_state, state_sharding
237
+
238
+
239
+ @at.typecheck
240
+ def train_step(
241
+ config: _config.TrainConfig,
242
+ rng: at.KeyArrayLike,
243
+ state: training_utils.TrainState,
244
+ batch: tuple[_model.Observation, _model.Actions],
245
+ ) -> tuple[training_utils.TrainState, dict[str, at.Array]]:
246
+ model = nnx.merge(state.model_def, state.params)
247
+ model.train()
248
+
249
+ @at.typecheck
250
+ def loss_fn(
251
+ model: _model.BaseModel, rng: at.KeyArrayLike, observation: _model.Observation, actions: _model.Actions
252
+ ):
253
+ chunked_loss = model.compute_loss(rng, observation, actions, train=True)
254
+ return jnp.mean(chunked_loss)
255
+
256
+ train_rng = jax.random.fold_in(rng, state.step)
257
+ observation, actions = batch
258
+
259
+ # Filter out frozen params.
260
+ diff_state = nnx.DiffState(0, config.trainable_filter)
261
+ loss, grads = nnx.value_and_grad(loss_fn, argnums=diff_state)(model, train_rng, observation, actions)
262
+
263
+ params = state.params.filter(config.trainable_filter)
264
+ updates, new_opt_state = state.tx.update(grads, state.opt_state, params)
265
+ new_params = optax.apply_updates(params, updates)
266
+
267
+ # Update the model in place and return the new full state.
268
+ nnx.update(model, new_params)
269
+ new_params = nnx.state(model)
270
+
271
+ new_state = dataclasses.replace(state, step=state.step + 1, params=new_params, opt_state=new_opt_state)
272
+ if state.ema_decay is not None:
273
+ new_state = dataclasses.replace(
274
+ new_state,
275
+ ema_params=jax.tree.map(
276
+ lambda old, new: state.ema_decay * old + (1 - state.ema_decay) * new, state.ema_params, new_params
277
+ ),
278
+ )
279
+
280
+ # Filter out params that aren't kernels.
281
+ kernel_params = nnx.state(
282
+ model,
283
+ nnx.All(
284
+ nnx.Param,
285
+ nnx.Not(nnx_utils.PathRegex(".*/(bias|scale|pos_embedding|input_embedding)")),
286
+ lambda _, x: x.value.ndim > 1,
287
+ ),
288
+ )
289
+ info = {
290
+ "loss": loss,
291
+ "grad_norm": optax.global_norm(grads),
292
+ "param_norm": optax.global_norm(kernel_params),
293
+ }
294
+ return new_state, info
295
+
296
+
297
+ def main(config: _config.TrainConfig):
298
+ init_logging()
299
+ logging.info(f"Running on: {platform.node()}")
300
+
301
+ if config.batch_size % jax.device_count() != 0:
302
+ raise ValueError(
303
+ f"Batch size {config.batch_size} must be divisible by the number of devices {jax.device_count()}."
304
+ )
305
+
306
+ jax.config.update("jax_compilation_cache_dir", str(epath.Path("~/.cache/jax").expanduser()))
307
+
308
+ rng = jax.random.key(config.seed)
309
+ train_rng, init_rng = jax.random.split(rng)
310
+
311
+ mesh = sharding.make_mesh(config.fsdp_devices)
312
+ data_sharding = jax.sharding.NamedSharding(mesh, jax.sharding.PartitionSpec(sharding.DATA_AXIS))
313
+ replicated_sharding = jax.sharding.NamedSharding(mesh, jax.sharding.PartitionSpec())
314
+
315
+ checkpoint_manager, resuming = _checkpoints.initialize_checkpoint_dir(
316
+ config.checkpoint_dir,
317
+ keep_period=config.keep_period,
318
+ overwrite=config.overwrite,
319
+ resume=config.resume,
320
+ )
321
+ init_wandb(config, resuming=resuming, enabled=config.wandb_enabled)
322
+ tb_writer = init_tensorboard(config)
323
+
324
+ data_loader = _data_loader.create_data_loader(
325
+ config,
326
+ sharding=data_sharding,
327
+ shuffle=True,
328
+ )
329
+ data_iter = iter(data_loader)
330
+ batch = next(data_iter)
331
+ logging.info(f"Initialized data loader:\n{training_utils.array_tree_to_info(batch)}")
332
+
333
+ # Log images from first batch to sanity check.
334
+ images_to_log = [
335
+ wandb.Image(np.concatenate([np.array(img[i]) for img in batch[0].images.values()], axis=1))
336
+ for i in range(min(5, len(next(iter(batch[0].images.values())))))
337
+ ]
338
+ wandb.log({"camera_views": images_to_log}, step=0)
339
+
340
+ train_state, train_state_sharding = init_train_state(config, init_rng, mesh, resume=resuming)
341
+ jax.block_until_ready(train_state)
342
+ logging.info(f"Initialized train state:\n{training_utils.array_tree_to_info(train_state.params)}")
343
+
344
+ if resuming:
345
+ train_state = _checkpoints.restore_state(checkpoint_manager, train_state, data_loader)
346
+
347
+ ptrain_step = jax.jit(
348
+ functools.partial(train_step, config),
349
+ in_shardings=(replicated_sharding, train_state_sharding, data_sharding),
350
+ out_shardings=(train_state_sharding, replicated_sharding),
351
+ donate_argnums=(1,),
352
+ )
353
+
354
+ start_step = int(train_state.step)
355
+ pbar = tqdm.tqdm(
356
+ range(start_step, config.num_train_steps),
357
+ initial=start_step,
358
+ total=config.num_train_steps,
359
+ dynamic_ncols=True,
360
+ )
361
+
362
+ infos = []
363
+ for step in pbar:
364
+ with sharding.set_mesh(mesh):
365
+ train_state, info = ptrain_step(train_rng, train_state, batch)
366
+ infos.append(info)
367
+ if step % config.log_interval == 0:
368
+ stacked_infos = common_utils.stack_forest(infos)
369
+ reduced_info = jax.device_get(jax.tree.map(jnp.mean, stacked_infos))
370
+ info_str = ", ".join(f"{k}={v:.4f}" for k, v in reduced_info.items())
371
+ pbar.write(f"Step {step}: {info_str}")
372
+ wandb.log(reduced_info, step=step)
373
+ if tb_writer is not None:
374
+ for key, value in reduced_info.items():
375
+ tb_writer.add_scalar(f"train/{key}", float(value), step)
376
+ tb_writer.flush()
377
+ infos = []
378
+ batch = next(data_iter)
379
+
380
+ if (step % config.save_interval == 0 and step > start_step) or step == config.num_train_steps - 1:
381
+ _checkpoints.save_state(checkpoint_manager, train_state, data_loader, step)
382
+
383
+ logging.info("Waiting for checkpoint manager to finish")
384
+ checkpoint_manager.wait_until_finished()
385
+ if tb_writer is not None:
386
+ tb_writer.close()
387
+
388
+
389
+ if __name__ == "__main__":
390
+ main(_config.cli())
pi05_twotasks_pytorch/code/openpi-main/src/openpi/__init__.py ADDED
File without changes
pi05_twotasks_pytorch/code/openpi-main/src/openpi/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (202 Bytes). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/__pycache__/transforms.cpython-311.pyc ADDED
Binary file (31.3 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/conftest.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import pynvml
4
+ import pytest
5
+
6
+
7
+ def set_jax_cpu_backend_if_no_gpu() -> None:
8
+ try:
9
+ pynvml.nvmlInit()
10
+ pynvml.nvmlShutdown()
11
+ except pynvml.NVMLError:
12
+ # No GPU found.
13
+ os.environ["JAX_PLATFORMS"] = "cpu"
14
+
15
+
16
+ def pytest_configure(config: pytest.Config) -> None:
17
+ set_jax_cpu_backend_if_no_gpu()
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__init__.py ADDED
File without changes
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (209 Bytes). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/gemma.cpython-311.pyc ADDED
Binary file (27.3 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/gemma_fast.cpython-311.pyc ADDED
Binary file (21.6 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/lora.cpython-311.pyc ADDED
Binary file (9.04 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/model.cpython-311.pyc ADDED
Binary file (17.9 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/pi0.cpython-311.pyc ADDED
Binary file (16.9 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/pi0_config.cpython-311.pyc ADDED
Binary file (6.05 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/pi0_fast.cpython-311.pyc ADDED
Binary file (19.2 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/siglip.cpython-311.pyc ADDED
Binary file (16.3 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/__pycache__/tokenizer.cpython-311.pyc ADDED
Binary file (23.7 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/gemma.py ADDED
@@ -0,0 +1,459 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 Big Vision Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Gemma adaptation for Pi, taken from big_vision.
16
+
17
+ We follow this einsum axis naming convention:
18
+ B: batch
19
+ T: query length
20
+ S: k/v length
21
+ N: num query heads
22
+ K: num k/v heads
23
+ G: num query heads per k/v head
24
+ H: head dim
25
+ D: d_model ("features")
26
+ """
27
+
28
+ from collections.abc import Sequence
29
+ import dataclasses
30
+ from typing import Literal, TypeAlias
31
+
32
+ import einops
33
+ import flax.linen as nn
34
+ import jax
35
+ import jax.numpy as jnp
36
+
37
+ import openpi.models.lora as lora
38
+ import openpi.shared.array_typing as at
39
+ import openpi.training.sharding as sharding
40
+
41
+ PALIGEMMA_VOCAB_SIZE = 257_152
42
+
43
+
44
+ @dataclasses.dataclass
45
+ class Config:
46
+ width: int
47
+ depth: int
48
+ mlp_dim: int
49
+ num_heads: int
50
+ num_kv_heads: int
51
+ head_dim: int
52
+ lora_configs: dict[str, lora.LoRAConfig] = dataclasses.field(default_factory=dict)
53
+
54
+
55
+ Variant = Literal["dummy", "gemma_300m", "gemma_300m_lora", "gemma_2b", "gemma_2b_lora"]
56
+
57
+
58
+ def get_config(variant: Variant) -> Config:
59
+ """Returns config for specified gemma variant."""
60
+ if variant == "dummy":
61
+ return Config(
62
+ width=64,
63
+ depth=4,
64
+ mlp_dim=128,
65
+ num_heads=8,
66
+ num_kv_heads=1,
67
+ head_dim=16,
68
+ )
69
+ if variant == "gemma_300m":
70
+ # 311M params
71
+ return Config(
72
+ width=1024,
73
+ depth=18,
74
+ mlp_dim=4096,
75
+ num_heads=8,
76
+ num_kv_heads=1,
77
+ head_dim=256,
78
+ )
79
+ if variant == "gemma_2b":
80
+ return Config(
81
+ width=2048,
82
+ depth=18,
83
+ mlp_dim=16_384,
84
+ num_heads=8,
85
+ num_kv_heads=1,
86
+ head_dim=256,
87
+ )
88
+ if variant == "gemma_2b_lora":
89
+ return Config(
90
+ width=2048,
91
+ depth=18,
92
+ mlp_dim=16_384,
93
+ num_heads=8,
94
+ num_kv_heads=1,
95
+ head_dim=256,
96
+ lora_configs={"attn": lora.LoRAConfig(rank=16, alpha=16.0), "ffn": lora.LoRAConfig(rank=16, alpha=16.0)},
97
+ )
98
+ if variant == "gemma_300m_lora":
99
+ # 311M params
100
+ return Config(
101
+ width=1024,
102
+ depth=18,
103
+ mlp_dim=4096,
104
+ num_heads=8,
105
+ num_kv_heads=1,
106
+ head_dim=256,
107
+ lora_configs={"attn": lora.LoRAConfig(rank=32, alpha=32.0), "ffn": lora.LoRAConfig(rank=32, alpha=32.0)},
108
+ )
109
+ raise ValueError(f"Unknown variant: {variant}")
110
+
111
+
112
+ @at.typecheck
113
+ class RMSNorm(nn.Module):
114
+ @nn.compact
115
+ def __call__(self, x, cond):
116
+ dtype = x.dtype # original dtype, could be half-precision
117
+ var = jnp.mean(jnp.square(x.astype(jnp.float32)), axis=-1, keepdims=True) # compute variance in float32
118
+ normed_inputs = jnp.asarray(x * jnp.reciprocal(jnp.sqrt(var + 1e-06))) # compute normalization in float32
119
+ if cond is None:
120
+ # regular RMSNorm
121
+ scale = self.param("scale", nn.initializers.zeros_init(), (x.shape[-1]))
122
+ normed_inputs = normed_inputs * (
123
+ 1 + scale
124
+ ) # scale by learned parameter in float32 (matches Flax implementation)
125
+ return normed_inputs.astype(dtype), None # return in original dtype
126
+
127
+ # adaptive RMSNorm
128
+ modulation = nn.Dense(x.shape[-1] * 3, kernel_init=nn.initializers.zeros, dtype=dtype)(cond)
129
+ scale, shift, gate = jnp.split(modulation[:, None, :], 3, axis=-1)
130
+ normed_inputs = normed_inputs * (1 + scale) + shift # scale and shift in float32
131
+ return normed_inputs.astype(dtype), gate
132
+
133
+
134
+ @at.typecheck
135
+ class Embedder(nn.Module):
136
+ """Embedder module."""
137
+
138
+ vocab_size: int
139
+ embed_dim: int
140
+
141
+ def setup(self):
142
+ self.input_embedding_table = self.param(
143
+ "input_embedding",
144
+ nn.initializers.normal(),
145
+ (self.vocab_size, self.embed_dim),
146
+ )
147
+
148
+ def encode(self, x):
149
+ x = self.input_embedding_table[(x,)]
150
+ x *= jnp.sqrt(self.embed_dim).astype(x.dtype)
151
+ return x
152
+
153
+ def decode(self, x):
154
+ return jnp.dot(x, self.input_embedding_table.T)
155
+
156
+
157
+ @at.typecheck
158
+ class Attention(nn.Module):
159
+ """Attention module."""
160
+
161
+ configs: Sequence[Config]
162
+
163
+ @nn.compact
164
+ def __call__(self, xs, positions, attn_mask, kv_cache):
165
+ # all experts must share the same head dim, num heads, and num kv heads for self-attention to work
166
+ assert all(config.head_dim == self.configs[0].head_dim for config in self.configs)
167
+ assert all(config.num_heads == self.configs[0].num_heads for config in self.configs)
168
+ assert all(config.num_kv_heads == self.configs[0].num_kv_heads for config in self.configs)
169
+
170
+ dtype = next(x.dtype for x in xs if x is not None) # original dtype, could be half-precision
171
+
172
+ qkvs = []
173
+ for i, (x, config) in enumerate(zip(xs, self.configs, strict=True)):
174
+ if x is None:
175
+ continue
176
+ if config.num_kv_heads == config.num_heads:
177
+ qkv_einsum = lora.Einsum(
178
+ shape=(3, config.num_heads, config.width, config.head_dim),
179
+ name=_name("qkv_einsum", i),
180
+ init_fn=nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0, 1)),
181
+ lora_config=config.lora_configs.get("attn"),
182
+ )
183
+ qkvs.append(qkv_einsum("BSD,3KDH->3BSKH", x))
184
+ else:
185
+ q_einsum = lora.Einsum(
186
+ shape=(config.num_heads, config.width, config.head_dim),
187
+ name=_name("q_einsum", i),
188
+ init_fn=nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0,)),
189
+ lora_config=config.lora_configs.get("attn"),
190
+ )
191
+ q = q_einsum("BTD,NDH->BTNH", x)
192
+ kv_einsum = lora.Einsum(
193
+ shape=(2, config.num_kv_heads, config.width, config.head_dim),
194
+ name=_name("kv_einsum", i),
195
+ init_fn=nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0, 1)),
196
+ lora_config=config.lora_configs.get("attn"),
197
+ )
198
+ k, v = kv_einsum("BSD,2KDH->2BSKH", x)
199
+ qkvs.append((q, k, v))
200
+
201
+ q, k, v = (jnp.concatenate(y, axis=1) for y in zip(*qkvs, strict=True))
202
+
203
+ q = _apply_rope(q, positions=positions)
204
+ q *= self.configs[0].head_dim ** -0.5
205
+
206
+ k = _apply_rope(k, positions=positions)
207
+
208
+ # should still be half-precision here (if input was half-precision)
209
+ assert q.dtype == k.dtype == v.dtype == dtype
210
+
211
+ if kv_cache is not None:
212
+ cache_k, cache_v = kv_cache
213
+ k = jnp.concatenate([cache_k, k], axis=1)
214
+ v = jnp.concatenate([cache_v, v], axis=1)
215
+
216
+ q = einops.rearrange(q, "B T (K G) H -> B T K G H", K=self.configs[0].num_kv_heads)
217
+ logits = jnp.einsum("BTKGH,BSKH->BKGTS", q, k, preferred_element_type=jnp.float32)
218
+
219
+ if attn_mask.shape != (q.shape[0], 1, q.shape[1], k.shape[1]):
220
+ raise ValueError(
221
+ f"Attention mask with shape {attn_mask.shape} but shapes for q and k are: {q.shape} and {k.shape}"
222
+ )
223
+
224
+ # big_neg = jnp.finfo(logits.dtype).min
225
+ big_neg = -2.3819763e38 # See gemma/modules.py
226
+ masked_logits = jnp.where(attn_mask[:, :, None, :, :], logits, big_neg)
227
+
228
+ probs = jax.nn.softmax(masked_logits, axis=-1).astype(dtype)
229
+
230
+ encoded = jnp.einsum("BKGTS,BSKH->BTKGH", probs, v)
231
+ encoded = einops.rearrange(encoded, "B T K G H -> B T (K G) H")
232
+
233
+ out = []
234
+ start = 0
235
+ for i, (x, config) in enumerate(zip(xs, self.configs, strict=True)):
236
+ if x is not None:
237
+ end = start + x.shape[1]
238
+ out_einsum = lora.Einsum(
239
+ shape=(config.num_heads, config.head_dim, config.width),
240
+ name=_name("attn_vec_einsum", i),
241
+ init_fn=nn.initializers.lecun_normal(in_axis=(-3, -2), out_axis=-1),
242
+ lora_config=config.lora_configs.get("attn"),
243
+ )
244
+ out.append(out_einsum("BTNH,NHD->BTD", encoded[:, start:end]))
245
+ start = end
246
+ else:
247
+ out.append(None)
248
+
249
+ return out, (k, v)
250
+
251
+
252
+ @at.typecheck
253
+ class FeedForward(nn.Module):
254
+ """Feed forward module."""
255
+
256
+ features: int
257
+ hidden_dim: int
258
+
259
+ @nn.compact
260
+ def __call__(self, x):
261
+ dtype = x.dtype # original dtype, could be half-precision
262
+ w_gating = self.param(
263
+ "gating_einsum",
264
+ nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0,)),
265
+ (2, self.features, self.hidden_dim),
266
+ ).astype(dtype)
267
+ ff_gate = jnp.dot(x, w_gating[0])
268
+ gate_value = nn.gelu(ff_gate)
269
+
270
+ ff1 = jnp.dot(x, w_gating[1])
271
+ activations = gate_value * ff1
272
+
273
+ w_linear = self.param(
274
+ "linear",
275
+ nn.initializers.lecun_normal(in_axis=-2, out_axis=-1),
276
+ (self.hidden_dim, self.features),
277
+ ).astype(dtype)
278
+ outputs = jnp.dot(activations, w_linear)
279
+ assert outputs.dtype == dtype
280
+ return outputs
281
+
282
+
283
+ @at.typecheck
284
+ class Block(nn.Module):
285
+ """Transformer block."""
286
+
287
+ configs: tuple[Config, ...]
288
+
289
+ dropout: float = 0.0
290
+ dropout_bdims: tuple[int, ...] = ()
291
+
292
+ @nn.compact
293
+ def __call__(self, xs, kv_cache, positions, attn_mask, adarms_cond, deterministic=True): # noqa: FBT002
294
+ xs = sharding.activation_sharding_constraint(xs)
295
+ drop = nn.Dropout(self.dropout, self.dropout_bdims) if self.dropout else lambda x, _: x
296
+
297
+ attn = Attention(configs=self.configs, name="attn")
298
+
299
+ pre_attn = []
300
+ gates = []
301
+ for i, x in enumerate(xs):
302
+ if x is not None:
303
+ x, gate = RMSNorm(name=_name("pre_attention_norm", i))(x, adarms_cond[i]) # noqa: PLW2901
304
+ pre_attn.append(x)
305
+ gates.append(gate if x is not None else None)
306
+
307
+ pre_attn = sharding.activation_sharding_constraint(pre_attn)
308
+ post_attn, kv_cache = attn(pre_attn, positions, attn_mask, kv_cache)
309
+ post_attn = jax.tree.map(lambda x: drop(x, deterministic), post_attn)
310
+ post_attn = sharding.activation_sharding_constraint(post_attn)
311
+ xs = [_gated_residual(x, y, gate) for x, y, gate in zip(xs, post_attn, gates, strict=True)]
312
+ xs = sharding.activation_sharding_constraint(xs)
313
+
314
+ out = []
315
+ gates = []
316
+ for i, (x, config) in enumerate(zip(xs, self.configs, strict=True)):
317
+ if x is not None:
318
+ x, gate = RMSNorm(name=_name("pre_ffw_norm", i))(x, adarms_cond[i]) # noqa: PLW2901
319
+ x = lora.FeedForward( # noqa: PLW2901
320
+ features=config.width,
321
+ hidden_dim=config.mlp_dim,
322
+ name=_name("mlp", i),
323
+ lora_config=config.lora_configs.get("ffn"),
324
+ )(x)
325
+ out.append(x)
326
+ gates.append(gate if x is not None else None)
327
+
328
+ out = sharding.activation_sharding_constraint(out)
329
+ out = jax.tree.map(lambda x: drop(x, deterministic), out)
330
+ xs = [_gated_residual(x, y, gate) for x, y, gate in zip(xs, out, gates, strict=True)]
331
+ xs = sharding.activation_sharding_constraint(xs)
332
+
333
+ return xs, kv_cache
334
+
335
+
336
+ KVCache: TypeAlias = tuple[at.Float[at.Array, "l b _t _k _h"], at.Float[at.Array, "l b _t _v _h"]]
337
+
338
+
339
+ @at.typecheck
340
+ class Module(nn.Module):
341
+ """Transformer model, supporting a mixture of different weights for different tokens."""
342
+
343
+ configs: Sequence[Config] # list of configs, one for each expert
344
+ embed_dtype: str
345
+
346
+ dropout: float = 0.0
347
+ dropout_bdims: tuple[int, ...] = () # Every float is dropped independently.
348
+ adarms: bool = False
349
+
350
+ def setup(self):
351
+ # all experts must have the same depth
352
+ assert all(config.depth == self.configs[0].depth for config in self.configs)
353
+
354
+ self.embedder = Embedder(
355
+ vocab_size=PALIGEMMA_VOCAB_SIZE,
356
+ embed_dim=self.configs[0].width, # embedder for first expert only
357
+ name="embedder",
358
+ )
359
+ block_cls = nn.remat(
360
+ Block,
361
+ prevent_cse=False,
362
+ static_argnums=(5,), # 0=self, 6=deterministic
363
+ policy=jax.checkpoint_policies.nothing_saveable,
364
+ )
365
+ self.layers = nn.scan(
366
+ block_cls,
367
+ variable_axes={"params": 0},
368
+ split_rngs={"params": True, "dropout": True},
369
+ in_axes=(
370
+ 0,
371
+ nn.broadcast,
372
+ nn.broadcast,
373
+ nn.broadcast,
374
+ nn.broadcast,
375
+ ), # 0=kv_cache, 1=positions, 2=mask, 3=adarms_cond, 4=deterministic
376
+ length=self.configs[0].depth,
377
+ )(
378
+ configs=self.configs,
379
+ dropout=self.dropout,
380
+ dropout_bdims=self.dropout_bdims,
381
+ )
382
+ self.final_norms = [RMSNorm(name=_name("final_norm", i)) for i in range(len(self.configs))]
383
+
384
+ @at.typecheck
385
+ def embed(self, tokens: at.Int[at.Array, "b t"]) -> at.Float[at.Array, "b t d"]:
386
+ return self.embedder.encode(tokens).astype(self.embed_dtype)
387
+
388
+ @at.typecheck
389
+ def __call__(
390
+ self,
391
+ # list of token arrays, one for each expert, or None if that expert should not be run
392
+ embedded: Sequence[at.Float[at.Array, "b _t _d"] | None],
393
+ positions: at.Int[at.Array, "b t"],
394
+ mask: at.Bool[at.Array, "b t s"],
395
+ adarms_cond: Sequence[at.Float[at.Array, "b _d"] | None] | None = None,
396
+ *,
397
+ kv_cache: KVCache | None = None,
398
+ deterministic: bool = True,
399
+ ) -> tuple[Sequence[at.Float[at.Array, "b _t _d"] | None], KVCache]:
400
+ embedded = jax.tree.map(lambda e: e.astype(self.embed_dtype), embedded)
401
+ mask = jnp.asarray(mask)[:, None, :, :]
402
+ if adarms_cond is None:
403
+ adarms_cond = [None] * len(self.configs)
404
+
405
+ embedded, kv_cache = self.layers(embedded, kv_cache, positions, mask, adarms_cond, deterministic)
406
+
407
+ assert all(e.dtype == jnp.dtype(self.embed_dtype) for e in embedded if e is not None)
408
+
409
+ return [
410
+ f(e, a)[0] if e is not None else e for f, e, a in zip(self.final_norms, embedded, adarms_cond, strict=True)
411
+ ], kv_cache
412
+
413
+ def init(self, use_adarms: Sequence[bool]):
414
+ """Convenience method for initializing all parameters, necessary due to the quirks of linen."""
415
+ self.embed(jnp.zeros((1, 1), dtype=jnp.int32))
416
+ self(
417
+ [jnp.zeros((1, 1, c.width)) for c in self.configs],
418
+ jnp.zeros((1, len(self.configs)), dtype=jnp.int32),
419
+ jnp.zeros((1, len(self.configs), len(self.configs)), dtype=bool),
420
+ adarms_cond=[jnp.zeros((1, c.width)) if u else None for u, c in zip(use_adarms, self.configs, strict=True)],
421
+ )
422
+
423
+
424
+ def _apply_rope(x, *, positions, max_wavelength=10_000):
425
+ """Applies RoPE positions [B, L] to x [B, L, H, D]."""
426
+ freq_exponents = (2.0 / x.shape[-1]) * jnp.arange(x.shape[-1] // 2, dtype=jnp.float32)
427
+ timescale = max_wavelength**freq_exponents
428
+ radians = positions[..., None] / timescale[None, None, :]
429
+ radians = radians[..., None, :]
430
+ assert radians.dtype == jnp.float32
431
+ # radians.shape = [...,L,1,d=D/2]
432
+ sin, cos = jnp.sin(radians), jnp.cos(radians)
433
+ x1, x2 = jnp.split(x, 2, axis=-1)
434
+ res = jnp.concatenate([x1 * cos - x2 * sin, x2 * cos + x1 * sin], axis=-1)
435
+ assert res.dtype == jnp.float32
436
+ # The original bigvision impl allows RoPE to upcast to float32. It is then immediately downcast again to the cache
437
+ # dtype when in inference mode (but not in training mode). I don't think any of this was intentional. Based on the
438
+ # original DeepMind impl, as well as the widely-used transformers impl, it is ok to always downcast back to bfloat16
439
+ # here.
440
+ return res.astype(x.dtype)
441
+
442
+
443
+ def _name(name, i):
444
+ # we name layers like this because we want the first expert's weights to have no suffix (e.g., "attn"), so that they
445
+ # can be loaded seamlessly from the existing PaliGemma checkpoint. subsequent experts will have a suffix (e.g.,
446
+ # "attn_1") and their weights will be initialized from scratch. in practice, we only use two experts -- PaliGemma,
447
+ # and the action expert.
448
+ if i == 0:
449
+ return name
450
+ return f"{name}_{i}"
451
+
452
+
453
+ def _gated_residual(x, y, gate):
454
+ assert (x is None) == (y is None)
455
+ if x is None:
456
+ return None
457
+ if gate is None:
458
+ return x + y
459
+ return x + y * gate
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/gemma_fast.py ADDED
@@ -0,0 +1,437 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 Big Vision Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Gemma model implementation from big_vision/models/ppp/gemma.py (with small modifications for NNX compatibility)
17
+ Used for FAST autoregressive policies.
18
+ """
19
+
20
+ import dataclasses
21
+ from typing import Literal, TypeAlias
22
+
23
+ import einops
24
+ import flax.linen as nn
25
+ import jax
26
+ import jax.numpy as jnp
27
+ import ml_collections
28
+
29
+ import openpi.models.lora as lora
30
+ import openpi.shared.array_typing as at
31
+
32
+ Variant = Literal["gemma_2b", "gemma_2b_lora"]
33
+
34
+
35
+ def get_config(variant):
36
+ """Returns config for specified gemma variant."""
37
+ if variant == "gemma_2b":
38
+ return ml_collections.ConfigDict(
39
+ {
40
+ "variant": variant,
41
+ "width": 2048,
42
+ "depth": 18,
43
+ "mlp_dim": 16_384,
44
+ "num_heads": 8,
45
+ "num_kv_heads": 1,
46
+ "head_dim": 256,
47
+ "norm_eps": 1e-6,
48
+ "vocab_size": 257_152,
49
+ "scan": True,
50
+ "remat_policy": "nothing_saveable",
51
+ }
52
+ )
53
+ if variant == "gemma_2b_lora":
54
+ return ml_collections.ConfigDict(
55
+ {
56
+ "variant": variant,
57
+ "width": 2048,
58
+ "depth": 18,
59
+ "mlp_dim": 16_384,
60
+ "num_heads": 8,
61
+ "num_kv_heads": 1,
62
+ "head_dim": 256,
63
+ "norm_eps": 1e-6,
64
+ "vocab_size": 257_152,
65
+ "scan": True,
66
+ "remat_policy": "nothing_saveable",
67
+ "lora_configs": {
68
+ "attn": lora.LoRAConfig(rank=16, alpha=16.0),
69
+ "ffn": lora.LoRAConfig(rank=16, alpha=16.0),
70
+ },
71
+ }
72
+ )
73
+ raise ValueError(f"Unknown variant: {variant}")
74
+
75
+
76
+ @at.typecheck
77
+ class Einsum(nn.Module):
78
+ shape: tuple[int, ...]
79
+
80
+ @nn.compact
81
+ def __call__(self, eqn, x):
82
+ dtype = x.dtype # original dtype, could be half-precision
83
+ w = self.param("w", nn.initializers.zeros_init(), self.shape).astype(dtype)
84
+ return jnp.einsum(eqn, x, w)
85
+
86
+
87
+ @at.typecheck
88
+ class RMSNorm(nn.Module):
89
+ @nn.compact
90
+ def __call__(self, x):
91
+ dtype = x.dtype # original dtype, could be half-precision
92
+ scale = self.param("scale", nn.initializers.zeros_init(), (x.shape[-1]))
93
+ var = jnp.mean(jnp.square(x.astype(jnp.float32)), axis=-1, keepdims=True) # compute variance in float32
94
+ normed_inputs = jnp.asarray(x * jnp.reciprocal(jnp.sqrt(var + 1e-06))) # compute normalization in float32
95
+ normed_inputs = normed_inputs * (
96
+ 1 + scale
97
+ ) # scale by learned parameter in float32 (matches Flax implementation)
98
+ return normed_inputs.astype(dtype) # return in original dtype
99
+
100
+
101
+ @at.typecheck
102
+ class Embedder(nn.Module):
103
+ """Embedder module."""
104
+
105
+ vocab_size: int
106
+ embed_dim: int
107
+
108
+ def setup(self):
109
+ self.input_embedding_table = self.param(
110
+ "input_embedding",
111
+ nn.initializers.zeros_init(),
112
+ (self.vocab_size, self.embed_dim),
113
+ )
114
+
115
+ def encode(self, x):
116
+ x = self.input_embedding_table[(x,)]
117
+ x *= jnp.sqrt(self.embed_dim).astype(x.dtype)
118
+ return x
119
+
120
+ def decode(self, x):
121
+ return jnp.dot(x, self.input_embedding_table.T)
122
+
123
+
124
+ @at.typecheck
125
+ class Attention(nn.Module):
126
+ """Attention module."""
127
+
128
+ num_heads: int
129
+ num_kv_heads: int
130
+ features: int
131
+ head_dim: int
132
+
133
+ cache_dtype: str | None = None
134
+
135
+ lora_config: lora.LoRAConfig | None = None
136
+
137
+ def setup(self):
138
+ if self.num_kv_heads == self.num_heads:
139
+ self.qkv_einsum = lora.Einsum(
140
+ shape=(3, self.num_heads, self.features, self.head_dim),
141
+ name="qkv_einsum",
142
+ init_fn=nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0, 1)),
143
+ lora_config=self.lora_config,
144
+ )
145
+ else:
146
+ self.q_einsum = lora.Einsum(
147
+ shape=(self.num_heads, self.features, self.head_dim),
148
+ name="q_einsum",
149
+ init_fn=nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0,)),
150
+ lora_config=self.lora_config,
151
+ )
152
+ self.kv_einsum = lora.Einsum(
153
+ shape=(2, self.num_kv_heads, self.features, self.head_dim),
154
+ name="kv_einsum",
155
+ init_fn=nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0, 1)),
156
+ lora_config=self.lora_config,
157
+ )
158
+ self.attn_vec_einsum = lora.Einsum(
159
+ shape=(self.num_heads, self.head_dim, self.features),
160
+ name="attn_vec_einsum",
161
+ init_fn=nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0,)),
162
+ lora_config=self.lora_config,
163
+ )
164
+
165
+ def _init_cache(self, k, v, cache_size):
166
+ """Initialize KV cache"""
167
+ prefill_len = k.shape[1]
168
+ pad_width = ((0, 0), (0, cache_size - prefill_len), (0, 0), (0, 0))
169
+ cache_dtype = self.cache_dtype or k.dtype
170
+ k_cache = jnp.pad(k.astype(cache_dtype), pad_width)
171
+ v_cache = jnp.pad(v.astype(cache_dtype), pad_width)
172
+ idx = jnp.zeros((k.shape[0],), dtype=jnp.int32) + prefill_len
173
+ return idx, k_cache, v_cache
174
+
175
+ def _update_cache(self, k, v, idx, k_cache, v_cache):
176
+ """Update KV cache with new values"""
177
+ assert k.shape[1] == 1, "Only support kv-cache updates of length 1"
178
+ indices = (0, idx[0], 0, 0)
179
+ cache_dtype = self.cache_dtype or k.dtype
180
+ k_new = jax.lax.dynamic_update_slice(k_cache, k.astype(cache_dtype), indices)
181
+ v_new = jax.lax.dynamic_update_slice(v_cache, v.astype(cache_dtype), indices)
182
+ idx_new = idx + 1
183
+ return idx_new, k_new, v_new
184
+
185
+ @nn.compact
186
+ def __call__(self, x, positions, attn_mask, kv_cache, decode, deterministic=True): # noqa: FBT002
187
+ dtype = x.dtype # original dtype, could be half-precision
188
+ if self.num_kv_heads == self.num_heads:
189
+ q, k, v = self.qkv_einsum("BSD,3KDH->3BSKH", x)
190
+ else:
191
+ q = self.q_einsum("BTD,NDH->BTNH", x)
192
+ k, v = self.kv_einsum("BSD,2KDH->2BSKH", x)
193
+
194
+ q = _apply_rope(q, positions=positions) # promotes to float32
195
+ q *= self.head_dim**-0.5
196
+
197
+ k = _apply_rope(k, positions=positions) # promotes to float32
198
+
199
+ if kv_cache is None:
200
+ idx, k_cache, v_cache = self._init_cache(k, v, attn_mask.shape[-1])
201
+ else:
202
+ idx, k_cache, v_cache = kv_cache
203
+ idx, k_cache, v_cache = self._update_cache(k, v, idx, k_cache, v_cache)
204
+
205
+ k, v = k_cache, v_cache
206
+ kv_cache = (idx, k_cache, v_cache)
207
+
208
+ q = einops.rearrange(q, "B T (K G) H -> B T K G H", K=self.num_kv_heads)
209
+ logits = jnp.einsum("BTKGH,BSKH->BKGTS", q, k, preferred_element_type=jnp.float32)
210
+
211
+ if attn_mask.shape != (q.shape[0], 1, q.shape[1], k.shape[1]):
212
+ raise ValueError(
213
+ f"Attention mask with shape {attn_mask.shape} but shapes for q and k are: {q.shape} and {k.shape}"
214
+ )
215
+
216
+ # big_neg = jnp.finfo(logits.dtype).min
217
+ big_neg = -2.3819763e38 # See gemma/modules.py
218
+ masked_logits = jnp.where(attn_mask[:, :, None, :, :], logits, big_neg)
219
+
220
+ probs = jax.nn.softmax(masked_logits, axis=-1).astype(dtype)
221
+
222
+ encoded = jnp.einsum("BKGTS,BSKH->BTKGH", probs, v)
223
+ encoded = einops.rearrange(encoded, "B T K G H -> B T (K G) H")
224
+ return self.attn_vec_einsum("BTNH,NHD->BTD", encoded), kv_cache
225
+
226
+
227
+ @at.typecheck
228
+ class Block(nn.Module):
229
+ """Transformer block."""
230
+
231
+ num_heads: int
232
+ num_kv_heads: int
233
+ embed_dim: int
234
+ head_dim: int
235
+ hidden_dim: int
236
+
237
+ dropout: float = 0.0
238
+ dropout_bdims: tuple[int, ...] = ()
239
+ cache_dtype: str | None = None
240
+ lora_configs: ml_collections.ConfigDict = dataclasses.field(default_factory=ml_collections.ConfigDict)
241
+
242
+ def setup(self):
243
+ self.pre_attention_norm = RMSNorm()
244
+ self.attn = Attention(
245
+ num_heads=self.num_heads,
246
+ num_kv_heads=self.num_kv_heads,
247
+ features=self.embed_dim,
248
+ head_dim=self.head_dim,
249
+ cache_dtype=self.cache_dtype,
250
+ lora_config=self.lora_configs.get("attn"),
251
+ )
252
+ self.pre_ffw_norm = RMSNorm()
253
+ self.mlp = lora.FeedForward(
254
+ features=self.embed_dim, hidden_dim=self.hidden_dim, name="mlp", lora_config=self.lora_configs.get("ffn")
255
+ )
256
+ if self.dropout:
257
+ self.drop = nn.Dropout(self.dropout, self.dropout_bdims)
258
+ else:
259
+ self.drop = lambda x, _: x
260
+
261
+ def __call__(self, x, kv_cache, positions, attn_mask, decode, deterministic=True): # noqa: FBT002
262
+ x = nn.with_logical_constraint(x, ("act_batch", "act_len", "act_emb"))
263
+ inputs_normalized = self.pre_attention_norm(x)
264
+ attn_output, kv_cache = self.attn(inputs_normalized, positions, attn_mask, kv_cache, decode, deterministic)
265
+ attn_output = self.drop(attn_output, deterministic)
266
+ attn_output += x
267
+ residual = attn_output
268
+ attn_output = self.pre_ffw_norm(attn_output)
269
+ outputs = self.mlp(attn_output)
270
+ outputs = self.drop(outputs, deterministic)
271
+ outputs = residual + outputs
272
+ return outputs, kv_cache
273
+
274
+
275
+ KVCache: TypeAlias = tuple[at.Int[at.Array, " b"], at.Float[at.Array, "b _t _k _h"], at.Float[at.Array, "b _t _v _h"]]
276
+
277
+
278
+ @at.typecheck
279
+ class Module(nn.Module):
280
+ """gemma model."""
281
+
282
+ variant: str
283
+
284
+ width: int
285
+ depth: int
286
+ mlp_dim: int
287
+ num_heads: int
288
+ num_kv_heads: int
289
+ head_dim: int
290
+ norm_eps: float
291
+ vocab_size: int
292
+ embed_dtype: str
293
+
294
+ dropout: float = 0.0
295
+ dropout_bdims: tuple[int, ...] = () # Every float is dropped independently.
296
+ cache_dtype: str | None = None
297
+
298
+ scan: bool = False
299
+ remat_policy: str = "none"
300
+ lora_configs: ml_collections.ConfigDict = dataclasses.field(default_factory=ml_collections.ConfigDict)
301
+
302
+ @nn.compact
303
+ def __call__(
304
+ self,
305
+ tokens=None,
306
+ embedded_prefix=None,
307
+ embed_only=False, # noqa: FBT002
308
+ pre_logits=None,
309
+ positions=None,
310
+ mask=None,
311
+ decode=False, # noqa: FBT002
312
+ kv_cache=None,
313
+ deterministic=True, # noqa: FBT002
314
+ return_prelogits=False, # noqa: FBT002
315
+ ):
316
+ """Embed only, or complete forward pass.
317
+
318
+ Args:
319
+ tokens: Embedded, then and appended to `embedded_prefix`. Can be None.
320
+ embedded_prefix: Optional prefix that is already embedded.
321
+ embed_only: Whether to compute embeddings only.
322
+ pre_logits: If present computes logits from pre_logits and returns.
323
+ positions: Optional `[B, T]` allows to specify the absolute position of
324
+ the tokens.
325
+ mask: Optional attention mask `[B, T, S]`.
326
+ decode: Whether to use kv-cache. Caller must pass masks and positions.
327
+ deterministic: Forwarded to all dropout layers.
328
+ return_prelogits: Whether to return the pre-logits.
329
+
330
+ Returns:
331
+ If `embed_only=False`, then `(logits, out)` will be returned.
332
+ If `embed_only=True`, then the embeddings will be returned.
333
+ If `return_prelogits=True`, then the pre-logits will be returned.
334
+ """
335
+ out = {}
336
+
337
+ embedder = Embedder(vocab_size=self.vocab_size, embed_dim=self.width, name="embedder")
338
+
339
+ if pre_logits is not None:
340
+ x = out["pre_logits"] = pre_logits
341
+ logits = out["logits"] = embedder.decode(x)
342
+ return logits, out
343
+
344
+ x = []
345
+ if embedded_prefix is not None:
346
+ x.append(embedded_prefix)
347
+ if tokens is not None:
348
+ x.append(embedder.encode(tokens))
349
+
350
+ x = jnp.concatenate(x, axis=-2)
351
+ x = x.astype(self.embed_dtype)
352
+ batch_size, seq_len, width = x.shape
353
+
354
+ if embed_only:
355
+ return x
356
+
357
+ if decode:
358
+ assert positions is not None and mask is not None, ( # noqa: PT018
359
+ "Must explicitly pass positions and mask for decoding."
360
+ )
361
+
362
+ if positions is None:
363
+ positions = jnp.arange(seq_len).astype(jnp.int32)[None, :]
364
+ assert positions.shape[1] == x.shape[1], (positions.shape, x.shape)
365
+
366
+ if mask is None:
367
+ mask = nn.attention.make_causal_mask(jnp.ones([batch_size, seq_len]))
368
+ if mask.ndim == 3:
369
+ mask = mask[:, None, :, :]
370
+ cache_size = max(seq_len, mask.shape[-1])
371
+ assert mask.shape == (batch_size, 1, seq_len, cache_size), mask.shape
372
+
373
+ if self.remat_policy == "none":
374
+ block_cls = Block
375
+ else:
376
+ block_cls = nn.remat(
377
+ Block,
378
+ prevent_cse=not self.scan,
379
+ static_argnums=(5, 6), # 0=self, 5=decode, 6=deterministic
380
+ policy=getattr(jax.checkpoint_policies, self.remat_policy),
381
+ )
382
+
383
+ block_kw = {
384
+ "num_heads": self.num_heads,
385
+ "head_dim": self.head_dim,
386
+ "num_kv_heads": self.num_kv_heads,
387
+ "embed_dim": width,
388
+ "hidden_dim": self.mlp_dim,
389
+ "dropout": self.dropout,
390
+ "dropout_bdims": self.dropout_bdims,
391
+ "cache_dtype": self.cache_dtype,
392
+ "lora_configs": self.lora_configs,
393
+ }
394
+ layers = self.scope.push("layers")
395
+ blocks = [
396
+ nn.scan(
397
+ block_cls,
398
+ variable_axes={"params": 0},
399
+ split_rngs={"params": True, "dropout": True},
400
+ in_axes=(0, nn.broadcast, nn.broadcast, nn.broadcast, nn.broadcast), # 0=kv_cache, 1=positions, 2=mask
401
+ length=self.depth,
402
+ )(parent=layers, **block_kw)
403
+ ]
404
+ for block in blocks:
405
+ x, kv_cache = block(x, kv_cache, positions, mask, decode, deterministic)
406
+
407
+ assert x.dtype == jnp.dtype(self.embed_dtype) # Sanity check.
408
+ out["encoded"] = x
409
+
410
+ x = RMSNorm(name="final_norm")(x)
411
+ out["pre_logits"] = x
412
+ if return_prelogits:
413
+ return x, kv_cache, out
414
+
415
+ x = embedder.decode(x)
416
+ out["logits"] = x
417
+
418
+ return x, kv_cache, out
419
+
420
+ def init(self):
421
+ """Convenience method for initializing all parameters, necessary due to the quirks of linen."""
422
+ self(jnp.zeros((1, 1), dtype=jnp.int32))
423
+
424
+
425
+ def _apply_rope(x, *, positions, max_wavelength=10_000):
426
+ """Applies RoPE positions [B, L] to x [B, L, H, D]."""
427
+ freq_exponents = (2.0 / x.shape[-1]) * jnp.arange(x.shape[-1] // 2, dtype=jnp.float32)
428
+ timescale = max_wavelength**freq_exponents
429
+ radians = positions[..., None] / timescale[None, None, :]
430
+ radians = radians[..., None, :]
431
+ assert radians.dtype == jnp.float32
432
+ # radians.shape = [...,L,1,d=D/2]
433
+ sin, cos = jnp.sin(radians), jnp.cos(radians)
434
+ x1, x2 = jnp.split(x, 2, axis=-1)
435
+ res = jnp.concatenate([x1 * cos - x2 * sin, x2 * cos + x1 * sin], axis=-1)
436
+ assert res.dtype == jnp.float32
437
+ return res
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/lora.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import re
3
+
4
+ import flax.linen as nn
5
+ import flax.struct as struct
6
+ import jax.numpy as jnp
7
+
8
+ import openpi.shared.array_typing as at
9
+
10
+
11
+ @struct.dataclass
12
+ class LoRAConfig:
13
+ """Configuration for LoRA."""
14
+
15
+ # LoRA rank.
16
+ rank: int
17
+ # LoRA scaling factor.
18
+ alpha: float = 1.0
19
+ # Initialization function for LoRA parameters.
20
+ init_fn: nn.initializers.Initializer = nn.initializers.normal(stddev=0.01)
21
+ # Enable rank-stabilized LoRA: https://arxiv.org/pdf/2312.03732
22
+ rslora: bool = False
23
+ # Axes in the weight to apply LoRA to. Should typically be the last two axes.
24
+ axes: tuple[int, int] = (-2, -1)
25
+ # Axis label which is used by LoRA in einsum equations. Must not be present in the original equation.
26
+ label: str = "L"
27
+
28
+ @property
29
+ def scaling_value(self) -> float:
30
+ return self.alpha / math.sqrt(self.rank) if self.rslora else self.alpha / self.rank
31
+
32
+
33
+ class Einsum(nn.Module):
34
+ """Einsum with LoRA support. Can be used as a drop-in replacement for the Gemma Einsum."""
35
+
36
+ # Shape of the weight.
37
+ shape: tuple[int, ...]
38
+ # Initialization function for the weight.
39
+ init_fn: nn.initializers.Initializer = nn.initializers.zeros
40
+ # If not None, apply LoRA to the weight.
41
+ lora_config: LoRAConfig | None = None
42
+
43
+ def setup(self):
44
+ self.w = self.param("w", self.init_fn, self.shape)
45
+
46
+ if config := self.lora_config:
47
+ # Setup LoRA parameters.
48
+ shape_a, shape_b = list(self.shape), list(self.shape)
49
+ shape_a[config.axes[1]] = config.rank
50
+ shape_b[config.axes[0]] = config.rank
51
+ self.w_a = self.param("lora_a", config.init_fn, shape_a)
52
+ self.w_b = self.param("lora_b", config.init_fn, shape_b)
53
+
54
+ @nn.compact
55
+ def __call__(self, eqn: str, x):
56
+ dtype = x.dtype # original dtype, could be half-precision
57
+ result = jnp.einsum(eqn, x, self.w.astype(dtype))
58
+
59
+ if config := self.lora_config:
60
+ eqn_a, eqn_b = self._make_lora_eqns(eqn)
61
+ lora = jnp.einsum(eqn_a, x, self.w_a.astype(dtype))
62
+ lora = jnp.einsum(eqn_b, lora, self.w_b.astype(dtype))
63
+ result = result + lora * config.scaling_value
64
+
65
+ return result
66
+
67
+ def _make_lora_eqns(self, eqn: str) -> tuple[str, str]:
68
+ if "L" in eqn:
69
+ raise ValueError(f"L already in eqn: {eqn}")
70
+ if not (m := re.match("(.*),(.*)->(.*)", eqn)):
71
+ raise ValueError(f"Unsupported einsum eqn: {eqn}")
72
+ lhs, rhs, out = m.groups()
73
+
74
+ assert self.lora_config is not None
75
+ a_label, b_label = (rhs[x] for x in self.lora_config.axes)
76
+ label = self.lora_config.label
77
+
78
+ a_rhs = rhs.replace(b_label, label)
79
+ a_out = out.replace(b_label, label)
80
+ eqn_a = f"{lhs},{a_rhs}->{a_out}"
81
+
82
+ b_rhs = rhs.replace(a_label, label)
83
+ eqn_b = f"{a_out},{b_rhs}->{out}"
84
+
85
+ return eqn_a, eqn_b
86
+
87
+
88
+ class FeedForward(nn.Module):
89
+ """Feed forward module."""
90
+
91
+ features: int
92
+ hidden_dim: int
93
+ # If not None, apply LoRA to the weight.
94
+ lora_config: LoRAConfig | None = None
95
+
96
+ def setup(self):
97
+ self.w_gating = self.param(
98
+ "gating_einsum",
99
+ nn.initializers.lecun_normal(in_axis=-2, out_axis=-1, batch_axis=(0,)),
100
+ (2, self.features, self.hidden_dim),
101
+ )
102
+ self.w_linear = self.param(
103
+ "linear",
104
+ nn.initializers.lecun_normal(in_axis=-2, out_axis=-1),
105
+ (self.hidden_dim, self.features),
106
+ )
107
+ self.w_gating_lora = None
108
+ self.w_linear_lora = None
109
+ if self.lora_config:
110
+ # Setup LoRA parameters.
111
+ # TODO: follow up with a simplified init_fn api.
112
+ self.w_gating_lora = (
113
+ self.param("gating_einsum_lora_a", self.lora_config.init_fn, (2, self.features, self.lora_config.rank)),
114
+ self.param(
115
+ "gating_einsum_lora_b", self.lora_config.init_fn, (2, self.lora_config.rank, self.hidden_dim)
116
+ ),
117
+ )
118
+ self.w_linear_lora = (
119
+ self.param("linear_lora_a", self.lora_config.init_fn, (self.hidden_dim, self.lora_config.rank)),
120
+ self.param("linear_lora_b", self.lora_config.init_fn, (self.lora_config.rank, self.features)),
121
+ )
122
+
123
+ @nn.compact
124
+ def __call__(self, x):
125
+ dtype = x.dtype # original dtype, could be half-precision
126
+ ff_gate = self._dot(
127
+ x,
128
+ self.w_gating[0],
129
+ None if self.w_gating_lora is None else (self.w_gating_lora[0][0], self.w_gating_lora[1][0]),
130
+ )
131
+ gate_value = nn.gelu(ff_gate)
132
+
133
+ ff1 = self._dot(
134
+ x,
135
+ self.w_gating[1],
136
+ None if self.w_gating_lora is None else (self.w_gating_lora[0][1], self.w_gating_lora[1][1]),
137
+ )
138
+ activations = gate_value * ff1
139
+
140
+ outputs = self._dot(activations, self.w_linear, self.w_linear_lora)
141
+ assert outputs.dtype == dtype
142
+ return outputs
143
+
144
+ def _dot(self, x: at.Array, w: at.Array, lora_weights: tuple[at.Array, at.Array] | None) -> at.Array:
145
+ base = jnp.dot(x, w.astype(x.dtype))
146
+ if lora_weights is None:
147
+ return base
148
+ return base + jnp.dot(jnp.dot(x, lora_weights[0].astype(x.dtype)), lora_weights[1].astype(x.dtype))
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/lora_test.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import flax.linen as nn
2
+ import jax
3
+ import jax.numpy as jnp
4
+
5
+ import openpi.models.lora as lora
6
+
7
+
8
+ def test_lora_einsum_params_shape():
9
+ shape = (3, 8, 32, 4) # (3KDH)
10
+ einsum = lora.Einsum(shape)
11
+ lora0 = lora.Einsum(shape, lora_config=lora.LoRAConfig(rank=2))
12
+ lora1 = lora.Einsum(shape, lora_config=lora.LoRAConfig(rank=2, axes=(1, 2)))
13
+
14
+ key = jax.random.key(0)
15
+ x = jax.random.normal(key, (8, 64, 32)) # (BSD)
16
+ eqn = "BSD,3KDH->3BSKH"
17
+
18
+ # Ensure that lora parameters are not initialized when LoRA is not used.
19
+ params = einsum.init(key, eqn, x)
20
+ assert "lora_a" not in params["params"]
21
+ assert "lora_b" not in params["params"]
22
+
23
+ # Check that default axes work.
24
+ params_lora0 = lora0.init(key, eqn, x)
25
+ assert params_lora0["params"]["lora_a"].shape == (3, 8, 32, 2)
26
+ assert params_lora0["params"]["lora_b"].shape == (3, 8, 2, 4)
27
+
28
+ # Check that user provided axes work.
29
+ params_lora1 = lora1.init(key, eqn, x)
30
+ assert params_lora1["params"]["lora_a"].shape == (3, 8, 2, 4)
31
+ assert params_lora1["params"]["lora_b"].shape == (3, 2, 32, 4)
32
+
33
+
34
+ def test_lora_einsum_same_output():
35
+ shape = (3, 8, 32, 4) # (3KDH)
36
+ einsum = lora.Einsum(shape)
37
+ einsum_lora = lora.Einsum(shape, lora_config=lora.LoRAConfig(rank=2, init_fn=nn.initializers.zeros))
38
+
39
+ key = jax.random.key(0)
40
+ x = jax.random.normal(key, (8, 64, 32)) # (BSD)
41
+ eqn = "BSD,3KDH->3BSKH"
42
+
43
+ params = einsum.init(key, eqn, x)
44
+ output = einsum.apply(params, eqn, x)
45
+
46
+ params_lora = einsum_lora.init(key, eqn, x)
47
+ output_lora = einsum_lora.apply(params_lora, eqn, x)
48
+
49
+ # Results are the same since the LoRA parameters are initialized to zeros.
50
+ assert jnp.allclose(output, output_lora)
51
+
52
+
53
+ def test_lora_ffn_params_shape():
54
+ ffn = lora.FeedForward(features=8, hidden_dim=32)
55
+ ffn_lora = lora.FeedForward(
56
+ features=8,
57
+ hidden_dim=32,
58
+ lora_config=lora.LoRAConfig(rank=2),
59
+ )
60
+
61
+ key = jax.random.key(0)
62
+ x = jax.random.normal(key, (2, 8))
63
+
64
+ params = ffn.init(key, x)
65
+ assert params["params"]["gating_einsum"].shape == (2, 8, 32)
66
+ assert params["params"]["linear"].shape == (32, 8)
67
+
68
+ params_lora = ffn_lora.init(key, x)
69
+ assert params_lora["params"]["gating_einsum"].shape == (2, 8, 32)
70
+ assert params_lora["params"]["linear"].shape == (32, 8)
71
+ assert params_lora["params"]["gating_einsum_lora_a"].shape == (2, 8, 2)
72
+ assert params_lora["params"]["gating_einsum_lora_b"].shape == (2, 2, 32)
73
+ assert params_lora["params"]["linear_lora_a"].shape == (32, 2)
74
+ assert params_lora["params"]["linear_lora_b"].shape == (2, 8)
75
+
76
+
77
+ def test_lora_ffn_same_output():
78
+ ffn = lora.FeedForward(features=8, hidden_dim=32)
79
+ ffn_lora = lora.FeedForward(
80
+ features=8,
81
+ hidden_dim=32,
82
+ lora_config=lora.LoRAConfig(rank=2, init_fn=nn.initializers.zeros),
83
+ )
84
+
85
+ key = jax.random.key(0)
86
+ x = jax.random.normal(key, (2, 8))
87
+
88
+ params = ffn.init(key, x)
89
+ output = ffn.apply(params, x)
90
+
91
+ params_lora = ffn_lora.init(key, x)
92
+ output_lora = ffn_lora.apply(params_lora, x)
93
+
94
+ assert jnp.allclose(output, output_lora)
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/model.py ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import abc
2
+ from collections.abc import Sequence
3
+ import dataclasses
4
+ import enum
5
+ import logging
6
+ import pathlib
7
+ from typing import Generic, TypeVar
8
+
9
+ import augmax
10
+ from flax import nnx
11
+ from flax import struct
12
+ from flax import traverse_util
13
+ import jax
14
+ import jax.numpy as jnp
15
+ import numpy as np
16
+ import orbax.checkpoint as ocp
17
+ import safetensors
18
+ import torch
19
+
20
+ from openpi.models_pytorch import pi0_pytorch
21
+ from openpi.shared import image_tools
22
+ import openpi.shared.array_typing as at
23
+
24
+ logger = logging.getLogger("openpi")
25
+
26
+ # Type variable for array types (JAX arrays, PyTorch tensors, or numpy arrays)
27
+ ArrayT = TypeVar("ArrayT", bound=jax.Array | torch.Tensor | np.ndarray)
28
+
29
+
30
+ class ModelType(enum.Enum):
31
+ """Supported model types."""
32
+
33
+ PI0 = "pi0"
34
+ PI0_FAST = "pi0_fast"
35
+ PI05 = "pi05"
36
+
37
+
38
+ # The model always expects these images
39
+ IMAGE_KEYS = (
40
+ "base_0_rgb",
41
+ "left_wrist_0_rgb",
42
+ "right_wrist_0_rgb",
43
+ )
44
+
45
+
46
+ # This may need change if we release a small model.
47
+ IMAGE_RESOLUTION = (224, 224)
48
+
49
+
50
+ # Data format
51
+ #
52
+ # Data transforms produce the model input as a nested dictionary which is later converted
53
+ # into `Obesrvation` and `Actions` objects. See below.
54
+ #
55
+ # In the dictory form, this data should look like:
56
+ # {
57
+ # # Observation data.
58
+ # "image": {
59
+ # "base_0_rgb": (float32|uint8)[*b, h, w, 3], # RGB image in [-1, 1] or [0, 255]
60
+ # ... # Additional camera views
61
+ # },
62
+ # "image_mask": {
63
+ # "base_0_rgb": bool[*b], # True if image is valid
64
+ # ... # Masks for additional views
65
+ # },
66
+ # "state": float32[*b, s], # Low-dimensional robot state
67
+ # "tokenized_prompt": int32[*b, l], # Optional, tokenized language prompt
68
+ # "tokenized_prompt_mask": bool[*b, l], # Optional, mask for tokenized prompt
69
+ # "token_ar_mask": int32[*b, l], # Optional, autoregressive mask for FAST model
70
+ # "token_loss_mask": bool[*b, l], # Optional, loss mask for FAST model
71
+ #
72
+ # # Actions data.
73
+ # "actions": float32[*b ah ad]
74
+ # }
75
+ # where:
76
+ # *b = batch dimensions
77
+ # h,w = image height/width
78
+ # s = state dimension
79
+ # l = sequence length
80
+ #
81
+ @at.typecheck
82
+ @struct.dataclass
83
+ class Observation(Generic[ArrayT]):
84
+ """Holds observations, i.e., inputs to the model.
85
+
86
+ See `Observation.from_dict` to see the expected dictionary form. This is the format
87
+ that should be produced by the data transforms.
88
+ """
89
+
90
+ # Images, in [-1, 1] float32.
91
+ images: dict[str, at.Float[ArrayT, "*b h w c"]]
92
+ # Image masks, with same keys as images.
93
+ image_masks: dict[str, at.Bool[ArrayT, "*b"]]
94
+ # Low-dimensional robot state.
95
+ state: at.Float[ArrayT, "*b s"]
96
+
97
+ # Tokenized prompt.
98
+ tokenized_prompt: at.Int[ArrayT, "*b l"] | None = None
99
+ # Tokenized prompt mask.
100
+ tokenized_prompt_mask: at.Bool[ArrayT, "*b l"] | None = None
101
+
102
+ # pi0-fast model specific fields.
103
+
104
+ # Token auto-regressive mask (for FAST autoregressive model).
105
+ token_ar_mask: at.Int[ArrayT, "*b l"] | None = None
106
+ # Token loss mask (for FAST autoregressive model).
107
+ token_loss_mask: at.Bool[ArrayT, "*b l"] | None = None
108
+
109
+ @classmethod
110
+ def from_dict(cls, data: at.PyTree[ArrayT]) -> "Observation[ArrayT]":
111
+ """This method defines the mapping between unstructured data (i.e., nested dict) to the structured Observation format."""
112
+ # Ensure that tokenized_prompt and tokenized_prompt_mask are provided together.
113
+ if ("tokenized_prompt" in data) != ("tokenized_prompt_mask" in data):
114
+ raise ValueError("tokenized_prompt and tokenized_prompt_mask must be provided together.")
115
+ # If images are uint8, convert them to [-1, 1] float32.
116
+ for key in data["image"]:
117
+ if data["image"][key].dtype == np.uint8:
118
+ data["image"][key] = data["image"][key].astype(np.float32) / 255.0 * 2.0 - 1.0
119
+ elif hasattr(data["image"][key], "dtype") and data["image"][key].dtype == torch.uint8:
120
+ data["image"][key] = data["image"][key].to(torch.float32).permute(0, 3, 1, 2) / 255.0 * 2.0 - 1.0
121
+ return cls(
122
+ images=data["image"],
123
+ image_masks=data["image_mask"],
124
+ state=data["state"],
125
+ tokenized_prompt=data.get("tokenized_prompt"),
126
+ tokenized_prompt_mask=data.get("tokenized_prompt_mask"),
127
+ token_ar_mask=data.get("token_ar_mask"),
128
+ token_loss_mask=data.get("token_loss_mask"),
129
+ )
130
+
131
+ def to_dict(self) -> at.PyTree[ArrayT]:
132
+ """Convert the Observation to a nested dict."""
133
+ result = dataclasses.asdict(self)
134
+ result["image"] = result.pop("images")
135
+ result["image_mask"] = result.pop("image_masks")
136
+ return result
137
+
138
+
139
+ # Defines the format of the actions. This field is included as "actions" inside the dictionary
140
+ # produced by the data transforms.
141
+ Actions = at.Float[ArrayT, "*b ah ad"]
142
+
143
+
144
+ def preprocess_observation(
145
+ rng: at.KeyArrayLike | None,
146
+ observation: Observation,
147
+ *,
148
+ train: bool = False,
149
+ image_keys: Sequence[str] = IMAGE_KEYS,
150
+ image_resolution: tuple[int, int] = IMAGE_RESOLUTION,
151
+ ) -> Observation:
152
+ """Preprocess the observations by performing image augmentations (if train=True), resizing (if necessary), and
153
+ filling in a default image mask (if necessary).
154
+ """
155
+
156
+ if not set(image_keys).issubset(observation.images):
157
+ raise ValueError(f"images dict missing keys: expected {image_keys}, got {list(observation.images)}")
158
+
159
+ batch_shape = observation.state.shape[:-1]
160
+
161
+ out_images = {}
162
+ for key in image_keys:
163
+ image = observation.images[key]
164
+ if image.shape[1:3] != image_resolution:
165
+ logger.info(f"Resizing image {key} from {image.shape[1:3]} to {image_resolution}")
166
+ image = image_tools.resize_with_pad(image, *image_resolution)
167
+
168
+ if train:
169
+ # Convert from [-1, 1] to [0, 1] for augmax.
170
+ image = image / 2.0 + 0.5
171
+
172
+ transforms = []
173
+ if "wrist" not in key:
174
+ height, width = image.shape[1:3]
175
+ transforms += [
176
+ augmax.RandomCrop(int(width * 0.95), int(height * 0.95)),
177
+ augmax.Resize(width, height),
178
+ augmax.Rotate((-5, 5)),
179
+ ]
180
+ transforms += [
181
+ augmax.ColorJitter(brightness=0.3, contrast=0.4, saturation=0.5),
182
+ ]
183
+ sub_rngs = jax.random.split(rng, image.shape[0])
184
+ image = jax.vmap(augmax.Chain(*transforms))(sub_rngs, image)
185
+
186
+ # Back to [-1, 1].
187
+ image = image * 2.0 - 1.0
188
+
189
+ out_images[key] = image
190
+
191
+ # obtain mask
192
+ out_masks = {}
193
+ for key in out_images:
194
+ if key not in observation.image_masks:
195
+ # do not mask by default
196
+ out_masks[key] = jnp.ones(batch_shape, dtype=jnp.bool)
197
+ else:
198
+ out_masks[key] = jnp.asarray(observation.image_masks[key])
199
+
200
+ return Observation(
201
+ images=out_images,
202
+ image_masks=out_masks,
203
+ state=observation.state,
204
+ tokenized_prompt=observation.tokenized_prompt,
205
+ tokenized_prompt_mask=observation.tokenized_prompt_mask,
206
+ token_ar_mask=observation.token_ar_mask,
207
+ token_loss_mask=observation.token_loss_mask,
208
+ )
209
+
210
+
211
+ @dataclasses.dataclass(frozen=True)
212
+ class BaseModelConfig(abc.ABC):
213
+ """Configuration shared by all models. Specific models should inherit from this class, and implement the `create`
214
+ method to create the corresponding model.
215
+ """
216
+
217
+ # Action space dimension.
218
+ action_dim: int
219
+ # Action sequence length.
220
+ action_horizon: int
221
+ # Tokenized prompt maximum length.
222
+ max_token_len: int
223
+
224
+ @property
225
+ @abc.abstractmethod
226
+ def model_type(self) -> ModelType:
227
+ """The model type."""
228
+
229
+ @abc.abstractmethod
230
+ def create(self, rng: at.KeyArrayLike) -> "BaseModel":
231
+ """Create a new model, initializing parameters."""
232
+
233
+ def load(self, params: at.Params, *, remove_extra_params: bool = True) -> "BaseModel":
234
+ """Create a model with the given parameters."""
235
+ model = nnx.eval_shape(self.create, jax.random.key(0))
236
+ graphdef, state = nnx.split(model)
237
+ if remove_extra_params:
238
+ params = ocp.transform_utils.intersect_trees(state.to_pure_dict(), params)
239
+ at.check_pytree_equality(expected=state.to_pure_dict(), got=params, check_shapes=True, check_dtypes=False)
240
+ state.replace_by_pure_dict(params)
241
+ return nnx.merge(graphdef, state)
242
+
243
+ def load_pytorch(self, train_config, weight_path: str):
244
+ logger.info(f"train_config: {train_config}")
245
+ model = pi0_pytorch.PI0Pytorch(config=train_config.model)
246
+ safetensors.torch.load_model(model, weight_path)
247
+ return model
248
+
249
+ @abc.abstractmethod
250
+ def inputs_spec(self, *, batch_size: int = 1) -> tuple[Observation, Actions]:
251
+ """Returns the input specification for the model. Values are jax.ShapeDtypeStruct."""
252
+
253
+ def fake_obs(self, batch_size: int = 1) -> Observation:
254
+ observation_spec, _ = self.inputs_spec(batch_size=batch_size)
255
+ return jax.tree.map(lambda x: jnp.ones(x.shape, x.dtype), observation_spec)
256
+
257
+ def fake_act(self, batch_size: int = 1) -> Actions:
258
+ _, action_spec = self.inputs_spec(batch_size=batch_size)
259
+ return jax.tree.map(lambda x: jnp.ones(x.shape, x.dtype), action_spec)
260
+
261
+
262
+ @dataclasses.dataclass
263
+ class BaseModel(nnx.Module, abc.ABC):
264
+ """Base class for all model implementations. Specific models should inherit from this class. They should call
265
+ super().__init__() to initialize the shared attributes (action_dim, action_horizon, and max_token_len).
266
+ """
267
+
268
+ action_dim: int
269
+ action_horizon: int
270
+ max_token_len: int
271
+
272
+ @abc.abstractmethod
273
+ def compute_loss(
274
+ self,
275
+ rng: at.KeyArrayLike,
276
+ observation: Observation,
277
+ actions: Actions,
278
+ *,
279
+ train: bool = False,
280
+ ) -> at.Float[at.Array, "*b ah"]: ...
281
+
282
+ @abc.abstractmethod
283
+ def sample_actions(self, rng: at.KeyArrayLike, observation: Observation, **kwargs) -> Actions: ...
284
+
285
+
286
+ def restore_params(
287
+ params_path: pathlib.Path | str,
288
+ *,
289
+ restore_type: type[np.ndarray] | type[jax.Array] = jax.Array,
290
+ dtype: jnp.dtype | None = None,
291
+ sharding: jax.sharding.Sharding | None = None,
292
+ ) -> at.Params:
293
+ """Restores unstructured params PyTree from a checkpoint.
294
+
295
+ This works with checkpoints saved with `save_state` during openpi training (see `training/checkpoints.py`) as
296
+ well as pre-trained checkpoints released for openpi.
297
+
298
+ Args:
299
+ params_path: The local path to the checkpoint directory.
300
+ restore_type: The type to restore the params as. Can be set to `np.ndarray` to load the params as a numpy array.
301
+ dtype: The dtype to restore all params as. If not provided, will use the original dtype from the checkpoint.
302
+ sharding: The sharding to use for the params. If not provided, the params will be replicated across all devices.
303
+
304
+ Returns:
305
+ The restored params.
306
+ """
307
+ params_path = pathlib.Path(params_path).resolve() if not str(params_path).startswith("gs://") else params_path
308
+
309
+ if restore_type is jax.Array and sharding is None:
310
+ mesh = jax.sharding.Mesh(jax.devices(), ("x",))
311
+ sharding = jax.sharding.NamedSharding(mesh, jax.sharding.PartitionSpec())
312
+
313
+ with ocp.PyTreeCheckpointer() as ckptr:
314
+ metadata = ckptr.metadata(params_path)
315
+ item = {"params": metadata["params"]}
316
+
317
+ params = ckptr.restore(
318
+ params_path,
319
+ ocp.args.PyTreeRestore(
320
+ item=item,
321
+ restore_args=jax.tree.map(
322
+ lambda _: ocp.ArrayRestoreArgs(sharding=sharding, restore_type=restore_type, dtype=dtype), item
323
+ ),
324
+ ),
325
+ )["params"]
326
+
327
+ # If the params were saved with `save_state` during openpi training, every key path will end with "value", which is
328
+ # added by `nnx.State`. We remove the "value" suffix here and always return what NNX calls a "pure dict".
329
+ flat_params = traverse_util.flatten_dict(params)
330
+ if all(kp[-1] == "value" for kp in flat_params):
331
+ flat_params = {kp[:-1]: v for kp, v in flat_params.items()}
332
+ return traverse_util.unflatten_dict(flat_params)
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/model_test.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flax import nnx
2
+ import jax
3
+ import pytest
4
+
5
+ from openpi.models import model as _model
6
+ from openpi.models import pi0_config
7
+ from openpi.models import pi0_fast
8
+ from openpi.shared import download
9
+ from openpi.shared import nnx_utils
10
+
11
+
12
+ def test_pi0_model():
13
+ key = jax.random.key(0)
14
+ config = pi0_config.Pi0Config()
15
+ model = config.create(key)
16
+
17
+ batch_size = 2
18
+ obs, act = config.fake_obs(batch_size), config.fake_act(batch_size)
19
+
20
+ loss = nnx_utils.module_jit(model.compute_loss)(key, obs, act)
21
+ assert loss.shape == (batch_size, config.action_horizon)
22
+
23
+ actions = nnx_utils.module_jit(model.sample_actions)(key, obs, num_steps=10)
24
+ assert actions.shape == (batch_size, model.action_horizon, model.action_dim)
25
+
26
+
27
+ def test_pi0_lora_model():
28
+ key = jax.random.key(0)
29
+ config = pi0_config.Pi0Config(paligemma_variant="gemma_2b_lora")
30
+ model = config.create(key)
31
+
32
+ batch_size = 2
33
+ obs, act = config.fake_obs(batch_size), config.fake_act(batch_size)
34
+
35
+ loss = nnx_utils.module_jit(model.compute_loss)(key, obs, act)
36
+ assert loss.shape == (batch_size, config.action_horizon)
37
+
38
+ actions = nnx_utils.module_jit(model.sample_actions)(key, obs, num_steps=10)
39
+ assert actions.shape == (batch_size, model.action_horizon, model.action_dim)
40
+
41
+
42
+ def test_pi0_fast_model():
43
+ key = jax.random.key(0)
44
+ config = pi0_fast.Pi0FASTConfig()
45
+ model = config.create(key)
46
+
47
+ batch_size = 2
48
+ obs, act = config.fake_obs(batch_size), config.fake_act(batch_size)
49
+
50
+ loss = nnx_utils.module_jit(model.compute_loss)(key, obs, act)
51
+ assert loss.shape == (batch_size,)
52
+
53
+ actions = nnx_utils.module_jit(model.sample_actions)(key, obs)
54
+ assert actions.shape == (batch_size, 256)
55
+
56
+
57
+ def test_pi0_fast_lora_model():
58
+ key = jax.random.key(0)
59
+ config = pi0_fast.Pi0FASTConfig(paligemma_variant="gemma_2b_lora")
60
+ model = config.create(key)
61
+
62
+ batch_size = 2
63
+ obs, act = config.fake_obs(batch_size), config.fake_act(batch_size)
64
+
65
+ loss = nnx_utils.module_jit(model.compute_loss)(key, obs, act)
66
+ assert loss.shape == (batch_size,)
67
+
68
+ actions = nnx_utils.module_jit(model.sample_actions)(key, obs)
69
+ assert actions.shape == (batch_size, 256)
70
+
71
+ lora_filter = nnx_utils.PathRegex(".*lora.*")
72
+ model_state = nnx.state(model)
73
+
74
+ lora_state_elems = list(model_state.filter(lora_filter))
75
+ assert len(lora_state_elems) > 0
76
+
77
+
78
+ @pytest.mark.manual
79
+ def test_model_restore():
80
+ key = jax.random.key(0)
81
+ config = pi0_config.Pi0Config()
82
+
83
+ batch_size = 2
84
+ obs, act = config.fake_obs(batch_size), config.fake_act(batch_size)
85
+
86
+ model = config.load(
87
+ _model.restore_params(download.maybe_download("gs://openpi-assets/checkpoints/pi0_base/params"))
88
+ )
89
+
90
+ loss = model.compute_loss(key, obs, act)
91
+ assert loss.shape == (batch_size, config.action_horizon)
92
+
93
+ actions = model.sample_actions(key, obs, num_steps=10)
94
+ assert actions.shape == (batch_size, model.action_horizon, model.action_dim)
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/pi0.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ import einops
4
+ import flax.nnx as nnx
5
+ import flax.nnx.bridge as nnx_bridge
6
+ import jax
7
+ import jax.numpy as jnp
8
+ from typing_extensions import override
9
+
10
+ from openpi.models import model as _model
11
+ from openpi.models import pi0_config
12
+ import openpi.models.gemma as _gemma
13
+ import openpi.models.siglip as _siglip
14
+ from openpi.shared import array_typing as at
15
+
16
+ logger = logging.getLogger("openpi")
17
+
18
+
19
+ def make_attn_mask(input_mask, mask_ar):
20
+ """Adapted from big_vision.
21
+
22
+ Tokens can attend to valid inputs tokens which have a cumulative mask_ar
23
+ smaller or equal to theirs. This way `mask_ar` bool[?B, N] can be used to
24
+ setup several types of attention, for example:
25
+
26
+ [[1 1 1 1 1 1]]: pure causal attention.
27
+
28
+ [[0 0 0 1 1 1]]: prefix-lm attention. The first 3 tokens can attend between
29
+ themselves and the last 3 tokens have a causal attention. The first
30
+ entry could also be a 1 without changing behaviour.
31
+
32
+ [[1 0 1 0 1 0 0 1 0 0]]: causal attention between 4 blocks. Tokens of a
33
+ block can attend all previous blocks and all tokens on the same block.
34
+
35
+ Args:
36
+ input_mask: bool[B, N] true if its part of the input, false if padding.
37
+ mask_ar: bool[?B, N] mask that's true where previous tokens cannot depend on
38
+ it and false where it shares the same attention mask as the previous token.
39
+ """
40
+ mask_ar = jnp.broadcast_to(mask_ar, input_mask.shape)
41
+ cumsum = jnp.cumsum(mask_ar, axis=1)
42
+ attn_mask = cumsum[:, None, :] <= cumsum[:, :, None]
43
+ valid_mask = input_mask[:, None, :] * input_mask[:, :, None]
44
+ return jnp.logical_and(attn_mask, valid_mask)
45
+
46
+
47
+ @at.typecheck
48
+ def posemb_sincos(
49
+ pos: at.Real[at.Array, " b"], embedding_dim: int, min_period: float, max_period: float
50
+ ) -> at.Float[at.Array, "b {embedding_dim}"]:
51
+ """Computes sine-cosine positional embedding vectors for scalar positions."""
52
+ if embedding_dim % 2 != 0:
53
+ raise ValueError(f"embedding_dim ({embedding_dim}) must be divisible by 2")
54
+
55
+ fraction = jnp.linspace(0.0, 1.0, embedding_dim // 2)
56
+ period = min_period * (max_period / min_period) ** fraction
57
+ sinusoid_input = jnp.einsum(
58
+ "i,j->ij",
59
+ pos,
60
+ 1.0 / period * 2 * jnp.pi,
61
+ precision=jax.lax.Precision.HIGHEST,
62
+ )
63
+ return jnp.concatenate([jnp.sin(sinusoid_input), jnp.cos(sinusoid_input)], axis=-1)
64
+
65
+
66
+ class Pi0(_model.BaseModel):
67
+ def __init__(self, config: pi0_config.Pi0Config, rngs: nnx.Rngs):
68
+ super().__init__(config.action_dim, config.action_horizon, config.max_token_len)
69
+ self.pi05 = config.pi05
70
+ paligemma_config = _gemma.get_config(config.paligemma_variant)
71
+ action_expert_config = _gemma.get_config(config.action_expert_variant)
72
+ # TODO: rewrite gemma in NNX. For now, use bridge.
73
+ llm = nnx_bridge.ToNNX(
74
+ _gemma.Module(
75
+ configs=[paligemma_config, action_expert_config],
76
+ embed_dtype=config.dtype,
77
+ adarms=config.pi05,
78
+ )
79
+ )
80
+ llm.lazy_init(rngs=rngs, method="init", use_adarms=[False, True] if config.pi05 else [False, False])
81
+ img = nnx_bridge.ToNNX(
82
+ _siglip.Module(
83
+ num_classes=paligemma_config.width,
84
+ variant="So400m/14",
85
+ pool_type="none",
86
+ scan=True,
87
+ dtype_mm=config.dtype,
88
+ )
89
+ )
90
+ img.lazy_init(next(iter(config.fake_obs().images.values())), train=False, rngs=rngs)
91
+ self.PaliGemma = nnx.Dict(llm=llm, img=img)
92
+ self.action_in_proj = nnx.Linear(config.action_dim, action_expert_config.width, rngs=rngs)
93
+ if config.pi05:
94
+ self.time_mlp_in = nnx.Linear(action_expert_config.width, action_expert_config.width, rngs=rngs)
95
+ self.time_mlp_out = nnx.Linear(action_expert_config.width, action_expert_config.width, rngs=rngs)
96
+ else:
97
+ self.state_proj = nnx.Linear(config.action_dim, action_expert_config.width, rngs=rngs)
98
+ self.action_time_mlp_in = nnx.Linear(2 * action_expert_config.width, action_expert_config.width, rngs=rngs)
99
+ self.action_time_mlp_out = nnx.Linear(action_expert_config.width, action_expert_config.width, rngs=rngs)
100
+ self.action_out_proj = nnx.Linear(action_expert_config.width, config.action_dim, rngs=rngs)
101
+
102
+ # This attribute gets automatically set by model.train() and model.eval().
103
+ self.deterministic = True
104
+
105
+ @at.typecheck
106
+ def embed_prefix(
107
+ self, obs: _model.Observation
108
+ ) -> tuple[at.Float[at.Array, "b s emb"], at.Bool[at.Array, "b s"], at.Bool[at.Array, " s"]]:
109
+ input_mask = []
110
+ ar_mask = []
111
+ tokens = []
112
+ # embed images
113
+ for name in obs.images:
114
+ image_tokens, _ = self.PaliGemma.img(obs.images[name], train=False)
115
+
116
+ tokens.append(image_tokens)
117
+ input_mask.append(
118
+ einops.repeat(
119
+ obs.image_masks[name],
120
+ "b -> b s",
121
+ s=image_tokens.shape[1],
122
+ )
123
+ )
124
+ # image tokens attend to each other
125
+ ar_mask += [False] * image_tokens.shape[1]
126
+
127
+ # add language (aka tokenized inputs)
128
+ if obs.tokenized_prompt is not None:
129
+ tokenized_inputs = self.PaliGemma.llm(obs.tokenized_prompt, method="embed")
130
+ tokens.append(tokenized_inputs)
131
+ input_mask.append(obs.tokenized_prompt_mask)
132
+ # full attention between image and language inputs
133
+ ar_mask += [False] * tokenized_inputs.shape[1]
134
+ tokens = jnp.concatenate(tokens, axis=1)
135
+ input_mask = jnp.concatenate(input_mask, axis=1)
136
+ ar_mask = jnp.array(ar_mask)
137
+ return tokens, input_mask, ar_mask
138
+
139
+ @at.typecheck
140
+ def embed_suffix(
141
+ self, obs: _model.Observation, noisy_actions: _model.Actions, timestep: at.Float[at.Array, " b"]
142
+ ) -> tuple[
143
+ at.Float[at.Array, "b s emb"],
144
+ at.Bool[at.Array, "b s"],
145
+ at.Bool[at.Array, " s"],
146
+ at.Float[at.Array, "b emb"] | None,
147
+ ]:
148
+ input_mask = []
149
+ ar_mask = []
150
+ tokens = []
151
+ if not self.pi05:
152
+ # add a single state token
153
+ state_token = self.state_proj(obs.state)[:, None, :]
154
+ tokens.append(state_token)
155
+ input_mask.append(jnp.ones((obs.state.shape[0], 1), dtype=jnp.bool_))
156
+ # image/language inputs do not attend to state or actions
157
+ ar_mask += [True]
158
+
159
+ action_tokens = self.action_in_proj(noisy_actions)
160
+ # embed timestep using sine-cosine positional encoding with sensitivity in the range [0, 1]
161
+ time_emb = posemb_sincos(timestep, self.action_in_proj.out_features, min_period=4e-3, max_period=4.0)
162
+ if self.pi05:
163
+ # time MLP (for adaRMS)
164
+ time_emb = self.time_mlp_in(time_emb)
165
+ time_emb = nnx.swish(time_emb)
166
+ time_emb = self.time_mlp_out(time_emb)
167
+ time_emb = nnx.swish(time_emb)
168
+ action_expert_tokens = action_tokens
169
+ adarms_cond = time_emb
170
+ else:
171
+ # mix timestep + action information using an MLP (no adaRMS)
172
+ time_tokens = einops.repeat(time_emb, "b emb -> b s emb", s=self.action_horizon)
173
+ action_time_tokens = jnp.concatenate([action_tokens, time_tokens], axis=-1)
174
+ action_time_tokens = self.action_time_mlp_in(action_time_tokens)
175
+ action_time_tokens = nnx.swish(action_time_tokens)
176
+ action_time_tokens = self.action_time_mlp_out(action_time_tokens)
177
+ action_expert_tokens = action_time_tokens
178
+ adarms_cond = None
179
+ tokens.append(action_expert_tokens)
180
+ input_mask.append(jnp.ones(action_expert_tokens.shape[:2], dtype=jnp.bool_))
181
+ # image/language/state inputs do not attend to action tokens
182
+ ar_mask += [True] + ([False] * (self.action_horizon - 1))
183
+ tokens = jnp.concatenate(tokens, axis=1)
184
+ input_mask = jnp.concatenate(input_mask, axis=1)
185
+ ar_mask = jnp.array(ar_mask)
186
+ return tokens, input_mask, ar_mask, adarms_cond
187
+
188
+ @override
189
+ def compute_loss(
190
+ self, rng: at.KeyArrayLike, observation: _model.Observation, actions: _model.Actions, *, train: bool = False
191
+ ) -> at.Float[at.Array, "*b ah"]:
192
+ preprocess_rng, noise_rng, time_rng = jax.random.split(rng, 3)
193
+ observation = _model.preprocess_observation(preprocess_rng, observation, train=train)
194
+
195
+ batch_shape = actions.shape[:-2]
196
+ noise = jax.random.normal(noise_rng, actions.shape)
197
+ time = jax.random.beta(time_rng, 1.5, 1, batch_shape) * 0.999 + 0.001
198
+ time_expanded = time[..., None, None]
199
+ x_t = time_expanded * noise + (1 - time_expanded) * actions
200
+ u_t = noise - actions
201
+
202
+ # one big forward pass of prefix + suffix at once
203
+ prefix_tokens, prefix_mask, prefix_ar_mask = self.embed_prefix(observation)
204
+ suffix_tokens, suffix_mask, suffix_ar_mask, adarms_cond = self.embed_suffix(observation, x_t, time)
205
+ input_mask = jnp.concatenate([prefix_mask, suffix_mask], axis=1)
206
+ ar_mask = jnp.concatenate([prefix_ar_mask, suffix_ar_mask], axis=0)
207
+ attn_mask = make_attn_mask(input_mask, ar_mask)
208
+ positions = jnp.cumsum(input_mask, axis=1) - 1
209
+ (prefix_out, suffix_out), _ = self.PaliGemma.llm(
210
+ [prefix_tokens, suffix_tokens], mask=attn_mask, positions=positions, adarms_cond=[None, adarms_cond]
211
+ )
212
+ v_t = self.action_out_proj(suffix_out[:, -self.action_horizon :])
213
+
214
+ return jnp.mean(jnp.square(v_t - u_t), axis=-1)
215
+
216
+ @override
217
+ def sample_actions(
218
+ self,
219
+ rng: at.KeyArrayLike,
220
+ observation: _model.Observation,
221
+ *,
222
+ num_steps: int | at.Int[at.Array, ""] = 10,
223
+ noise: at.Float[at.Array, "b ah ad"] | None = None,
224
+ ) -> _model.Actions:
225
+ observation = _model.preprocess_observation(None, observation, train=False)
226
+ # note that we use the convention more common in diffusion literature, where t=1 is noise and t=0 is the target
227
+ # distribution. yes, this is the opposite of the pi0 paper, and I'm sorry.
228
+ dt = -1.0 / num_steps
229
+ batch_size = observation.state.shape[0]
230
+ if noise is None:
231
+ noise = jax.random.normal(rng, (batch_size, self.action_horizon, self.action_dim))
232
+
233
+ # first fill KV cache with a forward pass of the prefix
234
+ prefix_tokens, prefix_mask, prefix_ar_mask = self.embed_prefix(observation)
235
+ prefix_attn_mask = make_attn_mask(prefix_mask, prefix_ar_mask)
236
+ positions = jnp.cumsum(prefix_mask, axis=1) - 1
237
+ _, kv_cache = self.PaliGemma.llm([prefix_tokens, None], mask=prefix_attn_mask, positions=positions)
238
+
239
+ def step(carry):
240
+ x_t, time = carry
241
+ suffix_tokens, suffix_mask, suffix_ar_mask, adarms_cond = self.embed_suffix(
242
+ observation, x_t, jnp.broadcast_to(time, batch_size)
243
+ )
244
+ # `suffix_attn_mask` is shape (b, suffix_len, suffix_len) indicating how the suffix tokens can attend to each
245
+ # other
246
+ suffix_attn_mask = make_attn_mask(suffix_mask, suffix_ar_mask)
247
+ # `prefix_attn_mask` is shape (b, suffix_len, prefix_len) indicating how the suffix tokens can attend to the
248
+ # prefix tokens
249
+ prefix_attn_mask = einops.repeat(prefix_mask, "b p -> b s p", s=suffix_tokens.shape[1])
250
+ # `combined_mask` is shape (b, suffix_len, prefix_len + suffix_len) indicating how the suffix tokens (which
251
+ # generate the queries) can attend to the full prefix + suffix sequence (which generates the keys and values)
252
+ full_attn_mask = jnp.concatenate([prefix_attn_mask, suffix_attn_mask], axis=-1)
253
+ assert full_attn_mask.shape == (
254
+ batch_size,
255
+ suffix_tokens.shape[1],
256
+ prefix_tokens.shape[1] + suffix_tokens.shape[1],
257
+ )
258
+ # `positions` is shape (b, suffix_len) indicating the positions of the suffix tokens
259
+ positions = jnp.sum(prefix_mask, axis=-1)[:, None] + jnp.cumsum(suffix_mask, axis=-1) - 1
260
+
261
+ (prefix_out, suffix_out), _ = self.PaliGemma.llm(
262
+ [None, suffix_tokens],
263
+ mask=full_attn_mask,
264
+ positions=positions,
265
+ kv_cache=kv_cache,
266
+ adarms_cond=[None, adarms_cond],
267
+ )
268
+ assert prefix_out is None
269
+ v_t = self.action_out_proj(suffix_out[:, -self.action_horizon :])
270
+
271
+ return x_t + dt * v_t, time + dt
272
+
273
+ def cond(carry):
274
+ x_t, time = carry
275
+ # robust to floating-point error
276
+ return time >= -dt / 2
277
+
278
+ x_0, _ = jax.lax.while_loop(cond, step, (noise, 1.0))
279
+ return x_0
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/pi0_config.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import dataclasses
2
+ from typing import TYPE_CHECKING
3
+
4
+ import flax.nnx as nnx
5
+ import jax
6
+ import jax.numpy as jnp
7
+ from typing_extensions import override
8
+
9
+ from openpi.models import model as _model
10
+ import openpi.models.gemma as _gemma
11
+ from openpi.shared import array_typing as at
12
+ import openpi.shared.nnx_utils as nnx_utils
13
+
14
+ if TYPE_CHECKING:
15
+ from openpi.models.pi0 import Pi0
16
+
17
+
18
+ @dataclasses.dataclass(frozen=True)
19
+ class Pi0Config(_model.BaseModelConfig):
20
+ dtype: str = "bfloat16"
21
+ paligemma_variant: _gemma.Variant = "gemma_2b"
22
+ action_expert_variant: _gemma.Variant = "gemma_300m"
23
+
24
+ # Set the model specific defaults.
25
+ action_dim: int = 32
26
+ action_horizon: int = 50
27
+ max_token_len: int = None # type: ignore
28
+ # Pi05 has two differences from Pi0:
29
+ # - the state input is part of the discrete language tokens rather than a continuous input that is part of the suffix
30
+ # - the action expert uses adaRMSNorm to inject the flow matching timestep
31
+ pi05: bool = False
32
+ # This config option is not used directly by the model, but it is read by the ModelTransformFactory.
33
+ discrete_state_input: bool = None # type: ignore
34
+
35
+ pytorch_compile_mode: str | None = "max-autotune"
36
+
37
+ def __post_init__(self):
38
+ if self.max_token_len is None:
39
+ object.__setattr__(self, "max_token_len", 200 if self.pi05 else 48)
40
+ if self.discrete_state_input is None:
41
+ object.__setattr__(self, "discrete_state_input", self.pi05)
42
+ if self.pytorch_compile_mode is not None:
43
+ assert self.pytorch_compile_mode in [
44
+ "default",
45
+ "reduce-overhead",
46
+ "max-autotune",
47
+ "max-autotune-no-cudagraphs",
48
+ ]
49
+
50
+ @property
51
+ @override
52
+ def model_type(self) -> _model.ModelType:
53
+ if self.pi05:
54
+ return _model.ModelType.PI05
55
+ return _model.ModelType.PI0
56
+
57
+ @override
58
+ def create(self, rng: at.KeyArrayLike) -> "Pi0":
59
+ from openpi.models.pi0 import Pi0
60
+
61
+ return Pi0(self, rngs=nnx.Rngs(rng))
62
+
63
+ @override
64
+ def inputs_spec(self, *, batch_size: int = 1) -> tuple[_model.Observation, _model.Actions]:
65
+ image_spec = jax.ShapeDtypeStruct([batch_size, *_model.IMAGE_RESOLUTION, 3], jnp.float32)
66
+ image_mask_spec = jax.ShapeDtypeStruct([batch_size], jnp.bool_)
67
+
68
+ with at.disable_typechecking():
69
+ observation_spec = _model.Observation(
70
+ images={
71
+ "base_0_rgb": image_spec,
72
+ "left_wrist_0_rgb": image_spec,
73
+ "right_wrist_0_rgb": image_spec,
74
+ },
75
+ image_masks={
76
+ "base_0_rgb": image_mask_spec,
77
+ "left_wrist_0_rgb": image_mask_spec,
78
+ "right_wrist_0_rgb": image_mask_spec,
79
+ },
80
+ state=jax.ShapeDtypeStruct([batch_size, self.action_dim], jnp.float32),
81
+ tokenized_prompt=jax.ShapeDtypeStruct([batch_size, self.max_token_len], jnp.int32),
82
+ tokenized_prompt_mask=jax.ShapeDtypeStruct([batch_size, self.max_token_len], bool),
83
+ )
84
+ action_spec = jax.ShapeDtypeStruct([batch_size, self.action_horizon, self.action_dim], jnp.float32)
85
+
86
+ return observation_spec, action_spec
87
+
88
+ def get_freeze_filter(self) -> nnx.filterlib.Filter:
89
+ """Returns the freeze filter based on the model config."""
90
+ filters = []
91
+ has_lora = False
92
+ gemma_params_filter = nnx_utils.PathRegex(".*llm.*")
93
+ action_expert_params_filter = nnx_utils.PathRegex(".*llm.*_1.*")
94
+ if "lora" in self.paligemma_variant:
95
+ filters.append(
96
+ gemma_params_filter,
97
+ )
98
+ if "lora" not in self.action_expert_variant:
99
+ # If only freeze gemma params, exclude action expert params.
100
+ filters.append(
101
+ nnx.Not(action_expert_params_filter),
102
+ )
103
+ has_lora = True
104
+ elif "lora" in self.action_expert_variant:
105
+ filters.append(
106
+ action_expert_params_filter,
107
+ )
108
+ has_lora = True
109
+
110
+ if has_lora:
111
+ # If any lora is used, exclude all lora params.
112
+ filters.append(
113
+ nnx.Not(nnx_utils.PathRegex(".*lora.*")),
114
+ )
115
+ if not filters:
116
+ return nnx.Nothing
117
+ return nnx.All(*filters)
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/pi0_fast.py ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import dataclasses
2
+ import logging
3
+ from typing import Any
4
+
5
+ import einops
6
+ import flax.nnx as nnx
7
+ import flax.nnx.bridge as nnx_bridge
8
+ import jax
9
+ import jax.numpy as jnp
10
+ from typing_extensions import override
11
+
12
+ from openpi.models import model as _model
13
+ import openpi.models.gemma_fast as _gemma
14
+ import openpi.models.siglip as _siglip
15
+ from openpi.shared import array_typing as at
16
+ import openpi.shared.nnx_utils as nnx_utils
17
+
18
+ logger = logging.getLogger("openpi")
19
+
20
+ PALIGEMMA_EOS_TOKEN = 1
21
+
22
+
23
+ def make_attn_mask(input_mask, mask_ar):
24
+ """Adapted from big_vision.
25
+
26
+ Tokens can attend to valid inputs tokens which have a cumulative mask_ar
27
+ smaller or equal to theirs. This way `mask_ar` bool[?B, N] can be used to
28
+ setup several types of attention, for example:
29
+
30
+ [[1 1 1 1 1 1]]: pure causal attention.
31
+
32
+ [[0 0 0 1 1 1]]: prefix-lm attention. The first 3 tokens can attend between
33
+ themselves and the last 3 tokens have a causal attention. The first
34
+ entry could also be a 1 without changing behaviour.
35
+
36
+ [[1 0 1 0 1 0 0 1 0 0]]: causal attention between 4 blocks. Tokens of a
37
+ block can attend all previous blocks and all tokens on the same block.
38
+
39
+ Args:
40
+ input_mask: bool[B, N] true if its part of the input, false if padding.
41
+ mask_ar: bool[?B, N] mask that's true where previous tokens cannot depend on
42
+ it and false where it shares the same attention mask as the previous token.
43
+ """
44
+ mask_ar = jnp.broadcast_to(mask_ar, input_mask.shape)
45
+ cumsum = jnp.cumsum(mask_ar, axis=1)
46
+ attn_mask = cumsum[:, None, :] <= cumsum[:, :, None]
47
+ valid_mask = input_mask[:, None, :] * input_mask[:, :, None]
48
+ return jnp.logical_and(attn_mask, valid_mask)
49
+
50
+
51
+ @jax.vmap
52
+ def left_to_right_align(x, input_mask, attn_mask):
53
+ """Converts input from left-align to right-aligned."""
54
+ # Due to vmap, this is operating in a single example (not batch level).
55
+ assert x.ndim == 2
56
+ assert input_mask.ndim == 1
57
+ assert attn_mask.ndim == 2
58
+ assert x.shape[0] == input_mask.shape[0]
59
+ assert attn_mask.shape[0] == attn_mask.shape[1], attn_mask.shape
60
+ seqlen = jnp.max(input_mask * jnp.arange(input_mask.shape[0])) + 1
61
+ x = jnp.roll(x, -seqlen, axis=0)
62
+ input_mask = jnp.roll(input_mask, -seqlen, axis=0)
63
+ attn_mask = jnp.roll(attn_mask, -seqlen, axis=(0, 1))
64
+ return x, input_mask, attn_mask
65
+
66
+
67
+ def put_along_last_axis(arr, indices, values):
68
+ """Like np.put_along_axis(..., axis=-1), since jax is missing it."""
69
+ assert arr.ndim == indices.ndim == values.ndim, (arr.ndim, indices.ndim, values.ndim)
70
+ onehot = jax.nn.one_hot(indices, arr.shape[-1], dtype=values.dtype)
71
+ put_mask = jnp.einsum("...i,...in->...n", jnp.ones(values.shape, jnp.int32), onehot)
72
+ put_values = jnp.einsum("...i,...in->...n", values, onehot)
73
+ return jnp.where(put_mask, put_values, arr)
74
+
75
+
76
+ @dataclasses.dataclass(frozen=True)
77
+ class Pi0FASTConfig(_model.BaseModelConfig):
78
+ dtype: str = "bfloat16"
79
+ paligemma_variant: _gemma.Variant = "gemma_2b"
80
+
81
+ # Set the model specific defaults.
82
+ action_dim: int = 32
83
+ action_horizon: int = 32
84
+ max_token_len: int = 250
85
+
86
+ # Tokenizer for the fast model.
87
+ fast_model_tokenizer: Any | None = None
88
+ # Keyword arguments for the fast model tokenizer.
89
+ fast_model_tokenizer_kwargs: dict[str, Any] | None = None
90
+
91
+ @property
92
+ @override
93
+ def model_type(self) -> _model.ModelType:
94
+ return _model.ModelType.PI0_FAST
95
+
96
+ @override
97
+ def create(self, rng: at.KeyArrayLike) -> "Pi0FAST":
98
+ return Pi0FAST(self, rngs=nnx.Rngs(rng))
99
+
100
+ @override
101
+ def inputs_spec(self, *, batch_size: int = 1) -> tuple[_model.Observation, _model.Actions]:
102
+ image_spec = jax.ShapeDtypeStruct([batch_size, *_model.IMAGE_RESOLUTION, 3], jnp.float32)
103
+ image_mask_spec = jax.ShapeDtypeStruct([batch_size], jnp.bool_)
104
+
105
+ with at.disable_typechecking():
106
+ observation_spec = _model.Observation(
107
+ images={
108
+ "base_0_rgb": image_spec,
109
+ "base_1_rgb": image_spec,
110
+ "wrist_0_rgb": image_spec,
111
+ },
112
+ image_masks={
113
+ "base_0_rgb": image_mask_spec,
114
+ "base_1_rgb": image_mask_spec,
115
+ "wrist_0_rgb": image_mask_spec,
116
+ },
117
+ state=jax.ShapeDtypeStruct([batch_size, self.action_dim], jnp.float32),
118
+ tokenized_prompt=jax.ShapeDtypeStruct([batch_size, self.max_token_len], jnp.int32),
119
+ tokenized_prompt_mask=jax.ShapeDtypeStruct([batch_size, self.max_token_len], bool),
120
+ token_ar_mask=jax.ShapeDtypeStruct([batch_size, self.max_token_len], jnp.int32),
121
+ token_loss_mask=jax.ShapeDtypeStruct([batch_size, self.max_token_len], jnp.bool_),
122
+ )
123
+ action_spec = jax.ShapeDtypeStruct([batch_size, self.action_horizon, self.action_dim], jnp.float32)
124
+
125
+ return observation_spec, action_spec
126
+
127
+ def get_freeze_filter(self) -> nnx.filterlib.Filter:
128
+ """Returns the freeze filter based on the model config."""
129
+ if "lora" in self.paligemma_variant:
130
+ return nnx.All(nnx_utils.PathRegex(".*llm.*"), nnx.Not(nnx_utils.PathRegex(".*lora.*")))
131
+ return nnx.Nothing
132
+
133
+
134
+ class Pi0FAST(_model.BaseModel):
135
+ def __init__(self, config: Pi0FASTConfig, rngs: nnx.Rngs):
136
+ super().__init__(config.action_dim, config.action_horizon, config.max_token_len)
137
+ paligemma_config = _gemma.get_config(config.paligemma_variant)
138
+ # TODO: rewrite gemma in NNX. For now, use bridge.
139
+ llm = nnx_bridge.ToNNX(
140
+ _gemma.Module(
141
+ **paligemma_config,
142
+ embed_dtype=config.dtype,
143
+ cache_dtype=config.dtype,
144
+ )
145
+ )
146
+ llm.lazy_init(rngs=rngs, method="init")
147
+ img = nnx_bridge.ToNNX(
148
+ _siglip.Module(
149
+ num_classes=paligemma_config.width,
150
+ variant="So400m/14",
151
+ pool_type="none",
152
+ scan=True,
153
+ dtype_mm=config.dtype,
154
+ )
155
+ )
156
+ img.lazy_init(next(iter(config.fake_obs().images.values())), train=False, rngs=rngs)
157
+ self.PaliGemma = nnx.Dict(llm=llm, img=img)
158
+
159
+ @at.typecheck
160
+ def embed_inputs(
161
+ self, obs: _model.Observation
162
+ ) -> tuple[at.Float[at.Array, "b s emb"], at.Bool[at.Array, "b s"], at.Int[at.Array, "b s"]]:
163
+ input_mask = []
164
+ ar_mask = []
165
+ token_embeddings = []
166
+ # embed images
167
+ for name in obs.images:
168
+ image_token_embeddings, _ = self.PaliGemma.img(obs.images[name], train=False)
169
+
170
+ token_embeddings.append(image_token_embeddings)
171
+ input_mask.append(
172
+ einops.repeat(
173
+ obs.image_masks[name],
174
+ "b -> b s",
175
+ s=image_token_embeddings.shape[1],
176
+ )
177
+ )
178
+ # image tokens attend to each other --> AR mask = 0
179
+ ar_mask.append(0 * input_mask[-1])
180
+
181
+ # add tokenized inputs
182
+ assert obs.tokenized_prompt is not None, "Tokenized prompt is required"
183
+ assert obs.tokenized_prompt_mask is not None, "Tokenized prompt mask is required"
184
+ assert obs.token_ar_mask is not None, "Token auto-regressive mask is required"
185
+ tokenized_inputs_embeddings = self.PaliGemma.llm(obs.tokenized_prompt, embed_only=True)
186
+ token_embeddings.append(tokenized_inputs_embeddings)
187
+ input_mask.append(obs.tokenized_prompt_mask)
188
+ ar_mask.append(obs.token_ar_mask)
189
+
190
+ # return embeddings, input mask, and ar mask
191
+ return (
192
+ jnp.concatenate(token_embeddings, axis=1),
193
+ jnp.concatenate(input_mask, axis=1),
194
+ jnp.concatenate(ar_mask, axis=1),
195
+ )
196
+
197
+ @override
198
+ def compute_loss(
199
+ self, rng: at.KeyArrayLike, observation: _model.Observation, actions: _model.Actions, *, train: bool = False
200
+ ) -> at.Float[at.Array, "*b ah"]:
201
+ observation = _model.preprocess_observation(
202
+ rng, observation, train=train, image_keys=list(observation.images.keys())
203
+ )
204
+
205
+ # Compute inputs: one big forward pass of prefix + suffix at once
206
+ input_token_embeddings, input_mask, ar_mask = self.embed_inputs(observation)
207
+ attn_mask = make_attn_mask(input_mask, ar_mask)
208
+
209
+ # Compute one-hot targets: we predict *next* token, so shift the input tokens by one.
210
+ targets = jax.nn.one_hot(
211
+ observation.tokenized_prompt[:, 1:],
212
+ self.PaliGemma.llm.module.vocab_size,
213
+ )
214
+
215
+ # Each input predicts *next* token, so we don't input the last token.
216
+ pre_logits, _, _ = self.PaliGemma.llm(
217
+ embedded_prefix=input_token_embeddings[:, :-1],
218
+ mask=attn_mask[:, :-1, :-1],
219
+ return_prelogits=True,
220
+ )
221
+
222
+ # Only decode logits for the target tokens to save memory
223
+ # (decoding matmul is large because it is a seq_len x vocab_size dense layer).
224
+ logits, _ = self.PaliGemma.llm(
225
+ pre_logits=pre_logits[:, -targets.shape[1] :],
226
+ )
227
+ logp = jax.nn.log_softmax(logits, axis=-1)
228
+
229
+ # Compute CE loss on token targets
230
+ assert observation.token_loss_mask is not None, "Token loss mask is required"
231
+ loss_mask = observation.token_loss_mask[:, 1:]
232
+ token_pplx = jnp.sum(targets * logp, axis=-1)
233
+ return -jnp.sum(token_pplx * loss_mask, axis=-1) / jnp.clip(jnp.sum(loss_mask, -1), 1)
234
+
235
+ @override
236
+ def sample_actions(
237
+ self,
238
+ rng: at.KeyArrayLike,
239
+ observation: _model.Observation,
240
+ *,
241
+ max_decoding_steps: int | at.Int[at.Array, ""] = 256,
242
+ temperature: float = 0.0,
243
+ ) -> _model.Actions:
244
+ # TODO: this is a hack to get the image keys.
245
+ observation = _model.preprocess_observation(
246
+ None, observation, train=False, image_keys=list(observation.images.keys())
247
+ )
248
+
249
+ # embed inputs
250
+ prefix_token_embeddings, prefix_mask, prefix_ar_mask = self.embed_inputs(observation)
251
+ prefix_attn_mask = make_attn_mask(prefix_mask, prefix_ar_mask)
252
+
253
+ # left to right align all input token sequences
254
+ prefix_token_embeddings, prefix_mask, prefix_attn_mask = left_to_right_align(
255
+ prefix_token_embeddings, prefix_mask, prefix_attn_mask
256
+ )
257
+ prefill_size = prefix_token_embeddings.shape[1]
258
+ prefill_len = jnp.sum(prefix_mask, axis=-1)
259
+ prefix_start = prefill_size - prefill_len
260
+
261
+ # first fill KV cache with a forward pass of the prefix
262
+ # pad attention mask to set the size of the KV cache (prefill_size + max_decoding_steps)
263
+ prefix_attn_mask = jnp.pad(prefix_attn_mask, ((0, 0), (0, 0), (0, max_decoding_steps)))
264
+ prefix_positions = jnp.cumsum(prefix_mask, axis=-1) - 1
265
+ prefix_logits, kv_cache, _ = self.PaliGemma.llm(
266
+ embedded_prefix=prefix_token_embeddings, mask=prefix_attn_mask, positions=prefix_positions, decode=True
267
+ )
268
+
269
+ # prepare decoding -- final logit decodes the first token
270
+ last_logit = prefix_logits[:, -1:]
271
+ output_tokens = jnp.zeros((last_logit.shape[0], max_decoding_steps))
272
+
273
+ def step(carry):
274
+ rng, last_logit, output_tokens, cache, _, step = carry
275
+
276
+ # Sample token from last logit
277
+ # Split RNG for this step
278
+ rng, rng_step = jax.random.split(rng)
279
+ token = jax.lax.cond(
280
+ temperature > 0.0,
281
+ lambda _: jax.random.categorical(rng_step, last_logit / temperature, axis=-1),
282
+ lambda _: jnp.argmax(last_logit, axis=-1),
283
+ operand=None,
284
+ )
285
+ output_tokens = put_along_last_axis(output_tokens, jnp.broadcast_to(step, (token.shape[0], 1)), token)
286
+
287
+ # Check for early stopping --> stop if all batch elements have EOS token
288
+ has_eos = jnp.any(token == PALIGEMMA_EOS_TOKEN, axis=-1)
289
+ all_eos = jnp.all(has_eos)
290
+
291
+ # Decode one step
292
+ token_embedding = self.PaliGemma.llm(token, embed_only=True)
293
+ positions = prefill_len[:, None] + step + 1
294
+ mask = jnp.logical_and(
295
+ jnp.arange(prefill_size + max_decoding_steps)[None, None, :] >= prefix_start[:, None, None],
296
+ jnp.arange(prefill_size + max_decoding_steps)[None, None, :]
297
+ < (jnp.broadcast_to(prefill_size + step + 1, (prefix_start.shape[0], 1, 1))),
298
+ )
299
+ last_logit, kv_cache, _ = self.PaliGemma.llm(
300
+ embedded_prefix=token_embedding, mask=mask, positions=positions, decode=True, kv_cache=cache
301
+ )
302
+
303
+ return rng, last_logit, output_tokens, kv_cache, all_eos, step + 1
304
+
305
+ def cond(carry):
306
+ _, _, _, _, all_eos, step = carry
307
+ return (~all_eos) & (step < max_decoding_steps)
308
+
309
+ # Use lax.while_loop so we can jit the full decoding loop.
310
+ _, _, output_tokens, _, _, _ = jax.lax.while_loop(
311
+ cond, step, (rng, last_logit, output_tokens, kv_cache, False, 0)
312
+ )
313
+ return output_tokens
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/pi0_test.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import flax.nnx as nnx
2
+ import jax
3
+
4
+ import openpi.models.pi0_config as _pi0_config
5
+
6
+
7
+ def _get_frozen_state(config: _pi0_config.Pi0Config) -> nnx.State:
8
+ abstract_model = nnx.eval_shape(config.create, jax.random.key(0))
9
+
10
+ freeze_filter = config.get_freeze_filter()
11
+ return nnx.state(abstract_model, nnx.All(nnx.Param, freeze_filter)).flat_state()
12
+
13
+
14
+ def test_pi0_full_finetune():
15
+ config = _pi0_config.Pi0Config()
16
+ state = _get_frozen_state(config)
17
+ assert len(state) == 0
18
+
19
+
20
+ def test_pi0_gemma_lora():
21
+ config = _pi0_config.Pi0Config(paligemma_variant="gemma_2b_lora")
22
+ state = _get_frozen_state(config)
23
+ assert len(state) == 9
24
+ assert all("lora" not in p for p in state)
25
+ assert all("llm" in p for p in state)
26
+ assert all("_1" not in p for p in state)
27
+
28
+
29
+ def test_pi0_action_expert_lora():
30
+ config = _pi0_config.Pi0Config(action_expert_variant="gemma_300m_lora")
31
+ state = _get_frozen_state(config)
32
+ # excluding embedder, rest of the params should be same as gemma_lora.
33
+ assert len(state) == 8
34
+ assert all("lora" not in p for p in state)
35
+ assert all("llm" in p for p in state)
36
+ # all frozen params should have _1 in their path since it's the action expert.
37
+ assert all(any("_1" in p for p in path) for path in state)
38
+
39
+
40
+ def test_pi0_all_lora():
41
+ config = _pi0_config.Pi0Config(paligemma_variant="gemma_2b_lora", action_expert_variant="gemma_300m_lora")
42
+ state = _get_frozen_state(config)
43
+ # sum of gemma_lora and action_expert_lora's frozen params.
44
+ assert len(state) == 17
45
+ assert all("lora" not in p for p in state)
46
+ assert all("llm" in p for p in state)
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/siglip.py ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 Big Vision Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """A refactored and simplified ViT adoptation for Pi, taken from big_vision."""
16
+
17
+ from collections.abc import Sequence
18
+
19
+ import flax.linen as nn
20
+ import jax
21
+ import jax.numpy as jnp
22
+ import numpy as np
23
+
24
+ import openpi.training.sharding as sharding
25
+
26
+
27
+ def posemb_sincos_2d(h, w, width, temperature=10_000.0, dtype=jnp.float32):
28
+ """Follows the MoCo v3 logic."""
29
+ y, x = jnp.mgrid[:h, :w]
30
+
31
+ assert width % 4 == 0, "Width must be mult of 4 for sincos posemb"
32
+ omega = jnp.arange(width // 4) / (width // 4 - 1)
33
+ omega = 1.0 / (temperature**omega)
34
+ y = jnp.einsum("m,d->md", y.flatten(), omega)
35
+ x = jnp.einsum("m,d->md", x.flatten(), omega)
36
+ pe = jnp.concatenate([jnp.sin(x), jnp.cos(x), jnp.sin(y), jnp.cos(y)], axis=1)
37
+ return jnp.asarray(pe, dtype)[None, :, :]
38
+
39
+
40
+ def get_posemb(self, typ, seqshape, width, name, dtype=jnp.float32):
41
+ if typ == "learn":
42
+ return self.param(
43
+ name,
44
+ nn.initializers.normal(stddev=1 / np.sqrt(width)),
45
+ (1, np.prod(seqshape), width),
46
+ dtype,
47
+ )
48
+ if typ == "sincos2d":
49
+ return posemb_sincos_2d(*seqshape, width, dtype=dtype)
50
+ raise ValueError(f"Unknown posemb type: {typ}")
51
+
52
+
53
+ class MlpBlock(nn.Module):
54
+ """Transformer MLP / feed-forward block."""
55
+
56
+ mlp_dim: int | None = None # Defaults to 4x input dim
57
+ dropout: float = 0.0
58
+ dtype_mm: str = "float32"
59
+
60
+ @nn.compact
61
+ def __call__(self, x, deterministic=True): # noqa: FBT002
62
+ """Applies Transformer MlpBlock module."""
63
+ inits = {
64
+ "kernel_init": nn.initializers.xavier_uniform(),
65
+ "bias_init": nn.initializers.normal(stddev=1e-6),
66
+ }
67
+
68
+ _, _, d = x.shape # n,l,d
69
+ x = nn.Dense(self.mlp_dim or 4 * d, dtype=self.dtype_mm, **inits)(x)
70
+ x = nn.gelu(x)
71
+ x = nn.Dropout(rate=self.dropout)(x, deterministic)
72
+ return nn.Dense(d, dtype=self.dtype_mm, **inits)(x)
73
+
74
+
75
+ class Encoder1DBlock(nn.Module):
76
+ """Single transformer encoder block (MHSA + MLP)."""
77
+
78
+ mlp_dim: int | None = None # Defaults to 4x input dim
79
+ num_heads: int = 12
80
+ dropout: float = 0.0
81
+ dtype_mm: str = "float32"
82
+
83
+ @nn.compact
84
+ def __call__(self, x, deterministic=True): # noqa: FBT002
85
+ out = {}
86
+ x = sharding.activation_sharding_constraint(x)
87
+ y = nn.LayerNorm(dtype=self.dtype_mm)(x)
88
+ y = out["sa"] = nn.MultiHeadDotProductAttention(
89
+ num_heads=self.num_heads,
90
+ kernel_init=nn.initializers.xavier_uniform(),
91
+ deterministic=deterministic,
92
+ dtype=self.dtype_mm,
93
+ )(y, y)
94
+ y = sharding.activation_sharding_constraint(y)
95
+ y = nn.Dropout(rate=self.dropout)(y, deterministic)
96
+ x = out["+sa"] = x + y
97
+
98
+ y = nn.LayerNorm(dtype=self.dtype_mm)(x)
99
+ y = out["mlp"] = MlpBlock(
100
+ mlp_dim=self.mlp_dim,
101
+ dropout=self.dropout,
102
+ dtype_mm=self.dtype_mm,
103
+ )(y, deterministic)
104
+ y = sharding.activation_sharding_constraint(y)
105
+ y = nn.Dropout(rate=self.dropout)(y, deterministic)
106
+ x = out["+mlp"] = x + y
107
+ x = sharding.activation_sharding_constraint(x)
108
+ return x, out
109
+
110
+
111
+ class Encoder(nn.Module):
112
+ """Transformer Model Encoder for sequence to sequence translation."""
113
+
114
+ depth: int
115
+ mlp_dim: int | None = None # Defaults to 4x input dim
116
+ num_heads: int = 12
117
+ dropout: float = 0.0
118
+ scan: bool = False
119
+ remat_policy: str = "nothing_saveable"
120
+ dtype_mm: str = "float32"
121
+
122
+ @nn.compact
123
+ def __call__(self, x, deterministic=True): # noqa: FBT002
124
+ out = {}
125
+
126
+ if self.scan:
127
+ block = nn.remat(
128
+ Encoder1DBlock,
129
+ prevent_cse=False,
130
+ static_argnums=(2,), # 0=self, 2=deterministic
131
+ policy=getattr(jax.checkpoint_policies, self.remat_policy, None),
132
+ )
133
+ x, scan_out = nn.scan(
134
+ block,
135
+ variable_axes={"params": 0},
136
+ split_rngs={"params": True, "dropout": True},
137
+ in_axes=nn.broadcast,
138
+ length=self.depth,
139
+ )(
140
+ name="encoderblock",
141
+ dtype_mm=self.dtype_mm,
142
+ mlp_dim=self.mlp_dim,
143
+ num_heads=self.num_heads,
144
+ dropout=self.dropout,
145
+ )(x, deterministic)
146
+ for lyr in range(self.depth):
147
+ out[f"block{lyr:02d}"] = jax.tree.map(lambda o, lyr=lyr: o[lyr], scan_out)
148
+ else:
149
+ # Input Encoder
150
+ for lyr in range(self.depth):
151
+ block_cur = Encoder1DBlock(
152
+ name=f"encoderblock_{lyr}",
153
+ dtype_mm=self.dtype_mm,
154
+ mlp_dim=self.mlp_dim,
155
+ num_heads=self.num_heads,
156
+ dropout=self.dropout,
157
+ )
158
+ x, out[f"block{lyr:02d}"] = block_cur(x, deterministic)
159
+ out["pre_ln"] = x # Alias for last block, but without the number in it.
160
+
161
+ return nn.LayerNorm(name="encoder_norm", dtype=self.dtype_mm)(x), out
162
+
163
+
164
+ class MAPHead(nn.Module):
165
+ """Multihead Attention Pooling."""
166
+
167
+ mlp_dim: int | None = None # Defaults to 4x input dim
168
+ num_heads: int = 12
169
+ dtype_mm: str = "float32"
170
+
171
+ @nn.compact
172
+ def __call__(self, x):
173
+ n, _, d = x.shape # n,l,d
174
+ probe = self.param("probe", nn.initializers.xavier_uniform(), (1, 1, d), x.dtype)
175
+ probe = jnp.tile(probe, [n, 1, 1])
176
+
177
+ x = nn.MultiHeadDotProductAttention(
178
+ num_heads=self.num_heads,
179
+ dtype=self.dtype_mm,
180
+ kernel_init=nn.initializers.xavier_uniform(),
181
+ )(probe, x)
182
+
183
+ y = nn.LayerNorm(dtype=self.dtype_mm)(x)
184
+ x = x + MlpBlock(mlp_dim=self.mlp_dim, dtype=self.dtype_mm)(y)
185
+ return x[:, 0]
186
+
187
+
188
+ class _Module(nn.Module):
189
+ """ViT model."""
190
+
191
+ num_classes: int | None = None
192
+ patch_size: Sequence[int] = (16, 16)
193
+ width: int = 768
194
+ depth: int = 12
195
+ mlp_dim: int | None = None # Defaults to 4x input dim
196
+ num_heads: int = 12
197
+ posemb: str = "learn" # Can also be "sincos2d"
198
+ rep_size: int | bool = False
199
+ dropout: float = 0.0
200
+ pool_type: str = "gap" # Can also be "map" or "tok"
201
+ head_zeroinit: bool = True
202
+ scan: bool = False
203
+ # or "dots_with_no_batch_dims_saveable" for more speed (memory costly)
204
+ remat_policy: str = "nothing_saveable"
205
+ dtype_mm: str = "float32"
206
+
207
+ @nn.compact
208
+ def __call__(self, image, *, train=False):
209
+ out = {}
210
+
211
+ # Kevin edit: do patch extraction and posemb in float32,
212
+ # because I feel like it's a bit safer.
213
+ image = jnp.asarray(image, jnp.float32)
214
+
215
+ # Patch extraction
216
+ x = out["stem"] = nn.Conv(
217
+ self.width,
218
+ self.patch_size,
219
+ strides=self.patch_size,
220
+ padding="VALID",
221
+ name="embedding",
222
+ dtype=jnp.float32,
223
+ )(image)
224
+
225
+ n, h, w, c = x.shape
226
+ x = jnp.reshape(x, [n, h * w, c])
227
+
228
+ # Add posemb before adding extra token.
229
+ x = out["with_posemb"] = x + get_posemb(self, self.posemb, (h, w), c, "pos_embedding", jnp.float32)
230
+
231
+ if self.pool_type == "tok":
232
+ cls = self.param("cls", nn.initializers.zeros, (1, 1, c), x.dtype)
233
+ x = jnp.concatenate([jnp.tile(cls, [n, 1, 1]), x], axis=1)
234
+
235
+ n, _, c = x.shape # n,l,d
236
+ x = nn.Dropout(rate=self.dropout)(x, not train)
237
+
238
+ # Kevin edit: now cast back to dtype_mm (potentially half precision)
239
+ x = x.astype(self.dtype_mm)
240
+
241
+ x, out["encoder"] = Encoder(
242
+ depth=self.depth,
243
+ mlp_dim=self.mlp_dim,
244
+ num_heads=self.num_heads,
245
+ dropout=self.dropout,
246
+ scan=self.scan,
247
+ remat_policy=self.remat_policy,
248
+ dtype_mm=self.dtype_mm,
249
+ name="Transformer",
250
+ )(x, deterministic=not train)
251
+ encoded = out["encoded"] = x
252
+
253
+ if self.pool_type == "map":
254
+ x = out["head_input"] = MAPHead(
255
+ num_heads=self.num_heads,
256
+ mlp_dim=self.mlp_dim,
257
+ dtype=self.dtype_mm,
258
+ )(x)
259
+ elif self.pool_type == "gap":
260
+ x = out["head_input"] = jnp.mean(x, axis=1)
261
+ elif self.pool_type == "0":
262
+ x = out["head_input"] = x[:, 0]
263
+ elif self.pool_type == "tok":
264
+ x = out["head_input"] = x[:, 0]
265
+ encoded = encoded[:, 1:]
266
+ elif self.pool_type == "none":
267
+ pass
268
+ else:
269
+ raise ValueError(f"Unknown pool type: '{self.pool_type}'")
270
+
271
+ x_2d = jnp.reshape(encoded, [n, h, w, -1])
272
+
273
+ if self.rep_size:
274
+ rep_size = self.width if self.rep_size is True else self.rep_size
275
+ hid = nn.Dense(rep_size, dtype=self.dtype_mm, name="pre_logits")
276
+ # NOTE: In the past we did not include tanh in pre_logits.
277
+ # For few-shot, it should not matter much, as it whitens anyways.
278
+ x_2d = nn.tanh(hid(x_2d))
279
+ x = nn.tanh(hid(x))
280
+
281
+ out["pre_logits_2d"] = x_2d
282
+ out["pre_logits"] = x
283
+
284
+ if self.num_classes:
285
+ kw = {"kernel_init": nn.initializers.zeros} if self.head_zeroinit else {}
286
+ head = nn.Dense(self.num_classes, dtype=self.dtype_mm, name="head", **kw)
287
+ x_2d = out["logits_2d"] = head(x_2d)
288
+ x = out["logits"] = head(x)
289
+
290
+ return x, out
291
+
292
+
293
+ def Module(num_classes=None, *, variant=None, **kw): # pylint: disable=invalid-name # noqa: N802
294
+ """Factory function, because linen really don't like what I'm doing!"""
295
+ return _Module(num_classes, **{**decode_variant(variant), **kw})
296
+
297
+
298
+ def decode_variant(variant):
299
+ """Converts a string like "B" or "B/32" into a params dict."""
300
+ if variant is None:
301
+ return {}
302
+
303
+ v, patch = variant, {}
304
+ if "/" in variant:
305
+ v, patch = variant.split("/")
306
+ patch = {"patch_size": (int(patch), int(patch))}
307
+
308
+ return {
309
+ # pylint:disable=line-too-long
310
+ # Reference: Table 2 of https://arxiv.org/abs/2106.04560.
311
+ "width": {
312
+ "mu": 32,
313
+ "Ti": 192,
314
+ "S": 384,
315
+ "M": 512,
316
+ "B": 768,
317
+ "L": 1024,
318
+ "So400m": 1152,
319
+ "H": 1280,
320
+ "g": 1408,
321
+ "g-opt": 1536,
322
+ "G": 1664,
323
+ "G-opt": 1536,
324
+ "e": 1792,
325
+ }[v],
326
+ "depth": {
327
+ "mu": 1,
328
+ "Ti": 12,
329
+ "S": 12,
330
+ "M": 12,
331
+ "B": 12,
332
+ "L": 24,
333
+ "So400m": 27,
334
+ "H": 32,
335
+ "g": 40,
336
+ "g-opt": 40,
337
+ "G": 48,
338
+ "G-opt": 48,
339
+ "e": 56,
340
+ }[v],
341
+ "mlp_dim": {
342
+ "mu": 128,
343
+ "Ti": 768,
344
+ "S": 1536,
345
+ "M": 2048,
346
+ "B": 3072,
347
+ "L": 4096,
348
+ "So400m": 4304,
349
+ "H": 5120,
350
+ "g": 6144,
351
+ "g-opt": 6144,
352
+ "G": 8192,
353
+ "G-opt": 8192,
354
+ "e": 15360,
355
+ }[v],
356
+ "num_heads": {
357
+ "mu": 2,
358
+ "Ti": 3,
359
+ "S": 6,
360
+ "M": 8,
361
+ "B": 12,
362
+ "L": 16,
363
+ "So400m": 16,
364
+ "H": 16,
365
+ "g": 16,
366
+ "g-opt": 16,
367
+ "G": 16,
368
+ "G-opt": 16,
369
+ "e": 16,
370
+ }[v],
371
+ # pylint:enable=line-too-long
372
+ **patch,
373
+ }
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/tokenizer.py ADDED
@@ -0,0 +1,371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+
4
+ import jax
5
+ import numpy as np
6
+ import orbax.checkpoint as ocp
7
+ import sentencepiece
8
+ from transformers import AutoProcessor
9
+
10
+ import openpi.models.utils.fsq_tokenizer as fsq_tokenizer
11
+ import openpi.shared.download as download
12
+
13
+
14
+ class PaligemmaTokenizer:
15
+ def __init__(self, max_len: int = 48):
16
+ self._max_len = max_len
17
+
18
+ path = download.maybe_download("gs://big_vision/paligemma_tokenizer.model", gs={"token": "anon"})
19
+ with path.open("rb") as f:
20
+ self._tokenizer = sentencepiece.SentencePieceProcessor(model_proto=f.read())
21
+
22
+ def tokenize(self, prompt: str, state: np.ndarray | None = None) -> tuple[np.ndarray, np.ndarray]:
23
+ cleaned_text = prompt.strip().replace("_", " ").replace("\n", " ")
24
+ if state is not None:
25
+ # This is the Pi05 format, where the state is part of the discrete language input.
26
+ discretized_state = np.digitize(state, bins=np.linspace(-1, 1, 256 + 1)[:-1]) - 1
27
+ state_str = " ".join(map(str, discretized_state))
28
+ full_prompt = f"Task: {cleaned_text}, State: {state_str};\nAction: "
29
+ tokens = self._tokenizer.encode(full_prompt, add_bos=True)
30
+ else:
31
+ # This is the Pi0 format, where the state is part of the continuous action expert input.
32
+ # tokenize "\n" separately as the "start of answer" token
33
+ tokens = self._tokenizer.encode(cleaned_text, add_bos=True) + self._tokenizer.encode("\n")
34
+ tokens_len = len(tokens)
35
+ if tokens_len < self._max_len:
36
+ padding = [False] * (self._max_len - tokens_len)
37
+ mask = [True] * tokens_len + padding
38
+ tokens = tokens + padding
39
+ else:
40
+ if len(tokens) > self._max_len:
41
+ logging.warning(
42
+ f"Token length ({len(tokens)}) exceeds max length ({self._max_len}), truncating. "
43
+ "Consider increasing the `max_token_len` in your model config if this happens frequently."
44
+ )
45
+ tokens = tokens[: self._max_len]
46
+ mask = [True] * self._max_len
47
+
48
+ return np.asarray(tokens), np.asarray(mask)
49
+
50
+
51
+ class FASTTokenizer:
52
+ def __init__(self, max_len: int = 256, fast_tokenizer_path: str = "physical-intelligence/fast"):
53
+ self._max_len = max_len
54
+
55
+ # Download base PaliGemma tokenizer
56
+ path = download.maybe_download("gs://big_vision/paligemma_tokenizer.model", gs={"token": "anon"})
57
+ with path.open("rb") as f:
58
+ self._paligemma_tokenizer = sentencepiece.SentencePieceProcessor(model_proto=f.read())
59
+
60
+ # Instantiate FAST tokenizer
61
+ self._fast_tokenizer = AutoProcessor.from_pretrained(fast_tokenizer_path, trust_remote_code=True)
62
+ self._fast_skip_tokens = 128 # Skip last 128 tokens in PaliGemma vocab since they are special tokens
63
+
64
+ def tokenize(
65
+ self, prompt: str, state: np.ndarray, actions: np.ndarray | None
66
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
67
+ cleaned_text = prompt.lower().strip().replace("_", " ")
68
+
69
+ # Convention: state gets discretized into 256 discrete bins (assumed range after normalization: [-1, 1])
70
+ discretized_state = np.digitize(state, bins=np.linspace(-1, 1, 256 + 1)[:-1]) - 1
71
+
72
+ # Convention: prefix includes prompt and string-representation of state, followed by ';'
73
+ state_str = " ".join(map(str, discretized_state))
74
+ prefix = f"Task: {cleaned_text}, State: {state_str};\n"
75
+ prefix_tokens = self._paligemma_tokenizer.encode(prefix, add_bos=True)
76
+
77
+ if actions is not None:
78
+ # Tokenize actions with FAST tokenizer --> map to last tokens in PaliGemma vocab
79
+ action_tokens = self._fast_tokenizer(actions[None])[0]
80
+ action_tokens_in_pg = self._act_tokens_to_paligemma_tokens(action_tokens)
81
+
82
+ # Convention: postfix contains 'Action:' followed by FAST tokens, followed by '|'
83
+ postfix_tokens = (
84
+ self._paligemma_tokenizer.encode("Action: ")
85
+ + action_tokens_in_pg.tolist()
86
+ + self._paligemma_tokenizer.encode("|", add_eos=True)
87
+ )
88
+ else:
89
+ postfix_tokens = []
90
+
91
+ # Create output token sequence & masks
92
+ # AR mask is 0 on prefix (bidirectional attention) and 1 on postfix (causal attention to all previous tokens)
93
+ tokens = prefix_tokens + postfix_tokens
94
+ token_mask = [True] * len(tokens)
95
+ ar_mask = [0] * len(prefix_tokens) + [1] * len(postfix_tokens)
96
+ loss_mask = [False] * len(prefix_tokens) + [True] * len(postfix_tokens) # Loss on postfix only
97
+
98
+ # Pad tokens to max length
99
+ tokens_len = len(tokens)
100
+ if tokens_len < self._max_len:
101
+ padding = [False] * (self._max_len - tokens_len)
102
+ tokens = tokens + padding
103
+ token_mask = token_mask + padding
104
+ ar_mask = ar_mask + padding
105
+ loss_mask = loss_mask + padding
106
+ else:
107
+ if len(tokens) > self._max_len:
108
+ logging.warning(
109
+ f"Token length ({len(tokens)}) exceeds max length ({self._max_len}), truncating. "
110
+ "Consider increasing the `max_token_len` in your model config if this happens frequently."
111
+ )
112
+ tokens = tokens[: self._max_len]
113
+ token_mask = token_mask[: self._max_len]
114
+ ar_mask = ar_mask[: self._max_len]
115
+ loss_mask = loss_mask[: self._max_len]
116
+
117
+ return np.asarray(tokens), np.asarray(token_mask), np.asarray(ar_mask), np.asarray(loss_mask)
118
+
119
+ def extract_actions(self, tokens: np.ndarray, action_horizon: int, action_dim: int) -> np.ndarray:
120
+ # Decode predicted output tokens
121
+ decoded_tokens = self._paligemma_tokenizer.decode(tokens.tolist())
122
+
123
+ # Extract actions from FAST model outputs
124
+ if "Action: " not in decoded_tokens:
125
+ return np.zeros((action_horizon, action_dim), dtype=np.float32)
126
+
127
+ # Extract actions from decoded tokens
128
+ raw_action_tokens = np.array(
129
+ self._paligemma_tokenizer.encode(decoded_tokens.split("Action: ")[1].split("|")[0].strip())
130
+ )
131
+ action_tokens = self._act_tokens_to_paligemma_tokens(raw_action_tokens)
132
+ return self._fast_tokenizer.decode(
133
+ [action_tokens.tolist()], time_horizon=action_horizon, action_dim=action_dim
134
+ )[0]
135
+
136
+ def _act_tokens_to_paligemma_tokens(self, tokens: np.ndarray | list[int]) -> np.ndarray:
137
+ if isinstance(tokens, list):
138
+ tokens = np.array(tokens)
139
+ return self._paligemma_tokenizer.vocab_size() - 1 - self._fast_skip_tokens - tokens
140
+
141
+
142
+ ###########################################################################
143
+ ## The tokenizers below are used for RoboArena baseline implementations. ##
144
+ ## They are *not* used for pi0-style models. ##
145
+ ###########################################################################
146
+
147
+
148
+ class BinningTokenizer:
149
+ """
150
+ Standard RT-2 / OpenVLA style binning tokenizer.
151
+ """
152
+
153
+ def __init__(self, max_len: int = 256, n_bins: int = 256):
154
+ self._max_len = max_len
155
+ self._n_bins = n_bins
156
+
157
+ # Download base PaliGemma tokenizer
158
+ path = download.maybe_download("gs://big_vision/paligemma_tokenizer.model", gs={"token": "anon"})
159
+ with path.open("rb") as f:
160
+ self._paligemma_tokenizer = sentencepiece.SentencePieceProcessor(model_proto=f.read())
161
+
162
+ self._fast_skip_tokens = 128 # Skip last 128 tokens in PaliGemma vocab since they are special tokens
163
+
164
+ def tokenize(
165
+ self, prompt: str, state: np.ndarray, actions: np.ndarray | None
166
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
167
+ """Tokenize a prompt and state into a sequence of tokens.
168
+
169
+ Args:
170
+ prompt: The text prompt to tokenize.
171
+ state: The state array to discretize and tokenize.
172
+ actions: Must be None. Action encoding is not currently supported.
173
+
174
+ Returns:
175
+ A tuple of (tokens, token_mask, ar_mask, targets).
176
+
177
+ Raises:
178
+ NotImplementedError: If actions is not None.
179
+ """
180
+ cleaned_text = prompt.lower().strip().replace("_", " ")
181
+
182
+ # Convention: state gets discretized into 256 discrete bins (assumed range after normalization: [-1, 1])
183
+ discretized_state = np.digitize(state, bins=np.linspace(-1, 1, 256 + 1)[:-1]) - 1
184
+
185
+ # Convention: prefix includes prompt and string-representation of state, followed by ';'
186
+ state_str = " ".join(map(str, discretized_state))
187
+ prefix = f"Task: {cleaned_text}, State: {state_str};\n"
188
+ prefix_tokens = self._paligemma_tokenizer.encode(prefix, add_bos=True)
189
+
190
+ if actions is not None:
191
+ raise NotImplementedError("BinningTokenizer does not support encoding actions atm (only for inference use)")
192
+ postfix_tokens = []
193
+
194
+ # Create output token sequence & masks
195
+ # AR mask is 0 on prefix (bidirectional attention) and 1 on postfix (causal attention to all previous tokens)
196
+ tokens = prefix_tokens + postfix_tokens
197
+ token_mask = [True] * len(tokens)
198
+ ar_mask = [0] * len(prefix_tokens) + [1] * len(postfix_tokens)
199
+ loss_mask = [False] * len(prefix_tokens) + [True] * len(postfix_tokens) # Loss on postfix only
200
+
201
+ # Pad tokens to max length
202
+ tokens_len = len(tokens)
203
+ if tokens_len < self._max_len:
204
+ padding = [False] * (self._max_len - tokens_len)
205
+ tokens = tokens + padding
206
+ token_mask = token_mask + padding
207
+ ar_mask = ar_mask + padding
208
+ loss_mask = loss_mask + padding
209
+ else:
210
+ if len(tokens) > self._max_len:
211
+ logging.warning(
212
+ f"Token length ({len(tokens)}) exceeds max length ({self._max_len}), truncating. "
213
+ "Consider increasing the `max_token_len` in your model config if this happens frequently."
214
+ )
215
+ tokens = tokens[: self._max_len]
216
+ token_mask = token_mask[: self._max_len]
217
+ ar_mask = ar_mask[: self._max_len]
218
+ loss_mask = loss_mask[: self._max_len]
219
+
220
+ return np.asarray(tokens), np.asarray(token_mask), np.asarray(ar_mask), np.asarray(loss_mask)
221
+
222
+ def extract_actions(self, tokens: np.ndarray, action_horizon: int, action_dim: int) -> np.ndarray:
223
+ # Decode predicted output tokens
224
+ decoded_tokens = self._paligemma_tokenizer.decode(tokens.tolist())
225
+
226
+ # Extract actions from FAST model outputs
227
+ if "Action: " not in decoded_tokens:
228
+ return np.zeros((action_horizon, action_dim), dtype=np.float32)
229
+
230
+ # Extract actions from decoded tokens
231
+ raw_action_tokens = np.array(
232
+ self._paligemma_tokenizer.encode(decoded_tokens.split("Action: ")[1].split("|")[0].strip())
233
+ )
234
+ action_tokens = self._act_tokens_to_paligemma_tokens(raw_action_tokens)
235
+ if len(action_tokens) < action_horizon * action_dim:
236
+ return np.zeros([action_horizon, action_dim], dtype=np.float32)
237
+ action_tokens = action_tokens[: (action_horizon * action_dim)].reshape([action_horizon, action_dim])
238
+ return action_tokens / self._n_bins * 2 - 1
239
+
240
+ def _act_tokens_to_paligemma_tokens(self, tokens: np.ndarray | list[int]) -> np.ndarray:
241
+ if isinstance(tokens, list):
242
+ tokens = np.array(tokens)
243
+ return self._paligemma_tokenizer.vocab_size() - 1 - self._fast_skip_tokens - tokens
244
+
245
+
246
+ class FSQTokenizer:
247
+ """
248
+ FSQ tokenizer from the FAST paper baselines.
249
+ """
250
+
251
+ def __init__(self, max_len: int = 256, fsq_tokenizer_path: str | None = None):
252
+ self._max_len = max_len
253
+
254
+ assert fsq_tokenizer_path is not None, "fsq_tokenizer_path must be provided"
255
+ # Download tokenizer
256
+ path = download.maybe_download(fsq_tokenizer_path)
257
+ tok_path = os.path.join(path, os.listdir(path)[0])
258
+
259
+ # Split step from path
260
+ step = int(tok_path.split("/")[-1])
261
+ base_path = tok_path.rsplit("/", 1)[0]
262
+
263
+ mgr = ocp.CheckpointManager(
264
+ base_path,
265
+ item_handlers={
266
+ "params": ocp.StandardCheckpointHandler(),
267
+ "opt_state": ocp.StandardCheckpointHandler(),
268
+ "config": ocp.JsonCheckpointHandler(),
269
+ },
270
+ options=ocp.CheckpointManagerOptions(max_to_keep=1),
271
+ )
272
+
273
+ try:
274
+ restored = mgr.restore(
275
+ step, args=ocp.args.Composite(config=ocp.args.JsonRestore(), params=ocp.args.StandardRestore())
276
+ )
277
+ config = restored["config"]
278
+ self._params = restored["params"]
279
+ self._fsq_tokenizer = fsq_tokenizer.FsqAttentionTokenizer(**config)
280
+ except Exception as e:
281
+ raise RuntimeError(
282
+ f"Failed to load FSQ tokenizer checkpoint from {fsq_tokenizer_path}. Error: {e!s}"
283
+ ) from e
284
+
285
+ # Compile tokenize and detokenize functions
286
+ self._tokenize_fn = jax.jit(
287
+ lambda params, x: self._fsq_tokenizer.apply({"params": params}, x, method=self._fsq_tokenizer.tokenize)
288
+ )
289
+ self._detokenize_fn = jax.jit(
290
+ lambda params, x: self._fsq_tokenizer.apply({"params": params}, x, method=self._fsq_tokenizer.detokenize)
291
+ )
292
+
293
+ # Download base PaliGemma tokenizer
294
+ path = download.maybe_download("gs://big_vision/paligemma_tokenizer.model", gs={"token": "anon"})
295
+ with path.open("rb") as f:
296
+ self._paligemma_tokenizer = sentencepiece.SentencePieceProcessor(model_proto=f.read())
297
+
298
+ self._fast_skip_tokens = 128 # Skip last 128 tokens in PaliGemma vocab since they are special tokens
299
+
300
+ def tokenize(
301
+ self, prompt: str, state: np.ndarray, actions: np.ndarray | None
302
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
303
+ cleaned_text = prompt.lower().strip().replace("_", " ")
304
+
305
+ # Convention: state gets discretized into 256 discrete bins (assumed range after normalization: [-1, 1])
306
+ discretized_state = np.digitize(state, bins=np.linspace(-1, 1, 256 + 1)[:-1]) - 1
307
+
308
+ # Convention: prefix includes prompt and string-representation of state, followed by ';'
309
+ state_str = " ".join(map(str, discretized_state))
310
+ prefix = f"Task: {cleaned_text}, State: {state_str};\n"
311
+ prefix_tokens = self._paligemma_tokenizer.encode(prefix, add_bos=True)
312
+
313
+ if actions is not None:
314
+ raise NotImplementedError("FSQTokenizer does not support encoding actions atm (only for inference use)")
315
+ postfix_tokens = []
316
+
317
+ # Create output token sequence & masks
318
+ # AR mask is 0 on prefix (bidirectional attention) and 1 on postfix (causal attention to all previous tokens)
319
+ tokens = prefix_tokens + postfix_tokens
320
+ token_mask = [True] * len(tokens)
321
+ ar_mask = [0] * len(prefix_tokens) + [1] * len(postfix_tokens)
322
+ loss_mask = [False] * len(prefix_tokens) + [True] * len(postfix_tokens) # Loss on postfix only
323
+
324
+ # Pad tokens to max length
325
+ tokens_len = len(tokens)
326
+ if tokens_len < self._max_len:
327
+ padding = [False] * (self._max_len - tokens_len)
328
+ tokens = tokens + padding
329
+ token_mask = token_mask + padding
330
+ ar_mask = ar_mask + padding
331
+ loss_mask = loss_mask + padding
332
+ else:
333
+ if len(tokens) > self._max_len:
334
+ logging.warning(
335
+ f"Token length ({len(tokens)}) exceeds max length ({self._max_len}), truncating. "
336
+ "Consider increasing the `max_token_len` in your model config if this happens frequently."
337
+ )
338
+ tokens = tokens[: self._max_len]
339
+ token_mask = token_mask[: self._max_len]
340
+ ar_mask = ar_mask[: self._max_len]
341
+ loss_mask = loss_mask[: self._max_len]
342
+
343
+ return np.asarray(tokens), np.asarray(token_mask), np.asarray(ar_mask), np.asarray(loss_mask)
344
+
345
+ def extract_actions(self, tokens: np.ndarray, action_horizon: int, action_dim: int) -> np.ndarray:
346
+ # Decode predicted output tokens
347
+ decoded_tokens = self._paligemma_tokenizer.decode(tokens.tolist())
348
+
349
+ # Extract actions from FAST model outputs
350
+ if "Action: " not in decoded_tokens:
351
+ return np.zeros((action_horizon, action_dim), dtype=np.float32)
352
+
353
+ # Extract actions from decoded tokens
354
+ raw_action_tokens = np.array(
355
+ self._paligemma_tokenizer.encode(decoded_tokens.split("Action: ")[1].split("|")[0].strip())
356
+ )
357
+ action_tokens = self._act_tokens_to_paligemma_tokens(raw_action_tokens)
358
+ try:
359
+ # Move computation to CPU and compile on-demand
360
+ device = jax.devices("cpu")[0]
361
+ with jax.default_device(device):
362
+ detok_act = self._detokenize_fn(self._params, action_tokens[None, ...])[0]
363
+ return detok_act[: action_horizon * action_dim].reshape([action_horizon, action_dim])
364
+ except Exception as e:
365
+ logging.warning(f"Error decoding FSQ: {e}")
366
+ return np.zeros((action_horizon, action_dim))
367
+
368
+ def _act_tokens_to_paligemma_tokens(self, tokens: np.ndarray | list[int]) -> np.ndarray:
369
+ if isinstance(tokens, list):
370
+ tokens = np.array(tokens)
371
+ return self._paligemma_tokenizer.vocab_size() - 1 - self._fast_skip_tokens - tokens
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/tokenizer_test.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ from openpi.models import tokenizer as _tokenizer
4
+
5
+
6
+ def test_tokenize():
7
+ tokenizer = _tokenizer.PaligemmaTokenizer(max_len=10)
8
+ tokens, masks = tokenizer.tokenize("Hello, world!")
9
+
10
+ assert tokens.shape == (10,)
11
+ assert masks.shape == (10,)
12
+
13
+
14
+ def test_fast_tokenizer():
15
+ prompt = "Hello, world!"
16
+ state = np.random.rand(5).astype(np.float32)
17
+ action = np.random.rand(3, 2).astype(np.float32)
18
+ tokenizer = _tokenizer.FASTTokenizer(max_len=256)
19
+ tokens, token_masks, ar_masks, loss_masks = tokenizer.tokenize(prompt, state, action)
20
+
21
+ assert tokens.shape == (256,)
22
+ assert token_masks.shape == (256,)
23
+ assert ar_masks.shape == (256,)
24
+ assert loss_masks.shape == (256,)
25
+
26
+ act = tokenizer.extract_actions(tokens, 3, 2)
27
+ assert act.shape == (3, 2)
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/utils/__pycache__/fsq_tokenizer.cpython-311.pyc ADDED
Binary file (28.6 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/utils/fsq_tokenizer.py ADDED
@@ -0,0 +1,472 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from typing import Any, Literal
3
+
4
+ import chex
5
+ from einops import einops
6
+ from flax import linen as nn
7
+ from flax.linen.module import Module
8
+ from flax.linen.module import compact
9
+ from flax.struct import dataclass
10
+ from flax.typing import Array
11
+ import jax
12
+ import jax.numpy as jnp
13
+
14
+
15
+ class FsqCodebook(nn.Module):
16
+ input_dim: int
17
+ target_codebook_size: int
18
+ codebook_type: Literal["fsq", "lfq"]
19
+
20
+ _bins_per_dim: tuple[int] | None = None
21
+
22
+ @property
23
+ def bins_per_dim(self) -> tuple[int]:
24
+ if self._bins_per_dim is not None:
25
+ return self._bins_per_dim
26
+
27
+ if self.codebook_type == "fsq":
28
+ return self._get_bins_fsq(self.target_codebook_size)
29
+ elif self.codebook_type == "lfq": # noqa: RET505
30
+ return self._get_bins_lfq(self.target_codebook_size)
31
+ elif self.codebook_type == "custom":
32
+ return self._get_bins_custom(self.target_codebook_size)
33
+ else:
34
+ raise ValueError(f"Codebook type {self.codebook_type} not supported.")
35
+
36
+ @property
37
+ def place_values(self) -> jnp.ndarray:
38
+ place_values = [1]
39
+ for b in self.bins_per_dim[:-1]:
40
+ place_values.append(place_values[-1] * b)
41
+ return jnp.array(place_values)
42
+
43
+ @staticmethod
44
+ def _get_bins_fsq(target_codebook_size: int) -> tuple[int]:
45
+ """
46
+ Get bins per dimension based on codebook size, from the original FSQ paper.
47
+ """
48
+ if target_codebook_size == 2**8:
49
+ return (8, 6, 5)
50
+ elif target_codebook_size == 2**10: # noqa: RET505
51
+ return (8, 5, 5, 5)
52
+ elif target_codebook_size == 2**12:
53
+ return (7, 5, 5, 5, 5)
54
+ elif target_codebook_size == 2**14:
55
+ return (8, 8, 8, 6, 5)
56
+ elif target_codebook_size == 2**16:
57
+ return (8, 8, 8, 5, 5, 5)
58
+ else:
59
+ raise ValueError(f"Codebook size {target_codebook_size} not supported.")
60
+
61
+ @staticmethod
62
+ def _get_bins_custom(target_codebook_size: int) -> tuple[int]:
63
+ if target_codebook_size == 2**8:
64
+ return (16, 16)
65
+ elif target_codebook_size == 2**10: # noqa: RET505
66
+ return (32, 32)
67
+ elif target_codebook_size == 2**12:
68
+ return (64, 64)
69
+ elif target_codebook_size == 2**14:
70
+ return (128, 128)
71
+ elif target_codebook_size == 2**16:
72
+ return (256, 256)
73
+ return None
74
+
75
+ @staticmethod
76
+ def _get_bins_lfq(target_codebook_size: int) -> tuple[int]:
77
+ """
78
+ Get bins per dimension according to the Lookup-Free Quantization paper (2 bins per dimension)
79
+ """
80
+ assert target_codebook_size & (target_codebook_size - 1) == 0, "Codebook size should be a power of two for LFQ"
81
+
82
+ return (2,) * int(math.log2(target_codebook_size))
83
+
84
+ def setup(self):
85
+ self.proj_down = nn.Dense(len(self.bins_per_dim))
86
+ self.proj_up = nn.Dense(self.input_dim)
87
+
88
+ def __call__(self, inputs: jnp.ndarray) -> tuple[jnp.ndarray, jnp.ndarray]:
89
+ tokens, z = self.encode(inputs)
90
+ output = self.decode(tokens, z_grad=z)
91
+ return tokens, output
92
+
93
+ def encode(self, inputs: jnp.ndarray) -> tuple[jnp.ndarray, jnp.ndarray]:
94
+ bases = jnp.array(self.bins_per_dim)
95
+
96
+ x = self.proj_down(inputs)
97
+ z = jnp.tanh(x)
98
+
99
+ # Quantize
100
+ digits = jnp.round((z + 1) * (bases - 1) / 2).astype(jnp.int32)
101
+ tokens = self.undigitize(digits)
102
+
103
+ return tokens, z
104
+
105
+ def decode(self, tokens: jnp.ndarray, z_grad: jax.Array | None = None) -> jnp.ndarray:
106
+ bases = jnp.array(self.bins_per_dim)
107
+ digits = self.digitize(tokens)
108
+
109
+ z_q = digits / (bases - 1) * 2 - 1
110
+
111
+ if z_grad is not None:
112
+ chex.assert_equal_shape([z_q, z_grad])
113
+ z_q = jax.lax.stop_gradient(z_q - z_grad) + z_grad
114
+
115
+ return self.proj_up(z_q)
116
+
117
+ def undigitize(self, digits: jnp.ndarray) -> jnp.ndarray:
118
+ return jnp.sum(digits * jnp.array(self.place_values), axis=-1)
119
+
120
+ def digitize(self, tokens: jnp.ndarray) -> jnp.ndarray:
121
+ return (tokens[..., None] // jnp.array(self.place_values)) % jnp.array(self.bins_per_dim)
122
+
123
+ @property
124
+ def vocab_size(self) -> int:
125
+ return math.prod(self.bins_per_dim)
126
+
127
+
128
+ class ResNetDownBlock(nn.Module):
129
+ stride: int = 1
130
+ n_filters: int = 64
131
+ dropout_rate: float = 0.0
132
+ group_size: int = 32
133
+
134
+ @nn.compact
135
+ def __call__(self, x: jnp.ndarray, *, train: bool = True) -> jnp.ndarray:
136
+ skip = x
137
+
138
+ if self.stride > 1 or x.shape[-1] != self.n_filters:
139
+ skip = nn.Conv(self.n_filters, (self.stride,), (self.stride,), "SAME")(skip)
140
+
141
+ x = nn.Conv(self.n_filters, (3,), (self.stride,), "SAME")(x)
142
+ x = nn.GroupNorm(num_groups=self.n_filters // self.group_size)(x)
143
+ x = nn.Dropout(self.dropout_rate)(x, deterministic=not train)
144
+ x = nn.relu(x)
145
+ x = nn.Conv(self.n_filters, (3,), (1,), "SAME")(x)
146
+
147
+ return skip + x
148
+
149
+
150
+ class ResNetUpBlock(nn.Module):
151
+ stride: int = 1
152
+ n_filters: int = 64
153
+ dropout_rate: float = 0.0
154
+ group_size: int = 32
155
+
156
+ @nn.compact
157
+ def __call__(self, x: jnp.ndarray, *, train: bool = True) -> jnp.ndarray:
158
+ skip = x
159
+
160
+ if self.stride > 1:
161
+ skip = nn.ConvTranspose(self.n_filters, (self.stride,), (self.stride,), "SAME")(skip)
162
+
163
+ x = nn.ConvTranspose(self.n_filters, (3,), (self.stride,), "SAME")(x)
164
+ x = nn.GroupNorm(num_groups=self.n_filters // self.group_size)(x)
165
+ x = nn.Dropout(self.dropout_rate)(x, deterministic=not train)
166
+ x = nn.relu(x)
167
+ x = nn.ConvTranspose(self.n_filters, (3,), (1,), "SAME")(x)
168
+
169
+ return skip + x
170
+
171
+
172
+ @dataclass
173
+ class LfqCodebookOutput:
174
+ tokens: jnp.ndarray
175
+ z: jnp.ndarray
176
+ z_q: jnp.ndarray
177
+ token_log_probs: jnp.ndarray
178
+ commit_loss: jnp.ndarray
179
+
180
+
181
+ class LookupFreeQuantization(nn.Module):
182
+ num_dims: int
183
+ latent_dim: int
184
+
185
+ def setup(self):
186
+ self.codebook = jnp.array([-1, 1])
187
+ self.activation = nn.tanh
188
+
189
+ self.project_down = nn.Dense(self.num_dims)
190
+ self.project_up = nn.Dense(self.latent_dim)
191
+
192
+ def encode(self, z: jnp.ndarray) -> jnp.ndarray:
193
+ z = self.project_down(z)
194
+ token_squared_distances = jnp.square(z[..., None] - self.codebook)
195
+ token_bits = jnp.argmin(token_squared_distances, axis=-1)
196
+ return jnp.sum(token_bits * (2 ** jnp.arange(self.num_dims)), axis=-1)
197
+
198
+ def decode(self, tokens: jnp.ndarray) -> jnp.ndarray:
199
+ token_bits = (tokens[..., None] & (2 ** jnp.arange(self.num_dims))).astype(jnp.int32)
200
+ return self.project_up(self.codebook[token_bits])
201
+
202
+ def loss(self, x: jnp.ndarray) -> LfqCodebookOutput:
203
+ z = self.project_down(x)
204
+ z = self.activation(z)
205
+
206
+ token_squared_distances = jnp.square(z[..., None] - self.codebook)
207
+ tokens = jnp.argmin(token_squared_distances, axis=-1)
208
+
209
+ token_bit_log_probs = -token_squared_distances
210
+ # Compute token log probs for tokens 0..2^num_dims-1 by summing corresponding log-probs
211
+ token_bit_expansions = jnp.bitwise_and(
212
+ jnp.arange(2**self.num_dims)[None, :], 2 ** jnp.arange(self.num_dims)[:, None]
213
+ ).astype(jnp.int32)
214
+ token_log_probs = (
215
+ token_bit_log_probs[..., 0] @ (1 - token_bit_expansions)
216
+ + token_bit_log_probs[..., 1] @ token_bit_expansions
217
+ ) # (batch_size, num_tokens, 2 ** num_dims)
218
+ token_log_probs = jax.lax.stop_gradient(jax.nn.log_softmax(token_log_probs, axis=-1))
219
+ chex.assert_shape(token_log_probs, (*x.shape[:-1], 2**self.num_dims))
220
+
221
+ z_q = self.codebook[tokens]
222
+ commit_loss = jnp.square(z - z_q).mean()
223
+ z_q = jax.lax.stop_gradient(z_q - z) + z
224
+
225
+ z_q = self.project_up(z_q)
226
+ z = self.project_up(z)
227
+
228
+ tokens = jnp.sum(tokens * (len(self.codebook) ** jnp.arange(self.num_dims)), axis=-1)
229
+ return LfqCodebookOutput(
230
+ tokens=tokens,
231
+ z=z,
232
+ z_q=z_q,
233
+ token_log_probs=jnp.zeros(()),
234
+ commit_loss=commit_loss,
235
+ )
236
+
237
+
238
+ def make_block_causal_attention_matrix(q: jnp.ndarray, k: jnp.ndarray, bs_q: int, bs_k: int) -> jnp.ndarray:
239
+ return nn.make_attention_mask(q, k, pairwise_fn=lambda x, y: jnp.greater_equal(x // bs_k, y // bs_q))
240
+
241
+
242
+ class GeGLU(Module):
243
+ """Gated Linear Unit with GELU (GeGLU) activation function.
244
+ GeGLU is a Flax layer that combines a linear transformation with a GELU
245
+ activation function in a gating mechanism. It is often used in Transformer models
246
+ to provide non-linear capabilities while preserving a strong linear component.
247
+
248
+ Attributes:
249
+ features: the number of output features (default: None).
250
+ """
251
+
252
+ output_dim: int = -1
253
+
254
+ @compact
255
+ def __call__(self, inputs: Array) -> Array:
256
+ """Applies the GeGLU activation to the inputs.
257
+ Args:
258
+ inputs: the nd-array to apply the GeGLU activation function to.
259
+ Returns:
260
+ The transformed input.
261
+ """
262
+ output_dim = inputs.shape[-1] if self.output_dim == -1 else self.output_dim
263
+
264
+ x = nn.Dense(output_dim * 2)(inputs)
265
+ x, gate = x[..., :output_dim], x[..., output_dim:]
266
+ return x * nn.gelu(gate)
267
+
268
+
269
+ class CrossAttentionLayer(nn.Module):
270
+ dropout_rate: float = 0.0
271
+ num_heads: int = None
272
+ causal: bool = False
273
+ mlp_ratio: float = 4.0
274
+
275
+ @nn.compact
276
+ def __call__(
277
+ self,
278
+ x: jnp.ndarray,
279
+ y: jnp.ndarray,
280
+ *,
281
+ mask_self: jnp.ndarray | None = None,
282
+ mask_cross: jnp.ndarray | None = None,
283
+ train: bool = True,
284
+ ) -> jnp.ndarray:
285
+ d_embed = x.shape[-1]
286
+ seq_len_q = x.shape[-2]
287
+ seq_len_k = y.shape[-2]
288
+
289
+ if self.causal:
290
+ # One block size will be 1
291
+ bs_q = max(seq_len_q // seq_len_k, 1)
292
+ bs_k = max(seq_len_k // seq_len_q, 1)
293
+
294
+ mask_self = nn.make_causal_mask(x[..., 0])
295
+ mask_cross = make_block_causal_attention_matrix(x[..., 0], y[..., 0], bs_q, bs_k)
296
+
297
+ # Self-attention block
298
+ skip = x
299
+ x = nn.LayerNorm()(x)
300
+ x = nn.MultiHeadDotProductAttention(
301
+ num_heads=self.num_heads or d_embed // 64,
302
+ dropout_rate=self.dropout_rate,
303
+ deterministic=not train,
304
+ )(x, x, x, mask=mask_self)
305
+ x = skip + x
306
+
307
+ # Cross-attention block
308
+ skip = x
309
+ x = nn.LayerNorm()(x)
310
+ x = nn.MultiHeadDotProductAttention(
311
+ num_heads=self.num_heads or d_embed // 64,
312
+ dropout_rate=self.dropout_rate,
313
+ deterministic=not train,
314
+ )(x, y, y, mask=mask_cross)
315
+ x = skip + x
316
+
317
+ # MLP block
318
+ skip = x
319
+ x = nn.LayerNorm()(x)
320
+ x = nn.Dense(int(d_embed * self.mlp_ratio))(x)
321
+ x = nn.Dropout(self.dropout_rate)(x, deterministic=not train)
322
+ x = GeGLU()(x)
323
+ x = nn.Dense(d_embed)(x)
324
+ return skip + x
325
+
326
+
327
+ def sinusoidal_pe_init(_, shape: tuple[int, int]) -> jnp.ndarray:
328
+ seq_len, d_embed = shape
329
+
330
+ position = jnp.arange(0, seq_len, 1)
331
+ div_term = jnp.exp(jnp.arange(0, d_embed, 2) * -(jnp.log(10000.0) / d_embed))
332
+ return jnp.concatenate(
333
+ [
334
+ jnp.sin(position[:, jnp.newaxis] * div_term),
335
+ jnp.cos(position[:, jnp.newaxis] * div_term),
336
+ ],
337
+ axis=-1,
338
+ )
339
+
340
+
341
+ class TokenizerEncoderDecoder(nn.Module):
342
+ num_tokens: int
343
+ num_cross_tokens: int
344
+ num_layers: int
345
+ causal: bool
346
+
347
+ mlp_ratio: float = 4.0
348
+ use_state_conditioning: bool = False
349
+
350
+ @nn.compact
351
+ def __call__(
352
+ self,
353
+ y: jnp.ndarray,
354
+ *,
355
+ train: bool = True,
356
+ state_conditioning: jnp.ndarray | None = None,
357
+ mask: jnp.ndarray | None = None,
358
+ ) -> jnp.ndarray:
359
+ x = self.param("q_embed", sinusoidal_pe_init, (self.num_tokens, y.shape[-1]))
360
+ x = jax.numpy.broadcast_to(x, y.shape[:-2] + x.shape[-2:])
361
+
362
+ if mask is not None:
363
+ # mask is (batch_dims..., num_cross_tokens)
364
+ chex.assert_equal_shape([y[..., 0], mask])
365
+ attn_mask = einops.repeat(mask, "... kv -> ... 1 q kv", q=self.num_tokens)
366
+ else:
367
+ attn_mask = jnp.ones((*y.shape[:-2], 1, self.num_tokens, self.num_cross_tokens))
368
+
369
+ if self.use_state_conditioning:
370
+ assert state_conditioning is not None, "State conditioning is required for this model."
371
+ state_embed = nn.Dense(y.shape[-1], name="state_proj")(state_conditioning)[..., None, :]
372
+ y = jnp.concatenate([y, state_embed], axis=-2)
373
+ attn_mask = jnp.concatenate([attn_mask, jnp.ones_like(attn_mask[..., 0:1])], axis=-1)
374
+
375
+ y = y + self.param("y_pos_enc", sinusoidal_pe_init, y.shape[-2:])
376
+
377
+ for _ in range(self.num_layers):
378
+ x = CrossAttentionLayer(causal=self.causal, mlp_ratio=self.mlp_ratio)(
379
+ x, y, train=train, mask_self=None, mask_cross=attn_mask
380
+ )
381
+
382
+ return x
383
+
384
+
385
+ class FsqAttentionTokenizer(nn.Module):
386
+ embed_dim: int
387
+ data_dim: int
388
+ data_horizon: int
389
+ num_tokens: int
390
+ num_layers: int
391
+ target_codebook_size: int
392
+ causal: bool = False
393
+ mlp_ratio: float = 2.0
394
+
395
+ bound: float | None = None
396
+
397
+ use_state_conditioning: bool = False
398
+
399
+ @property
400
+ def vocab_size(self) -> int:
401
+ return math.prod(FsqCodebook._get_bins_fsq(self.target_codebook_size)) # noqa: SLF001
402
+
403
+ def setup(self):
404
+ self.proj = nn.Dense(self.embed_dim)
405
+ self.encoder = TokenizerEncoderDecoder(
406
+ num_tokens=self.num_tokens,
407
+ num_cross_tokens=self.data_horizon,
408
+ num_layers=self.num_layers,
409
+ causal=self.causal,
410
+ use_state_conditioning=self.use_state_conditioning,
411
+ mlp_ratio=self.mlp_ratio,
412
+ )
413
+ self.codebook = FsqCodebook(
414
+ input_dim=self.embed_dim,
415
+ target_codebook_size=self.target_codebook_size,
416
+ codebook_type="custom",
417
+ )
418
+ self.decoder = TokenizerEncoderDecoder(
419
+ num_tokens=self.data_horizon,
420
+ num_cross_tokens=self.num_tokens,
421
+ num_layers=self.num_layers,
422
+ causal=self.causal,
423
+ use_state_conditioning=self.use_state_conditioning,
424
+ mlp_ratio=self.mlp_ratio,
425
+ )
426
+
427
+ self.proj_mean = nn.Dense(self.data_dim)
428
+ self.out_scale = self.param("out_scale", lambda _: jnp.full((), 1.0))
429
+
430
+ def tokenize(
431
+ self, action: jnp.ndarray, *, obs: jnp.ndarray | None = None, train: bool = False
432
+ ) -> tuple[jnp.ndarray, jnp.ndarray]:
433
+ if self.bound is not None:
434
+ action = jnp.clip(action, -self.bound, self.bound)
435
+
436
+ x = self.proj(action)
437
+ x = self.encoder(x, train=train, state_conditioning=obs)
438
+
439
+ return self.codebook.encode(x)
440
+
441
+ def detokenize(self, tokens: jnp.ndarray, *, obs: jnp.ndarray | None = None) -> jnp.ndarray:
442
+ x = self.decoder(self.codebook.decode(tokens), state_conditioning=obs)
443
+ mean = self.proj_mean(x)
444
+ return mean * self.out_scale
445
+
446
+ def loss(
447
+ self, action: jnp.ndarray, *, obs: jnp.ndarray | None = None, train: bool = True
448
+ ) -> tuple[jnp.ndarray, dict[str, jnp.ndarray]]:
449
+ # Encode
450
+ x = self.proj(action)
451
+ z = self.encoder(x, train=train, state_conditioning=obs)
452
+
453
+ # Quantize
454
+ tokens, z = self.codebook(z)
455
+
456
+ # Decode
457
+ x = self.decoder(z, train=train, state_conditioning=obs)
458
+ mean = self.proj_mean(x) * self.out_scale
459
+
460
+ mse = jnp.mean(jnp.square(action - mean))
461
+ mae = jnp.mean(jnp.abs(action - mean))
462
+
463
+ return mse, {
464
+ "mse": mse,
465
+ "mae": mae,
466
+ }
467
+
468
+ def __call__(self, *args: Any, **kwargs: Any) -> tuple[jnp.ndarray, dict[str, jnp.ndarray]]:
469
+ """
470
+ Dummy for .init
471
+ """
472
+ return self.loss(*args, **kwargs)
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models/vit.py ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 Google LLC.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """ViT implementation adapted from https://github.com/google-research/vision_transformer/blob/main/vit_jax/models_vit.py."""
15
+
16
+ from collections.abc import Callable
17
+ from typing import Any
18
+
19
+ import flax.linen as nn
20
+ import jax
21
+ import jax.numpy as jnp
22
+
23
+ from openpi.models import resnet as models_resnet
24
+
25
+ Array = Any
26
+ PRNGKey = Any
27
+ Shape = tuple[int]
28
+ Dtype = Any
29
+
30
+
31
+ class IdentityLayer(nn.Module):
32
+ """Identity layer, convenient for giving a name to an array."""
33
+
34
+ @nn.compact
35
+ def __call__(self, x):
36
+ return x
37
+
38
+
39
+ class AddPositionEmbs(nn.Module):
40
+ """Adds learned positional embeddings to the inputs.
41
+
42
+ Attributes:
43
+ posemb_init: positional embedding initializer.
44
+ """
45
+
46
+ posemb_init: Callable[[PRNGKey, Shape, Dtype], Array]
47
+ param_dtype: Dtype = jnp.float32
48
+
49
+ @nn.compact
50
+ def __call__(self, inputs):
51
+ """Applies the AddPositionEmbs module.
52
+
53
+ Args:
54
+ inputs: Inputs to the layer.
55
+
56
+ Returns:
57
+ Output tensor with shape `(bs, timesteps, in_dim)`.
58
+ """
59
+ # inputs.shape is (batch_size, seq_len, emb_dim).
60
+ assert inputs.ndim == 3, f"Number of dimensions should be 3, but it is: {inputs.ndim}"
61
+ pos_emb_shape = (1, inputs.shape[1], inputs.shape[2])
62
+ pe = self.param("pos_embedding", self.posemb_init, pos_emb_shape, self.param_dtype)
63
+ return inputs + pe
64
+
65
+
66
+ class MlpBlock(nn.Module):
67
+ """Transformer MLP / feed-forward block."""
68
+
69
+ mlp_dim: int
70
+ dtype: Dtype = jnp.float32
71
+ param_dtype: Dtype = jnp.float32
72
+ out_dim: int | None = None
73
+ dropout_rate: float = 0.1
74
+ kernel_init: Callable[[PRNGKey, Shape, Dtype], Array] = nn.initializers.xavier_uniform()
75
+ bias_init: Callable[[PRNGKey, Shape, Dtype], Array] = nn.initializers.normal(stddev=1e-6)
76
+
77
+ @nn.compact
78
+ def __call__(self, inputs, *, deterministic):
79
+ """Applies Transformer MlpBlock module."""
80
+ actual_out_dim = inputs.shape[-1] if self.out_dim is None else self.out_dim
81
+ x = nn.Dense(
82
+ features=self.mlp_dim,
83
+ dtype=self.dtype,
84
+ param_dtype=self.param_dtype,
85
+ kernel_init=self.kernel_init,
86
+ bias_init=self.bias_init,
87
+ )( # pytype: disable=wrong-arg-types
88
+ inputs
89
+ )
90
+ x = nn.gelu(x)
91
+ x = nn.Dropout(rate=self.dropout_rate)(x, deterministic=deterministic)
92
+ output = nn.Dense(
93
+ features=actual_out_dim,
94
+ dtype=self.dtype,
95
+ param_dtype=self.param_dtype,
96
+ kernel_init=self.kernel_init,
97
+ bias_init=self.bias_init,
98
+ )( # pytype: disable=wrong-arg-types
99
+ x
100
+ )
101
+ return nn.Dropout(rate=self.dropout_rate)(output, deterministic=deterministic)
102
+
103
+
104
+ class Encoder1DBlock(nn.Module):
105
+ """Transformer encoder layer.
106
+
107
+ Attributes:
108
+ inputs: input data.
109
+ mlp_dim: dimension of the mlp on top of attention block.
110
+ dtype: the dtype of the computation (default: float32).
111
+ dropout_rate: dropout rate.
112
+ attention_dropout_rate: dropout for attention heads.
113
+ deterministic: bool, deterministic or not (to apply dropout).
114
+ num_heads: Number of heads in nn.MultiHeadDotProductAttention
115
+ """
116
+
117
+ mlp_dim: int
118
+ num_heads: int
119
+ dtype: Dtype = jnp.float32
120
+ dropout_rate: float = 0.1
121
+ attention_dropout_rate: float = 0.1
122
+
123
+ @nn.compact
124
+ def __call__(self, inputs, deterministic):
125
+ """Applies Encoder1DBlock module.
126
+
127
+ Args:
128
+ inputs: Inputs to the layer.
129
+ deterministic: Dropout will not be applied when set to true.
130
+
131
+ Returns:
132
+ output after transformer encoder block.
133
+ """
134
+
135
+ # Attention block.
136
+ assert inputs.ndim == 3, f"Expected (batch, seq, hidden) got {inputs.shape}"
137
+ x = nn.LayerNorm(dtype=self.dtype)(inputs)
138
+ x = nn.MultiHeadDotProductAttention(
139
+ dtype=self.dtype,
140
+ kernel_init=nn.initializers.xavier_uniform(),
141
+ broadcast_dropout=False,
142
+ deterministic=deterministic,
143
+ dropout_rate=self.attention_dropout_rate,
144
+ num_heads=self.num_heads,
145
+ # why isn't this true by default???
146
+ force_fp32_for_softmax=True,
147
+ )(x, x)
148
+ x = nn.Dropout(rate=self.dropout_rate)(x, deterministic=deterministic)
149
+ x = x + inputs
150
+
151
+ # MLP block.
152
+ y = nn.LayerNorm(dtype=self.dtype)(x)
153
+ y = MlpBlock(mlp_dim=self.mlp_dim, dtype=self.dtype, dropout_rate=self.dropout_rate)(
154
+ y, deterministic=deterministic
155
+ )
156
+
157
+ return x + y, None
158
+
159
+
160
+ class Encoder(nn.Module):
161
+ """Transformer Model Encoder for sequence to sequence translation.
162
+
163
+ Attributes:
164
+ num_layers: number of layers
165
+ mlp_dim: dimension of the mlp on top of attention block
166
+ num_heads: Number of heads in nn.MultiHeadDotProductAttention
167
+ dropout_rate: dropout rate.
168
+ attention_dropout_rate: dropout rate in self attention.
169
+ """
170
+
171
+ dtype: jax.typing.DTypeLike
172
+ num_layers: int
173
+ mlp_dim: int
174
+ num_heads: int
175
+ dropout_rate: float = 0.1
176
+ attention_dropout_rate: float = 0.1
177
+ add_position_embedding: bool = True
178
+
179
+ @nn.compact
180
+ def __call__(self, x, *, train):
181
+ """Applies Transformer model on the inputs.
182
+
183
+ Args:
184
+ x: Inputs to the layer.
185
+ train: Set to `True` when training.
186
+
187
+ Returns:
188
+ output of a transformer encoder.
189
+ """
190
+ assert x.ndim == 3 # (batch, len, emb)
191
+
192
+ if self.add_position_embedding:
193
+ x = AddPositionEmbs(
194
+ posemb_init=nn.initializers.normal(stddev=0.02), # from BERT.
195
+ name="posembed_input",
196
+ )(x)
197
+ x = nn.Dropout(rate=self.dropout_rate)(x, deterministic=not train)
198
+
199
+ x = x.astype(self.dtype)
200
+ # Input Encoder
201
+ block = nn.remat(Encoder1DBlock, prevent_cse=False, static_argnums=(2,))
202
+ x, _ = nn.scan(
203
+ block,
204
+ variable_axes={"params": 0},
205
+ split_rngs={"params": True, "dropout": True},
206
+ in_axes=nn.broadcast,
207
+ length=self.num_layers,
208
+ )(
209
+ name="encoderblock",
210
+ mlp_dim=self.mlp_dim,
211
+ dropout_rate=self.dropout_rate,
212
+ attention_dropout_rate=self.attention_dropout_rate,
213
+ dtype=self.dtype,
214
+ num_heads=self.num_heads,
215
+ )(x, not train)
216
+ return nn.LayerNorm(name="encoder_norm", dtype=self.dtype)(x)
217
+
218
+
219
+ class VisionTransformer(nn.Module):
220
+ """VisionTransformer."""
221
+
222
+ dtype: jax.typing.DTypeLike
223
+ num_classes: int
224
+ patches: Any
225
+ transformer: Any
226
+ hidden_size: int
227
+ resnet: Any | None = None
228
+ representation_size: int | None = None
229
+ classifier: str = "token"
230
+ head_bias_init: float = 0.0
231
+ encoder: type[nn.Module] = Encoder
232
+ model_name: str | None = None
233
+
234
+ @nn.compact
235
+ def __call__(self, inputs, *, train):
236
+ x = inputs
237
+ # (Possibly partial) ResNet root.
238
+ if self.resnet is not None:
239
+ width = int(64 * self.resnet.width_factor)
240
+
241
+ # Root block.
242
+ x = models_resnet.StdConv(
243
+ features=width, kernel_size=(7, 7), strides=(2, 2), use_bias=False, name="conv_root"
244
+ )(x)
245
+ x = nn.GroupNorm(name="gn_root")(x)
246
+ x = nn.relu(x)
247
+ x = nn.max_pool(x, window_shape=(3, 3), strides=(2, 2), padding="SAME")
248
+
249
+ # ResNet stages.
250
+ if self.resnet.num_layers:
251
+ x = models_resnet.ResNetStage(
252
+ block_size=self.resnet.num_layers[0], nout=width, first_stride=(1, 1), name="block1"
253
+ )(x)
254
+ for i, block_size in enumerate(self.resnet.num_layers[1:], 1):
255
+ x = models_resnet.ResNetStage(
256
+ block_size=block_size, nout=width * 2**i, first_stride=(2, 2), name=f"block{i + 1}"
257
+ )(x)
258
+
259
+ n, h, w, c = x.shape
260
+
261
+ # We can merge s2d+emb into a single conv; it's the same.
262
+ x = nn.Conv(
263
+ features=self.hidden_size,
264
+ kernel_size=self.patches.size,
265
+ strides=self.patches.size,
266
+ padding="VALID",
267
+ name="embedding",
268
+ )(x)
269
+
270
+ # Here, x is a grid of embeddings.
271
+
272
+ # (Possibly partial) Transformer.
273
+ if self.transformer is not None:
274
+ n, h, w, c = x.shape
275
+ x = jnp.reshape(x, [n, h * w, c])
276
+
277
+ # If we want to add a class token, add it here.
278
+ if self.classifier in ["token", "token_unpooled"]:
279
+ cls = self.param("cls", nn.initializers.zeros, (1, 1, c))
280
+ cls = jnp.tile(cls, [n, 1, 1])
281
+ x = jnp.concatenate([cls, x], axis=1)
282
+
283
+ x = self.encoder(name="Transformer", **self.transformer, dtype=self.dtype)(x, train=train)
284
+
285
+ if self.classifier == "token":
286
+ x = x[:, 0]
287
+ elif self.classifier == "gap":
288
+ x = jnp.mean(x, axis=list(range(1, x.ndim - 1))) # (1,) or (1,2)
289
+ elif self.classifier in ["unpooled", "token_unpooled"]:
290
+ pass
291
+ else:
292
+ raise ValueError(f"Invalid classifier={self.classifier}")
293
+
294
+ if self.representation_size is not None:
295
+ x = nn.Dense(features=self.representation_size, name="pre_logits")(x)
296
+ x = nn.tanh(x)
297
+ else:
298
+ x = IdentityLayer(name="pre_logits")(x)
299
+
300
+ if self.num_classes:
301
+ x = nn.Dense(
302
+ features=self.num_classes,
303
+ name="head",
304
+ kernel_init=nn.initializers.zeros,
305
+ bias_init=nn.initializers.constant(self.head_bias_init),
306
+ )(x)
307
+ return x
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/__pycache__/gemma_pytorch.cpython-311.pyc ADDED
Binary file (13.9 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/__pycache__/pi0_pytorch.cpython-311.pyc ADDED
Binary file (24.8 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/__pycache__/preprocessing_pytorch.cpython-311.pyc ADDED
Binary file (7 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/gemma_pytorch.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Literal
2
+
3
+ import torch
4
+ from torch import nn
5
+ from transformers import GemmaForCausalLM
6
+ from transformers import PaliGemmaForConditionalGeneration
7
+ from transformers.models.auto import CONFIG_MAPPING
8
+ from transformers.models.gemma import modeling_gemma
9
+
10
+
11
+ class PaliGemmaWithExpertModel(nn.Module):
12
+ def __init__(
13
+ self,
14
+ vlm_config,
15
+ action_expert_config,
16
+ use_adarms=None,
17
+ precision: Literal["bfloat16", "float32"] = "bfloat16",
18
+ ):
19
+ if use_adarms is None:
20
+ use_adarms = [False, False]
21
+ super().__init__()
22
+
23
+ vlm_config_hf = CONFIG_MAPPING["paligemma"]()
24
+ vlm_config_hf._vocab_size = 257152 # noqa: SLF001
25
+ vlm_config_hf.image_token_index = 257152
26
+ vlm_config_hf.text_config.hidden_size = vlm_config.width
27
+ vlm_config_hf.text_config.intermediate_size = vlm_config.mlp_dim
28
+ vlm_config_hf.text_config.num_attention_heads = vlm_config.num_heads
29
+ vlm_config_hf.text_config.head_dim = vlm_config.head_dim
30
+ vlm_config_hf.text_config.num_hidden_layers = vlm_config.depth
31
+ vlm_config_hf.text_config.num_key_value_heads = vlm_config.num_kv_heads
32
+ vlm_config_hf.text_config.hidden_activation = "gelu_pytorch_tanh"
33
+ vlm_config_hf.text_config.torch_dtype = "float32"
34
+ vlm_config_hf.text_config.vocab_size = 257152
35
+ vlm_config_hf.text_config.use_adarms = use_adarms[0]
36
+ vlm_config_hf.text_config.adarms_cond_dim = vlm_config.width if use_adarms[0] else None
37
+ vlm_config_hf.vision_config.intermediate_size = 4304
38
+ vlm_config_hf.vision_config.projection_dim = 2048
39
+ vlm_config_hf.vision_config.projector_hidden_act = "gelu_fast"
40
+ vlm_config_hf.vision_config.torch_dtype = "float32"
41
+
42
+ action_expert_config_hf = CONFIG_MAPPING["gemma"](
43
+ head_dim=action_expert_config.head_dim,
44
+ hidden_size=action_expert_config.width,
45
+ intermediate_size=action_expert_config.mlp_dim,
46
+ num_attention_heads=action_expert_config.num_heads,
47
+ num_hidden_layers=action_expert_config.depth,
48
+ num_key_value_heads=action_expert_config.num_kv_heads,
49
+ vocab_size=257152,
50
+ hidden_activation="gelu_pytorch_tanh",
51
+ torch_dtype="float32",
52
+ use_adarms=use_adarms[1],
53
+ adarms_cond_dim=action_expert_config.width if use_adarms[1] else None,
54
+ )
55
+
56
+ self.paligemma = PaliGemmaForConditionalGeneration(config=vlm_config_hf)
57
+ self.gemma_expert = GemmaForCausalLM(config=action_expert_config_hf)
58
+ self.gemma_expert.model.embed_tokens = None
59
+
60
+ self.to_bfloat16_for_selected_params(precision)
61
+
62
+ def to_bfloat16_for_selected_params(self, precision: Literal["bfloat16", "float32"] = "bfloat16"):
63
+ if precision == "bfloat16":
64
+ self.to(dtype=torch.bfloat16)
65
+ elif precision == "float32":
66
+ self.to(dtype=torch.float32)
67
+ return
68
+ else:
69
+ raise ValueError(f"Invalid precision: {precision}")
70
+
71
+ params_to_keep_float32 = [
72
+ "vision_tower.vision_model.embeddings.patch_embedding.weight",
73
+ "vision_tower.vision_model.embeddings.patch_embedding.bias",
74
+ "vision_tower.vision_model.embeddings.position_embedding.weight",
75
+ "input_layernorm",
76
+ "post_attention_layernorm",
77
+ "model.norm",
78
+ ]
79
+
80
+ for name, param in self.named_parameters():
81
+ if any(selector in name for selector in params_to_keep_float32):
82
+ param.data = param.data.to(dtype=torch.float32)
83
+
84
+ def embed_image(self, image: torch.Tensor):
85
+ return self.paligemma.model.get_image_features(image)
86
+
87
+ def embed_language_tokens(self, tokens: torch.Tensor):
88
+ return self.paligemma.language_model.embed_tokens(tokens)
89
+
90
+ def forward(
91
+ self,
92
+ attention_mask: torch.Tensor | None = None,
93
+ position_ids: torch.LongTensor | None = None,
94
+ past_key_values: list[torch.FloatTensor] | None = None,
95
+ inputs_embeds: list[torch.FloatTensor] | None = None,
96
+ use_cache: bool | None = None,
97
+ adarms_cond: list[torch.Tensor] | None = None,
98
+ ):
99
+ if adarms_cond is None:
100
+ adarms_cond = [None, None]
101
+ if inputs_embeds[1] is None:
102
+ prefix_output = self.paligemma.language_model.forward(
103
+ inputs_embeds=inputs_embeds[0],
104
+ attention_mask=attention_mask,
105
+ position_ids=position_ids,
106
+ past_key_values=past_key_values,
107
+ use_cache=use_cache,
108
+ adarms_cond=adarms_cond[0] if adarms_cond is not None else None,
109
+ )
110
+ prefix_past_key_values = prefix_output.past_key_values
111
+ prefix_output = prefix_output.last_hidden_state
112
+ suffix_output = None
113
+ elif inputs_embeds[0] is None:
114
+ suffix_output = self.gemma_expert.model.forward(
115
+ inputs_embeds=inputs_embeds[1],
116
+ attention_mask=attention_mask,
117
+ position_ids=position_ids,
118
+ past_key_values=past_key_values,
119
+ use_cache=use_cache,
120
+ adarms_cond=adarms_cond[1] if adarms_cond is not None else None,
121
+ )
122
+ suffix_output = suffix_output.last_hidden_state
123
+ prefix_output = None
124
+ prefix_past_key_values = None
125
+ else:
126
+ models = [self.paligemma.language_model, self.gemma_expert.model]
127
+ num_layers = self.paligemma.config.text_config.num_hidden_layers
128
+
129
+ # Check if gradient checkpointing is enabled for any of the models
130
+ use_gradient_checkpointing = (
131
+ hasattr(self.gemma_expert.model, "gradient_checkpointing")
132
+ and self.gemma_expert.model.gradient_checkpointing
133
+ and self.training
134
+ ) or (hasattr(self, "gradient_checkpointing") and self.gradient_checkpointing and self.training)
135
+
136
+ # Force enable gradient checkpointing if we're in training mode and the model supports it
137
+ if self.training and hasattr(self.gemma_expert.model, "gradient_checkpointing"):
138
+ if not self.gemma_expert.model.gradient_checkpointing:
139
+ print("Forcing gradient checkpointing to be enabled for Gemma expert model")
140
+ self.gemma_expert.model.gradient_checkpointing = True
141
+ use_gradient_checkpointing = True
142
+
143
+ # Debug gradient checkpointing status
144
+ if hasattr(self, "_debug_gc_printed") and not self._debug_gc_printed:
145
+ print(f"Gemma expert model gradient checkpointing: {use_gradient_checkpointing}")
146
+ print(f"Model training mode: {self.training}")
147
+ print(
148
+ f"Gemma expert model has gradient_checkpointing attr: {hasattr(self.gemma_expert.model, 'gradient_checkpointing')}"
149
+ )
150
+ if hasattr(self.gemma_expert.model, "gradient_checkpointing"):
151
+ print(
152
+ f"Gemma expert model gradient_checkpointing value: {self.gemma_expert.model.gradient_checkpointing}"
153
+ )
154
+ self._debug_gc_printed = True
155
+
156
+ # Define the complete layer computation function for gradient checkpointing
157
+ def compute_layer_complete(layer_idx, inputs_embeds, attention_mask, position_ids, adarms_cond):
158
+ models = [self.paligemma.language_model, self.gemma_expert.model]
159
+
160
+ query_states = []
161
+ key_states = []
162
+ value_states = []
163
+ gates = []
164
+ for i, hidden_states in enumerate(inputs_embeds):
165
+ layer = models[i].layers[layer_idx]
166
+ hidden_states, gate = layer.input_layernorm(hidden_states, cond=adarms_cond[i]) # noqa: PLW2901
167
+ gates.append(gate)
168
+
169
+ input_shape = hidden_states.shape[:-1]
170
+ hidden_shape = (*input_shape, -1, layer.self_attn.head_dim)
171
+ query_state = layer.self_attn.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
172
+ key_state = layer.self_attn.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
173
+ value_state = layer.self_attn.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
174
+
175
+ query_states.append(query_state)
176
+ key_states.append(key_state)
177
+ value_states.append(value_state)
178
+
179
+ # Concatenate and process attention
180
+ query_states = torch.cat(query_states, dim=2)
181
+ key_states = torch.cat(key_states, dim=2)
182
+ value_states = torch.cat(value_states, dim=2)
183
+
184
+ dummy_tensor = torch.zeros(
185
+ query_states.shape[0],
186
+ query_states.shape[2],
187
+ query_states.shape[-1],
188
+ device=query_states.device,
189
+ dtype=query_states.dtype,
190
+ )
191
+ cos, sin = self.paligemma.model.language_model.rotary_emb(dummy_tensor, position_ids)
192
+ query_states, key_states = modeling_gemma.apply_rotary_pos_emb(
193
+ query_states, key_states, cos, sin, unsqueeze_dim=1
194
+ )
195
+
196
+ batch_size = query_states.shape[0]
197
+ scaling = self.paligemma.language_model.layers[layer_idx].self_attn.scaling
198
+
199
+ # Attention computation
200
+ att_output, _ = modeling_gemma.eager_attention_forward(
201
+ self.paligemma.language_model.layers[layer_idx].self_attn,
202
+ query_states,
203
+ key_states,
204
+ value_states,
205
+ attention_mask,
206
+ scaling,
207
+ )
208
+ # Get head_dim from the current layer, not from the model
209
+ head_dim = self.paligemma.language_model.layers[layer_idx].self_attn.head_dim
210
+ att_output = att_output.reshape(batch_size, -1, 1 * 8 * head_dim)
211
+
212
+ # Process layer outputs
213
+ outputs_embeds = []
214
+ start_pos = 0
215
+ for i, hidden_states in enumerate(inputs_embeds):
216
+ layer = models[i].layers[layer_idx]
217
+ end_pos = start_pos + hidden_states.shape[1]
218
+
219
+ if att_output.dtype != layer.self_attn.o_proj.weight.dtype:
220
+ att_output = att_output.to(layer.self_attn.o_proj.weight.dtype)
221
+ out_emb = layer.self_attn.o_proj(att_output[:, start_pos:end_pos])
222
+
223
+ # first residual
224
+ out_emb = modeling_gemma._gated_residual(hidden_states, out_emb, gates[i]) # noqa: SLF001
225
+ after_first_residual = out_emb.clone()
226
+ out_emb, gate = layer.post_attention_layernorm(out_emb, cond=adarms_cond[i])
227
+ # Convert to bfloat16 if the next layer (mlp) uses bfloat16
228
+ if layer.mlp.up_proj.weight.dtype == torch.bfloat16:
229
+ out_emb = out_emb.to(dtype=torch.bfloat16)
230
+
231
+ out_emb = layer.mlp(out_emb)
232
+ # second residual
233
+ out_emb = modeling_gemma._gated_residual(after_first_residual, out_emb, gate) # noqa: SLF001
234
+ outputs_embeds.append(out_emb)
235
+ start_pos = end_pos
236
+
237
+ return outputs_embeds
238
+
239
+ # Process all layers with gradient checkpointing if enabled
240
+ for layer_idx in range(num_layers):
241
+ if use_gradient_checkpointing:
242
+ inputs_embeds = torch.utils.checkpoint.checkpoint(
243
+ compute_layer_complete,
244
+ layer_idx,
245
+ inputs_embeds,
246
+ attention_mask,
247
+ position_ids,
248
+ adarms_cond,
249
+ use_reentrant=False,
250
+ preserve_rng_state=False,
251
+ )
252
+ else:
253
+ inputs_embeds = compute_layer_complete(
254
+ layer_idx, inputs_embeds, attention_mask, position_ids, adarms_cond
255
+ )
256
+
257
+ # Old code removed - now using compute_layer_complete function above
258
+
259
+ # final norm
260
+ # Define final norm computation function for gradient checkpointing
261
+ def compute_final_norms(inputs_embeds, adarms_cond):
262
+ outputs_embeds = []
263
+ for i, hidden_states in enumerate(inputs_embeds):
264
+ out_emb, _ = models[i].norm(hidden_states, cond=adarms_cond[i])
265
+ outputs_embeds.append(out_emb)
266
+ return outputs_embeds
267
+
268
+ # Apply gradient checkpointing to final norm if enabled
269
+ if use_gradient_checkpointing:
270
+ outputs_embeds = torch.utils.checkpoint.checkpoint(
271
+ compute_final_norms, inputs_embeds, adarms_cond, use_reentrant=False, preserve_rng_state=False
272
+ )
273
+ else:
274
+ outputs_embeds = compute_final_norms(inputs_embeds, adarms_cond)
275
+
276
+ prefix_output = outputs_embeds[0]
277
+ suffix_output = outputs_embeds[1]
278
+ prefix_past_key_values = None
279
+
280
+ return [prefix_output, suffix_output], prefix_past_key_values
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/pi0_pytorch.py ADDED
@@ -0,0 +1,462 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import math
3
+
4
+ import torch
5
+ from torch import Tensor
6
+ from torch import nn
7
+ import torch.nn.functional as F # noqa: N812
8
+
9
+ import openpi.models.gemma as _gemma
10
+ from openpi.models_pytorch.gemma_pytorch import PaliGemmaWithExpertModel
11
+ import openpi.models_pytorch.preprocessing_pytorch as _preprocessing
12
+
13
+
14
+ def get_safe_dtype(target_dtype, device_type):
15
+ """Get a safe dtype for the given device type."""
16
+ if device_type == "cpu":
17
+ # CPU doesn't support bfloat16, use float32 instead
18
+ if target_dtype == torch.bfloat16:
19
+ return torch.float32
20
+ if target_dtype == torch.float64:
21
+ return torch.float64
22
+ return target_dtype
23
+
24
+
25
+ def create_sinusoidal_pos_embedding(
26
+ time: torch.tensor, dimension: int, min_period: float, max_period: float, device="cpu"
27
+ ) -> Tensor:
28
+ """Computes sine-cosine positional embedding vectors for scalar positions."""
29
+ if dimension % 2 != 0:
30
+ raise ValueError(f"dimension ({dimension}) must be divisible by 2")
31
+
32
+ if time.ndim != 1:
33
+ raise ValueError("The time tensor is expected to be of shape `(batch_size, )`.")
34
+
35
+ dtype = get_safe_dtype(torch.float64, device.type)
36
+ fraction = torch.linspace(0.0, 1.0, dimension // 2, dtype=dtype, device=device)
37
+ period = min_period * (max_period / min_period) ** fraction
38
+
39
+ # Compute the outer product
40
+ scaling_factor = 1.0 / period * 2 * math.pi
41
+ sin_input = scaling_factor[None, :] * time[:, None]
42
+ return torch.cat([torch.sin(sin_input), torch.cos(sin_input)], dim=1)
43
+
44
+
45
+ def sample_beta(alpha, beta, bsize, device):
46
+ alpha_t = torch.as_tensor(alpha, dtype=torch.float32, device=device)
47
+ beta_t = torch.as_tensor(beta, dtype=torch.float32, device=device)
48
+ dist = torch.distributions.Beta(alpha_t, beta_t)
49
+ return dist.sample((bsize,))
50
+
51
+
52
+ def make_att_2d_masks(pad_masks, att_masks):
53
+ """Copied from big_vision.
54
+
55
+ Tokens can attend to valid inputs tokens which have a cumulative mask_ar
56
+ smaller or equal to theirs. This way `mask_ar` int[B, N] can be used to
57
+ setup several types of attention, for example:
58
+
59
+ [[1 1 1 1 1 1]]: pure causal attention.
60
+
61
+ [[0 0 0 1 1 1]]: prefix-lm attention. The first 3 tokens can attend between
62
+ themselves and the last 3 tokens have a causal attention. The first
63
+ entry could also be a 1 without changing behaviour.
64
+
65
+ [[1 0 1 0 1 0 0 1 0 0]]: causal attention between 4 blocks. Tokens of a
66
+ block can attend all previous blocks and all tokens on the same block.
67
+
68
+ Args:
69
+ input_mask: bool[B, N] true if its part of the input, false if padding.
70
+ mask_ar: int32[B, N] mask that's 1 where previous tokens cannot depend on
71
+ it and 0 where it shares the same attention mask as the previous token.
72
+ """
73
+ if att_masks.ndim != 2:
74
+ raise ValueError(att_masks.ndim)
75
+ if pad_masks.ndim != 2:
76
+ raise ValueError(pad_masks.ndim)
77
+
78
+ cumsum = torch.cumsum(att_masks, dim=1)
79
+ att_2d_masks = cumsum[:, None, :] <= cumsum[:, :, None]
80
+ pad_2d_masks = pad_masks[:, None, :] * pad_masks[:, :, None]
81
+ return att_2d_masks & pad_2d_masks
82
+
83
+
84
+ class PI0Pytorch(nn.Module):
85
+ def __init__(self, config):
86
+ super().__init__()
87
+ self.config = config
88
+ self.pi05 = config.pi05
89
+
90
+ paligemma_config = _gemma.get_config(config.paligemma_variant)
91
+ action_expert_config = _gemma.get_config(config.action_expert_variant)
92
+
93
+ self.paligemma_with_expert = PaliGemmaWithExpertModel(
94
+ paligemma_config,
95
+ action_expert_config,
96
+ use_adarms=[False, True] if self.pi05 else [False, False],
97
+ precision=config.dtype,
98
+ )
99
+
100
+ self.action_in_proj = nn.Linear(config.action_dim, action_expert_config.width)
101
+ self.action_out_proj = nn.Linear(action_expert_config.width, config.action_dim)
102
+
103
+ if self.pi05:
104
+ self.time_mlp_in = nn.Linear(action_expert_config.width, action_expert_config.width)
105
+ self.time_mlp_out = nn.Linear(action_expert_config.width, action_expert_config.width)
106
+ else:
107
+ self.state_proj = nn.Linear(config.action_dim, action_expert_config.width)
108
+ self.action_time_mlp_in = nn.Linear(2 * action_expert_config.width, action_expert_config.width)
109
+ self.action_time_mlp_out = nn.Linear(action_expert_config.width, action_expert_config.width)
110
+
111
+ torch.set_float32_matmul_precision("high")
112
+ if config.pytorch_compile_mode is not None:
113
+ self.sample_actions = torch.compile(self.sample_actions, mode=config.pytorch_compile_mode)
114
+
115
+ # Initialize gradient checkpointing flag
116
+ self.gradient_checkpointing_enabled = False
117
+
118
+ msg = "transformers_replace is not installed correctly. Please install it with `uv pip install transformers==4.53.2` and `cp -r ./src/openpi/models_pytorch/transformers_replace/* .venv/lib/python3.11/site-packages/transformers/`."
119
+ try:
120
+ from transformers.models.siglip import check
121
+
122
+ if not check.check_whether_transformers_replace_is_installed_correctly():
123
+ raise ValueError(msg)
124
+ except ImportError:
125
+ raise ValueError(msg) from None
126
+
127
+ def gradient_checkpointing_enable(self):
128
+ """Enable gradient checkpointing for memory optimization."""
129
+ self.gradient_checkpointing_enabled = True
130
+ self.paligemma_with_expert.paligemma.language_model.gradient_checkpointing = True
131
+ self.paligemma_with_expert.paligemma.vision_tower.gradient_checkpointing = True
132
+ self.paligemma_with_expert.gemma_expert.model.gradient_checkpointing = True
133
+
134
+ logging.info("Enabled gradient checkpointing for PI0Pytorch model")
135
+
136
+ def gradient_checkpointing_disable(self):
137
+ """Disable gradient checkpointing."""
138
+ self.gradient_checkpointing_enabled = False
139
+ self.paligemma_with_expert.paligemma.language_model.gradient_checkpointing = False
140
+ self.paligemma_with_expert.paligemma.vision_tower.gradient_checkpointing = False
141
+ self.paligemma_with_expert.gemma_expert.model.gradient_checkpointing = False
142
+
143
+ logging.info("Disabled gradient checkpointing for PI0Pytorch model")
144
+
145
+ def is_gradient_checkpointing_enabled(self):
146
+ """Check if gradient checkpointing is enabled."""
147
+ return self.gradient_checkpointing_enabled
148
+
149
+ def _apply_checkpoint(self, func, *args, **kwargs):
150
+ """Helper method to apply gradient checkpointing if enabled."""
151
+ if self.gradient_checkpointing_enabled and self.training:
152
+ return torch.utils.checkpoint.checkpoint(
153
+ func, *args, use_reentrant=False, preserve_rng_state=False, **kwargs
154
+ )
155
+ return func(*args, **kwargs)
156
+
157
+ def _prepare_attention_masks_4d(self, att_2d_masks):
158
+ """Helper method to prepare 4D attention masks for transformer."""
159
+ att_2d_masks_4d = att_2d_masks[:, None, :, :]
160
+ return torch.where(att_2d_masks_4d, 0.0, -2.3819763e38)
161
+
162
+ def _preprocess_observation(self, observation, *, train=True):
163
+ """Helper method to preprocess observation."""
164
+ observation = _preprocessing.preprocess_observation_pytorch(observation, train=train)
165
+ return (
166
+ list(observation.images.values()),
167
+ list(observation.image_masks.values()),
168
+ observation.tokenized_prompt,
169
+ observation.tokenized_prompt_mask,
170
+ observation.state,
171
+ )
172
+
173
+ def sample_noise(self, shape, device):
174
+ return torch.normal(
175
+ mean=0.0,
176
+ std=1.0,
177
+ size=shape,
178
+ dtype=torch.float32,
179
+ device=device,
180
+ )
181
+
182
+ def sample_time(self, bsize, device):
183
+ time_beta = sample_beta(1.5, 1.0, bsize, device)
184
+ time = time_beta * 0.999 + 0.001
185
+ return time.to(dtype=torch.float32, device=device)
186
+
187
+ def embed_prefix(
188
+ self, images, img_masks, lang_tokens, lang_masks
189
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
190
+ """Embed images with SigLIP and language tokens with embedding layer to prepare
191
+ for PaliGemma transformer processing.
192
+ """
193
+ embs = []
194
+ pad_masks = []
195
+ att_masks = []
196
+
197
+ # Process images
198
+ for img, img_mask in zip(images, img_masks, strict=True):
199
+
200
+ def image_embed_func(img):
201
+ return self.paligemma_with_expert.embed_image(img)
202
+
203
+ img_emb = self._apply_checkpoint(image_embed_func, img)
204
+
205
+ bsize, num_img_embs = img_emb.shape[:2]
206
+
207
+ embs.append(img_emb)
208
+ pad_masks.append(img_mask[:, None].expand(bsize, num_img_embs))
209
+
210
+ # Create attention masks so that image tokens attend to each other
211
+ att_masks += [0] * num_img_embs
212
+
213
+ # Process language tokens
214
+ def lang_embed_func(lang_tokens):
215
+ lang_emb = self.paligemma_with_expert.embed_language_tokens(lang_tokens)
216
+ lang_emb_dim = lang_emb.shape[-1]
217
+ return lang_emb * math.sqrt(lang_emb_dim)
218
+
219
+ lang_emb = self._apply_checkpoint(lang_embed_func, lang_tokens)
220
+
221
+ embs.append(lang_emb)
222
+ pad_masks.append(lang_masks)
223
+
224
+ # full attention between image and language inputs
225
+ num_lang_embs = lang_emb.shape[1]
226
+ att_masks += [0] * num_lang_embs
227
+
228
+ embs = torch.cat(embs, dim=1)
229
+ pad_masks = torch.cat(pad_masks, dim=1)
230
+ att_masks = torch.tensor(att_masks, dtype=torch.bool, device=pad_masks.device)
231
+
232
+ # Get batch size from the first dimension of the concatenated tensors
233
+ bsize = pad_masks.shape[0]
234
+ att_masks = att_masks[None, :].expand(bsize, len(att_masks))
235
+
236
+ return embs, pad_masks, att_masks
237
+
238
+ def embed_suffix(self, state, noisy_actions, timestep):
239
+ """Embed state, noisy_actions, timestep to prepare for Expert Gemma processing."""
240
+ embs = []
241
+ pad_masks = []
242
+ att_masks = []
243
+
244
+ if not self.pi05:
245
+ if self.state_proj.weight.dtype == torch.float32:
246
+ state = state.to(torch.float32)
247
+
248
+ # Embed state
249
+ def state_proj_func(state):
250
+ return self.state_proj(state)
251
+
252
+ state_emb = self._apply_checkpoint(state_proj_func, state)
253
+
254
+ embs.append(state_emb[:, None, :])
255
+ bsize = state_emb.shape[0]
256
+ device = state_emb.device
257
+
258
+ state_mask = torch.ones(bsize, 1, dtype=torch.bool, device=device)
259
+ pad_masks.append(state_mask)
260
+
261
+ # Set attention masks so that image and language inputs do not attend to state or actions
262
+ att_masks += [1]
263
+
264
+ # Embed timestep using sine-cosine positional encoding with sensitivity in the range [0, 1]
265
+ time_emb = create_sinusoidal_pos_embedding(
266
+ timestep, self.action_in_proj.out_features, min_period=4e-3, max_period=4.0, device=timestep.device
267
+ )
268
+ time_emb = time_emb.type(dtype=timestep.dtype)
269
+
270
+ # Fuse timestep + action information using an MLP
271
+ def action_proj_func(noisy_actions):
272
+ return self.action_in_proj(noisy_actions)
273
+
274
+ action_emb = self._apply_checkpoint(action_proj_func, noisy_actions)
275
+
276
+ if not self.pi05:
277
+ time_emb = time_emb[:, None, :].expand_as(action_emb)
278
+ action_time_emb = torch.cat([action_emb, time_emb], dim=2)
279
+
280
+ # Apply MLP layers
281
+ def mlp_func(action_time_emb):
282
+ x = self.action_time_mlp_in(action_time_emb)
283
+ x = F.silu(x) # swish == silu
284
+ return self.action_time_mlp_out(x)
285
+
286
+ action_time_emb = self._apply_checkpoint(mlp_func, action_time_emb)
287
+ adarms_cond = None
288
+ else:
289
+ # time MLP (for adaRMS)
290
+ def time_mlp_func(time_emb):
291
+ x = self.time_mlp_in(time_emb)
292
+ x = F.silu(x) # swish == silu
293
+ x = self.time_mlp_out(x)
294
+ return F.silu(x)
295
+
296
+ time_emb = self._apply_checkpoint(time_mlp_func, time_emb)
297
+ action_time_emb = action_emb
298
+ adarms_cond = time_emb
299
+
300
+ # Add to input tokens
301
+ embs.append(action_time_emb)
302
+
303
+ bsize, action_time_dim = action_time_emb.shape[:2]
304
+ action_time_mask = torch.ones(bsize, action_time_dim, dtype=torch.bool, device=timestep.device)
305
+ pad_masks.append(action_time_mask)
306
+
307
+ # Set attention masks so that image, language and state inputs do not attend to action tokens
308
+ att_masks += [1] + ([0] * (self.config.action_horizon - 1))
309
+
310
+ embs = torch.cat(embs, dim=1)
311
+ pad_masks = torch.cat(pad_masks, dim=1)
312
+ att_masks = torch.tensor(att_masks, dtype=embs.dtype, device=embs.device)
313
+ att_masks = att_masks[None, :].expand(bsize, len(att_masks))
314
+
315
+ return embs, pad_masks, att_masks, adarms_cond
316
+
317
+ def forward(self, observation, actions, noise=None, time=None) -> Tensor:
318
+ """Do a full training forward pass and compute the loss (batch_size x num_steps x num_motors)"""
319
+ images, img_masks, lang_tokens, lang_masks, state = self._preprocess_observation(observation, train=True)
320
+
321
+ if noise is None:
322
+ noise = self.sample_noise(actions.shape, actions.device)
323
+
324
+ if time is None:
325
+ time = self.sample_time(actions.shape[0], actions.device)
326
+
327
+ time_expanded = time[:, None, None]
328
+ x_t = time_expanded * noise + (1 - time_expanded) * actions
329
+ u_t = noise - actions
330
+
331
+ prefix_embs, prefix_pad_masks, prefix_att_masks = self.embed_prefix(images, img_masks, lang_tokens, lang_masks)
332
+ suffix_embs, suffix_pad_masks, suffix_att_masks, adarms_cond = self.embed_suffix(state, x_t, time)
333
+ if (
334
+ self.paligemma_with_expert.paligemma.language_model.layers[0].self_attn.q_proj.weight.dtype
335
+ == torch.bfloat16
336
+ ):
337
+ suffix_embs = suffix_embs.to(dtype=torch.bfloat16)
338
+ prefix_embs = prefix_embs.to(dtype=torch.bfloat16)
339
+
340
+ pad_masks = torch.cat([prefix_pad_masks, suffix_pad_masks], dim=1)
341
+ att_masks = torch.cat([prefix_att_masks, suffix_att_masks], dim=1)
342
+
343
+ att_2d_masks = make_att_2d_masks(pad_masks, att_masks)
344
+ position_ids = torch.cumsum(pad_masks, dim=1) - 1
345
+
346
+ # Prepare attention masks
347
+ att_2d_masks_4d = self._prepare_attention_masks_4d(att_2d_masks)
348
+
349
+ # Apply gradient checkpointing if enabled
350
+ def forward_func(prefix_embs, suffix_embs, att_2d_masks_4d, position_ids, adarms_cond):
351
+ (_, suffix_out), _ = self.paligemma_with_expert.forward(
352
+ attention_mask=att_2d_masks_4d,
353
+ position_ids=position_ids,
354
+ past_key_values=None,
355
+ inputs_embeds=[prefix_embs, suffix_embs],
356
+ use_cache=False,
357
+ adarms_cond=[None, adarms_cond],
358
+ )
359
+ return suffix_out
360
+
361
+ suffix_out = self._apply_checkpoint(
362
+ forward_func, prefix_embs, suffix_embs, att_2d_masks_4d, position_ids, adarms_cond
363
+ )
364
+
365
+ suffix_out = suffix_out[:, -self.config.action_horizon :]
366
+ suffix_out = suffix_out.to(dtype=torch.float32)
367
+
368
+ # Apply gradient checkpointing to final action projection if enabled
369
+ def action_out_proj_func(suffix_out):
370
+ return self.action_out_proj(suffix_out)
371
+
372
+ v_t = self._apply_checkpoint(action_out_proj_func, suffix_out)
373
+
374
+ return F.mse_loss(u_t, v_t, reduction="none")
375
+
376
+ @torch.no_grad()
377
+ def sample_actions(self, device, observation, noise=None, num_steps=10) -> Tensor:
378
+ """Do a full inference forward and compute the action (batch_size x num_steps x num_motors)"""
379
+ bsize = observation.state.shape[0]
380
+ if noise is None:
381
+ actions_shape = (bsize, self.config.action_horizon, self.config.action_dim)
382
+ noise = self.sample_noise(actions_shape, device)
383
+
384
+ images, img_masks, lang_tokens, lang_masks, state = self._preprocess_observation(observation, train=False)
385
+
386
+ prefix_embs, prefix_pad_masks, prefix_att_masks = self.embed_prefix(images, img_masks, lang_tokens, lang_masks)
387
+ prefix_att_2d_masks = make_att_2d_masks(prefix_pad_masks, prefix_att_masks)
388
+ prefix_position_ids = torch.cumsum(prefix_pad_masks, dim=1) - 1
389
+
390
+ # Compute image and language key value cache
391
+ prefix_att_2d_masks_4d = self._prepare_attention_masks_4d(prefix_att_2d_masks)
392
+ self.paligemma_with_expert.paligemma.language_model.config._attn_implementation = "eager" # noqa: SLF001
393
+
394
+ _, past_key_values = self.paligemma_with_expert.forward(
395
+ attention_mask=prefix_att_2d_masks_4d,
396
+ position_ids=prefix_position_ids,
397
+ past_key_values=None,
398
+ inputs_embeds=[prefix_embs, None],
399
+ use_cache=True,
400
+ )
401
+
402
+ dt = -1.0 / num_steps
403
+ dt = torch.tensor(dt, dtype=torch.float32, device=device)
404
+
405
+ x_t = noise
406
+ time = torch.tensor(1.0, dtype=torch.float32, device=device)
407
+ while time >= -dt / 2:
408
+ expanded_time = time.expand(bsize)
409
+ v_t = self.denoise_step(
410
+ state,
411
+ prefix_pad_masks,
412
+ past_key_values,
413
+ x_t,
414
+ expanded_time,
415
+ )
416
+
417
+ # Euler step - use new tensor assignment instead of in-place operation
418
+ x_t = x_t + dt * v_t
419
+ time += dt
420
+ return x_t
421
+
422
+ def denoise_step(
423
+ self,
424
+ state,
425
+ prefix_pad_masks,
426
+ past_key_values,
427
+ x_t,
428
+ timestep,
429
+ ):
430
+ """Apply one denoising step of the noise `x_t` at a given timestep."""
431
+ suffix_embs, suffix_pad_masks, suffix_att_masks, adarms_cond = self.embed_suffix(state, x_t, timestep)
432
+
433
+ suffix_len = suffix_pad_masks.shape[1]
434
+ batch_size = prefix_pad_masks.shape[0]
435
+ prefix_len = prefix_pad_masks.shape[1]
436
+
437
+ prefix_pad_2d_masks = prefix_pad_masks[:, None, :].expand(batch_size, suffix_len, prefix_len)
438
+
439
+ suffix_att_2d_masks = make_att_2d_masks(suffix_pad_masks, suffix_att_masks)
440
+
441
+ full_att_2d_masks = torch.cat([prefix_pad_2d_masks, suffix_att_2d_masks], dim=2)
442
+
443
+ prefix_offsets = torch.sum(prefix_pad_masks, dim=-1)[:, None]
444
+ position_ids = prefix_offsets + torch.cumsum(suffix_pad_masks, dim=1) - 1
445
+
446
+ # Prepare attention masks
447
+ full_att_2d_masks_4d = self._prepare_attention_masks_4d(full_att_2d_masks)
448
+ self.paligemma_with_expert.gemma_expert.model.config._attn_implementation = "eager" # noqa: SLF001
449
+
450
+ outputs_embeds, _ = self.paligemma_with_expert.forward(
451
+ attention_mask=full_att_2d_masks_4d,
452
+ position_ids=position_ids,
453
+ past_key_values=past_key_values,
454
+ inputs_embeds=[None, suffix_embs],
455
+ use_cache=False,
456
+ adarms_cond=[None, adarms_cond],
457
+ )
458
+
459
+ suffix_out = outputs_embeds[1]
460
+ suffix_out = suffix_out[:, -self.config.action_horizon :]
461
+ suffix_out = suffix_out.to(dtype=torch.float32)
462
+ return self.action_out_proj(suffix_out)
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/preprocessing_pytorch.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections.abc import Sequence
2
+ import logging
3
+
4
+ import torch
5
+
6
+ from openpi.shared import image_tools
7
+
8
+ logger = logging.getLogger("openpi")
9
+
10
+ # Constants moved from model.py
11
+ IMAGE_KEYS = (
12
+ "base_0_rgb",
13
+ "left_wrist_0_rgb",
14
+ "right_wrist_0_rgb",
15
+ )
16
+
17
+ IMAGE_RESOLUTION = (224, 224)
18
+
19
+
20
+ def preprocess_observation_pytorch(
21
+ observation,
22
+ *,
23
+ train: bool = False,
24
+ image_keys: Sequence[str] = IMAGE_KEYS,
25
+ image_resolution: tuple[int, int] = IMAGE_RESOLUTION,
26
+ ):
27
+ """Torch.compile-compatible version of preprocess_observation_pytorch with simplified type annotations.
28
+
29
+ This function avoids complex type annotations that can cause torch.compile issues.
30
+ """
31
+ if not set(image_keys).issubset(observation.images):
32
+ raise ValueError(f"images dict missing keys: expected {image_keys}, got {list(observation.images)}")
33
+
34
+ batch_shape = observation.state.shape[:-1]
35
+
36
+ out_images = {}
37
+ for key in image_keys:
38
+ image = observation.images[key]
39
+
40
+ # TODO: This is a hack to handle both [B, C, H, W] and [B, H, W, C] formats
41
+ # Handle both [B, C, H, W] and [B, H, W, C] formats
42
+ is_channels_first = image.shape[1] == 3 # Check if channels are in dimension 1
43
+
44
+ if is_channels_first:
45
+ # Convert [B, C, H, W] to [B, H, W, C] for processing
46
+ image = image.permute(0, 2, 3, 1)
47
+
48
+ if image.shape[1:3] != image_resolution:
49
+ logger.info(f"Resizing image {key} from {image.shape[1:3]} to {image_resolution}")
50
+ image = image_tools.resize_with_pad_torch(image, *image_resolution)
51
+
52
+ if train:
53
+ # Convert from [-1, 1] to [0, 1] for PyTorch augmentations
54
+ image = image / 2.0 + 0.5
55
+
56
+ # Apply PyTorch-based augmentations
57
+ if "wrist" not in key:
58
+ # Geometric augmentations for non-wrist cameras
59
+ height, width = image.shape[1:3]
60
+
61
+ # Random crop and resize
62
+ crop_height = int(height * 0.95)
63
+ crop_width = int(width * 0.95)
64
+
65
+ # Random crop
66
+ max_h = height - crop_height
67
+ max_w = width - crop_width
68
+ if max_h > 0 and max_w > 0:
69
+ # Use tensor operations instead of .item() for torch.compile compatibility
70
+ start_h = torch.randint(0, max_h + 1, (1,), device=image.device)
71
+ start_w = torch.randint(0, max_w + 1, (1,), device=image.device)
72
+ image = image[:, start_h : start_h + crop_height, start_w : start_w + crop_width, :]
73
+
74
+ # Resize back to original size
75
+ image = torch.nn.functional.interpolate(
76
+ image.permute(0, 3, 1, 2), # [b, h, w, c] -> [b, c, h, w]
77
+ size=(height, width),
78
+ mode="bilinear",
79
+ align_corners=False,
80
+ ).permute(0, 2, 3, 1) # [b, c, h, w] -> [b, h, w, c]
81
+
82
+ # Random rotation (small angles)
83
+ # Use tensor operations instead of .item() for torch.compile compatibility
84
+ angle = torch.rand(1, device=image.device) * 10 - 5 # Random angle between -5 and 5 degrees
85
+ if torch.abs(angle) > 0.1: # Only rotate if angle is significant
86
+ # Convert to radians
87
+ angle_rad = angle * torch.pi / 180.0
88
+
89
+ # Create rotation matrix
90
+ cos_a = torch.cos(angle_rad)
91
+ sin_a = torch.sin(angle_rad)
92
+
93
+ # Apply rotation using grid_sample
94
+ grid_x = torch.linspace(-1, 1, width, device=image.device)
95
+ grid_y = torch.linspace(-1, 1, height, device=image.device)
96
+
97
+ # Create meshgrid
98
+ grid_y, grid_x = torch.meshgrid(grid_y, grid_x, indexing="ij")
99
+
100
+ # Expand to batch dimension
101
+ grid_x = grid_x.unsqueeze(0).expand(image.shape[0], -1, -1)
102
+ grid_y = grid_y.unsqueeze(0).expand(image.shape[0], -1, -1)
103
+
104
+ # Apply rotation transformation
105
+ grid_x_rot = grid_x * cos_a - grid_y * sin_a
106
+ grid_y_rot = grid_x * sin_a + grid_y * cos_a
107
+
108
+ # Stack and reshape for grid_sample
109
+ grid = torch.stack([grid_x_rot, grid_y_rot], dim=-1)
110
+
111
+ image = torch.nn.functional.grid_sample(
112
+ image.permute(0, 3, 1, 2), # [b, h, w, c] -> [b, c, h, w]
113
+ grid,
114
+ mode="bilinear",
115
+ padding_mode="zeros",
116
+ align_corners=False,
117
+ ).permute(0, 2, 3, 1) # [b, c, h, w] -> [b, h, w, c]
118
+
119
+ # Color augmentations for all cameras
120
+ # Random brightness
121
+ # Use tensor operations instead of .item() for torch.compile compatibility
122
+ brightness_factor = 0.7 + torch.rand(1, device=image.device) * 0.6 # Random factor between 0.7 and 1.3
123
+ image = image * brightness_factor
124
+
125
+ # Random contrast
126
+ # Use tensor operations instead of .item() for torch.compile compatibility
127
+ contrast_factor = 0.6 + torch.rand(1, device=image.device) * 0.8 # Random factor between 0.6 and 1.4
128
+ mean = image.mean(dim=[1, 2, 3], keepdim=True)
129
+ image = (image - mean) * contrast_factor + mean
130
+
131
+ # Random saturation (convert to HSV, modify S, convert back)
132
+ # For simplicity, we'll just apply a random scaling to the color channels
133
+ # Use tensor operations instead of .item() for torch.compile compatibility
134
+ saturation_factor = 0.5 + torch.rand(1, device=image.device) * 1.0 # Random factor between 0.5 and 1.5
135
+ gray = image.mean(dim=-1, keepdim=True)
136
+ image = gray + (image - gray) * saturation_factor
137
+
138
+ # Clamp values to [0, 1]
139
+ image = torch.clamp(image, 0, 1)
140
+
141
+ # Back to [-1, 1]
142
+ image = image * 2.0 - 1.0
143
+
144
+ # Convert back to [B, C, H, W] format if it was originally channels-first
145
+ if is_channels_first:
146
+ image = image.permute(0, 3, 1, 2) # [B, H, W, C] -> [B, C, H, W]
147
+
148
+ out_images[key] = image
149
+
150
+ # obtain mask
151
+ out_masks = {}
152
+ for key in out_images:
153
+ if key not in observation.image_masks:
154
+ # do not mask by default
155
+ out_masks[key] = torch.ones(batch_shape, dtype=torch.bool, device=observation.state.device)
156
+ else:
157
+ out_masks[key] = observation.image_masks[key]
158
+
159
+ # Create a simple object with the required attributes instead of using the complex Observation class
160
+ class SimpleProcessedObservation:
161
+ def __init__(self, **kwargs):
162
+ for key, value in kwargs.items():
163
+ setattr(self, key, value)
164
+
165
+ return SimpleProcessedObservation(
166
+ images=out_images,
167
+ image_masks=out_masks,
168
+ state=observation.state,
169
+ tokenized_prompt=observation.tokenized_prompt,
170
+ tokenized_prompt_mask=observation.tokenized_prompt_mask,
171
+ token_ar_mask=observation.token_ar_mask,
172
+ token_loss_mask=observation.token_loss_mask,
173
+ )
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/gemma/configuration_gemma.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
2
+ # This file was automatically generated from src/transformers/models/gemma/modular_gemma.py.
3
+ # Do NOT edit this file manually as any edits will be overwritten by the generation of
4
+ # the file from the modular. If any change should be done, please apply the change to the
5
+ # modular_gemma.py file directly. One of our CI enforces this.
6
+ # 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
7
+ # coding=utf-8
8
+ # Copyright 2024 Google Inc. HuggingFace Inc. team. All rights reserved.
9
+ #
10
+ #
11
+ # Licensed under the Apache License, Version 2.0 (the "License");
12
+ # you may not use this file except in compliance with the License.
13
+ # You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # Unless required by applicable law or agreed to in writing, software
18
+ # distributed under the License is distributed on an "AS IS" BASIS,
19
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ # See the License for the specific language governing permissions and
21
+ # limitations under the License.
22
+ from typing import Optional
23
+ from ...configuration_utils import PretrainedConfig
24
+
25
+
26
+ class GemmaConfig(PretrainedConfig):
27
+ r"""
28
+ This is the configuration class to store the configuration of a [`GemmaModel`]. It is used to instantiate an Gemma
29
+ model according to the specified arguments, defining the model architecture. Instantiating a configuration with the
30
+ defaults will yield a similar configuration to that of the Gemma-7B.
31
+ e.g. [google/gemma-7b](https://huggingface.co/google/gemma-7b)
32
+ Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
33
+ documentation from [`PretrainedConfig`] for more information.
34
+ Args:
35
+ vocab_size (`int`, *optional*, defaults to 256000):
36
+ Vocabulary size of the Gemma model. Defines the number of different tokens that can be represented by the
37
+ `inputs_ids` passed when calling [`GemmaModel`]
38
+ hidden_size (`int`, *optional*, defaults to 3072):
39
+ Dimension of the hidden representations.
40
+ intermediate_size (`int`, *optional*, defaults to 24576):
41
+ Dimension of the MLP representations.
42
+ num_hidden_layers (`int`, *optional*, defaults to 28):
43
+ Number of hidden layers in the Transformer decoder.
44
+ num_attention_heads (`int`, *optional*, defaults to 16):
45
+ Number of attention heads for each attention layer in the Transformer decoder.
46
+ num_key_value_heads (`int`, *optional*, defaults to 16):
47
+ This is the number of key_value heads that should be used to implement Grouped Query Attention. If
48
+ `num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
49
+ `num_key_value_heads=1` the model will use Multi Query Attention (MQA) otherwise GQA is used. When
50
+ converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
51
+ by meanpooling all the original heads within that group. For more details, check out [this
52
+ paper](https://huggingface.co/papers/2305.13245). If it is not specified, will default to
53
+ `num_attention_heads`.
54
+ head_dim (`int`, *optional*, defaults to 256):
55
+ The attention head dimension.
56
+ hidden_act (`str` or `function`, *optional*, defaults to `"gelu_pytorch_tanh"`):
57
+ The legacy activation function. It is overwritten by the `hidden_activation`.
58
+ hidden_activation (`str` or `function`, *optional*):
59
+ The non-linear activation function (function or string) in the decoder. Will default to `"gelu_pytorch_tanh"`
60
+ if not specified. `"gelu_pytorch_tanh"` uses an approximation of the `"gelu"` activation function.
61
+ max_position_embeddings (`int`, *optional*, defaults to 8192):
62
+ The maximum sequence length that this model might ever be used with.
63
+ initializer_range (`float`, *optional*, defaults to 0.02):
64
+ The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
65
+ rms_norm_eps (`float`, *optional*, defaults to 1e-06):
66
+ The epsilon used by the rms normalization layers.
67
+ use_cache (`bool`, *optional*, defaults to `True`):
68
+ Whether or not the model should return the last key/values attentions (not used by all models). Only
69
+ relevant if `config.is_decoder=True`.
70
+ pad_token_id (`int`, *optional*, defaults to 0):
71
+ Padding token id.
72
+ eos_token_id (`int`, *optional*, defaults to 1):
73
+ End of stream token id.
74
+ bos_token_id (`int`, *optional*, defaults to 2):
75
+ Beginning of stream token id.
76
+ tie_word_embeddings (`bool`, *optional*, defaults to `True`):
77
+ Whether to tie weight embeddings
78
+ rope_theta (`float`, *optional*, defaults to 10000.0):
79
+ The base period of the RoPE embeddings.
80
+ attention_bias (`bool`, defaults to `False`, *optional*, defaults to `False`):
81
+ Whether to use a bias in the query, key, value and output projection layers during self-attention.
82
+ attention_dropout (`float`, *optional*, defaults to 0.0):
83
+ The dropout ratio for the attention probabilities.
84
+ use_adarms (`bool`, *optional*, defaults to `False`):
85
+ Whether to use ADARMS.
86
+ adarms_cond_dim (`int`, *optional*, defaults to `None`):
87
+ The dimension of the ADARMS condition.
88
+ ```python
89
+ >>> from transformers import GemmaModel, GemmaConfig
90
+ >>> # Initializing a Gemma gemma-7b style configuration
91
+ >>> configuration = GemmaConfig()
92
+ >>> # Initializing a model from the gemma-7b style configuration
93
+ >>> model = GemmaModel(configuration)
94
+ >>> # Accessing the model configuration
95
+ >>> configuration = model.config
96
+ ```"""
97
+
98
+ model_type = "gemma"
99
+ keys_to_ignore_at_inference = ["past_key_values"]
100
+ base_model_tp_plan = {
101
+ "layers.*.self_attn.q_proj": "colwise",
102
+ "layers.*.self_attn.k_proj": "colwise",
103
+ "layers.*.self_attn.v_proj": "colwise",
104
+ "layers.*.self_attn.o_proj": "rowwise",
105
+ "layers.*.mlp.gate_proj": "colwise",
106
+ "layers.*.mlp.up_proj": "colwise",
107
+ "layers.*.mlp.down_proj": "rowwise",
108
+ }
109
+ base_model_pp_plan = {
110
+ "embed_tokens": (["input_ids"], ["inputs_embeds"]),
111
+ "layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
112
+ "norm": (["hidden_states"], ["hidden_states"]),
113
+ }
114
+
115
+ def __init__(
116
+ self,
117
+ vocab_size=256000,
118
+ hidden_size=3072,
119
+ intermediate_size=24576,
120
+ num_hidden_layers=28,
121
+ num_attention_heads=16,
122
+ num_key_value_heads=16,
123
+ head_dim=256,
124
+ hidden_act="gelu_pytorch_tanh",
125
+ hidden_activation=None,
126
+ max_position_embeddings=8192,
127
+ initializer_range=0.02,
128
+ rms_norm_eps=1e-6,
129
+ use_cache=True,
130
+ pad_token_id=0,
131
+ eos_token_id=1,
132
+ bos_token_id=2,
133
+ tie_word_embeddings=True,
134
+ rope_theta=10000.0,
135
+ attention_bias=False,
136
+ attention_dropout=0.0,
137
+ use_adarms: bool = False,
138
+ adarms_cond_dim: Optional[int] = None,
139
+ **kwargs,
140
+ ):
141
+ self.vocab_size = vocab_size
142
+ self.max_position_embeddings = max_position_embeddings
143
+ self.hidden_size = hidden_size
144
+ self.intermediate_size = intermediate_size
145
+ self.num_hidden_layers = num_hidden_layers
146
+ self.num_attention_heads = num_attention_heads
147
+ self.head_dim = head_dim
148
+ self.num_key_value_heads = num_key_value_heads
149
+ self.hidden_act = hidden_act
150
+ self.hidden_activation = hidden_activation
151
+ self.initializer_range = initializer_range
152
+ self.rms_norm_eps = rms_norm_eps
153
+ self.use_cache = use_cache
154
+ self.rope_theta = rope_theta
155
+ self.attention_bias = attention_bias
156
+ self.attention_dropout = attention_dropout
157
+ self.use_adarms = use_adarms
158
+ self.adarms_cond_dim = adarms_cond_dim
159
+
160
+ # Set default for adarms_cond_dim if use_adarms is True
161
+ if self.use_adarms and self.adarms_cond_dim is None:
162
+ self.adarms_cond_dim = self.hidden_size
163
+
164
+ super().__init__(
165
+ pad_token_id=pad_token_id,
166
+ bos_token_id=bos_token_id,
167
+ eos_token_id=eos_token_id,
168
+ tie_word_embeddings=tie_word_embeddings,
169
+ **kwargs,
170
+ )
171
+
172
+
173
+ __all__ = ["GemmaConfig"]
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/gemma/modeling_gemma.py ADDED
@@ -0,0 +1,862 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
2
+ # This file was automatically generated from src/transformers/models/gemma/modular_gemma.py.
3
+ # Do NOT edit this file manually as any edits will be overwritten by the generation of
4
+ # the file from the modular. If any change should be done, please apply the change to the
5
+ # modular_gemma.py file directly. One of our CI enforces this.
6
+ # 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
7
+ # coding=utf-8
8
+ # Copyright 2024 Google Inc. HuggingFace Inc. team. All rights reserved.
9
+ #
10
+ #
11
+ # Licensed under the Apache License, Version 2.0 (the "License");
12
+ # you may not use this file except in compliance with the License.
13
+ # You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # Unless required by applicable law or agreed to in writing, software
18
+ # distributed under the License is distributed on an "AS IS" BASIS,
19
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ # See the License for the specific language governing permissions and
21
+ # limitations under the License.
22
+ from typing import Callable, Optional, Union
23
+
24
+ import torch
25
+ from torch import nn
26
+
27
+ from ...activations import ACT2FN
28
+ from ...cache_utils import Cache, DynamicCache
29
+ from ...generation import GenerationMixin
30
+ from ...masking_utils import create_causal_mask
31
+ from ...modeling_flash_attention_utils import FlashAttentionKwargs
32
+ from ...modeling_layers import GradientCheckpointingLayer
33
+ from ...modeling_outputs import (
34
+ BaseModelOutputWithPast,
35
+ CausalLMOutputWithPast,
36
+ SequenceClassifierOutputWithPast,
37
+ TokenClassifierOutput,
38
+ )
39
+ from ...modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
40
+ from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
41
+ from ...processing_utils import Unpack
42
+ from ...utils import LossKwargs, auto_docstring, can_return_tuple, logging
43
+ from .configuration_gemma import GemmaConfig
44
+
45
+
46
+ logger = logging.get_logger(__name__)
47
+
48
+
49
+ class GemmaRMSNorm(nn.Module):
50
+ def __init__(self, dim: int, eps: float = 1e-6, cond_dim: Optional[int] = None):
51
+ super().__init__()
52
+ self.eps = eps
53
+ self.dim = dim
54
+ self.cond_dim = cond_dim
55
+
56
+ # Dense layer for adaptive normalization (if cond_dim is provided)
57
+ if cond_dim is not None:
58
+ #self.dense = nn.Linear(cond_dim, dim * 3, bias=True, dtype=torch.bfloat16)
59
+ self.dense = nn.Linear(cond_dim, dim * 3, bias=True)
60
+ # Initialize with zeros (matches source implementation)
61
+ nn.init.zeros_(self.dense.weight)
62
+ else:
63
+ self.weight = nn.Parameter(torch.zeros(dim, dtype=torch.bfloat16))
64
+ self.dense = None
65
+
66
+ def _norm(self, x):
67
+ # Compute variance in float32 (like the source implementation)
68
+ var = torch.mean(torch.square(x.float()), dim=-1, keepdim=True)
69
+ # Compute normalization in float32
70
+ normed_inputs = x * torch.rsqrt(var + self.eps)
71
+ return normed_inputs
72
+
73
+ def forward(self, x, cond=None):
74
+ dtype = x.dtype # original dtype, could be half-precision
75
+ normed_inputs = self._norm(x)
76
+
77
+ if cond is None or self.dense is None:
78
+ # regular RMSNorm
79
+ # scale by learned parameter in float32 (matches source implementation)
80
+ normed_inputs = normed_inputs * (1.0 + self.weight.float())
81
+ return normed_inputs.to(dtype), None # return in original dtype with None gate
82
+
83
+ # adaptive RMSNorm (if cond is provided and dense layer exists)
84
+ if cond.shape[-1] != self.cond_dim:
85
+ raise ValueError(f"Expected cond dimension {self.cond_dim}, got {cond.shape[-1]}")
86
+
87
+ #self.dense.to(dtype=torch.bfloat16).to(dtype=torch.float32)
88
+ modulation = self.dense(cond)
89
+ # Reshape modulation to broadcast properly: [batch, 1, features] for [batch, seq, features]
90
+ if len(x.shape) == 3: # [batch, seq, features]
91
+ modulation = modulation.unsqueeze(1)
92
+
93
+ scale, shift, gate = torch.chunk(modulation, 3, dim=-1)
94
+
95
+ # Apply adaptive normalization: use model weight dtype to ensure compatibility
96
+ # model_dtype = self.dense.weight.dtype # Use the model's dtype (bfloat16)
97
+ # scale = scale.to(model_dtype)
98
+ # shift = shift.to(model_dtype)
99
+ # gate = gate.to(model_dtype)
100
+ # normed_inputs = normed_inputs.to(model_dtype) # Convert normed_inputs to model dtype
101
+
102
+ normed_inputs = normed_inputs * (1 + scale.to(torch.float32)) + shift.to(torch.float32)
103
+
104
+ return normed_inputs.to(dtype), gate.to(dtype)
105
+
106
+ def extra_repr(self):
107
+ repr_str = f"{tuple(self.weight.shape)}, eps={self.eps}"
108
+ if self.dense is not None:
109
+ repr_str += f", adaptive=True, cond_dim={self.cond_dim}"
110
+ return repr_str
111
+
112
+
113
+ class GemmaMLP(nn.Module):
114
+ def __init__(self, config):
115
+ super().__init__()
116
+ self.config = config
117
+ self.hidden_size = config.hidden_size
118
+ self.intermediate_size = config.intermediate_size
119
+ self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
120
+ self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
121
+ self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
122
+ self.act_fn = ACT2FN[config.hidden_act]
123
+
124
+ def forward(self, x):
125
+ down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
126
+ return down_proj
127
+
128
+
129
+ class GemmaRotaryEmbedding(nn.Module):
130
+ def __init__(self, config: GemmaConfig, device=None):
131
+ super().__init__()
132
+ # BC: "rope_type" was originally "type"
133
+ if hasattr(config, "rope_scaling") and config.rope_scaling is not None:
134
+ self.rope_type = config.rope_scaling.get("rope_type", config.rope_scaling.get("type"))
135
+ else:
136
+ self.rope_type = "default"
137
+ self.max_seq_len_cached = config.max_position_embeddings
138
+ self.original_max_seq_len = config.max_position_embeddings
139
+
140
+ self.config = config
141
+ self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
142
+
143
+ inv_freq, self.attention_scaling = self.rope_init_fn(self.config, device)
144
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
145
+ self.original_inv_freq = self.inv_freq
146
+
147
+ @torch.no_grad()
148
+ @dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
149
+ def forward(self, x, position_ids):
150
+ inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
151
+ position_ids_expanded = position_ids[:, None, :].float()
152
+
153
+ device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
154
+ with torch.autocast(device_type=device_type, enabled=False): # Force float32
155
+ freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
156
+ emb = torch.cat((freqs, freqs), dim=-1)
157
+ cos = emb.cos() * self.attention_scaling
158
+ sin = emb.sin() * self.attention_scaling
159
+
160
+ return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
161
+
162
+
163
+ def rotate_half(x):
164
+ """Rotates half the hidden dims of the input."""
165
+ x1 = x[..., : x.shape[-1] // 2]
166
+ x2 = x[..., x.shape[-1] // 2 :]
167
+ return torch.cat((-x2, x1), dim=-1)
168
+
169
+
170
+ def apply_rotary_pos_emb(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
171
+ """Applies Rotary Position Embedding to the query and key tensors.
172
+
173
+ Args:
174
+ q (`torch.Tensor`): The query tensor.
175
+ k (`torch.Tensor`): The key tensor.
176
+ cos (`torch.Tensor`): The cosine part of the rotary embedding.
177
+ sin (`torch.Tensor`): The sine part of the rotary embedding.
178
+ position_ids (`torch.Tensor`, *optional*):
179
+ Deprecated and unused.
180
+ unsqueeze_dim (`int`, *optional*, defaults to 1):
181
+ The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
182
+ sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
183
+ that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
184
+ k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
185
+ cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
186
+ the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
187
+ Returns:
188
+ `tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
189
+ """
190
+ cos = cos.unsqueeze(unsqueeze_dim)
191
+ sin = sin.unsqueeze(unsqueeze_dim)
192
+ q_embed = (q * cos) + (rotate_half(q) * sin)
193
+ k_embed = (k * cos) + (rotate_half(k) * sin)
194
+ return q_embed, k_embed
195
+
196
+
197
+ def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
198
+ """
199
+ This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
200
+ num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
201
+ """
202
+ batch, num_key_value_heads, slen, head_dim = hidden_states.shape
203
+ if n_rep == 1:
204
+ return hidden_states
205
+ hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
206
+ return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
207
+
208
+
209
+ def _gated_residual(x, y, gate):
210
+ """
211
+ Applies gated residual connection with optional gate parameter.
212
+
213
+ Args:
214
+ x: Input tensor (residual)
215
+ y: Output tensor to be added
216
+ gate: Optional gate tensor to modulate the addition
217
+
218
+ Returns:
219
+ x + y if gate is None, otherwise x + y * gate
220
+ """
221
+ if x is None and y is None:
222
+ return None
223
+ if x is None or y is None:
224
+ return x if x is not None else y
225
+ if gate is None:
226
+ return x + y
227
+ return x + y * gate
228
+
229
+
230
+ def eager_attention_forward(
231
+ module: nn.Module,
232
+ query: torch.Tensor,
233
+ key: torch.Tensor,
234
+ value: torch.Tensor,
235
+ attention_mask: Optional[torch.Tensor],
236
+ scaling: float,
237
+ dropout: float = 0.0,
238
+ **kwargs,
239
+ ):
240
+ key_states = repeat_kv(key, module.num_key_value_groups)
241
+ value_states = repeat_kv(value, module.num_key_value_groups)
242
+
243
+ attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
244
+ if attention_mask is not None:
245
+ causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
246
+ attn_weights = attn_weights + causal_mask
247
+
248
+ attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
249
+ attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
250
+ attn_output = torch.matmul(attn_weights, value_states)
251
+ attn_output = attn_output.transpose(1, 2).contiguous()
252
+
253
+ return attn_output, attn_weights
254
+
255
+
256
+ class GemmaAttention(nn.Module):
257
+ """Multi-headed attention from 'Attention Is All You Need' paper"""
258
+
259
+ def __init__(self, config: GemmaConfig, layer_idx: int):
260
+ super().__init__()
261
+ self.config = config
262
+ self.layer_idx = layer_idx
263
+ self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
264
+ self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
265
+ self.scaling = self.head_dim**-0.5
266
+ self.attention_dropout = config.attention_dropout
267
+ self.is_causal = True
268
+
269
+ self.q_proj = nn.Linear(
270
+ config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias
271
+ )
272
+ self.k_proj = nn.Linear(
273
+ config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
274
+ )
275
+ self.v_proj = nn.Linear(
276
+ config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
277
+ )
278
+ self.o_proj = nn.Linear(
279
+ config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias
280
+ )
281
+
282
+ def forward(
283
+ self,
284
+ hidden_states: torch.Tensor,
285
+ position_embeddings: tuple[torch.Tensor, torch.Tensor],
286
+ attention_mask: Optional[torch.Tensor],
287
+ past_key_value: Optional[Cache] = None,
288
+ cache_position: Optional[torch.LongTensor] = None,
289
+ use_cache: bool = False,
290
+ **kwargs: Unpack[FlashAttentionKwargs],
291
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor], Optional[tuple[torch.Tensor]]]:
292
+ input_shape = hidden_states.shape[:-1]
293
+ hidden_shape = (*input_shape, -1, self.head_dim)
294
+
295
+ query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
296
+ key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
297
+ value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
298
+
299
+ cos, sin = position_embeddings
300
+ query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
301
+
302
+ # Use cache if provided
303
+ if past_key_value is not None:
304
+ if use_cache:
305
+ # sin and cos are specific to RoPE models; cache_position needed for the static cache
306
+ cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
307
+ key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
308
+ else:
309
+ key_states = torch.cat([past_key_value[self.layer_idx][0], key_states], dim=2)
310
+ value_states = torch.cat([past_key_value[self.layer_idx][1], value_states], dim=2)
311
+
312
+ attention_interface: Callable = eager_attention_forward
313
+ if self.config._attn_implementation != "eager":
314
+ attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]
315
+
316
+ attn_output, attn_weights = attention_interface(
317
+ self,
318
+ query_states,
319
+ key_states,
320
+ value_states,
321
+ attention_mask,
322
+ dropout=0.0 if not self.training else self.attention_dropout,
323
+ scaling=self.scaling,
324
+ **kwargs,
325
+ )
326
+
327
+ attn_output = attn_output.reshape(*input_shape, -1).contiguous()
328
+ attn_output = self.o_proj(attn_output)
329
+ return attn_output, attn_weights
330
+
331
+
332
+ class GemmaDecoderLayer(GradientCheckpointingLayer):
333
+ def __init__(self, config: GemmaConfig, layer_idx: int):
334
+ super().__init__()
335
+ self.hidden_size = config.hidden_size
336
+
337
+ self.self_attn = GemmaAttention(config=config, layer_idx=layer_idx)
338
+
339
+ self.mlp = GemmaMLP(config)
340
+ cond_dim = getattr(config, 'adarms_cond_dim', None) if getattr(config, 'use_adarms', False) else None
341
+ self.input_layernorm = GemmaRMSNorm(config.hidden_size, eps=config.rms_norm_eps, cond_dim=cond_dim)
342
+ self.post_attention_layernorm = GemmaRMSNorm(config.hidden_size, eps=config.rms_norm_eps, cond_dim=cond_dim)
343
+
344
+ def forward(
345
+ self,
346
+ hidden_states: torch.Tensor,
347
+ attention_mask: Optional[torch.Tensor] = None,
348
+ position_ids: Optional[torch.LongTensor] = None,
349
+ past_key_value: Optional[Cache] = None,
350
+ output_attentions: Optional[bool] = False,
351
+ use_cache: Optional[bool] = False,
352
+ cache_position: Optional[torch.LongTensor] = None,
353
+ position_embeddings: Optional[tuple[torch.Tensor, torch.Tensor]] = None, # necessary, but kept here for BC
354
+ adarms_cond: Optional[torch.Tensor] = None,
355
+ **kwargs: Unpack[FlashAttentionKwargs],
356
+ ) -> tuple[torch.FloatTensor, Optional[tuple[torch.FloatTensor, torch.FloatTensor]]]:
357
+ residual = hidden_states
358
+ hidden_states, gate = self.input_layernorm(hidden_states, adarms_cond)
359
+
360
+ # Self Attention
361
+ hidden_states, self_attn_weights = self.self_attn(
362
+ hidden_states=hidden_states,
363
+ attention_mask=attention_mask,
364
+ position_ids=position_ids,
365
+ past_key_value=past_key_value,
366
+ output_attentions=output_attentions,
367
+ use_cache=use_cache,
368
+ cache_position=cache_position,
369
+ position_embeddings=position_embeddings,
370
+ **kwargs,
371
+ )
372
+ hidden_states = _gated_residual(residual, hidden_states, gate)
373
+
374
+ # Fully Connected
375
+ residual = hidden_states
376
+ hidden_states, gate = self.post_attention_layernorm(hidden_states, adarms_cond)
377
+ hidden_states = self.mlp(hidden_states)
378
+ hidden_states = _gated_residual(residual, hidden_states, gate)
379
+
380
+ outputs = (hidden_states,)
381
+ if output_attentions:
382
+ outputs += (self_attn_weights,)
383
+
384
+ return outputs
385
+
386
+
387
+ @auto_docstring
388
+ class GemmaPreTrainedModel(PreTrainedModel):
389
+ config_class = GemmaConfig
390
+ base_model_prefix = "model"
391
+ supports_gradient_checkpointing = True
392
+ _no_split_modules = ["GemmaDecoderLayer"]
393
+ _skip_keys_device_placement = ["past_key_values"]
394
+ _supports_flash_attn_3 = True
395
+ _supports_flash_attn_2 = True
396
+ _supports_sdpa = True
397
+ _supports_flex_attn = True
398
+ _supports_cache_class = True
399
+ _supports_quantized_cache = True
400
+ _supports_static_cache = True
401
+ _supports_attention_backend = True
402
+
403
+ def _init_weights(self, module):
404
+ std = self.config.initializer_range
405
+ if isinstance(module, nn.Linear):
406
+ module.weight.data.normal_(mean=0.0, std=std)
407
+ if module.bias is not None:
408
+ module.bias.data.zero_()
409
+ elif isinstance(module, nn.Embedding):
410
+ module.weight.data.normal_(mean=0.0, std=std)
411
+ if module.padding_idx is not None:
412
+ module.weight.data[module.padding_idx].zero_()
413
+ elif isinstance(module, GemmaRMSNorm):
414
+ if hasattr(module, 'weight'):
415
+ module.weight.data.fill_(1.0)
416
+
417
+
418
+ @auto_docstring
419
+ class GemmaModel(GemmaPreTrainedModel):
420
+ def __init__(self, config: GemmaConfig):
421
+ super().__init__(config)
422
+ self.padding_idx = config.pad_token_id
423
+ self.vocab_size = config.vocab_size
424
+
425
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
426
+ self.layers = nn.ModuleList(
427
+ [GemmaDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
428
+ )
429
+
430
+ cond_dim = getattr(config, 'adarms_cond_dim', None) if getattr(config, 'use_adarms', False) else None
431
+ self.norm = GemmaRMSNorm(config.hidden_size, eps=config.rms_norm_eps, cond_dim=cond_dim)
432
+ self.rotary_emb = GemmaRotaryEmbedding(config=config)
433
+ self.gradient_checkpointing = False
434
+
435
+ # Initialize weights and apply final processing
436
+ self.post_init()
437
+
438
+ def get_input_embeddings(self):
439
+ return self.embed_tokens
440
+
441
+ def set_input_embeddings(self, value):
442
+ self.embed_tokens = value
443
+
444
+ @can_return_tuple
445
+ @auto_docstring
446
+ def forward(
447
+ self,
448
+ input_ids: Optional[torch.LongTensor] = None,
449
+ attention_mask: Optional[torch.Tensor] = None,
450
+ position_ids: Optional[torch.LongTensor] = None,
451
+ past_key_values: Optional[Cache] = None,
452
+ inputs_embeds: Optional[torch.FloatTensor] = None,
453
+ use_cache: Optional[bool] = None,
454
+ output_attentions: Optional[bool] = None,
455
+ output_hidden_states: Optional[bool] = None,
456
+ cache_position: Optional[torch.LongTensor] = None,
457
+ adarms_cond: Optional[torch.Tensor] = None,
458
+ **kwargs: Unpack[FlashAttentionKwargs],
459
+ ) -> BaseModelOutputWithPast:
460
+ """
461
+ adarms_cond (`torch.Tensor` of shape `(batch_size, cond_dim)`, *optional*):
462
+ Condition for ADARMS.
463
+ """
464
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
465
+ output_hidden_states = (
466
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
467
+ )
468
+ use_cache = use_cache if use_cache is not None else self.config.use_cache
469
+
470
+ if (input_ids is None) ^ (inputs_embeds is not None):
471
+ raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
472
+
473
+ if self.gradient_checkpointing and self.training and use_cache:
474
+ logger.warning_once(
475
+ "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`."
476
+ )
477
+ use_cache = False
478
+
479
+ if inputs_embeds is None:
480
+ inputs_embeds = self.embed_tokens(input_ids)
481
+
482
+ if use_cache and past_key_values is None:
483
+ past_key_values = DynamicCache()
484
+
485
+ if cache_position is None:
486
+ past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
487
+ cache_position = torch.arange(
488
+ past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device
489
+ )
490
+
491
+ if position_ids is None:
492
+ position_ids = cache_position.unsqueeze(0)
493
+
494
+ causal_mask = create_causal_mask(
495
+ config=self.config,
496
+ input_embeds=inputs_embeds,
497
+ attention_mask=attention_mask,
498
+ cache_position=cache_position,
499
+ past_key_values=past_key_values,
500
+ position_ids=position_ids,
501
+ )
502
+
503
+ # embed positions
504
+ hidden_states = inputs_embeds
505
+ # Convert to bfloat16 if the first layer uses bfloat16
506
+ if len(self.layers) > 0 and self.layers[0].self_attn.q_proj.weight.dtype == torch.bfloat16:
507
+ hidden_states = hidden_states.to(torch.bfloat16)
508
+
509
+ # create position embeddings to be shared across the decoder layers
510
+ position_embeddings = self.rotary_emb(hidden_states, position_ids)
511
+
512
+ # normalized
513
+ # Gemma downcasts the below to float16, causing sqrt(3072)=55.4256 to become 55.5
514
+ # See https://github.com/huggingface/transformers/pull/29402
515
+ normalizer = torch.tensor(self.config.hidden_size**0.5, dtype=hidden_states.dtype)
516
+ #hidden_states = hidden_states * normalizer
517
+
518
+ # decoder layers
519
+ all_hidden_states = () if output_hidden_states else None
520
+ all_self_attns = () if output_attentions else None
521
+
522
+ for decoder_layer in self.layers[: self.config.num_hidden_layers]:
523
+ if output_hidden_states:
524
+ all_hidden_states += (hidden_states,)
525
+
526
+ layer_outputs = decoder_layer(
527
+ hidden_states,
528
+ attention_mask=causal_mask,
529
+ position_ids=position_ids,
530
+ past_key_value=past_key_values,
531
+ output_attentions=output_attentions,
532
+ use_cache=use_cache,
533
+ cache_position=cache_position,
534
+ position_embeddings=position_embeddings,
535
+ adarms_cond=adarms_cond,
536
+ **kwargs,
537
+ )
538
+
539
+ hidden_states = layer_outputs[0]
540
+
541
+ if output_attentions:
542
+ all_self_attns += (layer_outputs[1],)
543
+
544
+ hidden_states, _ = self.norm(hidden_states, adarms_cond)
545
+
546
+ # add hidden states from the last decoder layer
547
+ if output_hidden_states:
548
+ all_hidden_states += (hidden_states,)
549
+
550
+ return BaseModelOutputWithPast(
551
+ last_hidden_state=hidden_states,
552
+ past_key_values=past_key_values if use_cache else None,
553
+ hidden_states=all_hidden_states,
554
+ attentions=all_self_attns,
555
+ )
556
+
557
+
558
+ class KwargsForCausalLM(FlashAttentionKwargs, LossKwargs): ...
559
+
560
+
561
+ @auto_docstring
562
+ class GemmaForCausalLM(GemmaPreTrainedModel, GenerationMixin):
563
+ _tied_weights_keys = ["lm_head.weight"]
564
+ _tp_plan = {"lm_head": "colwise_rep"}
565
+ _pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
566
+
567
+ def __init__(self, config):
568
+ super().__init__(config)
569
+ self.model = GemmaModel(config)
570
+ self.vocab_size = config.vocab_size
571
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
572
+
573
+ # Initialize weights and apply final processing
574
+ self.post_init()
575
+
576
+ def get_input_embeddings(self):
577
+ return self.model.embed_tokens
578
+
579
+ def set_input_embeddings(self, value):
580
+ self.model.embed_tokens = value
581
+
582
+ def get_output_embeddings(self):
583
+ return self.lm_head
584
+
585
+ def set_output_embeddings(self, new_embeddings):
586
+ self.lm_head = new_embeddings
587
+
588
+ def set_decoder(self, decoder):
589
+ self.model = decoder
590
+
591
+ def get_decoder(self):
592
+ return self.model
593
+
594
+ @can_return_tuple
595
+ @auto_docstring
596
+ def forward(
597
+ self,
598
+ input_ids: Optional[torch.LongTensor] = None,
599
+ attention_mask: Optional[torch.Tensor] = None,
600
+ position_ids: Optional[torch.LongTensor] = None,
601
+ past_key_values: Optional[Cache] = None,
602
+ inputs_embeds: Optional[torch.FloatTensor] = None,
603
+ labels: Optional[torch.LongTensor] = None,
604
+ use_cache: Optional[bool] = None,
605
+ output_attentions: Optional[bool] = None,
606
+ output_hidden_states: Optional[bool] = None,
607
+ cache_position: Optional[torch.LongTensor] = None,
608
+ logits_to_keep: Union[int, torch.Tensor] = 0,
609
+ adarms_cond: Optional[torch.Tensor] = None,
610
+ **kwargs: Unpack[KwargsForCausalLM],
611
+ ) -> CausalLMOutputWithPast:
612
+ r"""
613
+ labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
614
+ Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
615
+ config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
616
+ (masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
617
+
618
+ adarms_cond (`torch.Tensor` of shape `(batch_size, cond_dim)`, *optional*):
619
+ Condition for ADARMS.
620
+
621
+ Example:
622
+
623
+ ```python
624
+ >>> from transformers import AutoTokenizer, GemmaForCausalLM
625
+
626
+ >>> model = GemmaForCausalLM.from_pretrained("google/gemma-7b")
627
+ >>> tokenizer = AutoTokenizer.from_pretrained("google/gemma-7b")
628
+
629
+ >>> prompt = "What is your favorite condiment?"
630
+ >>> inputs = tokenizer(prompt, return_tensors="pt")
631
+
632
+ >>> # Generate
633
+ >>> generate_ids = model.generate(inputs.input_ids, max_length=30)
634
+ >>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
635
+ "What is your favorite condiment?"
636
+ ```"""
637
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
638
+ output_hidden_states = (
639
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
640
+ )
641
+
642
+ # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
643
+ outputs: BaseModelOutputWithPast = self.model(
644
+ input_ids=input_ids,
645
+ attention_mask=attention_mask,
646
+ position_ids=position_ids,
647
+ past_key_values=past_key_values,
648
+ inputs_embeds=inputs_embeds,
649
+ use_cache=use_cache,
650
+ output_attentions=output_attentions,
651
+ output_hidden_states=output_hidden_states,
652
+ cache_position=cache_position,
653
+ adarms_cond=adarms_cond,
654
+ **kwargs,
655
+ )
656
+
657
+ hidden_states = outputs.last_hidden_state
658
+ # Only compute necessary logits, and do not upcast them to float if we are not computing the loss
659
+ slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
660
+ logits = self.lm_head(hidden_states[:, slice_indices, :])
661
+
662
+ loss = None
663
+ if labels is not None:
664
+ loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs)
665
+
666
+ return CausalLMOutputWithPast(
667
+ loss=loss,
668
+ logits=logits,
669
+ past_key_values=outputs.past_key_values,
670
+ hidden_states=outputs.hidden_states,
671
+ attentions=outputs.attentions,
672
+ )
673
+
674
+
675
+ @auto_docstring(
676
+ custom_intro="""
677
+ The Gemma Model transformer with a sequence classification head on top (linear layer).
678
+
679
+ [`GemmaForSequenceClassification`] uses the last token in order to do the classification, as other causal models
680
+ (e.g. GPT-2) do.
681
+
682
+ Since it does classification on the last token, it requires to know the position of the last token. If a
683
+ `pad_token_id` is defined in the configuration, it finds the last token that is not a padding token in each row. If
684
+ no `pad_token_id` is defined, it simply takes the last value in each row of the batch. Since it cannot guess the
685
+ padding tokens when `inputs_embeds` are passed instead of `input_ids`, it does the same (take the last value in
686
+ each row of the batch).
687
+ """
688
+ )
689
+ class GemmaForSequenceClassification(GemmaPreTrainedModel):
690
+ def __init__(self, config):
691
+ super().__init__(config)
692
+ self.num_labels = config.num_labels
693
+ self.model = GemmaModel(config)
694
+ self.score = nn.Linear(config.hidden_size, self.num_labels, bias=False)
695
+
696
+ # Initialize weights and apply final processing
697
+ self.post_init()
698
+
699
+ def get_input_embeddings(self):
700
+ return self.model.embed_tokens
701
+
702
+ def set_input_embeddings(self, value):
703
+ self.model.embed_tokens = value
704
+
705
+ @can_return_tuple
706
+ @auto_docstring
707
+ def forward(
708
+ self,
709
+ input_ids: Optional[torch.LongTensor] = None,
710
+ attention_mask: Optional[torch.Tensor] = None,
711
+ position_ids: Optional[torch.LongTensor] = None,
712
+ past_key_values: Optional[Cache] = None,
713
+ inputs_embeds: Optional[torch.FloatTensor] = None,
714
+ labels: Optional[torch.LongTensor] = None,
715
+ use_cache: Optional[bool] = None,
716
+ output_attentions: Optional[bool] = None,
717
+ output_hidden_states: Optional[bool] = None,
718
+ adarms_cond: Optional[torch.Tensor] = None,
719
+ ) -> SequenceClassifierOutputWithPast:
720
+ r"""
721
+ labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
722
+ Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
723
+ config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
724
+ `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
725
+
726
+ adarms_cond (`torch.Tensor` of shape `(batch_size, cond_dim)`, *optional*):
727
+ Condition for ADARMS.
728
+ """
729
+
730
+ transformer_outputs: BaseModelOutputWithPast = self.model(
731
+ input_ids,
732
+ attention_mask=attention_mask,
733
+ position_ids=position_ids,
734
+ past_key_values=past_key_values,
735
+ inputs_embeds=inputs_embeds,
736
+ use_cache=use_cache,
737
+ output_attentions=output_attentions,
738
+ output_hidden_states=output_hidden_states,
739
+ adarms_cond=adarms_cond,
740
+ )
741
+ hidden_states = transformer_outputs.last_hidden_state
742
+ logits = self.score(hidden_states)
743
+
744
+ if input_ids is not None:
745
+ batch_size = input_ids.shape[0]
746
+ else:
747
+ batch_size = inputs_embeds.shape[0]
748
+
749
+ if self.config.pad_token_id is None and batch_size != 1:
750
+ raise ValueError("Cannot handle batch sizes > 1 if no padding token is defined.")
751
+ if self.config.pad_token_id is None:
752
+ last_non_pad_token = -1
753
+ elif input_ids is not None:
754
+ # To handle both left- and right- padding, we take the rightmost token that is not equal to pad_token_id
755
+ non_pad_mask = (input_ids != self.config.pad_token_id).to(logits.device, torch.int32)
756
+ token_indices = torch.arange(input_ids.shape[-1], device=logits.device, dtype=torch.int32)
757
+ last_non_pad_token = (token_indices * non_pad_mask).argmax(-1)
758
+ else:
759
+ last_non_pad_token = -1
760
+ logger.warning_once(
761
+ f"{self.__class__.__name__} will not detect padding tokens in `inputs_embeds`. Results may be "
762
+ "unexpected if using padding tokens in conjunction with `inputs_embeds.`"
763
+ )
764
+
765
+ pooled_logits = logits[torch.arange(batch_size, device=logits.device), last_non_pad_token]
766
+
767
+ loss = None
768
+ if labels is not None:
769
+ loss = self.loss_function(logits=logits, labels=labels, pooled_logits=pooled_logits, config=self.config)
770
+
771
+ return SequenceClassifierOutputWithPast(
772
+ loss=loss,
773
+ logits=pooled_logits,
774
+ past_key_values=transformer_outputs.past_key_values,
775
+ hidden_states=transformer_outputs.hidden_states,
776
+ attentions=transformer_outputs.attentions,
777
+ )
778
+
779
+
780
+ @auto_docstring
781
+ class GemmaForTokenClassification(GemmaPreTrainedModel):
782
+ def __init__(self, config):
783
+ super().__init__(config)
784
+ self.num_labels = config.num_labels
785
+ self.model = GemmaModel(config)
786
+ if getattr(config, "classifier_dropout", None) is not None:
787
+ classifier_dropout = config.classifier_dropout
788
+ elif getattr(config, "hidden_dropout", None) is not None:
789
+ classifier_dropout = config.hidden_dropout
790
+ else:
791
+ classifier_dropout = 0.1
792
+ self.dropout = nn.Dropout(classifier_dropout)
793
+ self.score = nn.Linear(config.hidden_size, config.num_labels)
794
+
795
+ # Initialize weights and apply final processing
796
+ self.post_init()
797
+
798
+ def get_input_embeddings(self):
799
+ return self.model.embed_tokens
800
+
801
+ def set_input_embeddings(self, value):
802
+ self.model.embed_tokens = value
803
+
804
+ @can_return_tuple
805
+ @auto_docstring
806
+ def forward(
807
+ self,
808
+ input_ids: Optional[torch.LongTensor] = None,
809
+ attention_mask: Optional[torch.Tensor] = None,
810
+ position_ids: Optional[torch.LongTensor] = None,
811
+ past_key_values: Optional[Cache] = None,
812
+ inputs_embeds: Optional[torch.FloatTensor] = None,
813
+ labels: Optional[torch.LongTensor] = None,
814
+ use_cache: Optional[bool] = None,
815
+ output_attentions: Optional[bool] = None,
816
+ output_hidden_states: Optional[bool] = None,
817
+ adarms_cond: Optional[torch.Tensor] = None,
818
+ ) -> TokenClassifierOutput:
819
+ r"""
820
+ labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
821
+ Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
822
+ config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
823
+ `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
824
+
825
+ adarms_cond (`torch.Tensor` of shape `(batch_size, cond_dim)`, *optional*):
826
+ Condition for ADARMS.
827
+ """
828
+
829
+ outputs: BaseModelOutputWithPast = self.model(
830
+ input_ids,
831
+ attention_mask=attention_mask,
832
+ position_ids=position_ids,
833
+ past_key_values=past_key_values,
834
+ inputs_embeds=inputs_embeds,
835
+ use_cache=use_cache,
836
+ output_attentions=output_attentions,
837
+ output_hidden_states=output_hidden_states,
838
+ adarms_cond=adarms_cond,
839
+ )
840
+ sequence_output = outputs.last_hidden_state
841
+ sequence_output = self.dropout(sequence_output)
842
+ logits = self.score(sequence_output)
843
+
844
+ loss = None
845
+ if labels is not None:
846
+ loss = self.loss_function(logits, labels, self.config)
847
+
848
+ return TokenClassifierOutput(
849
+ loss=loss,
850
+ logits=logits,
851
+ hidden_states=outputs.hidden_states,
852
+ attentions=outputs.attentions,
853
+ )
854
+
855
+
856
+ __all__ = [
857
+ "GemmaModel",
858
+ "GemmaForCausalLM",
859
+ "GemmaForSequenceClassification",
860
+ "GemmaForTokenClassification",
861
+ "GemmaPreTrainedModel",
862
+ ]
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/paligemma/modeling_paligemma.py ADDED
@@ -0,0 +1,622 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2024 the HuggingFace Inc. team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """PyTorch PaliGemmamodel."""
16
+
17
+ from dataclasses import dataclass
18
+ from typing import Optional, Union
19
+
20
+ import torch
21
+ import torch.utils.checkpoint
22
+ from torch import nn
23
+
24
+ from ...cache_utils import Cache, HybridCache, StaticCache
25
+ from ...generation import GenerationMixin
26
+ from ...modeling_flash_attention_utils import FlashAttentionKwargs
27
+ from ...modeling_outputs import BaseModelOutputWithPast
28
+ from ...modeling_utils import PreTrainedModel
29
+ from ...processing_utils import Unpack
30
+ from ...utils import LossKwargs, ModelOutput, auto_docstring, can_return_tuple, is_torchdynamo_compiling, logging
31
+ from ..auto import AutoModel
32
+ from .configuration_paligemma import PaliGemmaConfig
33
+
34
+
35
+ logger = logging.get_logger(__name__)
36
+
37
+
38
+ @dataclass
39
+ @auto_docstring(
40
+ custom_intro="""
41
+ Base class for Paligemma outputs, with hidden states and attentions.
42
+ """
43
+ )
44
+ class PaligemmaModelOutputWithPast(BaseModelOutputWithPast):
45
+ r"""
46
+ past_key_values (`tuple(tuple(torch.FloatTensor))`, *optional*, returned when `use_cache=True` is passed or when `config.use_cache=True`):
47
+ Tuple of `tuple(torch.FloatTensor)` of length `config.n_layers`, with each tuple having 2 tensors of shape
48
+ `(batch_size, num_heads, sequence_length, embed_size_per_head)`)
49
+
50
+ Contains pre-computed hidden-states (key and values in the self-attention blocks) that can be used (see
51
+ `past_key_values` input) to speed up sequential decoding.
52
+ image_hidden_states (`torch.FloatTensor`, *optional*):
53
+ A `torch.FloatTensor` of size `(batch_size, num_images, sequence_length, hidden_size)`.
54
+ image_hidden_states of the model produced by the vision encoder and after projecting the last hidden state.
55
+ """
56
+
57
+ image_hidden_states: Optional[torch.FloatTensor] = None
58
+
59
+
60
+ @dataclass
61
+ @auto_docstring(
62
+ custom_intro="""
63
+ Base class for PaliGemma causal language model (or autoregressive) outputs.
64
+ """
65
+ )
66
+ class PaliGemmaCausalLMOutputWithPast(ModelOutput):
67
+ r"""
68
+ loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` is provided):
69
+ Language modeling loss (for next-token prediction).
70
+ logits (`torch.FloatTensor` of shape `(batch_size, sequence_length, config.text_config.vocab_size)`):
71
+ Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
72
+ past_key_values (`tuple(tuple(torch.FloatTensor))`, *optional*, returned when `use_cache=True` is passed or when `config.use_cache=True`):
73
+ Tuple of `tuple(torch.FloatTensor)` of length `config.n_layers`, with each tuple having 2 tensors of shape
74
+ `(batch_size, num_heads, sequence_length, embed_size_per_head)`)
75
+
76
+ Contains pre-computed hidden-states (key and values in the self-attention blocks) that can be used (see
77
+ `past_key_values` input) to speed up sequential decoding.
78
+ image_hidden_states (`torch.FloatTensor`, *optional*):
79
+ A `torch.FloatTensor` of size `(batch_size, num_images, sequence_length, hidden_size)`.
80
+ image_hidden_states of the model produced by the vision encoder after projecting last hidden state.
81
+ """
82
+
83
+ loss: Optional[torch.FloatTensor] = None
84
+ logits: Optional[torch.FloatTensor] = None
85
+ past_key_values: Optional[Union[list[torch.FloatTensor], Cache]] = None
86
+ hidden_states: Optional[tuple[torch.FloatTensor]] = None
87
+ attentions: Optional[tuple[torch.FloatTensor]] = None
88
+ image_hidden_states: Optional[torch.FloatTensor] = None
89
+
90
+
91
+ class PaliGemmaMultiModalProjector(nn.Module):
92
+ def __init__(self, config: PaliGemmaConfig):
93
+ super().__init__()
94
+ self.linear = nn.Linear(config.vision_config.hidden_size, config.vision_config.projection_dim, bias=True)
95
+
96
+ def forward(self, image_features):
97
+ hidden_states = self.linear(image_features)
98
+
99
+ return hidden_states
100
+
101
+
102
+ @auto_docstring
103
+ class PaliGemmaPreTrainedModel(PreTrainedModel):
104
+ config_class = PaliGemmaConfig
105
+ base_model_prefix = ""
106
+ supports_gradient_checkpointing = True
107
+ _no_split_modules = ["PaliGemmaMultiModalProjector"]
108
+ _skip_keys_device_placement = "past_key_values"
109
+ _supports_cache_class = True
110
+ _supports_quantized_cache = True
111
+ _supports_static_cache = True
112
+ _supports_flash_attn_2 = True
113
+ _supports_sdpa = True
114
+ _supports_flex_attn = True
115
+ _supports_attention_backend = True
116
+
117
+ def _init_weights(self, module):
118
+ # important: this ported version of PaliGemmaisn't meant for training from scratch - only
119
+ # inference and fine-tuning
120
+ std = getattr(self.config, "initializer_range", self.config.get_text_config().initializer_range)
121
+
122
+ if isinstance(module, nn.Linear):
123
+ module.weight.data.normal_(mean=0.0, std=std)
124
+ if module.bias is not None:
125
+ module.bias.data.zero_()
126
+
127
+
128
+ @auto_docstring(
129
+ custom_intro="""
130
+ The Base Paligemma model which consists of a vision backbone and a language model withou language modeling head.,
131
+ """
132
+ )
133
+ class PaliGemmaModel(PaliGemmaPreTrainedModel):
134
+ _checkpoint_conversion_mapping = {"language_model.model": "language_model"}
135
+ # we are filtering the logits/labels so we shouldn't divide the loss based on num_items_in_batch
136
+ accepts_loss_kwargs = False
137
+
138
+ def __init__(self, config: PaliGemmaConfig):
139
+ super().__init__(config)
140
+ self.vision_tower = AutoModel.from_config(config=config.vision_config)
141
+ self.multi_modal_projector = PaliGemmaMultiModalProjector(config)
142
+ self.vocab_size = config.text_config.vocab_size
143
+
144
+ language_model = AutoModel.from_config(config=config.text_config)
145
+ self.language_model = language_model
146
+
147
+ self.pad_token_id = self.config.pad_token_id if self.config.pad_token_id is not None else -1
148
+ self.post_init()
149
+
150
+ # Copied from transformers.models.llava.modeling_llava.LlavaModel.get_input_embeddings with Llava->PaliGemma
151
+ def get_input_embeddings(self):
152
+ return self.language_model.get_input_embeddings()
153
+
154
+ # Copied from transformers.models.llava.modeling_llava.LlavaModel.set_input_embeddings with Llava->PaliGemma
155
+ def set_input_embeddings(self, value):
156
+ self.language_model.set_input_embeddings(value)
157
+
158
+ def set_decoder(self, decoder):
159
+ self.language_model = decoder
160
+
161
+ def get_decoder(self):
162
+ return self.language_model
163
+
164
+ def _update_causal_mask(
165
+ self,
166
+ attention_mask,
167
+ token_type_ids=None,
168
+ past_key_values=None,
169
+ cache_position=None,
170
+ input_tensor=None,
171
+ is_training: Optional[bool] = None,
172
+ ):
173
+ if self.config.text_config._attn_implementation == "flash_attention_2":
174
+ if attention_mask is not None and 0.0 in attention_mask:
175
+ return attention_mask
176
+ return None
177
+ is_training = is_training if is_training is not None else self.training
178
+ using_static_cache = isinstance(past_key_values, StaticCache)
179
+ min_dtype = torch.finfo(self.dtype).min
180
+ if input_tensor is None:
181
+ input_tensor = attention_mask
182
+
183
+ inputs_lead_dim, sequence_length = input_tensor.shape[:2]
184
+ if using_static_cache:
185
+ target_length = past_key_values.get_max_cache_shape()
186
+ elif isinstance(past_key_values, HybridCache):
187
+ target_length = past_key_values.get_max_cache_shape()
188
+ else:
189
+ target_length = (
190
+ attention_mask.shape[-1]
191
+ if isinstance(attention_mask, torch.Tensor)
192
+ else cache_position[0] + sequence_length + 1
193
+ )
194
+
195
+ if attention_mask is not None and attention_mask.dim() == 4:
196
+ # In this case we assume that the mask comes already in inverted form and requires no inversion or slicing.
197
+ return attention_mask
198
+
199
+ causal_mask = torch.full(
200
+ (sequence_length, target_length), fill_value=min_dtype, dtype=self.dtype, device=cache_position.device
201
+ )
202
+ # Causal diagonal mask only if training, otherwise attend to the whole prefix. Training-specific attn for prefix is handled below
203
+ if sequence_length != 1:
204
+ if is_training:
205
+ causal_mask = torch.triu(causal_mask, diagonal=1)
206
+ else:
207
+ causal_mask[:, :sequence_length] = 0.0
208
+
209
+ causal_mask *= torch.arange(target_length, device=cache_position.device) > cache_position.reshape(-1, 1)
210
+ causal_mask = causal_mask[None, None, :, :].expand(inputs_lead_dim, 1, -1, -1)
211
+ if attention_mask is not None:
212
+ causal_mask = causal_mask.clone() # copy to contiguous memory for in-place edit
213
+ mask_length = attention_mask.shape[-1]
214
+
215
+ # First unmask prefix tokens during training
216
+ if is_training:
217
+ if token_type_ids is None:
218
+ raise ValueError("Token type ids must be provided during training")
219
+ causal_mask[:, :, :, :mask_length] = causal_mask[:, :, :, :mask_length].masked_fill(
220
+ token_type_ids[:, None, None, :].to(causal_mask.device) == 0, 0
221
+ )
222
+
223
+ # Then apply padding mask (will mask pad tokens)
224
+ padding_mask = causal_mask[:, :, :, :mask_length] + attention_mask[:, None, None, :].to(causal_mask.device)
225
+ padding_mask = padding_mask == 0
226
+ causal_mask[:, :, :, :mask_length] = causal_mask[:, :, :, :mask_length].masked_fill(
227
+ padding_mask, min_dtype
228
+ )
229
+
230
+ return causal_mask
231
+
232
+ def get_image_features(self, pixel_values: torch.FloatTensor):
233
+ """
234
+ Obtains image last hidden states from the vision tower and apply multimodal projection.
235
+
236
+ Args:
237
+ pixel_values (`torch.FloatTensor]` of shape `(batch_size, channels, height, width)`)
238
+ The tensors corresponding to the input images.
239
+ Returns:
240
+ image_features (`torch.Tensor`): Image feature tensor of shape `(num_images, image_length, embed_dim)`).
241
+ """
242
+ image_outputs = self.vision_tower(pixel_values)
243
+ selected_image_feature = image_outputs.last_hidden_state
244
+ image_features = self.multi_modal_projector(selected_image_feature)
245
+ return image_features
246
+
247
+ @can_return_tuple
248
+ @auto_docstring
249
+ def forward(
250
+ self,
251
+ input_ids: torch.LongTensor = None,
252
+ pixel_values: torch.FloatTensor = None,
253
+ attention_mask: Optional[torch.Tensor] = None,
254
+ position_ids: Optional[torch.LongTensor] = None,
255
+ past_key_values: Optional[Union[list[torch.FloatTensor], Cache]] = None,
256
+ token_type_ids: Optional[torch.LongTensor] = None,
257
+ cache_position: Optional[torch.LongTensor] = None,
258
+ inputs_embeds: Optional[torch.FloatTensor] = None,
259
+ labels: Optional[torch.LongTensor] = None,
260
+ use_cache: Optional[bool] = None,
261
+ output_attentions: Optional[bool] = None,
262
+ output_hidden_states: Optional[bool] = None,
263
+ return_dict: Optional[bool] = None,
264
+ **kwargs: Unpack[FlashAttentionKwargs],
265
+ ) -> Union[tuple, PaligemmaModelOutputWithPast]:
266
+ r"""
267
+ labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
268
+ Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
269
+ config.text_config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
270
+ (masked), the loss is only computed for the tokens with labels in `[0, ..., config.text_config.vocab_size]`.
271
+
272
+ Example:
273
+
274
+ ```python
275
+ >>> from PIL import Image
276
+ >>> import requests
277
+ >>> from transformers import AutoProcessor, PaliGemmaForConditionalGeneration
278
+
279
+ >>> model = PaliGemmaForConditionalGeneration.from_pretrained("google/paligemma2-3b-mix-224")
280
+ >>> processor = AutoProcessor.from_pretrained("google/paligemma2-3b-mix-224")
281
+
282
+ >>> prompt = "Where is the cat standing?"
283
+ >>> url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
284
+ >>> image = Image.open(requests.get(url, stream=True).raw)
285
+
286
+ >>> inputs = processor(images=image, text=prompt, return_tensors="pt")
287
+
288
+ >>> # Generate
289
+ >>> generate_ids = model.generate(**inputs,)
290
+ >>> processor.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
291
+ "Where is the cat standing?\nsnow"
292
+ ```"""
293
+
294
+ if (input_ids is None) ^ (inputs_embeds is not None):
295
+ raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
296
+
297
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
298
+ output_hidden_states = (
299
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
300
+ )
301
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
302
+
303
+ is_training = token_type_ids is not None and labels is not None
304
+
305
+ # Replace image id woth PAD if the image token if OOV, to avoid index-errors
306
+ if input_ids is not None and self.config.image_token_id >= self.vocab_size:
307
+ special_image_mask = input_ids == self.config.image_token_id
308
+ llm_input_ids = input_ids.clone()
309
+ llm_input_ids[special_image_mask] = 0
310
+ else:
311
+ llm_input_ids = input_ids
312
+
313
+ if inputs_embeds is None:
314
+ inputs_embeds = self.get_input_embeddings()(llm_input_ids)
315
+
316
+ if cache_position is None:
317
+ past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
318
+ cache_position = torch.arange(
319
+ past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device
320
+ )
321
+
322
+ if position_ids is None:
323
+ position_ids = cache_position.unsqueeze(0) + 1 # Paligemma positions are 1-indexed
324
+
325
+ # Merge text and images
326
+ if pixel_values is not None:
327
+ image_features = self.get_image_features(pixel_values)
328
+
329
+ if input_ids is None:
330
+ special_image_mask = inputs_embeds == self.get_input_embeddings()(
331
+ torch.tensor(self.config.image_token_id, dtype=torch.long, device=inputs_embeds.device)
332
+ )
333
+ else:
334
+ special_image_mask = (input_ids == self.config.image_token_id).unsqueeze(-1)
335
+ special_image_mask = special_image_mask.expand_as(inputs_embeds).to(inputs_embeds.device)
336
+
337
+ if not is_torchdynamo_compiling() and inputs_embeds[special_image_mask].numel() != image_features.numel():
338
+ image_tokens_in_text = (special_image_mask).sum(dim=1).sum(dim=0)[0]
339
+ raise ValueError(
340
+ f"Number of images does not match number of special image tokens in the input text. "
341
+ f"Got {image_tokens_in_text} image tokens in the text but {image_features.shape[0] * image_features.shape[1]} "
342
+ "tokens from image embeddings."
343
+ )
344
+ image_features = image_features.to(inputs_embeds.device, inputs_embeds.dtype)
345
+ inputs_embeds = inputs_embeds.masked_scatter(special_image_mask, image_features)
346
+
347
+ causal_mask = self._update_causal_mask(
348
+ attention_mask, token_type_ids, past_key_values, cache_position, inputs_embeds, is_training
349
+ )
350
+ outputs = self.language_model(
351
+ attention_mask=causal_mask,
352
+ position_ids=position_ids,
353
+ past_key_values=past_key_values,
354
+ inputs_embeds=inputs_embeds,
355
+ use_cache=use_cache,
356
+ output_attentions=output_attentions,
357
+ output_hidden_states=output_hidden_states,
358
+ return_dict=True,
359
+ cache_position=cache_position,
360
+ **kwargs,
361
+ )
362
+
363
+ return PaligemmaModelOutputWithPast(
364
+ last_hidden_state=outputs.last_hidden_state,
365
+ past_key_values=outputs.past_key_values,
366
+ hidden_states=outputs.hidden_states,
367
+ attentions=outputs.attentions,
368
+ image_hidden_states=image_features if pixel_values is not None else None,
369
+ )
370
+
371
+
372
+ class KwargsForCausalLM(FlashAttentionKwargs, LossKwargs): ...
373
+
374
+
375
+ @auto_docstring(
376
+ custom_intro="""
377
+ The Base Paligemma model which consists of a vision backbone and a language model without language modeling head.,
378
+ """
379
+ )
380
+ class PaliGemmaForConditionalGeneration(PaliGemmaPreTrainedModel, GenerationMixin):
381
+ _checkpoint_conversion_mapping = {
382
+ "^language_model.model": "model.language_model",
383
+ "^vision_tower": "model.vision_tower",
384
+ "^multi_modal_projector": "model.multi_modal_projector",
385
+ "^language_model.lm_head": "lm_head",
386
+ }
387
+ _tied_weights_keys = ["lm_head.weight"]
388
+
389
+ def __init__(self, config: PaliGemmaConfig):
390
+ super().__init__(config)
391
+ self.model = PaliGemmaModel(config)
392
+ self.lm_head = nn.Linear(config.text_config.hidden_size, config.text_config.vocab_size, bias=False)
393
+ self.post_init()
394
+
395
+ def get_input_embeddings(self):
396
+ return self.model.get_input_embeddings()
397
+
398
+ def set_input_embeddings(self, value):
399
+ self.model.set_input_embeddings(value)
400
+
401
+ def get_output_embeddings(self):
402
+ return self.lm_head
403
+
404
+ def set_output_embeddings(self, new_embeddings):
405
+ self.lm_head = new_embeddings
406
+
407
+ def set_decoder(self, decoder):
408
+ self.model.set_decoder(decoder)
409
+
410
+ def get_decoder(self):
411
+ return self.model.get_decoder()
412
+
413
+ def get_image_features(self, pixel_values):
414
+ return self.model.get_image_features(pixel_values)
415
+
416
+ # Make modules available throught conditional class for BC
417
+ @property
418
+ def language_model(self):
419
+ return self.model.language_model
420
+
421
+ @property
422
+ def vision_tower(self):
423
+ return self.model.vision_tower
424
+
425
+ @property
426
+ def multi_modal_projector(self):
427
+ return self.model.multi_modal_projector
428
+
429
+ @can_return_tuple
430
+ @auto_docstring
431
+ def forward(
432
+ self,
433
+ input_ids: torch.LongTensor = None,
434
+ pixel_values: torch.FloatTensor = None,
435
+ attention_mask: Optional[torch.Tensor] = None,
436
+ position_ids: Optional[torch.LongTensor] = None,
437
+ past_key_values: Optional[Union[list[torch.FloatTensor], Cache]] = None,
438
+ token_type_ids: Optional[torch.LongTensor] = None,
439
+ cache_position: Optional[torch.LongTensor] = None,
440
+ inputs_embeds: Optional[torch.FloatTensor] = None,
441
+ labels: Optional[torch.LongTensor] = None,
442
+ use_cache: Optional[bool] = None,
443
+ output_attentions: Optional[bool] = None,
444
+ output_hidden_states: Optional[bool] = None,
445
+ return_dict: Optional[bool] = None,
446
+ logits_to_keep: Union[int, torch.Tensor] = 0,
447
+ **kwargs: Unpack[KwargsForCausalLM],
448
+ ) -> Union[tuple, PaliGemmaCausalLMOutputWithPast]:
449
+ r"""
450
+ labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
451
+ Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
452
+ config.text_config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
453
+ (masked), the loss is only computed for the tokens with labels in `[0, ..., config.text_config.vocab_size]`.
454
+
455
+ Example:
456
+
457
+ ```python
458
+ >>> from PIL import Image
459
+ >>> import requests
460
+ >>> from transformers import AutoProcessor, PaliGemmaForConditionalGeneration
461
+
462
+ >>> model = PaliGemmaForConditionalGeneration.from_pretrained("google/paligemma2-3b-mix-224")
463
+ >>> processor = AutoProcessor.from_pretrained("google/paligemma2-3b-mix-224")
464
+
465
+ >>> prompt = "Where is the cat standing?"
466
+ >>> url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
467
+ >>> image = Image.open(requests.get(url, stream=True).raw)
468
+
469
+ >>> inputs = processor(images=image, text=prompt, return_tensors="pt")
470
+
471
+ >>> # Generate
472
+ >>> generate_ids = model.generate(**inputs,)
473
+ >>> processor.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
474
+ "Where is the cat standing?\nsnow"
475
+ ```"""
476
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
477
+ output_hidden_states = (
478
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
479
+ )
480
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
481
+
482
+ outputs = self.model(
483
+ input_ids=input_ids,
484
+ pixel_values=pixel_values,
485
+ token_type_ids=token_type_ids,
486
+ attention_mask=attention_mask,
487
+ position_ids=position_ids,
488
+ past_key_values=past_key_values,
489
+ inputs_embeds=inputs_embeds,
490
+ use_cache=use_cache,
491
+ labels=labels,
492
+ output_attentions=output_attentions,
493
+ output_hidden_states=output_hidden_states,
494
+ return_dict=True,
495
+ cache_position=cache_position,
496
+ **kwargs,
497
+ )
498
+
499
+ hidden_states = outputs[0]
500
+ # Only compute necessary logits, and do not upcast them to float if we are not computing the loss
501
+ slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
502
+ logits = self.lm_head(hidden_states[:, slice_indices, :])
503
+
504
+ loss = None
505
+ if labels is not None:
506
+ loss = self.loss_function(
507
+ logits=logits, labels=labels, vocab_size=self.config.text_config.vocab_size, **kwargs
508
+ )
509
+
510
+ return PaliGemmaCausalLMOutputWithPast(
511
+ loss=loss,
512
+ logits=logits,
513
+ past_key_values=outputs.past_key_values,
514
+ hidden_states=outputs.hidden_states,
515
+ attentions=outputs.attentions,
516
+ image_hidden_states=outputs.image_hidden_states,
517
+ )
518
+
519
+ def prepare_inputs_for_generation(
520
+ self,
521
+ input_ids,
522
+ past_key_values=None,
523
+ inputs_embeds=None,
524
+ cache_position=None,
525
+ position_ids=None,
526
+ pixel_values=None,
527
+ attention_mask=None,
528
+ token_type_ids=None,
529
+ use_cache=True,
530
+ logits_to_keep=None,
531
+ labels=None,
532
+ **kwargs,
533
+ ):
534
+ # Overwritten -- custom `position_ids` and `pixel_values` handling
535
+ model_inputs = super().prepare_inputs_for_generation(
536
+ input_ids,
537
+ past_key_values=past_key_values,
538
+ inputs_embeds=inputs_embeds,
539
+ attention_mask=attention_mask,
540
+ position_ids=position_ids,
541
+ cache_position=cache_position,
542
+ use_cache=use_cache,
543
+ logits_to_keep=logits_to_keep,
544
+ token_type_ids=token_type_ids,
545
+ **kwargs,
546
+ )
547
+
548
+ # position_ids in Paligemma are 1-indexed
549
+ if model_inputs.get("position_ids") is not None:
550
+ model_inputs["position_ids"] += 1
551
+ # If we're in cached decoding stage, pixel values should be None because input ids do not contain special image token anymore
552
+ # Otherwise we need pixel values to be passed to model. NOTE: use_cache=False needs pixel_values always
553
+ if cache_position[0] == 0:
554
+ model_inputs["pixel_values"] = pixel_values
555
+ is_training = token_type_ids is not None and labels is not None
556
+ if cache_position[0] == 0 and isinstance(past_key_values, HybridCache):
557
+ input_tensor = inputs_embeds if inputs_embeds is not None else input_ids
558
+ causal_mask = self.model._update_causal_mask(
559
+ attention_mask, token_type_ids, past_key_values, cache_position, input_tensor, is_training
560
+ )
561
+ model_inputs["attention_mask"] = causal_mask
562
+
563
+ return model_inputs
564
+
565
+ @staticmethod
566
+ # Copied from transformers.models.gptj.modeling_gptj.GPTJModel._prepare_4d_causal_attention_mask_with_cache_position
567
+ def _prepare_4d_causal_attention_mask_with_cache_position(
568
+ attention_mask: torch.Tensor,
569
+ sequence_length: int,
570
+ target_length: int,
571
+ dtype: torch.dtype,
572
+ cache_position: torch.Tensor,
573
+ batch_size: int,
574
+ **kwargs,
575
+ ):
576
+ """
577
+ Creates a causal 4D mask of shape `(batch_size, 1, query_length, key_value_length)` from a 2D mask of shape
578
+ `(batch_size, key_value_length)`, or if the input `attention_mask` is already 4D, do nothing.
579
+
580
+ Args:
581
+ attention_mask (`torch.Tensor`):
582
+ A 2D attention mask of shape `(batch_size, key_value_length)` or a 4D attention mask of shape
583
+ `(batch_size, 1, query_length, key_value_length)`.
584
+ sequence_length (`int`):
585
+ The sequence length being processed.
586
+ target_length (`int`):
587
+ The target length: when generating with static cache, the mask should be as long as the static cache,
588
+ to account for the 0 padding, the part of the cache that is not filled yet.
589
+ dtype (`torch.dtype`):
590
+ The dtype to use for the 4D attention mask.
591
+ cache_position (`torch.Tensor`):
592
+ Indices depicting the position of the input sequence tokens in the sequence.
593
+ batch_size (`torch.Tensor`):
594
+ Batch size.
595
+ """
596
+ if attention_mask is not None and attention_mask.dim() == 4:
597
+ # In this case we assume that the mask comes already in inverted form and requires no inversion or slicing.
598
+ causal_mask = attention_mask
599
+ else:
600
+ min_dtype = torch.finfo(dtype).min
601
+ causal_mask = torch.full(
602
+ (sequence_length, target_length), fill_value=min_dtype, dtype=dtype, device=cache_position.device
603
+ )
604
+ if sequence_length != 1:
605
+ causal_mask = torch.triu(causal_mask, diagonal=1)
606
+ causal_mask *= torch.arange(target_length, device=cache_position.device) > cache_position.reshape(-1, 1)
607
+ causal_mask = causal_mask[None, None, :, :].expand(batch_size, 1, -1, -1)
608
+ if attention_mask is not None:
609
+ causal_mask = causal_mask.clone() # copy to contiguous memory for in-place edit
610
+ mask_length = attention_mask.shape[-1]
611
+ padding_mask = causal_mask[:, :, :, :mask_length] + attention_mask[:, None, None, :].to(
612
+ causal_mask.device
613
+ )
614
+ padding_mask = padding_mask == 0
615
+ causal_mask[:, :, :, :mask_length] = causal_mask[:, :, :, :mask_length].masked_fill(
616
+ padding_mask, min_dtype
617
+ )
618
+
619
+ return causal_mask
620
+
621
+
622
+ __all__ = ["PaliGemmaForConditionalGeneration", "PaliGemmaPreTrainedModel", "PaliGemmaModel"]
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/siglip/check.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import transformers
2
+
3
+ def check_whether_transformers_replace_is_installed_correctly():
4
+ return transformers.__version__ == "4.53.2"
pi05_twotasks_pytorch/code/openpi-main/src/openpi/models_pytorch/transformers_replace/models/siglip/modeling_siglip.py ADDED
@@ -0,0 +1,1237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2024 Google AI and The HuggingFace Team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """PyTorch Siglip model."""
16
+
17
+ import math
18
+ import warnings
19
+ from dataclasses import dataclass
20
+ from typing import Any, Callable, Optional, Union
21
+
22
+ import numpy as np
23
+ import torch
24
+ import torch.utils.checkpoint
25
+ from torch import nn
26
+ from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
27
+ from torch.nn.init import _calculate_fan_in_and_fan_out
28
+
29
+ from ...activations import ACT2FN
30
+ from ...modeling_attn_mask_utils import _prepare_4d_attention_mask
31
+ from ...modeling_layers import GradientCheckpointingLayer
32
+ from ...modeling_outputs import BaseModelOutput, BaseModelOutputWithPooling, ImageClassifierOutput
33
+ from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
34
+ from ...utils import ModelOutput, auto_docstring, can_return_tuple, logging, torch_int
35
+ from .configuration_siglip import SiglipConfig, SiglipTextConfig, SiglipVisionConfig
36
+
37
+
38
+ logger = logging.get_logger(__name__)
39
+
40
+
41
+ def _trunc_normal_(tensor, mean, std, a, b):
42
+ # Cut & paste from PyTorch official master until it's in a few official releases - RW
43
+ # Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf
44
+ def norm_cdf(x):
45
+ # Computes standard normal cumulative distribution function
46
+ return (1.0 + math.erf(x / math.sqrt(2.0))) / 2.0
47
+
48
+ if (mean < a - 2 * std) or (mean > b + 2 * std):
49
+ warnings.warn(
50
+ "mean is more than 2 std from [a, b] in nn.init.trunc_normal_. "
51
+ "The distribution of values may be incorrect.",
52
+ stacklevel=2,
53
+ )
54
+
55
+ # Values are generated by using a truncated uniform distribution and
56
+ # then using the inverse CDF for the normal distribution.
57
+ # Get upper and lower cdf values
58
+ l = norm_cdf((a - mean) / std)
59
+ u = norm_cdf((b - mean) / std)
60
+
61
+ # Uniformly fill tensor with values from [l, u], then translate to
62
+ # [2l-1, 2u-1].
63
+ tensor.uniform_(2 * l - 1, 2 * u - 1)
64
+
65
+ # Use inverse cdf transform for normal distribution to get truncated
66
+ # standard normal
67
+ tensor.erfinv_()
68
+
69
+ # Transform to proper mean, std
70
+ tensor.mul_(std * math.sqrt(2.0))
71
+ tensor.add_(mean)
72
+
73
+ # Clamp to ensure it's in the proper range
74
+ tensor.clamp_(min=a, max=b)
75
+
76
+
77
+ def trunc_normal_tf_(
78
+ tensor: torch.Tensor, mean: float = 0.0, std: float = 1.0, a: float = -2.0, b: float = 2.0
79
+ ) -> torch.Tensor:
80
+ """Fills the input Tensor with values drawn from a truncated
81
+ normal distribution. The values are effectively drawn from the
82
+ normal distribution :math:`\\mathcal{N}(\text{mean}, \text{std}^2)`
83
+ with values outside :math:`[a, b]` redrawn until they are within
84
+ the bounds. The method used for generating the random values works
85
+ best when :math:`a \\leq \text{mean} \\leq b`.
86
+
87
+ NOTE: this 'tf' variant behaves closer to Tensorflow / JAX impl where the
88
+ bounds [a, b] are applied when sampling the normal distribution with mean=0, std=1.0
89
+ and the result is subsequently scaled and shifted by the mean and std args.
90
+
91
+ Args:
92
+ tensor: an n-dimensional `torch.Tensor`
93
+ mean: the mean of the normal distribution
94
+ std: the standard deviation of the normal distribution
95
+ a: the minimum cutoff value
96
+ b: the maximum cutoff value
97
+ """
98
+ with torch.no_grad():
99
+ _trunc_normal_(tensor, 0, 1.0, a, b)
100
+ tensor.mul_(std).add_(mean)
101
+
102
+
103
+ def variance_scaling_(tensor, scale=1.0, mode="fan_in", distribution="normal"):
104
+ fan_in, fan_out = _calculate_fan_in_and_fan_out(tensor)
105
+ if mode == "fan_in":
106
+ denom = fan_in
107
+ elif mode == "fan_out":
108
+ denom = fan_out
109
+ elif mode == "fan_avg":
110
+ denom = (fan_in + fan_out) / 2
111
+
112
+ variance = scale / denom
113
+
114
+ if distribution == "truncated_normal":
115
+ # constant is stddev of standard normal truncated to (-2, 2)
116
+ trunc_normal_tf_(tensor, std=math.sqrt(variance) / 0.87962566103423978)
117
+ elif distribution == "normal":
118
+ with torch.no_grad():
119
+ tensor.normal_(std=math.sqrt(variance))
120
+ elif distribution == "uniform":
121
+ bound = math.sqrt(3 * variance)
122
+ with torch.no_grad():
123
+ tensor.uniform_(-bound, bound)
124
+ else:
125
+ raise ValueError(f"invalid distribution {distribution}")
126
+
127
+
128
+ def lecun_normal_(tensor):
129
+ variance_scaling_(tensor, mode="fan_in", distribution="truncated_normal")
130
+
131
+
132
+ def default_flax_embed_init(tensor):
133
+ variance_scaling_(tensor, mode="fan_in", distribution="normal")
134
+
135
+
136
+ @dataclass
137
+ @auto_docstring(
138
+ custom_intro="""
139
+ Base class for vision model's outputs that also contains image embeddings of the pooling of the last hidden states.
140
+ """
141
+ )
142
+ # Copied from transformers.models.clip.modeling_clip.CLIPVisionModelOutput with CLIP->Siglip
143
+ class SiglipVisionModelOutput(ModelOutput):
144
+ r"""
145
+ image_embeds (`torch.FloatTensor` of shape `(batch_size, output_dim)` *optional* returned when model is initialized with `with_projection=True`):
146
+ The image embeddings obtained by applying the projection layer to the pooler_output.
147
+ """
148
+
149
+ image_embeds: Optional[torch.FloatTensor] = None
150
+ last_hidden_state: Optional[torch.FloatTensor] = None
151
+ hidden_states: Optional[tuple[torch.FloatTensor, ...]] = None
152
+ attentions: Optional[tuple[torch.FloatTensor, ...]] = None
153
+
154
+
155
+ @dataclass
156
+ @auto_docstring(
157
+ custom_intro="""
158
+ Base class for text model's outputs that also contains a pooling of the last hidden states.
159
+ """
160
+ )
161
+ # Copied from transformers.models.clip.modeling_clip.CLIPTextModelOutput with CLIP->Siglip
162
+ class SiglipTextModelOutput(ModelOutput):
163
+ r"""
164
+ text_embeds (`torch.FloatTensor` of shape `(batch_size, output_dim)` *optional* returned when model is initialized with `with_projection=True`):
165
+ The text embeddings obtained by applying the projection layer to the pooler_output.
166
+ """
167
+
168
+ text_embeds: Optional[torch.FloatTensor] = None
169
+ last_hidden_state: Optional[torch.FloatTensor] = None
170
+ hidden_states: Optional[tuple[torch.FloatTensor, ...]] = None
171
+ attentions: Optional[tuple[torch.FloatTensor, ...]] = None
172
+
173
+
174
+ @dataclass
175
+ @auto_docstring
176
+ # Copied from transformers.models.clip.modeling_clip.CLIPOutput with CLIP->Siglip
177
+ class SiglipOutput(ModelOutput):
178
+ r"""
179
+ loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `return_loss` is `True`):
180
+ Contrastive loss for image-text similarity.
181
+ logits_per_image (`torch.FloatTensor` of shape `(image_batch_size, text_batch_size)`):
182
+ The scaled dot product scores between `image_embeds` and `text_embeds`. This represents the image-text
183
+ similarity scores.
184
+ logits_per_text (`torch.FloatTensor` of shape `(text_batch_size, image_batch_size)`):
185
+ The scaled dot product scores between `text_embeds` and `image_embeds`. This represents the text-image
186
+ similarity scores.
187
+ text_embeds (`torch.FloatTensor` of shape `(batch_size, output_dim`):
188
+ The text embeddings obtained by applying the projection layer to the pooled output of [`SiglipTextModel`].
189
+ image_embeds (`torch.FloatTensor` of shape `(batch_size, output_dim`):
190
+ The image embeddings obtained by applying the projection layer to the pooled output of [`SiglipVisionModel`].
191
+ text_model_output (`BaseModelOutputWithPooling`):
192
+ The output of the [`SiglipTextModel`].
193
+ vision_model_output (`BaseModelOutputWithPooling`):
194
+ The output of the [`SiglipVisionModel`].
195
+ """
196
+
197
+ loss: Optional[torch.FloatTensor] = None
198
+ logits_per_image: Optional[torch.FloatTensor] = None
199
+ logits_per_text: Optional[torch.FloatTensor] = None
200
+ text_embeds: Optional[torch.FloatTensor] = None
201
+ image_embeds: Optional[torch.FloatTensor] = None
202
+ text_model_output: BaseModelOutputWithPooling = None
203
+ vision_model_output: BaseModelOutputWithPooling = None
204
+
205
+ def to_tuple(self) -> tuple[Any]:
206
+ return tuple(
207
+ self[k] if k not in ["text_model_output", "vision_model_output"] else getattr(self, k).to_tuple()
208
+ for k in self.keys()
209
+ )
210
+
211
+
212
+ class SiglipVisionEmbeddings(nn.Module):
213
+ def __init__(self, config: SiglipVisionConfig):
214
+ super().__init__()
215
+ self.config = config
216
+ self.embed_dim = config.hidden_size
217
+ self.image_size = config.image_size
218
+ self.patch_size = config.patch_size
219
+
220
+ self.patch_embedding = nn.Conv2d(
221
+ in_channels=config.num_channels,
222
+ out_channels=self.embed_dim,
223
+ kernel_size=self.patch_size,
224
+ stride=self.patch_size,
225
+ padding="valid",
226
+ )
227
+
228
+ self.num_patches = (self.image_size // self.patch_size) ** 2
229
+ self.num_positions = self.num_patches
230
+ self.position_embedding = nn.Embedding(self.num_positions, self.embed_dim)
231
+ self.register_buffer("position_ids", torch.arange(self.num_positions).expand((1, -1)), persistent=False)
232
+
233
+ def interpolate_pos_encoding(self, embeddings: torch.Tensor, height: int, width: int) -> torch.Tensor:
234
+ """
235
+ This method allows to interpolate the pre-trained position encodings, to be able to use the model on higher resolution
236
+ images. This method is also adapted to support torch.jit tracing and no class embeddings.
237
+
238
+ Adapted from:
239
+ - https://github.com/facebookresearch/dino/blob/de9ee3df6cf39fac952ab558447af1fa1365362a/vision_transformer.py#L174-L194, and
240
+ - https://github.com/facebookresearch/dinov2/blob/e1277af2ba9496fbadf7aec6eba56e8d882d1e35/dinov2/models/vision_transformer.py#L179-L211
241
+ """
242
+
243
+ num_patches = embeddings.shape[1]
244
+ num_positions = self.position_embedding.weight.shape[0]
245
+
246
+ # always interpolate when tracing to ensure the exported model works for dynamic input shapes
247
+ if not torch.jit.is_tracing() and num_patches == num_positions and height == width:
248
+ return self.position_embedding(self.position_ids)
249
+
250
+ patch_pos_embed = self.position_embedding.weight.unsqueeze(0)
251
+
252
+ dim = embeddings.shape[-1]
253
+
254
+ new_height = height // self.patch_size
255
+ new_width = width // self.patch_size
256
+
257
+ sqrt_num_positions = torch_int(num_positions**0.5)
258
+ patch_pos_embed = patch_pos_embed.reshape(1, sqrt_num_positions, sqrt_num_positions, dim)
259
+ patch_pos_embed = patch_pos_embed.permute(0, 3, 1, 2)
260
+
261
+ patch_pos_embed = nn.functional.interpolate(
262
+ patch_pos_embed,
263
+ size=(new_height, new_width),
264
+ mode="bicubic",
265
+ align_corners=False,
266
+ )
267
+
268
+ patch_pos_embed = patch_pos_embed.permute(0, 2, 3, 1).view(1, -1, dim)
269
+ return patch_pos_embed
270
+
271
+ def forward(self, pixel_values: torch.FloatTensor, interpolate_pos_encoding=False) -> torch.Tensor:
272
+ _, _, height, width = pixel_values.shape
273
+ target_dtype = self.patch_embedding.weight.dtype
274
+ patch_embeds = self.patch_embedding(pixel_values.to(dtype=target_dtype)) # shape = [*, width, grid, grid]
275
+ embeddings = patch_embeds.flatten(2).transpose(1, 2)
276
+
277
+ if interpolate_pos_encoding:
278
+ embeddings = embeddings + self.interpolate_pos_encoding(embeddings, height, width)
279
+ else:
280
+ embeddings = embeddings + self.position_embedding(self.position_ids)
281
+ return embeddings
282
+
283
+
284
+ # Copied from transformers.models.clip.modeling_clip.CLIPTextEmbeddings with CLIP->Siglip
285
+ class SiglipTextEmbeddings(nn.Module):
286
+ def __init__(self, config: SiglipTextConfig):
287
+ super().__init__()
288
+ embed_dim = config.hidden_size
289
+
290
+ self.token_embedding = nn.Embedding(config.vocab_size, embed_dim)
291
+ self.position_embedding = nn.Embedding(config.max_position_embeddings, embed_dim)
292
+
293
+ # position_ids (1, len position emb) is contiguous in memory and exported when serialized
294
+ self.register_buffer(
295
+ "position_ids", torch.arange(config.max_position_embeddings).expand((1, -1)), persistent=False
296
+ )
297
+
298
+ def forward(
299
+ self,
300
+ input_ids: Optional[torch.LongTensor] = None,
301
+ position_ids: Optional[torch.LongTensor] = None,
302
+ inputs_embeds: Optional[torch.FloatTensor] = None,
303
+ ) -> torch.Tensor:
304
+ seq_length = input_ids.shape[-1] if input_ids is not None else inputs_embeds.shape[-2]
305
+ max_position_embedding = self.position_embedding.weight.shape[0]
306
+
307
+ if seq_length > max_position_embedding:
308
+ raise ValueError(
309
+ f"Sequence length must be less than max_position_embeddings (got `sequence length`: "
310
+ f"{seq_length} and max_position_embeddings: {max_position_embedding}"
311
+ )
312
+
313
+ if position_ids is None:
314
+ position_ids = self.position_ids[:, :seq_length]
315
+
316
+ if inputs_embeds is None:
317
+ inputs_embeds = self.token_embedding(input_ids)
318
+
319
+ position_embeddings = self.position_embedding(position_ids)
320
+ embeddings = inputs_embeds + position_embeddings
321
+
322
+ return embeddings
323
+
324
+
325
+ def eager_attention_forward(
326
+ module: nn.Module,
327
+ query: torch.Tensor,
328
+ key: torch.Tensor,
329
+ value: torch.Tensor,
330
+ attention_mask: Optional[torch.Tensor],
331
+ scaling: float,
332
+ dropout: float = 0.0,
333
+ **kwargs,
334
+ ):
335
+ attn_weights = torch.matmul(query, key.transpose(-1, -2)) * scaling
336
+ if attention_mask is not None:
337
+ attn_weights = attn_weights + attention_mask
338
+
339
+ attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
340
+ attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
341
+
342
+ attn_output = torch.matmul(attn_weights, value)
343
+ attn_output = attn_output.transpose(1, 2).contiguous()
344
+
345
+ return attn_output, attn_weights
346
+
347
+
348
+ class SiglipAttention(nn.Module):
349
+ """Multi-headed attention from 'Attention Is All You Need' paper"""
350
+
351
+ def __init__(self, config):
352
+ super().__init__()
353
+ self.config = config
354
+ self.embed_dim = config.hidden_size
355
+ self.num_heads = config.num_attention_heads
356
+ self.head_dim = self.embed_dim // self.num_heads
357
+ if self.head_dim * self.num_heads != self.embed_dim:
358
+ raise ValueError(
359
+ f"embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`:"
360
+ f" {self.num_heads})."
361
+ )
362
+ self.scale = self.head_dim**-0.5
363
+ self.dropout = config.attention_dropout
364
+ self.is_causal = False
365
+
366
+ self.k_proj = nn.Linear(self.embed_dim, self.embed_dim)
367
+ self.v_proj = nn.Linear(self.embed_dim, self.embed_dim)
368
+ self.q_proj = nn.Linear(self.embed_dim, self.embed_dim)
369
+ self.out_proj = nn.Linear(self.embed_dim, self.embed_dim)
370
+
371
+ def forward(
372
+ self,
373
+ hidden_states: torch.Tensor,
374
+ attention_mask: Optional[torch.Tensor] = None,
375
+ output_attentions: Optional[bool] = False,
376
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor]]:
377
+ """Input shape: Batch x Time x Channel"""
378
+
379
+ batch_size, seq_length, embed_dim = hidden_states.shape
380
+
381
+ queries = self.q_proj(hidden_states)
382
+ keys = self.k_proj(hidden_states)
383
+ values = self.v_proj(hidden_states)
384
+
385
+ queries = queries.view(batch_size, seq_length, self.num_heads, self.head_dim).transpose(1, 2)
386
+ keys = keys.view(batch_size, seq_length, self.num_heads, self.head_dim).transpose(1, 2)
387
+ values = values.view(batch_size, seq_length, self.num_heads, self.head_dim).transpose(1, 2)
388
+
389
+ attention_interface: Callable = eager_attention_forward
390
+ if self.config._attn_implementation != "eager":
391
+ if self.config._attn_implementation == "sdpa" and output_attentions:
392
+ logger.warning_once(
393
+ "`torch.nn.functional.scaled_dot_product_attention` does not support `output_attentions=True`. Falling back to "
394
+ 'eager attention. This warning can be removed using the argument `attn_implementation="eager"` when loading the model.'
395
+ )
396
+ else:
397
+ attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]
398
+
399
+ attn_output, attn_weights = attention_interface(
400
+ self,
401
+ queries,
402
+ keys,
403
+ values,
404
+ attention_mask,
405
+ is_causal=self.is_causal,
406
+ scaling=self.scale,
407
+ dropout=0.0 if not self.training else self.dropout,
408
+ )
409
+
410
+ attn_output = attn_output.reshape(batch_size, seq_length, embed_dim).contiguous()
411
+ attn_output = self.out_proj(attn_output)
412
+
413
+ if not output_attentions:
414
+ attn_weights = None
415
+
416
+ return attn_output, attn_weights
417
+
418
+
419
+ # Copied from transformers.models.clip.modeling_clip.CLIPMLP with CLIP->Siglip
420
+ class SiglipMLP(nn.Module):
421
+ def __init__(self, config):
422
+ super().__init__()
423
+ self.config = config
424
+ self.activation_fn = ACT2FN[config.hidden_act]
425
+ self.fc1 = nn.Linear(config.hidden_size, config.intermediate_size)
426
+ self.fc2 = nn.Linear(config.intermediate_size, config.hidden_size)
427
+
428
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
429
+ hidden_states = self.fc1(hidden_states)
430
+ hidden_states = self.activation_fn(hidden_states)
431
+ hidden_states = self.fc2(hidden_states)
432
+ return hidden_states
433
+
434
+
435
+ class SiglipEncoderLayer(GradientCheckpointingLayer):
436
+ def __init__(self, config: Union[SiglipVisionConfig, SiglipTextConfig]):
437
+ super().__init__()
438
+ self.embed_dim = config.hidden_size
439
+ self.layer_norm1 = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_eps)
440
+ self.self_attn = SiglipAttention(config)
441
+ self.layer_norm2 = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_eps)
442
+ self.mlp = SiglipMLP(config)
443
+
444
+ def forward(
445
+ self,
446
+ hidden_states: torch.Tensor,
447
+ attention_mask: torch.Tensor,
448
+ output_attentions: Optional[bool] = False,
449
+ ) -> tuple[torch.FloatTensor]:
450
+ """
451
+ Args:
452
+ hidden_states (`torch.FloatTensor`):
453
+ Input to the layer of shape `(batch, seq_len, embed_dim)`.
454
+ attention_mask (`torch.FloatTensor`):
455
+ Attention mask of shape `(batch, 1, q_len, k_v_seq_len)` where padding elements are indicated by very large negative values.
456
+ output_attentions (`bool`, *optional*, defaults to `False`):
457
+ Whether or not to return the attentions tensors of all attention layers. See `attentions` under
458
+ returned tensors for more detail.
459
+ """
460
+ residual = hidden_states
461
+
462
+ hidden_states = self.layer_norm1(hidden_states)
463
+ hidden_states, attn_weights = self.self_attn(
464
+ hidden_states=hidden_states,
465
+ attention_mask=attention_mask,
466
+ output_attentions=output_attentions,
467
+ )
468
+ hidden_states = residual + hidden_states
469
+
470
+ residual = hidden_states
471
+ hidden_states = self.layer_norm2(hidden_states)
472
+ hidden_states = self.mlp(hidden_states)
473
+ hidden_states = residual + hidden_states
474
+
475
+ outputs = (hidden_states,)
476
+
477
+ if output_attentions:
478
+ outputs += (attn_weights,)
479
+
480
+ return outputs
481
+
482
+
483
+ @auto_docstring
484
+ class SiglipPreTrainedModel(PreTrainedModel):
485
+ config_class = SiglipConfig
486
+ base_model_prefix = "siglip"
487
+ supports_gradient_checkpointing = True
488
+
489
+ _no_split_modules = [
490
+ "SiglipTextEmbeddings",
491
+ "SiglipEncoderLayer",
492
+ "SiglipVisionEmbeddings",
493
+ "SiglipEncoderLayer",
494
+ "SiglipMultiheadAttentionPoolingHead",
495
+ ]
496
+ _supports_flash_attn_2 = True
497
+ _supports_sdpa = True
498
+ _supports_flex_attn = True
499
+ _supports_attention_backend = True
500
+
501
+ def _init_weights(self, module):
502
+ """Initialize the weights"""
503
+ if isinstance(module, SiglipVisionEmbeddings):
504
+ width = (
505
+ self.config.vision_config.hidden_size
506
+ if isinstance(self.config, SiglipConfig)
507
+ else self.config.hidden_size
508
+ )
509
+ nn.init.normal_(module.position_embedding.weight, std=1 / np.sqrt(width))
510
+ elif isinstance(module, nn.Embedding):
511
+ default_flax_embed_init(module.weight)
512
+ elif isinstance(module, SiglipAttention):
513
+ nn.init.xavier_uniform_(module.q_proj.weight)
514
+ nn.init.xavier_uniform_(module.k_proj.weight)
515
+ nn.init.xavier_uniform_(module.v_proj.weight)
516
+ nn.init.xavier_uniform_(module.out_proj.weight)
517
+ nn.init.zeros_(module.q_proj.bias)
518
+ nn.init.zeros_(module.k_proj.bias)
519
+ nn.init.zeros_(module.v_proj.bias)
520
+ nn.init.zeros_(module.out_proj.bias)
521
+ elif isinstance(module, SiglipMLP):
522
+ nn.init.xavier_uniform_(module.fc1.weight)
523
+ nn.init.xavier_uniform_(module.fc2.weight)
524
+ nn.init.normal_(module.fc1.bias, std=1e-6)
525
+ nn.init.normal_(module.fc2.bias, std=1e-6)
526
+ elif isinstance(module, SiglipMultiheadAttentionPoolingHead):
527
+ nn.init.xavier_uniform_(module.probe.data)
528
+ nn.init.xavier_uniform_(module.attention.in_proj_weight.data)
529
+ nn.init.zeros_(module.attention.in_proj_bias.data)
530
+ elif isinstance(module, SiglipModel):
531
+ logit_scale_init = torch.log(torch.tensor(1.0))
532
+ module.logit_scale.data.fill_(logit_scale_init)
533
+ module.logit_bias.data.zero_()
534
+ elif isinstance(module, SiglipForImageClassification):
535
+ nn.init.normal_(
536
+ module.classifier.weight,
537
+ std=self.config.vision_config.hidden_size**-0.5 * self.config.initializer_factor,
538
+ )
539
+ elif isinstance(module, (nn.Linear, nn.Conv2d)):
540
+ lecun_normal_(module.weight)
541
+ if module.bias is not None:
542
+ nn.init.zeros_(module.bias)
543
+ elif isinstance(module, nn.LayerNorm):
544
+ module.bias.data.zero_()
545
+ module.weight.data.fill_(1.0)
546
+
547
+
548
+ # Copied from transformers.models.altclip.modeling_altclip.AltCLIPEncoder with AltCLIP->Siglip
549
+ class SiglipEncoder(nn.Module):
550
+ """
551
+ Transformer encoder consisting of `config.num_hidden_layers` self attention layers. Each layer is a
552
+ [`SiglipEncoderLayer`].
553
+
554
+ Args:
555
+ config: SiglipConfig
556
+ """
557
+
558
+ def __init__(self, config: SiglipConfig):
559
+ super().__init__()
560
+ self.config = config
561
+ self.layers = nn.ModuleList([SiglipEncoderLayer(config) for _ in range(config.num_hidden_layers)])
562
+ self.gradient_checkpointing = False
563
+
564
+ # Ignore copy
565
+ @can_return_tuple
566
+ def forward(
567
+ self,
568
+ inputs_embeds,
569
+ attention_mask: Optional[torch.Tensor] = None,
570
+ output_attentions: Optional[bool] = None,
571
+ output_hidden_states: Optional[bool] = None,
572
+ ) -> BaseModelOutput:
573
+ r"""
574
+ Args:
575
+ inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
576
+ Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation.
577
+ This is useful if you want more control over how to convert `input_ids` indices into associated vectors
578
+ than the model's internal embedding lookup matrix.
579
+ attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
580
+ Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`:
581
+
582
+ - 1 for tokens that are **not masked**,
583
+ - 0 for tokens that are **masked**.
584
+
585
+ [What are attention masks?](../glossary#attention-mask)
586
+ output_attentions (`bool`, *optional*):
587
+ Whether or not to return the attentions tensors of all attention layers. See `attentions` under
588
+ returned tensors for more detail.
589
+ output_hidden_states (`bool`, *optional*):
590
+ Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors
591
+ for more detail.
592
+ return_dict (`bool`, *optional*):
593
+ Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
594
+ """
595
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
596
+ output_hidden_states = (
597
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
598
+ )
599
+
600
+ encoder_states = () if output_hidden_states else None
601
+ all_attentions = () if output_attentions else None
602
+
603
+ hidden_states = inputs_embeds
604
+ for encoder_layer in self.layers:
605
+ if output_hidden_states:
606
+ encoder_states = encoder_states + (hidden_states,)
607
+
608
+ layer_outputs = encoder_layer(
609
+ hidden_states,
610
+ attention_mask,
611
+ output_attentions=output_attentions,
612
+ )
613
+
614
+ hidden_states = layer_outputs[0]
615
+
616
+ if output_attentions:
617
+ all_attentions = all_attentions + (layer_outputs[1],)
618
+
619
+ if output_hidden_states:
620
+ encoder_states = encoder_states + (hidden_states,)
621
+
622
+ return BaseModelOutput(
623
+ last_hidden_state=hidden_states,
624
+ hidden_states=encoder_states,
625
+ attentions=all_attentions,
626
+ )
627
+
628
+
629
+ class SiglipTextTransformer(nn.Module):
630
+ def __init__(self, config: SiglipTextConfig):
631
+ super().__init__()
632
+ self.config = config
633
+ embed_dim = config.hidden_size
634
+ self.embeddings = SiglipTextEmbeddings(config)
635
+ self.encoder = SiglipEncoder(config)
636
+ self.final_layer_norm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps)
637
+
638
+ self.head = nn.Linear(embed_dim, config.projection_size)
639
+ self._use_flash_attention_2 = config._attn_implementation == "flash_attention_2"
640
+
641
+ @can_return_tuple
642
+ @auto_docstring
643
+ def forward(
644
+ self,
645
+ input_ids: Optional[torch.Tensor] = None,
646
+ attention_mask: Optional[torch.Tensor] = None,
647
+ position_ids: Optional[torch.Tensor] = None,
648
+ output_attentions: Optional[bool] = None,
649
+ output_hidden_states: Optional[bool] = None,
650
+ ) -> BaseModelOutputWithPooling:
651
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
652
+ output_hidden_states = (
653
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
654
+ )
655
+
656
+ if input_ids is None:
657
+ raise ValueError("You have to specify input_ids")
658
+
659
+ input_shape = input_ids.size()
660
+ input_ids = input_ids.view(-1, input_shape[-1])
661
+
662
+ hidden_states = self.embeddings(input_ids=input_ids, position_ids=position_ids)
663
+
664
+ # note: SigLIP's text model does not use a causal mask, unlike the original CLIP model.
665
+ # expand attention_mask
666
+ if attention_mask is not None and not self._use_flash_attention_2:
667
+ # [batch_size, seq_len] -> [batch_size, 1, tgt_seq_len, src_seq_len]
668
+ attention_mask = _prepare_4d_attention_mask(attention_mask, hidden_states.dtype)
669
+
670
+ encoder_outputs: BaseModelOutput = self.encoder(
671
+ inputs_embeds=hidden_states,
672
+ attention_mask=attention_mask,
673
+ output_attentions=output_attentions,
674
+ output_hidden_states=output_hidden_states,
675
+ )
676
+
677
+ last_hidden_state = encoder_outputs.last_hidden_state
678
+ last_hidden_state = self.final_layer_norm(last_hidden_state)
679
+
680
+ # Assuming "sticky" EOS tokenization, last token is always EOS.
681
+ pooled_output = last_hidden_state[:, -1, :]
682
+ pooled_output = self.head(pooled_output)
683
+
684
+ return BaseModelOutputWithPooling(
685
+ last_hidden_state=last_hidden_state,
686
+ pooler_output=pooled_output,
687
+ hidden_states=encoder_outputs.hidden_states,
688
+ attentions=encoder_outputs.attentions,
689
+ )
690
+
691
+
692
+ @auto_docstring(
693
+ custom_intro="""
694
+ The text model from SigLIP without any head or projection on top.
695
+ """
696
+ )
697
+ class SiglipTextModel(SiglipPreTrainedModel):
698
+ config_class = SiglipTextConfig
699
+
700
+ def __init__(self, config: SiglipTextConfig):
701
+ super().__init__(config)
702
+ self.text_model = SiglipTextTransformer(config)
703
+ # Initialize weights and apply final processing
704
+ self.post_init()
705
+
706
+ def get_input_embeddings(self) -> nn.Module:
707
+ return self.text_model.embeddings.token_embedding
708
+
709
+ def set_input_embeddings(self, value):
710
+ self.text_model.embeddings.token_embedding = value
711
+
712
+ @can_return_tuple
713
+ @auto_docstring
714
+ def forward(
715
+ self,
716
+ input_ids: Optional[torch.Tensor] = None,
717
+ attention_mask: Optional[torch.Tensor] = None,
718
+ position_ids: Optional[torch.Tensor] = None,
719
+ output_attentions: Optional[bool] = None,
720
+ output_hidden_states: Optional[bool] = None,
721
+ ) -> BaseModelOutputWithPooling:
722
+ r"""
723
+ Examples:
724
+
725
+ ```python
726
+ >>> from transformers import AutoTokenizer, SiglipTextModel
727
+
728
+ >>> model = SiglipTextModel.from_pretrained("google/siglip-base-patch16-224")
729
+ >>> tokenizer = AutoTokenizer.from_pretrained("google/siglip-base-patch16-224")
730
+
731
+ >>> # important: make sure to set padding="max_length" as that's how the model was trained
732
+ >>> inputs = tokenizer(["a photo of a cat", "a photo of a dog"], padding="max_length", return_tensors="pt")
733
+
734
+ >>> outputs = model(**inputs)
735
+ >>> last_hidden_state = outputs.last_hidden_state
736
+ >>> pooled_output = outputs.pooler_output # pooled (EOS token) states
737
+ ```"""
738
+
739
+ return self.text_model(
740
+ input_ids=input_ids,
741
+ attention_mask=attention_mask,
742
+ position_ids=position_ids,
743
+ output_attentions=output_attentions,
744
+ output_hidden_states=output_hidden_states,
745
+ )
746
+
747
+
748
+ class SiglipVisionTransformer(nn.Module):
749
+ def __init__(self, config: SiglipVisionConfig):
750
+ super().__init__()
751
+ self.config = config
752
+ embed_dim = config.hidden_size
753
+
754
+ self.embeddings = SiglipVisionEmbeddings(config)
755
+ self.encoder = SiglipEncoder(config)
756
+ self.post_layernorm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps)
757
+ self.use_head = True if not hasattr(config, "vision_use_head") else config.vision_use_head
758
+ if self.use_head:
759
+ self.head = SiglipMultiheadAttentionPoolingHead(config)
760
+
761
+ @can_return_tuple
762
+ @auto_docstring
763
+ def forward(
764
+ self,
765
+ pixel_values,
766
+ output_attentions: Optional[bool] = None,
767
+ output_hidden_states: Optional[bool] = None,
768
+ interpolate_pos_encoding: Optional[bool] = False,
769
+ ) -> BaseModelOutputWithPooling:
770
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
771
+ output_hidden_states = (
772
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
773
+ )
774
+
775
+ hidden_states = self.embeddings(pixel_values, interpolate_pos_encoding=interpolate_pos_encoding)
776
+ # Convert to bfloat16 if the encoder uses bfloat16
777
+ if len(self.encoder.layers) > 0 and self.encoder.layers[0].self_attn.q_proj.weight.dtype == torch.bfloat16:
778
+ hidden_states = hidden_states.to(torch.bfloat16)
779
+
780
+ encoder_outputs: BaseModelOutput = self.encoder(
781
+ inputs_embeds=hidden_states,
782
+ output_attentions=output_attentions,
783
+ output_hidden_states=output_hidden_states,
784
+ )
785
+
786
+ last_hidden_state = encoder_outputs.last_hidden_state
787
+ last_hidden_state = self.post_layernorm(last_hidden_state)
788
+
789
+ pooler_output = self.head(last_hidden_state) if self.use_head else None
790
+
791
+ return BaseModelOutputWithPooling(
792
+ last_hidden_state=last_hidden_state,
793
+ pooler_output=pooler_output,
794
+ hidden_states=encoder_outputs.hidden_states,
795
+ attentions=encoder_outputs.attentions,
796
+ )
797
+
798
+
799
+ class SiglipMultiheadAttentionPoolingHead(nn.Module):
800
+ """Multihead Attention Pooling."""
801
+
802
+ def __init__(self, config: SiglipVisionConfig):
803
+ super().__init__()
804
+
805
+ self.probe = nn.Parameter(torch.randn(1, 1, config.hidden_size))
806
+ self.attention = torch.nn.MultiheadAttention(config.hidden_size, config.num_attention_heads, batch_first=True)
807
+ self.layernorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
808
+ self.mlp = SiglipMLP(config)
809
+
810
+ def forward(self, hidden_state):
811
+ batch_size = hidden_state.shape[0]
812
+ probe = self.probe.repeat(batch_size, 1, 1)
813
+
814
+ hidden_state = self.attention(probe, hidden_state, hidden_state)[0]
815
+
816
+ residual = hidden_state
817
+ hidden_state = self.layernorm(hidden_state)
818
+ hidden_state = residual + self.mlp(hidden_state)
819
+
820
+ return hidden_state[:, 0]
821
+
822
+
823
+ @auto_docstring(
824
+ custom_intro="""
825
+ The vision model from SigLIP without any head or projection on top.
826
+ """
827
+ )
828
+ class SiglipVisionModel(SiglipPreTrainedModel):
829
+ config_class = SiglipVisionConfig
830
+ main_input_name = "pixel_values"
831
+
832
+ def __init__(self, config: SiglipVisionConfig):
833
+ super().__init__(config)
834
+
835
+ self.vision_model = SiglipVisionTransformer(config)
836
+
837
+ # Initialize weights and apply final processing
838
+ self.post_init()
839
+
840
+ def get_input_embeddings(self) -> nn.Module:
841
+ return self.vision_model.embeddings.patch_embedding
842
+
843
+ @can_return_tuple
844
+ @auto_docstring
845
+ def forward(
846
+ self,
847
+ pixel_values,
848
+ output_attentions: Optional[bool] = None,
849
+ output_hidden_states: Optional[bool] = None,
850
+ interpolate_pos_encoding: bool = False,
851
+ ) -> BaseModelOutputWithPooling:
852
+ r"""
853
+ Examples:
854
+
855
+ ```python
856
+ >>> from PIL import Image
857
+ >>> import requests
858
+ >>> from transformers import AutoProcessor, SiglipVisionModel
859
+
860
+ >>> model = SiglipVisionModel.from_pretrained("google/siglip-base-patch16-224")
861
+ >>> processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-224")
862
+
863
+ >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
864
+ >>> image = Image.open(requests.get(url, stream=True).raw)
865
+
866
+ >>> inputs = processor(images=image, return_tensors="pt")
867
+
868
+ >>> outputs = model(**inputs)
869
+ >>> last_hidden_state = outputs.last_hidden_state
870
+ >>> pooled_output = outputs.pooler_output # pooled features
871
+ ```"""
872
+
873
+ return self.vision_model(
874
+ pixel_values=pixel_values,
875
+ output_attentions=output_attentions,
876
+ output_hidden_states=output_hidden_states,
877
+ interpolate_pos_encoding=interpolate_pos_encoding,
878
+ )
879
+
880
+
881
+ @auto_docstring
882
+ class SiglipModel(SiglipPreTrainedModel):
883
+ config_class = SiglipConfig
884
+
885
+ def __init__(self, config: SiglipConfig):
886
+ super().__init__(config)
887
+
888
+ if not isinstance(config.text_config, SiglipTextConfig):
889
+ raise TypeError(
890
+ "config.text_config is expected to be of type SiglipTextConfig but is of type"
891
+ f" {type(config.text_config)}."
892
+ )
893
+
894
+ if not isinstance(config.vision_config, SiglipVisionConfig):
895
+ raise TypeError(
896
+ "config.vision_config is expected to be of type SiglipVisionConfig but is of type"
897
+ f" {type(config.vision_config)}."
898
+ )
899
+
900
+ text_config = config.text_config
901
+ vision_config = config.vision_config
902
+
903
+ # First, initialize the text and vision models with proper attention implementation
904
+ text_model = SiglipTextModel._from_config(text_config)
905
+ vision_model = SiglipVisionModel._from_config(vision_config)
906
+
907
+ # Second, get the text and vision submodules (for backward compatibility)
908
+ self.text_model = text_model.text_model
909
+ self.vision_model = vision_model.vision_model
910
+
911
+ self.logit_scale = nn.Parameter(torch.randn(1))
912
+ self.logit_bias = nn.Parameter(torch.randn(1))
913
+
914
+ # Initialize weights and apply final processing
915
+ self.post_init()
916
+
917
+ @auto_docstring
918
+ def get_text_features(
919
+ self,
920
+ input_ids: Optional[torch.Tensor] = None,
921
+ attention_mask: Optional[torch.Tensor] = None,
922
+ position_ids: Optional[torch.Tensor] = None,
923
+ output_attentions: Optional[bool] = None,
924
+ output_hidden_states: Optional[bool] = None,
925
+ ) -> torch.FloatTensor:
926
+ r"""
927
+ Returns:
928
+ text_features (`torch.FloatTensor` of shape `(batch_size, output_dim`): The text embeddings obtained by
929
+ applying the projection layer to the pooled output of [`SiglipTextModel`].
930
+
931
+ Examples:
932
+
933
+ ```python
934
+ >>> from transformers import AutoTokenizer, AutoModel
935
+ >>> import torch
936
+
937
+ >>> model = AutoModel.from_pretrained("google/siglip-base-patch16-224")
938
+ >>> tokenizer = AutoTokenizer.from_pretrained("google/siglip-base-patch16-224")
939
+
940
+ >>> # important: make sure to set padding="max_length" as that's how the model was trained
941
+ >>> inputs = tokenizer(["a photo of a cat", "a photo of a dog"], padding="max_length", return_tensors="pt")
942
+ >>> with torch.no_grad():
943
+ ... text_features = model.get_text_features(**inputs)
944
+ ```"""
945
+ # Use SigLIP model's config for some fields (if specified) instead of those of vision & text components.
946
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
947
+ output_hidden_states = (
948
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
949
+ )
950
+
951
+ text_outputs: BaseModelOutputWithPooling = self.text_model(
952
+ input_ids=input_ids,
953
+ attention_mask=attention_mask,
954
+ position_ids=position_ids,
955
+ output_attentions=output_attentions,
956
+ output_hidden_states=output_hidden_states,
957
+ )
958
+
959
+ pooled_output = text_outputs.pooler_output
960
+
961
+ return pooled_output
962
+
963
+ @auto_docstring
964
+ def get_image_features(
965
+ self,
966
+ pixel_values: Optional[torch.FloatTensor] = None,
967
+ output_attentions: Optional[bool] = None,
968
+ output_hidden_states: Optional[bool] = None,
969
+ interpolate_pos_encoding: bool = False,
970
+ ) -> torch.FloatTensor:
971
+ r"""
972
+ Returns:
973
+ image_features (`torch.FloatTensor` of shape `(batch_size, output_dim`): The image embeddings obtained by
974
+ applying the projection layer to the pooled output of [`SiglipVisionModel`].
975
+
976
+ Examples:
977
+
978
+ ```python
979
+ >>> from PIL import Image
980
+ >>> import requests
981
+ >>> from transformers import AutoProcessor, AutoModel
982
+ >>> import torch
983
+
984
+ >>> model = AutoModel.from_pretrained("google/siglip-base-patch16-224")
985
+ >>> processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-224")
986
+
987
+ >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
988
+ >>> image = Image.open(requests.get(url, stream=True).raw)
989
+
990
+ >>> inputs = processor(images=image, return_tensors="pt")
991
+
992
+ >>> with torch.no_grad():
993
+ ... image_features = model.get_image_features(**inputs)
994
+ ```"""
995
+ # Use SiglipModel's config for some fields (if specified) instead of those of vision & text components.
996
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
997
+ output_hidden_states = (
998
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
999
+ )
1000
+
1001
+ vision_outputs: BaseModelOutputWithPooling = self.vision_model(
1002
+ pixel_values=pixel_values,
1003
+ output_attentions=output_attentions,
1004
+ output_hidden_states=output_hidden_states,
1005
+ interpolate_pos_encoding=interpolate_pos_encoding,
1006
+ )
1007
+
1008
+ pooled_output = vision_outputs.pooler_output
1009
+
1010
+ return pooled_output
1011
+
1012
+ @can_return_tuple
1013
+ @auto_docstring
1014
+ def forward(
1015
+ self,
1016
+ input_ids: Optional[torch.LongTensor] = None,
1017
+ pixel_values: Optional[torch.FloatTensor] = None,
1018
+ attention_mask: Optional[torch.Tensor] = None,
1019
+ position_ids: Optional[torch.LongTensor] = None,
1020
+ return_loss: Optional[bool] = None,
1021
+ output_attentions: Optional[bool] = None,
1022
+ output_hidden_states: Optional[bool] = None,
1023
+ interpolate_pos_encoding: bool = False,
1024
+ ) -> SiglipOutput:
1025
+ r"""
1026
+ return_loss (`bool`, *optional*):
1027
+ Whether or not to return the contrastive loss.
1028
+
1029
+ Examples:
1030
+
1031
+ ```python
1032
+ >>> from PIL import Image
1033
+ >>> import requests
1034
+ >>> from transformers import AutoProcessor, AutoModel
1035
+ >>> import torch
1036
+
1037
+ >>> model = AutoModel.from_pretrained("google/siglip-base-patch16-224")
1038
+ >>> processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-224")
1039
+
1040
+ >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
1041
+ >>> image = Image.open(requests.get(url, stream=True).raw)
1042
+
1043
+ >>> texts = ["a photo of 2 cats", "a photo of 2 dogs"]
1044
+ >>> # important: we pass `padding=max_length` since the model was trained with this
1045
+ >>> inputs = processor(text=texts, images=image, padding="max_length", return_tensors="pt")
1046
+
1047
+ >>> with torch.no_grad():
1048
+ ... outputs = model(**inputs)
1049
+
1050
+ >>> logits_per_image = outputs.logits_per_image
1051
+ >>> probs = torch.sigmoid(logits_per_image) # these are the probabilities
1052
+ >>> print(f"{probs[0][0]:.1%} that image 0 is '{texts[0]}'")
1053
+ 31.9% that image 0 is 'a photo of 2 cats'
1054
+ ```"""
1055
+ # Use SigLIP model's config for some fields (if specified) instead of those of vision & text components.
1056
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
1057
+ output_hidden_states = (
1058
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
1059
+ )
1060
+
1061
+ vision_outputs: BaseModelOutputWithPooling = self.vision_model(
1062
+ pixel_values=pixel_values,
1063
+ output_attentions=output_attentions,
1064
+ output_hidden_states=output_hidden_states,
1065
+ interpolate_pos_encoding=interpolate_pos_encoding,
1066
+ )
1067
+
1068
+ text_outputs: BaseModelOutputWithPooling = self.text_model(
1069
+ input_ids=input_ids,
1070
+ attention_mask=attention_mask,
1071
+ position_ids=position_ids,
1072
+ output_attentions=output_attentions,
1073
+ output_hidden_states=output_hidden_states,
1074
+ )
1075
+
1076
+ image_embeds = vision_outputs.pooler_output
1077
+ text_embeds = text_outputs.pooler_output
1078
+
1079
+ # normalized features
1080
+ image_embeds = image_embeds / image_embeds.norm(p=2, dim=-1, keepdim=True)
1081
+ text_embeds = text_embeds / text_embeds.norm(p=2, dim=-1, keepdim=True)
1082
+
1083
+ # cosine similarity as logits
1084
+ logits_per_text = torch.matmul(text_embeds, image_embeds.t().to(text_embeds.device))
1085
+
1086
+ logit_scale, logit_bias = self.logit_scale.to(text_embeds.device), self.logit_bias.to(text_embeds.device)
1087
+ logits_per_text = logits_per_text * logit_scale.exp() + logit_bias
1088
+
1089
+ logits_per_image = logits_per_text.t()
1090
+
1091
+ loss = None
1092
+ if return_loss:
1093
+ # Adapted from https://github.com/google-research/big_vision/blob/01edb81a4716f93a48be43b3a4af14e29cdb3a7f/big_vision/trainers/proj/image_text/siglip.py#L287
1094
+ eye = torch.eye(logits_per_text.size(0), device=logits_per_text.device)
1095
+ m1_diag1 = -torch.ones_like(logits_per_text) + 2 * eye
1096
+ loglik = torch.nn.functional.logsigmoid(m1_diag1 * logits_per_text)
1097
+ nll = -torch.sum(loglik, dim=-1)
1098
+ loss = nll.mean()
1099
+
1100
+ return SiglipOutput(
1101
+ loss=loss,
1102
+ logits_per_image=logits_per_image,
1103
+ logits_per_text=logits_per_text,
1104
+ text_embeds=text_embeds,
1105
+ image_embeds=image_embeds,
1106
+ text_model_output=text_outputs,
1107
+ vision_model_output=vision_outputs,
1108
+ )
1109
+
1110
+
1111
+ @auto_docstring(
1112
+ custom_intro="""
1113
+ SigLIP vision encoder with an image classification head on top (a linear layer on top of the pooled final hidden states of
1114
+ the patch tokens) e.g. for ImageNet.
1115
+ """
1116
+ )
1117
+ class SiglipForImageClassification(SiglipPreTrainedModel):
1118
+ main_input_name = "pixel_values"
1119
+
1120
+ def __init__(self, config: SiglipConfig) -> None:
1121
+ super().__init__(config)
1122
+
1123
+ self.num_labels = config.num_labels
1124
+
1125
+ # Create the vision model with proper attention
1126
+ # and take only vision_model submodule (for backward compatibility)
1127
+ vision_model = SiglipVisionModel._from_config(config.vision_config)
1128
+ self.vision_model = vision_model.vision_model
1129
+
1130
+ # Classifier head
1131
+ self.classifier = (
1132
+ nn.Linear(config.vision_config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
1133
+ )
1134
+
1135
+ # Initialize weights and apply final processing
1136
+ self.post_init()
1137
+
1138
+ @can_return_tuple
1139
+ @auto_docstring
1140
+ def forward(
1141
+ self,
1142
+ pixel_values: Optional[torch.Tensor] = None,
1143
+ labels: Optional[torch.Tensor] = None,
1144
+ output_attentions: Optional[bool] = None,
1145
+ output_hidden_states: Optional[bool] = None,
1146
+ interpolate_pos_encoding: bool = False,
1147
+ ) -> ImageClassifierOutput:
1148
+ r"""
1149
+ labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
1150
+ Labels for computing the image classification/regression loss. Indices should be in `[0, ...,
1151
+ config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
1152
+ `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
1153
+
1154
+ Examples:
1155
+
1156
+ ```python
1157
+ >>> from transformers import AutoImageProcessor, SiglipForImageClassification
1158
+ >>> import torch
1159
+ >>> from PIL import Image
1160
+ >>> import requests
1161
+
1162
+ >>> torch.manual_seed(3) # doctest: +IGNORE_RESULT
1163
+ >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
1164
+ >>> image = Image.open(requests.get(url, stream=True).raw)
1165
+
1166
+ >>> # note: we are loading a `SiglipModel` from the hub here,
1167
+ >>> # so the head will be randomly initialized, hence the predictions will be random if seed is not set above.
1168
+ >>> image_processor = AutoImageProcessor.from_pretrained("google/siglip-base-patch16-224")
1169
+ >>> model = SiglipForImageClassification.from_pretrained("google/siglip-base-patch16-224")
1170
+
1171
+ >>> inputs = image_processor(images=image, return_tensors="pt")
1172
+ >>> outputs = model(**inputs)
1173
+ >>> logits = outputs.logits
1174
+ >>> # model predicts one of the two classes
1175
+ >>> predicted_class_idx = logits.argmax(-1).item()
1176
+ >>> print("Predicted class:", model.config.id2label[predicted_class_idx])
1177
+ Predicted class: LABEL_1
1178
+ ```"""
1179
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
1180
+ output_hidden_states = (
1181
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
1182
+ )
1183
+
1184
+ outputs: BaseModelOutputWithPooling = self.vision_model(
1185
+ pixel_values,
1186
+ output_attentions=output_attentions,
1187
+ output_hidden_states=output_hidden_states,
1188
+ interpolate_pos_encoding=interpolate_pos_encoding,
1189
+ )
1190
+
1191
+ sequence_output = outputs.last_hidden_state
1192
+
1193
+ # average pool the patch tokens
1194
+ sequence_output = torch.mean(sequence_output, dim=1)
1195
+ # apply classifier
1196
+ logits = self.classifier(sequence_output)
1197
+
1198
+ loss = None
1199
+ if labels is not None:
1200
+ # move labels to correct device to enable model parallelism
1201
+ labels = labels.to(logits.device)
1202
+ if self.config.problem_type is None:
1203
+ if self.num_labels == 1:
1204
+ self.config.problem_type = "regression"
1205
+ elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
1206
+ self.config.problem_type = "single_label_classification"
1207
+ else:
1208
+ self.config.problem_type = "multi_label_classification"
1209
+
1210
+ if self.config.problem_type == "regression":
1211
+ loss_fct = MSELoss()
1212
+ if self.num_labels == 1:
1213
+ loss = loss_fct(logits.squeeze(), labels.squeeze())
1214
+ else:
1215
+ loss = loss_fct(logits, labels)
1216
+ elif self.config.problem_type == "single_label_classification":
1217
+ loss_fct = CrossEntropyLoss()
1218
+ loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
1219
+ elif self.config.problem_type == "multi_label_classification":
1220
+ loss_fct = BCEWithLogitsLoss()
1221
+ loss = loss_fct(logits, labels)
1222
+
1223
+ return ImageClassifierOutput(
1224
+ loss=loss,
1225
+ logits=logits,
1226
+ hidden_states=outputs.hidden_states,
1227
+ attentions=outputs.attentions,
1228
+ )
1229
+
1230
+
1231
+ __all__ = [
1232
+ "SiglipModel",
1233
+ "SiglipPreTrainedModel",
1234
+ "SiglipTextModel",
1235
+ "SiglipVisionModel",
1236
+ "SiglipForImageClassification",
1237
+ ]
pi05_twotasks_pytorch/code/openpi-main/src/openpi/policies/__pycache__/aloha_policy.cpython-311.pyc ADDED
Binary file (15.6 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/policies/__pycache__/droid_policy.cpython-311.pyc ADDED
Binary file (5.1 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/policies/__pycache__/franka_ee_policy.cpython-310.pyc ADDED
Binary file (4.08 kB). View file
 
pi05_twotasks_pytorch/code/openpi-main/src/openpi/policies/__pycache__/franka_ee_policy.cpython-311.pyc ADDED
Binary file (8.01 kB). View file