一、计算图与动态图机制
计算图是用来描述运算的有向无环图。计算图有两个主要元素:结点(Node)和边(Edge)。结点表示数据,如向量,矩阵,张量;边表示运算,如加减乘除卷积等。下面用计算图表示:
y
=
(
x
+
w
)
∗
(
w
+
1
)
y =(x+ w)* (w+1)
y=(x+w)∗(w+1)
采用计算图描述运算的好处:不仅使得运算更加简洁,而且使得梯度求导更加方便。下面用代码展示上述计算图梯度求导过程:
import torch
# 需要计算梯度-requires_grad=True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
# 前向传播
a = torch.add(w, x) # retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)
# 反向传播-自动求导
y.backward()
print(w.grad)
# 5
由第2节,我们可以知道Tensor中有叶子节点(is_leaf)与grad_fn的概念
叶子结点︰用户创建的结点称为叶子结点,如 x 与 w x与w x与w
is_leaf:指示张量是否为叶子结点
为什么要设置叶子节点这一概念?主要是为了节省内存,在梯度反向传播之后,非叶子节点的梯度是会被释放掉的。
import torch
# 需要计算梯度-requires_grad=True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
# 前向传播
a = torch.add(w, x) # retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)
# 反向传播-自动求导
y.backward()
print(w.grad)
# 查看叶子结点
print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)
# 查看梯度
print("gradient:\n", w.grad, x.grad, a.grad, b.grad, y.grad)
is_leaf:
True True False False False
gradient:
tensor([5.]) tensor([2.]) None None None
如果我们想要保存非叶子节点的梯度,那么应该怎么做呢?
import torch
# 需要计算梯度-requires_grad=True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
# 前向传播
a = torch.add(w, x)
# 保存非叶子节点a的梯度
a.retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)
# 反向传播-自动求导
y.backward()
print(w.grad)
# 查看叶子结点
print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)
# 查看梯度
print("gradient:\n", w.grad, x.grad, a.grad, b.grad, y.grad)
tensor([5.])
is_leaf:
True True False False False
gradient:
tensor([5.]) tensor([2.]) tensor([2.]) None None
grad_fn:grad_fn:记录创建该张量时所用的方法(函数),是自动求导的关键
import torch
# 需要计算梯度-requires_grad=True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
# 前向传播
a = torch.add(w, x)
# 保存非叶子节点a的梯度
a.retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)
# 反向传播-自动求导
y.backward()
print(w.grad)
# 查看创建张良所使用的函数
print("grad_fn:\n", w.grad_fn, x.grad_fn, a.grad_fn, b.grad_fn, y.grad_fn)
tensor([5.])
grad_fn:
None None <AddBackward0 object at 0x0000021BCD8FB710> <AddBackward0 object at 0x0000021BCD900128> <MulBackward0 object at 0x0000021BCD9000F0>
1.静态图与动态图
根据计算图搭建方式,可将计算图分为静态图与动态图。静态图是先搭建图后运算。静态图的特点:高效不灵活。TensorFlow是静态图。动态图是运算与搭建同时进行。动态图的特点:灵活易调节。PyTorch是动态图。
二、torch.autograd—自动求导系统
深度学习模型的训练就是不断更新权值。权值的更新需要求解梯度。PyTorch提供自动求导系统解决这一问题。自动求导系统autograd只需要搭建前向传播的计算图,然后通过torch.autograd就可以得到每个张量的梯度。下面我们讲解torch.autograd中的方法。
torch.autograd.backward()
torch.autograd.backward(tensors,
grad_tensors=None,
retain_graph=None,create_graph=False)
功能:自动求取梯度
-
tensors:用于求导的张量,如loss
-
retain_graph :保存计算图(如果想多次使用计算图)
-
create_graph :创建导数计算图,用于高阶求导
-
grad_tensors:多梯度权重(用于多个梯度权重的设置)
w = torch.tensor([1.], requires_grad=True) x = torch.tensor([2.], requires_grad=True) a = torch.add(w, x) # retain_grad() b = torch.add(w, 1) y0 = torch.mul(a, b) # y0 = (x+w) * (w+1) y1 = torch.add(a, b) # y1 = (x+w) + (w+1) dy1/dw = 2 loss = torch.cat([y0, y1], dim=0) # [y0, y1] grad_tensors = torch.tensor([1., 2.]) loss.backward(gradient=grad_tensors) # gradient 传入 torch.autograd.backward()中的grad_tensors print(w.grad)
tensor([9.])
torch.autograd.grad()
torch.autograd.grad(outputs,
inputs,grad_outputs=None,
retain_graph=None,create_graph=False)
功能:求取梯度
-
outputs: 用于求导的张量,如 loss
-
inputs :需要梯度的张量
-
create_graph :创建导数计算图,用于高阶求导
-
retain_graph :保存计算图
-
grad_outputs:多梯度权重
x = torch.tensor([3.], requires_grad=True) y = torch.pow(x, 2) # y = x**2 grad_1 = torch.autograd.grad(y, x, create_graph=True) # grad_1 = dy/dx = 2x = 2 * 3 = 6 print(grad_1) grad_2 = torch.autograd.grad(grad_1[0], x) # grad_2 = d(dy/dx)/dx = d(2x)/dx = 2 print(grad_2)
(tensor([6.], grad_fn=<MulBackward0>),) (tensor([2.]),)
torch.autograd()
中需要注意如下几点:
-
梯度不自动清零,需要手动清零
w = torch.tensor([1.], requires_grad=True) x = torch.tensor([2.], requires_grad=True) for i in range(4): a = torch.add(w, x) b = torch.add(w, 1) y = torch.mul(a, b) y.backward() print(w.grad) # 梯度清零 # w.grad.zero_()
tensor([5.]) tensor([10.]) tensor([15.]) tensor([20.])
-
依赖于叶子节点的节点,requires_grad默认为True
w = torch.tensor([1.], requires_grad=True) x = torch.tensor([2.], requires_grad=True) a = torch.add(w, x) b = torch.add(w, 1) y = torch.mul(a, b) print(a.requires_grad, b.requires_grad, y.requires_grad)
True True True
-
叶子节点不可执行in-place(原地操作)
如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!