rust-candle学习笔记11-实现一个简单的自注意力

参考:about-pytorch

定义ScaledDotProductAttention结构体:

rust 复制代码
use candle_core::{Result, Device, Tensor};
use candle_nn::{Linear, Module, linear_no_bias, VarMap, VarBuilder, ops};

struct ScaledDotProductAttention {
    wq: Linear,
    wk: Linear,
    wv: Linear,
    d_model: Tensor,
    device: Device,
}

为ScaledDotProductAttention结构体实现new方法:

rust 复制代码
impl ScaledDotProductAttention {
    fn new(vb: VarBuilder, embedding_dim: usize, out_dim: usize, device: Device) -> Result<Self> {
        Ok(Self { 
            wq: linear_no_bias(embedding_dim, out_dim, vb.pp("wq"))?, 
            wk: linear_no_bias(embedding_dim, out_dim, vb.pp("wk"))?, 
            wv: linear_no_bias(embedding_dim, out_dim, vb.pp("wv"))?,
            d_model: Tensor::new(embedding_dim as f32, &device)?,
            device,
        })
    }
}

为结构体实现Module的forward trait:

rust 复制代码
impl Module for ScaledDotProductAttention {
    fn forward(&self, xs: &Tensor) -> Result<Tensor> {
        let q = self.wq.forward(xs)?;
        let k = self.wk.forward(xs)?;
        let v = self.wv.forward(xs)?;
        let attn_score = q.matmul(&k.t()?)?;
        let attn_score = attn_score.broadcast_div(&self.d_model.sqrt()?)?;
        let dim = attn_score.rank() - 1;
        let attn_weights = ops::softmax(&attn_score, dim)?;
        let attn_output = attn_weights.matmul(&v)?;
        Ok(attn_output)
    }
}

融合qkv实现:

定义ScaledDotProductAttentionFusedQKV结构体:

rust 复制代码
struct ScaledDotProductAttentionFusedQKV {
    w_qkv: Linear,
    d_model: Tensor,
    device: Device,
}

为结构体实现new方法:

rust 复制代码
impl ScaledDotProductAttentionFusedQKV {
    fn new(vb: VarBuilder, embedding_dim: usize, out_dim: usize, device: Device) -> Result<Self> {
        Ok(Self { 
            w_qkv: linear_no_bias(embedding_dim, 3*out_dim, vb.pp("w_qkv"))?,
            d_model: Tensor::new(embedding_dim as f32, &device)?,
            device,
        })
    }
}

为结构体实现forward trait:

rust 复制代码
impl Module for ScaledDotProductAttentionFusedQKV {
    fn forward(&self, xs: &Tensor) -> Result<Tensor> {
        let qkv = self.w_qkv.forward(xs)?;
        let (batch_size, seq_len, _) = qkv.dims3()?;
        let qkv = qkv.reshape((batch_size, seq_len, 3, ()))?;
        let q = qkv.get_on_dim(2, 0)?;
        let q = q.reshape((batch_size, seq_len, ()))?;
        let k = qkv.get_on_dim(2, 1)?;
        let k = k.reshape((batch_size, seq_len, ()))?;
        let v = qkv.get_on_dim(2, 2)?;
        let v = v.reshape((batch_size, seq_len, ()))?;
        let attn_score = q.matmul(&k.t()?)?;
        let attn_score = attn_score.broadcast_div(&self.d_model.sqrt()?)?;
        let dim = attn_score.rank() - 1;
        let attn_weights = ops::softmax(&attn_score, dim)?;
        let attn_output = attn_weights.matmul(&v)?;
        Ok(attn_output)
    }
}

测试:

rust 复制代码
fn main() -> Result<()> {
    let device = Device::cuda_if_available(0)?;
    let varmap = VarMap::new();
    let vb = VarBuilder::from_varmap(&varmap, candle_core::DType::F32, &device);
    
    let input = Tensor::from_vec(vec![0.43f32, 0.15, 0.89, 
                                                    0.55, 0.87, 0.66,
                                                    0.57, 0.85, 0.64,
                                                    0.22, 0.58, 0.33,
                                                    0.77, 0.25, 0.10,
                                                    0.05, 0.80, 0.55, 
                                                    0.43, 0.15, 0.89, 
                                                    0.55, 0.87, 0.66,
                                                    0.57, 0.85, 0.64,
                                                    0.22, 0.58, 0.33,
                                                    0.77, 0.25, 0.10,
                                                    0.05, 0.80, 0.55], (2, 6, 3), &device)?;
    // let model = ScaledDotProductAttention::new(vb.clone(), 3, 2, device.clone())?;
    let model = ScaledDotProductAttentionFusedQKV::new(vb.clone(), 3, 2, device.clone())?;
    let output = model.forward(&input)?;
    println!("output: {:?}\n", output);
    println!("output: {:?}\n", output.to_vec3::<f32>()?);
    Ok(())
}
相关推荐
一战成名9966 小时前
深度解析 CANN 模型转换工具链:从 ONNX 到 OM
人工智能·学习·安全·开源
Yu_Lijing6 小时前
网络复习篇——网络基础(一)
网络·c++·笔记
蒸蒸yyyyzwd6 小时前
分布式算法学习笔记1.1-1.4
笔记·学习
匆匆那年9677 小时前
llamafactory推理消除模型的随机性
linux·服务器·学习·ubuntu
好好学习天天向上~~7 小时前
5_Linux学习总结_vim
linux·学习·vim
笨笨阿库娅7 小时前
从零开始的算法基础学习
学习·算法
羊群智妍15 小时前
2026 AI搜索流量密码:免费GEO监测工具,优化效果看得见
笔记·百度·微信·facebook·新浪微博
阿蒙Amon15 小时前
TypeScript学习-第10章:模块与命名空间
学习·ubuntu·typescript
AI绘画哇哒哒15 小时前
【干货收藏】深度解析AI Agent框架:设计原理+主流选型+项目实操,一站式学习指南
人工智能·学习·ai·程序员·大模型·产品经理·转行
陈天伟教授15 小时前
人工智能应用- 语言理解:04.大语言模型
人工智能·语言模型·自然语言处理