PyTorch深度学习基础(第四章)

PyTorch深度学习基础(第四章)

PyTorch的Tensor和NumPy的ndarray十分类似,但是Tensor具备两个ndarray不具备而对于深度学习来说非常重要的功能。其一是Tensor能用利用GPU计算,GPU根据芯片性能的不同,在进行矩阵运算时,能比CPU快几十倍。其二是Tensor在计算时,能够作为节点自动地加入计算图,而计算图可以为其中的每个节点自动计算微分,也就是说当我们使用Tensor时,就不需要手动计算微分了。



一、Tensor对象及其运算

Tensor对象是一个任意维度的矩阵,但是一个Tensor中所有元素的数据类型必须一致。 torch包含的数据类型和普遍编程语言的数据类型类似,包含淫点型、有符号整型和无符号整型。这些类型既可以定义在CPU上,也可以定义在GPU上。在使用Tensor数据类型时,可以通过dtype属性指定它的数据类型,device指定它的设备(CPU或者GPU)。

代码如下:

import torch
import numpy as np


###########   4.1Tensor的对象及其运算   ###########
# torch.tensor
print('torch.Tensor默认为:{}'.format(torch.Tensor(1).dtype))
print('torch.tensor默认为:{}'.format(torch.tensor(1).dtype))
# 可以用list 构建
a = torch.tensor([[1, 2], [3, 4]], dtype=torch.float64)
# 也可以用ndarray构建
b = torch.tensor(np.array([[1, 2], [3, 4]]), dtype=torch.uint8)
print(a)
print(b)

# 通过device 指定设备
cuda0 = torch.device('cuda:0')
c = torch.ones((2, 2), device=cuda0)
print(c)

通过device 在GPU上定义变量后,可以在终端上通过nvidia-smi命令查看显存(显卡内存)占用。torch还支持在CPU和GPU之间复制变量

代码如下:

c = c.to('cpu', torch.double)
print(c.device)
b = b.to(cuda0, torch.float)
print(b.device)

对Tensor执行算数运算符的运算,是两个矩阵对应元素的运算。torch.mm执行矩阵乘法的运算。
代码如下:

a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[1, 2], [3, 4]])
c = a * b
print("逐元素相乘:", c)
c = torch.mm(a, b)
print("矩阵乘法:", c)

torch.clamp起到分段函数的作用,可用于去掉矩阵中过小或者过大的元素;torch.round将小数转为整数;torch.tanh计算双曲正切函数,该函数将数值映射到(0,1)。
代码如下:


a = torch.tensor([[1, 2], [3, 4]])
torch.clamp(a, min=2, max=3)
 
a = torch.tensor([-1.1, 0.5, 0.501, 0.99])
torch.round(a)
 
a = torch.Tensor([-3, -2, -1, -0.5, 0, 0.5, 1, 2, 3])
torch.tanh(a)

(1)除了直接从 ndarray 或 list类型的数据中创建Tensor,PyTorch 还提供了一些可直接创建数据的函数,这些函数往往需要提供矩阵的维度。torch.arange 和Python内置的range的使用方法基本相同,其中第3个参数是步长。torch.limspace 的第3个参数指定返回的个数。torch.ones返回全1,torch.zeros返回全0矩阵。

(2)torch.rand 返回范围为[0,1]的均匀分布采样的元素所组成的矩阵,torch.randn返回从正态分布采样的元素所组成的矩阵,torch.randint 返回指定区间的均匀分布采样的随机整数所生成的矩阵。
代码如下:

print(torch.arange(5))
print(torch.arange(1, 5, 2))
print(torch.linspace(0, 5, 10))
 
print(torch.ones(3, 3))
print(torch.zeros(3, 3))
 
print(torch.rand(3, 3))
print(torch.randn(3, 3))
print(torch.randint(0, 9, (3, 3)))


二、Tensor的索引和切片

Tensor支持基本索引和切片操作,还支持ndarray中的高级索引(整数索引和布尔索引)操作。

########   4.2Tenser的索引和切片  #########
a = torch.arange(9).view(3,3)
#基本索引
print(a[2,2])

#切片
print(a[1:,:-1])
#row:1,2 col:1,2 -1:取开区间

#带步长的切片
print(a[::2])
print(a[::2,::2])

#整数索引
rows = [0,1]
cols = [2,2]
print(a[rows,cols])

#布尔索引
index = a>4
print(index)
print(a[index])

torch.nonzero用于返回非零值的索引矩阵。

a = torch.arange(9).view(3, 3)
index = torch.nonzero(a >= 8)
print(index)
 
a = torch.randint(0, 2, (3, 3))
print(a)
index = torch.nonzero(a)
print(index)

torch.where(condition,x,y)判断condition 的条件是否满足。 当某个元素满足条件时,则返回对应矩阵x相同位置的元素,否则返回矩阵y的元素。

x = torch.randn(3, 2)
y = torch.ones(3, 2)
print(x)
print(torch.where(x > 0, x, y))

三、Tensor的变换、拼接和拆分

Tensor.nelement、Tensor.ndimension、ndimension.size可分别用来查看矩阵元素的个数、轴的个数以及维度,属性Tensor.shape 也可以用来查看 Tensor的维度。

a = torch.rand(1, 2, 3, 4, 5)
print("元素个数", a.nelement())
print("轴的个数", a.ndimension())
print("矩阵维度", a.size(), a.shape)

在PyTorch中,Tensor.view 和 Tensor.reshape 都能被用来更改 Tensor 的维度。它们的区别在于,Tensor.view 要求 Tensor 的物理存储必须是连续的,否则将报错;而Tensor.reshape 则没有这种要求。但是,Tensor.view 返回的一定是一个索引,更改返回值,则原始值同样被更改;Tensor.reshape 返回的是引用还是复制是不确定的。它们的相同之处是都接收要输出的维度作为参数,且输出的矩阵元素个数不能改变,可以在维度中输入一1,PyTorch 会自动推断它的数值。

b = a.view(2*3, 4*5)
print(b.shape)
c = a.reshape(-1)
print(c.shape)
d = a.reshape(2*3, -1)
print(d.shape)

torch.squeeze 和 torch.unsqueeze 用于为Tensor 去掉和添加轴。其中 torch.squeeze用于去掉维度为1的轴,而torch.unsqueeze用于给Tensor 的指定位置添加一个维度为1的轴。

b = torch.squeeze(a)
print(b.shape)
c = torch.unsqueeze(b, 0)
print(c.shape)

torch.t和torch.transpose 用于转置二维矩阵。这两个函数只接收二维Tensor,torch.t是torch.transpose.的简化版。

a = torch.tensor([[2]])
b = torch.tensor([[2, 3]])
print(torch.transpose(a, 1, 0,))
print(torch.t(a))
print(torch.transpose(b, 1, 0,))
print(torch.t(b))

对于高纬度Tensor,可以使用permute方法来交换维度。

a = torch.rand((1, 224, 224, 3))
print(a.shape)
b = a.permute(0, 3, 1, 2)
print(b.shape)

PyTorch 提供了 torch.cat 和 torch.stack 用于拼接矩阵。不同之处是,torch.cat 在已有的轴dim 上拼接矩阵,给定轴的维度可以不同,而其他轴的维度必须相同。torch.stack在新的轴上拼接,它要求被拼接的矩阵的所有维度都相同。下面的例子可以很清楚地表明它们的使用方式和区别。

a = torch.randn(2, 3)
b = torch.randn(3, 3)

# 默认维度为dim=0

c = torch.cat((a, b))
d = torch.cat((b, b, b), dim=1)
 
print(c.shape)
print(d.shape)
 
c = torch.stack((b, b), dim=1)
d = torch.stack((b, b), dim=0)
print(c.shape)
print(d.shape)

除了拼接矩阵,PyTorch还提供了torch.split和torch.chunk用于拆分矩阵。它们的不同之处在于,torch.split传入的是拆分后每个矩阵的大小,可以传入list,也可以传入整数,而torch.chunk传入的是拆分的矩阵个数。

a = torch.randn(10, 3)
# dim  0:10,  分为1234   10=1+2+3+4
for x in torch.split(a, [1, 2, 3, 4], dim=0):
    print(x.shape)
 
# dim 0:10 均匀分割为4
for x in torch.split(a, 4, dim=0):
    print(x.shape)
 
# 其中的4是拆分后矩阵个数
for x in torch.chunk(a, 4, dim=0):
    print(x.shape)


四、PyTorch的Reduction操作

Reduction操作的特点是它往往对一个Tensor内的元素执行归约操作,比如torch.max找极大值、torch.cumsum计算累加,它还提供了dim参数来指定沿矩阵的哪个维度执行操作。

# 默认求取全局最大值
a = torch.tensor([[1, 2], [3, 4]])
print("全局最大值:", torch.max(a))
# 指定维度 dim 后, 返回最大值其索引
print(torch.max(a, dim=0))
a = torch.tensor([[1, 2], [3, 4]])
print("沿着横轴计算每一列的累加:")
print(torch.cumsum(a, dim=0))
print("沿着纵轴计算每一行的乘积:")
print(torch.cumprod(a, dim=1))
 
# 计算矩阵的均值、中值、协方差
a = torch.Tensor([[1, 2], [3, 4]])
a.mean(),a.median(), a.std()
 
# torch.unique用来找出矩阵中出现了哪些元素
a = torch.randint(0, 3, (3, 3))
print(a)
print(torch.unique(a))

五、PyTorch的自动微分

当将 Tensor 的 requires_grad 属性设置为True时,PyTorch 的torch.autograd会自动追踪它的计算轨迹。当需要计算微分的时候,只需要对最终计算结果的Tensor 调用backward方法,所有计算节点的微分就会被保存在grad属性。

x = torch.arange(9).view(3, 3)
x.requires_grad
x = torch.rand(3, 3, requires_grad=True)
print(x)
 
w = torch.ones(3, 3, requires_grad=True)
y = torch.sum(torch.mm(w, x))
print(y)
 
y.backward()
print(y.grad)
print(x.grad)
print(w.grad)

Tensor.detach会将Tensor从计算图剥离出去,不再计算它的微分。

x = torch.rand(3, 3, requires_grad=True)
w = torch.rand(3, 3, requires_grad=True)
print(x)
print(y)
yy = torch.mm(w, x)
 
detached_yy = yy.detach()
y = torch.mean(yy)
y.backward()
 
print(yy.grad)
print(detached_yy)
print(w.grad)
print(x.grad)

with torch.no_grad():包括的代码段不会计算微分。

with torch.no_grad():
    y = torch.sum(torch.mm(w, x))

  • 34
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值