PyTorch使用教程-深度学习框架
PyTorch使用教程-深度学习框架
1. PyTorch简介
1.1-什么是PyTorch
PyTorch是一个广泛使用的开源机器学习框架,特别适合深度学习的应用。它以其动态计算图而闻名,允许在运行时修改模型,使得实验和调试更加灵活。PyTorch提供了强大的GPU加速功能,支持自动微分,简化了梯度计算和模型训练。此外,PyTorch拥有直观的API,与Python深度集成,使得它易于学习和使用。它还拥有一个庞大的社区和丰富的生态系统,包括预训练模型和专用库,适用于计算机视觉、自然语言处理等多种任务。PyTorch的灵活性和强大的功能使其成为研究人员和开发者的首选工具之一。
1.2-为什么要使用PyTorch
- 动态计算图:PyTorch的动态计算图使得模型构建更加灵活,可以在运行时更改模型结构,适合研究和原型设计。
- 易用性和灵活性:PyTorch的API设计直观,与Python深度集成,使得学习和使用变得简单愉快。
- 易于调试:由于PyTorch的动态性和Python性质,使用标准Python调试工具可以方便地调试程序。
- 强大的社区支持:PyTorch拥有一个活跃的社区,用户可以在官方论坛、GitHub、Stack Overflow等平台上找到大量资源和帮助。
- 广泛的预训练模型:PyTorch提供了大量的预训练模型,如ResNet、VGG、Inception等,这些模型可以帮助用户快速开始新项目。
- 高效的GPU利用:PyTorch可以高效地利用NVIDIA的CUDA库进行GPU计算,并支持分布式计算,允许在多个GPU或服务器上训练模型。
1.3-PyTorch核心组件
- 张量(Tensor)
在PyTorch中,张量是数据的基本表示形式,可以有任意数量的维度,这使得它们非常灵活。PyTorch的张量数据类型,类似于多维数组,用于存储和操作模型的输入和输出以及模型的参数。张量与NumPy的 ndarray 类似,只是张量可以在 GPU 上运行以加速计算。在 PyTorch 中,张量以 “类” 的形式封装起来,对张量的一些运算、处理的方法被封装在类中
- 标量(0阶张量):标量是一个单一的数值
- 向量(1阶张量):向量是一维数组,可以表示为一列或一行数值
- 矩阵(2阶张量):矩阵是一个二维数组,包含行和列
- 高阶张量:高阶张量是更高维度的数组。
- 图形
图形是由已连接节点(称为顶点)和边缘组成的数据结构。每个现代深度学习框架都基于图形的概念,其中神经网络表示为计算的图形结构。PyTorch 在由函数对象组成的有向无环图 (DAG) 中保存张量和执行操作的记录。
1.4-PyTorch安装
# 直接安装
pip install torch# 使用代理镜像源
pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple# 指定版本安装
pip install torch==2.3.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
建议python使用版本不要太老,否则安装torch相对早些版本
2. PyTorch使用
创建一个test01.py
,进行代码的调试使用
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Project :hello-algo-main
# @File :test01.py
# @Time :2024/11/11 23:15import torch
import numpy as np
2.1. 张量的创建
2.1.1-torch.tensor()
根据指定数据创建张量
- 标量
# 创建张量 - 标量
data1 = torch.tensor(666)
print(data1)
print(type(data1))
print(data1.shape)"""
输出:
tensor(666)
<class 'torch.Tensor'>
torch.Size([])
"""
- 使用
torch.tensor(666)
创建了一个标量张量data1
,其值为666。- 打印出
data1
的内容、类型和形状。类型为torch.Tensor 类
,形状为torch.Size([])
,表示这是一个0维张量(标量)。
- numpy 数组
# numpy 数组
data2 = torch.tensor(np.random.randn(2, 4))
print(data2)
print(type(data2))
print(data2.shape)
"""
输出:
tensor([[-0.1815, 0.4556, -0.6612, -0.7966],[-0.9630, 0.4847, 0.2520, -0.2234]], dtype=torch.float64)
<class 'torch.Tensor'>
torch.Size([2, 4])
"""
- 使用
np.random.randn(2, 4)
生成一个2x4的两行四列NumPy数组,并用torch.tensor()
将其转换为PyTorch张量data2
。- 打印出
data2
的内容、类型和形状。类型为torch.Tensor 类
,形状为torch.Size([2, 4])
,表示这是一个2维张量(矩阵)。
- 列表
# 列表
data3 = [[1, 2, 3], [4, 5, 6]]
data3_t = torch.tensor(data3)
print(data3_t)
print(type(data3_t))
print(data3_t.shape)
"""
输出:
tensor([[1, 2, 3],[4, 5, 6]])
<class 'torch.Tensor'>
torch.Size([2, 3])
"""
- 定义一个Python列表
data3
,并使用torch.tensor()
将其转换为PyTorch张量data3_t
。- 打印出
data3_t
的内容、类型和形状。类型为torch.Tensor 类
,形状为torch.Size([2, 3])
,表示这是一个2维张量。
2.1.2-torch.Tensor()
根据指定形状创建张量,也可以用来创建指定数据的张量
# 创建2行3列的张量
data1 = torch.Tensor(2, 3)
print(data1)
"""
输出:
tensor([[0., 0., 0.],[0., 0., 0.]])
"""data2 = torch.Tensor([666])
print(data2)
"""
输出:
tensor([666.])
"""data3 = torch.Tensor([111, 666])
print(data3)
"""
输出:
tensor([111., 666.])
"""
2.1.3-torch.tensor()和torch.Tensor()
在PyTorch中,torch.tensor()
和torch.Tensor()
实际上是指同一件事,通常不会产生混淆。torch.tensor()
是创建一个新的PyTorch张量(Tensor)的函数,而torch.Tensor
是张量对象的类。在实际使用中,torch.tensor()
是用来创建张量的函数,而torch.Tensor
通常用在类型注释或者继承中。
torch.tensor()
:- 这是一个函数,用于创建一个新的PyTorch张量。它接受各种类型的输入数据(如列表、NumPy数组、标量等),并将它们转换成PyTorch张量。
- 例如:
torch.tensor([1, 2, 3])
会创建一个包含元素1, 2, 3的一维张量。
torch.Tensor
:- 这是一个类,代表了PyTorch中的张量数据类型。
- 在大多数情况下,你不会直接使用
torch.Tensor()
来创建张量,因为这样做需要传递一个数据对象,而且通常使用torch.tensor()
更为方便。 - 但是,
torch.Tensor
可以在类型注释中使用,以表明一个函数的参数或返回值是PyTorch张量类型。 - 另外,如果你想要创建一个特定类型的张量(例如,指定了数据类型或设备的张量),你可能会直接使用
torch.Tensor
的构造函数。
2.1.4-创建线性和随机张量
torch.arange 和 torch.linspace 创建线性张量
torch.randn 创建随机张量
data1 = torch.arange(0, 8, 2)
print(data1)
"""
tensor([0, 2, 4, 6])
"""data2 = torch.linspace(0, 10, 5)
print(data2)
"""
tensor([ 0.0000, 2.5000, 5.0000, 7.5000, 10.0000])
"""data3 = torch.randn(3, 5)
print(data3)
"""
tensor([[ 1.1598, -1.3089, -0.4497, 0.3560, -1.1106],[ 0.8603, 0.3001, -0.7244, 0.9294, -0.1535],[ 0.6036, -1.1146, -0.7932, -1.2622, -0.9836]])
"""
data1 = torch.arange(0, 8, 2)
:使用torch.arange()
函数创建一个从0开始,到8结束(不包括8),步长为2的一维张量。输出结果为:
tensor([0, 2, 4, 6])
,这是一个包含0, 2, 4, 6的张量。
data2 = torch.linspace(0, 10, 5)
:使用torch.linspace()
函数创建一个在0到10之间均匀分布的5个元素的一维张量。输出结果为:
tensor([0.0000, 2.5000, 5.0000, 7.5000, 10.0000])
,这是一个包含0, 2.5, 5, 7.5, 10的张量。
data3 = torch.randn(3, 5)
:使用torch.randn()
函数创建一个3行5列的二维张量,其中的元素是从标准正态分布(均值为0,方差为1)中随机采样的。输出结果为一个3x5的矩阵,其中的元素是随机生成的,每次运行代码时都会不同。
2.1.5-创建0&1&指定值张量
torch.ones 创建全1张量
torch.zeros 创建全0张量
torch.full 创建全为指定值张量
这些函数提供了一种快速创建具有特定值的张量的方法,这些张量可以用于初始化、占位、填充、算法实现等多种场景。它们是深度学习和科学计算中常用的工具,因为它们可以简化代码并提高效率。
# torch.zeros() 创建全0张量
data1 = torch.zeros(2, 4)
print(data1)
"""
tensor([[0., 0., 0., 0.],[0., 0., 0., 0.]])
"""# torch.ones()创建全1张量
data2 = torch.ones(2, 4)
print(data2)
"""
tensor([[1., 1., 1., 1.],[1., 1., 1., 1.]])
"""# 创建指定值张量
data3 = torch.full([2, 4], 666)
print(data3)
"""
tensor([[666, 666, 666, 666],[666, 666, 666, 666]])
"""
2.1.6-张量元素类型转换
data3 = torch.full([2, 4], 666)
print(data3.dtype)
"""
torch.int64
"""
data4 = data3.type(torch.float64)
print(data4.dtype)
"""
torch.float64
"""
data5 = data3.type(torch.int)
print(data5.dtype)
"""
torch.int32
"""
2.2. 张量的类型转换
2.2.1-张量转换为NumPy数组
data1 = torch.tensor([1, 2, 3])
print(data1) # tensor([1, 2, 3])data_np = data1.numpy()
print(data_np) # [1 2 3]print(type(data1)) # <class 'torch.Tensor'>
print(type(data_np)) # <class 'numpy.ndarray'>
2.2.2-NumPy数组转换为张量
data_np = np.array([1, 2, 3, 4])
print(data_np) # [1 2 3 4]data_tensor = torch.from_numpy(data_np)
print(data_tensor) # tensor([1, 2, 3, 4], dtype=torch.int32)print(type(data_np)) # <class 'numpy.ndarray'>
print(type(data_tensor)) # <class 'torch.Tensor'>data_tensor2 = torch.tensor(data_np)
print(data_tensor2) # tensor([1, 2, 3, 4], dtype=torch.int32)
print(type(data_tensor2)) # <class 'torch.Tensor'>
2.2.3-标量张量和数字转换
data = torch.tensor([666, ])
print(data.item()) # 666
data2 = torch.tensor(666)
print(data2.item()) # 666
3.张量的数值运算
3.1-张量基本运算
-
add()
+ -
sub()
- -
mul()
* -
div()
/ -
neg()
正负数取反
函数不影响原始数据值
data = torch.randint(0, 10, [2, 4])
print(data)
"""
tensor([[9, 0, 3, 0],[5, 7, 2, 4]])
"""
print(data.add(10))
"""
tensor([[19, 10, 13, 10],[15, 17, 12, 14]])
"""print(data.sub(10))
"""
tensor([[ -1, -10, -7, -10],[ -5, -3, -8, -6]])
"""print(data.mul(10))
"""
tensor([[90, 0, 30, 0],[50, 70, 20, 40]])
"""print(data.div(10))
"""
tensor([[0.9000, 0.0000, 0.3000, 0.0000],[0.5000, 0.7000, 0.2000, 0.4000]])
"""print(data.neg())
"""
tensor([[-9, 0, -3, 0],[-5, -7, -2, -4]])"""
-
加入下划线后将会修改原数据
-
add_()
+ -
sub_()
- -
mul_()
* -
div_()
/ -
neg_()
正负数取反
-
data = torch.randint(0, 10, [2, 4])
print(data)
"""
tensor([[9, 4, 4, 3],[0, 4, 6, 8]])
"""print(data.add_(10))
"""
tensor([[19, 14, 14, 13],[10, 14, 16, 18]])
"""print(data)
"""
tensor([[19, 14, 14, 13],[10, 14, 16, 18]])
"""
3.2-张量乘法运算
- 点乘运算
点乘指(Hadamard)的是两个同维数组对应位置的元素相乘,使用mul 和运算符 * 实现
data1 = torch.tensor([[1, 2], [3, 4]])
data2 = torch.tensor([[2, 2], [3, 3]])data_mul = torch.mul(data1, data2)
print(data_mul)
"""
tensor([[ 2, 4],[ 9, 12]])
"""data_cheng = data1 * data2
print(data_cheng)
"""
tensor([[ 2, 4],[ 9, 12]])
"""
- 乘法运算
- 数组乘法运算要求第一个数组 shape: (n, m),第二个数组 shape: (m, p), 两个数组乘法运算 shape 为: (n, p)。
- 运算符 @ 用于进行两个矩阵的乘积运算
- torch.matmul 中输入的 shape 不同的张量, 对应的维度必须符合数组乘法的运算规则
data1 = torch.tensor([[1, 2], [3, 4], [6, 7], [7, 8]])
data2 = torch.tensor([[2, 5], [3, 6]])data_new1 = data1 @ data2
print(data_new1)
"""
tensor([[ 8, 17],[18, 39],[33, 72],[38, 83]])
"""data_new2 = torch.matmul(data1, data2)
print(data_new2)
"""
tensor([[ 8, 17],[18, 39],[33, 72],[38, 83]])
"""
在这段代码中,
data_new1 = data1 @ data2
表示对两个张量data1
和data2
进行矩阵乘法(也称为点乘或内积)。矩阵乘法的计算方式如下:给定两个矩阵 A 和 B,其中 A 的维度为 m×n,B 的维度为 n×p,它们的乘积 C 的维度将是 m×p,C 中的每个元素 c_ij 是通过取 A 的第 i 行与 B 的第 j 列的点积得到的。
具体来说,对于
data1
和data2
:
data1
是一个 4x2 的矩阵:[[1, 2],[3, 4],[6, 7],[7, 8]]
data2
是一个 2x2 的矩阵:[[2, 5],[3, 6]]
计算结果
data_new1
的每个元素是通过以下方式计算的:
第一行第一列的元素:
data1
的第一行[1, 2]
与data2
的第一列[2, 3]
的点积:
( (1 × 2) + (2 × 3) = 2 + 6 = 8 )第一行第二列的元素:
data1
的第一行[1, 2]
与data2
的第二列[5, 6]
的点积:
( (1 × 5) + (2× 6) = 5 + 12 = 17 )第二行第一列的元素:
data1
的第二行[3, 4]
与data2
的第一列[2, 3]
的点积:
( (3 × 2) + (4 × 3) = 6 + 12 = 18 )第二行第二列的元素:
data1
的第二行[3, 4]
与data2
的第二列[5, 6]
的点积:
( (3 ×5) + (4 × 6) = 15 + 24 = 39 )以此类推,计算出
data_new1
的所有元素。最终得到的
data_new1
是一个 4x2 的矩阵:[[ 8, 17], [18, 39], [33, 72], [38, 83]]
这就是
data_new1
的计算过程。
3.3-张量的运算函数
-
均值
-
平方根
-
求和
-
指数计算
-
对数计算等等
data = torch.randint(0, 10, [1, 3], dtype=torch.float64)
print(data) # tensor([[4., 4., 3.]], dtype=torch.float64)# 平均
print(data.mean()) # tensor(3.6667, dtype=torch.float64)# 求和
print(data.sum()) # tensor(11., dtype=torch.float64)# 平方数
print(torch.pow(data, 2)) # tensor([[16., 16., 9.]], dtype=torch.float64)# n次方,例如3次方
print(torch.pow(data, 3)) # tensor([[64., 64., 27.]], dtype=torch.float64)# 求平方根
print(data.sqrt()) # tensor([[2.0000, 2.0000, 1.7321]], dtype=torch.float64)# 指数计算(e的n次方)
print(data.exp()) # tensor([[54.5982, 54.5982, 20.0855]], dtype=torch.float64)# 对数计算
print(data.log()) # tensor([[1.3863, 1.3863, 1.0986]], dtype=torch.float64)
print(data.log10()) # tensor([[0.6021, 0.6021, 0.4771]], dtype=torch.float64)
4.张量索引介绍
4.1-简单索引、列表索引、范围索引
-
基本索引
-
行索引: 使用行号进行索引,例如
data[i]
会返回第i
行的元素。 -
列索引: 使用列号和冒号进行索引,例如
data[:, j]
会返回第j
列的所有元素。
-
-
组合索引
-
行和列索引: 可以同时指定行和列进行索引,例如
data[i, j]
会返回位于第i
行第j
列的单个元素。 -
多行多列索引: 使用逗号分隔的索引可以同时索引多行和多列,例如
data[i:j, k:l]
会返回从第i
行到第j-1
行,第k
列到第l-1
列的子张量。
-
-
列表索引
- 使用列表索引: 可以传递一个列表来索引多个元素,例如
data[[a, b], [c, d]]
会返回位于(a,c)
和(b,d)
位置的元素。
- 使用列表索引: 可以传递一个列表来索引多个元素,例如
-
布尔索引
- 使用布尔数组索引: 可以传递一个布尔数组来索引满足条件的元素,例如
data[condition]
会返回所有condition
为True
的元素。
- 使用布尔数组索引: 可以传递一个布尔数组来索引满足条件的元素,例如
-
范围索引
- 使用冒号(:): 可以指定一个范围来索引,例如
data[:n]
会返回前n
个元素。
- 使用冒号(:): 可以指定一个范围来索引,例如
-
嵌套索引
- 使用嵌套列表索引: 可以传递一个嵌套列表来索引多个元素,例如
data[[a, b], [c, d]]
与列表索引类似,但使用嵌套列表。
- 使用嵌套列表索引: 可以传递一个嵌套列表来索引多个元素,例如
-
None索引
- 使用None: 可以传递
None
来保持某个维度不变,例如data[None, :]
会将张量扩展为一个新的维度。
- 使用None: 可以传递
-
索引赋值
- 索引后赋值: 可以在索引后直接赋值,例如
data[i, j] = value
会将位于第i
行第j
列的元素设置为value
。
- 索引后赋值: 可以在索引后直接赋值,例如
# 使用torch.randint函数创建一个形状为4x5的四行五列张量,其中的元素是从0到9(包含0,不包含10)的随机整数。
data = torch.randint(0, 10, [4, 5])
# 简单取值
print(data)
"""
tensor([[7, 4, 6, 6, 1],[6, 8, 8, 0, 9],[7, 5, 0, 9, 7],[6, 2, 2, 1, 1]])
"""print(data[0]) # tensor([7, 4, 6, 6, 1])
print(data[0, :]) # tensor([7, 4, 6, 6, 1])
# data[0]和data[0, :]都表示取出张量的第一行。data[0]是使用行索引,而data[0, :]是使用行索引和列索引(冒号表示取整行),所以一般都使用data[0]print(data[:, 0]) # tensor([7, 6, 7, 6])
# data[:, 0]表示取出张量的第一列。冒号表示取整列,0表示列的索引# 列表索引
print(data[[0, 1], [1, 2]]) # tensor([4, 8])
# data[[0, 1], [1, 2]]表示取出张量中位置为(0,1)和(1,2)的元素,即取出第一行的第二个元素和第二行的第三个元素。
print(data[:, [0, 1]])
# data[:, [0, 1]]表示取出张量的前两列。
"""
tensor([[7, 4],[6, 8],[7, 5],[6, 2]])
"""print(data[[[0], [1]], [1, 2]])
# data[[[0], [1]], [1, 2]]表示取出张量中位置为(0,1)和(1,2)的元素,这与data[[0, 1], [1, 2]]相同,但是使用了嵌套列表。
"""
tensor([[4, 6],[8, 8]])
"""# 范围索引
print(data[:3, :2])
# data[:3, :2]表示取出张量的前3行和前2列。
"""
tensor([[7, 4],[6, 8],[7, 5]])
"""print(data[2:, :2])
# data[2:, :2]表示取出张量的第3行到最后(因为索引从0开始,2表示第三行)以及这两行的前两列。
"""
tensor([[7, 5],[6, 2]])
"""
4.2-多维索引
# 创建一个形状为3x4x5的三维张量
data = torch.randint(0, 10, [3, 4, 5])
print(data)
# 打印整个三维张量,可以看到它包含三个2D矩阵(每个矩阵的形状为4x5)
"""
tensor([[[8, 1, 2, 7, 1],[1, 2, 2, 5, 6],[9, 5, 8, 9, 2],[8, 8, 8, 8, 0]],[[2, 9, 8, 3, 2],[2, 8, 0, 5, 7],[9, 0, 8, 0, 0],[6, 0, 0, 8, 1]],[[1, 8, 9, 1, 5],[5, 0, 6, 9, 8],[8, 8, 1, 3, 2],[3, 2, 3, 1, 4]]])
"""print(data[0, :, :])
# data[0, :, :]表示取出张量的第一个“层”(或者说第一个3D切片),即第一组4x5的矩阵。这里的:表示选取该维度的所有元素。
"""
tensor([[8, 1, 2, 7, 1],[1, 2, 2, 5, 6],[9, 5, 8, 9, 2],[8, 8, 8, 8, 0]])
"""print(data[:, 0, :])
# data[:, 0, :]表示取出张量中每个“层”的第一个“行”(或者说第一个4D切片),即取出所有层的第一行。这里的0表示第一个元素的索引。
"""
tensor([[8, 1, 2, 7, 1],[2, 9, 8, 3, 2],[1, 8, 9, 1, 5]])
"""print(data[:, :, 0])
# data[:, :, 0]表示取出张量中每个“层”的第一个“元素”(或者说第一个3D切片),即取出所有层的第一列。这里的0表示第一个元素的索引。
"""
tensor([[8, 1, 9, 8],[2, 2, 9, 6],[1, 5, 8, 3]])
"""
在多维数据处理中,这样的索引操作非常有用,它们允许你快速访问和操作数据的特定部分。例如,在处理图像数据时,你可能需要访问特定通道的所有像素,或者在处理时间序列数据时,你可能需要访问特定时间点的所有特征。这些操作使得这些任务变得简单而高效。
5.张量形状操作
5.1-reshape()函数-重塑形状
reshape()
函数:
reshape()
函数用于改变张量的形状,而不改变其数据。如果新形状与原始张量不兼容(即元素总数不同),则会抛出错误。- 例如:
x = torch.randn(2, 3)
创建一个2x3的张量,x.reshape(3, 2)
将其重塑为3x2的张量。
data = torch.tensor([[1, 2, 3], [5, 6, 7]])
print(data.shape) # torch.Size([2, 3])data_shape1 = data.reshape(1, 6)
print(data_shape1) # tensor([[1, 2, 3, 5, 6, 7]])
print(data_shape1.shape) # torch.Size([1, 6])
data_shape2 = data.reshape(6, 1)
print(data_shape2)
"""
tensor([[1],[2],[3],[5],[6],[7]])
"""
print(data_shape2.shape) # torch.Size([6, 1])
5.2-squeeze()和unsqueeze()函数-降维升维
squeeze()
函数:
squeeze()
函数用于去除张量中所有长度为1的维度。如果指定了维度,则只去除指定的维度中长度为1的维度。- 例如:
x = torch.randn(2, 1, 3)
,x.squeeze()
将其变为torch.randn(2, 3)
,因为去除了长度为1的第二维。
unsqueeze()
函数:
unsqueeze()
函数用于在指定位置添加一个长度为1的新维度。这对于增加张量的维度数量很有用,尤其是在需要满足某些操作的维度要求时。- 例如:
x = torch.randn(2, 3)
,x.unsqueeze(1)
将其变为torch.randn(2, 1, 3)
,在第二维添加了一个长度为1的新维度。
data = torch.tensor([1, 2, 3, 4, 5])
print(data.shape)print(data.unsqueeze(1).shape)
print(data.unsqueeze(1).squeeze().shape)
data
是一个一维张量,所以它的形状(shape)是torch.Size([5])
,表示这个张量有5个元素。
data.unsqueeze(1)
在索引为1的位置(即在第一个维度的后面)添加了一个长度为1的新维度。因为原始张量是一维的,所以这个操作将其变为一个二维张量,形状变为torch.Size([5, 1])
。
data.unsqueeze(1)
将张量变为torch.Size([5, 1])
。然后,squeeze()
函数移除了所有长度为1的维度。由于这个张量只有一个长度为1的维度,squeeze()
将其移除,张量恢复到原始的一维形状,即torch.Size([5])
。
5.3-transpose()和permute()函数
transpose()
函数:
transpose()
函数用于交换张量的两个维度。它接受两个参数,分别是要交换的维度的索引。- 例如:
x = torch.randn(2, 3)
,x.transpose(0, 1)
将其变为torch.randn(3, 2)
,即交换了第一维和第二维。
permute()
函数:
permute()
函数用于重新排列张量的维度。它接受一系列维度索引作为参数,并按照这些索引重新排列张量的维度。- 例如:
x = torch.randn(2, 3, 4)
,x.permute(1, 2, 0)
将其变为torch.randn(3, 4, 2)
,即重新排列了维度的顺序。
# 创建一个形状为(2, 3, 4)的三维张量
data = torch.randn(2, 3, 4)# 这个函数交换张量的第0维和第1维。在形状上,这意味着交换第一个数字和第二个数字:
transposed_data = torch.transpose(data, 0, 1)
print(transposed_data.shape) # 输出: torch.Size([3, 2, 4])# 我们对data应用了torch.transpose(data, 0, 1),得到形状为(3, 2, 4)的张量。然后,我们再次应用torch.transpose,这次交换第1维和第2维:
transposed_data_again = torch.transpose(transposed_data, 1, 2)
print(transposed_data_again.shape) # 输出: torch.Size([3, 4, 2])# 这个函数重新排列张量的维度,按照给定的索引顺序。索引[1, 2, 0]意味着我们取第1维作为新的第0维,第2维作为新的第1维,第0维作为新的第2维:
permuted_data = torch.permute(data, [1, 2, 0])
print(permuted_data.shape) # 输出: torch.Size([3, 4, 2])# 这与torch.permute(data, [1, 2, 0])相同,但是使用张量对象自身的permute方法
permuted_data_self = data.permute([1, 2, 0])
print(permuted_data_self.shape) # 输出: torch.Size([3, 4, 2])
5.4-view()和contiguous()函数
view()
函数:
view()
函数用于改变张量的形状,类似于reshape()
,但它要求张量在内存中是连续的。如果不连续,需要先调用contiguous()
方法。- 例如:
x = torch.randn(2, 3)
,x.view(3, 2)
将其变为3x2的张量。
contiguous()
函数:
contiguous()
函数用于确保张量在内存中是连续的。有些操作可能会使张量在内存中不连续,这时候如果需要使用view()
,就必须先调用contiguous()
。- 例如:
x = torch.randn(2, 3).transpose(0, 1)
后,x
在内存中不连续,x.contiguous()
会返回一个新的连续张量。
data = torch.tensor([[10, 20, 30], [40, 50, 60]])
print(data)
"""
tensor([[10, 20, 30],[40, 50, 60]])
"""
print(data.shape)
# torch.Size([2, 3])print(data.is_contiguous())
# Trueprint(data.view(3, 2))
"""
tensor([[10, 20],[30, 40],[50, 60]])
"""
6.张量的拼接操作
- torch.cat()
将两个张量根据指定的维度拼接起来,不改变维度数
data1 = torch.randint(0, 10, [1, 2, 3])
data2 = torch.randint(0, 10, [1, 2, 3])
print(data1)
"""
tensor([[[4, 1, 8],[2, 8, 1]]])
"""
print(data2)
"""
tensor([[[0, 3, 1],[4, 2, 2]]])
"""
# 按0维度拼接
data_0 = torch.cat([data1, data2], dim=0)
print(data_0)
"""
tensor([[[4, 1, 8],[2, 8, 1]],[[0, 3, 1],[4, 2, 2]]])
"""# 按1维度拼接
data_1 = torch.cat([data1, data2], dim=1)
print(data_1)
"""
tensor([[[4, 1, 8],[2, 8, 1],[0, 3, 1],[4, 2, 2]]])
"""# 按2维度拼接
data_2 = torch.cat([data1, data2], dim=2)
print(data_2)
"""
tensor([[[4, 1, 8, 0, 3, 1],[2, 8, 1, 4, 2, 2]]])
"""
7.自动微分模块
PyTorch的一个核心特性是自动微分(Automatic Differentiation),它允许我们自动计算梯度,这对于训练深度学习模型至关重要。
- 张量(Tensor):PyTorch中的基本数据结构,可以看作是一个多维数组。
- 梯度(Gradient):在数学中,梯度是一个向量,指向函数增长最快的方向。在深度学习中,梯度用于更新模型参数。
- 反向传播(Backpropagation):一种通过计算梯度来更新网络权重的技术。
- 计算图(Computation Graph):一个有向图,其中的节点表示操作,边表示数据(张量)流动的方向。
微分逻辑:
# 创建一个张量,并设置requires_grad=True来追踪其梯度
x = torch.tensor(2.0, requires_grad=True)# 执行一些操作
y = x * x
z = y * y# 计算z关于x的梯度
z.backward()# 输出x的梯度
print(x.grad) # tensor(32.) 梯度32
使用案例帮助理解功能
import torch
import torch.nn as nn
import torch.optim as optim# 定义一个简单的线性模型
model = nn.Linear(1, 1)# 定义损失函数
loss_fn = nn.MSELoss()# 定义优化器
optimizer = optim.SGD(model.parameters(), lr=0.01)# 一些模拟数据
x = torch.tensor([[1.0], [2.0], [3.0]], dtype=torch.float32)
y = torch.tensor([[2.0], [4.0], [6.0]], dtype=torch.float32)# 训练模型
for epoch in range(100):# 前向传播pred = model(x)loss = loss_fn(pred, y)# 反向传播和优化optimizer.zero_grad() # 清零梯度loss.backward() # 反向传播optimizer.step() # 更新参数if (epoch + 1) % 10 == 0:print(f'Epoch [{epoch + 1}/100], Loss: {loss.item():.4f}')"""
Epoch [10/100], Loss: 2.0538
Epoch [20/100], Loss: 0.4096
Epoch [30/100], Loss: 0.2430
Epoch [40/100], Loss: 0.2175
Epoch [50/100], Loss: 0.2060
Epoch [60/100], Loss: 0.1962
Epoch [70/100], Loss: 0.1869
Epoch [80/100], Loss: 0.1781
Epoch [90/100], Loss: 0.1698
Epoch [100/100], Loss: 0.1618
"""
定义一个简单的线性模型
model
,一个损失函数loss_fn
,以及一个优化器optimizer
。然后,我们使用模拟数据x
和y
来训练模型。在每个epoch中,我们首先进行前向传播,计算损失,然后进行反向传播和参数更新。
8.pytorch示例代码理解
8.1-线性回归
需要自行安装涉及的numpy、matplotlib模块
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Project :hello-algo-main
# @File :xianxinghuigui.py
# @Time :2024-11-14 18:29
# @Author :wangting_666import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt# 设置随机种子,保证结果可复现
torch.manual_seed(0)
np.random.seed(0)# 生成线性回归的数据
x = torch.linspace(-1, 1, 100).reshape(-1, 1) # 生成从 -1 到 1 的 100 个点
y = 3 * x + 2 + torch.randn(x.size(0), 1) * 0.3 # 真实的线性关系加上一些噪声# 定义线性回归模型
class LinearRegressionModel(nn.Module):def __init__(self):super(LinearRegressionModel, self).__init__()self.linear = nn.Linear(1, 1) # 1 输入特征,1 输出特征def forward(self, x):return self.linear(x)# 实例化模型、定义损失函数和优化器
model = LinearRegressionModel()
criterion = nn.MSELoss() # 均方误差损失
optimizer = optim.SGD(model.parameters(), lr=0.01) # 使用SGD优化器# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):model.train()# 前向传播outputs = model(x)loss = criterion(outputs, y) # 计算损失# 反向传播和优化optimizer.zero_grad() # 清空梯度loss.backward() # 计算梯度optimizer.step() # 更新参数# 每 100 次输出一次损失if (epoch + 1) % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')# 评估模型
with torch.no_grad():model.eval() # 切换到评估模式predicted = model(x)# 绘制数据和拟合的直线plt.scatter(x.numpy(), y.numpy(), label='Actual Data')plt.plot(x.numpy(), predicted.numpy(), color='red', label='Fitted Line')plt.xlabel('x')plt.ylabel('y')plt.title('线性回归结果图_wangting666')plt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = Falseplt.legend()plt.show()
控制台输出:
Epoch [100/1000], Loss: 1.0944
Epoch [200/1000], Loss: 0.3330
Epoch [300/1000], Loss: 0.1551
Epoch [400/1000], Loss: 0.1099
Epoch [500/1000], Loss: 0.0984
Epoch [600/1000], Loss: 0.0955
Epoch [700/1000], Loss: 0.0947
Epoch [800/1000], Loss: 0.0945
Epoch [900/1000], Loss: 0.0945
Epoch [1000/1000], Loss: 0.0945
绘图结果:
8.2-使用 GPU 加速训练
PyTorch 支持将张量和模型移动到 GPU(如果有可用的 GPU)。通过 to(device)
可以将数据或模型转移到指定的设备
import torch
import torch.nn as nn# 检查是否有 GPU 可用
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')# 定义一个简单的神经网络
class SimpleNN(nn.Module):def __init__(self):super(SimpleNN, self).__init__()self.fc1 = nn.Linear(2, 4)self.fc2 = nn.Linear(4, 1)def forward(self, x):x = torch.relu(self.fc1(x))x = self.fc2(x)return x# 初始化模型
model = SimpleNN().to(device)# 创建输入数据并将其也转移到 GPU
input_data = torch.tensor([[1.0, 2.0]]).to(device)# 进行前向传播
output = model(input_data)
print("模型输出:\n", output)
输出:
模型输出:tensor([[0.2424]], grad_fn=<AddmmBackward0>)
通过
device = torch.device('cuda')
检查是否有可用的 GPU,并通过.to(device)
将模型和数据迁移到 GPU 上。这样可以加速计算。
8.3-图片识别
官方素材 :https://download.pytorch.org/tutorial/faces.zip
数据存于“data / faces /”的目录中
这个数据集实际上是imagenet数据集标注为face的图片当中在 dlib 面部检测 (dlib’s pose estimation) 表现良好的图片。我们要处理的是一个面部姿态的数据集
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Project :hello-algo-main
# @File :test03.py
# @Time :2024-11-14 19:03
# @Author :wangting_666from __future__ import print_function, division
import os
import torch
import pandas as pd
from skimage import io, transform
import numpy as np
import matplotlib.pyplot as plt
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils# 注意skimage包的安装名<scikit-image>,安装方式: pip install scikit-image -i https://pypi.tuna.tsinghua.edu.cn/simple# 忽略警告
import warningswarnings.filterwarnings("ignore")plt.ion()landmarks_frame = pd.read_csv('data/faces/face_landmarks.csv')n = 65
img_name = landmarks_frame.iloc[n, 0]
landmarks = landmarks_frame.iloc[n, 1:].values
landmarks = landmarks.astype('float').reshape(-1, 2)print('Image name: {}'.format(img_name))
print('Landmarks shape: {}'.format(landmarks.shape))
print('First 4 Landmarks: {}'.format(landmarks[:4]))def show_landmarks(image, landmarks):"""匹配显示出csv中带有地标的对应图片"""plt.imshow(image)plt.scatter(landmarks[:, 0], landmarks[:, 1], s=10, marker='.', c='r')plt.pause(0.001)plt.figure()
show_landmarks(io.imread(os.path.join('data/faces/', img_name)), landmarks)
plt.show()
控制台输出:
Image name: person-7.jpg
Landmarks shape: (68, 2)
First 4 Landmarks: [[32. 65.][33. 76.][34. 86.][34. 97.]]
绘图如下:
根据计算的结果比对face_landmarks.csv
可以看到结果和图片集中能匹配上person-7.jpg文件的图形
相关文章:
PyTorch使用教程-深度学习框架
PyTorch使用教程-深度学习框架 1. PyTorch简介 1.1-什么是PyTorch PyTorch是一个广泛使用的开源机器学习框架,特别适合深度学习的应用。它以其动态计算图而闻名,允许在运行时修改模型,使得实验和调试更加灵活。PyTorch提供了强大的GPU加…...
TON商城与Telegram App:生态融合与去中心化未来的精彩碰撞
随着区块链技术的快速发展,去中心化应用(DApp)逐渐成为了数字生态的重要组成部分。而Telegram作为全球领先的即时通讯应用,不仅仅满足于传统的社交功能,更在区块链领域大胆探索,推出了基于其去中心化网络的…...
“乐鑫组件注册表”简介
当启动一个新的开发项目时,开发者们通常会利用库和驱动程序等现有的代码资源。这种做法不仅节省时间,还简化了项目的维护工作。本文将深入探讨乐鑫组件注册表的概念及其核心理念,旨在指导您高效地使用和贡献组件。 概念解析 ESP-IDF 的架构…...
凹凸/高度贴图、法线贴图、视差贴图、置换贴图异同
参考: 凹凸贴图、法线贴图、置换贴图-CSDN博客 视差贴图 - LearnOpenGL CN 1,Learn about Parallax(视差贴图) - 知乎 “视差贴图”的工作流程及原理(OpenGL) - 哔哩哔哩 法线与置换贴图原理讲解以及烘焙制作! - 知乎 1. Bump Mapping 凹凸贴图 BumpMap…...
ZSTD 内存泄漏问题
优质博文:IT-BLOG-CN Zstandard(简称zstd)是一种无损压缩算法,由Facebook开发并开源。它旨在提供高压缩比和高解压速度的平衡,适用于多种数据压缩需求。 特点 【1】高压缩比: zstd能够在保持较高压缩比的…...
c# npoi操作excel
今天在弄使用npoi对excel表的操作,遇到个问题就是使用workbook通过filestream打开后,让后workbook.write(filestream)居然报文件流关闭了,无法写入,弄了好久都不行,最后通过写2个excel文件来解决,现在看来我…...
十二:HTTP错误响应码:理解与应对
在现代网络技术中,HTTP(超文本传输协议)是浏览器与服务器之间沟通的基础。每当我们访问网站或发送请求,HTTP会返回一个响应码,这些代码不仅可以表示成功,还可以指示各种问题。本文将以HTTP错误响应码为主题,探讨其含义、常见类型及应对措施。 1. 400 Bad Request - 请求…...
Rust学习(六):函数式编程
Rust学习(六):函数式编程 我们在前一篇博客中已经介绍了如何通过trait和impl实现Rust的面向对象编程,但是Rust本身实际上并不提倡通过类来解决问题。Rust推崇的是函数式编程,强调将函数作为参数值或者其他函数的返回值…...
使用 Vue 和 Create-Vue 构建工程化前端项目
目录 前言1. 工程化的意义与 Vue 的生态支持2. 搭建 Vue 工程化项目2.1 环境准备2.2 使用 create-vue 创建项目2.2.1 初始化项目2.2.2 安装依赖2.2.3 本地运行 3. Vue 项目的目录结构解析4. Vue 开发流程详解4.1 项目入口与根组件4.1.1 main.js 的作用4.1.2 App.vue 的结构 4.2…...
opencv图片明暗度判断方法
OpenCV 的LAB 颜色空间(也称为 CIELAB)是一种颜色对手的颜色模型,它旨在模仿人类的色彩感知。LAB 颜色空间由三个分量组成: L: 亮度分量 (Lightness),范围从 0(黑色)到 100(白色&…...
QT6学习第三天
QT6学习第三天 第一个Widgets项目创建项目项目界面简单介绍编译文件介绍 我在第一天中将重点标了颜色,后边我把一些简单的东西都不写了,写了的都是实际用的东西,就不标颜色了。 第一个Widgets项目 首先我们创建一个widgets项目,…...
计算机网络-MSTP基础实验一(单域多实例)
前面我们已经大致了解了MSTP的基本概念和工作原理,但是我自己也觉得MSTP的理论很复杂不结合实验是很难搞懂的,今天来做一个配套的小实验以及一些配置命令。 一、网络拓扑 单域多实例拓扑 基本需求:SW1为VLAN10的网关,SW2为VLAN20的…...
React合成事件及其核心思想详解
相关联Javascript知识 1.JavaScript 的事件流 事件流是 JavaScript 处理事件的机制,它描述了事件从发生到被处理的过程。事件流主要包括两个阶段:捕获阶段和冒泡阶段。在捕获阶段,事件从文档的根元素开始,逐层向下传播到目标元素&…...
Datawhale模型减肥秘籍Tasking之模型量化
Datawhale模型减肥秘籍Tasking之模型量化 什么是量化?为什么量化?量化基本方法基于k-means的量化线性量化 训练后量化量化粒度动态量化参数的计算 ( Cliping )指数移动平均(EMA)Min-MaxKL 量化均方误差(MSE)…...
在云服务器搭建 Docker
操作场景 本文档介绍如何在腾讯云云服务器上搭建和使用 Docker。本文适用于熟悉 Linux 操作系统,刚开始使用腾讯云云服务器的开发者。如需了解更多关于 Docker 相关信息,请参见 Docker 官方。 说明: Windows Subsystem for Linuxÿ…...
Redis 的代理类注入失败,连不上 redis
在测试 redis 是否成功连接时,发现 bean 没有被创建成功,导致报错 根据报错提示,需要我们添加依赖: <dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>&l…...
版本控制【Git Bash】【Gitee】
目录 一、什么是版本控制? 二、版本控制的种类: 1、本地版本控制 2、集中版本控制 3、分布式版本控制 三、下载Git Bash 四、Git Bash 配置 五、Git Bash使用 1、切换目录:cd 2.查看当前文件路径:pwd 3.列出当前目录下文件…...
Neo4j Desktop 和 Neo4j Community Edition 区别
Neo4j Desktop 和 Neo4j Community Edition 的主要区别在于它们的用途、功能以及安装和管理方式。以下是这两者的详细对比: 1. Neo4j Desktop Neo4j Desktop 是一个图形化的桌面应用程序,主要为开发人员和个人使用提供了一个便捷的环境来安装、管理和运…...
使用uniapp开发微信小程序使用uni_modules导致主包文件过大,无法发布的解决方法
在使用uniapp开发微信小程序时候,过多的引入uni_modules的组件库,会导致主包文件过大,导致无法上传微信小程序,主包要求大小不超过1.5MB.分包大小每个不能超过2M。 解决方法:分包。 1.对每个除了主页面navbar的页面进…...
HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)事件推荐开发者测试
意图框架向开发者提供真机测试能力,即开发者可连接设备进行调测。开发者完成代码开发之后,功能正式上架应用市场前,可以在HarmonyOS NEXT设备上面进行自验证,打磨体验。真机测试分为三个步骤:基础信息提供,…...
GD32F103 实践-- MCU编译运行
编译 打开固件库示例工程:在SDK路径下找到固件库示例工程,路径通常是SDK\GD32F10x_Firmware_Library_Template\Keil5_project\Project 选择芯片型号:根据你的MCU型号选择,例如GD32F103RCT6 修改宏定义:根据MCU型号修…...
SQL复杂数据类型处理
背景 数据处理中,经常碰到复杂数据类型,需要将他们进行解析才能利用。 复杂数据类型 1、MAP结构转为列 WITH tmp AS ( SELECT {"Users":{"4418":{"UserId":4418,"Score":0,"IsStudent":true},&q…...
ROS第九梯:ROS+VSCode+Python+C++自定义消息发布和订阅
首先,Python版本的ROS项目和C++版本的ROS项目前期创建功能包的步骤基本一致,具体可参考第二章。 费一步:新建msg文件 在功能包(data_input)目录下创建一个msg文件夹,并在msg文件夹下创建一个名为Box的msg文件,具体如下图所示: 该msg文件为一个用于描述3D Box的文件,…...
【Linux】指令 + 压缩与解压
Linux 一.Linux基本指令1.grep2.zip和unzip1.Linux中的压缩文件发送Windows中2.Linux中接收Windows中压缩文件 3.tar(重要)1.Linux与Linux互传压缩文件 4.bc5.uname 二.Linux相关知识点1.Linux常用热键2.关机操作 一.Linux基本指令 1.grep 行文本过滤工…...
力扣(leetcode)题目总结——动态规划篇
leetcode 经典题分类 链表数组字符串哈希表二分法双指针滑动窗口递归/回溯动态规划二叉树辅助栈 本系列专栏:点击进入 leetcode题目分类 关注走一波 前言:本系列文章初衷是为了按类别整理出力扣(leetcode)最经典题目,…...
数据仓库数据湖湖仓一体解决方案
一、资料介绍 数据仓库与数据湖是现代数据管理的两大核心概念。数据仓库是结构化的数据存储仓库,用于支持企业的决策分析,其数据经过清洗、整合,以固定的模式存储,适合复杂查询。数据湖则是一个集中存储大量原始数据的存储库&…...
微信小程序 最新获取用户头像以及用户名
一.在小程序改版为了安全起见 使用用户填写来获取头像以及用户名 二.代码实现 <view class"login_box"><!-- 头像 --><view class"avator_box"><button wx:if"{{ !userInfo.avatarUrl }}" class"avatorbtn" op…...
无人机在森林中的应用!
一、森林资源调查 无人机可以利用遥感技术快速获取所需区域高精度的空间遥感信息,对森林图斑进行精确区划。相较于传统手段,无人机调查具有低成本、高效率、高时效的特点,尤其在地理环境条件不好的区域,调查人员无法或难以到达的…...
Seatunnel解决Excel中无法将数字类型转换成字符串类型以及源码打包
需求 需要实现将Excel中的数字类型的单元格像数据库中字符串类型的字段中推送 问题原因 Seatunnel在读取字段类型的时候都是使用强转的形式去获取数据的 假如说数据类型不一样的话直接强转就会报错 修改位置 org/apache/seatunnel/api/table/type/SeaTunnelRow.java org…...
在阿里云快速启动Appsmith搭建前端页面
什么是Appsmith Appsmith是一个开源的低代码开发平台,它使得开发者能够快速地构建内部工具、业务管理系统、CRM系统等。Appsmith通过提供一系列预建的UI组件(如表格、图表、表单等),以及对数据库、API调用的直接支持,…...
wordpress改变url/全网引流推广
或许因为自己“国外币”的身份难以服众,指望着“竞斗云”A 股上市公司的身份可以为 BATT 做背书,方便自己发币、炒币、割韭菜,没想到最后沦落为上市公司“花样割韭菜”的工具。文| 茶凉 运营| 盖遥出品| O…...
苏州做网站公/seo系统推广
Action参数绑定功能提供了URL变量和操作方法的参数绑定支持,这一功能可以使得你的操作方法定义和参数获取更加清晰,也便于跨模块调用操作方法了。这一新特性对以往的操作方法使用没有任何影响,你也可以用新的方式来改造以往的操作方法定义。 …...
河南网站建设/灰色关键词快速排名
“一个人漂泊久了其实也不挑生活品质了” 在一个论坛看到这句话,是一个漂在厦门的女孩说的,看到就忽忽的心酸。 我想回家。转载于:https://www.cnblogs.com/diandian/archive/2006/06/16/427679.html...
做设计的兼职网站/网络服务提供者
一:读写流的一些案例。 --->关于StreamWrite 这里的一些常用的方法和我们之前的那个FileStream是一样的,参数很多都是一样的用法。 Console.WriteLine("输入文件名:");string file Console.ReadLine();//StreamWriter------------实现一…...
做网站哪些技术/百度seo排名360
2019独角兽企业重金招聘Python工程师标准>>> 准备域名和证书 任务时间:20min ~ 40min 小程序后台服务需要通过 HTTPS 访问,在实验开始之前,我们要准备域名和 SSL 证书。 域名注册 如果您还没有域名,可以在腾讯云上选购…...
电信单宽带办理多少钱/seo网站优化怎么做
我在Python中看到的最接近代码生成的是Python的__metaclass__特性。例如,下面是一个创建只读属性的简单元类:class ReadonlyProperties(type):def __init__(cls, name, bases, attrs):props attrs.get("props",[])if props:# generate proper…...