1use crate::common::dropout::Dropout;
14use crate::t5::layer_norm::T5LayerNorm;
15use crate::t5::T5Config;
16use std::borrow::Borrow;
17use tch::nn::LinearConfig;
18use tch::{nn, Device, Kind, Tensor};
19
20#[derive(Debug)]
21pub struct LayerState {
24 pub prev_key: Tensor,
26 pub prev_value: Tensor,
28}
29
30impl Clone for LayerState {
31 fn clone(&self) -> Self {
32 LayerState {
33 prev_key: self.prev_key.copy(),
34 prev_value: self.prev_value.copy(),
35 }
36 }
37}
38
39impl LayerState {
40 pub(crate) fn reorder_cache(&mut self, new_indices: &Tensor) {
41 self.prev_key = self.prev_key.index_select(0, new_indices);
42 self.prev_value = self.prev_value.index_select(0, new_indices);
43 }
44}
45
46pub fn get_relative_position_bucket(
47 relative_position: &Tensor,
48 bidirectional: bool,
49 num_buckets: i64,
50 max_distance: i64,
51) -> Tensor {
52 let n = -relative_position;
53 let mut num_buckets = num_buckets;
54 let mut ret = n.zeros_like();
55 let n = if bidirectional {
56 num_buckets /= 2;
57 ret += n.lt(0).to_kind(Kind::Int64) * num_buckets;
58 n.abs()
59 } else {
60 n.max_other(&n.zeros_like())
61 };
62
63 let max_exact = num_buckets / 2;
64 let is_small = n.lt(max_exact);
65
66 let value_if_large: Tensor = ((n.to_kind(Kind::Float) / max_exact as f64).log2()
67 / (max_distance as f64 / max_exact as f64).log2()
68 * (num_buckets - max_exact) as f64)
69 .to_kind(Kind::Int64)
70 + max_exact;
71
72 let value_if_large = value_if_large.min_other(&value_if_large.full_like(num_buckets - 1));
73 ret += n.where_self(&is_small, &value_if_large);
74 ret
75}
76
77#[derive(Debug)]
78pub struct T5Attention {
79 is_decoder: bool,
80 is_bidirectional: bool,
81 has_relative_attention_bias: bool,
82 relative_attention_num_buckets: i64,
83 relative_attention_max_distance: i64,
84 d_kv: i64,
85 n_heads: i64,
86 dropout: Dropout,
87 inner_dim: i64,
88 output_attentions: bool,
89 store_cache: bool,
90 query: nn::Linear,
91 key: nn::Linear,
92 value: nn::Linear,
93 output: nn::Linear,
94 relative_attention_bias: Option<nn::Embedding>,
95}
96
97impl T5Attention {
98 pub fn new<'p, P>(
99 p: P,
100 config: &T5Config,
101 is_decoder: bool,
102 is_bidirectional: bool,
103 store_cache: bool,
104 output_attentions: bool,
105 has_relative_attention_bias: bool,
106 ) -> T5Attention
107 where
108 P: Borrow<nn::Path<'p>>,
109 {
110 let p = p.borrow();
111
112 let linear_config = LinearConfig {
113 bias: false,
114 ..Default::default()
115 };
116
117 let inner_dim = config.num_heads * config.d_kv;
118 let key = nn::linear(p / "k", config.d_model, inner_dim, linear_config);
119 let value = nn::linear(p / "v", config.d_model, inner_dim, linear_config);
120 let query = nn::linear(p / "q", config.d_model, inner_dim, linear_config);
121 let output = nn::linear(p / "o", inner_dim, config.d_model, linear_config);
122
123 let dropout = Dropout::new(config.dropout_rate);
124 let relative_attention_bias = if has_relative_attention_bias {
125 Some(nn::embedding(
126 p / "relative_attention_bias",
127 config.relative_attention_num_buckets,
128 config.num_heads,
129 Default::default(),
130 ))
131 } else {
132 None
133 };
134
135 T5Attention {
136 is_decoder,
137 is_bidirectional,
138 has_relative_attention_bias,
139 relative_attention_num_buckets: config.relative_attention_num_buckets,
140 relative_attention_max_distance: config.relative_attention_max_distance.unwrap_or(128),
141 d_kv: config.d_kv,
142 n_heads: config.num_heads,
143 dropout,
144 inner_dim,
145 output_attentions,
146 store_cache,
147 query,
148 key,
149 value,
150 output,
151 relative_attention_bias,
152 }
153 }
154
155 fn unshape(&self, x: Tensor, bs: i64) -> Tensor {
156 x.transpose(1, 2)
157 .contiguous()
158 .view((bs, -1, self.inner_dim))
159 }
160
161 fn shape(&self, x: Tensor, bs: i64) -> Tensor {
162 x.view((bs, -1, self.n_heads, self.d_kv)).transpose(1, 2)
163 }
164
165 pub fn forward_t(
166 &self,
167 hidden_states: &Tensor,
168 key_value_states: Option<&Tensor>,
169 position_bias: Option<&Tensor>,
170 attention_mask: Option<&Tensor>,
171 mut layer_state: Option<LayerState>,
172 query_length: Option<i64>,
173 train: bool,
174 ) -> (Tensor, Option<Tensor>, Option<Tensor>, Option<LayerState>) {
175 let input_size = hidden_states.size();
176 let (bs, seq_length) = (input_size[0], input_size[1]);
177
178 let real_seq_length = if layer_state.is_some() {
179 match query_length {
180 Some(value) => value,
181 None => seq_length + layer_state.as_ref().unwrap().prev_key.size()[2],
182 }
183 } else {
184 seq_length
185 };
186
187 let key_length = match key_value_states {
188 Some(value) => value.size()[1],
189 None => real_seq_length,
190 };
191
192 let q: Tensor = self.shape(hidden_states.as_ref().apply(&self.query), bs);
193
194 let (mut k, mut v) = if let Some(key_value_states_value) = key_value_states {
195 (
196 self.shape(key_value_states_value.apply(&self.key), bs),
197 self.shape(key_value_states_value.apply(&self.value), bs),
198 )
199 } else {
200 (
201 self.shape(hidden_states.apply(&self.key), bs),
202 self.shape(hidden_states.apply(&self.value), bs),
203 )
204 };
205
206 if layer_state.is_some() {
207 let layer_state = layer_state.as_ref().unwrap();
208 if key_value_states.is_none() {
209 k = Tensor::cat(&[&layer_state.prev_key, &k], 2);
210 v = Tensor::cat(&[&layer_state.prev_value, &v], 2);
211 } else {
212 k = layer_state.prev_key.copy();
213 v = layer_state.prev_value.copy();
214 }
215 };
216
217 layer_state = if self.is_decoder & self.store_cache {
218 Some(LayerState {
219 prev_key: k.copy(),
220 prev_value: v.copy(),
221 })
222 } else {
223 None
224 };
225
226 let mut scores = Tensor::einsum("bnqd,bnkd->bnqk", &[q, k], None::<i64>);
227
228 let calculated_position_bias = if position_bias.is_none() {
229 let mut temp_value = if self.has_relative_attention_bias {
230 self.compute_bias(real_seq_length, key_length, hidden_states.device())
231 } else {
232 Tensor::zeros(
233 [1, self.n_heads, real_seq_length, key_length],
234 (scores.kind(), scores.device()),
235 )
236 };
237 if layer_state.is_some() {
238 let length = temp_value.size()[2];
239 temp_value = temp_value.slice(2, length - seq_length, length, 1);
240 };
241 if let Some(attention_mask) = attention_mask {
242 temp_value = temp_value + attention_mask
243 };
244 Some(temp_value)
245 } else {
246 None
247 };
248
249 let position_bias = if let Some(position_bias) = position_bias {
250 position_bias
251 } else {
252 calculated_position_bias.as_ref().unwrap()
253 };
254
255 scores += position_bias;
256
257 let attention_weights = scores
258 .softmax(-1, scores.kind())
259 .apply_t(&self.dropout, train);
260 let context = self
261 .unshape(attention_weights.matmul(&v), bs)
262 .apply(&self.output);
263
264 let attention_weights = if self.output_attentions {
265 Some(attention_weights)
266 } else {
267 None
268 };
269
270 let position_bias = if self.has_relative_attention_bias {
271 calculated_position_bias
272 } else {
273 None
274 };
275
276 (context, attention_weights, position_bias, layer_state)
277 }
278
279 fn compute_bias(&self, q_len: i64, k_len: i64, device: Device) -> Tensor {
280 let context_position = Tensor::arange(q_len, (Kind::Int64, device)).unsqueeze(1);
281 let memory_position = Tensor::arange(k_len, (Kind::Int64, device)).unsqueeze(0);
282 let relative_position = memory_position - context_position;
283
284 let rp_bucket = get_relative_position_bucket(
285 &relative_position,
286 self.is_bidirectional,
287 self.relative_attention_num_buckets,
288 self.relative_attention_max_distance,
289 );
290 rp_bucket
291 .apply(self.relative_attention_bias.as_ref().unwrap())
292 .permute([2, 0, 1])
293 .unsqueeze(0)
294 }
295}
296
297pub struct T5LayerSelfAttention {
298 self_attention: T5Attention,
299 layer_norm: T5LayerNorm,
300 dropout: Dropout,
301}
302
303impl T5LayerSelfAttention {
304 pub fn new<'p, P>(
305 p: P,
306 config: &T5Config,
307 has_relative_attention_bias: bool,
308 is_decoder: bool,
309 store_cache: bool,
310 output_attentions: bool,
311 ) -> T5LayerSelfAttention
312 where
313 P: Borrow<nn::Path<'p>>,
314 {
315 let p = p.borrow();
316
317 let self_attention = T5Attention::new(
318 p / "SelfAttention",
319 config,
320 is_decoder,
321 !is_decoder,
322 store_cache,
323 output_attentions,
324 has_relative_attention_bias,
325 );
326
327 let layer_norm =
328 T5LayerNorm::new(p / "layer_norm", config.d_model, config.layer_norm_epsilon);
329 let dropout = Dropout::new(config.dropout_rate);
330
331 T5LayerSelfAttention {
332 self_attention,
333 layer_norm,
334 dropout,
335 }
336 }
337
338 pub fn forward_t(
339 &self,
340 hidden_states: &Tensor,
341 position_bias: Option<&Tensor>,
342 attention_mask: Option<&Tensor>,
343 layer_state: Option<LayerState>,
344 train: bool,
345 ) -> (Tensor, Option<Tensor>, Option<Tensor>, Option<LayerState>) {
346 let norm_x = hidden_states.apply(&self.layer_norm);
347 let (y, attention_weights, position_bias, layer_state) = self.self_attention.forward_t(
348 &norm_x,
349 None,
350 position_bias,
351 attention_mask,
352 layer_state,
353 None,
354 train,
355 );
356
357 let output = hidden_states + y.apply_t(&self.dropout, train);
358
359 (output, attention_weights, position_bias, layer_state)
360 }
361}
362
363pub struct T5LayerCrossAttention {
364 encoder_decoder_attention: T5Attention,
365 layer_norm: T5LayerNorm,
366 dropout: Dropout,
367}
368
369impl T5LayerCrossAttention {
370 pub fn new<'p, P>(
371 p: P,
372 config: &T5Config,
373 has_relative_attention_bias: bool,
374 is_decoder: bool,
375 store_cache: bool,
376 output_attentions: bool,
377 ) -> T5LayerCrossAttention
378 where
379 P: Borrow<nn::Path<'p>>,
380 {
381 let p = p.borrow();
382
383 let encoder_decoder_attention = T5Attention::new(
384 p / "EncDecAttention",
385 config,
386 is_decoder,
387 true,
388 store_cache,
389 output_attentions,
390 has_relative_attention_bias,
391 );
392
393 let layer_norm =
394 T5LayerNorm::new(p / "layer_norm", config.d_model, config.layer_norm_epsilon);
395 let dropout = Dropout::new(config.dropout_rate);
396
397 T5LayerCrossAttention {
398 encoder_decoder_attention,
399 layer_norm,
400 dropout,
401 }
402 }
403
404 pub fn forward_t(
405 &self,
406 hidden_states: &Tensor,
407 kv: Option<&Tensor>,
408 position_bias: Option<&Tensor>,
409 attention_mask: Option<&Tensor>,
410 layer_state: Option<LayerState>,
411 query_length: Option<i64>,
412 train: bool,
413 ) -> (Tensor, Option<Tensor>, Option<Tensor>, Option<LayerState>) {
414 let norm_x = hidden_states.apply(&self.layer_norm);
415
416 let (y, attention_weights, position_bias, layer_state) =
417 self.encoder_decoder_attention.forward_t(
418 &norm_x,
419 kv,
420 position_bias,
421 attention_mask,
422 layer_state,
423 query_length,
424 train,
425 );
426
427 let output = hidden_states + y.apply_t(&self.dropout, train);
428
429 (output, attention_weights, position_bias, layer_state)
430 }
431}