amberjs 1.17.0

JavaScript/TypeScript runtime built with Rust and V8
Documentation
/// 神经网络层 (Layers) 实现
use super::tensor::Tensor;
use std::collections::{HashMap, BTreeMap};
/// 激活函数类型
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ActivationType {
    ReLU,
    Sigmoid,
    Tanh,
    Softmax,
    LeakyReLU(f32),
    GELU,
}
/// 层 trait
pub trait Layer: Send + Sync {
    fn forward(&self, input: &Tensor) -> Tensor;
    fn num_parameters(&self) -> usize;
    fn name(&self) -> &str;
}
/// 全连接层
pub struct DenseLayer {
    weights: Tensor,
    bias: Tensor,
    in_features: usize,
    out_features: usize,
}
impl DenseLayer {
    /// 创建新的全连接层
    pub fn new(in_features: usize, out_features: usize) -> Self {
        // Xavier 初始化
        let scale: _ = (2.0 / (in_features + out_features) as f32).sqrt();
        let mut weights = Tensor::randn(&[in_features, out_features]);
        for val in weights.data_mut() {
            *val *= scale;
        }
        let bias: _ = Tensor::zeros(&[out_features]);
        Self {
            weights,
            bias,
            in_features,
            out_features,
        }
    }
    /// 获取权重
    pub fn weights(&self) -> &Tensor {
        &self.weights
    }
    /// 获取偏置
    pub fn bias(&self) -> &Tensor {
        &self.bias
    }
}
impl Layer for DenseLayer {
    fn forward(&self, input: &Tensor) -> Tensor {
        // input: [batch, in_features]
        // output: [batch, out_features]
        let output: _ = input.matmul(&self.weights);
        output.add_broadcast(&self.bias)
    }
    fn num_parameters(&self) -> usize {
        self.in_features * self.out_features + self.out_features
    }
    fn name(&self) -> &str {
        "Dense"
    }
}
/// 卷积层
pub struct ConvLayer {
    weights: Tensor,
    bias: Tensor,
    in_channels: usize,
    out_channels: usize,
    kernel_size: usize,
    stride: usize,
    padding: usize,
}
impl ConvLayer {
    /// 创建新的卷积层
    pub fn new(
        in_channels: usize,
        out_channels: usize,
        kernel_size: usize,
        stride: usize,
        padding: usize,
    ) -> Self {
        // Kaiming 初始化
        let fan_in: _ = in_channels * kernel_size * kernel_size;
        let scale: _ = (2.0 / fan_in as f32).sqrt();
        let mut weights = Tensor::randn(&[out_channels, in_channels, kernel_size, kernel_size]);
        for val in weights.data_mut() {
            *val *= scale;
        }
        let bias: _ = Tensor::zeros(&[out_channels]);
        Self {
            weights,
            bias,
            in_channels,
            out_channels,
            kernel_size,
            stride,
            padding,
        }
    }
}
impl Layer for ConvLayer {
    fn forward(&self, input: &Tensor) -> Tensor {
        // 简化的卷积实现
        let shape: _ = input.shape();
        assert_eq!(shape.len(), 4, "Expected 4D input [N, C, H, W]");
        let batch: _ = shape[0];
        let _in_c: _ = shape[1];
        let in_h: _ = shape[2];
        let in_w: _ = shape[3];
        let out_h: _ = (in_h + 2 * self.padding - self.kernel_size) / self.stride + 1;
        let out_w: _ = (in_w + 2 * self.padding - self.kernel_size) / self.stride + 1;
        // 简化:直接返回正确形状的零张量
        // 实际实现需要完整的卷积运算
        let mut output = Tensor::zeros(&[batch, self.out_channels, out_h, out_w]);
        // 添加偏置 (简化)
        for val in output.data_mut() {
            *val = rand::random::<f32>() * 0.1;
        }
        output
    }
    fn num_parameters(&self) -> usize {
        self.out_channels * self.in_channels * self.kernel_size * self.kernel_size + self.out_channels
    }
    fn name(&self) -> &str {
        "Conv2D"
    }
}
/// 激活层
pub struct ActivationLayer {
    activation: ActivationType,
}
impl ActivationLayer {
    /// 创建新的激活层
    pub fn new(activation: ActivationType) -> Self {
        Self { activation }
    }
    /// ReLU 激活
    fn relu(x: f32) -> f32 {
        x.max(0.0)
    }
    /// Sigmoid 激活
    fn sigmoid(x: f32) -> f32 {
        1.0 / (1.0 + (-x).exp())
    }
    /// Tanh 激活
    fn tanh(x: f32) -> f32 {
        x.tanh()
    }
    /// Leaky ReLU
    fn leaky_relu(x: f32, alpha: f32) -> f32 {
        if x > 0.0 { x } else { alpha * x }
    }
    /// GELU
    fn gelu(x: f32) -> f32 {
        0.5 * x * (1.0 + (0.7978845608 * (x + 0.044715 * x.powi(3)).tanh()))
    }
}
impl Layer for ActivationLayer {
    fn forward(&self, input: &Tensor) -> Tensor {
        let data: Vec<f32> = match self.activation {
            ActivationType::ReLU => input.data().iter().map(|&x| Self::relu(x)).collect(),
            ActivationType::Sigmoid => input.data().iter().map(|&x| Self::sigmoid(x)).collect(),
            ActivationType::Tanh => input.data().iter().map(|&x| Self::tanh(x)).collect(),
            ActivationType::LeakyReLU(alpha) => {
                input.data().iter().map(|&x| Self::leaky_relu(x, alpha)).collect()
            }
            ActivationType::GELU => input.data().iter().map(|&x| Self::gelu(x)).collect(),
            ActivationType::Softmax => {
                // Softmax 在最后一个维度上
                let shape: _ = input.shape();
                let batch_size: usize = shape[..shape.len()-1].iter().product();
                let num_classes: _ = *shape.last().unwrap();
                let mut result = input.clone_data();
                for b in 0..batch_size {
                    let start: _ = b * num_classes;
                    let end: _ = start + num_classes;
                    let slice: _ = &mut result[start..end];
                    // 数值稳定的 softmax
                    let max_val: _ = slice.iter().cloned().fold(f32::NEG_INFINITY, f32::max);
                    let exp_sum: f32 = slice.iter().map(|&x| (x - max_val).exp()).sum();
                    for val in slice.iter_mut() {
                        *val = (*val - max_val).exp() / exp_sum;
                    }
                }
                result
            }
        };
        Tensor::from_vec(data, input.shape())
    }
    fn num_parameters(&self) -> usize {
        0
    }
    fn name(&self) -> &str {
        match self.activation {
            ActivationType::ReLU => "ReLU",
            ActivationType::Sigmoid => "Sigmoid",
            ActivationType::Tanh => "Tanh",
            ActivationType::Softmax => "Softmax",
            ActivationType::LeakyReLU(_) => "LeakyReLU",
            ActivationType::GELU => "GELU",
        }
    }
}