A Transformer Encoder with interleaved self-attention and cross-attention. This architecture processes a primary sequence `x` (e.g., text) by alternating between self-attention blocks (to process `x` itself) and cross-attention blocks (to infuse information from a context sequence `u`,
| 283 | |
| 284 | |
| 285 | class CrossAttnEncoder(nn.Module): |
| 286 | """A Transformer Encoder with interleaved self-attention and cross-attention. |
| 287 | |
| 288 | This architecture processes a primary sequence `x` (e.g., text) by alternating |
| 289 | between self-attention blocks (to process `x` itself) and cross-attention |
| 290 | blocks (to infuse information from a context sequence `u`, e.g., an image). |
| 291 | |
| 292 | Attributes: |
| 293 | depth: The total number of layers. Each "layer" consists of one |
| 294 | self-attention block and one cross-attention block. |
| 295 | remat_policy: Gradient checkpointing policy ('none', 'minimal', etc.). |
| 296 | """ |
| 297 | depth: int |
| 298 | mlp_dim: Optional[int] = None |
| 299 | num_heads: int = 12 |
| 300 | dropout: float = 0.0 |
| 301 | drop_path: float = 0.0 |
| 302 | remat_policy: str = "none" |
| 303 | casual_mask: bool = False |
| 304 | use_flash_attn: bool = False |
| 305 | dtype: Optional[Dtype] = jnp.float32 |
| 306 | param_dtype: Dtype = jnp.float32 |
| 307 | mesh: Optional[Any] = None |
| 308 | |
| 309 | @nn.compact |
| 310 | def __call__(self, x: Array, u: Array, deterministic: bool = True) -> Tuple[Array, dict]: |
| 311 | out = {} |
| 312 | # Linearly increasing drop path rate for stochastic depth |
| 313 | dpr = [rate.item() for rate in np.linspace(0, self.drop_path, self.depth)] |
| 314 | |
| 315 | # Configure gradient checkpointing (remat) if specified |
| 316 | if self.remat_policy not in (None, "none"): |
| 317 | policy = (jax.checkpoint_policies.checkpoint_dots_with_no_batch_dims |
| 318 | if self.remat_policy == "minimal" else None) |
| 319 | logging.info(f"Applying activation checkpointing: {self.remat_policy}") |
| 320 | SelfAttnBlock = nn.remat( |
| 321 | Encoder1DBlock, prevent_cse=True, policy=policy, static_argnums=(1,)) |
| 322 | CrossAttnBlock = nn.remat( |
| 323 | CrossAttnEncoder1DBlock, prevent_cse=True, policy=policy, static_argnums=(2,)) |
| 324 | else: |
| 325 | SelfAttnBlock = Encoder1DBlock |
| 326 | CrossAttnBlock = CrossAttnEncoder1DBlock |
| 327 | |
| 328 | for i in range(self.depth): |
| 329 | # 1. Self-attention on text embeddings `x` |
| 330 | x, out[f"self_attn_block_{i:02d}"] = SelfAttnBlock( |
| 331 | name=f"self_attn_block_{i}", |
| 332 | mlp_dim=self.mlp_dim, |
| 333 | depth=self.depth, |
| 334 | num_heads=self.num_heads, |
| 335 | dropout=self.dropout, |
| 336 | drop_path=dpr[i], |
| 337 | casual_mask=self.casual_mask, |
| 338 | use_flash_attn=self.use_flash_attn, |
| 339 | dtype=self.dtype, |
| 340 | param_dtype=self.param_dtype, |
| 341 | mesh=self.mesh |
| 342 | )(x, deterministic) |