Tensor(张量)

Definition

  • In mathematics, a tensor is an algebraic object that describes a multilinear relationship between sets of algebraic objects related to a vector space.
    • 例如标量可以视为0维的张量,矩阵就是二维的
    • 多维的张量可以承载更多的数据,例如:
      • 3维 = 时间序列
      • 4维 = 图像
      • 5维 = 视频
  • 比如我们考虑一个照片,它可以表示为这样的一个张量
  • 再比如说如果我们要训练一个照片的数据集,就可以考虑再加上一个数据量的维度,即
 

Create a tensor

  • torch.tensor( data )torch.Tensor( size )
    • 第一个函数允许我们从已有的List或者是NumPy数组来创建张量
    • 第二个允许我们创建一个基本张量
  • torch.ones(size)torch.zeros(size)torch.eye(size)
    • 创建单位矩阵或者是零矩阵或者是对角矩阵
  • torch.arange(s,e,step)linspace(s, e, steps)
    • torch.arange() 函数用于创建一个等差数列的一维张量,其中参数包括起始值、终止值(不包括)、步长
    • linspace(s, e, steps)函数用于在指定的起始值和终止值之间创建一个等间距的一维张量。它的用法如下:
  • rand(size)randn(size)
    • rand是[0,1)均匀分布;randn是服从N(0,1)的正态分布
  • normal(mean, std)
    • 正态分布(均值为mean,标准差是std)
  • randperm(n)
    • 函数用于生成一个随机排列的整数序列。它接受一个参数 n,表示生成的随机排列的整数范围是从 0 到 n-1。返回的张量包含了从 0 到 n-1 的整数的随机排列

Operations

  • 加法操作
    • 使用原始加号
    • 使用函数add(tensor1,tensor2)
    • in-place,原值修改
    • 前两个都是返回新的tensor,后一个是在原本基础上修改
  • 索引操作
    • 💡
      需要注意的是,索引出来的结果与原数据共享内存,修改一个,另一个会跟着修改。如果不想修改,可以考虑使用copy( )等方法
  • 维度变换
    • 张量的维度变换常见的方法有torch.view()torch.reshape(),主要谈第一种方法torch.view()
    • y = x.view(16): 这行代码将原始张量 x 变形为一个包含16个元素的一维张量 y。这相当于将原始张量展平成一个一维张量。view(16) 中的参数 16 表示最终张量的大小
    • z = x.view(-1, 8): 这行代码也是对张量 x 进行形状改变,但是通过 1 参数来自动计算另一维度的大小。这里 1 表示该维度的大小由其他维度的大小来决定,即张量的总元素数量不变的情况下,PyTorch 会根据其他维度的大小自动计算该维度的大小。在这个例子中,原始张量 x 包含了16个元素,所以 PyTorch 会根据需要自动计算出另一维度的大小为2。最终得到的张量 z 是一个大小为2x8的二维张量
    • 在 PyTorch 中,view() 方法用于改变张量的形状,但不会对原始张量进行修改,而是返回一个新的张量,其形状已经被改变了
    • 💡
      torch.view() 返回的新tensor与源tensor共享内存(其实是同一个tensor),更改其中的一个,另外一个也会跟着改变。(顾名思义,view()仅仅是改变了对这个张量的观察角度)
    • 很多情况下,我们希望原始张量和变换后的张量互相不影响。为为了使创建的张量和原始张量不共享内存,我们需要使用第二种方法torch.reshape(), 同样可以改变张量的形状
    • 此函数并不能保证返回的是其拷贝值,所以官方不推荐使用。推荐的方法是我们先用 clone() 创造一个张量副本然后再使用 torch.view()进行函数维度变换 。使用 clone() 还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源 Tensor 
  • 取值操作 如果我们有一个元素 tensor ,我们可以使用 .item() 来获得这个 value,而不获得其他性质:
    💡
    PyTorch中的 Tensor 支持超过一百种操作,包括转置、索引、切片、数学运算、线性代数、随机数等等,具体使用方法可参考官方文档

    Broadcasting

    对两个形状不一定的元素进行按元素进行运算的时候,会先将部分元素进行适当复制,再进行运算

    Autograd

    Autograd简介

    autograd是一个面向torch.tensor类的包
    💡
    梯度方向为方向导数最大的方向,梯度的模为最大的方向导数
    • 基本流程
      • 设置属性.requires_grad 为 True,那么它将会追踪对于该张量的所有操作
        完成计算后可以通过调用.backward(),来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad属性。
        💡
        如果y.backward() 中的y是标量,则无须传入参数;否则应当传入y的同型tensor
    • 阻止跟踪记录
      • 要阻止一个张量被跟踪历史,可以调用.detach() 来将它分离并阻止它未来的计算记录被跟踪
      • 为了防止跟踪历史记录(和使用内存),可以将代码块包装在 with torch.no_grad():中在评估模型时特别有用,因为模型可能具有 requires_grad = True 的可训练的参数,但是我们不需要在此过程中对他们进行梯度计算
    • 函数与autograd
      • 还有一个类对于autograd的实现非常重要:Function
        Tensor  Function 互相连接生成了一个无环图 (acyclic graph),它编码了完整的计算历史。每个张量都有一个.grad_fn属性,该属性引用了创建 Tensor 自身的Function(除非这个张量是用户手动创建的,即这个张量的grad_fn是 None )
        在PyTorch中,grad_fn属性是张量的一个属性,它指示了张量是如何计算得到的。对于通过对输入进行数学运算或函数操作而得到的张量,PyTorch会为其分配一个grad_fn属性,用于构建计算图和计算梯度。grad_fn属性是一个PowBackward0对象的引用,它是PyTorch用于构建计算图和计算梯度的一部分
        创建一个张量并设置requires_grad=True用来追踪其计算历史
    • 实例
      • 如果需要计算导数,可以在 Tensor 上调用 .backward()。如果Tensor 是一个标量(即它包含一个元素的数据),则不需要为 backward() 指定任何参数,但是如果它有更多的元素,则需要指定一个gradient参数,该参数是形状匹配的张量。
      • 下面我们创建一个tensor来追踪其计算过程
        •  
    • .requires_grad_(...) 函数可以随时修改张量的requires_grad 参数,该参数默认初始化为False
      • 📌
        区分
        在 PyTorch 中,grad_fn_grad_fn 两者都是表示张量的属性,但在内部实现上有所不同。
        1. grad_fn:是一个公开的属性,用于指示创建张量的操作或函数。它是一个指向创建当前张量的操作的引用,可以让用户轻松地了解张量是如何被创建的。例如,如果一个张量是通过加法操作创建的,则它的 grad_fn 属性将指向一个 AddBackward0 对象,表示它是通过加法操作得到的。grad_fn 属性通常用于计算梯度时构建反向传播图。
        1. _grad_fn:这是一个内部属性,用于表示张量在反向传播过程中用于计算梯度的函数。与 grad_fn 不同,_grad_fn 是在计算梯度时才会被设置的。它指向的对象通常是一个在反向传播中执行梯度计算的函数,而不是张量本身的创建操作。用户通常不需要直接访问 _grad_fn 属性。
        总的来说,grad_fn 属性用于表示张量的创建过程,而 _grad_fn 属性用于表示张量在反向传播过程中所用的梯度计算函数。通常情况下,我们只需要关注 grad_fn 属性来理解张量是如何被创建的。

    梯度

    我们先补充数学知识
    考虑如下的两个张量,我们想要求解,我们可以通过一系列的推到最后得出一个结论:其雅各比行列式就是W的转置,即有
    关于上面的解释,,前项取决于out(z)函数的运算本身,求导即为一个与z的同型矩阵,每个位上为0.25(1/4),而z对x的导数即为2的专置,也就是2
    数学上,若有向量函数,那么关于的梯度就是一个雅可比矩阵:
    而 torch.autograd 这个包就是用来计算一些雅可比矩阵的乘积的。例如,如果是一个标量函数的梯度,那么:,由链式法则,我们可以得到:
    这意味着梯度是累加的(accumulated)
    现在我们来看一个雅可比向量积的例子:
    在这种情况下,不再是标量。torch.autograd 不能直接计算完整的雅可比矩阵,但是如果我们只想要雅可比向量积,只需传递一个张量参数给 backward:
    可以通过将代码块包装在 with torch.no_grad(): 中,来阻止 autograd 跟踪设置了.requires_grad=True的张量的历史记录。
    我们也可以通过对tensor.data 进行操作来规避对梯度的影响

    Parallel Computing

    Why CUDA

    CUDA是NVIDIA提供的一种GPU并行计算框架。对于GPU本身的编程,使用的是CUDA语言来实现的。但是,在我们使用PyTorch编写深度学习代码时,使用的CUDA又是另一个意思。在PyTorch使用 CUDA表示要开始要求我们的模型或者数据开始使用GPU了。
    在编写程序中,当我们使用了 .cuda() 时,其功能是让我们的模型或者数据从CPU迁移到GPU上(默认是0号GPU)当中,通过GPU开始计算。
    📌
    tips
    1. 我们使用GPU时使用的是.cuda()而不是使用.gpu(),AMD的GPU编程接口采用的是OpenCL,在现阶段PyTorch并不支持。
    1. 数据在GPU和CPU之间进行传递时会比较耗时,尽量避免数据的切换。
    1. GPU运算很快,但是在使用简单的操作时,我们应该尽量使用CPU去完成。
    1. 当我们的服务器上有多个GPU,我们应该指明我们使用的GPU是哪一块,如果我们不设置的话,tensor.cuda()方法会默认将tensor保存到第一块GPU上,等价于tensor.cuda(0),这将有可能导致爆显存。我们可以通过以下两种方式继续设置。

      PC Methods

      • Network partitioning
        • 将一个模型的各个部分拆分,然后将不同的部分放入到GPU来做不同任务的计算
          将一个模型的各个部分拆分,然后将不同的部分放入到GPU来做不同任务的计算
          不同模型组件在不同的GPU上时,GPU之间的传输就很重要,对于GPU之间的通信是一个考验
      • Layer-wise partitioning
        • 同一层的模型做一个拆分,让不同的GPU去训练同一层模型的部分任务
          同一层的模型做一个拆分,让不同的GPU去训练同一层模型的部分任务
          这样可以保证在不同组件之间传输的问题,但是在我们需要大量的训练,同步任务加重的情况下,会出现和第一种方式一样的问题。
      • Data parallelism
        • 拆分数据就是,同一个模型在不同GPU中训练一部分数据,然后再分别计算一部分数据之后,只需要将输出的数据做一个汇总,然后再反传
          拆分数据就是,同一个模型在不同GPU中训练一部分数据,然后再分别计算一部分数据之后,只需要将输出的数据做一个汇总,然后再反传
       

      How to use CUDA

      • 单卡
        • 在PyTorch框架下,CUDA的使用变得非常简单,我们只需要显式的将数据和模型通过.cuda()方法转移到GPU上就可加速我们的训练
      • 多卡
        • 单机多卡DPDataParallel
          • notion image
          • 将计算任务划分成多个子任务并在多个GPU卡上同时执行这些子任务。主要使用到了nn.DataParallel函数。
          • 除此之外,我们也可以指定GPU进行并行训练,一般有两种方式
            • nn.DataParallel函数传入device_ids参数,可以指定了使用的GPU编号
            • 手动指定对程序可见的GPU设备
             
        • 多机多卡DDP
       
      Loading...
      wyaaaattwho
      wyaaaattwho
      wyaaaattwho
      公告

      News

      • Our paper Multi-view Consistent Latent Action Learning for World Modeling and Control got accepted by ICML 2026!
      • Our paper TACO: Temporal Consensus Optimization for Continual Neural Mapping got accepted by RSS 2026!
      • Our paper UDON: Uncertainty-weighted Graph-based Optimization for Multi-robot Neural Implicit Mapping got accepted by ICRA 2026!