Skip to main content

candle_transformers/models/
debertav2.rs

1use std::collections::HashMap;
2
3use candle::{bail, Context, DType, Device, Module, Result, Tensor, D};
4use candle_nn::{
5    conv1d, embedding, layer_norm, Conv1d, Conv1dConfig, Embedding, LayerNorm, VarBuilder,
6};
7use serde::{Deserialize, Deserializer};
8
9pub const DTYPE: DType = DType::F32;
10
11// NOTE: HiddenAct and HiddenActLayer are both direct copies from bert.rs.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
13#[serde(rename_all = "lowercase")]
14pub enum HiddenAct {
15    Gelu,
16    GeluApproximate,
17    Relu,
18}
19
20pub struct HiddenActLayer {
21    act: HiddenAct,
22    span: tracing::Span,
23}
24
25impl HiddenActLayer {
26    fn new(act: HiddenAct) -> Self {
27        let span = tracing::span!(tracing::Level::TRACE, "hidden-act");
28        Self { act, span }
29    }
30
31    fn forward(&self, xs: &Tensor) -> Result<Tensor> {
32        let _enter = self.span.enter();
33        match self.act {
34            // https://github.com/huggingface/transformers/blob/cd4584e3c809bb9e1392ccd3fe38b40daba5519a/src/transformers/activations.py#L213
35            HiddenAct::Gelu => xs.gelu_erf(),
36            HiddenAct::GeluApproximate => xs.gelu(),
37            HiddenAct::Relu => xs.relu(),
38        }
39    }
40}
41
42pub type Id2Label = HashMap<u32, String>;
43pub type Label2Id = HashMap<String, u32>;
44
45#[derive(Debug, Clone, PartialEq, Deserialize)]
46pub struct Config {
47    pub vocab_size: usize,
48    pub hidden_size: usize,
49    pub num_hidden_layers: usize,
50    pub num_attention_heads: usize,
51    pub intermediate_size: usize,
52    pub hidden_act: HiddenAct,
53    pub hidden_dropout_prob: f64,
54    pub attention_probs_dropout_prob: f64,
55    pub max_position_embeddings: usize,
56    pub type_vocab_size: usize,
57    pub initializer_range: f64,
58    pub layer_norm_eps: f64,
59    pub relative_attention: bool,
60    pub max_relative_positions: isize,
61    pub pad_token_id: Option<usize>,
62    pub position_biased_input: bool,
63    #[serde(deserialize_with = "deserialize_pos_att_type")]
64    pub pos_att_type: Vec<String>,
65    pub position_buckets: Option<isize>,
66    pub share_att_key: Option<bool>,
67    pub attention_head_size: Option<usize>,
68    pub embedding_size: Option<usize>,
69    pub norm_rel_ebd: Option<String>,
70    pub conv_kernel_size: Option<usize>,
71    pub conv_groups: Option<usize>,
72    pub conv_act: Option<String>,
73    pub id2label: Option<Id2Label>,
74    pub label2id: Option<Label2Id>,
75    pub pooler_dropout: Option<f64>,
76    pub pooler_hidden_act: Option<HiddenAct>,
77    pub pooler_hidden_size: Option<usize>,
78    pub cls_dropout: Option<f64>,
79}
80
81fn deserialize_pos_att_type<'de, D>(deserializer: D) -> std::result::Result<Vec<String>, D::Error>
82where
83    D: Deserializer<'de>,
84{
85    #[derive(Deserialize, Debug)]
86    #[serde(untagged)]
87    enum StringOrVec {
88        String(String),
89        Vec(Vec<String>),
90    }
91
92    match StringOrVec::deserialize(deserializer)? {
93        StringOrVec::String(s) => Ok(s.split('|').map(String::from).collect()),
94        StringOrVec::Vec(v) => Ok(v),
95    }
96}
97
98// NOTE: Dropout is probably not needed for now since this will primarily be used
99// in inferencing. However, for training/fine-tuning it will be necessary.
100pub struct StableDropout {
101    _drop_prob: f64,
102    _count: usize,
103}
104
105impl StableDropout {
106    pub fn new(drop_prob: f64) -> Self {
107        Self {
108            _drop_prob: drop_prob,
109            _count: 0,
110        }
111    }
112
113    pub fn forward(&self, x: &Tensor) -> Result<Tensor> {
114        Ok(x.clone())
115    }
116}
117
118// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L823
119pub struct DebertaV2Embeddings {
120    device: Device,
121    word_embeddings: Embedding,
122    position_embeddings: Option<Embedding>,
123    token_type_embeddings: Option<Embedding>,
124    layer_norm: LayerNorm,
125    dropout: StableDropout,
126    position_ids: Tensor,
127    config: Config,
128    embedding_size: usize,
129    embed_proj: Option<candle_nn::Linear>,
130}
131
132impl DebertaV2Embeddings {
133    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
134        let device = vb.device().clone();
135        let config = config.clone();
136
137        let embedding_size = config.embedding_size.unwrap_or(config.hidden_size);
138
139        let word_embeddings =
140            embedding(config.vocab_size, embedding_size, vb.pp("word_embeddings"))?;
141
142        let position_embeddings = if config.position_biased_input {
143            Some(embedding(
144                config.max_position_embeddings,
145                embedding_size,
146                vb.pp("position_embeddings"),
147            )?)
148        } else {
149            None
150        };
151
152        let token_type_embeddings: Option<Embedding> = if config.type_vocab_size > 0 {
153            Some(candle_nn::embedding(
154                config.type_vocab_size,
155                config.hidden_size,
156                vb.pp("token_type_embeddings"),
157            )?)
158        } else {
159            None
160        };
161
162        let embed_proj: Option<candle_nn::Linear> = if embedding_size != config.hidden_size {
163            Some(candle_nn::linear_no_bias(
164                embedding_size,
165                config.hidden_size,
166                vb.pp("embed_proj"),
167            )?)
168        } else {
169            None
170        };
171
172        let layer_norm = layer_norm(
173            config.hidden_size,
174            config.layer_norm_eps,
175            vb.pp("LayerNorm"),
176        )?;
177
178        let dropout = StableDropout::new(config.hidden_dropout_prob);
179
180        let position_ids =
181            Tensor::arange(0, config.max_position_embeddings as u32, &device)?.unsqueeze(0)?;
182
183        Ok(Self {
184            word_embeddings,
185            position_embeddings,
186            token_type_embeddings,
187            layer_norm,
188            dropout,
189            position_ids,
190            device,
191            config,
192            embedding_size,
193            embed_proj,
194        })
195    }
196
197    pub fn forward(
198        &self,
199        input_ids: Option<&Tensor>,
200        token_type_ids: Option<&Tensor>,
201        position_ids: Option<&Tensor>,
202        mask: Option<&Tensor>,
203        inputs_embeds: Option<&Tensor>,
204    ) -> Result<Tensor> {
205        let (input_shape, input_embeds) = match (input_ids, inputs_embeds) {
206            (Some(ids), None) => {
207                let embs = self.word_embeddings.forward(ids)?;
208                (ids.dims(), embs)
209            }
210            (None, Some(e)) => (e.dims(), e.clone()),
211            (None, None) => {
212                bail!("Must specify either input_ids or inputs_embeds")
213            }
214            (Some(_), Some(_)) => {
215                bail!("Can't specify both input_ids and inputs_embeds")
216            }
217        };
218
219        let seq_length = match input_shape.last() {
220            Some(v) => *v,
221            None => bail!("DebertaV2Embeddings invalid input shape"),
222        };
223
224        let position_ids = match position_ids {
225            Some(v) => v.clone(),
226            None => self.position_ids.narrow(1, 0, seq_length)?,
227        };
228
229        let token_type_ids = match token_type_ids {
230            Some(ids) => ids.clone(),
231            None => Tensor::zeros(input_shape, DType::U32, &self.device)?,
232        };
233
234        let position_embeddings = match &self.position_embeddings {
235            Some(emb) => emb.forward(&position_ids)?,
236            None => Tensor::zeros_like(&input_embeds)?,
237        };
238
239        let mut embeddings = input_embeds;
240
241        if self.config.position_biased_input {
242            embeddings = embeddings.add(&position_embeddings)?;
243        }
244
245        if self.config.type_vocab_size > 0 {
246            embeddings = self.token_type_embeddings.as_ref().map_or_else(
247                || bail!("token_type_embeddings must be set when type_vocab_size > 0"),
248                |token_type_embeddings| {
249                    embeddings.add(&token_type_embeddings.forward(&token_type_ids)?)
250                },
251            )?;
252        }
253
254        if self.embedding_size != self.config.hidden_size {
255            embeddings = if let Some(embed_proj) = &self.embed_proj {
256                embed_proj.forward(&embeddings)?
257            } else {
258                bail!("embed_proj must exist if embedding_size != config.hidden_size");
259            }
260        }
261
262        embeddings = self.layer_norm.forward(&embeddings)?;
263
264        if let Some(mask) = mask {
265            let mut mask = mask.clone();
266            if mask.dims() != embeddings.dims() {
267                if mask.dims().len() == 4 {
268                    mask = mask.squeeze(1)?.squeeze(1)?;
269                }
270                mask = mask.unsqueeze(2)?;
271            }
272
273            mask = mask.to_dtype(embeddings.dtype())?;
274            embeddings = embeddings.broadcast_mul(&mask)?;
275        }
276
277        self.dropout.forward(&embeddings)
278    }
279}
280
281// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L72
282struct XSoftmax {}
283
284impl XSoftmax {
285    pub fn apply(input: &Tensor, mask: &Tensor, dim: D, device: &Device) -> Result<Tensor> {
286        // NOTE: At the time of this writing, candle does not have a logical-not operator.
287        let mut rmask = mask.broadcast_as(input.shape())?.to_dtype(DType::F32)?;
288
289        rmask = rmask
290            .broadcast_lt(&Tensor::new(&[1.0_f32], device)?)?
291            .to_dtype(DType::U8)?;
292
293        let min_value_tensor = Tensor::new(&[f32::MIN], device)?.broadcast_as(input.shape())?;
294        let mut output = rmask.where_cond(&min_value_tensor, input)?;
295
296        output = candle_nn::ops::softmax(&output, dim)?;
297
298        let t_zeroes = Tensor::new(&[0f32], device)?.broadcast_as(input.shape())?;
299        output = rmask.where_cond(&t_zeroes, &output)?;
300
301        Ok(output)
302    }
303}
304
305// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L605
306pub struct DebertaV2DisentangledSelfAttention {
307    config: Config,
308    num_attention_heads: usize,
309    query_proj: candle_nn::Linear,
310    key_proj: candle_nn::Linear,
311    value_proj: candle_nn::Linear,
312    dropout: StableDropout,
313    device: Device,
314    relative_attention: bool,
315    pos_dropout: Option<StableDropout>,
316    position_buckets: isize,
317    max_relative_positions: isize,
318    pos_ebd_size: isize,
319    share_att_key: bool,
320    pos_key_proj: Option<candle_nn::Linear>,
321    pos_query_proj: Option<candle_nn::Linear>,
322}
323
324impl DebertaV2DisentangledSelfAttention {
325    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
326        let config = config.clone();
327        let vb = vb.clone();
328
329        if !config
330            .hidden_size
331            .is_multiple_of(config.num_attention_heads)
332        {
333            return Err(candle::Error::Msg(format!(
334                "The hidden size {} is not a multiple of the number of attention heads {}",
335                config.hidden_size, config.num_attention_heads
336            )));
337        }
338
339        let num_attention_heads = config.num_attention_heads;
340
341        let attention_head_size = config
342            .attention_head_size
343            .unwrap_or(config.hidden_size / config.num_attention_heads);
344
345        let all_head_size = num_attention_heads * attention_head_size;
346
347        let query_proj = candle_nn::linear(config.hidden_size, all_head_size, vb.pp("query_proj"))?;
348        let key_proj = candle_nn::linear(config.hidden_size, all_head_size, vb.pp("key_proj"))?;
349        let value_proj = candle_nn::linear(config.hidden_size, all_head_size, vb.pp("value_proj"))?;
350
351        let share_att_key = config.share_att_key.unwrap_or(false);
352        let relative_attention = config.relative_attention;
353        let mut max_relative_positions = config.max_relative_positions;
354
355        let mut pos_ebd_size: isize = 0;
356        let position_buckets = config.position_buckets.unwrap_or(-1);
357        let mut pos_dropout: Option<StableDropout> = None;
358        let mut pos_key_proj: Option<candle_nn::Linear> = None;
359        let mut pos_query_proj: Option<candle_nn::Linear> = None;
360
361        if relative_attention {
362            if max_relative_positions < 1 {
363                max_relative_positions = config.max_position_embeddings as isize;
364            }
365            pos_ebd_size = max_relative_positions;
366            if position_buckets > 0 {
367                pos_ebd_size = position_buckets
368            }
369
370            pos_dropout = Some(StableDropout::new(config.hidden_dropout_prob));
371
372            if !share_att_key {
373                if config.pos_att_type.iter().any(|s| s == "c2p") {
374                    pos_key_proj = Some(candle_nn::linear(
375                        config.hidden_size,
376                        all_head_size,
377                        vb.pp("pos_key_proj"),
378                    )?);
379                }
380                if config.pos_att_type.iter().any(|s| s == "p2c") {
381                    pos_query_proj = Some(candle_nn::linear(
382                        config.hidden_size,
383                        all_head_size,
384                        vb.pp("pos_query_proj"),
385                    )?);
386                }
387            }
388        }
389
390        let dropout = StableDropout::new(config.attention_probs_dropout_prob);
391        let device = vb.device().clone();
392
393        Ok(Self {
394            config,
395            num_attention_heads,
396            query_proj,
397            key_proj,
398            value_proj,
399            dropout,
400            device,
401            relative_attention,
402            pos_dropout,
403            position_buckets,
404            max_relative_positions,
405            pos_ebd_size,
406            share_att_key,
407            pos_key_proj,
408            pos_query_proj,
409        })
410    }
411
412    pub fn forward(
413        &self,
414        hidden_states: &Tensor,
415        attention_mask: &Tensor,
416        query_states: Option<&Tensor>,
417        relative_pos: Option<&Tensor>,
418        rel_embeddings: Option<&Tensor>,
419    ) -> Result<Tensor> {
420        let query_states = match query_states {
421            Some(qs) => qs,
422            None => hidden_states,
423        };
424
425        let query_layer = self.transpose_for_scores(&self.query_proj.forward(query_states)?)?;
426        let key_layer = self.transpose_for_scores(&self.key_proj.forward(query_states)?)?;
427        let value_layer = self.transpose_for_scores(&self.value_proj.forward(query_states)?)?;
428
429        let mut rel_att: Option<Tensor> = None;
430
431        let mut scale_factor: usize = 1;
432
433        if self.config.pos_att_type.iter().any(|s| s == "c2p") {
434            scale_factor += 1;
435        }
436
437        if self.config.pos_att_type.iter().any(|s| s == "p2c") {
438            scale_factor += 1;
439        }
440
441        let scale = {
442            let q_size = query_layer.dim(D::Minus1)?;
443            Tensor::new(&[(q_size * scale_factor) as f32], &self.device)?.sqrt()?
444        };
445
446        let mut attention_scores: Tensor = {
447            let key_layer_transposed = key_layer.t()?;
448            let div = key_layer_transposed
449                .broadcast_div(scale.to_dtype(query_layer.dtype())?.as_ref())?;
450            query_layer.matmul(&div)?
451        };
452
453        if self.relative_attention {
454            if let Some(rel_embeddings) = rel_embeddings {
455                let rel_embeddings = self
456                    .pos_dropout
457                    .as_ref()
458                    .context("relative_attention requires pos_dropout")?
459                    .forward(rel_embeddings)?;
460                rel_att = Some(self.disentangled_attention_bias(
461                    query_layer,
462                    key_layer,
463                    relative_pos,
464                    rel_embeddings,
465                    scale_factor,
466                )?);
467            }
468        }
469
470        if let Some(rel_att) = rel_att {
471            attention_scores = attention_scores.broadcast_add(&rel_att)?;
472        }
473
474        attention_scores = attention_scores.reshape((
475            (),
476            self.num_attention_heads,
477            attention_scores.dim(D::Minus2)?,
478            attention_scores.dim(D::Minus1)?,
479        ))?;
480
481        let mut attention_probs =
482            XSoftmax::apply(&attention_scores, attention_mask, D::Minus1, &self.device)?;
483
484        attention_probs = self.dropout.forward(&attention_probs)?;
485
486        let mut context_layer = attention_probs
487            .reshape((
488                (),
489                attention_probs.dim(D::Minus2)?,
490                attention_probs.dim(D::Minus1)?,
491            ))?
492            .matmul(&value_layer)?;
493
494        context_layer = context_layer
495            .reshape((
496                (),
497                self.num_attention_heads,
498                context_layer.dim(D::Minus2)?,
499                context_layer.dim(D::Minus1)?,
500            ))?
501            .permute((0, 2, 1, 3))?
502            .contiguous()?;
503
504        let dims = context_layer.dims();
505
506        context_layer = match dims.len() {
507            2 => context_layer.reshape(())?,
508            3 => context_layer.reshape((dims[0], ()))?,
509            4 => context_layer.reshape((dims[0], dims[1], ()))?,
510            5 => context_layer.reshape((dims[0], dims[1], dims[2], ()))?,
511            _ => {
512                bail!(
513                    "Invalid shape for DisentabgledSelfAttention context layer: {:?}",
514                    dims
515                )
516            }
517        };
518
519        Ok(context_layer)
520    }
521
522    fn transpose_for_scores(&self, xs: &Tensor) -> Result<Tensor> {
523        let dims = xs.dims().to_vec();
524        match dims.len() {
525            3 => {
526                let reshaped = xs.reshape((dims[0], dims[1], self.num_attention_heads, ()))?;
527
528                reshaped.transpose(1, 2)?.contiguous()?.reshape((
529                    (),
530                    reshaped.dim(1)?,
531                    reshaped.dim(D::Minus1)?,
532                ))
533            }
534            shape => {
535                bail!("Invalid shape for transpose_for_scores. Expected 3 dimensions, got {shape}")
536            }
537        }
538    }
539
540    fn disentangled_attention_bias(
541        &self,
542        query_layer: Tensor,
543        key_layer: Tensor,
544        relative_pos: Option<&Tensor>,
545        rel_embeddings: Tensor,
546        scale_factor: usize,
547    ) -> Result<Tensor> {
548        let mut relative_pos = relative_pos.map_or(
549            build_relative_position(
550                query_layer.dim(D::Minus2)?,
551                key_layer.dim(D::Minus2)?,
552                &self.device,
553                Some(self.position_buckets),
554                Some(self.max_relative_positions),
555            )?,
556            |pos| pos.clone(),
557        );
558
559        relative_pos = match relative_pos.dims().len() {
560            2 => relative_pos.unsqueeze(0)?.unsqueeze(0)?,
561            3 => relative_pos.unsqueeze(1)?,
562            other => {
563                bail!("Relative position ids must be of dim 2 or 3 or 4. Got dim of size {other}")
564            }
565        };
566
567        let att_span = self.pos_ebd_size;
568
569        let rel_embeddings = rel_embeddings
570            .narrow(0, 0, (att_span * 2) as usize)?
571            .unsqueeze(0)?;
572
573        let mut pos_query_layer: Option<Tensor> = None;
574        let mut pos_key_layer: Option<Tensor> = None;
575
576        let repeat_with = query_layer.dim(0)? / self.num_attention_heads;
577        if self.share_att_key {
578            pos_query_layer = Some(
579                self.transpose_for_scores(&self.query_proj.forward(&rel_embeddings)?)?
580                    .repeat(repeat_with)?,
581            );
582
583            pos_key_layer = Some(
584                self.transpose_for_scores(&self.key_proj.forward(&rel_embeddings)?)?
585                    .repeat(repeat_with)?,
586            )
587        } else {
588            if self.config.pos_att_type.iter().any(|s| s == "c2p") {
589                pos_key_layer = Some(
590                    self.transpose_for_scores(
591                        &self
592                            .pos_key_proj
593                            .as_ref()
594                            .context(
595                                "Need pos_key_proj when share_att_key is false or not specified",
596                            )?
597                            .forward(&rel_embeddings)?,
598                    )?
599                    .repeat(repeat_with)?,
600                )
601            }
602            if self.config.pos_att_type.iter().any(|s| s == "p2c") {
603                pos_query_layer = Some(self.transpose_for_scores(&self
604                    .pos_query_proj
605                    .as_ref()
606                    .context("Need a pos_query_proj when share_att_key is false or not specified")?
607                    .forward(&rel_embeddings)?)?.repeat(repeat_with)?)
608            }
609        }
610
611        let mut score = Tensor::new(&[0 as f32], &self.device)?;
612
613        if self.config.pos_att_type.iter().any(|s| s == "c2p") {
614            let pos_key_layer = pos_key_layer.context("c2p without pos_key_layer")?;
615
616            let scale = Tensor::new(
617                &[(pos_key_layer.dim(D::Minus1)? * scale_factor) as f32],
618                &self.device,
619            )?
620            .sqrt()?;
621
622            let mut c2p_att = query_layer.matmul(&pos_key_layer.t()?)?;
623
624            let c2p_pos = relative_pos
625                .broadcast_add(&Tensor::new(&[att_span as i64], &self.device)?)?
626                .clamp(0 as f32, (att_span * 2 - 1) as f32)?;
627
628            c2p_att = c2p_att.gather(
629                &c2p_pos
630                    .squeeze(0)?
631                    .expand(&[
632                        query_layer.dim(0)?,
633                        query_layer.dim(1)?,
634                        relative_pos.dim(D::Minus1)?,
635                    ])?
636                    .contiguous()?,
637                D::Minus1,
638            )?;
639
640            score = score.broadcast_add(
641                &c2p_att.broadcast_div(scale.to_dtype(c2p_att.dtype())?.as_ref())?,
642            )?;
643        }
644
645        if self.config.pos_att_type.iter().any(|s| s == "p2c") {
646            let pos_query_layer = pos_query_layer.context("p2c without pos_key_layer")?;
647
648            let scale = Tensor::new(
649                &[(pos_query_layer.dim(D::Minus1)? * scale_factor) as f32],
650                &self.device,
651            )?
652            .sqrt()?;
653
654            let r_pos = {
655                if key_layer.dim(D::Minus2)? != query_layer.dim(D::Minus2)? {
656                    build_relative_position(
657                        key_layer.dim(D::Minus2)?,
658                        key_layer.dim(D::Minus2)?,
659                        &self.device,
660                        Some(self.position_buckets),
661                        Some(self.max_relative_positions),
662                    )?
663                    .unsqueeze(0)?
664                } else {
665                    relative_pos
666                }
667            };
668
669            let p2c_pos = r_pos
670                .to_dtype(DType::F32)?
671                .neg()?
672                .broadcast_add(&Tensor::new(&[att_span as f32], &self.device)?)?
673                .clamp(0f32, (att_span * 2 - 1) as f32)?;
674
675            let p2c_att = key_layer
676                .matmul(&pos_query_layer.t()?)?
677                .gather(
678                    &p2c_pos
679                        .squeeze(0)?
680                        .expand(&[
681                            query_layer.dim(0)?,
682                            key_layer.dim(D::Minus2)?,
683                            key_layer.dim(D::Minus2)?,
684                        ])?
685                        .contiguous()?
686                        .to_dtype(DType::U32)?,
687                    D::Minus1,
688                )?
689                .t()?;
690
691            score =
692                score.broadcast_add(&p2c_att.broadcast_div(&scale.to_dtype(p2c_att.dtype())?)?)?;
693        }
694
695        Ok(score)
696    }
697}
698
699// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L270
700pub struct DebertaV2Attention {
701    dsa: DebertaV2DisentangledSelfAttention,
702    output: DebertaV2SelfOutput,
703}
704
705impl DebertaV2Attention {
706    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
707        let dsa = DebertaV2DisentangledSelfAttention::load(vb.pp("attention.self"), config)?;
708        let output = DebertaV2SelfOutput::load(vb.pp("attention.output"), config)?;
709        Ok(Self { dsa, output })
710    }
711
712    fn forward(
713        &self,
714        hidden_states: &Tensor,
715        attention_mask: &Tensor,
716        query_states: Option<&Tensor>,
717        relative_pos: Option<&Tensor>,
718        rel_embeddings: Option<&Tensor>,
719    ) -> Result<Tensor> {
720        let self_output = self.dsa.forward(
721            hidden_states,
722            attention_mask,
723            query_states,
724            relative_pos,
725            rel_embeddings,
726        )?;
727
728        self.output
729            .forward(&self_output, query_states.unwrap_or(hidden_states))
730    }
731}
732
733// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L255
734pub struct DebertaV2SelfOutput {
735    dense: candle_nn::Linear,
736    layer_norm: LayerNorm,
737    dropout: StableDropout,
738}
739
740impl DebertaV2SelfOutput {
741    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
742        let dense = candle_nn::linear(config.hidden_size, config.hidden_size, vb.pp("dense"))?;
743        let layer_norm = candle_nn::layer_norm(
744            config.hidden_size,
745            config.layer_norm_eps,
746            vb.pp("LayerNorm"),
747        )?;
748        let dropout = StableDropout::new(config.hidden_dropout_prob);
749        Ok(Self {
750            dense,
751            layer_norm,
752            dropout,
753        })
754    }
755
756    pub fn forward(&self, hidden_states: &Tensor, input_tensor: &Tensor) -> Result<Tensor> {
757        let mut hidden_states = self.dense.forward(hidden_states)?;
758        hidden_states = self.dropout.forward(&hidden_states)?;
759        self.layer_norm
760            .forward(&hidden_states.broadcast_add(input_tensor)?)
761    }
762}
763
764// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L307
765pub struct DebertaV2Intermediate {
766    dense: candle_nn::Linear,
767    intermediate_act: HiddenActLayer,
768}
769
770impl DebertaV2Intermediate {
771    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
772        let dense = candle_nn::linear(
773            config.hidden_size,
774            config.intermediate_size,
775            vb.pp("intermediate.dense"),
776        )?;
777        let intermediate_act = HiddenActLayer::new(config.hidden_act);
778        Ok(Self {
779            dense,
780            intermediate_act,
781        })
782    }
783
784    pub fn forward(&self, hidden_states: &Tensor) -> Result<Tensor> {
785        self.intermediate_act
786            .forward(&self.dense.forward(hidden_states)?)
787    }
788}
789
790// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L323
791pub struct DebertaV2Output {
792    dense: candle_nn::Linear,
793    layer_norm: LayerNorm,
794    dropout: StableDropout,
795}
796
797impl DebertaV2Output {
798    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
799        let dense = candle_nn::linear(
800            config.intermediate_size,
801            config.hidden_size,
802            vb.pp("output.dense"),
803        )?;
804        let layer_norm = candle_nn::layer_norm(
805            config.hidden_size,
806            config.layer_norm_eps,
807            vb.pp("output.LayerNorm"),
808        )?;
809        let dropout = StableDropout::new(config.hidden_dropout_prob);
810        Ok(Self {
811            dense,
812            layer_norm,
813            dropout,
814        })
815    }
816
817    pub fn forward(&self, hidden_states: &Tensor, input_tensor: &Tensor) -> Result<Tensor> {
818        let mut hidden_states = self.dense.forward(hidden_states)?;
819        hidden_states = self.dropout.forward(&hidden_states)?;
820        hidden_states = {
821            let to_norm = hidden_states.broadcast_add(input_tensor)?;
822            self.layer_norm.forward(&to_norm)?
823        };
824        Ok(hidden_states)
825    }
826}
827
828// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L339
829pub struct DebertaV2Layer {
830    attention: DebertaV2Attention,
831    intermediate: DebertaV2Intermediate,
832    output: DebertaV2Output,
833}
834
835impl DebertaV2Layer {
836    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
837        let attention = DebertaV2Attention::load(vb.clone(), config)?;
838        let intermediate = DebertaV2Intermediate::load(vb.clone(), config)?;
839        let output = DebertaV2Output::load(vb.clone(), config)?;
840        Ok(Self {
841            attention,
842            intermediate,
843            output,
844        })
845    }
846
847    fn forward(
848        &self,
849        hidden_states: &Tensor,
850        attention_mask: &Tensor,
851        query_states: Option<&Tensor>,
852        relative_pos: Option<&Tensor>,
853        rel_embeddings: Option<&Tensor>,
854    ) -> Result<Tensor> {
855        let attention_output = self.attention.forward(
856            hidden_states,
857            attention_mask,
858            query_states,
859            relative_pos,
860            rel_embeddings,
861        )?;
862
863        let intermediate_output = self.intermediate.forward(&attention_output)?;
864
865        let layer_output = self
866            .output
867            .forward(&intermediate_output, &attention_output)?;
868
869        Ok(layer_output)
870    }
871}
872
873// TODO: In order to fully test ConvLayer a model needs to be found has a configuration where `conv_kernel_size` exists and is > 0
874// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L373
875pub struct ConvLayer {
876    _conv_act: String,
877    _conv: Conv1d,
878    _layer_norm: LayerNorm,
879    _dropout: StableDropout,
880    _config: Config,
881}
882
883impl ConvLayer {
884    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
885        let config = config.clone();
886        let kernel_size = config.conv_kernel_size.unwrap_or(3);
887        let groups = config.conv_groups.unwrap_or(1);
888        let conv_act: String = config.conv_act.clone().unwrap_or("tanh".to_string());
889
890        let conv_conf = Conv1dConfig {
891            padding: (kernel_size - 1) / 2,
892            groups,
893            ..Default::default()
894        };
895
896        let conv = conv1d(
897            config.hidden_size,
898            config.hidden_size,
899            kernel_size,
900            conv_conf,
901            vb.pp("conv"),
902        )?;
903
904        let layer_norm = layer_norm(
905            config.hidden_size,
906            config.layer_norm_eps,
907            vb.pp("LayerNorm"),
908        )?;
909
910        let dropout = StableDropout::new(config.hidden_dropout_prob);
911
912        Ok(Self {
913            _conv_act: conv_act,
914            _conv: conv,
915            _layer_norm: layer_norm,
916            _dropout: dropout,
917            _config: config,
918        })
919    }
920
921    pub fn forward(
922        &self,
923        _hidden_states: &Tensor,
924        _residual_states: &Tensor,
925        _input_mask: &Tensor,
926    ) -> Result<Tensor> {
927        todo!("Need a model that contains a conv layer to test against.")
928    }
929}
930
931// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L409
932pub struct DebertaV2Encoder {
933    layer: Vec<DebertaV2Layer>,
934    relative_attention: bool,
935    max_relative_positions: isize,
936    position_buckets: isize,
937    rel_embeddings: Option<Embedding>,
938    norm_rel_ebd: String,
939    layer_norm: Option<LayerNorm>,
940    conv: Option<ConvLayer>,
941    device: Device,
942}
943
944impl DebertaV2Encoder {
945    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
946        let layer = (0..config.num_hidden_layers)
947            .map(|index| DebertaV2Layer::load(vb.pp(format!("layer.{index}")), config))
948            .collect::<Result<Vec<_>>>()?;
949
950        let relative_attention = config.relative_attention;
951        let mut max_relative_positions = config.max_relative_positions;
952
953        let position_buckets = config.position_buckets.unwrap_or(-1);
954
955        let mut rel_embeddings: Option<Embedding> = None;
956
957        if relative_attention {
958            if max_relative_positions < 1 {
959                max_relative_positions = config.max_position_embeddings as isize;
960            }
961
962            let mut pos_ebd_size = max_relative_positions * 2;
963
964            if position_buckets > 0 {
965                pos_ebd_size = position_buckets * 2;
966            }
967
968            rel_embeddings = Some(embedding(
969                pos_ebd_size as usize,
970                config.hidden_size,
971                vb.pp("rel_embeddings"),
972            )?);
973        }
974
975        // NOTE: The Python code assumes that the config attribute "norm_rel_ebd" is an array of some kind, but most examples have it as a string.
976        // So it might need to be updated at some point.
977        let norm_rel_ebd = match config.norm_rel_ebd.as_ref() {
978            Some(nre) => nre.trim().to_string(),
979            None => "none".to_string(),
980        };
981
982        let layer_norm: Option<LayerNorm> = if norm_rel_ebd == "layer_norm" {
983            Some(layer_norm(
984                config.hidden_size,
985                config.layer_norm_eps,
986                vb.pp("LayerNorm"),
987            )?)
988        } else {
989            None
990        };
991
992        let conv: Option<ConvLayer> = if config.conv_kernel_size.unwrap_or(0) > 0 {
993            Some(ConvLayer::load(vb.pp("conv"), config)?)
994        } else {
995            None
996        };
997
998        Ok(Self {
999            layer,
1000            relative_attention,
1001            max_relative_positions,
1002            position_buckets,
1003            rel_embeddings,
1004            norm_rel_ebd,
1005            layer_norm,
1006            conv,
1007            device: vb.device().clone(),
1008        })
1009    }
1010
1011    pub fn forward(
1012        &self,
1013        hidden_states: &Tensor,
1014        attention_mask: &Tensor,
1015        query_states: Option<&Tensor>,
1016        relative_pos: Option<&Tensor>,
1017    ) -> Result<Tensor> {
1018        let input_mask = if attention_mask.dims().len() <= 2 {
1019            attention_mask.clone()
1020        } else {
1021            attention_mask
1022                .sum_keepdim(attention_mask.rank() - 2)?
1023                .gt(0.)?
1024        };
1025
1026        let attention_mask = self.get_attention_mask(attention_mask.clone())?;
1027
1028        let relative_pos = self.get_rel_pos(hidden_states, query_states, relative_pos)?;
1029
1030        let mut next_kv: Tensor = hidden_states.clone();
1031        let rel_embeddings = self.get_rel_embedding()?;
1032        let mut output_states = next_kv.to_owned();
1033        let mut query_states: Option<Tensor> = query_states.cloned();
1034
1035        for (i, layer_module) in self.layer.iter().enumerate() {
1036            // NOTE: The original python code branches here if this model is being
1037            // used for training vs. inferencing. For now, we will only handle the
1038            // inferencing side of things
1039
1040            output_states = layer_module.forward(
1041                next_kv.as_ref(),
1042                &attention_mask,
1043                query_states.as_ref(),
1044                relative_pos.as_ref(),
1045                rel_embeddings.as_ref(),
1046            )?;
1047
1048            if i == 0 {
1049                if let Some(conv) = &self.conv {
1050                    output_states = conv.forward(hidden_states, &output_states, &input_mask)?;
1051                }
1052            }
1053
1054            if query_states.is_some() {
1055                query_states = Some(output_states.clone());
1056            } else {
1057                next_kv = output_states.clone();
1058            }
1059        }
1060
1061        Ok(output_states)
1062    }
1063
1064    fn get_attention_mask(&self, mut attention_mask: Tensor) -> Result<Tensor> {
1065        match attention_mask.dims().len() {
1066            0..=2 => {
1067                let extended_attention_mask = attention_mask.unsqueeze(1)?.unsqueeze(2)?;
1068                attention_mask = extended_attention_mask.broadcast_mul(
1069                    &extended_attention_mask
1070                        .squeeze(D::Minus2)?
1071                        .unsqueeze(D::Minus1)?,
1072                )?;
1073            }
1074            3 => attention_mask = attention_mask.unsqueeze(1)?,
1075            len => bail!("Unsupported attentiom mask size length: {len}"),
1076        }
1077
1078        Ok(attention_mask)
1079    }
1080
1081    fn get_rel_pos(
1082        &self,
1083        hidden_states: &Tensor,
1084        query_states: Option<&Tensor>,
1085        relative_pos: Option<&Tensor>,
1086    ) -> Result<Option<Tensor>> {
1087        if self.relative_attention && relative_pos.is_none() {
1088            let q = if let Some(query_states) = query_states {
1089                query_states.dim(D::Minus2)?
1090            } else {
1091                hidden_states.dim(D::Minus2)?
1092            };
1093
1094            return Ok(Some(build_relative_position(
1095                q,
1096                hidden_states.dim(D::Minus2)?,
1097                &self.device,
1098                Some(self.position_buckets),
1099                Some(self.max_relative_positions),
1100            )?));
1101        }
1102
1103        if relative_pos.is_some() {
1104            Ok(relative_pos.cloned())
1105        } else {
1106            Ok(None)
1107        }
1108    }
1109    fn get_rel_embedding(&self) -> Result<Option<Tensor>> {
1110        if !self.relative_attention {
1111            return Ok(None);
1112        }
1113
1114        let rel_embeddings = self
1115            .rel_embeddings
1116            .as_ref()
1117            .context("self.rel_embeddings not present when using relative_attention")?
1118            .embeddings()
1119            .clone();
1120
1121        if !self.norm_rel_ebd.contains("layer_norm") {
1122            return Ok(Some(rel_embeddings));
1123        }
1124
1125        let layer_normed_embeddings = self
1126            .layer_norm
1127            .as_ref()
1128            .context("DebertaV2Encoder layer_norm is None when norm_rel_ebd contains layer_norm")?
1129            .forward(&rel_embeddings)?;
1130
1131        Ok(Some(layer_normed_embeddings))
1132    }
1133}
1134
1135// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L991
1136pub struct DebertaV2Model {
1137    embeddings: DebertaV2Embeddings,
1138    encoder: DebertaV2Encoder,
1139    z_steps: usize,
1140    pub device: Device,
1141}
1142
1143impl DebertaV2Model {
1144    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
1145        let vb = vb.clone();
1146        let embeddings = DebertaV2Embeddings::load(vb.pp("embeddings"), config)?;
1147        let encoder = DebertaV2Encoder::load(vb.pp("encoder"), config)?;
1148        let z_steps: usize = 0;
1149
1150        Ok(Self {
1151            embeddings,
1152            encoder,
1153            z_steps,
1154            device: vb.device().clone(),
1155        })
1156    }
1157
1158    pub fn forward(
1159        &self,
1160        input_ids: &Tensor,
1161        token_type_ids: Option<Tensor>,
1162        attention_mask: Option<Tensor>,
1163    ) -> Result<Tensor> {
1164        let input_ids_shape = input_ids.shape();
1165
1166        let attention_mask = match attention_mask {
1167            Some(mask) => mask,
1168            None => Tensor::ones(input_ids_shape, DType::I64, &self.device)?,
1169        };
1170
1171        let token_type_ids = match token_type_ids {
1172            Some(ids) => ids,
1173            None => Tensor::zeros(input_ids_shape, DType::U32, &self.device)?,
1174        };
1175
1176        let embedding_output = self.embeddings.forward(
1177            Some(input_ids),
1178            Some(&token_type_ids),
1179            None,
1180            Some(&attention_mask),
1181            None,
1182        )?;
1183
1184        let encoder_output =
1185            self.encoder
1186                .forward(&embedding_output, &attention_mask, None, None)?;
1187
1188        if self.z_steps > 1 {
1189            todo!("Complete DebertaV2Model forward() when z_steps > 1 -- Needs a model to test this situation.")
1190        }
1191
1192        Ok(encoder_output)
1193    }
1194}
1195
1196#[derive(Debug)]
1197pub struct NERItem {
1198    pub entity: String,
1199    pub word: String,
1200    pub score: f32,
1201    pub start: usize,
1202    pub end: usize,
1203    pub index: usize,
1204}
1205
1206#[derive(Debug)]
1207pub struct TextClassificationItem {
1208    pub label: String,
1209    pub score: f32,
1210}
1211
1212pub struct DebertaV2NERModel {
1213    pub device: Device,
1214    deberta: DebertaV2Model,
1215    dropout: candle_nn::Dropout,
1216    classifier: candle_nn::Linear,
1217}
1218
1219fn id2label_len(config: &Config, id2label: Option<HashMap<u32, String>>) -> Result<usize> {
1220    let id2label_len = match (&config.id2label, id2label) {
1221        (None, None) => bail!("Id2Label is either not present in the model configuration or not passed into DebertaV2NERModel::load as a parameter"),
1222        (None, Some(id2label_p)) => id2label_p.len(),
1223        (Some(id2label_c), None) => id2label_c.len(),
1224        (Some(id2label_c), Some(id2label_p)) => {
1225          if *id2label_c == id2label_p {
1226            id2label_c.len()
1227          } else {
1228            bail!("Id2Label is both present in the model configuration and provided as a parameter, and they are different.")
1229          }
1230        }
1231    };
1232    Ok(id2label_len)
1233}
1234
1235impl DebertaV2NERModel {
1236    pub fn load(vb: VarBuilder, config: &Config, id2label: Option<Id2Label>) -> Result<Self> {
1237        let id2label_len = id2label_len(config, id2label)?;
1238
1239        let deberta = DebertaV2Model::load(vb.clone(), config)?;
1240        let dropout = candle_nn::Dropout::new(config.hidden_dropout_prob as f32);
1241        let classifier: candle_nn::Linear = candle_nn::linear_no_bias(
1242            config.hidden_size,
1243            id2label_len,
1244            vb.root().pp("classifier"),
1245        )?;
1246
1247        Ok(Self {
1248            device: vb.device().clone(),
1249            deberta,
1250            dropout,
1251            classifier,
1252        })
1253    }
1254
1255    pub fn forward(
1256        &self,
1257        input_ids: &Tensor,
1258        token_type_ids: Option<Tensor>,
1259        attention_mask: Option<Tensor>,
1260    ) -> Result<Tensor> {
1261        let output = self
1262            .deberta
1263            .forward(input_ids, token_type_ids, attention_mask)?;
1264        let output = self.dropout.forward(&output, false)?;
1265        self.classifier.forward(&output)
1266    }
1267}
1268
1269pub struct DebertaV2SeqClassificationModel {
1270    pub device: Device,
1271    deberta: DebertaV2Model,
1272    dropout: StableDropout,
1273    pooler: DebertaV2ContextPooler,
1274    classifier: candle_nn::Linear,
1275}
1276
1277impl DebertaV2SeqClassificationModel {
1278    pub fn load(vb: VarBuilder, config: &Config, id2label: Option<Id2Label>) -> Result<Self> {
1279        let id2label_len = id2label_len(config, id2label)?;
1280        let deberta = DebertaV2Model::load(vb.clone(), config)?;
1281        let pooler = DebertaV2ContextPooler::load(vb.clone(), config)?;
1282        let output_dim = pooler.output_dim()?;
1283        let classifier = candle_nn::linear(output_dim, id2label_len, vb.root().pp("classifier"))?;
1284        let dropout = match config.cls_dropout {
1285            Some(cls_dropout) => StableDropout::new(cls_dropout),
1286            None => StableDropout::new(config.hidden_dropout_prob),
1287        };
1288
1289        Ok(Self {
1290            device: vb.device().clone(),
1291            deberta,
1292            dropout,
1293            pooler,
1294            classifier,
1295        })
1296    }
1297
1298    pub fn forward(
1299        &self,
1300        input_ids: &Tensor,
1301        token_type_ids: Option<Tensor>,
1302        attention_mask: Option<Tensor>,
1303    ) -> Result<Tensor> {
1304        let encoder_layer = self
1305            .deberta
1306            .forward(input_ids, token_type_ids, attention_mask)?;
1307        let pooled_output = self.pooler.forward(&encoder_layer)?;
1308        let pooled_output = self.dropout.forward(&pooled_output)?;
1309        self.classifier.forward(&pooled_output)
1310    }
1311}
1312
1313pub struct DebertaV2ContextPooler {
1314    dense: candle_nn::Linear,
1315    dropout: StableDropout,
1316    config: Config,
1317}
1318
1319// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L49
1320impl DebertaV2ContextPooler {
1321    pub fn load(vb: VarBuilder, config: &Config) -> Result<Self> {
1322        let pooler_hidden_size = config
1323            .pooler_hidden_size
1324            .context("config.pooler_hidden_size is required for DebertaV2ContextPooler")?;
1325
1326        let pooler_dropout = config
1327            .pooler_dropout
1328            .context("config.pooler_dropout is required for DebertaV2ContextPooler")?;
1329
1330        let dense = candle_nn::linear(
1331            pooler_hidden_size,
1332            pooler_hidden_size,
1333            vb.root().pp("pooler.dense"),
1334        )?;
1335
1336        let dropout = StableDropout::new(pooler_dropout);
1337
1338        Ok(Self {
1339            dense,
1340            dropout,
1341            config: config.clone(),
1342        })
1343    }
1344
1345    pub fn forward(&self, hidden_states: &Tensor) -> Result<Tensor> {
1346        let context_token = hidden_states.narrow(1, 0, 1)?.squeeze(1)?;
1347        let context_token = self.dropout.forward(&context_token)?;
1348
1349        let pooled_output = self.dense.forward(&context_token.contiguous()?)?;
1350        let pooler_hidden_act = self
1351            .config
1352            .pooler_hidden_act
1353            .context("Could not obtain pooler hidden act from config")?;
1354
1355        HiddenActLayer::new(pooler_hidden_act).forward(&pooled_output)
1356    }
1357
1358    pub fn output_dim(&self) -> Result<usize> {
1359        self.config.pooler_hidden_size.context("DebertaV2ContextPooler cannot return output_dim (pooler_hidden_size) since it is not specified in the model config")
1360    }
1361}
1362
1363// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L557
1364pub(crate) fn build_relative_position(
1365    query_size: usize,
1366    key_size: usize,
1367    device: &Device,
1368    bucket_size: Option<isize>,
1369    max_position: Option<isize>,
1370) -> Result<Tensor> {
1371    let q_ids = Tensor::arange(0, query_size as i64, device)?.unsqueeze(0)?;
1372    let k_ids: Tensor = Tensor::arange(0, key_size as i64, device)?.unsqueeze(D::Minus1)?;
1373    let mut rel_pos_ids = k_ids.broadcast_sub(&q_ids)?;
1374    let bucket_size = bucket_size.unwrap_or(-1);
1375    let max_position = max_position.unwrap_or(-1);
1376
1377    if bucket_size > 0 && max_position > 0 {
1378        rel_pos_ids = make_log_bucket_position(rel_pos_ids, bucket_size, max_position, device)?;
1379    }
1380
1381    rel_pos_ids = rel_pos_ids.to_dtype(DType::I64)?;
1382    rel_pos_ids = rel_pos_ids.narrow(0, 0, query_size)?;
1383    rel_pos_ids.unsqueeze(0)
1384}
1385
1386// https://github.com/huggingface/transformers/blob/78b2929c0554b79e0489b451ce4ece14d265ead2/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L542
1387pub(crate) fn make_log_bucket_position(
1388    relative_pos: Tensor,
1389    bucket_size: isize,
1390    max_position: isize,
1391    device: &Device,
1392) -> Result<Tensor> {
1393    let sign = relative_pos.to_dtype(DType::F32)?.sign()?;
1394
1395    let mid = bucket_size / 2;
1396
1397    let lt_mid = relative_pos.lt(mid as i64)?;
1398    let gt_neg_mid = relative_pos.gt(-mid as i64)?;
1399
1400    let condition = lt_mid
1401        .to_dtype(candle::DType::F32)?
1402        .mul(&gt_neg_mid.to_dtype(candle::DType::F32)?)?
1403        .to_dtype(DType::U8)?;
1404
1405    let on_true = Tensor::new(&[(mid - 1) as u32], device)?
1406        .broadcast_as(relative_pos.shape())?
1407        .to_dtype(relative_pos.dtype())?;
1408
1409    let on_false = relative_pos
1410        .to_dtype(DType::F32)?
1411        .abs()?
1412        .to_dtype(DType::I64)?;
1413
1414    let abs_pos = condition.where_cond(&on_true, &on_false)?;
1415
1416    let mid_as_tensor = Tensor::from_slice(&[mid as f32], (1,), device)?;
1417
1418    let log_pos = {
1419        let first_log = abs_pos
1420            .to_dtype(DType::F32)?
1421            .broadcast_div(&mid_as_tensor)?
1422            .log()?;
1423
1424        let second_log =
1425            Tensor::from_slice(&[((max_position as f32 - 1.0) / mid as f32)], (1,), device)?
1426                .log()?;
1427
1428        let first_div_second = first_log.broadcast_div(&second_log)?;
1429
1430        let to_ceil = first_div_second
1431            .broadcast_mul(Tensor::from_slice(&[(mid - 1) as f32], (1,), device)?.as_ref())?;
1432
1433        let ceil = to_ceil.ceil()?;
1434
1435        ceil.broadcast_add(&mid_as_tensor)?
1436    };
1437
1438    Ok({
1439        let abs_pos_lte_mid = abs_pos.to_dtype(DType::F32)?.broadcast_le(&mid_as_tensor)?;
1440        let relative_pos = relative_pos.to_dtype(relative_pos.dtype())?;
1441        let log_pos_mul_sign = log_pos.broadcast_mul(&sign.to_dtype(DType::F32)?)?;
1442        abs_pos_lte_mid.where_cond(&relative_pos.to_dtype(DType::F32)?, &log_pos_mul_sign)?
1443    })
1444}