transformer学习笔记-自注意力机制(2)

经过上一篇transformer学习笔记-自注意力机制(1)原理学习,这一篇对其中的几个关键知识点代码演示:

1、整体qkv注意力计算

先来个最简单未经变换的QKV处理:

import torch  
Q = torch.tensor([[3.0, 3.0,0.0],
                  [0.5, 4.0,0.0]])
K = Q.T
V = Q

scores = Q @ K #计算内积
weights = torch.softmax(scores, dim=0)
print(f"概率分布:{weights}")
newQ = weights @ V
print(f"输出:{newQ}")

再来个输入经过Wq/Wk/Wv变换的:

import torch  
Q = torch.tensor([[3.0, 3.0,0.0],
                  [0.5, 4.0,0.0]])
torch.manual_seed(123)  
d_q, d_k, d_v = 4, 4, 5 # W_query, W_key, W_value 的维度  
d = Q.shape[1] #  W_query, W_key, W_value 的行数等于输入token的维度
# 获取W_query, W_key, W_value(随机生成)
W_query = torch.nn.Parameter(torch.rand(d, d_q))  
W_key = torch.nn.Parameter(torch.rand(d, d_k))  
W_value = torch.nn.Parameter(torch.rand(d, d_v))

print("W_query:", W_query)
print("W_key:", W_key)
print("W_value:", W_value)

#先只计算苹果对整个句子的注意力,看看效果
apple = Q[0]
query_apple = apple @ W_query  
keys = Q @ W_key  
values = Q @ W_value  
print(f"query_apple:{query_apple}")
print(f"keys:{keys}")
print(f"values:{values}")
scores = query_apple @ keys.T
print(f"scores:{scores}")
weights = torch.softmax(scores, dim=0)
print(f"weights:{weights}")
newQ = weights @ values
print(f"newQ:{newQ}")

#再看下整体的
querys = Q @ W_query
all_scores = querys @ keys.T
print(f"all_scores:{all_scores}")
all_weights = torch.softmax(all_scores, dim=-1)
print(f"all_weights:{all_weights}")
output = all_weights @ values
print(f"output:{output}")

在这里插入图片描述
最终生成的output的维度与W_value 的维度一致。

2、调换顺序结果不变

import torch

def simple_attention(Q):
    K = Q.T
    V = Q
    
    scores = Q @ K #计算内积
    weights = torch.softmax(scores, dim=-1)
    print(f"概率分布:{weights}")
    newQ = weights @ V
    print(f"输出:{newQ}")
    
Q = torch.tensor([[3.0, 3.0,0.0],
                  [0.5, 4.0,0.0]])
Q1 = torch.tensor([[0.5, 4.0,0.0],
                   [3.0, 3.0,0.0]])
print("模拟‘苹果梨’:")
simple_attention(Q)
print("模拟‘梨苹果’:")
simple_attention(Q1)

在这里插入图片描述
可以看到“苹果梨”、“梨苹果”即便换了词token的顺序,并不会影响新的梨和新的苹果的向量数值。这里我们用了softmax函数求概率分布,因此跟上一篇文章的示例数值不一样,不要在意这个细节。

3、softmax:

import numpy as np

def softmax(x):
    e_x = np.exp(x)
    return e_x / e_x.sum(axis=0)

def softmax_with_temperature(x,T):
    e_x = np.exp(x/T)
    return e_x / e_x.sum(axis=0)


# 示例使用
if __name__ == "__main__":
    input_vector = np.array([2.0, 1.0, 0.1])
    output = softmax(input_vector)
    print("Softmax Output:", output)

    print("Softmax with Temperature 0.5 Output:", softmax_with_temperature(input_vector,0.5))
    print("Softmax with Temperature 1 Output:", softmax_with_temperature(input_vector,1))
    print("Softmax with Temperature 5 Output:", softmax_with_temperature(input_vector,5))

在这里插入图片描述
可以看到随着T的不断加大,概率分布不断趋于均匀分布。

4、softmax除以 d k \sqrt{d_k} dk

还是用上面的softmax函数,演示下除以 d k \sqrt{d_k} dk 的效果:

        # 高维输入向量
        input_vector_high_dim = np.random.randn(100) * 10  # 生成一个100维的高斯分布随机向量,乘以10增加内积
        output_high_dim = softmax(input_vector_high_dim)
        print("High Dimension Softmax Output:", output_high_dim)
        # 打印高维输出的概率分布
        print("Max Probability in High Dimension:", np.max(output_high_dim))
        print("Min Probability in High Dimension:", np.min(output_high_dim))

        # 高维输入向量除以10
        input_vector_high_dim_div10 = input_vector_high_dim / 10
        output_high_dim_div10 = softmax(input_vector_high_dim_div10)
        print("High Dimension Softmax Output (Divided by 10):", output_high_dim_div10)
        # 打印高维输出的概率分布
        print("Max Probability in High Dimension (Divided by 10):", np.max(output_high_dim_div10))
        print("Min Probability in High Dimension (Divided by 10):", np.min(output_high_dim_div10))

        # 绘制高维概率分布曲线
        plt.figure(figsize=(10, 6))

        # 绘制图形
        plt.plot(output_high_dim, label='High Dim')
        plt.plot(output_high_dim_div10, label='High Dim Divided by 10')
        plt.legend()
        plt.title('High Dimension Softmax Output Comparison')
        plt.xlabel('Index')
        plt.ylabel('Probability')
        plt.show()

在这里插入图片描述
在除以 d k \sqrt{d_k} dk 之前,由于内积变大,导致概率分布变得尖锐,趋近0的位置梯度基本消失,softmax 函数的损失函数的导数在输出接近 0 时接近零,在反向传播过程中,无法有效地更新权重。有兴趣的话可以试试对softmax 函数的损失函数求导。

继续上面的代码,来看下softmax的输出的损失函数求梯度:

        def test_grad( dim_vertor):
            import numpy as np
            import torch
            import torch.nn.functional as F

            # 假设的输入
            z = torch.tensor(dim_vertor, requires_grad=True)
            print(z)
            # 计算 softmax 输出
            p = F.softmax(z, dim=0)
            true_label = np.zeros(100)
            true_label[3] = 1
            # 模拟损失函数(例如交叉熵)
            y = torch.tensor(true_label)  # one-hot 编码的真实标签
            loss = -torch.sum(y * torch.log(p))

            # 反向传播并获取梯度
            loss.backward()
            # print(z.grad)  # 输出梯度
            return z.grad
        grad_div10 = test_grad(input_vector_high_dim_div10)
        grad = test_grad(input_vector_high_dim)
        print(f"grad_div10:{grad_div10}")
        print(f"grad:{grad}")

在这里插入图片描述
明显看出,没有除以 d k \sqrt{d_k} dk 求出的梯度,基本为0;上面的代码是torch已经实现的。当然也可以根据损失函数自己求导,这里我们只为演示效果,点到即止:

5、多头注意力:

import torch
import torch.nn as nn

torch.manual_seed(123)

# 输入矩阵 Q
Q = torch.tensor([[3.0, 3.0, 0.0],
                  [0.5, 4.0, 0.0]])

# 维度设置
d_q, d_k, d_v = 4, 4, 5  # 每个头的 query, key, value 的维度
d_model = Q.shape[1]     # 输入 token 的维度
num_heads = 2            # 头的数量

# 初始化每个头的权重矩阵
W_query = nn.ParameterList([nn.Parameter(torch.rand(d_model, d_q)) for _ in range(num_heads)])
W_key = nn.ParameterList([nn.Parameter(torch.rand(d_model, d_k)) for _ in range(num_heads)])
W_value = nn.ParameterList([nn.Parameter(torch.rand(d_model, d_v)) for _ in range(num_heads)])

# 输出权重矩阵
W_output = nn.Parameter(torch.rand(num_heads * d_v, d_model))

# 打印权重矩阵
for i in range(num_heads):
    print(f"W_query_{i+1}:\n{W_query[i]}")
    print(f"W_key_{i+1}:\n{W_key[i]}")
    print(f"W_value_{i+1}:\n{W_value[i]}")

# 计算每个头的 Q, K, V
queries = [Q @ W_query[i] for i in range(num_heads)]
keys = [Q @ W_key[i] for i in range(num_heads)]
values = [Q @ W_value[i] for i in range(num_heads)]

# 计算每个头的注意力分数和权重
outputs = []
for i in range(num_heads):
    scores = queries[i] @ keys[i].T / (d_k ** 0.5)
    weights = torch.softmax(scores, dim=-1)
    output = weights @ values[i]
    outputs.append(output)

# 拼接所有头的输出
concat_output = torch.cat(outputs, dim=-1)
print(f"concat_output:\n{concat_output}")
# 最终线性变换
final_output = concat_output @ W_output

# 打印结果
print(f"Final Output:\n{final_output}")

6、掩码注意力:

import torch

# 原始 Q 矩阵
Q = torch.tensor([[3.0, 3.0, 0.0],
                  [0.5, 4.0, 0.0],
                  [1.0, 2.0, 0.0],
                  [2.0, 1.0, 0.0]])

torch.manual_seed(123)
d_q, d_k, d_v = 4, 4, 5  # query, key, value 的维度
d = Q.shape[1]           # query, key, value 的行数等于输入 token 的维度

# 初始化权重矩阵
W_query = torch.nn.Parameter(torch.rand(d, d_q))
W_key = torch.nn.Parameter(torch.rand(d, d_k))
W_value = torch.nn.Parameter(torch.rand(d, d_v))

print("W_query:", W_query)
print("W_key:", W_key)
print("W_value:", W_value)

# 计算 Q, K, V
querys = Q @ W_query
keys = Q @ W_key
values = Q @ W_value

print(f"querys:\n{querys}")
print(f"keys:\n{keys}")
print(f"values:\n{values}")

# 计算注意力分数
all_scores = querys @ keys.T / (d_k ** 0.5)
print(f"all_scores:\n{all_scores}")

# 生成掩码
seq_len = Q.shape[0]
mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1).bool()
masked_scores = all_scores.masked_fill(mask, float('-inf'))

print(f"Mask:\n{mask}")
print(f"Masked Scores:\n{masked_scores}")

# 计算权重
all_weights = torch.softmax(masked_scores, dim=-1)
print(f"all_weights:\n{all_weights}")

# 计算输出
output = all_weights @ values
print(f"output:\n{output}")

主要看下生成的掩码矩阵,和通过掩码矩阵处理的权重分布:在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/936007.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于米尔全志T527开发板的OpenCV进行手势识别方案

本文将介绍基于米尔电子MYD-LT527开发板(米尔基于全志T527开发板)的OpenCV手势识别方案测试。 摘自优秀创作者-小火苗 米尔基于全志T527开发板 一、软件环境安装 1.安装OpenCV sudo apt-get install libopencv-dev python3-opencv 2.安装pip sudo apt…

arXiv-2024 | VLM-GroNav: 基于物理对齐映射视觉语言模型的户外环境机器人导航

作者: Mohamed Elnoor, Kasun Weerakoon, Gershom Seneviratne, Ruiqi Xian, Tianrui Guan, Mohamed Khalid M Jaffar, Vignesh Rajagopal, and Dinesh Manocha单位:马里兰大学学院公园分校原文链接:VLM-GroNav: Robot Navigation Using Phys…

Typora 修改默认的高亮颜色

shift F12 参考 怎么给typora添加颜色?

基于阿里云Ubuntu22.04 64位服务器Java及MySql环境配置命令记录

基于阿里云Ubuntu22.04 64位服务器Java及MySql环境配置命令记录 Java 23 离线环境配置MySql 环境配置MySQL常用命令 Java 23 离线环境配置 下载 Ubuntu环境下 Java 23 离线包 链接: java Downloads. 在Linux环境下创建一个安装目录 mkdir -p /usr/local/java将下载好的jdk压缩…

【树莓派4B】MindSpore lite 部署demo

一个demo,mindspore lite 部署在树莓派4B ubuntu22.04中,为后续操作开个门! 环境 开发环境:wsl-ubuntu22.04分发版部署环境:树莓派4B,操作系统为ubuntu22.04mindspore lite版本:mindspore-li…

RK3576 Android14,内存大于4G时UVC应用无法申请内存

最近有个项目需要将Linux虚拟成UVC摄像头,开发过程中遇到一个奇怪的事情,通过V4l2框架接口申请内存时,相同的板子,只是内存一个4G一个8G。4G的内存可以申请成功,8G就不行。提示“内存不足” 内存更大反而内存不足&…

HarmonyOS-高级(四)

文章目录 应用开发安全应用DFX能力介绍HiLog使用指导HiAppEvent 🏡作者主页:点击! 🤖HarmonyOS专栏:点击! ⏰️创作时间:2024年12月11日11点18分 应用开发安全 应用隐私保护 隐私声明弹窗的作…

函数与结构体(入门6)

【深基7.例1】距离函数 #include <iostream> #include <iomanip> #include <cmath> using namespace std; int main() {double x1, x2, x3, y1, y2, y3;cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;double d1 pow(pow(…

质数的和与积

质数的和与积 C语言代码C 代码Java代码Python代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 两个质数的和是S&#xff0c;它们的积最大是多少&#xff1f; 输入 一个不大于10000的正整数S&#xff0c;为两个质数的和。 输出 一个整…

OpenCV图像处理实战:从边缘检测到透视变换,掌握七大核心函数

一、引言 图像处理是计算机视觉领域中的基础&#xff0c;而边缘检测和轮廓分析则是其核心任务之一。OpenCV作为一个强大的计算机视觉库&#xff0c;提供了众多功能强大的函数&#xff0c;帮助开发者实现高效的图像处理。在本文中&#xff0c;我们将深入探索OpenCV中的七个重要…

JavaWeb01

JavaWeb 1. BS 和 CS BS B/S结构(Browser/server&#xff0c;浏览器/服务器模式)&#xff0c;是WEB兴起后的一种网络结构模式&#xff0c;WEB浏览器是客户端最主要的应用软件。这种模式统一了客户端&#xff0c;将系统功能实现的核心部分集中到服务器上&#xff0c;简化了系统…

开发者工具的模块化与可扩展性设计

文章目录 前言模块化设计的重要性可扩展性设计的重要性设计模式与技术实现实战代码插件管理器类&#xff1a;PluginManager注册插件方法&#xff1a;register_plugin执行插件方法&#xff1a;execute_plugin 插件实现插件 1&#xff1a;代码格式化插件插件 2&#xff1a;代码行…

嵌入式现状、机遇、挑战与展望

在当今数字化浪潮中&#xff0c;嵌入式系统宛如一颗璀璨的明珠&#xff0c;熠熠生辉&#xff0c;深刻地渗透到了我们生活的方方面面&#xff0c;成为推动现代科技进步不可或缺的关键力量。从智能家居的便捷控制&#xff0c;到工业生产的精准运作&#xff0c;再到汽车的智能驾驶…

️️️ 避坑指南:如何修复国密gmssl 库填充问题并提炼优秀加密实践20241212

&#x1f6e1;️ 避坑指南&#xff1a;如何修复国密gmssl 库填充问题并提炼优秀加密实践 ✨ 引言 在当下的数据安全环境中&#xff0c;SM4作为中国国家密码算法的代表性选择&#xff0c;被广泛应用于金融、通信和政府领域。然而&#xff0c;在实际开发中&#xff0c;即便是开…

markdown入门

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

四、个人项目系统搭建

文章目录 一、python写的后端代码二、html代码三、index.css四、js代码 效果图&#xff1a; 一、python写的后端代码 后端代码使用Flask编写&#xff0c;如下所示&#xff1a; # app.py from flask import Flask, render_template, request, jsonify, g import sqlite3 import…

【含开题报告+文档+PPT+源码】基于微信小程序的点餐系统的设计与实现

开题报告 随着互联网技术的日益成熟和消费者生活水平与需求层次的显著提升&#xff0c;外卖点餐平台在中国市场上迅速兴起并深深植根于民众日常生活的各个角落。这类平台的核心在于构建了一个基于互联网的强大订餐服务系统&#xff0c;它无缝整合了餐饮商户资源与广大消费者的…

【DFT】【MBIST】Memory Repair

Memory Repaire 1. Overview2. Memory Repair2.1 Column MUX2.2 Type of Repair 3. Tessent Repair Architecture3.1 BIRA3.2 BISR3.3 Implementing Soft Repair3.4 Repair Steps 1. Overview 假设通过 MBIST 发现 SoC 中一个或多个 Memory 存在故障&#xff0c;不能正常进行读…

[搜广推]王树森推荐算法——基于物体的协同过滤

基于物体的协同过滤 ItemCF 基于物体的协同过滤&#xff08;Item-Based Collaborative Filtering&#xff0c;简称ItemCF&#xff09;是一种经典的推荐系统算法 基本思想 量化用户对物品的兴趣&#xff0c;通过分析用户的行为来找到与目标物品相似的其他物品&#xff0c;然后…

scala的隐式转换

定义 隐式转换是 Scala 提供的一种强大的特性&#xff0c;它允许编译器在特定的情况下自动将一种类型转换为另一种类型。这种转换不是显式地通过方法调用进行的&#xff0c;而是由编译器自动插入转换代码。隐式转换主要通过定义隐式转换函数来实现。隐式转换函数是一种带有imp…