• 【PyTorch】1-基础知识(张量、导数、CUDA)


    PyTorch:1-基础知识

    注:所有资料来源且归属于thorough-pytorch(https://datawhalechina.github.io/thorough-pytorch/),下文仅为学习记录

    1.1:张量

    神经网络核心包:autograd(自动微分)

    张量的核心:数据容器

    张量维度几何含义
    0标量
    1向量
    2矩阵
    3时间序列
    4图像
    5视频

    1个图像

    (width, height, channel) = 3D
    
    • 1

    1个图像数据集

    (batch_size, width, height, channel) = 4D
    
    • 1

    torch.Tensor

    存储和变换数据

    创建tensor

    【1】随机矩阵

    import torch
    # row行数, col列数
    x = torch.rand(row, col)
    
    • 1
    • 2
    • 3

    【2】全0矩阵

    import torch
    # row行数, col列数
    x = torch.zeros(row, col, dtype=torch.long)
    
    • 1
    • 2
    • 3

    【3】张量构建

    import torch
    # x1为元素1,x2为元素2,默认转float
    x = torch.tensor([x1, x2])
    
    • 1
    • 2
    • 3

    【4】输出张量维度

    print(x.size())
    # or
    print(x.shape)
    
    • 1
    • 2
    • 3

    常见构造

    函数功能
    Tensor(sizes)基础构造函数
    tensor(data)类似于np.array
    ones(sizes)全1
    zeros(sizes)全0
    eye(sizes)对角为1,其余为0
    arange(s,e,step)从s到e,步长为step
    linspace(s,e,steps)从s到e,均匀分成step份
    rand/randn(sizes)rand是[0,1)均匀分布;randn是服从N(0,1)的正态分布
    normal(mean,std)正态分布(均值为mean,标准差是std)
    randperm(m)随机排列

    张量的操作

    【1】加法

    x = torch.rand(row, col)
    y = torch.rand(row, col)
    
    # m1
    x + y
    # m2
    torch.add(x,y)
    # m3
    y.add_(x)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    【2】索引

    取某一行/列

    x = torch.rand(row, col)
    print(x[: 1]) # 取第2列
    
    • 1
    • 2

    ps:索引出来的结果与原数据共享内存。修改一个,另一个会跟着修改。如果不想修改,可以使用copy()

    【3】维度变换

    torch.view() 共享内存

    import torch
    x = torch.randn(4, 4)
    y = x.view(16)
    z = x.view(-1, 8) # -1是指这一维的维数由其他维度决定
    print(x.size(), y.size(), z.size())
    
    # torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    torch.reshape()不共享内存

    import torch
    x = torch.randn(4, 4)
    y = x.reshape(16)
    z = x.reshape(-1, 8) # -1是指这一维的维数由其他维度决定
    print(x.size(), y.size(), z.size())
    
    # output is the same
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    推荐的方法:先用 clone() 创造一个张量副本,然后再使用 torch.view()进行函数维度变换

    【4】取值

    import torch
    x = torch.randn(1) 
    print(type(x)) 
    print(type(x.item()))
    
    #  表示x是张量
    #  表示x的元素是浮点数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    广播机制

    背景:对两个形状不同的 Tensor 按元素运算

    import torch
    x = torch.arange(1, 3).view(1, 2)
    print(x)
    y = torch.arange(1, 4).view(3, 1)
    print(y)
    print(x + y)
    # 很明显此处讲x的row扩展为了3,y的col扩展为了2,然后再进行加法操作
    
    """
    tensor([[1, 2]])
    tensor([[1],
            [2],
            [3]])
    tensor([[2, 3],
            [3, 4],
            [4, 5]])
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    1.2:自动求导

    Autograd

    记录张量操作

    属性 .requires_gradTrue,则会追踪对于 Tensor 的所有操作。

    完成计算后可以调用 .backward(),自动计算所有的梯度。

    张量的所有梯度将会自动累加到.grad属性。

    防止操作追踪

    防止跟踪历史记录,可以将代码块包装在 with torch.no_grad(): 中,也就是evaluate模型时所用。

    每个张量都有一个.grad_fn属性,该属性引用了创建 Tensor 自身的Function

    若张量为用户手动创建,则.grad_fn = None

    计算导数

    y.backward() 时,如果 y 是标量,则不需要为 backward() 传入任何参数;否则,需要传入一个与 y 同形的Tensor

    Example

    import torch
    x = torch.ones(2, 2, requires_grad=True)
    print(x)
    
    y = x**2
    print(y)
    print(y.grad_fn)
    
    """
    tensor([[1., 1.],
            [1., 1.]], requires_grad=True)
    tensor([[1., 1.],
            [1., 1.]], grad_fn=)
    
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    梯度

    因为 out 是一个标量,因此out.backward() out.backward(torch.tensor(1.)) 等价,求解的导数是 d(out)/dx

    grad在反向传播过程中是累加的,所以一般在反向传播之前需把梯度清零 x.grad.data.zero_()

    雅可比向量积的例子

    import torch
    x = torch.randn(3, requires_grad=True)
    print(x)
    
    y = x * 2
    i = 0
    while y.data.norm() < 1000:
        y = y * 2
        i = i + 1
    print(y)
    print(i)
    
    # y不再是标量!
    # torch.autograd无法直接计算完整的雅可比矩阵
    # 想要雅可比向量积,需将这个向量作为参数传给 backward
    v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
    y.backward(v)
    
    print(x.grad)
    
    """
    tensor([ 0.3718,  0.4511, -0.5233], requires_grad=True)
    
    tensor([  761.5394,   923.9069, -1071.7576], grad_fn=)
    
    10
    
    tensor([2.0480e+02, 2.0480e+03, 2.0480e-01])
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    修改张量数值,但不被autograd记录/反向传播

    可对 tensor.data 进行操作

    import torch
    x = torch.ones(1,requires_grad=True)
    
    print(x.data)               # 还是一个tensor
    print(x.data.requires_grad) # 但是已经是独立于计算图之外
    
    y = 2 * x
    x.data *= 100               # 只改变了值,不会记录在计算图,所以不会影响梯度传播
    
    y.backward()
    print(x)                    # 更改data的值也会影响tensor的值 
    print(x.grad)
    
    """
    tensor([1.])
    
    False
    
    tensor([100.], requires_grad=True)
    
    tensor([2.])
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    并行计算

    查看GPU情况

    nvidia-smi
    # windows下的cmd也可以用!
    
    • 1
    • 2

    CUDA

    CUDA是NVIDIA提供的一种GPU并行计算框架。

    在PyTorch使用 CUDA,表示开始要求模型或者数据使用GPU。

    当使用 .cuda() 时,其功能是让模型或者数据从CPU迁移到GPU上(默认是0号GPU)

    设置训练所用的GPU

    方法1:运行train.py时设置可用cuda

    CUDA_VISBLE_DEVICE=0,1 python train.py 
    # 使用0,1两块GPU
    
    • 1
    • 2

    方法2:在train.py开头设置可用cuda

    import os
    os.environ["CUDA_VISIBLE_DEVICE"] = "2"
    
    • 1
    • 2

    常见并行方法

    【1】Network partitioning

    网络结构分布到不同的设备中

    【2】Layer-wise partitioning

    同一层的任务分布到不同数据中

    【3】Data parallelism

    不同的数据分布到不同的设备中,执行相同的任务

    cuda加速训练

    【1】单卡

    显式的将数据和模型通过.cuda()方法转移到GPU上

    model = Net()
    model.cuda() # 模型显示转移到CUDA上
    
    for image,label in dataloader:
        # 图像和标签显示转移到CUDA上
        image = image.cuda() 
        label = label.cuda()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    【2】多卡

    DataParallelDistributedDataParallel

    DP.png

    DP数据并行

    model = Net()
    model.cuda() # 模型显示转移到CUDA上
    
    if torch.cuda.device_count() > 1: # 含有多张GPU的卡
    	model = nn.DataParallel(model) # 单机多卡DP训练
    
    • 1
    • 2
    • 3
    • 4
    • 5

    指定GPU进行并行训练

    model = nn.DataParallel(model, device_ids=[0,1]) # 使用第0和第1张卡进行并行训练
    
    • 1

    DDP多机多卡

    AI硬件加速设备

    TPU

    Tensor Processing Unit,张量处理器。

    NPU

    存中…(img-6EdY2G6i-1713698392008)]

    DP数据并行

    model = Net()
    model.cuda() # 模型显示转移到CUDA上
    
    if torch.cuda.device_count() > 1: # 含有多张GPU的卡
    	model = nn.DataParallel(model) # 单机多卡DP训练
    
    • 1
    • 2
    • 3
    • 4
    • 5

    指定GPU进行并行训练

    model = nn.DataParallel(model, device_ids=[0,1]) # 使用第0和第1张卡进行并行训练
    
    • 1

    DDP多机多卡

    AI硬件加速设备

    TPU

    Tensor Processing Unit,张量处理器。

    NPU

    Neural-network Processing Unit,神经网络处理器。

  • 相关阅读:
    MVC架构回顾
    云安全之等级保护详解
    开放式激光振镜运动控制器在动力电池模组连接片的焊接应用
    2024年网络安全(黑客技术)三个月自学手册
    Vue学习
    非零基础自学Java (老师:韩顺平) 第8章 面向对象编程(中级部分) 8.13 断点调试(debug)
    ChatGPT最强平替Claude也推出付费版;Midjourney 学习指南
    el-cascader级联选择器-懒加载+多选+回显功能
    .NET开源且免费的Windows远程桌面管理软件
    HCIP实验1-2:OSPF多区域
  • 原文地址:https://blog.csdn.net/m0_65787507/article/details/138042451