trustformers_core/traits.rs
1//! Core traits defining the fundamental abstractions of TrustformeRS.
2//!
3//! This module contains the essential traits that form the foundation of the TrustformeRS
4//! transformer library. These traits define the interfaces for models, layers, configuration,
5//! tokenization, optimization, and parameter initialization.
6//!
7//! # Overview
8//!
9//! The traits in this module establish a consistent API across all transformer implementations:
10//!
11//! - [`Model`]: The main trait for transformer models with forward pass and loading capabilities
12//! - [`Layer`]: Building blocks for neural network architectures
13//! - [`Config`]: Configuration management for models and components
14//! - [`WeightReader`]: Interface for loading pretrained model weights
15//! - [`Tokenizer`]: Text tokenization and encoding/decoding
16//! - [`Optimizer`]: Parameter optimization algorithms
17//! - [`ParameterInit`]: Weight initialization strategies
18//!
19//! # Examples
20//!
21//! ```no_run
22//! use trustformers_core::traits::{Model, Config};
23//! use trustformers_core::tensor::Tensor;
24//! use trustformers_core::errors::Result;
25//! use std::io::Read;
26//! use serde::{Deserialize, Serialize};
27//!
28//! // Example model configuration
29//! #[derive(Debug, Deserialize, Serialize)]
30//! struct MyConfig { hidden_size: usize }
31//! impl Config for MyConfig {
32//! fn architecture(&self) -> &'static str { "my_model" }
33//! }
34//!
35//! // Example model implementation
36//! struct MyModel {
37//! config: MyConfig,
38//! // ... model layers
39//! }
40//!
41//! impl Model for MyModel {
42//! type Config = MyConfig;
43//! type Input = Tensor;
44//! type Output = Tensor;
45//!
46//! fn forward(&self, input: Self::Input) -> Result<Self::Output> {
47//! // Model forward pass implementation
48//! Ok(input)
49//! }
50//!
51//! fn load_pretrained(&mut self, _reader: &mut dyn Read) -> Result<()> {
52//! // Load pretrained weights
53//! Ok(())
54//! }
55//!
56//! fn get_config(&self) -> &Self::Config {
57//! &self.config
58//! }
59//!
60//! fn num_parameters(&self) -> usize { 0 }
61//! }
62//! ```
63
64use crate::errors::Result;
65use crate::tensor::Tensor;
66use serde::{Deserialize, Serialize};
67use std::io::Read;
68
69/// The main trait for transformer models.
70///
71/// This trait defines the interface that all transformer models must implement,
72/// providing a consistent API for forward passes, weight loading, and configuration access.
73///
74/// # Type Parameters
75///
76/// - `Config`: The configuration type for this model, must implement [`Config`]
77/// - `Input`: The input type for the model's forward pass
78/// - `Output`: The output type produced by the model
79///
80/// # Thread Safety
81///
82/// Models must be `Send + Sync` to support multi-threaded inference and training.
83///
84/// # Example
85///
86/// ```no_run
87/// use trustformers_core::traits::{Model, Config};
88/// use trustformers_core::tensor::Tensor;
89/// use trustformers_core::errors::Result;
90/// use std::io::Read;
91/// use serde::{Deserialize, Serialize};
92///
93/// #[derive(Deserialize, Serialize)]
94/// struct BertConfig {
95/// hidden_size: usize,
96/// num_attention_heads: usize,
97/// // ... other config fields
98/// }
99///
100/// impl Config for BertConfig {
101/// fn architecture(&self) -> &'static str {
102/// "bert"
103/// }
104/// }
105///
106/// struct BertModel {
107/// config: BertConfig,
108/// // ... model layers
109/// }
110///
111/// impl Model for BertModel {
112/// type Config = BertConfig;
113/// type Input = Tensor;
114/// type Output = Tensor;
115///
116/// fn forward(&self, input: Self::Input) -> Result<Self::Output> {
117/// // BERT forward pass implementation
118/// Ok(input)
119/// }
120///
121/// fn load_pretrained(&mut self, _reader: &mut dyn Read) -> Result<()> {
122/// // Load BERT weights from reader
123/// Ok(())
124/// }
125///
126/// fn get_config(&self) -> &Self::Config {
127/// &self.config
128/// }
129///
130/// fn num_parameters(&self) -> usize { 0 }
131/// }
132/// ```
133pub trait Model: Send + Sync {
134 type Config: Config;
135 type Input;
136 type Output;
137
138 /// Performs a forward pass through the model.
139 ///
140 /// # Arguments
141 ///
142 /// * `input` - The input data for the model
143 ///
144 /// # Returns
145 ///
146 /// Returns `Ok(output)` on success, or an error if the forward pass fails.
147 ///
148 /// # Errors
149 ///
150 /// May return errors for:
151 /// - Invalid input dimensions
152 /// - Numerical computation errors
153 /// - Out of memory conditions
154 fn forward(&self, input: Self::Input) -> Result<Self::Output>;
155
156 /// Loads pretrained weights into the model.
157 ///
158 /// This method reads model weights from a reader (typically a file or network stream)
159 /// and updates the model's parameters accordingly.
160 ///
161 /// # Arguments
162 ///
163 /// * `reader` - A reader providing access to the pretrained weight data
164 ///
165 /// # Returns
166 ///
167 /// Returns `Ok(())` on successful loading, or an error if loading fails.
168 ///
169 /// # Errors
170 ///
171 /// May return errors for:
172 /// - IO errors while reading
173 /// - Incompatible weight formats
174 /// - Mismatched tensor shapes
175 fn load_pretrained(&mut self, reader: &mut dyn Read) -> Result<()>;
176
177 /// Returns a reference to the model's configuration.
178 ///
179 /// # Returns
180 ///
181 /// A reference to the model's configuration object.
182 fn get_config(&self) -> &Self::Config;
183
184 /// Returns the total number of parameters in the model.
185 ///
186 /// This method calculates the total number of trainable parameters
187 /// across all layers in the model. It's useful for compression metrics,
188 /// model size analysis, and memory usage calculations.
189 ///
190 /// # Returns
191 ///
192 /// The total number of parameters as a `usize`.
193 ///
194 /// # Example
195 ///
196 /// ```no_run
197 /// use trustformers_core::traits::Model;
198 ///
199 /// fn analyze_model_size<M: Model>(model: &M) {
200 /// let params = model.num_parameters();
201 /// let memory_mb = params * 4 / (1024 * 1024); // Assuming f32 weights
202 /// println!("Model has {} parameters ({} MB)", params, memory_mb);
203 /// }
204 /// ```
205 fn num_parameters(&self) -> usize;
206
207 /// Enumerates the model's parameters as `(name, tensor)` pairs.
208 ///
209 /// This is the canonical way to read a model's weights without knowing its
210 /// concrete type. Names should follow the checkpoint convention used by the
211 /// model family (for example `encoder.layer.0.attention.self.query.weight`),
212 /// because downstream tooling keys off them.
213 ///
214 /// # Contract
215 ///
216 /// * Every returned name must be unique.
217 /// * The returned tensors must be the *live* parameters of the model, not
218 /// copies that were synthesised on the fly.
219 /// * The order should be stable across calls on an unmodified model so that
220 /// serialised artifacts are reproducible.
221 ///
222 /// # Default Implementation
223 ///
224 /// The default returns an empty vector, so that existing implementations keep
225 /// compiling. **Model implementations that want to be exportable must override
226 /// it**: every exporter in [`crate::export`] refuses to write a file for a model
227 /// that exposes no named tensors, rather than inventing weights. The same is
228 /// true for the checkpoint writers and weight converters.
229 ///
230 /// # Example
231 ///
232 /// ```no_run
233 /// use trustformers_core::traits::Model;
234 ///
235 /// fn total_bytes<M: Model>(model: &M) -> usize {
236 /// model
237 /// .named_tensors()
238 /// .iter()
239 /// .map(|(_, tensor)| tensor.size_bytes())
240 /// .sum()
241 /// }
242 /// ```
243 fn named_tensors(&self) -> Vec<(String, &Tensor)> {
244 Vec::new()
245 }
246
247 /// Mutable counterpart of [`Model::named_tensors`].
248 ///
249 /// Used by weight loaders to copy checkpoint tensors into a live model. The
250 /// same contract applies: unique names, live parameters, stable order. The
251 /// default returns an empty vector, which makes weight loading fail loudly
252 /// instead of silently doing nothing.
253 fn named_tensors_mut(&mut self) -> Vec<(String, &mut Tensor)> {
254 Vec::new()
255 }
256}
257
258/// A building block for neural network architectures.
259///
260/// The `Layer` trait represents a single computational unit in a neural network,
261/// such as a linear transformation, attention mechanism, or normalization layer.
262/// Layers can be composed together to build complete models.
263///
264/// # Type Parameters
265///
266/// - `Input`: The input type accepted by this layer
267/// - `Output`: The output type produced by this layer
268///
269/// # Thread Safety
270///
271/// Layers must be `Send + Sync` to support parallel computation.
272///
273/// # Example
274///
275/// ```no_run
276/// use trustformers_core::traits::Layer;
277/// use trustformers_core::tensor::Tensor;
278/// use trustformers_core::errors::Result;
279///
280/// struct LinearLayer {
281/// weight: Tensor,
282/// bias: Option<Tensor>,
283/// }
284///
285/// impl Layer for LinearLayer {
286/// type Input = Tensor;
287/// type Output = Tensor;
288///
289/// fn forward(&self, input: Self::Input) -> Result<Self::Output> {
290/// // Compute linear transformation: y = xW^T + b
291/// let output = input.matmul(&self.weight.transpose(0, 1)?)?;
292/// if let Some(bias) = &self.bias {
293/// output.add(bias)
294/// } else {
295/// Ok(output)
296/// }
297/// }
298/// }
299/// ```
300pub trait Layer: Send + Sync {
301 type Input;
302 type Output;
303
304 /// Performs the forward computation of this layer.
305 ///
306 /// # Arguments
307 ///
308 /// * `input` - The input data to process
309 ///
310 /// # Returns
311 ///
312 /// Returns `Ok(output)` containing the layer's output, or an error if computation fails.
313 ///
314 /// # Errors
315 ///
316 /// May return errors for:
317 /// - Invalid input dimensions
318 /// - Numerical errors during computation
319 /// - Resource allocation failures
320 fn forward(&self, input: Self::Input) -> Result<Self::Output>;
321
322 /// Performs the forward computation **without taking ownership** of the input.
323 ///
324 /// # Why this exists
325 ///
326 /// Attention projects one hidden-state tensor into query, key and value. With
327 /// an owning-only API that is three deep copies of a `[batch, seq, hidden]`
328 /// tensor per attention block, per forward pass — pure waste, because none of
329 /// the projection code needs to own its input. Layers that can compute from a
330 /// borrow override this method; the attention layers call it.
331 ///
332 /// # Contract
333 ///
334 /// An override **must** produce exactly the same output as
335 /// [`Layer::forward`] for the same input. The two are checked against each
336 /// other in the layer test suites.
337 ///
338 /// # Default Implementation
339 ///
340 /// Clones the input and delegates to [`Layer::forward`], so every existing
341 /// implementation keeps working unchanged. A type that overrides
342 /// `forward_ref` must therefore implement `forward` in terms of
343 /// `forward_ref` (or independently) — never the other way round, which would
344 /// recurse forever.
345 ///
346 /// # Errors
347 ///
348 /// The same conditions as [`Layer::forward`].
349 fn forward_ref(&self, input: &Self::Input) -> Result<Self::Output>
350 where
351 Self::Input: Clone,
352 {
353 self.forward(input.clone())
354 }
355}
356
357/// Configuration trait for models and components.
358///
359/// This trait provides a standardized interface for configuration objects
360/// that can be serialized, deserialized, and validated. All model configurations
361/// must implement this trait to ensure compatibility with the TrustformeRS ecosystem.
362///
363/// # Requirements
364///
365/// Implementing types must be serializable and deserializable using serde.
366///
367/// # Example
368///
369/// ```no_run
370/// use trustformers_core::traits::Config;
371/// use trustformers_core::errors::{Result, TrustformersError};
372/// use serde::{Deserialize, Serialize};
373///
374/// #[derive(Debug, Clone, Deserialize, Serialize)]
375/// struct GPT2Config {
376/// vocab_size: usize,
377/// hidden_size: usize,
378/// num_layers: usize,
379/// num_heads: usize,
380/// }
381///
382/// impl Config for GPT2Config {
383/// fn validate(&self) -> Result<()> {
384/// if self.hidden_size % self.num_heads != 0 {
385/// return Err(TrustformersError::invalid_input(
386/// "hidden_size must be divisible by num_heads".to_string(),
387/// ));
388/// }
389/// Ok(())
390/// }
391///
392/// fn architecture(&self) -> &'static str {
393/// "gpt2"
394/// }
395/// }
396/// ```
397pub trait Config: for<'de> Deserialize<'de> + Serialize {
398 /// Validates the configuration for correctness.
399 ///
400 /// This method should check that all configuration parameters are valid
401 /// and compatible with each other. The default implementation accepts
402 /// all configurations as valid.
403 ///
404 /// # Returns
405 ///
406 /// Returns `Ok(())` if the configuration is valid, or an error describing
407 /// the validation failure.
408 ///
409 /// # Example
410 ///
411 /// Common validations include:
412 /// - Checking that dimensions are compatible
413 /// - Verifying that values are within acceptable ranges
414 /// - Ensuring required fields are properly set
415 fn validate(&self) -> Result<()> {
416 Ok(())
417 }
418
419 /// Returns the architecture name for this configuration.
420 ///
421 /// This should return a static string identifying the model architecture,
422 /// such as "bert", "gpt2", "t5", etc. This is used for model registration
423 /// and automatic model selection.
424 ///
425 /// # Returns
426 ///
427 /// A static string slice containing the architecture name.
428 fn architecture(&self) -> &'static str;
429}
430
431/// Interface for reading model weights from various sources.
432///
433/// `WeightReader` provides an abstraction over different weight storage formats,
434/// allowing models to load pretrained parameters from files, network sources,
435/// or other storage backends.
436///
437/// # Supported Formats
438///
439/// Implementations may support various formats including:
440/// - SafeTensors (.safetensors)
441/// - PyTorch checkpoints (.pt, .bin)
442/// - NumPy arrays (.npz)
443/// - Custom formats
444///
445/// # Example
446///
447/// ```no_run
448/// use trustformers_core::traits::WeightReader;
449/// use trustformers_core::tensor::Tensor;
450/// use trustformers_core::errors::Result;
451///
452/// struct SafeTensorsReader {
453/// // ... implementation details
454/// }
455///
456/// impl WeightReader for SafeTensorsReader {
457/// fn read_tensor(&mut self, _name: &str) -> Result<Tensor> {
458/// // Read tensor from SafeTensors file
459/// Ok(Tensor::zeros(&[768, 768])?)
460/// }
461///
462/// fn list_tensors(&self) -> Vec<String> {
463/// vec![
464/// "bert.embeddings.word_embeddings.weight".to_string(),
465/// "bert.encoder.layer.0.attention.self.query.weight".to_string(),
466/// // ... more tensor names
467/// ]
468/// }
469/// }
470/// ```
471pub trait WeightReader {
472 /// Reads a tensor by name from the weight source.
473 ///
474 /// # Arguments
475 ///
476 /// * `name` - The name/key of the tensor to read (e.g., "encoder.layer.0.weight")
477 ///
478 /// # Returns
479 ///
480 /// Returns `Ok(tensor)` containing the requested tensor, or an error if the
481 /// tensor cannot be found or loaded.
482 ///
483 /// # Errors
484 ///
485 /// May return errors for:
486 /// - Tensor not found with the given name
487 /// - IO errors while reading
488 /// - Corrupted or invalid tensor data
489 /// - Unsupported tensor format
490 fn read_tensor(&mut self, name: &str) -> Result<Tensor>;
491
492 /// Lists all available tensor names in the weight source.
493 ///
494 /// This method is useful for debugging and for discovering the structure
495 /// of saved model weights.
496 ///
497 /// # Returns
498 ///
499 /// A vector containing the names of all available tensors.
500 fn list_tensors(&self) -> Vec<String>;
501}
502
503/// Text tokenization interface for transformer models.
504///
505/// The `Tokenizer` trait provides methods for converting between text and token IDs,
506/// which is essential for preparing input data for transformer models. Implementations
507/// may use various tokenization algorithms such as WordPiece, BPE, or SentencePiece.
508///
509/// # Thread Safety
510///
511/// Tokenizers must be `Send + Sync` to support concurrent tokenization.
512///
513/// # Example
514///
515/// ```no_run
516/// use trustformers_core::traits::{Tokenizer, TokenizedInput};
517/// use trustformers_core::errors::Result;
518/// use std::collections::HashMap;
519///
520/// struct BertTokenizer {
521/// vocab: HashMap<String, u32>,
522/// // ... other fields
523/// }
524///
525/// impl Tokenizer for BertTokenizer {
526/// fn encode(&self, _text: &str) -> Result<TokenizedInput> {
527/// // Tokenize text into subwords
528/// let tokens: Vec<u32> = vec![101, 2023, 2003, 1037, 3231, 102]; // [CLS] this is a test [SEP]
529/// Ok(TokenizedInput::new(tokens, vec![1; 6]))
530/// }
531///
532/// fn encode_pair(&self, text: &str, text2: &str) -> Result<TokenizedInput> {
533/// // Encode two texts for tasks like question answering
534/// let tokens1 = self.encode(text)?;
535/// let tokens2 = self.encode(text2)?;
536/// // Combine tokens with separator
537/// let len1 = tokens1.input_ids.len();
538/// let len2 = tokens2.input_ids.len();
539/// let mut combined_ids = tokens1.input_ids;
540/// combined_ids.extend_from_slice(&tokens2.input_ids);
541/// let combined_len = combined_ids.len();
542/// Ok(TokenizedInput::with_token_type_ids(
543/// combined_ids,
544/// vec![1; combined_len],
545/// Some(vec![0; len1].into_iter().chain(vec![1; len2]).collect()),
546/// ))
547/// }
548///
549/// fn decode(&self, _ids: &[u32]) -> Result<String> {
550/// // Convert token IDs back to text
551/// Ok("this is a test".to_string())
552/// }
553///
554/// fn vocab_size(&self) -> usize {
555/// 30522 // BERT base vocabulary size
556/// }
557///
558/// fn get_vocab(&self) -> HashMap<String, u32> {
559/// self.vocab.clone()
560/// }
561///
562/// fn token_to_id(&self, token: &str) -> Option<u32> {
563/// self.vocab.get(token).copied()
564/// }
565///
566/// fn id_to_token(&self, id: u32) -> Option<String> {
567/// self.vocab.iter().find(|(_, &v)| v == id).map(|(k, _)| k.clone())
568/// }
569/// }
570/// ```
571pub trait Tokenizer: Send + Sync {
572 /// Encodes a single text string into tokens.
573 ///
574 /// # Arguments
575 ///
576 /// * `text` - The input text to tokenize
577 ///
578 /// # Returns
579 ///
580 /// Returns a `TokenizedInput` containing:
581 /// - `input_ids`: The token IDs
582 /// - `attention_mask`: Binary mask indicating real vs padding tokens
583 /// - `token_type_ids`: Optional segment IDs for models like BERT
584 ///
585 /// # Errors
586 ///
587 /// May return errors for:
588 /// - Invalid UTF-8 sequences
589 /// - Text exceeding maximum length
590 /// - Unknown tokens that cannot be handled
591 fn encode(&self, text: &str) -> Result<TokenizedInput>;
592
593 /// Encodes a pair of texts for sequence-pair tasks.
594 ///
595 /// This method is used for tasks that require two input sequences,
596 /// such as question answering, textual entailment, or sequence classification.
597 ///
598 /// # Arguments
599 ///
600 /// * `text` - The first text sequence
601 /// * `text2` - The second text sequence
602 ///
603 /// # Returns
604 ///
605 /// Returns a `TokenizedInput` with both sequences encoded and separated
606 /// by appropriate special tokens (e.g., `[SEP]` for BERT).
607 ///
608 /// # Errors
609 ///
610 /// May return errors for the same reasons as `encode()`.
611 fn encode_pair(&self, text: &str, text2: &str) -> Result<TokenizedInput>;
612
613 /// Decodes token IDs back into text.
614 ///
615 /// # Arguments
616 ///
617 /// * `ids` - The token IDs to decode
618 ///
619 /// # Returns
620 ///
621 /// Returns the decoded text string. Special tokens may be included
622 /// or excluded depending on the implementation.
623 ///
624 /// # Errors
625 ///
626 /// May return errors for:
627 /// - Invalid token IDs
628 /// - Decoding errors
629 fn decode(&self, ids: &[u32]) -> Result<String>;
630
631 /// Returns the size of the tokenizer's vocabulary.
632 ///
633 /// # Returns
634 ///
635 /// The total number of tokens in the vocabulary.
636 fn vocab_size(&self) -> usize;
637
638 /// Returns a copy of the vocabulary as a mapping from tokens to IDs.
639 ///
640 /// # Returns
641 ///
642 /// A HashMap containing the vocabulary mapping.
643 fn get_vocab(&self) -> std::collections::HashMap<String, u32>;
644
645 /// Converts a token string to its corresponding ID.
646 ///
647 /// # Arguments
648 ///
649 /// * `token` - The token string to convert
650 ///
651 /// # Returns
652 ///
653 /// The token ID if the token exists in the vocabulary, None otherwise.
654 fn token_to_id(&self, token: &str) -> Option<u32>;
655
656 /// Converts a token ID to its corresponding token string.
657 ///
658 /// # Arguments
659 ///
660 /// * `id` - The token ID to convert
661 ///
662 /// # Returns
663 ///
664 /// The token string if the ID exists in the vocabulary, None otherwise.
665 fn id_to_token(&self, id: u32) -> Option<String>;
666}
667
668/// Represents tokenized input ready for model consumption.
669///
670/// `TokenizedInput` contains all the necessary components for feeding
671/// text data into a transformer model after tokenization.
672///
673/// # Fields
674///
675/// * `input_ids` - The token IDs representing the input text
676/// * `attention_mask` - Binary mask (0 or 1) indicating which tokens are real vs padding
677/// * `token_type_ids` - Optional segment IDs for models that use them (e.g., BERT)
678///
679/// # Example
680///
681/// ```no_run
682/// use trustformers_core::traits::TokenizedInput;
683///
684/// let input = TokenizedInput::with_token_type_ids(
685/// vec![101, 2023, 2003, 1037, 3231, 102], // [CLS] this is a test [SEP]
686/// vec![1, 1, 1, 1, 1, 1], // All tokens are real (not padding)
687/// Some(vec![0, 0, 0, 0, 0, 0]), // All tokens from first segment
688/// );
689/// ```
690#[derive(Debug, Clone, Default)]
691pub struct TokenizedInput {
692 /// Token IDs representing the encoded text.
693 /// These correspond to entries in the tokenizer's vocabulary.
694 pub input_ids: Vec<u32>,
695
696 /// Binary attention mask indicating real tokens (1) vs padding tokens (0).
697 /// This prevents the model from attending to padding tokens.
698 pub attention_mask: Vec<u8>,
699
700 /// Optional token type IDs for distinguishing between different segments.
701 /// Used by models like BERT for tasks involving multiple sequences.
702 /// Typically 0 for the first sequence and 1 for the second sequence.
703 pub token_type_ids: Option<Vec<u32>>,
704
705 /// Optional special tokens mask indicating special tokens (1) vs regular tokens (0).
706 /// Used to identify tokens like `[CLS]`, `[SEP]`, `[PAD]` etc.
707 pub special_tokens_mask: Option<Vec<u8>>,
708
709 /// Optional offset mapping showing where each token sits in the original text.
710 ///
711 /// Each tuple is a `(start, end)` **byte** offset into that text, so
712 /// `&text[start..end]` is the substring the token came from. Byte offsets —
713 /// not character (code point) offsets — are the in-tree convention:
714 /// every producer of this field emits byte spans, and the tokenizer tests
715 /// assert the round trip against `text.as_bytes()`.
716 ///
717 /// Callers that need character offsets (Python's `str` indexing, for
718 /// instance) convert at the boundary with
719 /// `trustformers_tokenizers::byte_offsets_to_char_offsets`, whose inverse is
720 /// `char_offsets_to_byte_offsets`. Converting anywhere other than the
721 /// boundary risks a double conversion, which is silent for ASCII and wrong
722 /// for everything else.
723 ///
724 /// Special tokens that correspond to no input text (`[CLS]`, `[SEP]`, and
725 /// friends) carry `(0, 0)`.
726 pub offset_mapping: Option<Vec<(usize, usize)>>,
727
728 /// Optional overflowing tokens when text exceeds max length.
729 /// Contains tokens that were truncated from the input.
730 pub overflowing_tokens: Option<Vec<u32>>,
731}
732
733impl TokenizedInput {
734 /// Create a new TokenizedInput with minimal required fields
735 pub fn new(input_ids: Vec<u32>, attention_mask: Vec<u8>) -> Self {
736 Self {
737 input_ids,
738 attention_mask,
739 token_type_ids: None,
740 special_tokens_mask: None,
741 offset_mapping: None,
742 overflowing_tokens: None,
743 }
744 }
745
746 /// Create a new TokenizedInput with token type IDs
747 pub fn with_token_type_ids(
748 input_ids: Vec<u32>,
749 attention_mask: Vec<u8>,
750 token_type_ids: Option<Vec<u32>>,
751 ) -> Self {
752 Self {
753 input_ids,
754 attention_mask,
755 token_type_ids,
756 special_tokens_mask: None,
757 offset_mapping: None,
758 overflowing_tokens: None,
759 }
760 }
761}
762
763/// Parameter optimization algorithms for training neural networks.
764///
765/// The `Optimizer` trait defines the interface for gradient-based optimization
766/// algorithms such as SGD, Adam, AdamW, etc. Optimizers update model parameters
767/// based on computed gradients to minimize the loss function.
768///
769/// # Thread Safety
770///
771/// Optimizers must be `Send + Sync` to support distributed training.
772///
773/// # Example
774///
775/// ```no_run
776/// use trustformers_core::traits::Optimizer;
777/// use trustformers_core::tensor::Tensor;
778/// use trustformers_core::errors::Result;
779///
780/// struct SGD {
781/// learning_rate: f32,
782/// momentum: f32,
783/// velocity: std::collections::HashMap<String, Tensor>,
784/// }
785///
786/// impl Optimizer for SGD {
787/// fn update(&mut self, _parameter: &mut Tensor, _grad: &Tensor) -> Result<()> {
788/// // SGD with momentum: v = momentum * v - lr * grad
789/// // parameter += v
790/// Ok(())
791/// }
792///
793/// fn zero_grad(&mut self) {
794/// // Clear accumulated gradients
795/// }
796///
797/// fn step(&mut self) {
798/// // Apply updates to all parameters
799/// }
800///
801/// fn get_lr(&self) -> f32 {
802/// self.learning_rate
803/// }
804///
805/// fn set_lr(&mut self, lr: f32) {
806/// self.learning_rate = lr;
807/// }
808/// }
809/// ```
810pub trait Optimizer: Send + Sync {
811 /// Updates a parameter based on its gradient.
812 ///
813 /// # Arguments
814 ///
815 /// * `parameter` - The parameter tensor to update
816 /// * `grad` - The gradient tensor for this parameter
817 ///
818 /// # Returns
819 ///
820 /// Returns `Ok(())` on successful update, or an error if the update fails.
821 ///
822 /// # Errors
823 ///
824 /// May return errors for:
825 /// - Mismatched tensor shapes
826 /// - Numerical errors (e.g., NaN or Inf values)
827 /// - Memory allocation failures
828 fn update(&mut self, parameter: &mut Tensor, grad: &Tensor) -> Result<()>;
829
830 /// Clears all accumulated gradients.
831 ///
832 /// This should be called before each backward pass to ensure
833 /// gradients don't accumulate across batches (unless gradient
834 /// accumulation is intentionally being used).
835 fn zero_grad(&mut self);
836
837 /// Performs a single optimization step.
838 ///
839 /// This method applies all pending parameter updates. It should be
840 /// called after gradients have been computed for all parameters.
841 fn step(&mut self);
842
843 /// Gets the current learning rate.
844 ///
845 /// # Returns
846 ///
847 /// The current learning rate value.
848 fn get_lr(&self) -> f32;
849
850 /// Sets a new learning rate.
851 ///
852 /// # Arguments
853 ///
854 /// * `lr` - The new learning rate value
855 ///
856 /// # Note
857 ///
858 /// This is useful for implementing learning rate schedules.
859 fn set_lr(&mut self, lr: f32);
860
861 /// Accumulates gradients for gradient accumulation.
862 ///
863 /// This method is used when training with gradient accumulation,
864 /// where gradients from multiple batches are accumulated before
865 /// performing an update step.
866 ///
867 /// # Arguments
868 ///
869 /// * `parameter` - The parameter tensor
870 /// * `grad` - The gradient to accumulate
871 ///
872 /// # Returns
873 ///
874 /// Returns `Ok(())` on success, or an error if accumulation fails.
875 ///
876 /// # Default Implementation
877 ///
878 /// The default implementation simply calls `update()`. Override this
879 /// method for optimizers that need special gradient accumulation logic.
880 fn accumulate_grad(&mut self, parameter: &mut Tensor, grad: &Tensor) -> Result<()> {
881 // Default implementation: just store the gradient for later use
882 self.update(parameter, grad)
883 }
884
885 /// Applies accumulated gradients after gradient accumulation.
886 ///
887 /// This method should be called after accumulating gradients from
888 /// multiple batches to apply the averaged update.
889 ///
890 /// # Arguments
891 ///
892 /// * `accumulation_steps` - The number of accumulation steps performed
893 ///
894 /// # Returns
895 ///
896 /// Returns `Ok(())` on success, or an error if application fails.
897 ///
898 /// # Default Implementation
899 ///
900 /// The default implementation is a no-op. Override this method for
901 /// optimizers that implement gradient accumulation.
902 fn apply_accumulated_grads(&mut self, accumulation_steps: usize) -> Result<()> {
903 // Default implementation: no-op, override if needed
904 let _ = accumulation_steps;
905 Ok(())
906 }
907}
908
909/// Weight initialization strategies for neural network parameters.
910///
911/// The `ParameterInit` trait provides various initialization methods that help
912/// ensure proper gradient flow and training stability. Different initialization
913/// strategies are optimal for different activation functions and architectures.
914///
915/// # Example
916///
917/// ```no_run
918/// use trustformers_core::traits::ParameterInit;
919///
920/// // Example type implementing ParameterInit
921/// struct WeightMatrix {
922/// data: Vec<f32>,
923/// shape: [usize; 2],
924/// }
925///
926/// impl ParameterInit for WeightMatrix {
927/// fn normal(&mut self, mean: f32, std: f32) {
928/// // fill data with normal distribution values
929/// }
930/// fn uniform(&mut self, min: f32, max: f32) {
931/// // fill data with uniform distribution values
932/// }
933/// fn xavier_uniform(&mut self) {
934/// // Xavier/Glorot initialization
935/// }
936/// fn xavier_normal(&mut self) {}
937/// fn kaiming_uniform(&mut self, _mode: &str, _nonlinearity: &str) {}
938/// fn kaiming_normal(&mut self, _mode: &str, _nonlinearity: &str) {}
939/// }
940///
941/// let mut weight = WeightMatrix { data: vec![0.0; 768 * 768], shape: [768, 768] };
942///
943/// // Initialize with Xavier/Glorot uniform for tanh activations
944/// weight.xavier_uniform();
945///
946/// // Or use Kaiming/He initialization for ReLU activations
947/// weight.kaiming_normal("fan_in", "relu");
948/// ```
949pub trait ParameterInit {
950 /// Initializes the tensor with values from a normal distribution.
951 ///
952 /// # Arguments
953 ///
954 /// * `mean` - The mean of the normal distribution
955 /// * `std` - The standard deviation of the normal distribution
956 ///
957 /// # Example
958 ///
959 /// ```no_run
960 /// # use trustformers_core::traits::ParameterInit;
961 /// # struct Weights { data: Vec<f32> }
962 /// # impl ParameterInit for Weights {
963 /// # fn normal(&mut self, mean: f32, std: f32) {}
964 /// # fn uniform(&mut self, min: f32, max: f32) {}
965 /// # fn xavier_uniform(&mut self) {}
966 /// # fn xavier_normal(&mut self) {}
967 /// # fn kaiming_uniform(&mut self, _: &str, _: &str) {}
968 /// # fn kaiming_normal(&mut self, _: &str, _: &str) {}
969 /// # }
970 /// let mut tensor = Weights { data: vec![0.0; 10000] };
971 /// tensor.normal(0.0, 0.02); // Common for transformer embeddings
972 /// ```
973 fn normal(&mut self, mean: f32, std: f32);
974
975 /// Initializes the tensor with values from a uniform distribution.
976 ///
977 /// # Arguments
978 ///
979 /// * `min` - The minimum value (inclusive)
980 /// * `max` - The maximum value (exclusive)
981 ///
982 /// # Example
983 ///
984 /// ```no_run
985 /// # use trustformers_core::traits::ParameterInit;
986 /// # struct Weights { data: Vec<f32> }
987 /// # impl ParameterInit for Weights {
988 /// # fn normal(&mut self, mean: f32, std: f32) {}
989 /// # fn uniform(&mut self, min: f32, max: f32) {}
990 /// # fn xavier_uniform(&mut self) {}
991 /// # fn xavier_normal(&mut self) {}
992 /// # fn kaiming_uniform(&mut self, _: &str, _: &str) {}
993 /// # fn kaiming_normal(&mut self, _: &str, _: &str) {}
994 /// # }
995 /// let mut tensor = Weights { data: vec![0.0; 10000] };
996 /// tensor.uniform(-0.1, 0.1);
997 /// ```
998 fn uniform(&mut self, min: f32, max: f32);
999
1000 /// Xavier/Glorot uniform initialization.
1001 ///
1002 /// Initializes weights to maintain variance across layers, optimal for
1003 /// tanh and sigmoid activations. The range is [-x, x] where
1004 /// x = sqrt(6 / (fan_in + fan_out)).
1005 ///
1006 /// # References
1007 ///
1008 /// Glorot & Bengio (2010): "Understanding the difficulty of training
1009 /// deep feedforward neural networks"
1010 fn xavier_uniform(&mut self);
1011
1012 /// Xavier/Glorot normal initialization.
1013 ///
1014 /// Similar to `xavier_uniform` but uses a normal distribution with
1015 /// std = sqrt(2 / (fan_in + fan_out)).
1016 fn xavier_normal(&mut self);
1017
1018 /// Kaiming/He uniform initialization.
1019 ///
1020 /// Designed for ReLU and similar activations. Maintains variance when
1021 /// half of the neurons are zeroed out by ReLU.
1022 ///
1023 /// # Arguments
1024 ///
1025 /// * `mode` - Either "fan_in" or "fan_out", determines which dimension to use
1026 /// * `nonlinearity` - The activation function ("relu", "leaky_relu", "linear")
1027 ///
1028 /// # Example
1029 ///
1030 /// ```no_run
1031 /// # use trustformers_core::traits::ParameterInit;
1032 /// # struct Weights { data: Vec<f32> }
1033 /// # impl ParameterInit for Weights {
1034 /// # fn normal(&mut self, mean: f32, std: f32) {}
1035 /// # fn uniform(&mut self, min: f32, max: f32) {}
1036 /// # fn xavier_uniform(&mut self) {}
1037 /// # fn xavier_normal(&mut self) {}
1038 /// # fn kaiming_uniform(&mut self, _: &str, _: &str) {}
1039 /// # fn kaiming_normal(&mut self, _: &str, _: &str) {}
1040 /// # }
1041 /// let mut conv_weight = Weights { data: vec![0.0; 64 * 32 * 3 * 3] };
1042 /// conv_weight.kaiming_uniform("fan_in", "relu");
1043 /// ```
1044 ///
1045 /// # References
1046 ///
1047 /// He et al. (2015): "Delving Deep into Rectifiers: Surpassing
1048 /// Human-Level Performance on ImageNet Classification"
1049 fn kaiming_uniform(&mut self, mode: &str, nonlinearity: &str);
1050
1051 /// Kaiming/He normal initialization.
1052 ///
1053 /// Similar to `kaiming_uniform` but uses a normal distribution.
1054 /// Generally preferred over uniform for deeper networks.
1055 ///
1056 /// # Arguments
1057 ///
1058 /// * `mode` - Either "fan_in" or "fan_out"
1059 /// * `nonlinearity` - The activation function ("relu", "leaky_relu", "linear")
1060 fn kaiming_normal(&mut self, mode: &str, nonlinearity: &str);
1061}