day02 pytorch介绍与安装

news/2025/10/26 19:19:45/文章来源:https://www.cnblogs.com/fuminer/p/19167228

1 框架介绍与安装¶

  • 本章节主要带领大家学习使用深度学习框架 PyTorch:

PyTorch 介绍¶

  • 在2017年1月, Facebook的人工智能研究院 (FAIR) 向世界推出了PyTorch. 这个基于Torch的框架, 以其Python语言作为前端, 同时为深度学习研究者和开发者提供了两大核心优势:
  • 一是强大的GPU加速张量计算能力, 其并行计算能力在当时与NumPy相媲美.
  • 二是内置的自动微分系统, 使得构建深度神经网络变得更加直观和高效.
  • 2018年10月, 在NeurIPS 2018会议上, Facebook宣布了PyTorch 1.0的发布. 这个版本的推出, 标志着PyTorch在商业化进程中取得了重要进展.
  • 在2019年前, Tensorflow一直作为深度学习系统中的领头存在, 而以2019年为分界线, Pytorch异军突起, 逐渐成为了开发者和研究人员最为喜爱的框架. 随着Pytorch的不断普及和完善, 其生态也越发蓬勃.
  • 在AI领域, huggingface社区的开源的transformers库使用pytorch实现了市面上绝大多数开源的预训练模型.
  • 微软的分布式训练框架deepspeed也支持Pytorch, 由于Pytorch备受研究人员的青睐, 近年来绝大多数开源神经网络架构都采用Pytorch实现.

PyTorch 安装¶

  • https://github.com/pytorch/pytorch
  • 安装:
  • pip install torch==2.1.0
  • 通过本章节的学习, 同学们将会了解Pytorch的发展历史, 并掌握 PyTorch 深度学习框架的安装.

1 张量的创建¶

学习目标¶

  • 掌握张量创建
    PyTorch 是一个 Python 深度学习框架,它将数据封装成张量(Tensor)来进行运算。PyTorch 中的张量就是元素为同一种数据类型的多维矩阵。在 PyTorch 中,张量以 "类" 的形式封装起来,对张量的一些运算、处理的方法被封装在类中。

1. 基本创建方式¶

  • torch.tensor 根据指定数据创建张量
  • torch.Tensor 根据形状创建张量, 其也可用来创建指定数据的张量
  • torch.IntTensor、torch.FloatTensor、torch.DoubleTensor 创建指定类型的张量
import torch
import numpy as np
import random# 1. 根据已有数据创建张量
def test01():# 1. 创建张量标量data = torch.tensor(10)print(data)# 2. numpy 数组, 由于 data 为 float64, 下面代码也使用该类型data = np.random.randn(2, 3)data = torch.tensor(data)print(data)# 3. 列表, 下面代码使用默认元素类型 float32data = [[10., 20., 30.], [40., 50., 60.]]data = torch.tensor(data)print(data)# 2. 创建指定形状的张量
def test02():# 1. 创建2行3列的张量, 默认 dtype 为 float32data = torch.Tensor(2, 3)print(data)# 2. 注意: 如果传递列表, 则创建包含指定元素的张量data = torch.Tensor([10])print(data)data = torch.Tensor([10, 20])print(data)# 3. 使用具体类型的张量
def test03():# 1. 创建2行3列, dtype 为 int32 的张量data = torch.IntTensor(2, 3)print(data)# 2. 注意: 如果传递的元素类型不正确, 则会进行类型转换data = torch.IntTensor([2.5, 3.3])print(data)# 3. 其他的类型data = torch.ShortTensor()  # int16data = torch.LongTensor()   # int64data = torch.FloatTensor()  # float32data = torch.DoubleTensor() # float64if __name__ == '__main__':test02()

程序输出结果:

tensor(10)
tensor([[ 0.1345,  0.1149,  0.2435],[ 0.8026, -0.6744, -1.0918]], dtype=torch.float64)
tensor([[10., 20., 30.],[40., 50., 60.]])
tensor([[0.0000e+00, 3.6893e+19, 2.2018e+05],[4.6577e-10, 2.4158e-12, 1.1625e+33]])
tensor([10.])
tensor([10., 20.])
tensor([[         0, 1610612736, 1213662609],[ 805308409,  156041223,          1]], dtype=torch.int32)
tensor([2, 3], dtype=torch.int32)

2. 创建线性和随机张量¶

  • torch.arange 和 torch.linspace 创建线性张量
  • torch.random.init_seed 和 torch.random.manual_seed 随机种子设置
  • torch.randn 创建随机张量
import torch# 1. 创建线性空间的张量
def test01():# 1. 在指定区间按照步长生成元素 [start, end, step)data = torch.arange(0, 10, 2)print(data)# 2. 在指定区间按照元素个数生成data = torch.linspace(0, 11, 10)print(data)# 2. 创建随机张量
def test02():# 1. 创建随机张量data = torch.randn(2, 3)  # 创建2行3列张量print(data)# 2. 随机数种子设置print('随机数种子:', torch.random.initial_seed())torch.random.manual_seed(100)print('随机数种子:', torch.random.initial_seed())if __name__ == '__main__':test02()

程序输出结果:

tensor([0, 2, 4, 6, 8])
tensor([ 0.0000,  1.2222,  2.4444,  3.6667,  4.8889,  6.1111,  7.3333,  8.5556,9.7778, 11.0000])
tensor([[-0.5209, -0.2439, -1.1780],[ 0.8133,  1.1442,  0.6790]])
随机数种子: 4508475192273306739
随机数种子: 100

3. 创建01张量¶

  • torch.ones 和 torch.ones_like 创建全1张量
  • torch.zeros 和 torch.zeros_like 创建全0张量
  • torch.full 和 torch.full_like 创建全为指定值张量
import torch# 1. 创建全0张量
def test01():# 1. 创建指定形状全0张量data = torch.zeros(2, 3)print(data)# 2. 根据张量形状创建全0张量data = torch.zeros_like(data)print(data)# 2. 创建全1张量
def test02():# 1. 创建指定形状全0张量data = torch.ones(2, 3)print(data)# 2. 根据张量形状创建全0张量data = torch.ones_like(data)print(data)# 3. 创建全为指定值的张量
def test03():# 1. 创建指定形状指定值的张量data = torch.full([2, 3], 10)print(data)# 2. 根据张量形状创建指定值的张量data = torch.full_like(data, 20)print(data)if __name__ == '__main__':test01()test02()test03()

程序输出结果:

tensor([[0., 0., 0.],[0., 0., 0.]])
tensor([[0., 0., 0.],[0., 0., 0.]])
tensor([[1., 1., 1.],[1., 1., 1.]])
tensor([[1., 1., 1.],[1., 1., 1.]])
tensor([[10, 10, 10],[10, 10, 10]])
tensor([[20, 20, 20],[20, 20, 20]])

4. 张量元素类型转换¶

  • tensor.type(torch.DoubleTensor)
  • torch.double()
import torchdef test():data = torch.full([2, 3], 10)print(data.dtype)# 将 data 元素类型转换为 float64 类型# 1. 第一种方法data = data.type(torch.DoubleTensor)print(data.dtype)# 转换为其他类型# data = data.type(torch.ShortTensor)# data = data.type(torch.IntTensor)# data = data.type(torch.LongTensor)# data = data.type(torch.FloatTensor)# 2. 第二种方法data = data.double()print(data.dtype)# 转换为其他类型# data = data.short()# data = data.int()# data = data.long()# data = data.float()if __name__ == '__main__':test()

程序输出结果:

torch.int64
torch.float64
torch.float64

5. 小节¶

在本小节中,我们主要学习了以下内容:
1. 创建张量的方式1. torch.tensor 根据指定数据创建张量2. torch.Tensor 根据形状创建张量, 其也可用来创建指定数据的张量3. torch.IntTensor、torch.FloatTensor、torch.DoubleTensor 创建指定类型的张量
  • 创建线性和随机张量 - torch.arange 和 torch.linspace 创建线性张量
    • torch.random.init_seed 和 torch.random.manual_seed 随机种子设置
    • torch.randn 创建随机张量
  • 创建01张量 - torch.ones 和 torch.ones_like 创建全1张量
    • torch.zeros 和 torch.zeros_like 创建全0张量
    • torch.full 和 torch.full_like 创建全为指定值张量
  • 张量元素类型转换 - tensor.type(torch.DoubleTensor)
    • torch.double()

2 张量数值计算¶

学习目标¶

  • 掌握张量基本运算
  • 掌握阿达玛积、点积运算
  • 掌握PyTorch指定运算设备
    PyTorch 计算的数据都是以张量形式存在, 我们需要掌握张量各种运算. 并且, 我们可以在 CPU 中运算, 也可以在 GPU 中运算.

1. 张量基本运算¶

基本运算中,包括 add、sub、mul、div、neg 等函数, 以及这些函数的带下划线的版本 add_、sub_、mul_、div_、neg_,其中带下划线的版本为修改原数据。

import numpy as np
import torchdef test():data = torch.randint(0, 10, [2, 3])print(data)print('-' * 50)# 1. 不修改原数据new_data = data.add(10)  # 等价 new_data = data + 10print(new_data)print('-' * 50)# 2. 直接修改原数据# 注意: 带下划线的函数为修改原数据本身data.add_(10)  # 等价 data += 10print(data)# 3. 其他函数print(data.sub(100))print(data.mul(100))print(data.div(100))print(data.neg())if __name__ == '__main__':test()

程序输出结果:

tensor([[3, 7, 4],[0, 0, 6]])
--------------------------------------------------
tensor([[13, 17, 14],[10, 10, 16]])
--------------------------------------------------
tensor([[13, 17, 14],[10, 10, 16]])
tensor([[-87, -83, -86],[-90, -90, -84]])
tensor([[1300, 1700, 1400],[1000, 1000, 1600]])
tensor([[0.1300, 0.1700, 0.1400],[0.1000, 0.1000, 0.1600]])
tensor([[-13, -17, -14],[-10, -10, -16]])

2. 阿达玛积¶

阿达玛积指的是矩阵对应位置的元素相乘.

import numpy as np
import torchdef test():data1 = torch.tensor([[1, 2], [3, 4]])data2 = torch.tensor([[5, 6], [7, 8]])# 第一种方式data = torch.mul(data1, data2)print(data)print('-' * 50)# 第二种方式data = data1 * data2print(data)print('-' * 50)if __name__ == '__main__':test()

程序输出结果:

tensor([[ 5, 12],[21, 32]])
--------------------------------------------------
tensor([[ 5, 12],[21, 32]])
--------------------------------------------------

3. 点积运算¶

点积运算要求第一个矩阵 shape: (n, m),第二个矩阵 shape: (m, p), 两个矩阵点积运算 shape 为: (n, p)。
  • 运算符 @ 用于进行两个矩阵的点乘运算
  • torch.mm 用于进行两个矩阵点乘运算, 要求输入的矩阵为2维
  • torch.bmm 用于批量进行矩阵点乘运算, 要求输入的矩阵为3维
  • torch.matmul 对进行点乘运算的两矩阵形状没有限定. - 对于输入都是二维的张量相当于 mm 运算.
    • 对于输入都是三维的张量相当于 bmm 运算
    • 对数输入的 shape 不同的张量, 对应的最后几个维度必须符合矩阵运算规则
import numpy as np
import torch# 1. 点积运算
def test01():data1 = torch.tensor([[1, 2], [3, 4], [5, 6]])data2 = torch.tensor([[5, 6], [7, 8]])# 第一种方式data = data1 @ data2print(data)print('-' * 50)# 第二种方式data = torch.mm(data1, data2)print(data)print('-' * 50)# 第三种方式data = torch.matmul(data1, data2)print(data)print('-' * 50)# 2. torch.mm 和 torch.matmull 的区别
def test02():# matmul 可以两个维度可以不同# 第一个张量: (3, 4, 5)# 第二个张量: (5, 4)# torch.mm 不可以相乘,而 matmul 则可以相乘print(torch.matmul(torch.randn(3, 4, 5), torch.randn(5, 4)).shape)print(torch.matmul(torch.randn(5, 4), torch.randn(3, 4, 5)).shape)# 3. torch.mm 函数的用法
def test03():# 批量点积运算# 第一个维度为 batch_size# 矩阵的二三维要满足矩阵乘法规则data1 = torch.randn(3, 4, 5)data2 = torch.randn(3, 5, 8)data = torch.bmm(data1, data2)print(data.shape)if __name__ == '__main__':test01()test02()test03()

程序输出结果:

tensor([[19, 22],[43, 50],[67, 78]])
--------------------------------------------------
tensor([[19, 22],[43, 50],[67, 78]])
--------------------------------------------------
tensor([[19, 22],[43, 50],[67, 78]])
--------------------------------------------------
torch.Size([3, 4, 4])
torch.Size([3, 5, 5])
torch.Size([3, 4, 8])

4. 指定运算设备¶

PyTorch 默认会将张量创建在 CPU 控制的内存中, 即: 默认的运算设备为 CPU。我们也可以将张量创建在 GPU 上, 能够利用对于矩阵计算的优势加快模型训练。将张量移动到 GPU 上有两种方法:

  1. 使用 cuda 方法
  2. 直接在 GPU 上创建张量
  3. 使用 to 方法指定设备
import torch# 1. 使用 cuda 方法
def test01():data = torch.tensor([10, 20 ,30])print('存储设备:', data.device)# 如果安装的不是 gpu 版本的 PyTorch# 或电脑本身没有 NVIDIA 卡的计算环境# 下面代码可能会报错data = data.cuda()print('存储设备:', data.device)# 使用 cpu 函数将张量移动到 cpu 上data = data.cpu()print('存储设备:', data.device)# 输出结果:# 存储设备: cpu# 存储设备: cuda:0# 存储设备: cpu# 2. 直接将张量创建在 GPU 上
def test02():data = torch.tensor([10, 20, 30], device='cuda:0')print('存储设备:', data.device)# 使用 cpu 函数将张量移动到 cpu 上data = data.cpu()print('存储设备:', data.device)# 输出结果:# 存储设备: cuda:0# 存储设备: cpu# 3. 使用 to 方法
def test03():data = torch.tensor([10, 20, 30])print('存储设备:', data.device)data = data.to('cuda:0')print('存储设备:', data.device)# 输出结果:# 存储设备: cpu# 存储设备: cuda:0# 4. 存储在不同设备的张量不能运算
def test04():data1 = torch.tensor([10, 20, 30], device='cuda:0')data2 = torch.tensor([10, 20, 30])print(data1.device, data2.device)# RuntimeError: Expected all tensors to be on the same device,# but found at least two devices, cuda:0 and cpu!data = data1 + data2print(data)if __name__ == '__main__':test04()

程序输出结果:

存储设备: cpu
存储设备: cuda:0
存储设备: cpu
存储设备: cuda:0
存储设备: cpu
存储设备: cpu
存储设备: cuda:0
cuda:0 cpu

5. 小节¶

在本小节中,我们主要学习的主要内容如下:

  • 张量基本运算函数 add、sub、mul、div、neg 等函数, add_、sub_、mul_、div_、neg_ 等 inplace 函数
  • 张量的阿达玛积运算 mul 和运算符 * 的用法
  • 点积运算: - 运算符 @ 用于进行两个矩阵的点乘运算
    • torch.mm 用于进行两个矩阵点乘运算, 要求输入的矩阵为2维
    • torch.bmm 用于批量进行矩阵点乘运算, 要求输入的矩阵为3维
    • torch.matmul 对进行点乘运算的两矩阵形状没有限定. - 对于输入都是二维的张量相当于 mm 运算.
      • 对于输入都是三维的张量相当于 bmm 运算
      • 对数输入的 shape 不同的张量, 对应的最后几个维度必须符合矩阵运算规则
  • 将变量移动到 GPU 设备的方法,例如: cuda 方法、直接在 GPU 上创建张量、使用 to 方法指定设备

3 张量类型转换¶

学习目标¶

  • 掌握张量类型转换方法
    张量的类型转换也是经常使用的一种操作,是必须掌握的知识点。在本小节,我们主要学习如何将 numpy 数组和 PyTorch Tensor 的转化方法.

1. 张量转换为 numpy 数组¶

使用 Tensor.numpy 函数可以将张量转换为 ndarray 数组,但是共享内存,可以使用 copy 函数避免共享。

# 1. 将张量转换为 numpy 数组
def test01():data_tensor = torch.tensor([2, 3, 4])# 使用张量对象中的 numpy 函数进行转换data_numpy = data_tensor.numpy()print(type(data_tensor))print(type(data_numpy))# 注意: data_tensor 和 data_numpy 共享内存# 修改其中的一个,另外一个也会发生改变# data_tensor[0] = 100data_numpy[0] = 100print(data_tensor)print(data_numpy)if __name__ == '__main__':test01()

2. numpy 转换为张量¶

  • 使用 from_numpy 可以将 ndarray 数组转换为 Tensor,默认共享内存,使用 copy 函数避免共享。
  • 使用 torch.tensor 可以将 ndarray 数组转换为 Tensor,默认不共享内存。
# 1. 使用 from_numpy 函数
def test01():data_numpy = np.array([2, 3, 4])# 将 numpy 数组转换为张量类型# 1. from_numpy# 2. torch.tensor(ndarray)# 浅拷贝data_tensor = torch.from_numpy(data_numpy)# nunpy 和 tensor 共享内存# data_numpy[0] = 100data_tensor[0] = 100print(data_tensor)print(data_numpy)# 2. 使用 torch.tensor 函数
def test02():data_numpy = np.array([2, 3, 4])data_tensor = torch.tensor(data_numpy)# nunpy 和 tensor 不共享内存# data_numpy[0] = 100data_tensor[0] = 100print(data_tensor)print(data_numpy)if __name__ == '__main__':test01()test02()

3. 标量张量和数字的转换¶

对于只有一个元素的张量,使用 item 方法将该值从张量中提取出来。

# 3. 标量张量和数字的转换
def test03():# 当张量只包含一个元素时, 可以通过 item 函数提取出该值data = torch.tensor([30,])print(data.item())data = torch.tensor(30)print(data.item())if __name__ == '__main__':test03()

程序输出结果:

30
30

小节¶

在本小节中, 我们主要学习了 numpy 和 tensor 互相转换的规则, 以及标量张量与数值之间的转换规则。


4 张量拼接操作¶

学习目标¶

  • 掌握torch.cat torch.stack使用
    张量的拼接操作在神经网络搭建过程中是非常常用的方法,例如: 在后面将要学习到的残差网络、注意力机制中都使用到了张量拼接。

1. torch.cat 函数的使用¶

torch.cat 函数可以将两个张量根据指定的维度拼接起来.
import torchdef test():data1 = torch.randint(0, 10, [3, 5, 4])data2 = torch.randint(0, 10, [3, 5, 4])print(data1)print(data2)print('-' * 50)# 1. 按0维度拼接new_data = torch.cat([data1, data2], dim=0)print(new_data.shape)print('-' * 50)# 2. 按1维度拼接new_data = torch.cat([data1, data2], dim=1)print(new_data.shape)print('-' * 50)# 3. 按2维度拼接new_data = torch.cat([data1, data2], dim=2)print(new_data.shape)if __name__ == '__main__':test()

程序输出结果:

tensor([[[6, 8, 3, 5],[1, 1, 3, 8],[9, 0, 4, 4],[1, 4, 7, 0],[5, 1, 4, 8]],[[0, 1, 4, 4],[4, 1, 8, 7],[5, 2, 6, 6],[2, 6, 1, 6],[0, 7, 8, 9]],[[0, 6, 8, 8],[5, 4, 5, 8],[3, 5, 5, 9],[3, 5, 2, 4],[3, 8, 1, 1]]])
tensor([[[4, 6, 8, 1],[0, 1, 8, 2],[4, 9, 9, 8],[5, 1, 5, 9],[9, 4, 3, 0]],[[7, 6, 3, 3],[4, 3, 3, 2],[2, 1, 1, 1],[3, 0, 8, 2],[8, 6, 6, 5]],[[0, 7, 2, 4],[4, 3, 8, 3],[4, 2, 1, 9],[4, 2, 8, 9],[3, 7, 0, 8]]])
--------------------------------------------------
torch.Size([6, 5, 4])
--------------------------------------------------
torch.Size([3, 10, 4])
tensor([[[6, 8, 3, 5, 4, 6, 8, 1],[1, 1, 3, 8, 0, 1, 8, 2],[9, 0, 4, 4, 4, 9, 9, 8],[1, 4, 7, 0, 5, 1, 5, 9],[5, 1, 4, 8, 9, 4, 3, 0]],[[0, 1, 4, 4, 7, 6, 3, 3],[4, 1, 8, 7, 4, 3, 3, 2],[5, 2, 6, 6, 2, 1, 1, 1],[2, 6, 1, 6, 3, 0, 8, 2],[0, 7, 8, 9, 8, 6, 6, 5]],[[0, 6, 8, 8, 0, 7, 2, 4],[5, 4, 5, 8, 4, 3, 8, 3],[3, 5, 5, 9, 4, 2, 1, 9],[3, 5, 2, 4, 4, 2, 8, 9],[3, 8, 1, 1, 3, 7, 0, 8]]])

2. torch.stack 函数的使用¶

torch.stack 函数可以将两个张量根据指定的维度叠加起来.
import torchdef test():data1= torch.randint(0, 10, [2, 3])data2= torch.randint(0, 10, [2, 3])print(data1)print(data2)new_data = torch.stack([data1, data2], dim=0)print(new_data.shape)new_data = torch.stack([data1, data2], dim=1)print(new_data.shape)new_data = torch.stack([data1, data2], dim=2)print(new_data.shape)if __name__ == '__main__':test()

程序输出结果:

tensor([[5, 8, 7],[6, 0, 6]])
tensor([[5, 8, 0],[9, 0, 1]])
torch.Size([2, 2, 3])
torch.Size([2, 2, 3])
torch.Size([2, 3, 2])

3. 小节¶

张量的拼接操作也是在后面我们经常使用一种操作。cat 函数可以将张量按照指定的维度拼接起来,stack 函数可以将张量按照指定的维度叠加起来。


5 张量索引操作¶

学习目标¶

  • 掌握张量不同索引操作
    我们在操作张量时,经常需要去进行获取或者修改操作,掌握张量的花式索引操作是必须的一项能力。

1. 简单行、列索引¶

准备数据

import torchdata = torch.randint(0, 10, [4, 5])
print(data)
print('-' * 50)

程序输出结果:

tensor([[0, 7, 6, 5, 9],[6, 8, 3, 1, 0],[6, 3, 8, 7, 3],[4, 9, 5, 3, 1]])
--------------------------------------------------
# 1. 简单行、列索引
def test01():print(data[0])print(data[:, 0])print('-' * 50)if __name__ == '__main__':test01()

程序输出结果:

tensor([0, 7, 6, 5, 9])
tensor([0, 6, 6, 4])
--------------------------------------------------

2. 列表索引¶

# 2. 列表索引
def test02():# 返回 (0, 1)、(1, 2) 两个位置的元素print(data[[0, 1], [1, 2]])print('-' * 50)# 返回 0、1 行的 1、2 列共4个元素print(data[[[0], [1]], [1, 2]])
if __name__ == '__main__':test02()

程序输出结果:

tensor([7, 3])
--------------------------------------------------
tensor([[7, 6],[8, 3]])

3. 范围索引¶

# 3. 范围索引
def test03():# 前3行的前2列数据print(data[:3, :2])# 第2行到最后的前2列数据print(data[2:, :2])
if __name__ == '__main__':test03()

程序输出结果:

tensor([[0, 7],[6, 8],[6, 3]])
tensor([[6, 3],[4, 9]])

4. 布尔索引¶

# 布尔索引
def test():# 第2列大于5的行数据print(data[data[:, 2] > 5])# 第1行大于5的列数据print(data[:, data[1] > 5])
if __name__ == '__main__':test04()

程序输出结果:

tensor([[0, 7, 6, 5, 9],[6, 3, 8, 7, 3]])
tensor([[0, 7],[6, 8],[6, 3],[4, 9]])

5. 多维索引¶

# 多维索引
def test05():data = torch.randint(0, 10, [3, 4, 5])print(data)print('-' * 50)print(data[0, :, :])print(data[:, 0, :])print(data[:, :, 0])if __name__ == '__main__':test05()

程序输出结果:

tensor([[[2, 4, 1, 2, 3],[5, 5, 1, 5, 0],[1, 4, 5, 3, 8],[7, 1, 1, 9, 9]],[[9, 7, 5, 3, 1],[8, 8, 6, 0, 1],[6, 9, 0, 2, 1],[9, 7, 0, 4, 0]],[[0, 7, 3, 5, 6],[2, 4, 6, 4, 3],[2, 0, 3, 7, 9],[9, 6, 4, 4, 4]]])
--------------------------------------------------
tensor([[2, 4, 1, 2, 3],[5, 5, 1, 5, 0],[1, 4, 5, 3, 8],[7, 1, 1, 9, 9]])
tensor([[2, 4, 1, 2, 3],[9, 7, 5, 3, 1],[0, 7, 3, 5, 6]])
tensor([[2, 5, 1, 7],[9, 8, 6, 9],[0, 2, 2, 9]])

6 张量形状操作¶

学习目标¶

  • 掌握reshape, transpose, permute, view, contigous, squeeze, unsqueeze等函数使用
    在我们后面搭建网络模型时,数据都是基于张量形式的表示,网络层与层之间很多都是以不同的 shape 的方式进行表现和运算,我们需要掌握对张量形状的操作,以便能够更好处理网络各层之间的数据连接。

1. reshape 函数的用法¶

reshape 函数可以在保证张量数据不变的前提下改变数据的维度,将其转换成指定的形状,在后面的神经网络学习时,会经常使用该函数来调节数据的形状,以适配不同网络层之间的数据传递。

import torch
import numpy as npdef test():data = torch.tensor([[10, 20, 30], [40, 50, 60]])# 1. 使用 shape 属性或者 size 方法都可以获得张量的形状print(data.shape, data.shape[0], data.shape[1])print(data.size(), data.size(0), data.size(1))# 2. 使用 reshape 函数修改张量形状new_data = data.reshape(1, 6)print(new_data.shape)if __name__ == '__main__':test()

程序运行结果:

torch.Size([2, 3]) 2 3
torch.Size([2, 3]) 2 3
torch.Size([1, 6])

2. transpose 和 permute 函数的使用¶

transpose 函数可以实现交换张量形状的指定维度, 例如: 一个张量的形状为 (2, 3, 4) 可以通过 transpose 函数把 3 和 4 进行交换, 将张量的形状变为 (2, 4, 3)

permute 函数可以一次交换更多的维度。

import torch
import numpy as npdef test():data = torch.tensor(np.random.randint(0, 10, [3, 4, 5]))print('data shape:', data.size())# 1. 交换1和2维度new_data = torch.transpose(data, 1, 2)print('data shape:', new_data.size())# 2. 将 data 的形状修改为 (4, 5, 3)new_data = torch.transpose(data, 0, 1)new_data = torch.transpose(new_data, 1, 2)print('new_data shape:', new_data.size())# 3. 使用 permute 函数将形状修改为 (4, 5, 3)new_data = torch.permute(data, [1, 2, 0])print('new_data shape:', new_data.size())if __name__ == '__main__':test()

程序运行结果:

data shape: torch.Size([3, 4, 5])
data shape: torch.Size([3, 5, 4])
new_data shape: torch.Size([4, 5, 3])
new_data shape: torch.Size([4, 5, 3])

3. view 和 contigous 函数的用法¶

view 函数也可以用于修改张量的形状,但是其用法比较局限,只能用于存储在整块内存中的张量。在 PyTorch 中,有些张量是由不同的数据块组成的,它们并没有存储在整块的内存中,view 函数无法对这样的张量进行变形处理,例如: 一个张量经过了 transpose 或者 permute 函数的处理之后,就无法使用 view 函数进行形状操作。

import torch
import numpy as npdef test():data = torch.tensor([[10, 20, 30], [40, 50, 60]])print('data shape:', data.size())# 1. 使用 view 函数修改形状new_data = data.view(3, 2)print('new_data shape:', new_data.shape)# 2. 判断张量是否使用整块内存print('data:', data.is_contiguous())  # True# 3. 使用 transpose 函数修改形状new_data = torch.transpose(data, 0, 1)print('new_data:', new_data.is_contiguous())  # False# new_data = new_data.view(2, 3)  # RuntimeError# 需要先使用 contiguous 函数转换为整块内存的张量,再使用 view 函数print(new_data.contiguous().is_contiguous())new_data = new_data.contiguous().view(2, 3)print('new_data shape:', new_data.shape)if __name__ == '__main__':test()

程序运行结果:

data shape: torch.Size([2, 3])
new_data shape: torch.Size([3, 2])
data: True
new_data: False
True
new_data shape: torch.Size([2, 3])

4. squeeze 和 unsqueeze 函数的用法¶

squeeze 函数用删除 shape 为 1 的维度,unsqueeze 在每个维度添加 1, 以增加数据的形状。

import torch
import numpy as npdef test():data = torch.tensor(np.random.randint(0, 10, [1, 3, 1, 5]))print('data shape:', data.size())# 1. 去掉值为1的维度new_data = data.squeeze()print('new_data shape:', new_data.size())  # torch.Size([3, 5])# 2. 去掉指定位置为1的维度,注意: 如果指定位置不是1则不删除new_data = data.squeeze(2)print('new_data shape:', new_data.size())  # torch.Size([3, 5])# 3. 在2维度增加一个维度new_data = data.unsqueeze(-1)print('new_data shape:', new_data.size())  # torch.Size([3, 1, 5, 1])if __name__ == '__main__':test()

程序运行结果:

data shape: torch.Size([1, 3, 1, 5])
new_data shape: torch.Size([3, 5])
new_data shape: torch.Size([1, 3, 5])
new_data shape: torch.Size([1, 3, 1, 5, 1])

5. 小节¶

本小节带着同学们学习了经常使用的关于张量形状的操作,我们用到的主要函数有:

  • reshape 函数可以在保证张量数据不变的前提下改变数据的维度.
  • transpose 函数可以实现交换张量形状的指定维度, permute 可以一次交换更多的维度.
  • view 函数也可以用于修改张量的形状, 但是它要求被转换的张量内存必须连续,所以一般配合 contiguous 函数使用.
  • squeeze 和 unsqueeze 函数可以用来增加或者减少维度.

7 张量运算函数¶

学习目标¶

  • 掌握张量相关运算函数

1. 常见运算函数¶

PyTorch 为每个张量封装很多实用的计算函数,例如计算均值、平方根、求和等等

import torchdef test():data = torch.randint(0, 10, [2, 3], dtype=torch.float64)print(data)print('-' * 50)# 1. 计算均值# 注意: tensor 必须为 Float 或者 Double 类型print(data.mean())print(data.mean(dim=0))  # 按列计算均值print(data.mean(dim=1))  # 按行计算均值print('-' * 50)# 2. 计算总和print(data.sum())print(data.sum(dim=0))print(data.sum(dim=1))print('-' * 50)# 3. 计算平方print(data.pow(2))print('-' * 50)# 4. 计算平方根print(data.sqrt())print('-' * 50)# 5. 指数计算, e^n 次方print(data.exp())print('-' * 50)# 6. 对数计算print(data.log())  # 以 e 为底print(data.log2())print(data.log10())if __name__ == '__main__':test()

程序运行结果:

tensor([[4., 0., 7.],[6., 3., 5.]], dtype=torch.float64)
--------------------------------------------------
tensor(4.1667, dtype=torch.float64)
tensor([5.0000, 1.5000, 6.0000], dtype=torch.float64)
tensor([3.6667, 4.6667], dtype=torch.float64)
--------------------------------------------------
tensor(25., dtype=torch.float64)
tensor([10.,  3., 12.], dtype=torch.float64)
tensor([11., 14.], dtype=torch.float64)
--------------------------------------------------
tensor([[16.,  0., 49.],[36.,  9., 25.]], dtype=torch.float64)
--------------------------------------------------
tensor([[2.0000, 0.0000, 2.6458],[2.4495, 1.7321, 2.2361]], dtype=torch.float64)
--------------------------------------------------
tensor([[5.4598e+01, 1.0000e+00, 1.0966e+03],[4.0343e+02, 2.0086e+01, 1.4841e+02]], dtype=torch.float64)
--------------------------------------------------
tensor([[1.3863,   -inf, 1.9459],[1.7918, 1.0986, 1.6094]], dtype=torch.float64)
tensor([[2.0000,   -inf, 2.8074],[2.5850, 1.5850, 2.3219]], dtype=torch.float64)
tensor([[0.6021,   -inf, 0.8451],[0.7782, 0.4771, 0.6990]], dtype=torch.float64)

8 自动微分模块¶

学习目标¶

  • 掌握梯度计算
    自动微分(Autograd)模块对张量做了进一步的封装,具有自动求导功能。自动微分模块是构成神经网络训练的必要模块,在神经网络的反向传播过程中,Autograd 模块基于正向计算的结果对当前的参数进行微分计算,从而实现网络权重参数的更新。

1. 梯度基本计算¶

我们使用 backward 方法、grad 属性来实现梯度的计算和访问.

import torch# 1. 单标量梯度的计算
# y = x**2 + 20
def test01():# 定义需要求导的张量# 张量的值类型必须是浮点类型x = torch.tensor(10, requires_grad=True, dtype=torch.float64)# 变量经过中间运算f = x ** 2 + 20# 自动微分f.backward()# 打印 x 变量的梯度# backward 函数计算的梯度值会存储在张量的 grad 变量中print(x.grad)# 2. 单向量梯度的计算
# y = x**2 + 20
def test02():# 定义需要求导张量x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)# 变量经过中间计算f1 = x ** 2 + 20# 注意:# 由于求导的结果必须是标量# 而 f 的结果是: tensor([120., 420.])# 所以, 不能直接自动微分# 需要将结果计算为标量才能进行计算f2 = f1.mean()  # f2 = 1/2 * x# 自动微分f2.backward()# 打印 x 变量的梯度print(x.grad)if __name__ == '__main__':test01()

程序运行结果:

tensor(20., dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)

2. 控制梯度计算¶

我们可以通过一些方法使得在 requires_grad=True 的张量在某些时候计算不进行梯度计算。

import torch# 1. 控制不计算梯度
def test01():x = torch.tensor(10, requires_grad=True, dtype=torch.float64)print(x.requires_grad)# 第一种方式: 对代码进行装饰with torch.no_grad():y = x ** 2print(y.requires_grad)# 第二种方式: 对函数进行装饰@torch.no_grad()def my_func(x):return x ** 2print(my_func(x).requires_grad)# 第三种方式torch.set_grad_enabled(False)y = x ** 2print(y.requires_grad)# 2. 注意: 累计梯度
def test02():# 定义需要求导张量x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)for _ in range(3):f1 = x ** 2 + 20f2 = f1.mean()# 默认张量的 grad 属性会累计历史梯度值# 所以, 需要我们每次手动清理上次的梯度# 注意: 一开始梯度不存在, 需要做判断if x.grad is not None:x.grad.data.zero_()f2.backward()print(x.grad)# 3. 梯度下降优化最优解
def test03():# y = x**2x = torch.tensor(10, requires_grad=True, dtype=torch.float64)for _ in range(5000):# 正向计算f = x ** 2# 梯度清零if x.grad is not None:x.grad.data.zero_()# 反向传播计算梯度f.backward()# 更新参数x.data = x.data - 0.001 * x.gradprint('%.10f' % x.data)if __name__ == '__main__':test01()print('--------------------')test02()print('--------------------')test03()

程序运行结果:

True
False
False
False
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)

3. 梯度计算注意¶

当对设置 requires_grad=True 的张量使用 numpy 函数进行转换时, 会出现如下报错:
Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
此时, 需要先使用 detach 函数将张量进行分离, 再使用 numpy 函数.
注意: detach 之后会产生一个新的张量, 新的张量作为叶子结点,并且该张量和原来的张量共享数据, 但是分离后的张量不需要计算梯度。

import torch# 1. detach 函数用法
def test01():x = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)# Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.# print(x.numpy())  # 错误print(x.detach().numpy())  # 正确# 2. detach 前后张量共享内存
def test02():x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)# x2 作为叶子结点x2 = x1.detach()# 两个张量的值一样: 140421811165776 140421811165776print(id(x1.data), id(x2.data))x2.data = torch.tensor([100, 200])print(x1)print(x2)# x2 不会自动计算梯度: Falseprint(x2.requires_grad)if __name__ == '__main__':test01()test02()

程序运行结果:

10. 20.]
140495634222288 140495634222288
tensor([10., 20.], dtype=torch.float64, requires_grad=True)
tensor([100, 200])
False

4. 小节¶

本小节主要讲解了 PyTorch 中非常重要的自动微分模块的使用和理解。我们对需要计算梯度的张量需要设置 requires_grad=True 属性,并且需要注意的是梯度是累计的,在每次计算梯度前需要先进行梯度清零。


10 模型的保存加载¶

学习目标¶

  • 掌握PyTorch保存模型的方法
  • 神经网络的训练有时需要几天, 几周, 甚至几个月, 为了在每次使用模型时避免高代价的重复训练, 我们就需要将模型序列化到磁盘中, 使用的时候反序列化到内存中.

1: 保存模型参数¶

import torch
import torch.nn as nn# 假设我们有一个模型
class SimpleModel(nn.Module):def __init__(self):super(SimpleModel, self).__init__()self.fc = nn.Linear(10, 1)def forward(self, x):return self.fc(x)model = SimpleModel()# 保存模型的参数
torch.save(model.state_dict(), 'model_weights.pth')

2: 保存全部模型¶

import torch
import torch.nn as nn# 假设我们有一个模型
class SimpleModel(nn.Module):def __init__(self):super(SimpleModel, self).__init__()self.fc = nn.Linear(10, 1)def forward(self, x):return self.fc(x)model = SimpleModel()# 保存全部模型
torch.save(model, 'model.pth')

3: 加载模型参数¶

# 创建一个与保存时相同结构的模型
model = SimpleModel()# 加载模型的参数
model.load_state_dict(torch.load('model_weights.pth'))
print(model)

4: 加载全部模型¶

model = torch.load('model.pth')
print(model)
  • 注意📢:
  • 模型结构: 如果你只保存了模型的参数, 那么在加载时需要确保你有与保存时相同的模型结构.
  • 设备兼容性: 如果你在一个设备上保存了模型(例如GPU), 而在另一个设备上加载(例如CPU), 你可能需要使用 map_location 参数来指定设备.
  • device = torch.device('cpu') model.load_state_dict(torch.load('model_weights.pth', map_location=device))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/946967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Xshell7免费版下载及安装(详细教程)

Xshell7免费版下载及安装(详细教程)Xshell7免费版下载及安装(详细教程) https://www.xshell.com/zh/free-for-home-school/ xhsell免费版本下载地址

APT36组织利用Linux BOSS恶意软件通过.desktop文件攻击印度政府

网络安全研究人员发现APT36组织使用伪造成PDF文件的恶意Linux桌面文件,针对印度政府系统进行网络间谍活动。该攻击通过钓鱼邮件传播,利用BOSS Linux系统的漏洞窃取数据并维持持久访问权限。APT36组织利用Linux BOSS恶…

Sqlite EF CodeFirst For WPF

Sqlite EF在WPF 开发中使用Sqlite 数据库的EF框架 1.安装必要的插件install-package System.Data.Sqliteinstall-package System.Data.Sqlite.EF6install-package Sqlite.CodeFirst2.建立数据模型 using System; using…

大模型强化学习的熵控制:CE-GPPO、EPO与AsyPPO技术方案对比详解

LLM的强化学习训练最近进展很快,SOTA模型在各种推理benchmark上的表现确实亮眼。但更值得关注的其实是另一条信息——从Rutgers到Alibaba再到HKUST,这些研究团队正在攻克的是RL领域的一个老大难:怎么控制好熵,同时…

拼多多一面

1、你们是使用redis去记录一下是否同步成功,那么如果在这里面redis写挂了怎么办 答:如果只是因为网络波动导致一瞬间没有数据的话,可以使用重试机制,如果是因为redis的集群宕机的话,可以使用redis的哨兵机制,同时…

10.20-10.25 总结

10.20-10.25 总结 10.20 杂题 最近的 CF 和 AT 的题目,写了三道题目。主要的启发是对于一些最优化的 dp 要多发掘性质或者是最后答案的形态,还有一些题目可以分块或者是看成一块一块的观察。 10.21 比赛 不常规的四道…

就是 CCPC2025 重庆站游记

。懂不懂什么叫超长前摇。 10.26 终于过审核了,非常感谢重庆大学的李佳老师!!

25秋周总结6

总结 这周只考了两次,剩下时间都是自习。然后这两次考联考和 NOIP 模拟,我考得都很炸,大概总结就是这段时间有点飘、有点浮躁,看着题感觉简单于是就觉得随便考没问题的。但是两次都存在遇到简单题但是没注意到性质…

20232313 2025-2026-1 《网络与系统攻防技术》实验三实验报告 - 20232313

1.实验内容基本实验内容如下:学会使用msf编码器,veil-evasion,自己利用shellcode编程等免杀工具或技巧 正确使用msf编码器,使用msfvenom生成如jar之类的其他文件 veil,加壳工具 使用C + shellcode编程 通过组合应…

鸭子类型,反射

什么是鸭子类型鸭子模型(Duck Typing)是编程语言类型检查中的一种设计思想,核心原则是:“如果一个东西走路像鸭子,叫起来像鸭子,那么它就是鸭子”。(是一种编程语言风格,不是一个真实存在的约束关系,而是一种普…

Verilog学习-从FPGA的角度看Uart模块

想从零移植Uboot到FPGA上,但现有的小麻雀内核栈空间是使用FPGA内部的资源,它的内存十分有限,完全无法存放Uboot代码本体,故需要添加SDRAM控制器来调用其FPGA片内的SDRAM或者外部连接的SPI NorFlash,但是改动这些东…

朝花夕拾 -- AES(1)

初识AESAES(1) 零、 前言 ​ 朝花夕拾杯中酒。从CTF开始攻击CBC模式下的加密漏洞,再到第四学期的《密码学基础》课程,时至今日,《密码工程》课程的需要以及自己对于对称密码的兴趣驱使,下定决心写下这篇笔记…

【学习笔记】构造

本文记载了一些关于构造题的学习笔记。

特殊的背包问题

特殊的背包问题 设 \(n\) 为物品个数,\(m\) 为背包容量,\(k\) 为所有物品中重量最大值。 1. 最优化问题 当 \(m\) 较大时可以应用下面的解法。先贪心,然后扔掉一些,再补上一些。 1.1 完全背包 1 先找出性价比最高的…

2025 年 10 月承烧板厂家最新推荐,实力品牌深度解析采购无忧之选!

2025 年 10 月承烧板厂家最新推荐,实力品牌深度解析采购无忧之选!引言承烧板采购中,品牌实力是品质的核心保障,也是规避采购风险的关键。据中国耐火材料行业协会 2025 年 10 月发布的《承烧板采购风险报告》显示,…

【URP】Unity[视差贴图]模拟[冰面裂缝]实践

Unity URP 冰面裂缝视差效果实现方案 冰面裂缝效果优化的URP Shader实现。该方案通过‌视差遮挡贴图(POM)‌技术增强深度表现,结合‌高度图动态控制‌实现可调节的冰缝裂痕效果。 核心特【从UnityURP开始探索游戏渲染…

2025年热门的用地预审技术服务供应商、市面上用地预审技术服务公司、行业内用地预审技术服务品牌、市场用地预审技术服务方案、2025年用地预审技术服务单位深度解析

摘要 用地预审技术服务行业随着国家土地管理政策的收紧和基础设施建设加速而蓬勃发展,2025年预计市场规模将增长15%以上,驱动因素包括城镇化进程和生态保护需求。本排名基于市场调研、用户反馈和专家评估,为用地预审…

2025年热门的用地预审技术服务供应商、市面上用地预审技术服务公司、行业内用地预审技术服务品牌、市场用地预审技术服务方案、2025年用地预审技术服务单位综合排名与分析

文章摘要 用地预审技术服务行业在国土空间规划优化和基础设施建设加速的背景下快速发展,2025年预计市场规模将增长15%以上。本文基于行业数据和用户反馈,深度评测热门供应商,并提供权威排名榜单,其中陕西丰耘甲信息…

2025年市面上母线槽品牌、市场母线槽公司、国内母线槽产品、口碑好的母线槽实力厂家、母线槽品牌排行深度评测

文章摘要 母线槽作为现代电力传输的核心设备,行业正加速向智能化、数字化转型,2025年预计市场规模将突破百亿元。本文基于权威数据分析和用户反馈,综合评估市面上主流母线槽品牌,提供客观排名和选择指南。表单数据…

2025年母线槽品牌排行、口碑好的母线槽品牌、市面上母线槽品牌、母线槽公司推荐、市场母线槽供应厂家深度解析

文章摘要 母线槽行业在2025年迎来数字化与智能化转型,随着建筑、电力和数据中心需求的增长,品牌竞争加剧。本文基于市场调研和用户口碑,为您呈现一份权威的母线槽品牌排行榜单,涵盖市面上热门品牌的核心优势与服务…