PyTorch张量运算

本文详细介绍了在PyTorch中如何使用张量进行基本的加减乘除运算,包括标量、向量和矩阵的处理,以及向量点积和矩阵乘法。还展示了如何在实际项目中运用张量运算处理文本和图片数据。
部署运行你感兴趣的模型镜像

诸神缄默不语-个人优快云博文目录

在深度学习领域,张量是一种非常核心的数据结构,它是标量、向量和矩阵等数学概念的高维扩展。PyTorch作为一款流行的深度学习框架,提供了丰富的张量操作API,帮助研究人员和开发者有效地实现复杂的数学运算和神经网络模型。在本文中,我们将探索PyTorch中的张量运算,包括基础的加减乘除,以及更高级的点乘和叉乘等操作。

在PyTorch中,张量(Tensor)是一个多维数组,用于存储数值型数据。通过张量,我们可以表示标量(0维张量)、向量(1维张量)、矩阵(2维张量)等各种形式的数据。

1. 创建张量

更复杂的张量创建方案以后再写,这里仅分享简单的通过torch.tensor()函数直接创建张量::

import torch

# 创建一个标量(0维张量)
scalar = torch.tensor(5)

# 创建一个向量(1维张量)
vector = torch.tensor([1, 2, 3])

# 创建一个矩阵(2维张量)
matrix = torch.tensor([[1, 2], [3, 4]])

# 创建一个3维张量
tensor3d = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])

2. 张量的加减乘除

张量之间的基本运算包括加法、减法、乘法和除法。这些运算可以应用于标量、向量、矩阵以及更高维度的张量。

一般来说对于mini-batch场景都可以直接不考虑批次影响直接运算。对于矩阵乘法这还包括torch.bmm()场景(NLP中输入往往是[batch_size, word_num, embedding_size]就符合这个场景)。

这里只介绍了比较简单的场景,还没有介绍广播机制。

加法

  1. 尺寸相同的张量相加,就是逐元素相加:
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
tensor2 = torch.tensor([[7, 8, 9], [10, 11, 12]])
print(tensor1 + tensor2)

输出:

tensor([[ 8, 10, 12],
        [14, 16, 18]])
  1. 张量加数字就是每个元素上加这个数字:
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(tensor1 + 1)

输出:

tensor([[2, 3, 4],
        [5, 6, 7]])

减法

  1. 尺寸相同的张量相减,就是逐元素相加:
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
tensor2 = torch.tensor([[7, 8, 9], [10, 11, 12]])
print(tensor1 - tensor2)

输出:

tensor([[-6, -6, -6],
        [-6, -6, -6]])
  1. 张量加数字就是每个元素上加这个数字:
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(tensor1 - 1)

输出:

tensor([[0, 1, 2],
        [3, 4, 5]])

乘法

  1. 元素乘法(Hadamard乘法/哈达玛积):尺寸相同的张量相乘,逐元素相乘
    tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    tensor2 = torch.tensor([[7, 8, 9], [10, 11, 12]])
    print(tensor1 * tensor2)
    
    或者:
    tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    tensor2 = torch.tensor([[7, 8, 9], [10, 11, 12]])
    print(torch.mul(tensor1, tensor2))
    
    输出:
    tensor([[ 7, 16, 27],
            [40, 55, 72]])
    
  2. 张量乘数字:逐元素相乘
    tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    print(tensor1 * 2)
    
  3. 矩阵乘法:二元张量
    tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    tensor2 = torch.tensor([[7, 8, 9, 10], [11, 12, 13, 14], [15, 16, 17, 18]])
    print(tensor1 @ tensor2)
    
    或者:
    tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    tensor2 = torch.tensor([[7, 8, 9, 10], [11, 12, 13, 14], [15, 16, 17, 18]])
    print(torch.mm(tensor1, tensor2))
    
    或者:
    tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    tensor2 = torch.tensor([[7, 8, 9, 10], [11, 12, 13, 14], [15, 16, 17, 18]])
    print(torch.matmul(tensor1, tensor2))
    
    输出:
    tensor([[ 74,  80,  86,  92],
            [173, 188, 203, 218]])
    

mini-batch矩阵乘法

torch.matmul()torch.bmm()在mini-batch矩阵乘法时的效果相同:

tensor1 = torch.randn((8, 2, 3))
tensor1[0, :, :] = torch.tensor([[1, 2, 3], [4, 5, 6]])
tensor2 = torch.randn((8, 3, 4))
tensor2[0, :, :] = torch.tensor(
    [[7, 8, 9, 10], [11, 12, 13, 14], [15, 16, 17, 18]]
)

tensor3 = torch.bmm(tensor1, tensor2)
print(tensor3.size())
print(tensor3)

tensor4 = torch.matmul(tensor1, tensor2)
print(tensor4.size())
print(tensor4)

输出:

torch.Size([8, 2, 4])
tensor([[[ 7.4000e+01,  8.0000e+01,  8.6000e+01,  9.2000e+01],
         [ 1.7300e+02,  1.8800e+02,  2.0300e+02,  2.1800e+02]],

        [[-7.4121e-01,  4.5700e-01,  4.8753e-01, -1.5857e+00],
         [-1.3277e+00, -3.1067e-01,  6.9044e-02, -1.5349e+00]],

        [[-7.9833e-01,  6.2960e-02,  9.2492e-01, -1.0725e+00],
         [-2.3740e+00,  1.4807e+00, -3.7188e-01, -6.8096e-01]],

        [[-1.3164e+00,  1.8683e-01, -2.4655e+00,  2.8674e+00],
         [ 1.1632e+00, -1.1536e+00,  7.8646e-01,  2.8742e-01]],

        [[ 2.9451e-01,  2.8613e+00,  1.0916e-01,  3.3683e+00],
         [-5.0816e+00, -4.6865e+00, -2.4027e+00, -5.5370e+00]],

        [[ 7.5808e-01, -1.0055e-01,  1.6402e-01, -1.6499e-01],
         [ 3.0521e-01,  2.2200e-01,  8.0074e-01,  9.8477e-01]],

        [[-5.3240e-01, -1.5062e+00,  4.1627e-02, -7.6117e-01],
         [-9.1952e-01,  7.5713e-01, -1.8531e+00,  1.9099e+00]],

        [[ 3.5094e+00,  2.4735e+00,  1.9523e+00,  2.4074e+00],
         [ 2.4156e-01,  5.4852e+00,  3.9815e+00, -1.8851e+00]]])
torch.Size([8, 2, 4])
tensor([[[ 7.4000e+01,  8.0000e+01,  8.6000e+01,  9.2000e+01],
         [ 1.7300e+02,  1.8800e+02,  2.0300e+02,  2.1800e+02]],

        [[-7.4121e-01,  4.5700e-01,  4.8753e-01, -1.5857e+00],
         [-1.3277e+00, -3.1067e-01,  6.9044e-02, -1.5349e+00]],

        [[-7.9833e-01,  6.2960e-02,  9.2492e-01, -1.0725e+00],
         [-2.3740e+00,  1.4807e+00, -3.7188e-01, -6.8096e-01]],

        [[-1.3164e+00,  1.8683e-01, -2.4655e+00,  2.8674e+00],
         [ 1.1632e+00, -1.1536e+00,  7.8646e-01,  2.8742e-01]],

        [[ 2.9451e-01,  2.8613e+00,  1.0916e-01,  3.3683e+00],
         [-5.0816e+00, -4.6865e+00, -2.4027e+00, -5.5370e+00]],

        [[ 7.5808e-01, -1.0055e-01,  1.6402e-01, -1.6499e-01],
         [ 3.0521e-01,  2.2200e-01,  8.0074e-01,  9.8477e-01]],

        [[-5.3240e-01, -1.5062e+00,  4.1627e-02, -7.6117e-01],
         [-9.1952e-01,  7.5713e-01, -1.8531e+00,  1.9099e+00]],

        [[ 3.5094e+00,  2.4735e+00,  1.9523e+00,  2.4074e+00],
         [ 2.4156e-01,  5.4852e+00,  3.9815e+00, -1.8851e+00]]])

除法

  1. 逐元素相除
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
tensor2 = torch.tensor([[7, 8, 9], [10, 11, 12]])
print(tensor1 / tensor2)

输出:

tensor([[0.1429, 0.2500, 0.3333],
        [0.4000, 0.4545, 0.5000]])
  1. 张量除以数字:逐元素相除
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(tensor1 / 2)

输出:

tensor([[0.5000, 1.0000, 1.5000],
        [2.0000, 2.5000, 3.0000]])

3. 向量点积

torch.dot()只支持一维向量点积1

vector1 = torch.tensor([1, 2, 3])
vector2 = torch.tensor([4, 5, 6])
print(torch.dot(vector1, vector2))

4. 实践应用示例

假设我们有一批文本数据编码后的向量,我们想要计算这些向量之间的相似度。一种方法是使用向量的点乘来计算:

text_vector1 = torch.tensor([0.1, 0.2, 0.3])
text_vector2 = torch.tensor([0.4, 0.5, 0.6])
similarity = torch.dot(text_vector1, text_vector2)

此外,如果我们处理的是图片数据,我们可能需要对图片的像素值进行标准化处理,这就需要用到张量的乘法和除法运算:

image_tensor = torch.tensor([[[0.1, 0.2], [0.3, 0.4]], [[0.5, 0.6], [0.7, 0.8]]])
norm_factor = torch.tensor(255.0)
normalized_image = image_tensor / norm_factor

通过这些示例,我们可以看到张量运算在处理各种类型的数据时的强大能力和灵活性。

结语

PyTorch张量运算是深度学习编程中的基石,掌握这些基础和高级运算对于高效实现和优化神经网络模型至关重要。希望本文能帮助你更好地理解和使用PyTorch进行张量运算,从而在你的研究和项目中取得更好的成果。


  1. torch.dot — PyTorch 2.2 documentation ↩︎

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

<think>我们正在讨论PyTorch张量运算中的逆变和协变概念。请注意,在PyTorch或TensorFlow这类深度学习框架中,通常不直接涉及物理学或微分几何中的张量变换规则(如逆变和协变)。它们所称的“张量”更偏向于多维数组,并且不区分指标的上标(逆变)和下标(协变)。 然而,根据用户提供的引用[4],其中提到了逆变分量和协变分量的变换规则,这属于微分几何或张量分析中的概念。在PyTorch中,我们通常不区分这些,因为PyTorch张量是用于数值计算的多维数组,不涉及度规或坐标变换。 如果用户希望了解PyTorch中如何实现类似物理中的张量变换(逆变和协变),我们需要明确:这需要额外的数学处理,PyTorch本身不直接支持。但我们可以通过编写代码来模拟变换过程。 下面我将分步骤讲解: 1. **理解逆变和协变**(基于引用[4]): - **逆变分量**(contravariant components):当坐标系统发生变化时,分量变换与基向量变换方向相反(使用雅可比矩阵)。例如,矢量v的逆变分量变换为:$v'^i = \sum_j \frac{\partial x'^i}{\partial x^j} v^j$,即$v'^i = J^i_j v^j$(其中$J$是雅可比矩阵)。 - **协变分量**(covariant components):变换与基向量方向相同(使用雅可比矩阵的逆)。例如,协变分量变换为:$w'_i = \sum_j \frac{\partial x^j}{\partial x'^i} w_j$,即$w'_i = (J^{-1})^j_i w_j$。 2. **在PyTorch中模拟变换**: - 我们可以创建两个坐标系,并计算它们之间的雅可比矩阵及其逆。 - 然后,对给定的张量(向量或更高阶张量)按照变换规则进行乘法运算。 3. **注意事项**: - 在PyTorch中,张量运算通常不区分上下指标,所以我们需要明确指定变换规则。 - 高阶张量的变换需要每个指标分别应用变换规则。 示例:考虑一个二维空间中的向量(一阶张量)变换。 步骤1:定义原始坐标系(x, y)和新坐标系(x', y')。例如,假设新坐标系是由原始坐标系旋转θ角得到: $$ \begin{cases} x' = x \cos\theta + y \sin\theta \\ y' = -x \sin\theta + y \cos\theta \end{cases} $$ 步骤2:计算雅可比矩阵$J$(从原始坐标到新坐标): $$ J = \begin{bmatrix} \frac{\partial x'}{\partial x} & \frac{\partial x'}{\partial y} \\ \frac{\partial y'}{\partial x} & \frac{\partial y'}{\partial y} \end{bmatrix} = \begin{bmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{bmatrix} $$ 步骤3:雅可比矩阵的逆矩阵$J^{-1}$(从新坐标到原始坐标)就是它的转置(因为旋转矩阵是正交矩阵): $$ J^{-1} = J^T = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix} $$ 步骤4:定义原始坐标系中的一个向量(逆变分量)$v = [v^x, v^y]^T$,在新坐标系中的分量$v'^i = J^i_j v^j$,即: $$ v' = J \cdot v $$ 类似地,协变分量(如梯度向量)的变换为:$w'_i = (J^{-1})^j_i w_j$,即: $$ w' = (J^{-1})^T \cdot w = J \cdot w \quad \text{(因为$J^{-1}=J^T$,所以$(J^{-1})^T=J$)} $$ 注意:在这个例子中,由于旋转矩阵是正交矩阵,协变分量的变换矩阵就是$J$(与逆变分量的变换矩阵相同)。但对于一般的坐标变换,协变分量的变换矩阵是雅可比逆的转置(即$(J^{-1})^T$)。 下面用PyTorch代码实现: ```python import torch import numpy as np # 定义旋转角度 theta(例如,30度) theta = np.pi / 6 # 30度 cos_theta = np.cos(theta) sin_theta = np.sin(theta) # 雅可比矩阵 J (从原坐标到新坐标的变换矩阵) J = torch.tensor([ [cos_theta, sin_theta], [-sin_theta, cos_theta] ], dtype=torch.float32) # 逆变向量变换:v' = J @ v v = torch.tensor([1.0, 0.0]) # 原始坐标系中的向量(逆变分量) v_prime = J @ v # 新坐标系中的逆变分量 print("逆变向量变换后:", v_prime) # 协变向量变换:w' = (J^{-1})^T @ w,但这里因为J是正交矩阵,所以(J^{-1})^T = J w = torch.tensor([0.0, 1.0]) # 原始坐标系中的协变向量(例如梯度) # 对于正交变换,协变分量的变换矩阵与逆变相同(因为(J^{-1})^T = J),所以: w_prime = J @ w # 但注意:一般情况下,我们需要计算J^{-1}的转置。由于这里J是正交矩阵,J^{-1}=J^T,所以(J^{-1})^T = J。 print("协变向量变换后:", w_prime) # 如果不是正交变换,我们需要计算雅可比矩阵的逆的转置 # 假设一个一般的坐标变换(例如极坐标变换)则需单独计算,但这里我们仍用旋转矩阵演示一般流程: # 计算J^{-1}的转置(即(J^{-1})^T) J_inv = torch.inverse(J) J_inv_T = J_inv.t() # 这就是协变分量的变换矩阵 # 注意:在旋转的例子中,J_inv_T应该等于J(因为正交),我们用数值验证: print("J_inv_T (应等于J):", J_inv_T) w_prime_general = J_inv_T @ w print("使用一般方法的协变变换:", w_prime_general) # 应该与w_prime相同 ``` 注意:上面的例子中,我们使用了正交变换(旋转)来简化。如果是一般的坐标变换,我们需要计算雅可比矩阵及其逆矩阵,然后对协变分量使用逆矩阵的转置进行变换。 **总结**: - 在PyTorch中,我们可以通过矩阵乘法来模拟逆变和协变分量的变换。 - 逆变分量使用雅可比矩阵($J$)变换:$v' = J \cdot v$。 - 协变分量使用雅可比逆矩阵的转置($(J^{-1})^T$)变换:$w' = (J^{-1})^T \cdot w$。 但是,请注意,PyTorch本身不区分这些变换,因此需要用户根据物理或几何问题的背景手动实现变换规则。 **相关问题**: 1. 在深度学习中,为什么通常不需要考虑张量的逆变和协变性质? 2. 如何在PyTorch中实现更高阶张量(如二阶张量)的逆变和协变变换? 3. 除了旋转坐标系,还有哪些常见的坐标变换需要处理逆变和协变? </think>在 PyTorch 中,张量的**逆变(contravariant)**和**协变(covariant)**概念源于微分几何中的张量变换规则,而非深度学习框架的原生特性。PyTorch 的 `torch.Tensor` 本质是多维数组(多维数组),不自动区分逆变/协变指标。但我们可以通过自定义变换实现相关操作: ### 一、核心概念 1. **逆变分量**(上标指标) 坐标变换时,分量变化与基向量**相反**: $$ v'^i = \sum_j \frac{\partial x'^i}{\partial x^j} v^j \quad \text{(雅可比矩阵乘法)} $$ ```python # 示例:逆变向量变换 J = torch.tensor([[2, 0], [0, 3]]) # 雅可比矩阵 (假设的坐标变换) v_contra = torch.tensor([1.0, 2.0]) # 原始逆变分量 v_prime = J @ v_contra # 新坐标系分量 ``` 2. **协变分量**(下标指标) 分量变化与基向量**相同**: $$ w'_i = \sum_j \frac{\partial x^j}{\partial x'^i} w_j \quad \text{(雅可比逆矩阵乘法)} $$ ```python # 示例:协变向量变换 J_inv = torch.inverse(J) # 雅可比逆矩阵 w_cov = torch.tensor([3.0, 4.0]) # 原始协变分量 w_prime = J_inv.t() @ w_cov # 新坐标系分量 (需转置) ``` ### 二、PyTorch 实现要点 1. **张量创建**:普通张量无逆变/协变区分 ```python tensor = torch.tensor([[1, 2], [3, 4]]) # 通用多维数组 ``` 2. **手动实现变换**: ```python def transform_tensor(tensor, J, is_contravariant=True): if is_contravariant: return J @ tensor # 逆变变换 else: return torch.inverse(J).t() @ tensor # 协变变换 ``` 3. **物理意义验证**(标量不变性): ```python # 标量 s = v·w 应在坐标变换下不变 s_original = v_contra.dot(w_cov) s_transformed = v_prime.dot(w_prime) torch.isclose(s_original, s_transformed) # 应返回 True ``` ### 三、与深度学习的关系 在神经网络中,PyTorch 张量通常**不区分**逆变/协变: - **自动微分**:`tensor.backward()` 梯度是协变向量(对坐标变换敏感) - **矩阵运算**:`torch.mm(A, x)` 中若 `A` 视为二阶混合张量,需注意指标位置 - **最佳实践**:大多数网络层(如全连接层)设计为坐标无关,无需显式处理此概念 > 示例代码验证了张量分量在坐标变换下的不变性原理[^4],这是广义相对论等物理理论的核心,但在深度学习中较少显式使用。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诸神缄默不语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值