pytorch计算图

Pytorch中的神经网络

pytorch的计算图

pytorch是动态图机制,所以在训练模型的时候,每迭代一次都会构建一个新的计算图。而计算图代表着程序中变量之间的关系。 y = ( a + b ) ( b + c ) y=(a+b)(b+c) y=(a+b)(b+c)在这个运算过程就会建立一个如下的计算图。在这个计算图中,叶子节点(leaf_node)就是参与运算的变量。这个图里面只有a,b,c是leaf_node。之所以要关注leaf_node,因为计算网络在反向传播的时候,需要根据链式求导法则求出网络最后输出的梯度,然后再对网络进行优化。

pytorch计算图_第1张图片
注意:pytoch构建的计算图是动态图,为了节约内存,所以每次一轮迭代完之后计算图就被在内存释放。
例如:

net = nn.Linear(3, 4)  # 一层的网络,也可以算是一个计算图就构建好了
input = torch.randn((20,3),requires_grad=True)  # 定义一个图的输入变量
output = net(input)  # 最后的输出
loss = torch.sum(output)  # 这边加了一个sum() ,因为被backward只能是标量
loss.backward() #计算当前tensor对图叶子结点的梯度。 到这计算图已经结束,计算图被释放了
#再次执行backward()的时候,会提示错误。
#可以在反向传播的时候添加一个标识,例如loss.backward(retain_graph=True),添加上之后计算图不会立即被释放。

对计算图中的反向传播进一步理解。

x = torch.tensor([[1, 2]],dtype=torch.float32,requires_grad=True)  # 定义一个输入变量
y = torch.tensor([[3, 4], [5, 6]],dtype=torch.float32)
loss = torch.mm(x, y)    # 矩阵乘积
loss.backward(torch.tensor([[1, 0]],dtype=torch.float32), retain_graph=True) # 求梯度,保留图 。                                  
print(x.grad.data)   # 求出 x_1 的梯度
x.grad.data.zero_()  # 最后的梯度会累加到叶节点,所以叶节点清零
loss.backward(torch.FloatTensor([[0, 1]]))   # 求出 x_2的梯度
print(x.grad.data)        # 求出 x_2的梯度

输出结果

tensor([[3., 5.]])
tensor([[4., 6.]])

上面的过程等价于下面的数学表达式:
pytorch计算图_第2张图片

pytorch的计算图中,只有两种元素: 数据(tensor)和运算。tensor可以分为两类,叶子节点(leaf node)和非叶子节点。使用backward()函数反向传播计算tensor的梯度时,并不计算所有tensor的梯度,而是只计算满足这几个条件的tensor的梯度:1.类型为叶子节点、2.requires_grad=True、3.依赖该tensor的所有tensor的requires_grad=True。

自己定义的tensor中,requires_grad属性默认是False,而神经网络中的权重w的tensor中requires_grad属性默认为True。

Autograd自动求导

autograd包提供Tensor所有操作的自动求导方法。
torch.Tensor是这个包里面最重要的类。如果设置了requires_grad为True,那么它开始追踪所有在它上面的操作。当你完成了计算,可以使用调用backward(),回自动计算所有的梯度。然后这个tensor的梯度会被自动累积到grad属性上。

结束一个tensor的追踪历史,可以调用detach()方法,与之前的计算历史分离。并且阻断未来的计算追踪。

参考:
colah’s blog
pytorch的计算图-知乎
https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html

你可能感兴趣的:(pytorch)