前言

就一个NN而言,包含梯度、偏置、参数更新,而前面第一篇博客学习了theano中符号变量的定义, 第二篇博客学习了变量的随机初始化, 变量之间的互相操作(类似于sigmoid(w∗x+b)sigmoid(w*x+b)), 但是参数更新还应涉及到损失函数的偏导计算,这一章节就是看看theano的梯度计算函数`tensor.grad(). 此外还有雅可比式(一阶导),海森矩阵(二阶导),雅克比乘以向量,海森矩阵乘以向量的操作

梯度计算

目前感觉这个函数没什么需要注意的, 使用方法直接就是 T.grad(y,x), 意思就是y对x求导,而且我们还能用function.marker.fgraph.outputs[0]把得到的导数公式输出出来,先导入模块,没什么好说的

import theano
import theano.tensor as T
from theano import pp#用于输出表达式
  • y=x^2+x^3+x^4试水

    x=T.dscalar('x')#定义一个变量
    y=x**2+x**3+x**4#定义一个操作
    gy=T.grad(y,x)#将y对x求导
    f=theano.function([x],gy)# 执行这个求导函数
    pp(f.maker.fgraph.outputs[0])

    输出是

    Elemwise{Composite{((i0 * i1) + (i2 * sqr(i1)) + (i3 * Composite{(sqr(i0) * i0)}(i1)))}}(TensorConstant{2.0}, x, TensorConstant{3.0}, TensorConstant{4.0})

    然后怎么依据这个输出把导数表达式写出来呢?这里我们把i0,i1,i2,i3分别用2,x,3,4替换(TensorConstant{2.0}意思就是常数张量2.0,’sqr’代表平方),然后带入到前面的Composite{((i0 * i1) + (i2 * sqr(i1)) + (i3 * Composite{(sqr(i0) * i0)}(i1)))}中, 注意遇到Composite{xxx}(xxx), 就用()中的xxx去替换{}中的xxx,然后我来分析一波

    这样就能得到一个结果2*x+3*x^2+4*(x^2)*x,刚好就是y=x2+x3+x4y=x^2+x^3+x^4对xx的偏导结果

  • 同样的例子套入到对率函数中去

    y1=1/(1+T.exp(-x))
    gy1=T.grad(y1,x)
    f2=theano.function([x],gy1)# pp(gy1)pp(f2.maker.fgraph.outputs[0])

    输出是

    Elemwise{Composite{(scalar_sigmoid((-i0)) * scalar_sigmoid(i0))}}(x)

    按照上面的图画一下,然后可以写出来结果是sigmoid(-x)*sigmoid(x),其实也就是

    y∂y∂x=sigmoid(x)=11+e−x=sigmoid(−x)∗sigmoid(x)=11+e−x∗11+ex=y(1−y)

    \begin{aligned}y&=sigmoid(x)=\frac{1}{1+e^{-x}}\\\frac{\partial y}{\partial x}&=sigmoid(-x)*sigmoid(x)\\&=\frac{1}{1+e^{-x}}*\frac{1}{1+e^x}\\&=y(1-y)\end{aligned}

注意, T.grad()的第二个参数可以是一个列表,那么输出也就是列表了,意思应该就是损失函数可以对权重和偏置在一个函数中求导

计算雅克比矩阵

theano中雅克比就是计算一个函数的输出相对于每个输入的一阶偏导数。theano中有两种方法去实现

  • 间接(人工)方法
    由于这需要使用到循环(对每个输入都要计算偏导数), 因而提前接触到了theano中用于创建循环的函数scan(), 如果想提前了解scan(), 可以去看这位博主的五个例子掌握theano.scan函数

    x=T.dvector('x')
    y=x**2
    J,updates=theano.scan(lambda i,y,x : T.grad(y[i],x),sequences=T.arange(y.shape[0]),non_sequences=[y,x])
    f=theano.function([x],J,updates=updates)
    f([4,4])
    ​```
    array([[ 8.,  0.],[ 0.,  8.]])
    ​```

    这里稍微说一下用到的scan内容:

    • 第一个参数默认就是定义的函数了,这里用了个lambda表达式lambda i,y,x : T.grad(y[i],x)意思是我们要计算这个梯度, 而这i,y,x的来源就是后面的几个参数,赋值顺序一般是sequences中的变量outputs_info的变量,non_sequences中的变量 , 这个顺序要记住
    • 参数sequences表示我们需要遍历的量,一般都是T.arange()创建的列表,把它丢给了i
    • 参数non_sequences是其他两个输入量[y,x],把它丢给了lambda函数中的y,x
    • 返回值J是输出变量列表,updates是字典,表示每个输出变量列表的更新规则
  • 直接方法
    theano中直接提供了一个函数来实现Jacobian矩阵的计算theano.gradient.jacobian(expression, wrt, consider_constant=None, disconnected_inputs='raise')

    
    #直接计算hessian矩阵x=T.dvector('x')
    y=T.dvector('y')
    input=[x,y]
    s=T.sum(x**2+y**2)
    f=theano.gradient.jacobian(expression=s,wrt=input)
    h=theano.function(input,f)
    x=[1,2]
    y=[1,2]
    h(x,y)
    '''
    [array([ 2.,  4.]), array([ 2.,  4.])]
    '''

    看样子计算的就是损失函数expression关于input中变量的偏导数

计算海森矩阵

普遍接受的关于海森矩阵的数学说法是: 它是具有标量输出和向量输入的二阶偏导函数的矩阵。同样有间接和直接两种计算方法

  • 间接(人工)计算方法
    与间接计算Jacobian矩阵不同的是我们不是计算某个表达式的雅克比式,而是计算关于导数T.grad(cost,x)的雅可比式

    
    #间接计算Hessian矩阵x=T.dvector('x')
    y=x**2
    cost=y.sum()
    gy=T.grad(cost,x)#先计算损失关于x的梯度
    H,updates=theano.scan(lambda i,gy,x : T.grad(gy[i],x),sequences=T.arange(gy.shape[0]),non_sequences=[gy,x])
    f=theano.function([x],H,updates=updates)
    f([4,4])
    '''
    array([[ 2.,  0.],[ 0.,  2.]])
    '''

    依旧是theano.scan()的应用, 第一个参数是计算梯度的函数, 后面的先把sequences的列表丢给i, 然后将non_sequence中的gy,x分别丢给lambda表达式中的gyx

  • 直接计算方法
    theano中直接提供了一个函数来实现Hessian矩阵的计算:theano.gradient.hessian(cost, wrt, consider_constant=None, disconnected_inputs='raise')

    x=T.dvector('x')
    y=T.dvector('y')
    input=[x,y]
    s=T.sum(x**2+y**2)
    f=theano.gradient.hessian(cost=s,wrt=input)
    h=theano.function(input,f)
    x=[1,2]
    y=[1,2]
    h(x,y)
    '''
    [array([[ 2.,  0.],[ 0.,  2.]]), array([[ 2.,  0.],[ 0.,  2.]])]
    '''

    看样子计算的就是损失函数cost关于input中变量的偏导数

雅可比式与向量乘积

R-操作(右乘)

计算目标

∂f(x)∂xv

\frac{\partial f(x)}{\partial x}v
其中 xx可以是矩阵或者是张量,主要还是因为我们需要依据权重矩阵做一些表达式的计算

#雅可比式*向量
W=T.dmatrix('W')
V=T.dmatrix('V')
x=T.dvector('x')
y=T.dot(x,W)
JV=T.Rop(y,W,V)#这里直接调用的就是Rop函数对应右乘操作
f=theano.function([W,V,x],JV)
w=[[1, 1], [1, 1]]
v=[[2, 2], [2, 2]]
x=[0,1]
f(w,v,x)
'''
array([ 2.,  2.])
'''

这干了一件什么事情呢?数学表达式如下:

y∂y∂W∗V=W∗x=x∗V

\begin{aligned} y&=W*x\\ \frac{\partial y}{\partial W}*V&=x*V \end{aligned}

L-操作(左乘)

#向量*雅可比式
W = T.dmatrix('W')
V = T.dvector('V')
x = T.dvector('x')
y = T.dot(x, W)
VJ = T.Lop(y, W, V)#这里直接调用的就是Rop函数对应右乘操作
f = theano.function([V,x], VJ)
f([2, 2], [0, 1])
'''
array([[ 0.,  0.],[ 2.,  2.]])
'''
yV∗∂y∂W=W∗x=V∗x

\begin{aligned} y&=W*x\\ V*\frac{\partial y}{\partial W}&=V*x \end{aligned}

左乘和右乘的差别

其实从矩阵的乘法规则就能发现他们的不同:

左乘中的v与输出有相同的shape, 右乘中的v与输入有相同的shape

左乘的结果与输入有相同shape, 右乘的结果与输出有相似的shape

海森矩阵与向量乘积

由于Hessian矩阵具有对成型, 所以有两种操作可以得到相同的结果,但是性能可能稍有不同。所以theano建议大家在使用两个方法时先分析一下

方法一:

x=T.dvector('x')
v=T.dvector('v')
y=T.sum(x**2)#定义操作
gy=T.grad(y,x)#一阶导
vH=T.grad(T.sum(gy*v),x)#利用一阶导得到二阶导
f=theano.function([x,v],vH)
f([4,4],[2,2])
'''
array([ 4.,  4.])
'''

方法二:

x=T.dvector('x')
v=T.dvector('v')
y=T.sum(x**2)#定义操作
gy=T.grad(y,x)#一阶导
Hv=T.Rop(gy,x,v)#利用Jacobian矩阵的右乘操作
f=theano.function([x,v],Hv)
f([4,4],[2,2])
'''
array([ 4.,  4.])
'''

注意事项

  • grad函数是符号运算: 接受和返回Theano变量
  • grad可以被重复使用
  • grad操作中, 标量损失可以直接用grad处理, 但是数组类型的需要用循环处理,比如计算Jacobian矩阵中需要对向量中每个值进行梯度的循环计算
  • 内置函数能够高效计算向量*雅可比式、向量*海森矩阵

代码地址:链接: https://pan.baidu.com/s/1eSAIZOu 密码: wu27

【theano-windows】学习笔记三——theano中的导数相关推荐

  1. docker学习笔记(三)docker中的网络

    目录 Linux中的网卡 Network Namespace Docker中的Bridge网络 使用自定义Bridge网络创建容器 Container中的其他网络 Host网络 None网络 Linu ...

  2. 【theano-windows】学习笔记十七——梯度中的consider_constant

    前言 主要是在写玻尔兹曼机相关的theano时, 在计算梯度grad的时候发现一个参数名字叫做consider_constant,来看看这个到底做了什么事情 参考博客: using consider_ ...

  3. 【theano-windows】学习笔记十一——theano中与神经网络相关函数

    前言 经过softmax和MLP的学习, 我们发现thenao.tensor中除了之前的博客[theano-windows]学习笔记五--theano中张量部分函数提到的张量的定义和基本运算外, 还有 ...

  4. 【theano-windows】学习笔记六——theano中的循环函数scan

    前言 Scan是Theano中最基础的循环函数, 官方教程主要是通过大量的例子来说明用法. 不过在学习的时候我比较习惯先看看用途, 然后是参数说明, 最后再是研究实例. 国际惯例, 参考网址 官网关于 ...

  5. python3常用模块_Python学习笔记三(常用模块)

    Python 学习笔记三 (常用模块) 1.os模块 os模块包装了不同操作系统的通用接口,使用户在不同操作系统下,可以使用相同的函数接口,返回相同结构的结果. os.name:返回当前操作系统名称( ...

  6. K8S 学习笔记三 核心技术 Helm nfs prometheus grafana 高可用集群部署 容器部署流程

    K8S 学习笔记三 核心技术 2.13 Helm 2.13.1 Helm 引入 2.13.2 使用 Helm 可以解决哪些问题 2.13.3 Helm 概述 2.13.4 Helm 的 3 个重要概念 ...

  7. OpenCasCade学习笔记(三):加载显示STEP格式图片,并实现平移、缩放和旋转操作

    OpenCasCade学习笔记(三):加载显示STEP格式图片,并实现平移.缩放和旋转操作 C3DWidget.h #pragma once#include <QtWidgets/QApplic ...

  8. J2EE学习笔记三:EJB基础概念和知识 收藏

    J2EE学习笔记三:EJB基础概念和知识 收藏 EJB正是J2EE的旗舰技术,因此俺直接跳到这一章来了,前面的几章都是讲Servlet和JSP以及JDBC的,俺都懂一些.那么EJB和通常我们所说的Ja ...

  9. tensorflow学习笔记(三十二):conv2d_transpose (解卷积)

    tensorflow学习笔记(三十二):conv2d_transpose ("解卷积") deconv解卷积,实际是叫做conv_transpose, conv_transpose ...

最新文章

  1. 浅谈如何提升数据中心制冷能效
  2. java书籍_学习Java最好的10本书,从入门到精通
  3. SVN服务备份操作步骤
  4. [刨根问底] 五分钟搞懂组合评价模型—模糊Borda (以2021 年大学生数模国赛C题为例)
  5. System x 服务器制作ServerGuide U盘安装Windows Server 2003 操作系统
  6. matlab gui串口通信,Matlab GUI上位机界面实现串口通信
  7. TFS2010学习之一
  8. 运放输入偏置电流方向_输入偏置电流和输入失调电流(运放参数的详细解释和分析)...
  9. 微信公众号的黑色商业链揭秘
  10. linux安装frps服务,Debian手动搭建frps服务端
  11. 跳一跳改分java源码_解密微信小程序漏洞:可下载任意小游戏源代码,“跳一跳”可改分...
  12. dom4j解析XML实例
  13. python3+itchat实战
  14. maven如何排除依赖
  15. iphone常用代码锦集(二)
  16. Android kernel log level查看和设置
  17. 从古到今 回顾苹果Mac OS的前世今生
  18. 高响应比优先调度算法
  19. 自定义 MyBatis 拦截器
  20. wifinbsp;驱动nbsp;进阶11

热门文章

  1. linux中544进程,Linux基础--进程管理及其基本命令
  2. mysql 索引 原理_MySQL索引实现原理分析
  3. 计算机的硬盘和光盘数,磁盘与光盘介绍-计算机组成原理与汇编语言-电子发烧友网站...
  4. php中文网面试题_2020年PHP面试题大汇总(收藏)
  5. java alder32_Java里面计算Adler32校验
  6. 【算法竞赛学习】气象海洋预测-Task2 数据分析
  7. 证明:对于一棵二叉树,若度为2的结点有n2个,叶子结点有n0个,则n0=n2+1
  8. PyTorch常用代码段整理合集
  9. PADS2007中的层类型(plane type) 简介
  10. python计算机视觉编程——第一章(基本的图像操作和处理)