Pytorch简明教程01


01 Pytorch基础知识

主要介绍pytorch中的tensor,包括tensor的创建、基本操作、广播机制等

1.1 Tensor简介

tensor,即张量,是基于向量和矩阵的拓展:

  • 0D tensor:标量
  • 1D tensor:矢量
  • 2D tensor:矩阵
  • 3D tensor:时间序列,RGB图像
  • 4D tensor:多张RGB图像,一段视频
  • 5D tensor:多个视频(第一个维度是batchsize

1.2 Tensor的创建

# 直接通过torch.tensor(data)创建
torch.tensor([1,2,3,4])
# 随机初始化
torch.rand(4)
# 全0
torch.zeros(4)
# 全1
torch.ones(4)
# 规定范围和步长进行创建
torch.arange(0,10,2)
函数功能
Tensor(sizes)基础构造函数
tensor(data)类似于np.array,参数是一个list,[]
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)随机排列

在创建tensor的时候,可以通过参数dtype来指定tensor中的数据类型。

也可以基于numpy的array创建tensor,主要使用torch.from_numpy()方法

# 从NumPy ndarray转换为Tensor
import numpy as np
np_array = np.array([1, 2, 3])
tensor_from_np = torch.from_numpy(np_array)

通过size()或者shape可以查看tensor的形状。

1.3 张量的操作

1. 运算操作

运算包括普通的四则运算和矩阵运算

四则运算,都是进行逐个元素的运算

  • 加法

    torch.add(tensor1, tensor2)
    # 或者
    tensor1 + tensor2
    
  • 减法

    torch.sub(tensor1, tensor2)
    # 或者
    tensor1 - tensor2
    
  • 乘法(逐元素):

    torch.mul(tensor1, tensor2)
    # 或者
    tensor1 * tensor2
    
  • 除法(逐元素):

    torch.div(tensor1, tensor2)
    # 或者
    tensor1 / tensor2
    
import torch

# 创建两个Tensor
tensor1 = torch.tensor([1, 2, 3], dtype=torch.float32)
tensor2 = torch.tensor([4, 5, 6], dtype=torch.float32)

# 加法
add_result = tensor1 + tensor2

# 减法
sub_result = tensor1 - tensor2

# 乘法(逐元素)
mul_result = tensor1 * tensor2

# 除法(逐元素)
div_result = tensor1 / tensor2

print(f"Addition: {add_result}")
print(f"Subtraction: {sub_result}")
print(f"Multiplication: {mul_result}")
print(f"Division: {div_result}")

Addition: tensor([5., 7., 9.])
Subtraction: tensor([-3., -3., -3.])
Multiplication: tensor([ 4., 10., 18.])
Division: tensor([0.2500, 0.4000, 0.5000])

2. 矩阵运算

  • 矩阵乘法

    torch.matmul(tensor1, tensor2)
    # 或者使用 @ 符号
    tensor1 @ tensor2
    
  • 转置

    torch.transpose(tensor, 0, 1)
    # 对于2D tensor,也可以使用 tensor.t()
    
  • 逆矩阵

    torch.inverse(tensor)
    
# 创建两个矩阵
matrix1 = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
matrix2 = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)

# 矩阵乘法
matmul_result = torch.matmul(matrix1, matrix2)

# 矩阵转置
transpose_result = matrix1.t()

print(f"Matrix Multiplication:\n{matmul_result}")
print(f"Transpose of Matrix 1:\n{transpose_result}")
Matrix Multiplication:
tensor([[19., 22.],
        [43., 50.]])
Transpose of Matrix 1:
tensor([[1., 3.],
        [2., 4.]])

3. 维度变换

张量的维度变换常见的方法有torch.view()torch.reshape(),两个的区别:
torch.view()是直接在原tensor上进行变换,返回的tensor和原tensor共用一块地址;

torch.reshape() 返回的新tensor不是和原tensor共用一块地址。但是此函数并不能保证返回的是其拷贝值,所以官方不推荐使用。推荐的方法是我们先用 clone() 创造一个张量副本然后再使用 torch.view()进行函数维度变换 。

注:使用 clone() 还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源 Tensor 。

view方法就是指定一个shape来改变tensor的形状;同时他还可以自动推断维度大小;

import torch

# 创建一个1x4的Tensor
x = torch.randn(1, 4)
print(f"Original Tensor:\n{x}\n")

# 使用view方法改变形状为2x2
y = x.view(2, 2)
print(f"Reshaped Tensor (2x2):\n{y}")

# 创建一个Tensor
x = torch.randn(3, 2)
print(f"Original Tensor (3x2):\n{x}\n")

# 使用view改变形状,自动计算第二维度
y = x.view(6, -1)
print(f"Reshaped Tensor (6x1):\n{y}")

4. 扩展和压缩维度

用于指定增加或者减少特定维度。

unsqueeze方法用于增加Tensor的一个维度。你需要指定增加维度的位置。增加的这个新维度将有一个大小为1。这在某些操作中特别有用,例如,当你需要将一个一维的Tensor转换为二维的行或列向量时。

import torch

# 创建一个一维Tensor
x = torch.tensor([1, 2, 3, 4])
print(f"Original Tensor: {x.size()}")

# 在第0维增加一个维度
y = x.unsqueeze(0)
print(f"Tensor after unsqueeze at dim 0: {y.size()}")

# 在第1维增加一个维度
z = x.unsqueeze(1)
print(f"Tensor after unsqueeze at dim 1: {z.size()}")

Original Tensor: torch.Size([4])
Tensor after unsqueeze at dim 0: torch.Size([1, 4])
Tensor after unsqueeze at dim 1: torch.Size([4, 1])

unsqueeze相反,squeeze方法用于移除Tensor中所有大小为1的维度。这在从某些操作中获取输出时非常有用,这些操作可能会引入大小为1的不必要维度。squeeze也可以指定移除特定的单一维度,但这个维度的大小必须为1,否则Tensor的形状不会改变。

# 使用之前示例中的y和z

# 从y中移除所有大小为1的维度
y_squeezed = y.squeeze()
print(f"y after squeeze: {y_squeezed.size()}")

# 从z中移除所有大小为1的维度
z_squeezed = z.squeeze()
print(f"z after squeeze: {z_squeezed.size()}")

# 尝试从y中移除特定的维度,如果那个维度的大小不为1,则形状不变
y_squeezed_specific = y.squeeze(1)
print(f"y after trying to squeeze dim 1: {y_squeezed_specific.size()}")

y after squeeze: torch.Size([4])
z after squeeze: torch.Size([4])
y after trying to squeeze dim 1: torch.Size([1, 4])

小结:

  • unsqueeze 增加一个新的维度到Tensor中,通常用来创建额外的批处理维度或将一维Tensor转换为二维的行/列向量。
  • squeeze 移除Tensor中所有大小为1的维度,或者指定移除某个特定维度(如果该维度大小为1),常用于移除不必要的单一维度,简化Tensor的形状。

1.4 广播机制

当对两个形状不同的 Tensor 按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个 Tensor 形状相同后再按元素运算。

x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)
tensor([[1, 2]])
tensor([[1],
        [2],
        [3]])
tensor([[2, 3],
        [3, 4],
        [4, 5]])

由于x和y分别是1行2列和3行1列的矩阵,如果要计算x+y,那么x中第一行的2个元素被广播 (复制)到了第二行和第三行,⽽y中第⼀列的3个元素被广播(复制)到了第二列。如此,就可以对2个3行2列的矩阵按元素相加。

1.5 梯度计算

torch.Tensor 是这个包的核心类。如果设置它的属性 .requires_gradTrue,那么它将会追踪对于该张量的所有操作。当完成计算后可以通过调用 .backward(),来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad属性,通过.grad.data来查看梯度值。

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

有时候,你可能不希望PyTorch跟踪计算图中的操作,例如在推理时不需要计算梯度。你可以使用torch.no_grad()来临时禁用梯度计算:在评估模型的时候可以用这个,防止内存爆炸。

with torch.no_grad():
    # 在这个block中,所有的Tensor操作都不会跟踪梯度
    y = x * 2
    print(y)

或者,你可以使用.detach()方法得到一个新Tensor,它与原Tensor共享数据但不需要梯度:

y = x.detach()
print(y)

在PyTorch中,当你创建一个新的Tensor时,requires_grad参数默认是False。这意味着,默认情况下,PyTorch不会跟踪该Tensor上的操作,也就是说,不会自动计算关于这个Tensor的梯度。这样做是为了优化性能,因为在很多情况下,尤其是在推理(inference)阶段,你不需要计算梯度。

如果你需要对一个Tensor计算梯度,你必须在创建Tensor时明确设置requires_grad=True,或者在创建后通过tensor.requires_grad_(True)来修改它的requires_grad属性。

只有在tensor进行backward()操作之后,计算图中的元素才会计算梯度,并且由于梯度是可以累加的,多次执行backward()操作,梯度是不断叠加的。

每次使用.backward()方法计算梯度后,通常需要手动将梯度清零。这是因为默认情况下,当.backward()被调用时,梯度会被累加到Tensor的.grad属性中,而不是被替换。这样设计的目的是为了方便在一些情况下(如RNN的训练)对梯度进行累积。但在大多数训练循环中,我们希望每一步的梯度是基于当前步的数据独立计算的,而不是累积之前所有步骤的梯度,因此需要在每次迭代之前清除之前累积的梯度。可以通过x.grad.data.zero_()手动清零,也可以在optimizer中自动清零。,通过调用.zero_grad()方法来实现这一点,通常是在优化器对象上调用此方法,例如:

optimizer.zero_grad()

这将遍历所有通过optimizer管理的参数(即所有设置了requires_grad=True的参数),并将它们的.grad属性重置为零。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值