Initial commit

This commit is contained in:
redclawsystems
2026-03-04 00:08:42 +00:00
commit 4d88dc0584
4449 changed files with 1556714 additions and 0 deletions
@@ -0,0 +1,160 @@
//! Attention mechanisms for translation models
use crate::Result;
use rtx_tensor::Tensor;
use serde::{Deserialize, Serialize};
/// Attention mechanism types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AttentionType {
/// Additive (Bahdanau) attention
Additive,
/// Multiplicative (Luong) attention
Multiplicative,
/// Scaled dot-product attention
ScaledDotProduct,
/// Multi-head attention
MultiHead { num_heads: usize },
}
/// Attention configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttentionConfig {
pub attention_type: AttentionType,
pub hidden_size: usize,
pub dropout_rate: f32,
pub temperature: f32,
}
impl Default for AttentionConfig {
fn default() -> Self {
Self {
attention_type: AttentionType::ScaledDotProduct,
hidden_size: 512,
dropout_rate: 0.1,
temperature: 1.0,
}
}
}
/// Attention layer for sequence-to-sequence models
pub struct AttentionLayer {
config: AttentionConfig,
}
impl AttentionLayer {
pub fn new(config: AttentionConfig) -> Self {
Self { config }
}
/// Apply attention mechanism
pub fn forward(
&self,
query: &Tensor,
key: &Tensor,
value: &Tensor,
mask: Option<&Tensor>,
) -> Result<(Tensor, Tensor)> {
match &self.config.attention_type {
AttentionType::Additive => self.additive_attention(query, key, value, mask),
AttentionType::Multiplicative => self.multiplicative_attention(query, key, value, mask),
AttentionType::ScaledDotProduct => {
self.scaled_dot_product_attention(query, key, value, mask)
}
AttentionType::MultiHead { num_heads } => {
self.multi_head_attention(query, key, value, mask, *num_heads)
}
}
}
fn scaled_dot_product_attention(
&self,
query: &Tensor,
key: &Tensor,
value: &Tensor,
_mask: Option<&Tensor>,
) -> Result<(Tensor, Tensor)> {
// Compute attention scores: Q * K^T / sqrt(d_k)
let key_shape = key.shape().dims();
let d_k = key_shape[key_shape.len() - 1] as f32;
let scores = (query.matmul(&key.transpose(-2, -1)?)? / d_k.sqrt())?;
// Apply mask if provided
// Note: Stubbed - where_cond not available in rtx-tensor
let masked_scores = scores;
// Apply softmax to get attention weights
let attention_weights = masked_scores.softmax(-1)?;
// Apply attention to values
let context = attention_weights.matmul(value)?;
Ok((context, attention_weights))
}
fn additive_attention(
&self,
query: &Tensor,
key: &Tensor,
value: &Tensor,
_mask: Option<&Tensor>,
) -> Result<(Tensor, Tensor)> {
// Mock implementation - in practice would use learned parameters
let scores = query.matmul(&key.transpose(-2, -1)?)?;
let attention_weights = scores.softmax(-1)?;
let context = attention_weights.matmul(value)?;
Ok((context, attention_weights))
}
fn multiplicative_attention(
&self,
query: &Tensor,
key: &Tensor,
value: &Tensor,
_mask: Option<&Tensor>,
) -> Result<(Tensor, Tensor)> {
// Mock implementation
let scores = query.matmul(&key.transpose(-2, -1)?)?;
let attention_weights = scores.softmax(-1)?;
let context = attention_weights.matmul(value)?;
Ok((context, attention_weights))
}
fn multi_head_attention(
&self,
query: &Tensor,
key: &Tensor,
value: &Tensor,
mask: Option<&Tensor>,
_num_heads: usize,
) -> Result<(Tensor, Tensor)> {
// For simplicity, delegate to scaled dot-product
self.scaled_dot_product_attention(query, key, value, mask)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rtx_tensor::Device;
#[test]
fn test_attention_layer() -> Result<()> {
let config = AttentionConfig::default();
let layer = AttentionLayer::new(config);
let seq_len = 10;
let hidden_size = 64;
let device = Device::cuda(0).unwrap_or(Device::default());
let query = Tensor::randn(&[1, seq_len, hidden_size], &device)?;
let key = Tensor::randn(&[1, seq_len, hidden_size], &device)?;
let value = Tensor::randn(&[1, seq_len, hidden_size], &device)?;
let (context, weights) = layer.forward(&query, &key, &value, None)?;
assert_eq!(context.shape(), &[1, seq_len, hidden_size]);
assert_eq!(weights.shape(), &[1, seq_len, seq_len]);
Ok(())
}
}