人工智能:损失函数对标量、向量、矩阵求导的是如何计算的?

专栏推荐



正文

深度学习框架pytorch拥有自动求导的机制,自动求导是 PyTorch 中非常重要的特性,能够让我们避免手动去计算非常复杂的导数,这能够极大地减少了我们构建模型的时间。

人工智能:损失函数对标量、向量、矩阵求导的是如何计算的?


人工智能:损失函数对标量、向量、矩阵求导的是如何计算的?


导入的包

import torch

from torch.autograd import Variable

对标量进行自动求导

x = Variable(torch.Tensor([2]), requires_grad=True)

y = x + 2

z = y ** 2 + 3

print(z)

z.backward()

print(x.grad)

我们可以看到变量x在申明的时候,指定了requires_grad=True,这样和x进行运算的所有变量都相当于设置了requires_grad=True,比如y、z都相当于设置了requires_grad=True。这样我们就可以使用反向传播了,本例中z.backward()就是表示的执行反向传播,最后x.grad表示的是z对x的偏导数。

对矩阵求梯度

x = Variable(torch.randn(10, 20), requires_grad=True)

y = Variable(torch.randn(10, 5), requires_grad=True)

w = Variable(torch.randn(20, 5), requires_grad=True)

out = torch.mean(y - torch.matmul(x, w))

out.backward()

print(x.grad)

print(w.grad)

本例中我们申明了三个矩阵,分别是x、y、w,然后我们对其进行计算操作。torch.matmul 是做矩阵乘法,torch.mean是做均值化。然后执行反向传播就可以获取到矩阵x的梯度了。

在pytorch0.4之后Variable 正式合并入Tensor, Variable 本来实现的自动微分功能,Tensor就能支持,所以我们可以直接在创建tensor的时候,使用autograd功能,只需要设置tensor.requries_grad=True.

x = t.ones(2, 2, requires_grad=True)

这样这个x就可以自动求导了

y = w * x + b

x=torch.ones(1)

b=torch.rand(1,requires_grad=True)

w=torch.rand(2,requires_grad=True)

z=w*x

y=z+b

y.backward()#自动求导,它会对所有需要求梯度的变量进行求导,然后得到他们的梯度。y.backward()等价于y.backward(torch.FloatTensor([1])),因为我们上面求得梯度都是标量(维度是1,所以torch.FloatTensor([1])),backward中的参数就没有必要来写了。

求完梯度之后,我们就可以使用属性grad来求出每个变量的梯度

print (x.grad) #求变量x的梯度,梯度为w,也就是2

print(w.grad)#求变量w的梯度,梯度为x,也就是1

print (b. grad)#求变量b的梯度,梯度为常数1

人工智能:损失函数对标量、向量、矩阵求导的是如何计算的?

我们前面是对我们的标量进行求导,我们也可以来对我们的矩阵进行求导

x = torch.randn(3) #创建一个随机矩阵,类型是tensor,x的结果为tensor([-0.2895, 0.7542, -1.3040])

x=Variable(x, requires_grad=True) #我们将tensor转成变量

y= x * 2 #构建计算图print (y)

y.backward(torch.FloatTensor( [1, 1,1])) #对变量进行求梯度,因为我们的矩阵是三维的,所以我们需要torch.FloatTensor( [1, 1,1])

print (x. grad) #输出变量x的梯度,结果为:tensor([2., 2., 2.]),因为我们的tensor为三行一列的向量,所以我们的梯度需要[1,1,1]表示对这个向量中的每一个进行求梯度。

我们也可以y.backward(torch.FloatTensor( [1, 0.1 , 0. 01] )) ,这样得到的梯度就是它们原本的梯度分别乘上 1 , 0.1 和 0.01,结果为:

tensor([2.0000, 0.2000, 0.0200])

可运行代码为:

import torch

from torch.autograd import Variable

x= torch.randn(3) #创建一个随机矩阵,1行3列,类型是tensor

print(x)

x=Variable(x, requires_grad=True)

print(x)

y=x*2

y.backward(torch.FloatTensor([1,1,1]))

print(x.grad)

结果为:

人工智能:损失函数对标量、向量、矩阵求导的是如何计算的?

对矩阵求梯度

import torch

from torch.autograd import Variable

x= torch.randn(2,3) #创建一个随机矩阵,1行3列,类型是tensor

print(x)

x=Variable(x, requires_grad=True)

print(x)

y=x*2

y.backward(torch.FloatTensor([[1,0.1,0.01],[1,1,1]]))

print(x.grad)

如果我们要是将x= torch.randn(2,3),建立一个两行三列的,那么我们的这里y.backward(torch.FloatTensor([[1,0.1,0.01],[1,1,1]]))也要两行三列,这样才能一一对应,结果为:

人工智能:损失函数对标量、向量、矩阵求导的是如何计算的?

多次自动求导

#调用 backward就会自动反向求导,但是求导完之后计算图就会被丢弃,以后就不能调用backward了,为了防止这种情况,我们可以在自动求导的时候,指定不丢弃计算图retain_graph=True。

x=torch.randn(3)

x=Variable(x,requires_grad=True)

y=x*3

y.backward(torch.FloatTensor([1,1,1]),retain_graph=True)#第一次求导

print(x.grad)

x.grad.data.zero_() # 归零之前求得的梯度

y.backward(torch.FloatTensor([1,1,1]))#第二次求导

print(x.grad)



分享到:


相關文章: