1use super::config::ESMFold2Config;
4#[allow(unused_imports)]
5use super::layers::{
6 atom_encoder::AtomEncoder, confidence_head::{ConfidenceHead, bins_to_scalar},
8 diffusion::DiffusionModule,
9 folding_trunk::FoldingTrunk,
10 lm_encoder::LMEncoder,
11};
12use super::output::ESMFold2Output;
13use candle_core::{DType, Device, Result, Tensor};
14use candle_nn::VarBuilder;
15
16pub struct ESMFold2Model {
21 config: ESMFold2Config,
22 lm_encoder: LMEncoder,
23 folding_trunk: FoldingTrunk,
24 diffusion: DiffusionModule,
25 confidence_head: ConfidenceHead,
26 device: Device,
27}
28
29impl ESMFold2Model {
30 pub fn load(vb: VarBuilder, config: ESMFold2Config) -> Result<Self> {
36 let device = vb.device().clone();
37
38 let lm_encoder = LMEncoder::load(
39 vb.pp("lm_encoder"),
40 config.lm_d_model,
41 config.d_single,
42 config.lm_encoder_n_layers,
43 )?;
44
45 let folding_trunk = FoldingTrunk::load(
46 vb.pp("folding_trunk"),
47 config.trunk_n_layers,
48 config.d_single,
49 config.d_pair,
50 config.trunk_n_heads,
51 )?;
52
53 let diffusion = DiffusionModule::load(
54 vb.pp("structure_head"),
55 config.c_token,
56 config.c_atom,
57 config.d_single,
58 config.d_pair,
59 config.token_num_blocks,
60 config.token_num_heads,
61 config.fourier_dim,
62 )?;
63
64 let confidence_head = ConfidenceHead::load(
65 vb.pp("confidence_head"),
66 config.d_single,
67 config.d_pair,
68 config.num_plddt_bins,
69 config.num_pae_bins,
70 config.num_pde_bins,
71 config.distogram_bins,
72 )?;
73
74 Ok(Self {
75 config,
76 lm_encoder,
77 folding_trunk,
78 diffusion,
79 confidence_head,
80 device,
81 })
82 }
83
84 pub fn forward(
96 &self,
97 hidden_states: &Tensor,
98 residue_indices: &Tensor,
99 chain_ids: &Tensor,
100 num_loops: usize,
101 num_steps: usize,
102 ) -> Result<ESMFold2Output> {
103 let (b, l, _) = hidden_states.dims3()?;
104
105 let mut single = self.lm_encoder.forward(hidden_states)?;
107
108 let mut pair = self
110 .folding_trunk
111 .init_pair(&single, residue_indices, chain_ids)?;
112
113 for _ in 0..num_loops {
115 let (s, p) = self.folding_trunk.forward(&single, &pair)?;
116 single = s;
117 pair = p;
118 }
119
120 let coords = self.diffusion.forward(&single, &pair, l, num_steps)?;
122
123 let conf = self.confidence_head.forward(&single, &pair)?;
125
126 let pae = conf
128 .pae_logits
129 .map(|t| bins_to_scalar(&t, 0.0, 32.0))
130 .transpose()?;
131
132 let ptm = Tensor::zeros(b, DType::F32, &self.device)?;
134 let iptm = Tensor::zeros(b, DType::F32, &self.device)?;
135
136 Ok(ESMFold2Output {
137 sample_atom_coords: coords,
138 plddt: conf.plddt,
139 ptm,
140 iptm,
141 pae,
142 distogram_logits: conf.distogram_logits,
143 })
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use candle_core::Device;
151
152 fn make_model(device: &Device) -> ESMFold2Model {
153 use super::super::config::ESMFold2Config;
154 let cfg = ESMFold2Config {
155 lm_d_model: 64,
156 lm_encoder_n_layers: 1,
157 d_single: 32,
158 d_pair: 16,
159 trunk_n_layers: 1,
160 trunk_n_heads: 2,
161 c_token: 32,
162 c_atom: 16,
163 token_num_blocks: 1,
164 token_num_heads: 2,
165 fourier_dim: 16,
166 num_plddt_bins: 50,
167 num_pae_bins: 64,
168 num_pde_bins: 64,
169 distogram_bins: 39,
170 ..ESMFold2Config::fast()
171 };
172 let vb = VarBuilder::zeros(DType::F32, device);
173 ESMFold2Model::load(vb, cfg).unwrap()
174 }
175
176 #[test]
177 fn test_forward_output_shapes() {
178 let device = Device::Cpu;
179 let model = make_model(&device);
180
181 let b = 1usize;
182 let l = 8usize;
183 let hidden = Tensor::zeros(&[b, l, 64], DType::F32, &device).unwrap();
184 let res_idx: Vec<f32> = (0..l).map(|i| i as f32).collect();
185 let residue_indices = Tensor::from_vec(res_idx, &[b, l], &device).unwrap();
186 let chain_ids = Tensor::zeros(&[b, l], DType::F32, &device).unwrap();
187
188 let out = model
189 .forward(&hidden, &residue_indices, &chain_ids, 1, 2)
190 .unwrap();
191
192 assert_eq!(out.sample_atom_coords.dims(), &[b, l, 3]);
193 assert_eq!(out.plddt.dims(), &[b, l]);
194 assert_eq!(out.ptm.dims(), &[b]);
195 assert_eq!(out.iptm.dims(), &[b]);
196 }
197}