精华内容
下载资源
问答
  • 矩阵基本知识以及矩阵求导,蛮不错的,硬盘里翻出来的,之前下载的
  • 矩阵求导

    2020-12-04 23:32:07
    也就是实值函数f矩阵X求导其实就是fX的各元素分别求导得到一个与X同型的矩阵。比如 且f(X)=x + 2y + 3z + 4w,则 再比如正规方程推导那篇文章中的例子,设 ,则 矩阵标量的求导 如果函数f把实数x映射...

    一、矩阵和向量求导

    参考地址:https://cloud.tencent.com/developer/article/1668818

    求导公式大全:https://cloud.tencent.com/developer/article/1551901  

    机器学习中最常用的矩阵求导有:标量对矩阵的求导,矩阵对标量求导以及向量对向量的求导。下面分别对这几种求导方式进行介绍。

    标量对矩阵的求导

    如果函数f把一个元素为实数的m×n矩阵,映射为一个实数,求导其实就是实值函数f对矩阵X求导其实就是f对X的各元素分别求导得到一个与X同型的矩阵。比如


    Y = A' * X * B --> DY/DX = A * B'       其中 A(m,1) ,X(m,n) ,B(n,1)
    Y = A' * X' * B --> DY/DX = B * A'

    以Y = A' * X * B 为例:

    我们先直接计算y

    故y对x求导为

    也可以参见求导公式 

     

    矩阵对标量的求导

    如果函数f把实数x映射成一个元素为实数的m×n矩阵

    也就是矩阵Y对实数x求导其实就是矩阵的各元素分别对x求导得到一个与Y同型的矩阵。

    以Y=A*x为例,求导为A

    求导就是分别将y1,y2对x进行求导,结果为

     

    向量对向量的求导

    如果函数f把元素为实数的n维向量映射成一个元素为实数的m维Y向量(多元线性函数的组合)

    也就是m维向量Y对n维向量X求导其实就是Y向量的第一个元素对X向量的各元素分别求导形成结果矩阵的第一行,Y向量的第二个元素对X向量的各元素分别求导形成结果矩阵的第二行,以此类推,最后得到一个m×n的矩阵。

    Y = A * X --> DY/DX = A'        
    Y = X * A --> DY/DX = A

    以Y = A * X求导过程为例

    故分别将y1、y2对x1、x2求导的结果为:

     

    参考地址:https://cloud.tencent.com/developer/article/1551901

    二、几种重要的矩阵

    1、梯度(Gradient)

     2、雅克比矩阵(Jacobian matrix)

     3、海森矩阵(Hessian matrix)

    展开全文
  • pytorch求导

    千次阅读 2020-03-27 10:13:18
    前言:构建深度学习模型的基本流程就是:搭建计算图,求得损失函数,然后计算损失函数模型参数的导数,再利用梯度下降法等方法来更新参数。搭建计算图的过程,称为“正向传播”,这个是需要我们自己动手的,因为...

    前言:构建深度学习模型的基本流程就是:搭建计算图,求得损失函数,然后计算损失函数对模型参数的导数,再利用梯度下降法等方法来更新参数。搭建计算图的过程,称为“正向传播”,这个是需要我们自己动手的,因为我们需要设计我们模型的结构。由损失函数求导的过程,称为“反向传播”,求导是件辛苦事儿,所以自动求导基本上是各种深度学习框架的基本功能和最重要的功能之一,PyTorch也不例外,后面有时间会写一下tensorflow和mxnet框架的自动求导。

    默认已经具备了导数相关知识,会矩阵,向量,标量之间的求导法则。

    一、pytorch自动求导初步认识

    比如有一个函数,y=x的平方(y=x2),在x=3的时候它的导数为6,我们通过代码来演示这样一个过程。

    x = torch.tensor(3.0, requires_grad=True)
    y = torch.pow(x, 2)
    print(x.requires_grad)
    print(y.requires_grad)
    y.backward()
    print(x.grad)
    

    最终的运行结果为:

    True
    True
    tensor(6.)   #这和我们自己算的是一模一样的。

    这里有一些关键点,

    1.1 tensor的创建与属性设置

    先来看一下tensor的定义:

    tensor(data, dtype=None, device=None, requires_grad=False) -> Tensor
     
    参数:
        data: (array_like): tensor的初始值. 可以是列表,元组,numpy数组,标量等;
        dtype: tensor元素的数据类型
        device: 指定CPU或者是GPU设备,默认是None
        requires_grad:是否可以求导,即求梯度,默认是False,即不可导的
    

    (1)tensor对象的requires_grad属性

    每一个tensor都有一个requires_grad属性,表示这个tensor是否是可求导的,如果是true则可以求导,否则不能求导,语法格式为:

    x.requires_grad    判断一个tensor是否可以求导,返回布尔值

    需要注意的是,只有当所有的“叶子变量”,即所谓的leaf variable都是不可求导的,那函数y才是不能求导的,什么是leaf variable呢?这其实涉及到“计算图”相关的知识,但是我们通过下面的例子一下就能明白了,如下:

    
    #创建一个二元函数,即z=f(x,y)=x2+y2,x可求导,y设置不可求导
    x=torch.tensor(3.0,requires_grad=True)
    y=torch.tensor(4.0,requires_grad=False)
    z=torch.pow(x,2)+torch.pow(y,2)
     
    #判断x,y是否是可以求导的
    print(x.requires_grad)
    print(y.requires_grad)
    print(z.requires_grad)
     
    #求导,通过backward函数来实现
    z.backward()  
     
    #查看导数,也即所谓的梯度
    print(x.grad)
    print(y.grad)
     
    '''运行结果为:
    True       # x是可导的
    False      # y是不可导的
    True       # z是可导的,因为它有一个 leaf variable 是可导的,即x可导
    tensor(6.) # x的导数
    None       # 因为y不可导,所以是none
    '''
    

    如果是上面的 leaf variable变量x也设置为不可导的,那么z也不可导,因为x、y均不可导,那么z自然不可导了。

    (2)leaf variable(也是tensor)的requires_grad_()方法

    如果某一个叶子变量,开始时不可导的,后面想设置它可导,或者反过来,该怎么办呢?tensor提供了一个方法,即

    x.requires_grad_(True/False)   设置tensor的可导与不可导,注意后面有一个下划线哦!

    但是需要注意的是,我只能够设置叶子变量,即leaf variable的这个方法,否则会出现以下错误:

    RuntimeError: you can only change requires_grad flags of leaf variables.

    1.2 函数的求导方法——y.backward()方法

    上面只演示了简单函数的求导法则,

    需要注意的是:如果出现了复合函数,比如 y是x的函数,z是y的函数,f是z的函数,那么在求导的时候,会使用 f.backwrad()只会默认求f对于叶子变量leaf variable的导数值,而对于中间变量y、z的导数值是不知道的,直接通过x.grad是知道的、y.grad、z.grad的值为none。

    下面来看一下这个函数backward的定义:

    backward(gradient=None, retain_graph=None, create_graph=False)
     

    它的三个参数都是可选的,上面的示例中还没有用到任何一个参数,关于这三个参数,我后面会详细说到,这里先跳过。

    1.3 查看求得的导数的值——x.grad属性

    通过tensor的grad属性查看所求得的梯度值。

    总结:

    (1)torch.tensor()设置requires_grad关键字参数

    (2)查看tensor是否可导,x.requires_grad 属性

    (3)设置叶子变量 leaf variable的可导性,x.requires_grad_()方法

    (4)自动求导方法 y.backward() ,直接调用backward()方法,只会计算对计算图叶节点的导数。

    (4)查看求得的到数值, x.grad 属性

    易错点:

    为什么上面的标量x的值是3.0和4.0,而不是整数呢?这是因为,要想使x支持求导,必须让x为浮点类型,也就是我们给初始值的时候要加个点:“.”。不然的话,就会报错。 即,不能定义[1,2,3],而应该定义成[1.,2.,3.],前者是整数,后者才是浮点数,浮点数才能求导。

    二、求导的核心函数——backwrad函数详解

    2.1 默认的求导规则

    在pytorch里面,默认:只能是【标量】对【标量】,或者【标量】对向【量/矩阵】求导!这个很关键,很重要!

    (1)标量对标量求导

    参见上面的例子,x,y,z都是标量,所以求导过程也很简单,不再赘述。

    (2)标量对向量/矩阵求导

    为什么标量对于向量/矩阵是默认的呢?因为在深度学习中,我们一般在求导的时候是对损失函数求导,损失函数一般都是一个标量,即讲所有项的损失加起来,但是参数又往往是向量或者是矩阵,所以这就是默认的了。看下面的例子。

    比如有一个输入层为3节点的输入层,输出层为一个节点的输出层,这样一个简单的神经网络,针对以组样本而言,有

    X=(x1,x2,x3)=(1.5,2.5,3.5),X是(1,3)维的,输出层的权值矩阵为W=(w1,w2,w3)T=(0.2,0.4,0.6)T,这里表示初始化的权值矩阵,T表示转置,则W表示的是(3,1)维度,偏置项为b=0.1,是一个标量,则可以构建一个模型如下:

    Y=XW+b,其中W,b就是要求倒数的变量,这里Y是一个标量,W是向量,b是标量,W,b是叶节点,leaf variable,

    将上面展开得到:

    Y=x1*w1+x2*w2*x3*w3+b   (这里的1,2,3是下标,不是次方哦!难得用公式截图)

    自己手动计算得到,

    Y对w1的导数为1.5

    Y对w2的导数为2.5

    Y对w3的导数为3.5

    Y对b的导数为1

    下面我们来验证一下:

    #创建一个多元函数,即Y=XW+b=Y=x1*w1+x2*w2*x3*w3+b,x不可求导,W,b设置可求导
    X=torch.tensor([1.5,2.5,3.5],requires_grad=False)
    W=torch.tensor([0.2,0.4,0.6],requires_grad=True)
    b=torch.tensor(0.1,requires_grad=True)
    Y=torch.add(torch.dot(X,W),b)
     
     
    #判断每个tensor是否是可以求导的
    print(X.requires_grad)
    print(W.requires_grad)
    print(b.requires_grad)
    print(Y.requires_grad)
     
     
    #求导,通过backward函数来实现
    Y.backward()  
     
    #查看导数,也即所谓的梯度
    print(W.grad)
    print(b.grad)
     
    '''运行结果为:
    False
    True
    True
    True
    tensor([1.5000, 2.5000, 3.5000])
    tensor(1.)
    '''
    

    我们发现这和我们自己算的结果是一样的。

    (3)标量对向量/矩阵求导的进一步理解

    比如有下面的一个复合函数,而且是矩阵,定义如下:

    '''
    x 是一个(2,3)的矩阵,设置为可导,是叶节点,即leaf variable
    y 是中间变量,由于x可导,所以y可导
    z 是中间变量,由于x,y可导,所以z可导
    f 是一个求和函数,最终得到的是一个标量scaler
    '''
     
    x = torch.tensor([[1.,2.,3.],[4.,5.,6.]],requires_grad=True)
    y = torch.add(x,1)
    z = 2*torch.pow(y,2)
    f = torch.mean(z)  
    

    则x,y,z,f实际上的函数关系如下:

    可见现在我么自己都可以手动求出函数f对于x11,x12,x13,x21,x22,x23的导数了,那我们通过torch来试一试。

    print(x.requires_grad)
    print(y.requires_grad)
    print(z.requires_grad)
    print(f.requires_grad)
    print('===================================')
    f.backward()
    print(x.grad)
     
    '''运行结果为:
    True
    True
    True
    True
    ===================================
    tensor([[1.3333, 2.0000, 2.6667],
            [3.3333, 4.0000, 4.6667]])
    '''
    

    现在我们是不是更加了解自动求导的规则了呢?

    标量如何对标量、向量、矩阵求导数!!!

    2.2 向量/矩阵对向量/矩阵求导——通过backward的第一个参数gradient来实现

    (1)求导的一个规则

    比如有下面的例子:

    '''
    x 是一个(2,3)的矩阵,设置为可导,是叶节点,即leaf variable
    y 也是一个(2,3)的矩阵,即
    y=x2+x (x的平方加x)
    实际上,就是要y的各个元素对相对应的x求导
    '''
     
    x = torch.tensor([[1.,2.,3.],[4.,5.,6.]],requires_grad=True)
    y = torch.add(torch.pow(x,2),x)
     
    gradient=torch.tensor([[1.0,1.0,1.0],[1.0,1.0,1.0]])
     
    y.backward(gradient)
     
    print(x.grad)
     
    '''运行结果为:
    tensor([[ 3.,  5.,  7.],
            [ 9., 11., 13.]])
    '''
    

    这其实跟我们自己算的是一样的,

    相较于上面的标量对于向量或者是矩阵求导,关键是backward()函数的第一个参数gradient,那么这个参数是什么意思呢?

    为了搞清楚传入的这个gradient参数到底做了什么工作,我们进一步做一个实验,有下面的一个向量对向量的求导,即

    x = torch.tensor([1.,2.,3.],requires_grad=True)
    y = torch.pow(x,2)
     
    gradient=torch.tensor([1.0,1.0,1.0])
    y.backward(gradient)
    print(x.grad)
    '''得到的结果:
    tensor([2., 4., 6.])   这和我们期望的是一样的
    '''  
    

    因为这里的gradient参数全部是1,所以看不出差别,现在更改一下gradient的值,如下:

    gradient=torch.tensor([1.0,0.1,0.01])
     
    '''输出为:
    tensor([2.0000, 0.4000, 0.0600])
    '''
    

    从结果上来看,就是第二个导数缩小了十倍,第三个导数缩小了100倍,这个倍数和gradient里面的数字是息息相关的。

    如果你想让不同的分量有不同的权重,从效果上来理解确实是这样子的,比如我是三个loss,loss1,loss2,loss3,它们的权重可能是不一样的,我们就可以通过它来设置,即

    dy/dx=0.1*dy1/dx+1.0*dy2/dx+0.0001*dy3/dx

    需要注意的是,gradient的维度是和最终的需要求导的那个y的维度是一样的,从上面的两个例子也可以看出来。

    总结:gradient参数的维度与最终的函数y保持一样的形状,每一个元素表示当前这个元素所对应的权

     

    2.3 自动求导函数backward的第二、第三个参数

    (1)保留运算图——retain_graph

    在构建函数关系的时候,特别是多个复合函数的时候,会有一个运算图,比如下面:

    则有如下一些函数关系:

    p=f(y)——>y=f(x)

    q=f(z)——>z=f(x)

    一个计算图在进行反向求导之后,为了节省内存,这个计算图就销毁了。 如果你想再次求导,就会报错。

    就比如这里的例子而言,

    你先求p求导,那么这个过程就是反向的p对y求导,y对x求导。 求导完毕之后,这三个节点构成的计算子图就会被释放:

    那么计算图就只剩下z、q了,已经不完整,无法求导了。 所以这个时候,无论你是想再次运行p.backward()还是q.backward(),都无法进行因为x已经被销毁了,报错如下:

    RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed. Specify retain_graph=True when calling backward the first time.

    那怎么办呢?遇到这种问题,我们可以通过设置 retain_graph=True 来保留计算图,

    更改你的backward函数,添加参数retain_graph=True,重新进行backward,这个时候你的计算图就被保留了,不会报错。 但是这样会吃内存!,尤其是,你在大量迭代进行参数更新的时候,很快就会内存不足,所以这个参数在绝大部分情况下是不要去使用的。

    (2)高阶导数——create_graph

    create_graph参数的资料现在很少,我也还没有搜寻到一些更详细的用法,它的官方描述是这样的:

    更高层次的计算图会创建出来,允许计算高阶导数,如二阶导数、三阶导数等等,下面有一个简单的小例子:

    x = torch.tensor(5.0,requires_grad=True)
    y = torch.pow(x,3)
     
    grad_x = torch.autograd.grad(y, x, create_graph=True)
    print(grad_x) # dy/dx = 3 * x2,即75
     
    grad_grad_x = torch.autograd.grad(grad_x[0],x)
    print(grad_grad_x) # 二阶导数 d(2x)/dx = 30
     
    '''运行结果为:
    (tensor(75., grad_fn=<MulBackward0>),)
    (tensor(30.),)
    '''
    

    三、关于向量对向量求导的解释

    补充说明:关于向量对向量求梯度的进一步绕论:

    比如说下面一个三维向量求梯度:

    然后,要计算z关于x或者y的梯度,需要将一个外部梯度传递给z.backward()函数,如下所示:

     z.backward(torch.FloatTensor([1.0, 1.0, 1.0])
    

    反向函数传递的张量就像梯度加权输出的权值。从数学上讲,这是一个向量乘以非标量张量的雅可比矩阵(本文将进一步讨论),因此它几乎总是一个维度的单位张量,与 backward张量相同,除非需要计算加权输出。

    注意 :向后图是由autograd类在向前传递过程中自动动态创建的。Backward()只是通过将其参数传递给已经生成的反向图来计算梯度。

    数学—雅克比矩阵和向量

    从数学上讲,autograd类只是一个雅可比向量积计算引擎。雅可比矩阵是一个非常简单的单词,它表示两个向量所有可能的偏导数。它是一个向量相对于另一个向量的梯度。

    注意:在这个过程中,PyTorch从不显式地构造整个雅可比矩阵。直接计算JVP (Jacobian vector product)通常更简单、更有效。

    如果一个向量X = [x1, x2,…xn]通过f(X) = [f1, f2,…fn]来计算其他向量,则雅可比矩阵(J)包含以下所有偏导组合:

    注意:雅可比矩阵实现的是 n维向量m 维向量的映射。

    雅克比矩阵

    上面的矩阵表示f(X)相对于X的梯度。

    假设一个启用PyTorch梯度的张量X

    X = [x1,x2,…,xn](假设这是某个机器学习模型的权值)

    X经过一些运算形成一个向量Y

    Y = f(X) = [y1, y2,…,ym]

    然后使用Y计算标量损失l。假设向量v恰好是标量损失l关于向量Y的梯度,如下:(注意体会这句话,这个很重要!

    向量v称为grad_tensor(梯度张量),并作为参数传递给backward() 函数。

    为了得到损失的梯度l关于权重X的梯度,雅可比矩阵J是向量乘以向量v

    这种计算雅可比矩阵并将其与向量v相乘的方法使PyTorch能够轻松地为非标量输出提供外部梯度

    四、求导的另外两种方法

    4.1 方法一:通过 torch.autograd.backward()求导

    前面介绍的求导的基本公式为:

    y.backward(grad_tensors=Noneretain_graph=Nonecreate_graph=False),这三个参数我在前面的文章里面已经说了,

    参考前面的第一篇文章,反向求导它等价于:

    torch.autograd.backward(tensors,grad_tensors=Noneretain_graph=Nonecreate_graph=False), 这里的tensors参数就相当于是y,

    所以:

    y.backward() #标量y  等价于

    torch.autograd.backward(y)

    需要注意的是,这个函数只是提供求导功能,并不返回值,返回的总是None,如下例子:

    import torch
     
    x=torch.tensor([1.0,2.0,3.0],requires_grad=True)
    y=torch.tensor([4.0,5.0,6.0],requires_grad=True)
     
    z=torch.sum(torch.pow(x,2)+torch.pow(y,3))  # z=x2+y3
     
    torch.autograd.backward([z]) # 求导,等价于z.backward()
     
    print(x.grad)   # 获取求导的结果
    print(y.grad)
    '''
    tensor([2., 4., 6.])
    tensor([ 48.,  75., 108.])
    '''
    

    注意事项:

    (1)该方法只负责求导,返回的总是None,

    (2)当向量对向量求导的时候,需要传递参数grad_tensor,这个参数的含义其实和前一篇文章的y.backward()里面的那个是一个含义;

    (3)retain_graph=Nonecreate_graph=False 也和前面的含义是一样的

    4.2 方法二:通过torch.autograd.grad()来求导

    除了前面的两种方法来求导以外,即

    y.backward()

    torch.autograd.backward(y)  这两种方法

    还有一种方法,即通过torch.autograd.grad()来求导,先来看一下这个函数的定义。

    def grad(outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=False,
             only_inputs=True, allow_unused=False):
    '''
    outputs : 函数的因变量,即需要求导的那个函数,在本例子中,为z,当然,他可以是一个tensor,也可以是几个tensor,如[tensor1,tensor2,tensor3...]
    inputs : 函数的自变量,在本例中,即对应的是[x,y],他可以是一个tensor,也可以是几个tensor,如[tensor1,tensor2,tensor3...]
    grad_output : 这个参数和前面两种方法中的grad_tensors是同样的含义,当出现向量对向量求导的时候需要指定该参数
    '''
    

    依然以这个例子而言,来看一下怎么做:

    import torch
     
    x=torch.tensor([1.0,2.0,3.0],requires_grad=True)
    y=torch.tensor([4.0,5.0,6.0],requires_grad=True)
     
    z=torch.sum(torch.pow(x,2)+torch.pow(y,3))  # z=x2+y3
     
    print(torch.autograd.grad(z,[x,y]))  # 求导,并且返回值
    '''
    (tensor([2., 4., 6.]), tensor([ 48.,  75., 108.]))
    '''
    

    注意事项:

    该函数会自动完成求导过程,而且会自动返回对于每一个自变量求导的结果。这是和前面不一样的地方。

    五、求中间节点导数的两种方法

    在Pytorch的计算图中,只有叶结点的梯度会被保存下来,中间结点(包括输出结点)的梯度会在使用后被自动释放以节省内存,例如:
    import torch
    
    x = torch.Tensor([0, 1, 2, 3]).requires_grad_()
    y = torch.Tensor([4, 5, 6, 7]).requires_grad_()
    w = torch.Tensor([1, 2, 3, 4]).requires_grad_()
    z = x+y
    
    o = w.matmul(z)
    o.backward()
    
    print('x.requires_grad:', x.requires_grad) # True
    print('y.requires_grad:', y.requires_grad) # True
    print('z.requires_grad:', z.requires_grad) # True
    print('w.requires_grad:', w.requires_grad) # True
    print('o.requires_grad:', o.requires_grad) # True
    
    
    print('x.grad:', x.grad) # tensor([1., 2., 3., 4.])
    print('y.grad:', y.grad) # tensor([1., 2., 3., 4.])
    print('w.grad:', w.grad) # tensor([ 4.,  6.,  8., 10.])
    print('z.grad:', z.grad) # None
    print('o.grad:', o.grad) # None
    

    由于zo为中间变量,因此在反向传播完成计算得到了叶结点x,y,w的梯度后就自动释放了,所以打印出来的结果为None.如果想要获得中间结点的梯度值,可以通过以下两种办法.

    5.1 方法一:设置变量的 retain_grad ()方法

    同样是上面的例子,加入两行代码:
    import torch
    
    x = torch.Tensor([0, 1, 2, 3]).requires_grad_()
    y = torch.Tensor([4, 5, 6, 7]).requires_grad_()
    w = torch.Tensor([1, 2, 3, 4]).requires_grad_()
    z = x+y
    z.retain_grad()
    
    o = w.matmul(z)
    o.backward()
    o.retain_grad()
    
    print('x.requires_grad:', x.requires_grad) # True
    print('y.requires_grad:', y.requires_grad) # True
    print('z.requires_grad:', z.requires_grad) # True
    print('w.requires_grad:', w.requires_grad) # True
    print('o.requires_grad:', o.requires_grad) # True
    
    
    print('x.grad:', x.grad) # tensor([1., 2., 3., 4.])
    print('y.grad:', y.grad) # tensor([1., 2., 3., 4.])
    print('w.grad:', w.grad) # tensor([ 4.,  6.,  8., 10.])
    print('z.grad:', z.grad) # tensor([1., 2., 3., 4.])
    print('o.grad:', o.grad) # tensor(1.)
    

    但是这种加retain_grad()的方法会增加内存的占用(pytorch设计的本意中,之所以把这些中间结点的梯度释放搞卸磨杀驴,就是不希望这部分结点的梯度占用存储空间),并不是一个好的办法,对此另外一种方法,就是使用hook保存中间结点的梯度.

    5.2 方法二:使用 register_hook ()方法调用hook函数

    对于中间结点 z,hook的使用方式为 z.register_hook(hook_fn),其中 hook_fn为用户自定义的钩子函数,其签名为:
    hook_fn(grad) -> Tensor or None
    

    函数的输入为z的梯度,输出为一个Tensor或者None.需要注意的是,反向传播时梯度传播到z结点,在继续向前传播之前会先进入hook_fn函数并进行运算.如果hook_fn函数的返回值为None,则不改变z的梯度值,如果hook_fn函数的返回值为Tensor,则将会用该Tensor的值代替原来计算得到的z的梯度,继续向前反向传播.
    下面的例子仅仅打印z的梯度值,并不改变其梯度值,

    import torch
    
    x = torch.Tensor([0, 1, 2, 3]).requires_grad_()
    y = torch.Tensor([4, 5, 6, 7]).requires_grad_()
    w = torch.Tensor([1, 2, 3, 4]).requires_grad_()
    z = x+y
    
    # ===================
    def hook_fn(grad):
        print(grad)
    
    z.register_hook(hook_fn)
    # ===================
    
    o = w.matmul(z)
    
    print('=====Start backprop=====')
    o.backward()
    print('=====End backprop=====')
    
    print('x.grad:', x.grad)
    print('y.grad:', y.grad)
    print('w.grad:', w.grad)
    print('z.grad:', z.grad)
    

    运行结果为:

    =====Start backprop=====
    tensor([1., 2., 3., 4.])
    =====End backprop=====
    x.grad: tensor([1., 2., 3., 4.])
    y.grad: tensor([1., 2., 3., 4.])
    w.grad: tensor([ 4.,  6.,  8., 10.])
    z.grad: None
    

    下面的例子通过hook_fn改变了结点z的值,

    import torch
    
    x = torch.Tensor([0, 1, 2, 3]).requires_grad_()
    y = torch.Tensor([4, 5, 6, 7]).requires_grad_()
    w = torch.Tensor([1, 2, 3, 4]).requires_grad_()
    z = x + y
    
    
    # ===================
    def hook_fn(grad):
        g = 2 * grad
        print(g)
        return g
    
    
    z.register_hook(hook_fn)
    # ===================
    
    o = w.matmul(z)
    
    print('=====Start backprop=====')
    o.backward()
    print('=====End backprop=====')
    
    print('x.grad:', x.grad)
    print('y.grad:', y.grad)
    print('w.grad:', w.grad)
    print('z.grad:', z.grad)
    

    运行结果为,

    =====Start backprop=====
    tensor([2., 4., 6., 8.])
    =====End backprop=====
    x.grad: tensor([2., 4., 6., 8.])
    y.grad: tensor([2., 4., 6., 8.])
    w.grad: tensor([ 4.,  6.,  8., 10.])
    z.grad: None
    

    结果显示,首先z本身的梯度变成了原来的两倍,并使用改变后的梯度值继续计算前向结点的梯度,使得叶节点的梯度也变成了原来的2倍.
    同一个结点还可以注册多个钩子函数,其执行顺序为函数的注册顺序,下面的例子,

    import torch
    
    x = torch.Tensor([0, 1, 2, 3]).requires_grad_()
    y = torch.Tensor([4, 5, 6, 7]).requires_grad_()
    w = torch.Tensor([1, 2, 3, 4]).requires_grad_()
    z = x + y
    
    # ===================
    z.register_hook(lambda x: 2*x)
    z.register_hook(lambda x: print(x))
    # ===================
    
    o = w.matmul(z)
    
    print('=====Start backprop=====')
    o.backward()
    print('=====End backprop=====')
    
    print('x.grad:', x.grad)
    print('y.grad:', y.grad)
    print('w.grad:', w.grad)
    print('z.grad:', z.grad)
    

    运行结果为,

    =====Start backprop=====
    tensor([2., 4., 6., 8.])
    =====End backprop=====
    x.grad: tensor([2., 4., 6., 8.])
    y.grad: tensor([2., 4., 6., 8.])
    w.grad: tensor([ 4.,  6.,  8., 10.])
    z.grad: None
    

    ————————————————
    版权声明:本文部分为CSDN博主「LoveMIss-Y」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    本文一.二.三部分转载自:
    原文链接1:https://blog.csdn.net/qq_27825451/article/details/89393332
    本文四部分转载自:
    原文链接2:https://blog.csdn.net/qq_27825451/article/details/89553479

    展开全文
  • 在进行向量的求导时,非常好用...2.向量x求导∇xxTAx=(A+AT)x\nabla_x x^TAx=(A+A^T)x∇x​xTAx=(A+AT)x其中x为向量,A为矩阵 3.向量x求二阶导(即Hessian矩阵)∇2xTAx=A+AT\nabla ^2 x^TAx=A+A^T∇2xTAx=A+...

    在进行对向量的求导时,非常好用的三个公式
    分别是
    1.对于向量x求导 ∇ x w T x = w \nabla_x w^Tx=w xwTx=w
    2.对向量x求导 ∇ x x T A x = ( A + A T ) x \nabla_x x^TAx=(A+A^T)x xxTAx=(A+AT)x其中x为向量,A为矩阵
    3.对向量x求二阶导(即Hessian矩阵) ∇ 2 x T A x = A + A T \nabla ^2 x^TAx=A+A^T 2xTAx=A+AT


    详细的证明
    1.对于向量x求导
    ∇ x w T x = w \nabla_x w^Tx=w xwTx=w
    证明:
    w T x = ( w 1 w 2 . . . w n ) ⋅ ( x 1 x 2 . . . x n ) = ∑ i = 1 n w i x i w^Tx=\begin{pmatrix}w_1&amp;w_2&amp;...&amp;w_n\end{pmatrix}\cdot\begin{pmatrix}x_1\\x_2\\...\\x_n\end{pmatrix}\\ =\sum\limits_{i=1}^nw_ix_i wTx=(w1w2...wn)x1x2...xn=i=1nwixi
    所以对 x i x_i xi求导,对应的导数为 w i w_i wi
    ∇ x w T x = w \nabla_x w^Tx=w xwTx=w


    2.对向量x求导
    ∇ x x T A x = ( A + A T ) x \nabla_x x^TAx=(A+A^T)x xxTAx=(A+AT)x
    其中x为向量,A为矩阵

    证明:
    对于二次型 x T A x x^TAx xTAx
    x T A x = ( x 1 x 2 . . . x n ) ( a 11 a 12 . . . a 1 n a 21 a 22 . . . a 2 n . . a n 1 a n 2 . . . a n n ) ( x 1 x 2 . . . x n ) = ( x 1 x 2 . . . x n ) ( a 11 x 1 + a 12 x 2 + . . . + a 1 n x n a 21 x 1 + a 22 x 2 + . . . + a 2 n x n . . . a n 1 x 1 + a n 2 x 2 + . . . + a n n x n ) = a 11 x 1 x 1 + a 12 x 1 x 2 + . . . + a 1 n x 1 x n + a 21 x 2 x 1 + a 22 x 2 x 2 + . . . + a 2 n x 2 x n + . . . + a n 1 x n x 1 + a n 2 x n x 2 + . . . + a n n x n x n = ∑ i = 1 n ∑ j = 1 n a i j x i x j x^TAx=\begin{pmatrix}x_1&amp;x_2&amp;...&amp;x_n\end{pmatrix}\begin{pmatrix} a_{11}&amp;a_{12}&amp;...&amp;a_{1n}\\a_{21}&amp;a_{22}&amp;...&amp;a_{2n}\\.\\.\\a_{n1}&amp;a_{n2}&amp;...&amp;a_{nn}\end{pmatrix}\begin{pmatrix}x_1\\x_2\\...\\\\x_n\end{pmatrix}\\ =\begin{pmatrix}x_1&amp;x_2&amp;...&amp;x_n\end{pmatrix}\begin{pmatrix}a_{11}x_1+a_{12}x_2+...+a_{1n}x_{n}\\a_{21}x_1+a_{22}x_2+...+a_{2n}x_n\\...\\a_{n1}x_1+a_{n2}x_2+...+a_{nn}x_n\end{pmatrix}\\ =a_{11}x_1x_1+a_{12}x_1x_2+...+a_{1n}x_1x_n+a_{21}x_2x_1+a_{22}x_2x_2+...+a_{2n}x_2x_n +...+a_{n1}x_nx_1+a_{n2}x_nx_2+...+a_{nn}x_nx_n \\ =\sum\limits_{i=1}^n\sum\limits_{j=1}^na_{ij}x_ix_j xTAx=(x1x2...xn)a11a21..an1a12a22an2.........a1na2nannx1x2...xn=(x1x2...xn)a11x1+a12x2+...+a1nxna21x1+a22x2+...+a2nxn...an1x1+an2x2+...+annxn=a11x1x1+a12x1x2+...+a1nx1xn+a21x2x1+a22x2x2+...+a2nx2xn+...+an1xnx1+an2xnx2+...+annxnxn=i=1nj=1naijxixj
    其中,若只对 x 1 x_1 x1求导则整理上式
    x T A x = a 11 x 1 x 1 + ∑ i = 2 n a i 1 x i x 1 + ∑ j = 2 n a 1 j x j x 1 + c x^TAx=a_{11}x_1x_1+\sum\limits_{i=2}^na_{i1}x_ix_1+\sum\limits_{j=2}^na_{1j}x_{j}x_1+c xTAx=a11x1x1+i=2nai1xix1+j=2na1jxjx1+c
    x 1 x_1 x1求导,则上式为
    2 a 11 x 1 + ∑ i = 2 n a i 1 x i + ∑ j = 2 n a 1 j x j = ∑ j = 1 n a 1 j x j + ∑ j = 1 n a 1 j x j = A [ 1 , : ] ⋅ x + A T [ 1 , : ] ⋅ x 2a_{11}x_1+\sum\limits_{i=2}^na_{i1}x_i+\sum\limits_{j=2}^na_{1j}x_{j}\\ =\sum\limits_{j=1}^na_{1j}x_{j}+\sum\limits_{j=1}^na_{1j}x_{j}\\ =A[1,:]\cdot x +A^T[1,:]\cdot x 2a11x1+i=2nai1xi+j=2na1jxj=j=1na1jxj+j=1na1jxj=A[1,:]x+AT[1,:]x
    由此可知,对x求导后,导数为
    ( A + A T ) ⋅ x (A+A^T)\cdot x (A+AT)x


    3.对向量x求二阶导(即Hessian矩阵) ∇ 2 x T A x = A + A T \nabla ^2 x^TAx=A+A^T 2xTAx=A+AT

    证明:
    对于二次型 x T A x = ∑ i = 1 n ∑ j = 1 n x i x j a i j x^TAx=\sum\limits_{i=1}^n\sum\limits_{j=1}^nx_ix_ja_{ij} xTAx=i=1nj=1nxixjaij
    而海森矩阵的每一个元素 H i j = ∂ 2 f ∂ x i ∂ x j H_{ij}=\frac{\partial ^2f}{\partial x_i\partial x_j} Hij=xixj2f

    如求 H i j H_{ij} Hij
    则需要找到原等式中,存在 x i x j x_ix_j xixj的项
    H i j = ∂ 2 f ∂ x i ∂ x j = a i j + a j i H_{ij}=\frac{\partial ^2f}{\partial x_i\partial x_j}=a_{ij}+a_{ji} Hij=xixj2f=aij+aji
    H = A + A T H=A+A^T H=A+AT

    这个二阶偏导数的形式也与一元函数的二阶导数形式上统一

    展开全文
  • 微积分的核心是极限(Limit),求导(Derivative)是微积分的重要内容,本质就是求极限。导数公式有很多, 靠死记还是比较麻烦的,但这又是微积分的基础,不然接下去导数的应用(求切线、求法线、增减性、求极值、求凹凸性...

    2f2c9cd0ba3a0e45c26c03f6f0a9aee0.png

    微积分的核心是极限(Limit)求导(Derivative)是微积分的重要内容,本质就是求极限。导数公式有很多, 靠死记还是比较麻烦的,但这又是微积分的基础,不然接下去导数的应用(求切线、求法线、增减性、求极值、求凹凸性等)都没法学,更不用说导数的逆运算——求积分了。所以本文想系统的梳理一下求导法则常见函数求导公式争取利用最少的知识把下面公式都推导出来。

    fbfaa2d4c2d06e2986f9e20cf6bdeae0.png
    图:常见函数求导公式

    一、导数的定义

    e85e10397a951babdc66323a60174800.png

    AB弦的斜率是

    ,当B点不断向A点靠近时,AB弦的斜率就变成了
    在点A处的切线斜率(
    可以类比平均速度和瞬时速度),可以得到求导公式:

    (Differentiation from first principle)

    也可以用如下公式求

    处的切线斜率:

    那么根据上述定义,我们计算几个常见的求导公式。

    (1)

    (2)


    因为

    所以

    (3)

    注:

    (4)

    注:

    (5)


    又因为

    所以

    的导数等于其本身乘以在
    处的导数,那么什么时候
    的导数等于其本身呢?即
    ,

    这里,令

    ,

    所以

    那么

    注:根据

    结合后面复合函数求导法则可以推导出

    如果

    不能理解,可以考虑推导
    ,然后再利用反函数求导得到

    二、导数的四则运算及复合函数求导(The chain rule)

    是关于x的两个可导函数,则
    Scalar muptiplication rule:

    Addition rule:

    The product rule:

    The quotient rule:

    对于

    直接根据定义就可以证明了,比较容易,下面证明求导的乘法与除法公式。

    (1)The product rule

    (2)The quotient rule

    根据导数的乘法与除法法则,我们就可以计算

    比如下面计算一下

    其他三个也可以类似的推导得到,所以只需要记住

    就够了。

    接下去讲一个非常重要的复合函数求导——链式法则(The chain rule)

    处可导,且
    处可导,则复合函数
    的求导结果为:
    .

    用莱布尼兹表示,若

    都是可导函数,则

    学了链式法则,那么我们就可以推导


    则根据
    和链式法则有

    三、隐函数求导

    把能够写成

    的函数称为显函数,但是有些情况下如
    我们不能把x,y分离开,只知道x,y存在一定的关系
    ,把这样的称为隐函数。隐函数求导就是对
    两边同时对x进行求导,且在求导过程中把y看成是一个关于x的函数,求导完成后只需要把
    分离开来就得到了y关于x的导数。

    接下去我们根据隐函数求导来推导一下求导公式表中的剩下公式。

    (1)

    ,则
    ,两边对x进行求导可得:
    ,那么

    又因为
    ,

    所以

    那么我们也可以知道

    类似的我们也可以算得剩下三个反三角函数的导数

    (2)

    ,则
    ,两边对x求导可得
    ,

    又因为

    所以

    也可以类似得到,其中要用到两个三角恒等式

    总结,我们通过导数的定义,推导了导数四则运算法则、链式法则,以及借助隐函数求导,把常见函数求导公式都推导了一遍。所以我们只需要记忆一些最基本的定义、最常见的函数求导就够了,其它复杂的忘记了现推一下也很快知道了。

    这是我认为的推导常见函数求导公式比较顺的一个思路,可能还有更好的,欢迎交流讨论~

    想了解更多国际数学课程知识,可参阅:

    双木止月Tong:【国际数学课程】目录​zhuanlan.zhihu.com
    9b200121c51af7c73d9f0ba0a9750b43.png
    展开全文
  • 设,求.(这同样可以看成二元函数换一元函数,即)解:Easy设,求.(这类题目给出,然后给出,因此在对求导时出现的直接代入即可)解:2. 设,求.(这类题目给出,然后给出,与上面一道题目类型一致)解:3. 设,求.(这道...
  • 矩阵的迹以及迹矩阵求导

    千次阅读 2019-06-08 12:18:25
    ref: ... 矩阵的迹概念 矩阵的迹 就是 矩阵的主角线上所有元素的和。 矩阵A的迹,记作tr(A),可知tra(A)=∑aii,1<=i<=n。 定理:tr(AB) = tr(BA) 证明 定理:tr(ABC) = tr(C...
  • 矩阵的求导

    2017-10-07 13:07:26
    复杂矩阵问题求导方法:可以从小到大,从scalar到vector再到matrix。  x is a column vector, A is a matrix d(A∗x)/dx=A  d(xT∗A)/dxT=A  d(xT∗A)/dx=AT  d(xT∗A∗x)/dx=xT...
  • 矩阵求导公式总结

    万次阅读 多人点赞 2016-06-12 15:40:53
    今天推导公式,发现居然有矩阵的求导,狂汗--完全不会。不过还好网上有人总结了。吼吼,赶紧搬过来收藏备份。 基本公式: Y = A * X --> DY/DX = A' ...Y = X * A --> DY/DX = A ...1. 矩阵Y标量x求导
  • 常见的矩阵求导

    千次阅读 2016-10-07 09:55:30
    机器学习中常用的矩阵求导公式  opencv_le 2016-02-25 2191原文链接 https://zhuanlan.zhihu.com/p/25063314  或者简洁版 http://www.sohu.com/a/221429567_129720 矩阵求导好像...
  • PyTorch自动求导

    2020-02-16 10:53:39
    PyTorch的Autograd模块是应用所有神经网络的核心内容,在张量(Tensor)上的所有操作,Autograd都能为他们自动提供微分,也就是自动求导的方法,从而简化了手动计算导数的复杂过程。 在0.4之前的版本中,PyTorch通过...
  • 比如这里x是列向量,求Ax关于x求导数,那么对x的每个分量分别求偏导数(写成一行),然后整理排成一列(同x一样是列向量)。 同理有 关于x的转置x.T求导数,x.T是行向量,那么Ax分别对x.T向量中的分量求偏导...
  • 矩阵、向量求导法则

    2016-06-28 16:15:00
    5. 向量积列向量X求导运算法则: 注意与标量求导有点不同。 d(UV')/dX = (dU/dX)V' + U(dV'/dX) d(U'V)/dX = (dU'/dX)V + (dV'/dX)U' 重要结论: d(X'A)/dX = (dX'/dX)A + (dA/dX)X' = IA + 0X' = A d...
  • 矩阵求导公式【转】

    万次阅读 2016-08-28 08:59:25
    原文地址:矩阵求导公式【转】作者:三寅今天推导公式,发现居然有矩阵的求导,狂汗--完全不会。不过还好网上有人总结了。吼吼,赶紧搬过来收藏备份。 基本公式: Y = A * X --> DY/DX = A' Y = X * A --> DY/...
  • 为了方便理解和查询,本文总结了以下内容:常见的六种三角函数对应的反三角函数的定义、定义域、值域,并给出对应三角形图示汇总、对应图象汇总利用反函数求导法则完成了上述所有反三角函数的导数公式的推导,并详细...
  • 矩阵求导公式

    万次阅读 2017-04-04 10:52:26
    今天推导公式,发现居然有矩阵的求导,狂汗--完全不会。不过还好网上有人总结了。吼吼,赶紧搬过来收藏备份。 基本公式: Y = A * X --> DY/DX = A' Y = X * A --> DY/DX = A Y = A' * X * B --> DY/DX = ...
  • 隐函数的求导

    2021-10-15 14:55:20
    例题:求方程 e^y + xy - e = 0 所确定的隐函数的导函数 dy/dx ...xy x求导 就是 x’y + y’x ,即 (xy)’ = y+ xdy/dx e^y dy/dx + y + x dy/dx = 0 ; => dy/dx = -y/(e^y + x ) e^y + x 不等于0 记录这篇
  • 矩阵求导的一些公式

    2016-12-30 16:59:08
    1. 矩阵Y标量x求导:  相当于每个元素求导数后转置一下,注意M×N矩阵求导后变成N×M了  Y = [y(ij)] --> dY/dx = [dy(ji)/dx]  2. 标量y列向量X求导:  注意与上面不同,这次括号内是求偏导,不...
  • DAY 4.这世上总要有个明白人,懂得克制。DAY 4.1. 利用莱布尼茨定理求高阶导2.隐函数求导3.对数求导4....例题1 设 求 解:方程两边同时对x求导得 = 3.对数求导例题2 求 y 的一阶导解:方程两边同时取对数...
  • a^x求导是怎么来的呢?

    千次阅读 2021-01-07 01:16:04
    axa^xax求导是怎么来的呢? eee的由来: 复利模型:如果这里不懂,复利模型又叫做利滚利模型,将钱存入银行,如果一年的增长率是rrr,那么xxx个周期后总增长率为: Q=(1+r)x Q = (1+r)^x Q=(1+r)x 可以理解为xxx个...
  • python函数值求导和求值

    千次阅读 2020-12-24 09:18:30
    python函数值求导和求值
  • f(x)g(x)求导的理解

    千次阅读 2018-12-12 10:40:28
    1.若g(x)=x,则f(x)g(x)g(x)=x,则f(x)g(x)g(x)=x,则f(x)g(x)求导就是一般的f(x)xf(x)xf(x)对x求导。 2.若g(x)g(x)g(x)为其它的函数,应该怎么做呢? (1)可以从导数定义去看。 例如:求f(x)=sinx在2x趋近...
  • 图像求导推理

    千次阅读 2019-08-04 10:36:51
    从名字也可以看出,微分算子,当然涉及到求导,为什么图像进行求导就可以检测图像中的边缘呢?图像的边缘一般存在灰度变化强烈的地方,只有灰度变化的明显我们才可以从图像中清晰的看到没有一个物体...
  • 泛函求导的理解

    千次阅读 2019-01-07 11:25:01
    泛函求导的理解 1、当y发生变化时,本应是一个集合发生变化,但是对于每一个点,其变化性质一致,故可以当成一个变量来求导,此时类似与求关于y的偏导 2、为什么可以忽略对x的积分号? 因为可以将式子合并到一个...
  • 在证明由函数y=f(u)与u=φ(x)构成的复合函数y=f[φ(x)]的求导公式dy/dx.du/dx时,在数学分析教材的证明中都用到当Δu趋于零时的无穷小量α,并需要补充义当Δu=0时,α=0,这初学者来说是不容易理解的.本文给出的...
  • 使用tr矩阵进行求导

    千次阅读 2018-05-05 16:45:23
    使用tr矩阵进行求导:常用:
  • 一直矩阵求导和向量求导云里雾里,直到这两天看到刘建平老师的博客,我认为是讲的最清楚的的一个系列,所以特地将其整理成pdf文档,并添加书签,供大家们参考。
  • 矩阵运算及求导

    千次阅读 2019-11-16 09:57:06
    数值变量数值变量求导是最简单的情况,也是数学里头经常遇到的,得到的结果是函数的导数。 Vector-Scalar 向量数值变量求导,得到的是一个列向量。 [ ∂ y ∂ x ] = [ ∂ y i ∂ x ] T [\frac{\partial...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 55,651
精华内容 22,260
关键字:

怎么对x求导