MolecularDiffusion.modules.models.ipdiff.score_model¶
IPDiff’s score network: KGDiff/TargetDiff’s, plus an interaction prior.
Ported from IPDiff’s models/molopt_score_model.py (commit 00ed078).
That file is TargetDiff’s ScorePosNet3D with four additions, so rather
than re-porting ~700 lines this subclasses the already-in-tree
ScorePosNet3D (itself a TargetDiff
port) and overrides only what genuinely differs:
Member |
IPDiff’s change |
|---|---|
|
no affinity head; adds |
|
concatenates IPNet’s features into the protein and ligand token embeddings before the node indicator |
|
the affinity head is gone (see |
|
the matching |
|
|
|
|
Everything else – the beta schedules, the whole D3PM q_v_* family,
_predict_x0_from_eps, sample_time, compute_v_Lt and forward
– is inherited unchanged, because IPDiff did not change it.
The two mechanisms, in one place. Let a_bar be the cumulative alpha
and s_t = shift_t_mlp_pos([h_bap_ligand, t]):
prior conditioning –
h = emb_mlp([h, h_bap])on every token, so the denoiser sees the interaction representation directly;prior shifting – the forward process becomes
x_t = sqrt(a_bar) x0 + sqrt(1-a_bar) eps + k_t s_twithk_t = sqrt(a_bar)(1 - sqrt(a_bar)), i.e. the noising trajectory itself bends toward the prior, and the reverse posterior undoes it exactly.
There is no classifier, no CFG, and no gradient of any predictor: unlike
KGDiff, the parent’s use_classifier_guide machinery is switched off and
its expert_pred head is deleted outright (the released IPDiff checkpoint
has no such tensors).
Passing h_bap into an inherited ``forward``. The parent’s forward
calls self._embed(...) with a fixed argument list, so the conditioning
features are handed over on self (hbap_protein /
hbap_ligand) immediately before each call rather than threaded
through the signature. None means “no prior” and reproduces upstream’s
zero-fill (molopt_score_model.py:321-324).
Classes¶
TargetDiff's denoiser conditioned on a frozen interaction prior. |
Module Contents¶
- class MolecularDiffusion.modules.models.ipdiff.score_model.IPDiffScorePosNet3D(cond_dim: int = 128, **kwargs: Any)¶
Bases:
MolecularDiffusion.modules.models.kgdiff.score_model.ScorePosNet3DTargetDiff’s denoiser conditioned on a frozen interaction prior.
- get_diffusion_loss(net_cond, protein_pos, protein_v, batch_protein, ligand_pos, ligand_v, batch_ligand, time_step=None) dict¶
loss_pos + loss_v_weight * loss_v, with prior shifting.h_bapis computed ONCE, from the ground-truth complex – the training-time counterpart of the sampler’s per-step recomputation.
- q_pos_posterior(x0, xt, t, batch, t_minus1=None, shift=None, shift_minus1=None)¶
TargetDiff’s posterior mean, un-shifted at
tand re-shifted att-1.With no shift (the first reverse step, and
t == 0) this is exactly the parent’s expression. Upstream’s middle branch (molopt_score_model.py:415-417) is unreachable – the outer condition already excludesshift is None– so it is not ported.
- sample_diffusion(protein_pos, protein_v, batch_protein, init_ligand_pos, init_ligand_v, batch_ligand, net_cond=None, num_steps: int | None = None, center_pos_mode: str | None = None, progress: bool = True, **_ignored: Any) dict¶
Ancestral DDPM reverse loop with per-step prior re-conditioning.
Each step predicts x0, takes the shifted posterior, then re-runs IPNet on
(predicted x0, the real pocket)so the next step’s conditioning reflects the molecule as it currently stands. That second IPNet pass is the expensive part – it builds a fully connected complex graph every step (seebapnet.py).Trajectories (
pos_traj/v_traj) are deliberately not accumulated: the platform’s GIF path is out of scope for this port and keeping them costsnum_stepscopies of the cloud.
- cond_dim = 128¶
- emb_mlp¶
- hbap_ligand: torch.Tensor | None = None¶
- hbap_protein: torch.Tensor | None = None¶
- k_t¶
- shift_t_mlp_pos¶