深度学习blog-深刻理解线性变换和矩阵

深度学习中避免不了矩阵运算,或者张量(其实是矩阵数组)运算。卷积是矩阵加、乘法,注意力也是一样。本质都一样,所谓注意力,卷积、滤波,是对不必了解数学的人说的,底层都是矩阵运算,线性变换。

任何一个向量都可以用基向量的线性组合来表示。

即任何一个向量都可以用基向量通过线性变换得到。

矩阵相乘的几何意义就是两个线性变换的相继作用。

通过线性变换,不仅可以得到这一组合的变换结果,也可以有效地计算任意向量的线性变换结果。

看看旋转变换:

比如上图所示,向量R逆时针旋转角度B前后的情况。

在左图中,有:

x0 = |R| * cosA => cosA = x0 / |R|

y0 = |R| * sinA => sinA = y0 / |R|

同样的,在右图中:

x1 = |R| * cos(A+B)

y1 = |R| * sin(A+B)

其中(x1, y1)就是(x0, y0)旋转角B后得到的向量,展开cos(A+B)和sin(A+B):

x1 = |R| * (cosAcosB - sinAsinB)

y1 = |R| * (sinAcosB + cosAsinB)

把 cosA = x0 / |R| 和 sinA = y0 / |R| 代入上面的式子,得到:

x1 = |R| * (x0 * cosB / |R| - y0 * sinB / |R|) => x1 = x0 * cosB - y0 * sinB

y1 = |R| * (y0 * cosB / |R| + x0 * sinB / |R|) => y1 = x0 * sinB + y0 * cosB

这样就得到了二维坐标下向量的逆时针旋转公式。顺时针旋转就把角度变为负:

x1 = x0 * cos(-B) - y0 * sin(-B) => x1 = x0 * cosB + y0 * sinB

y1 = x0 * sin(-B) + y0 * cos(-B)=> y1 = -x0 * sinB + y0 * cosB

把这个公式写成矩阵的形式,每个线性变换(这里是旋转变换)都对应一个矩阵,叫做变换矩阵。

线性变换的性质

  1. 唯一性:每个线性变换由其在基向量上的值唯一确定。
  2. 矩阵表示:每个线性变换可以用矩阵表示,通过矩阵与向量的乘法来实现变换。
  3. 复合性:两个线性变换的复合依然是线性变换。
  4. 零向量的映射:线性变换总是将零向量映射为零向量,即 T(0)=0T(0)=0。
  5. 负元素的象为原来元素的象的负元素。
  6. 线性变换把线性相关的元素组仍变为线性相关的元素组。
  7. 特征值和特征向量:线性变换的特征值和特征向量可帮助理解变换性质,如缩放、旋转等。

注: 线性无关的元素组经过线性变换不一定再是线性无关的, 变换后的情况与元素组和线性变换有关。若线性变换 T 将所有的元素组仍变换为线性无关的元素组,则称之为满秩的线性变换,其变换矩阵为满秩矩阵。

常见变换:平移变换、 旋转变换、 缩放变换、 反射变换、 投影变换。

1、线性变换是自身空间下的变换,而仿射变换是不同空间下的变换。线性变换作用后,空间维数不变,仿射变换作用后空间维数可能改变。

2、仿射变换与线性变换的区别在于变换前后是否改变原点。仿射变换=线性变换+平移变换

3、旋转,伸缩改变向量的方法,伸缩不改变方向

4、正交变换是指通过正交矩阵进行的线性变换。可以简单理解为矩阵的行(或列)向量是正交的,并且每个向量的长度为1。

性质:
保持角度和长度:正交变换保持向量之间的夹角和长度,意味着不改变几何形状。
几何意义:正交变换可以看作是对空间的旋转或反射。

几种特殊矩阵:对称矩阵、正交矩阵、单位矩阵、酉矩阵、 Hermite矩阵、上下三角矩阵等。

向量完成变换的关键是:要找到那个变换矩阵T

变换矩阵T的本质是:找到一组基向量

找到一组基向量等价于:找到了一个坐标系

找到一组基向量意味着:找到了一个向量空间

PyTorch 张量操作函数:

a. 张量创建

torch.zeros(size):创建全0张量。

torch.ones(size):创建全1张量。

torch.empty(size):创建未初始化的张量。

torch.rand(size):创建随机值张量。
torch.eye(n):创建单位矩阵。

b. 张量形状操作
tensor.view(shape):重塑张量。
tensor.reshape(...):重塑张量,注意跟view的区别。
tensor.permute(dims):改变张量的维度顺序。
tensor.unsqueeze(dim):在指定维度上增加一个维度。
tensor.squeeze(dim):去除指定维度的大小为1的维度。
torch.cat(tensors, dim):沿指定维度拼接多个张量。

c. 张量运算
torch.matmul(a, b):矩阵乘法。
torch.add(a, b):张量加法。
torch.subtract(a, b):张量减法。
torch.multiply(a, b):张量逐元素相乘。
torch.divide(a, b):张量逐元素相除。

d. 张量统计

tensor.mean(dim):计算均值。

tensor.sum(dim):计算和。

tensor.max(dim):计算最大值。

tensor.min(dim):计算最小值。

e. 张量索引与切片

tensor[index]:索引单个元素。

tensor[start:end]:切片操作。

f. 其他操作
transpose(dim0, dim1):交换两个维度。

transpose(-2, -1)交换最后两个维度,负数表示从里层开始算,正数表示从外层开始算。

torch.stack(tensors, dim):在新维度上堆叠多个张量。

tensor.clone():克隆一个张量。
tensor.contiguous() :使张量在内存里连续,一般用在view()函数之前。

张量运算常见错误:

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F

input_tensor = torch.randn(2, 3, 4, 5)
print(input_tensor)
print("----------------")
y=input_tensor.permute(0,2,3,1)
y=y.view(4,3,2,5)
print(y.shape)

运行错误:

y=y.view(4,3,2,5)

RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.

解析错误原因

在 PyTorch 中,view 方法要求输入张量的内存是连续的(contiguous)。当你调用 permute 方法时,它会改变张量的维度顺序,但不会改变其在内存中的存储顺序。

因此,经过 permute 后的张量可能不是连续的,这就导致了在使用 view 时出现了错误。在 permute 之后,y 的形状变为 (2, 4, 5, 3),但是这个张量在内存中并不连续。

当你尝试执行 y = y.view(4, 3, 2, 5) 时,PyTorch 检测到 y 的内存布局不符合 view 的要求,因此抛出了 RuntimeError。

解决:view替换为reshape 或者先调用contiguous()

y=y.reshape(3,4,5,2)

y=y.contiguous().view(4,3,2,5)

这同时也展示了view、permute、reshape用法的不同。view和reshape的输入参数是张量的每个维度的大小,在不关心每个维度是多长时,可以用permute,输入原张量维度的序号(0,1,2,3,4...)他们的用途都是重塑张量的形状,但是,view需要张量的内存是连续的,如果一个张量发生了形状的改变,在内存里可能就不是连续的,此时调用view前,先用contiguous()。

在 PyTorch 中, torch.nn.Linear 是用于构建线性变换(又称为全连接层或线性层)的类,常用在神经网络中。原型:torch.nn.Linear(self, in_features: int, out_features: int, bias: bool = True,device=None, dtype=None)

输入参数解析

1.in_features (int):

这是输入特征的维度,即输入向量的大小。例如,如果输入数据是一个具有 10 个特征的样本,则 in_features 应设置为 10。

2.out_features (int):

这是输出特征的维度,即线性变换后输出向量的大小。例如,如果希望输出数据具有 5 个特征,则 out_features 应设置为 5。

3.bias (bool, optional):

默认值为 True。这个参数指示是否包含偏置项(bias term)。如果设置为 True,则该线性层在计算时会添加一个偏置项;如果设置为 False,则省略偏置项。线性变换的公式一般为:

output=input⋅weightT+biasoutput=input⋅weightT+bias

  • biasFalse 时,公式简化为:output=input⋅weightToutput=input⋅weightT

4.device (torch.device, optional):

这个参数用于指定张量要分配到的设备(例如,CPU 或 GPU)。

5.dtype (torch.dtype, optional):

这是指定张量数据类型的参数。例如 torch.float32torch.float64

简单例子:

python 复制代码
import torch
import torch.nn as nn


class Example(nn.Module):
    def __init__(self, d_model, num_heads):
        super(Example, self).__init__()
        self.d_model = d_model
        self.num_heads = num_heads
        # 两个参数分别是输入
        self.W_q = nn.Linear(d_model, d_model)

    def forward(self, x):
        # 输入 x, shape = (batch_size, seq_length, d_model)
        # 假设我们有 batch_size=2, seq_length=3, d_model=4
        x = torch.arange(24).view(2, 3, 4).float()  # Shape: (2, 3, 4)
        print(x)
        # 执行线性变换
        Q = self.W_q(x)  # 仍然是(2, 3, 4)
        print(Q)

        # 对Q进行reshape操作
        Q = Q.view(2, 3, 2, 2)  # Shape: (2, 3, 2, 2), 假设 num_heads=2, d_k=2
        Q = Q.transpose(1, 2)  # Shape: (2, 2, 3, 2)

        # 进行一些示例
        print("原始Q:", x)
        print("线性变换后的Q:", Q)

model = Example(4, 2)
model(torch.randn(2, 3, 4))

# 输入维度为3,输出维度为2
linear_layer = nn.Linear(3, 3)

# 随机输入一个batch大小为1,特征维度为3的张量
input_tensor = torch.tensor([[1.0, 2.0, 3.0]])  # Batch size = 1, Features = 3

# 线性层前向传播
output = linear_layer(input_tensor)
print(output)


print("---------------")
# in_features=4,out_features=3
m = nn.Linear(4, 3)
# 只要最后一维的大小等于 in_features(这里是4)
input = torch.randn(2,3,5,4) 
print(input)
output = m(input)
print(output)
print(output. Size())

总之线性变换对应一个变换矩阵,变换矩阵也是一个函数(映射)。

相关推荐
宅小年3 分钟前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼17 分钟前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS25 分钟前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区2 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈2 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang2 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx
shengjk13 小时前
NanoClaw 深度剖析:一个"AI 原生"架构的个人助手是如何运转的?
人工智能
西门老铁5 小时前
🦞OpenClaw 让 MacMini 脱销了,而我拿出了6年陈的安卓机
人工智能
恋猫de小郭6 小时前
AI 可以让 WIFI 实现监控室内人体位置和姿态,无需摄像头?
前端·人工智能·ai编程