ferritin_plms/esm3/layers/
blocks.rs1use crate::esm3::models::esm3::ESM3Config;
4use crate::esm3::utils::affine3d::Affine3D;
5use crate::esmc::layers::attention::MultiHeadAttention;
6use crate::esmc::layers::geom_attention::GeometricReasoningOriginalImpl;
7use crate::esmc::models::esmc::{ESMCConfig, ESMTokenizer, FfnType};
8use candle_core::{D, Module, Result, Tensor};
9use candle_nn::{self as nn, VarBuilder};
10
11pub struct SwiGLU {
14 layer_norm: nn::LayerNorm,
15 linear1: nn::Linear,
16 linear2: nn::Linear,
17}
18
19impl SwiGLU {
20 fn hidden_dim(expansion_ratio: f64, d_model: usize) -> usize {
21 ((expansion_ratio * d_model as f64 + 255.0) / 256.0).floor() as usize * 256
22 }
23
24 pub fn load(vb: VarBuilder, config: &ESM3Config) -> Result<Self> {
25 let hidden = Self::hidden_dim(config.expansion_ratio, config.d_model);
26 Ok(Self {
27 layer_norm: nn::layer_norm(config.d_model, 1e-5, vb.pp("0"))?,
28 linear1: nn::linear_no_bias(config.d_model, hidden * 2, vb.pp("1"))?,
29 linear2: nn::linear_no_bias(hidden, config.d_model, vb.pp("3"))?,
30 })
31 }
32}
33
34impl Module for SwiGLU {
35 fn forward(&self, x: &Tensor) -> Result<Tensor> {
36 let x = self.layer_norm.forward(x)?;
37 let x = self.linear1.forward(&x)?;
38 let chunks = x.chunk(2, D::Minus1)?;
39 self.linear2.forward(&(chunks[0].silu()? * &chunks[1])?)
40 }
41}
42
43pub struct UnifiedTransformerBlock {
46 attn: MultiHeadAttention,
47 geom_attn: Option<GeometricReasoningOriginalImpl>,
48 ffn: SwiGLU,
49 scaling_factor: f64,
50}
51
52impl UnifiedTransformerBlock {
53 pub fn load(vb: VarBuilder, config: &ESM3Config, layer_idx: usize) -> Result<Self> {
54 let esmc_cfg = esmc_config_from_esm3(config);
56
57 let attn = MultiHeadAttention::load(vb.pp("attn"), &esmc_cfg)?;
58
59 let geom_attn = if layer_idx < config.n_layers_geom {
60 Some(GeometricReasoningOriginalImpl::load(
61 vb.pp("geometric"),
62 &esmc_cfg,
63 )?)
64 } else {
65 None
66 };
67
68 let ffn = SwiGLU::load(vb.pp("ffn"), config)?;
69
70 Ok(Self {
71 attn,
72 geom_attn,
73 ffn,
74 scaling_factor: config.residue_scaling_factor(),
75 })
76 }
77
78 pub fn forward(
79 &self,
80 x: &Tensor,
81 sequence_id: Option<&Tensor>,
82 affine: Option<&Affine3D>,
83 affine_mask: Option<&Tensor>,
84 chain_id: Option<&Tensor>,
85 ) -> Result<Tensor> {
86 let mut x = x.clone();
87
88 let r1 = self.attn.forward(&x, sequence_id)?;
90 x = (&x + (r1 / self.scaling_factor)?)?;
91
92 if let (Some(geom), Some(aff), Some(mask)) = (&self.geom_attn, affine, affine_mask) {
94 let r2 = geom.forward(&x, aff, mask, sequence_id, chain_id)?;
95 x = (&x + (r2 / self.scaling_factor)?)?;
96 }
97
98 let r3 = self.ffn.forward(&x)?;
100 x = (&x + (r3 / self.scaling_factor)?)?;
101
102 Ok(x)
103 }
104}
105
106fn esmc_config_from_esm3(cfg: &ESM3Config) -> ESMCConfig {
108 let n_layers = cfg.n_layers;
109 ESMCConfig {
110 d_model: cfg.d_model,
111 n_heads: cfg.n_heads,
112 n_layers,
113 v_head_transformer: Some(cfg.v_head_transformer),
114 ffn_type: FfnType::SWIGLU,
115 tokenizer: ESMTokenizer::Esm3OpenSmall,
116 use_plain_attn: true,
117 n_layers_geom: cfg.n_layers_geom,
118 scale_residue: cfg.scale_residue,
119 residue_scaling_factor: cfg.residue_scaling_factor(),
120 mask_and_zero_frameless: cfg.mask_and_zero_frameless,
121 bias: cfg.bias,
122 qk_layernorm: cfg.qk_layernorm,
123 expansion_ratio: cfg.expansion_ratio,
124 regression_head_output_dim: 0,
126 regression_head_hidden_dim: 0,
127 embedding_dim: 0,
128 }
129}