pytorch学习记录(2) Autograd

2 AutoGrad

2.1 autograd基础操作

  • 计算梯度:z.backward()

    沿着计算图的每一条边计算梯度,直到叶子节点为止

  • 查看梯度:x.grad
    ∂ z ∂ x \frac{\partial z}{\partial x} xz
    注意:

  • 默认参数backward(retain_graph=False)下,计算图graph会被清空,如需保留,设置retain_graph=True

  • 如果多次调用backward()函数(训练的时候多次循环),梯度会不断累加,所以在下一次求梯度之前,要使用net.zero_grad()将梯度清零,或者x.grad.zero_() 也可以

  • 默认requires_grad=False,而且tensor类型必须是float

    需要求梯度:x = torch.tensor([2,2],requires_grad=True,dtype = torch.float)

def f(a):
    return sum(a**2)
    
x = torch.tensor([2,2],requires_grad=True,dtype = torch.float)
y = x+1
z = f(y)
print(x,y,z)

if x.grad is not None:
    x.grad.zero_() # 梯度清零
    
z.backward()
print(x.grad)	# tensor([6., 6.])
x.grad.zero_() 
print(x.grad)  # tensor([0., 0.])

y.backward()  # 会报错,因为y不是一个标量,只能对标量进行求导
			  # Error: grad can be implicitly created only for scalar outputs
# 真的想要求梯度,可以在调⽤ backward 时需要传⼊⼀个和 y 同形的权重向量进⾏加权求和得到⼀个标量。
v = torch.tensor([2.,1.])
if x.grad is not None:
    x.grad.zero_()
y.backward(v)
print(x.grad) # tensor([2., 1.])

2.2 自定义autograd

通过继承torch.autograd.Function可以定义自己的函数,并实现相应的梯度计算,

需要实现forward()backward()

  • 属性(成员变量)
    saved_tensors: 传给forward()的参数,在backward()中会用到。
    needs_input_grad:长度为 :attr:num_inputsbool元组,表示输出是否需要梯度。可以用于优化反向过程的缓存。
    num_inputs: 传给函数 :func:forward的参数的数量。
    num_outputs: 函数 :func:forward返回的值的数目。
    requires_grad: 布尔值,表示函数 :func:backward 是否永远不会被调用。

  • 成员函数
    forward()
    forward()可以有任意多个输入、任意多个输出,但是输入和输出必须是Variable。(官方给的例子中有只传入tensor作为参数的例子)
    backward()
    backward()的输入和输出的个数就是forward()函数的输出和输入的个数。其中,backward()输入表示关于forward()输出的梯度(计算图中上一节点的梯度),backward()的输出表示关于forward()的输入的梯度。在输入不需要梯度时(通过查看needs_input_grad参数)或者不可导时,可以返回None

from torch.autograd import Function as Function
class Exp(Function):
    @staticmethod
    def forward(ctx,x):
        result = x.exp()
        ctx.save_for_backward(result)			# ctx可以理解为用于梯度缓存
        return result
    @staticmethod
    def backward(ctx,grad_output):				# backward() 就是在定义怎么对forward()求梯度
        result, = ctx.save_tensors
        return grad_output * result
my_exp = Exp.apply # convert to function

x = torch.tensor([1.,2.],requires_grad = True)

y = my_exp(x)
print(y)				# tensor([2.7183, 7.3891], grad_fn=<ExpBackward>)
print(x.exp())

y.sum().backward()
print(x.grad)			# tensor([2.7183, 7.3891])
class my_flip(Function):
    @staticmethod
    def forward(ctx,x):
        return x
    @staticmethod
    def backward(ctx,grad_output):    # 求导的结果是-1,用在链式法则里面,就是整体梯度反转
        return -1.0*grad_output

flip=my_flip.apply
x = torch.tensor([1.,2.],requires_grad=True)
xx = my_exp(x)
y = flip(xx)
print(y)						# tensor([2.7183, 7.3891], grad_fn=<my_flipBackward>)
z = y.sum()
print(z)						# tensor(10.1073, grad_fn=<SumBackward0>)
z.backward()
print(x.grad)					# tensor([-2.7183, -7.3891])

猜你喜欢

转载自blog.csdn.net/qq_33993729/article/details/107142375