深度学习:PyTorch学习之库内容初级实验


一、引言

代码参考:《深度学习入门之基于PyTorch和TensorFlow的理论与实现》。

代码源可以参考这里。会在实验与学习中加入一些自己的理解。


二、张量部分

1、创建张量。

张量是PyTorch里基本的运算单位,类似NumPy中的数组。但张量可以在GPU版本的PyTorch上运行,可NumPy中的数组只能在CPU版本的PyTorch上运行。

1°创建一个随机初始化的 Tensor 。

x = torch.randn(2,2)

2°直接把 Python 列表构建成 Tensor 。

x = torch.tensor([[1, 2], [3, 4]])

3°创建一个全零 Tensor 。

x = torch.zeros(2,2)

结果如下:

tensor([[0., 0.],
        [0., 0.]])

4°基于现有的 Tensor 创建新的 Tensor 。

x = torch.zeros(2,2)
y = torch.ones_like(x)
print(x)
print(y)

torch.ones_like函数和torch.zeros_like函数的基本功能是根据给定张量,生成与其形状相同的全1张量或全0张量。在这两个函数中,还可以指定数据类型、设备、是否计算梯度等信息,可以结合具体场景灵活使用。结果如下。

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

5°指定 Tensor 数据类型。

x = torch.ones(2, 2, dtype=torch.long)
print(x)

返回结果。

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

2、Terson 数学运算。

1°两个 Tensor 相加。

x = torch.ones(2,2)
y = torch.ones(2,2)
z = x + y  #等价于z = torch.add(x, y)
print(z)

返回结果。

tensor([[2., 2.],
        [2., 2.]])

2°使用._add()实现相加后的替换。

x = torch.ones(2,2)
y = torch.ones(2,2)
y.add_(x)
print(y)

返回结果。

tensor([[2., 2.],
        [2., 2.]])

3°Tenosr乘法。包含对应元素相乘、矩阵相乘两种形式。

对应元素相乘。

x = torch.tensor([[1, 2], [3, 4]])
y = torch.tensor([[1, 2], [3, 4]])
x.mul(y)

返回结果。

tensor([[ 1,  4],
        [ 9, 16]])

矩阵相乘。这种形式是比较常见的。

x = torch.tensor([[1, 2], [3, 4]])
y = torch.tensor([[1, 2], [3, 4]])
x.mm(y)

返回结果。

tensor([[ 7, 10],
        [15, 22]])

3、张量与NumPy数组。

Tensor 与 NumPy 数组可以互相转换,两者共享内存位置,一个改变,另一个也随之改变。运行前,先把NumPy导入,import numpy as np。

1°Tensor 转化为 NumPy 数组。

a = torch.ones(2,2)
b = a.numpy()
print(type(a))
print(type(b))
print(a)
print(b)

把 Tensor 类型数据,转为 NumPy 。从打印结果,也可以看出,a是一个 Tensor 类型数据,用 tensor 表示了,而b已经是 NumPy 类型了。

<class 'torch.Tensor'>
<class 'numpy.ndarray'>
tensor([[1., 1.],
        [1., 1.]])
[[1. 1.]
 [1. 1.]]

2°此时,如果Tensor发生改变,对应的NumPy数组也有相同的变化。

a.add_(1)
print(a)
print(b)

结果如下。

tensor([[2., 2.],
        [2., 2.]])
[[2. 2.]
 [2. 2.]]

3°NumPy 转化为 Tensor 数组。

a = np.array([[1, 1], [1, 1]])
b = torch.from_numpy(a)
print(type(a))
print(type(b))
print(a)
print(b)

返回结果。

<class 'numpy.ndarray'>
<class 'torch.Tensor'>
[[1 1]
 [1 1]]
tensor([[1, 1],
        [1, 1]], dtype=torch.int32)

4°如果 NumPy 数组发生改变,对应的 Tensor 也有相同的变化。

np.add(a, 1, out=a)
print(a)
print(b)

返回结果。

[[2 2]
 [2 2]]
tensor([[2, 2],
        [2, 2]], dtype=torch.int32)

5°新建张量默认保存在CPU中,如果安装了GPU版本的PyTorch,就可以将张量转移到GPU里,代码如下。

a = torch.ones(2,2)
# 检查是否可以使用GPU
if torch.cuda.is_available():
    a_cuda = a.cuda()
    print(a_cuda)

由于我装的是CPU版本的PyTorch,所以这里不会执行if语句。如果安装了GPU,a_cuda的打印结果如下:

tensor([[1., 1.],
        [1., 1.]], device='cuda:0')

三、自动求导

构建深度学习模型的基本流程为搭建计算图、求损失函数,然后计算损失函数对模型参数的导数,最后用梯度下降法等来更新参数。搭建计算图的过程,称为“正向传播”,需要手动搭建,和本身设计模型的结构相关。而由损失函数求导的过程,称为“反向传播”,是一件辛苦事。

深度学习的算法本质,在于反向传播求导数。这个功能是通过PyTorch的自动求导(autograd)模块实现的。对于张量的所有操作,自动求导模块都能为它们自动提供微分,避免了手动计算导数的复杂过程,可以节约时间。

如果要让张量使用自动求导的功能,需要在定义张量的时候,设置参数tensor.requries_grad=True。否则,默认情况下,张量是没有求导功能的。

x = torch.ones(2, 2)
y = torch.ones(2, 2, requires_grad=True)
print(x.requires_grad)  # 使用x.requires_grad调用变量的属性值
print(y.requires_grad)
x.requires_grad_(False)  # 使用x.requires_grad_调用内置的函数,来改变属性
print(x.requires_grad)

使用print把requires_grad结果打印下来,也可以发现默认情况下,张量确实没有求导功能。想改变这个属性,可以使用tensor.requires_grad_()方法。

False
True
False

1°返回值是标量的情况。

print(x)
print(y)
z = x + y
print(z)
z = z.mean()
print(z)

输出定义为张量x和张量y每个元素相加后求平均的结果,是一个一维数据。在PyTorch中,每个通过函数计算得到的变量,都有一个.grad_fn属性,grad_fn是用来记录变量是怎么来的,方便计算梯度,比如:y = x*3,grad_fn就记录了y由x计算的过程。

tensor([[1., 1.],
        [1., 1.]])
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
tensor([[2., 2.],
        [2., 2.]], grad_fn=<AddBackward0>)
tensor(2., grad_fn=<MeanBackward0>) #坑点待补

2°如果此时,需要计算z对x的偏导数,以及z对y的偏导数。首先要对z使用.backward()来定义反向传播,代码为z.backward()。

z.backward(torch.ones_like(z)) #定义反向传播
#直接使用x.grad来计算z对x的偏导,y.grad来计算z对y的偏导。
print(x.grad)
print(y.grad)

可以看到,只需简单两句,就完成了PyTorch的自动求导功能了。

tensor([[0.2500, 0.2500],
        [0.2500, 0.2500]])
tensor([[0.2500, 0.2500],
        [0.2500, 0.2500]])
#对结果进行验证,是对的,具体参考“标量对矩阵的求导运算”。但这里貌似,就只是对公式上的求导。而非具体值。

为了验证结果,将x和y的一些数据进行改变,再次验证。

x = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)
y = torch.tensor([[5., 4.], [12., 23.]], requires_grad=True)
print(x.requires_grad)
print(y.requires_grad)
print(x)
print(y)
z = x + y
print(z)
#z = z.mean()
print(z)
z.backward()
print(x.grad)
print(y.grad)

输出结果。

True
True
tensor([[1., 2.],
        [3., 4.]], requires_grad=True)
tensor([[ 5.,  4.],
        [12., 23.]], requires_grad=True)
tensor([[ 6.,  6.],
        [15., 27.]], grad_fn=<AddBackward0>)
tensor([[ 6.,  6.],
        [15., 27.]], grad_fn=<AddBackward0>)
tensor([[1., 1.],
        [1., 1.]])
tensor([[1., 1.],
        [1., 1.]])

3°当输出是多维张量。

x = torch.ones(2, 2, requires_grad=True)
y = torch.ones(2, 2, requires_grad=True)
z = 2 * x + 3 * y
print(z)
z.backward(torch.ones_like(z))
print(x.grad)
print(y.grad)

当输出z是一个标量时,不需要在backward()中指定任何参数,但如果z是一个多维张量,则需要在backward()中参数,来匹配相应的尺寸。

4°禁止自动求导。使用with torch.no_grad():指令。

print(x.requires_grad)
print((2 * x).requires_grad)
with torch.no_grad():
    print((2 * x).requires_grad)

四、参考文献

torch.ones_like函数和torch.zero_like函数
requires_grad,grad_fn,grad的含义及使用

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATian+

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值