pytorch_basic

封面

pytorch baisc

最近用Pytorch的时候发现对于pytorch的一些细节问题掌握不够充分。包括整个框架的使用流程,Tensor的一些初始化,类型转换的细节也理解的不是很深。为了方便以后能够更从容的使用Pytorch,重新学习以下Pytorch的一些基础内容,并对重点做一下记录。

目前大致按照官方tutorials的顺序记录,随着学习的深入和对文档的查阅慢慢补充。

Basic - Tensor

torch.Tensor

  1. Tensor的创建

    • 直接创建,不初始化: torch.empty()

      e.g., torch.empty(5, 3, dtype=torch.long)

      其中内部的参数是tensor的形状

      相应的,有如下的初始化方式,参数均和上述一致:

    • 随机初始化: torch.rand()

    • 0值初始化:torch.zeros()
    • 列表初始化:torch.tensor(A_List)
    • 用已有Tensor初始化:torch.new_ones()(除非指定数据类型,否则和输入的tensor数据类型相同)

        x = x.new_ones(5, 3, dtype=torch.double)
        # new_* methods take in sizes
        print(x)
      
        x = torch.randn_like(x, dtype=torch.float)
        # override dtype!
        print(x)
      
  2. 操作

    • 形状相同可以直接四则运算(+, -, *, /),这样的运算是对应位置上的元素在运算
    • 四则运算函数,返回一个运算结果,可以通过out参数将结果输出到给定tensor:
    • torch.add(x, y)
    • torch.sub(x, y)
    • torch.mul(x, y)
    • torch.div(x, y, out=result)
    • 原地运算,函数名后缀为下划线的函数,运算结果直接在对应Tensor上改变。
    • y.add_(x)
    • x.copy_(y)
    • x.t_()
  3. 索引

    • 可以用numpy数组的索引方式来索引tensor
    • 如果一个tensor只有一个元素,可以使用x.item()获得该元素
  4. 改变Tensor形状

    • view()

      view()函数接受的参数即是需要修改后的形状。

      x.view(16): 将x改为长度为16的向量

      x.view(-1, 8): -1表示其他不确定的维度,这个维度需要根据第二个参数8计算出来。例如., 此处x原始的形状为(4,4);那么第二个维度的大小为8,可以计算出第一个维度的大小为2,则新的x的形状为:(2,8)

  5. numpy.ndarray -> tensor:

    • 如何转化:

        # converting numpy array to torch tensor
        import numpy as np
        a = np.ones(5)
        b = torch.from_numpy(a)
        np.add(a, 1, out=a)
        print(a)
        print(b)
      
        # tensor to numpy
        a = torch.ones(5)
        b = a.numpy()
      

      可以通过tensor_name.numpy()方法将一个Tensor转化为numpy数组。

      通过Tensor转化的Numpy和原始的Tensor共享内存

      也就是说,如果你修改得到的Numpy数组,相应的Tensor内容也会变化。(类似指针操作)

      同理,使用numpy数组生成的Tensor和原始numpy数组也有这样的关系。

  6. 使用GPU

    使用.to()函数将变量转为GPU数据。

    eg.,

     # let us run this cell only if CUDA is available
     # We will use ``torch.device`` objects to move tensors in and out of GPU
     if torch.cuda.is_available():
         device = torch.device("cuda")          # a CUDA device object
         y = torch.ones_like(x, device=device)  # directly create a tensor on GPU
         x = x.to(device)                       # or just use strings ``.to("cuda")``
         z = x + y
         print(z)
         print(z.to("cpu", torch.double))       # ``.to`` can also change dtype together!
    

参考官方文档

Basic - Autograd, 自动求导

torch.autograd, torch.Function

Function: 参考文档

autograd这个包为所有在张量上的操作提供了自动求导的功能。

该框架是在运行时定义的,因此反向传播的方式由代码运行的方式定义,每次迭代都可以不同。

  1. requires_gradgrad属性

    • requires_grad属性,boolean类型,True表示需要自动计算梯度
    • grad:存储自动计算的梯度
    • requires_grad_()方法可以改变一个Tensor的该属性的值
  2. 停止追踪历史计算

    • .detach():避免张量追溯历史记录或者被之后的计算追溯。(不太明白,后续修改补充。原句:To stop a tensor from tracking history, you can call .detach() to detach it from the computation history, and to prevent future computation from being tracked.)

      如果需要使用一个.requires_grad属性为True的变量,但是又不想对这个变量做的操作被追溯(计算梯度),可以使用.detach()方法得到该变量的副本,并且副本的该属性默认为False

  3. 避免追踪历史记录或者使用内存:

    • 将代码块写在with_torch.no_grad():下。该方法下的代码块在执行时将不会自动计算梯度或者更新参数。适合在对已经训练好的模型测试,评估时使用。
  4. 自动求导过程中最重要的类:Function

    • TensorFunction是相关联的,二者一起构建了一个非循环图以编码一个完整的计算过程。
    • .grad_fn:指向了生成这个TensorFunction。当属性值为None,表示这个Tensor是由用户创建的
  5. 求导:.backward()

    此处存疑,未能完全理解

    使用.backward()求导需要注意的问题:

    1. 如果该Tensor是一个标量,不需要特别指定参数
    2. 如果该Tensor含有不止一个元素,需要指定一个gradient参数,这个参数是一个形状匹配的Tensor

      autograd是一个计算向量-雅可比矩阵乘积的引擎

      下面对此详细说明:

      实际上,.backward()是需要参数的。只不过当Tensor是一个标量的时候,默认方法实质上等价于.backward(torch.tensor(1.)), autograd引擎实际上计算的是$1.0*\dfrac{d(o)}{dx}$,其中1.0被理解为$\dfrac{dl}{do}=1.0$

      .backward()的形参视为$v$,最终计算的值其实是$J^T\dotv$。(为什么不是$v^T\dotJ$, 因为前者得到的是列向量)

  6. 原始教程

点击此处查看原始教程

Basic - Neural Network

torch.nn

重点内容:

  • 定义模型
  • nn.Module
  • forward(input)
  1. 模型训练流程

    • 定义神经网络,定义可学习的参数
    • 遍历输入数据集
    • 处理输入
    • 计算损失值
    • 计算梯度
    • 更新权重
  2. 定义网络

    • 继承nn.Module
    • 重写__init__()
    • 重写forward()

      模型的参数

    • model.parameters()方法返回模型中的参数

    • model(input)直接调用forward()方法,返回前馈网络的传播。
    • model.zero_grad(),在反向传播前,应该清空上一次迭代的梯度

      重点

    • torch.nn只支持mini-batches输入。也就是说,整个troch.nn包中的方法都只支持使用mini-batches作为输入,不支持单个样本的输入。例如2为卷积层接收的输入应该是一个4维的张量,这个张量各个维度的意义是:样本数,通道数,高度,宽度。

    • 如果确实需要输入单个样本,可以考虑使用.unsqueeze(0)方法,为样本增加一个维度。
  3. 计算loss值

    Loss Function接受一个张量对(output, target)作为输入,并且计算输出和目标值的差距。

    有很多常用的Loss函数,这里不一一写出,详情参考Loss Function

    关于Loss函数的一些细节问题之后补充
  4. 反向传播

    示例:

     net.zero_grad()
     # zeroes the gradient buffers of all parameters
    
     print('conv1.bias.grad before backward')
     print(net.conv1.bias.grad)
    
     loss.backward()
    
     print('conv1.bias.grad after backward')
     print(net.conv1.bias.grad)
    
分享到