深度学习框架pytorch入门与实战

2.2.1 Tensor

函数名后带下划线_的函数会修改Tensor本身。例如,x.add_(y)和 x.t_()会改变x,但x.add(y)和 x.t()会返回一个新的Tensor,而x不变

Tensor 支持很多运算,包括数学运算、线性代数、选择、切片等,其接口设计与numpy极为相似

Tensor和numpy的数组间的仙湖操作非常容易且快速。Tensor不支持的操作,可以先转为numpy数组处理,之后再转回Tensor。

a = t.ones(5) # tensor([1., 1., 1., 1., 1.])
b = a.numpy() # array([1., 1., 1., 1., 1.], dtype=float32)
a = t.from_numpy(b) # tensor([1., 1., 1., 1., 1.])

Tensor 和 numpy对象共享内存,它们之间的转换很快,几乎不消耗资源,如果其中一个变了,另一个也随之改变

**Tensor可以通过 .cuda 转为GPU的Tensor,**从而使运算加速

2.2.2 Autograd: 自动微分

深度学习算法本质上是通过反向传播求导。

在Tensor上的所有操作,Autograd都能为它们自动提供微分。

autograd.Variable是Autograd中的核心类,它简单封装了Tensor,并支持几乎所有的Tensor操作。Tensor在被封装为Variable之后,可以调用它的.backward实现反向传播,自动计算所有梯度。

from torch.autograd import Variable
x = Variable(t.ones(2, 2),requires_grad = True)
x
#	Variable containing:
#		1	1
#		1	1
#	[torch.FloatTensor of size 2*2]

Variable主要包含三个变量:

  1. data:保存Variable说包含的Tensor
  2. grad:保存data对应的梯度,grad是个Variable,而不是Tensor
  3. grad_fn:只想一个Function对象,用来反向传播计算输入的梯度

**注:**grad在反向传播过程中是累加的,这意味着每次运行反向传播,梯度都会累加之前的梯度,所以反向传播需要把之前的梯度清零

# 以下画线结束的函数是inplace操作
x.grad.data.zero_()

Variable 和 Tensor 具有近乎一致的接口,在实际应用中可以无缝切换

2.2.3 神经网络

torch.nn是专门为神经网络设计得模块化接口。nn构建于Autograd 之上。

nn.Module是nn中最重要的类,包含网络各层的定义及forward方法,调用forward(input)方法,可返回向前传播的结果。

只要在nn.Module的子类中国定义了forward函数,backward函数就会被自动实现(利用Autograd)。在forward函数中可使用任何Variable支持的函数。

网络的科学系参数通过net.parameters()返回,net.named_parameters可同时返回科学系的参数及名称

3 Tensor 和 autograd

3.1 Tensor

3.1.1 基础操作

tensor 和 numpy 的接口设计类似。

从接口的角度讲,对tensor的操作分为两类:
(1)torch.function,如torch.save等。
(2)tensor.function,如tensor。view等。

从存储角度讲,对ensor的操作分为两类:
(1)不会修改自身的数据,如a.add(b)
(2)会修改自身的数据,如a.add_(b)
函数名以_结尾都是inplace方式,会修改调用者自己的数据。

创建Tensor

在这里插入图片描述
使用Tensor函数新建tensor方式多变,既可以接受一个list,并根据list的数据新建tensor,也可以根据指定的形状新建tensor,还能传入其他的tensor。

import torch as t
a = t.Tensor(2, 3) # 创建一个2*3的tensor
#用list的数据创建tensor
b = t.Tensor([[1, 2, 3],[4, 5, 6]])

# 查看torch.size()
b_size = b.size() # torch.Size([2, 3])

#创建一个和b形状相同的tensor
c = t.Tensor(b_size)

# 创建一个元素为2和3的tensor
d = t.Tensor((2, 3))

查看tensor的形状的两种方法:
tensor.size()
tensor.shape

常用Tensor操作
通过tensor.view方法可以调整tensor的形状,调整前后元素综述一致。

view不会修改自身的数据,返回的新tensor与原tensor共享内存。在实际应用中需添加或减少某一维度,使用sequeeze和unsequeeze函数

a = t.arange(0,6)
a.view(2, 3)	# tensor([[0, 1, 2],
			   	#	     [3, 4, 5]])
b = a.view(-1, 3)	#当某一维度为-1时,会自动计算它的大小
				#	tensor([[0, 1, 2],
				#	        [3, 4, 5]])
b.unsqueeze(1)	# 在第1维上增加1
				# tensor([[[0, 1, 2]],

				#	        [[3, 4, 5]]])
c = b.view(1, 1, 1, 2, 3)
c.squeeze(0)	# 压缩第0维
				# tensor([[[[0, 1, 2],
				#            [3, 4, 5]]]])
c.squeeze()		# 压缩所有为“1”的维度
				# tensor([[0, 1, 2],
				#       [3, 4, 5]])

resize 与 view 不同,可以修改tensor的尺寸。如果新尺寸超过原尺寸,会自动分配新的内存空间,如果新尺寸系哦啊与原尺寸,旧数据仍然会保存。

索引操作

Tensor支持与numpy.ndarray类似的索引操作,且语法上也类似。

a = t.randn(3, 4)
a[0] # 第0行
a[:, 0] # 第0列
a[0][2] # 第0行第2个元素  ==a[0, 2]
a[0, -1] # 第0行最后一个元素
a[:2] # 前两行
a[:2, :2] #前两行,第0,1列
a[0:1, :2] # 第0行,前两列 size 1*2
			# tensor([[-2.6012, -1.0866]])
a[0, :2]	# 第0行,前两列 size 2
			# tensor([-2.6012, -1.0866])
a[a>1]		# 等价于a.masked_select(a>1) , 选择结果不与原tensor共享内存
			# tensor([1.1954, 2.5044])

在这里插入图片描述

高级索引

高级索引可以看成是普通索引操作的扩展,但高级索引操作的结果一般不和原Tensor共享内存。

x = t.arange(0,27).view(3,3,3)
x[[1,2],[1,2],[1,2]] # 等价于 x[1,1,1] x[2,2,2]
x[[2,1,0],[0],[1]] # 等价于 x[2,0,1] x[1,0,1], x[0,0,1]
x[[0,2], ...] # 等价于 x[0] x[2]
Tensor类型

默认的tensor是FloatTensor,可通过t.set_default_tensor_type修改默认tensor类型
在这里插入图片描述
可通过type(new_type)转换数据类型。 还有float,long,half等快捷方法。

CPU tensor 和GPU tensor 之间的相互转换可以通过tensor.cuda 和 tensor.cpu 的方法实现。Tensor有一个new方法,用法同t.Tensor,调用对应的构造函数,生成与当前tensor类型一致的tensor。

#设置默认tensor
t.set_default_tensor_type('torch.IntTensor')
a = t.Tensor(2, 3)

#把a转成FloatTensor,等价于b = a.type(t.FloatTensor)
b = a.float() 

c = a.type_as(b) # 以b相同的数据类型保存a

d = a.new(2, 3) # 等价于torch.IntTensor(3, 4)
逐元素操作

在这里插入图片描述
在这里插入图片描述

# a中每一个元素都与3比较,其较大的一个
t.clamp(a, min = 3)
归并操作

在这里插入图片描述
以上大多数函数都有一个参数dim(对应于Numpy中的axis),用来指定这些操作是在哪个维度上执行的。

假设输入的形状是(m,n,k):

  1. 如果指定dim=0,输出的形状就是(1,n,k)或者(n,k);

siez中是否有1,取决于参数keepdim,keepdim=True会保留维度1。从Pytorch0.2.0版本起,keepdim默认为False

b = t. ones(2, 3)
b.sum(dim = 0, keepdim=True# 2 2 2   (size 1*3)
c.sum(dim = 0)  # 2
				# 2
				# 2   (size 3)
比较

在这里插入图片描述
其中max/min 操作比较特殊,以max为例,有以下三种情况

  • t.max(tensor): 返回tensor中最大的一个数
  • t.max(tensor, dim): 指定维上最大的数,返回tensor和下标
  • t.max(tensor1, tensor2): 比较两个tensor,返回较大tensor的元素
线性代数

Pytorch的线性函数主要封装了Blas和Lapack,其用法和接口都与之类似。
在这里插入图片描述

注:矩阵的转置会导致存储空间不连续,需调用.contiguous方法将其转为连续。

b = a.t()
b.is_contiguous() # False
b.contiguous()  

3.1.2 Tensor 和 Numpy

Tensor 和 Numpy 数组之间具有很高的相似性。Numpy和Tensor共享内存。当Tensor不支持的操作时,可先转为Numpy数组,处理后再转回tensor。

  • 当输入数组的某维度长度为1时,计算时沿此维度复制扩充成一样的形状。
    pytorch当前支持自动广播法则,但建议使用以下两个函数组合手动实现。
  • unsqueeze 或者view: 为数据某一维的形状补1,实现法则1
  • expand或者expand_as,重复数组,实现法则3;该操作不会复制数组,所以不会占用额外的空间。
    注: repeat 实现与expand想类似的功能,但是repeat会把相同数据复制多份,占用额外的空间
import numpy as np
import torch as t
a = np.ones([2, 3],dtype=np.float32)
b = t.from_numpy(32) # 将numpy对象传入tensor
b = t.Tensor(a)	# 将numpy对象传入tensor,若numpy类型不是Float32会新建
c = b.numpy() # 将tensor对象转换成numpy
			  # a,b,c公用内存

Numpy的广播法则:

  • 让所有输入数组都像其中shape最长的数组看齐,shape中不足的部分通过在前面加1补齐
  • 两个数组要么在某一个维度的长度一致,要么其中一个为1,否则不能计算。

3.1.3 内部结构

tensor 分为头信息区(Tensor)和存储区(Storage),信息区主要保存着tensor的形状(size),步长(stride),数据类型(type)等信息,而真正的数据则保存成联系数组。在这里插入图片描述
在这里插入图片描述

3.1.4 其他有关Tensor的话题

持久化
Tensor的保存: t.save
Tensor的加载:t.load
在save/load时刻指定使用的pickle模块,在load时还可以将GPU tensor映射到CPU或其他GPU上。

if t.cuda.is_available():
	a = a.cuda(1) # 把a转换为GPU1上的tensor
	t.save(a, 'a.pth')
	# 加载为b,存储于GPU1上(因为保存时tensor就在GPU1上)
	b = t.load('a.pth')
	# 加载为c,存储于CPU
	c = t.load('a.pth', map_location=lambda storage, loc: storage)
	# 加载为d,存储于GPU0上
	d = t.load('a.pth', map_location={'cuda:1':'cuda:0'})

向量化
向量化计算时一种特殊的并行计算方式,可在同一时间执行多个操作,通常是对不同的数据执行同样的一个或一批指令,或者说把指令应用于一个数组/向量上。

注意:

  • 大多数t.function都有一个参数out,这时产生的结果都将保存在out指定的tensor之中。
  • t.set_num_threads 可以设置Pytorch进行CPU多线程并行计算时所占用的线程数,用来限制Pytorch所占用的CPU数目。
  • t.set_printoptions 可以用来设置打印tensor时的数值进度和格式。

3.2 autograd

3.2.1 Variable

autograd中的核心数据结构是Variable。Variable封装了tensor,其中主要包含了三个属性:

  • data:保存variable所包含的tensor
  • grad:保存data对应的梯度,grad也是variable,与data形状一致
  • grad_fn:指向一个Function,记录variable的操作历史
    在这里插入图片描述
    Variable的构造函数需要传入tensor,同时有两个可选参数。
  • requires_grad(bool):是否需要对该variable进行求导
  • volatile(bool): 意为“挥发”,设置为True,构建在该variable上的图都不会求导,专为推理阶段设计。

Variable支持大部分的tensor支持的函数,但不支持部分inplace函数。在反向传播中,variable需要缓存原来的tensor来计算梯度。如果想要计算各个Variable的梯度,只需调用根节点的backward方法,Auto果然多会自动沿着计算图反向传播,计算每一个叶子节点的梯度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值