更多深度文章,请关注:https://yq.aliyun.com/cloud
PyTorch 由于使用了强大的 GPU 加速的 Tensor 计算(类似 numpy)和基于 tape 的 autograd 系统的深度神经网络。这使得今年一月份被开源的 PyTorch 成为了深度学习领域新流行框架,许多新的论文在发表过程中都加入了大多数人不理解的 PyTorch 代码。这篇文章我们就来讲述一下我对 PyTorch 代码的理解,希望能帮助你阅读 PyTorch 代码。整个过程是基于贾斯汀 · 约翰逊的伟大教程。如果你想了解更多或者有超过 10 分钟的时间,建议你去读下整篇代码。
PyTorch 由 4 个主要包装组成:
1. 导入工具
你可以这样导入 PyTorch:
- import torch # arrays on GPU
- import torch.autograd as autograd #build a computational graph
- import torch.nn as nn # neural net library
- import torch.nn.functional as F # most non-linearities are here
- import torch.optim as optim # optimization package
2.torch 数组取代了 numpy ndarray - > 在 GPU 支持下提供线性代数
第一个特色,PyTorch 提供了一个像 Numpy 数组一样的多维数组,当数据类型被转换为(torch.cuda.TensorFloat)时,可以在 GPU 上进行处理。这个数组和它的关联函数是一般的科学计算工具。
从下面的代码中,我们可以发现,PyTorch 提供的这个包的功能可以将我们常用的二维数组变成 GPU 可以处理的三维数组。这极大的提高了 GPU 的利用效率,提升了计算速度。
大家可以自己比较 Torch 和 numpy ,从而发现他们的优缺点。
- # 2 matrices of size 2x3 into a 3d tensor 2x2x3
- d=[[[1., 2.,3.],[4.,5.,6.]],[[7.,8.,9.],[11.,12.,13.]]]
- d=torch.Tensor(d) # array from python list
- print "shape of the tensor:",d.size()
- # the first index is the depth
- z=d[0]+d[1]
- print "adding up the two matrices of the 3d tensor:",z
- shape of the tensor: torch.Size([2, 2, 3])
- adding up the two matrices of the 3d tensor:
- 8 10 12
- 15 17 19
- [torch.FloatTensor of size 2x3]
- # a heavily used operation is reshaping of tensors using .view()
- print d.view(2,-1) #-1 makes torch infer the second dim
- 1 2 3 4 5 6
- 7 8 9 11 12 13
- [torch.FloatTensor of size 2x6]
3.torch.autograd 可以生成一个计算图 - > 自动计算梯度
第二个特色是 autograd 包,其提供了定义计算图的能力,以便我们可以自动计算渐变梯度。在计算图中,一个节点是一个数组,边(edge)是 on 数组的一个操作。要做一个计算图,我们需要在(torch.aurograd.Variable())函数中通过包装数组来创建一个节点。那么我们在这个节点上所做的所有操作都将被定义为边,它们将是计算图中新的节点。图中的每个节点都有一个(node.data)属性,它是一个多维数组和一个(node.grad)属性,这是相对于一些标量值的渐变(node.grad 也是一个. Variable()) 。在定义计算图之后,我们可以使用单个命令(loss.backward())来计算图中所有节点的损耗梯度。
- # d is a tensor not a node, to create a node based on it:
- x= autograd.Variable(d, requires_grad=True)
- print "the node's data is the tensor:", x.data.size()
- print "the node's gradient is empty at creation:", x.grad # the grad is empty right now
- the node's data is the tensor: torch.Size([2, 2, 3])
- the node's gradient is empty at creation: None
- # do operation on the node to make a computational graph
- y= x+1
- z=x+y
- s=z.sum()
- print s.creator
- <torch.autograd._functions.reduce.Sum object at 0x7f1e59988790>
- # calculate gradients
- s.backward()
- print "the variable now has gradients:",x.grad
- the variable now has gradients: Variable containing:
- (0 ,.,.) =
- 2 2 2
- 2 2 2
- (1 ,.,.) =
- 2 2 2
- 2 2 2
- [torch.FloatTensor of size 2x2x3]
4.torch.nn 包含各种 NN 层(张量行的线性映射)+(非线性)-->
其作用是有助于构建神经网络计算图,而无需手动操纵张量和参数,减少不必要的麻烦。
第三个特色是高级神经网络库(torch.nn),其抽象出了神经网络层中的所有参数处理,以便于在通过几个命令(例如 torch.nn.conv)就很容易地定义 NN。这个包也带有流行的损失函数的功能(例如 torch.nn.MSEloss)。我们首先定义一个模型容器,例如使用(torch.nn.Sequential)的层序列的模型,然后在序列中列出我们期望的层。这个高级神经网络库也可以处理其他的事情,我们可以使用(model.parameters())访问参数(Variable())
- # linear transformation of a 2x5 matrix into a 2x3 matrix
- linear_map=nn.Linear(5,3)
- print "using randomly initialized params:", linear_map.parameters
- using randomly initialized params: <bound method Linear.parameters of Linear (5 -> 3)>
- # data has 2 examples with 5 features and 3 target
- data=torch.randn(2,5) # training
- y=autograd.Variable(torch.randn(2,3)) # target
- # make a node
- x=autograd.Variable(data, requires_grad=True)
- # apply transformation to a node creates a computational graph
- a=linear_map(x)
- z=F.relu(a)
- o=F.softmax(z)
- print "output of softmax as a probability distribution:", o.data.view(1,-1)
- # loss function
- loss_func=nn.MSELoss() #instantiate loss function
- L=loss_func(z,y) # calculateMSE loss between output and target
- print "Loss:", L
- output of softmax as a probability distribution:
- 0.2092 0.1979 0.5929 0.4343 0.3038 0.2619
- [torch.FloatTensor of size 1x6]
- Loss: Variable containing:
- 2.9838
- [torch.FloatTensor of size 1]
我们还可以通过子类(torch.nn.Module)定义自定义层,并实现接受(Variable())作为输入的(forward())函数,并产生(Variable())作为输出。我们也可以通过定义一个时间变化的层来做一个动态网络。
- class Log_reg_classifier(nn.Module):
- def __init__(self, in_size,out_size):
- super(Log_reg_classifier,self).__init__() #always call parent's init
- self.linear=nn.Linear(in_size, out_size) #layer parameters
- def forward(self,vect):
- return F.log_softmax(self.linear(vect)) #
5.torch.optim 也可以做优化—>
我们使用 torch.nn 构建一个 nn 计算图,使用 torch.autograd 来计算梯度,然后将它们提供给 torch.optim 来更新网络参数。
第四个特色是与 NN 库一起工作的优化软件包(torch.optim)。该库包含复杂的优化器,如 Adam,RMSprop 等。我们定义一个优化器并传递网络参数和学习率(opt = torch.optim.Adam(model.parameters(),lr = learning_rate)),然后我们调用(opt.step())对我们的参数进行近一步更新。
- optimizer=optim.SGD(linear_map.parameters(),lr=1e-2) # instantiate optimizer with model params + learning rate
- # epoch loop: we run following until convergence
- optimizer.zero_grad() # make gradients zero
- L.backward(retain_variables=True)
- optimizer.step()
- print L
- Variable containing:
- 2.9838
- [torch.FloatTensor of size 1]
建立神经网络很容易,但是如何协同工作并不容易。这是一个示例显示如何协同工作:
- # define model
- model = Log_reg_classifier(10,2)
- # define loss function
- loss_func=nn.MSELoss()
- # define optimizer
- optimizer=optim.SGD(model.parameters(),lr=1e-1)
- # send data through model in minibatches for 10 epochs
- for epoch in range(10):
- for minibatch, target in data:
- model.zero_grad() # pytorch accumulates gradients, making them zero for each minibatch
- #forward pass
- out=model(autograd.Variable(minibatch))
- #backward pass
- L=loss_func(out,target) #calculate loss
- L.backward() # calculate gradients
- optimizer.step() # make an update step
希望上述的介绍能够帮你更好的阅读 PyTorch 代码。
本文由北邮 @爱可可 - 爱生活老师推荐,阿里云云栖社区组织翻译。
文章原标题《Understand PyTorch code in 10 minutes》,
作者: Hamidreza Saghir,机器学习研究员 - 多伦多大学博士生 译者:袁虎 审阅:阿福
文章为简译,更为详细的内容,请查看原文
来源: https://yq.aliyun.com/articles/114620