矩阵计算(导数)

 

1 标量的导数

image

2 亚导数

比如说y=|x|这个函数在x=0的时候时不可导的。当x>0,其到导数为1,x<0,其导数为-1,所以在x=0的这个地方的亚导数就是可以是[-1,1]中的一个数
image

矩阵求导

向量化的优点

1.简洁
比如说:
{y1=W1X11+W2X12+...+WnX1ny2=W1X21+W2X22+...+WnX1n.....yn=W1Xn1+W2Xn2+...+WnXnn
这个函数可以简化成

Y=XW

[y1y2...yn]=[X11,X12...,X1nX21,X22...,X2n...Xn1,Xn2...,Xnn][W1W2...Wn]

2.加速计算机的计算
image
image

对于同样一个矩阵相乘的操作,我们可以我们可以看出用矩阵的话是1.5ms,但是如果用for循环的话是474ms。

标量函数和向量函数

标量函数

其实标量函数就是最后运算之后输出为标量的函数,例如:

  • f(x)=x2,x>x2
  • f(x)=x12+x22,其中[X1X2]=>X12+X22

这两个最终的运算结果都是一个标量。

向量函数

就是最后运算结果为一个向量,例如:
f(x)=[f1(x)=Xf2(x)=X2],x>[XX2]

f(x)=[f1(x)=X,f2(x)=X2f3(x)=X3,f4(x)=X4],x>[X,X2X3,X4]

f(x)=[f1(x)=X1+X2,f2(x)=X12+X22f3(x)=X13+X23,f4(x)=X14+X24],[X1X2]>[X1+X2,X12+X22X13+X23,X14+X24]

矩阵求导

dAdB:矩阵求导的本质就是矩阵A中的每一个元素对矩阵B中的每个元素求导。
然后从求导后的元素个数角度:
因为他是矩阵A中的每个元素对矩阵B中的每个元素,所以是这样的形状。

A B dAdB
1×1 1×1 1×1
1×p 1×n p×n
q×p m×n p×q×m×n

求导方法

YX拉伸,其中Y横向拉伸,X纵向拉伸。

{,

这里的前面,后面指的是YX或者是XY,这里本文用的是YX

例一:f(x)标量,x向量

df(x)dx,其中f(x)就是Y,f(x)为标量函数,x为向量。也就是f(x)=f(x1,x2,x3...xn),x=[x1,x2,x2...n]T
我们按照上面的规则,f(x)是标量不变,拉伸,X纵向拉伸。

df(x)dx=[f(x)x1f(x)x2f(x)x3....f(x)xn]

这个实际上就是将多元函数的偏导写在一个列向量中。

例二:f(x)向量,x标量

df(x)dx,f(x)为向量函数,x为向量。也就是f(x)=[f1(x)f2(x)...fn(x)],然后这个f(x)横向拉伸,x不变。
最终结果就是:
df(x)dx=[f1(x)x,f2(x)x...fn(x)x]

例三:f(x)为向量函数,x为向量函数

f(x)=[f1(x)f2(x)...fn(x)]x=[x1x2...xn]
然后我们按照我们的规则,前面的横向拉伸,后面的纵向拉伸,然后本质就是A中的每个元素对矩阵B中的每一个求导。

df(x)dx=[f1(x)x1,f2(x)x1....fn(x)x1f1(x)x2,f2(x)x2....fn(x)x2f1(x)x3,f2(x)x3....fn(x)x3....f1(x)xn,f2(x)xn....fn(x)xn]

我们看完上面这个对矩阵求导后的形状应该就了解了,上面的图也应该就知道了。

常见矩阵求导公式的推导

例一:f(x)=ATX,求df(x)dx
其中:
A=[a1a2...an]x=[x1x2...xn]
我们可以看出f(x)是标量,x是向量。
解:f(x)=ATX=1naixi
所以要把x纵向展开
df(x)dx=[f(x)x1f(x)x2f(x)x3...f(x)xn]=[a1a2a3...an]=A
ps:这里f(x)x1=a1是因为f(x)=1naixi,对于除了a1x1在外的其他项,对x1求偏导都是0。
也可以这样看,d(ATX)dx=d(XTA)dx=A

例二:f(x)=XTAX
这个可以自己证明一下,最终结果为A+ATX.

两种布局

  • 两种布局:

{>YX>XY

  • 向量求导时的拉伸方向:

都是前面的横向拉伸,后面的纵向拉伸

  • YX拉伸术-->分母布局
    Y横向拉伸(f(x)横向拉伸)
    X纵向拉伸

  • XY拉伸术-->分子布局
    X横向拉伸
    Y纵向拉伸(f(x)横向拉伸)

梯度

这里主要搞得清楚他的形状
image
下面我们都使用的是分子布局(XY拉伸术),也就是X横向拉伸,Y纵向拉伸

  • ∂y/∂x
    当y是标量,x是向量的时候:
    image
    这里注意一点,你的梯度指向的是你的值变大的方向。
    我们将X横向拉伸

  • y/∂x
    当y是向量,x是标量的时候:
    image

  • y/∂x
    我们可以发现T=
    image
    然后我们拓展的矩阵:
    image

pytorch 自动求导

向量的链式法则

  • 标量的链式法则

y=f(x),u=g(x),yx=yuux

  • 拓展到向量
    image

例一:
image
例二:
image

自动求导

自动求导计算一个函数在指定值上的导数
它有别于

  • 符号求导(显式求导)
    image
  • 数值求导(隐式求导)
    image

计算图

·将代码分解成操作子
·将计算表示成一个无环图
image
·将代码分解成操作子
·将计算表示成一个无环图
·显示构造
image
·将代码分解成操作子
·将计算表示成一个无环图
·显式构造
     .Tensorflow/Theano/MXNet
·隐式构造
     .PyTorch/MXNet

自动求导的两种模式

正向积累和反向传播(反向积累)
image
对于反向积累
image
他需要读取之前的结果
image
image
image

image

自动求导的实现

假设我们想对函数y=2xx关于列向量x求导,最终计算的结果是个标量

import torch

x = torch.arange(4.0)
x

# tensor([0., 1., 2., 3.])

在我们计算y关于x的梯度之前,我们需要一个地方来存储梯度

x.requires_grad_(True)
x.grad

requires_grad: 如果需要为张量计算梯度,则为True,否则为False。我们使用pytorch创建tensor时,可以指定requires_grad为True(默认为False),创建一个Tensor并设置requires_grad=True,requires_grad=True说明该变量需要计算梯度。

grad:当执行完了backward()之后,通过x.grad查看x的梯度值。

在这里我们可以在创建完x之后再x.requires_grad_(True),或者我们创建的时候就
`x = torch.arange(4.0,requires_grad=True)``

现在让我们计算y

y = 2 * torch.dot(x, x)
y


# tensor(28., grad_fn=<MulBackward0>)

通过调用反向传播函数来自动计算y关于x每个分量的梯度

y.backward()
x.grad

# tensor([ 0.,  4.,  8., 12.])
x.grad == 4 * x

# tensor([True, True, True, True])

y=2xx然后他的函数求导之后的值和4*x一样的。
现在让我们计算x的另一个函数
x.grad.zero_()是让他的梯度清空

x.grad.zero_()
y = x.sum()
y.backward()
x.grad

# tensor([1., 1., 1., 1.])

深度学习中 ,我们的目的不是计算微分矩阵,而是批量中每个样本单独计算的偏导数之和

x.grad.zero_()
y = x * x
y.sum().backward()
x.grad
# tensor([0., 2., 4., 6.])

将某些计算移动到记录的计算图之外

x.grad.zero_()
y = x * x
u = y.detach()
z = u * x

z.sum().backward()
x.grad == u

# tensor([True, True, True, True])
x.grad.zero_()
y.sum().backward()
x.grad == 2 * x
# tensor([True, True, True, True])

即使构建函数的计算图需要通过Python控制流(例如,条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度

def f(a):
    b = a * 2
    while b.norm() < 1000:
        b = b * 2
    if b.sum() > 0:
        c = b
    else:
        c = 100 * b
    return c

a = torch.randn(size=(), requires_grad=True)
d = f(a)
d.backward()

a.grad == d / a

# tensor(True)
posted @   lipu123  阅读(167)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示