|
|
|
|
| """Distogram head.""" |
|
|
| from typing import Final |
|
|
| from flax_model.alphafold3.common import base_config |
| from flax_model.alphafold3.model import feat_batch |
| from flax_model.alphafold3.model import model_config |
| from flax_model.alphafold3.model.components import haiku_modules as hm |
| import haiku as hk |
| import jax |
| import jax.numpy as jnp |
|
|
|
|
| _CONTACT_THRESHOLD: Final[float] = 8.0 |
| _CONTACT_EPSILON: Final[float] = 1e-3 |
|
|
|
|
| class DistogramHead(hk.Module): |
| """Distogram head.""" |
|
|
| class Config(base_config.BaseConfig): |
| first_break: float = 2.3125 |
| last_break: float = 21.6875 |
| num_bins: int = 64 |
|
|
| def __init__( |
| self, |
| config: Config, |
| global_config: model_config.GlobalConfig, |
| name='distogram_head', |
| ): |
| super().__init__(name=name) |
| self.config = config |
| self.global_config = global_config |
|
|
| def __call__( |
| self, |
| batch: feat_batch.Batch, |
| embeddings: dict[str, jnp.ndarray], |
| return_distogram: bool = False, |
| ) -> dict[str, jnp.ndarray]: |
| pair_act = embeddings['pair'] |
| seq_mask = batch.token_features.mask.astype(bool) |
| pair_mask = seq_mask[:, None] * seq_mask[None, :] |
|
|
| left_half_logits = hm.Linear( |
| self.config.num_bins, |
| initializer=self.global_config.final_init, |
| name='half_logits', |
| )(pair_act) |
|
|
| right_half_logits = left_half_logits |
| logits = left_half_logits + jnp.swapaxes(right_half_logits, -2, -3) |
| probs = jax.nn.softmax(logits, axis=-1) |
| breaks = jnp.linspace( |
| self.config.first_break, |
| self.config.last_break, |
| self.config.num_bins - 1, |
| ) |
|
|
| bin_tops = jnp.append(breaks, breaks[-1] + (breaks[-1] - breaks[-2])) |
| threshold = _CONTACT_THRESHOLD + _CONTACT_EPSILON |
| is_contact_bin = 1.0 * (bin_tops <= threshold) |
| contact_probs = jnp.einsum( |
| 'ijk,k->ij', probs, is_contact_bin, precision=jax.lax.Precision.HIGHEST |
| ) |
| contact_probs = pair_mask * contact_probs |
|
|
| return_dict = {'bin_edges': breaks, 'contact_probs': contact_probs} |
| if return_distogram: |
| return_dict['distogram'] = logits |
|
|
| return return_dict |
|
|