【theano-windows】学习笔记二——theano中的函数和共享参数

前言

上一篇博客中学到了theano中的变量类型,也就是dscalardvector之类的, 然后还有一个theano.functioneval函数, 将我们所定义的操作转换成theano可执行的函数,类似于def, 还有就是简单的线性代数运算操作。

在神经网络(NN)中, 我们声明了权重、偏置,剩下的就是激活函数,权重和偏置更新之类的东西了,而权重我们一直存储在一个变量(比如w)中,不会说每次梯度更新都声明一个变量(w1,w2,w3…..), 因而这个变量是共享的. 这个学习笔记主要就是解决这两个问题(激活函数,权重和偏置共享),当然还会稍微看看函数拷贝以及随机数生成的操作。

国际惯例,参考网址

官方tutorial

程序运行预先导入的模块有:

#-*- coding:utf-8 -*-
#http://www.deeplearning.net/software/theano/tutorial/examples.html
import theano
import theano.tensor as T
import numpy as np
import matplotlib.pyplot as plt

对率函数

logistic函数又称为对数几率函数(周志华《机器学习》58页),是一种重要的sigmoid函数, 注意与对数函数ln()区分开,logistic函数公式如下:

s(x)=11+ex

theano可执行的函数来实现就是

x=T.dvector('x')
y=1/(1+T.exp(-x))
logistic=theano.function([x],y)
x_tick=np.arange(-6,6,0.1)
y_tick=logistic(x_tick)

画出来瞅瞅

#把坐标轴移到中间
ax=plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_position(('data',0))
ax.spines['left'].set_position(('data',0))
#画图
plt.plot(x_tick,y_tick,'r-')
plt.show()

这里写图片描述

需要了解的是,logistic函数是逐元素进行的,因为这些操作(除,加,指数)本身就是逐元素运算。

此外,由于

s(x)=11+ex=1+tanh(x/2)2

所以函数也可以这样写

y2=(1+T.tanh(x/2))/2
logistic2=theano.function([x],y2)
y2_tick=logistic2(x_tick)
plt.plot(x_tick,y_tick,'r-')
plt.show()

同时进行多种运算

上面的theano.function都只定义了一种运算操作,然而theano还支持多输出, 比如我们可以同时计算两个矩阵的差, 差的绝对值, 差的平方

#多个操作同时进行
a,b=T.dmatrices('a','b')
diff=a-b
diff_abs=abs(diff)
diff_square=diff**2
f=theano.function([a,b],[diff,diff_abs,diff_square])
x1=np.array([[1,1],[1,1]])
y1=np.array([[0,1],[2,3]])
c,d,e=f(x1,y1)
print 'a-b=',c
print 'abs(a-b)=',d
print 'square(a-b)=',e

可以发现theano.function在执行多输出时, 按照第二个参数的顺序返回结果,所以我们可以用相同数量的变量接收结果

设置函数的默认参数值

C++差不多, 就是在function启用定义操作的时候, 对输入参数(也就是第一个参数列表)的某(几)个预先赋值, 需要使用theano.compile.io模块中的In函数

In(variable, name=None, value=None, update=None, mutable=False, strict=False, autoname=True, implicit=None)

value: 变量名,类似于上面用T.dvector声明的变量x

name: 默认就是变量名,也可将此变量设置为其它名字,后面就可以用这个名字访问或者赋值了, 其实就是方便了你不用严格按照function中参数的输入顺序也能使用变量名来进行输入

value: 变量的默认值, 当update=None的时候, 这个值就是参数默认值,反之updata是一个操作, 而非None的时候, 改变为默认值将会被’stick around’(停留), 主要还是因为一个update或者用户的显式操作

update: 每次调用update指向的操作函数,都会将返回值赋给value

mutable: 允许编译函数改变被用于默认值得python对象,感觉可以类比一下c++mutable,戳这里. 默认是False, 也就是不允许编译过的函数改变value所指向的python对象(这个以后实战操作看看具体用法)

strict: 检查你的输入是否为正确的类型,如果不是,就自动转换为合适的类型

后面几个用到再看,毕竟现在是新手, 好像很少用到后面几个参数

#import theano.compile.io as TIO#这个也可以
from theano import In
x,y,w=T.dscalars('x','y','w')
z=(x+y)*w
#为y设置默认值1,为w设置默认值2和名字w_by_name
# f = theano.function([x, TIO.In(y, value=1), TIO.In(w, value=2, name='w_by_name')], z)
f = theano.function([x, In(y, value=1), In(w, value=2, name='w_by_name')], z)
#使用y和z的默认值计算
f(33)
#使用z的默认参数
f(33,2)
#利用变量名不按照function中参数顺序赋值
f(33,w_by_name=1,y=0)

使用共享变量

例子: 做一个加法器, 每次调用函数就会加上所输入的值

思路: 先定义输入变量(每次需要加的数), 将每次返回的加和以后的数设置为共享变量, 利用update更新当前加和值,在取结果的时候要注意使用get_value()函数

from theano import shared
state=shared(0.0)#和的初始值为0,并且为共享变量
inc=T.dscalar('inc')#每次的增量加法减法共享这个和
accumulator=theano.function([inc],state,updates=[(state,state+inc)])#加法
decrementor=theano.function([inc],state,updates=[(state,state-inc)])#减法
#使用get_value()方法获取初始值
print state.get_value()
#加法
accumulator(3.0) #不要直接返回或者直接输出,要用get_value()取值
print state.get_value()
#减法
decrementor(2.0) #不要直接返回或者直接输出,要用get_value()取值
print state.get_value()

【注1】一定要注意state和所加数字inc变量类型一定要相同,如果把state=shared(0.0)改成state=shared(0),就会报错typeError: ('An update must have the same type as the original shared variable (shared_var=<TensorType(int32, scalar)>, shared_var.type=TensorType(int32, scalar), update_val=Elemwise{add,no_inplace}.0, update_val.type=TensorType(float64, scalar)).', 'If the difference is related to the broadcast pattern, you can call the tensor.unbroadcast(var, axis_to_unbroadcast[, ...]) function to remove broadcastable dimensions.')

【注2】我刚开始以为theano.function中第二个参数对应的是一个操作, 因为前面的theano.function([x],z)中的z一般就是定义的一个操作, 比如z=x**2之类的, 但是这种想法可能是错的. 因为在这节的实例中state仅仅是一个共享变量而已, 其操作都在update中, 所以目前可以把第二个参数当成返回的结果值,不管此结果值是一个变量(如共享变量)还是一个表达式结果(比如z=x+y)

这里接触了function中的另一个参数update, 此参数必须提供以的形式提供(共享变量, 新表达式), 它也可以是一个字典, 字典的keys就是共享变量, 字典的values就是新的表达式. 无论哪种方式,只要函数运行,共享变量的值就会被表达式的结果替代. 注意,一定要用get_value()的方式获取结果值, 否则获取到的就是未进行表达式运算的值

有时候我们在表达式中不想更新某个变量,就可以使用givens(variable1,variable2)variable2暂时替换variable1,这时候就不会更新variable1

state.set_value(0.0)
foo=T.scalar(dtype=state.dtype)#替换变量必须与被替换变量类型相同
temp_express=state+inc
skip_shared=theano.function([inc,foo],temp_express,givens=[(state,foo)])
skip_shared(1,3)
print state.get_value()
#0.0

这个givens参数可以使用任何符号变量替代,不仅仅是共享变量,也可以使用常量,表达式替换。但是不允许givens的表达式替换具有相互依赖关系.

关于theano.function更多的关于输入输出的介绍,可以戳这里的官网教程

拷贝函数

使用copy()方法能够将定义过的function的功能拷贝过来, 至于里面的输入参数, 可以使用swap={old_variable:new_variable}进行替换. 比如我们想拷贝一下上面的那个加法函数, 原始的state共享变量用new_state替换, 就可以这样写:

new_state=theano.shared(0.0)#定义新的共享变量
new_accmulator=accumulator.copy(swap={state:new_state})#拷贝函数并替换共享变量
new_accmulator(100)
print new_state.get_value()
#100.0

我们也可以在拷贝的时候把updates删掉

new_state1=theano.shared(1.0)
#移除拷贝函数的updates操作
null_accmulator=accumulator.copy(delete_updates=True,swap={state:new_state1})
null_accmulator(20)
print new_state1.get_value()
#1.0

随机数

生成随机数

只需要记住随机数的实现存在于RandomStreames模块中, function是用于执行功能的, 再考虑到numpy的随机数使用预先得有一个随机数种子seed, 那么可以很清晰得到theano中随机数的生成方法

#导入模块
from theano.tensor.shared_randomstreams import RandomStreams
#生成随机数种子
srng=RandomStreams(seed=234)
rv_u=srng.uniform((2,2))#从均匀分布中采样出一个2*2矩阵
rv_n=srng.normal((2,2))#从正太分布中采样出一个2*2矩阵
f=theano.function([],rv_u)
g=theano.function([],rv_n,no_default_updates=True)#加入了no_default_updates每次生成的随机数都一样
nearly=theano.function([],rv_u+rv_u-2*rv_u)
#分别利用f和g生成随机数
f_val0=f()
f_val1=f()#与f_val0不一样
g_val0=g()
g_val1=g()#与g_val0一样
nearly()
'''
array([[ 0.,  0.],[ 0.,  0.]], dtype=float32)
'''

no_default_updates表示每次生成的随机数都一样。需要注意的一点是,在任意一个函数执行的时候, 一个随机变量最多获取一次, 也就是说虽然rv_u在输出表达式中出现了三次, nearly函数仍能够保证返回接近0的值(除去化整误差)

随机数种子

单独为每个变量设置随机数种子, 比如为rv_u设置随机数种子需要三步, 先获取其种子, 随后赋予其一个种子值, 最后将此种子值设置入此rv_u的种子流中即可

rng_val=rv_u.rng.get_value(borrow=True)
rng_val.seed(89234)
rv_u.rng.set_value(rng_val,borrow=True)

也可以为设置所有变量的随机数种子一样

srng.seed(902340)#这个srng是一个RandomStreams变量

当然这样还不足够, 因为我们说过,所有的更新都必须放入到function中走一遍才能生效,紧接着的下个例子能体现出这一点

函数间共享随机流

下面的几行代码实现的就是:先第一次使用随机数生成器生成一组数据, 然后将第一次使用的随机数状态赋给下一次生成随机数的生成器,所以第一次执行function f()只是将随机数种子重置为第一次的种子,而它生成随机变量时,此重置效果并未执行,所以虽然接连两次执行f(), 却看到了v2!=v1v3=v1的结果

state_after_v0=rv_u.rng.get_value().get_state()#获取随机数生成器状态
nearly()#执行函数影响当前rv_u的随机数生成器
v1=f()#第一次生成随机数
#为某个变量设置随机数种子三部曲
rng=rv_u.rng.get_value(borrow=True)
rng.set_state(state_after_v0)
rv_u.rng.set_value(rng,borrow=True)
v2=f()#调用一次函数,使重新赋值的随机数生成器种子生效
v3=f()#利用重新赋值的种子生成随机数
print v2==v1
print v3==v1
'''
[[False False][False False]]
[[ True  True][ True  True]]
'''

上面生成的随机数分布分别是均匀分布和正太分布,当然theano中还提供了其他分布,戳这里

图结构间的随机流状态复制

关于什么是图结构,姑且把它先当做一个类吧, 然后这部分想要实现的就是类实例之间的随机种子复制

我们需要使用的模块有

from theano.sandbox.rng_mrg import MRG_RandomStreams
from theano.tensor.shared_randomstreams import RandomStreams

然后定义一个图类

#定义一个图类
class Graph():def __init__(self,seed=123):self.rng=RandomStreams(seed)self.y=self.rng.uniform(size=(1,))

随后生成两个实例,看看不同随机数种子生成结果

#实例化第一个对象
g1=Graph(seed=123)
f1=theano.function([],g1.y)
#实例化第二个对象
g2=Graph(seed=987)
f2=theano.function([],g2.y)
a=f1()
b=f2()
print a
#[ 0.72803009]
print b
#[ 0.55056769]

接着定义一个拷贝随机数生成器种子的函数并生效, 然后再分别生成两个实例的随机数, 看看是否相等

#共享g1和g2的随机数种子
def copy_random_state(g1,g2):if isinstance(g1.rng,MRG_RandomStreams):g2.rng.rstate=g1.rng.rstatefor (su1,su2) in zip(g1.rng.state_updates,g2.rng.state_updates):su2[0].set_value(su1[0].get_value())#赋值
copy_random_state(g1,g2)
c=f1()
d=f2()
print c==d
#True

【注】这一部分消化不了没关系,毕竟这么多乱糟糟的随机数定义和生成器种子拷贝方法,还设计到变量或者图之间的各种函数,熟悉一点点,再后面看到它知道就行了,以后哪个用的多就记哪个

总结

这一章节首先注意的是共享变量的定义, 然后是function比较重要的两个参数updates()givens(),它俩都是后一个值取代前一个值,只不过前者用于共享变量的更新,后者是不想更新共享变量时候用其它东西替代共享变量进行运算。还有一个就是copy()函数用于拷贝定义的函数, swap替换变量和`delete_updates取消操作的使用要记住。还有就是随机数生成以及变量或者图间随机数生成器的种子共享,也就是说如何让两次调用随机数生成器得到相同的随机数

从NN的设计来看,我们大概已经知道了如何定义权重、偏置,以及它们的随机初始化赋值, 如何进行它们之间的函数操作(加减乘除, 函数激活), 如何让之前计算的权重、偏置共享到下一次计算中,也就是说用新的权重覆盖旧的权重, 剩下的就是损失函数的梯度计算问题了。
代码地址:链接: https://pan.baidu.com/s/1pLMBQYZ 密码: f6f8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246644.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【theano-windows】学习笔记三——theano中的导数

前言 就一个NN而言&#xff0c;包含梯度、偏置、参数更新&#xff0c;而前面第一篇博客学习了theano中符号变量的定义, 第二篇博客学习了变量的随机初始化, 变量之间的互相操作(类似于sigmoid(w∗xb)), 但是参数更新还应涉及到损失函数的偏导计算&#xff0c;这一章节就是看看…

【theano-windows】学习笔记五——theano中张量部分函数

前言 至此感觉应该可以写出一个logistic回归程序了&#xff0c;但是为了达到对theano中张量的更灵活的使用, 还是先看一下thenao.tensor对变量都提供了哪些操作&#xff0c;最全的文档戳这里或者这里, 这里就稍微摘取一点自我感觉以后可能用得多的函数 基本张量函数 创建张量…

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

前言 Scan是Theano中最基础的循环函数, 官方教程主要是通过大量的例子来说明用法. 不过在学习的时候我比较习惯先看看用途, 然后是参数说明, 最后再是研究实例. 国际惯例, 参考网址 官网关于Scan的11个例子 官网更全面的介绍 简介 用途 递归的一般形式, 可以被用于循环s…

【theano-windows】学习笔记九——softmax手写数字分类

前言 上一篇博客折腾了数据集的预备知识, 接下来按照官方的Deep learning 0.1 documentation一步步走, 先折腾softmax, 关于softmax和logistic回归分类的联系, 我在之前写过一个小博客 国际惯例, 参考博客走一波: Classifying MNIST digits using Logistic Regression soft…

【theano-windows】学习笔记十——多层感知机手写数字分类

前言 上一篇学习了softmax, 然后更进一步就是学习一下基本的多层感知机(MLP)了. 其实多层感知机同时就是w*xb用某个激活函数激活一下, 得到的结果作为下一层神经元的输入x, 类似于 output⋯f3(f2(f1(x∗w1b2)∗w2b2)∗w3b3)⋯output=\cdots f^3(f^2(f^1(x*w^1+b^2)*w^2+b^2)*…

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

前言 经过softmax和MLP的学习, 我们发现thenao.tensor中除了之前的博客【theano-windows】学习笔记五——theano中张量部分函数提到的张量的定义和基本运算外, 还有一个方法称为nnet, 如果自己实现过前面两篇博客中的代码就会发现用到了theano.tensor.nnet.sigmoid和thenao.te…

【caffe-windows】全卷积网络特征图分析

前言 突然就想分析一下全卷积网络的转置卷积部分了, 就是这么猝不及防的想法, 而且这个网络对图片的输入大小无要求&#xff0c;这么神奇的网络是时候分析一波了&#xff0c;我个人的学习方法调试代码&#xff0c;然后对照论文看理论 本次分析主要针对每层的权重大小和特征图…

【theano-windows】学习笔记十二——卷积神经网络

前言 按照进度, 学习theano中的卷积操作 国际惯例, 来一波参考网址 Convolutional Neural Networks (LeNet) 卷积神经网络如何应用在彩色图像上&#xff1f; 卷积小知识 三大特性&#xff1a;局部感知(稀疏连接), 权值共享, 池化 上图很重要, 描述的是前一个隐层m-1具有四…

【theano-windows】学习笔记十三——去噪自编码器

前言 上一章节学习了卷积的写法,主要注意的是其实现在theano.tensor.nnet和theano.sandbox.cuda.dnn中都有对应函数实现, 这一节就进入到无监督或者称为半监督的网络构建中. 首先是自编码器(Autoencoders)和降噪自编码器(denoising Autoencoders) 国际惯例, 参考网址: Denoi…

【theano-windows】学习笔记十四——堆叠去噪自编码器

前言 前面已经学习了softmax,多层感知器,CNN&#xff0c;AE&#xff0c;dAE&#xff0c;接下来可以仿照多层感知器的方法去堆叠自编码器 国际惯例&#xff0c;参考文献&#xff1a; Stacked Denoising Autoencoders (SdA) Greedy Layer-Wise Training of Deep Networks 理…

【theano-windows】学习笔记十五——受限玻尔兹曼机

前言 终于到了最喜欢的模型: 受限玻尔兹曼机(RBM)了, 发现关于RBM是如何从能量模型发展过来的介绍非常不错, 而关于详细理论证明, 可以去看我前面的受限玻尔兹曼机的一系列博客. 国际惯例, 参考博客,超级强推第二个博客, 证明过程很给力: Restricted Boltzmann Machines (R…

【Ogre-windows】环境配置

前言 由于工程原因, 学习一下Ogre面向对象图形渲染开源引擎, 慢慢爬坑吧。首先还是环境的配置问题哎. 其实最重要的是要预先编译三方库, 虽然官方说可以自动编译, 但是在自己电脑上还是出现了无法解析外部符号之类的问题, 正常情况下我就认为是三方库的lib出现了问题, 最后额外…

【theano-windows】学习笔记十六——深度信念网络DBN

前言 前面学习了受限玻尔兹曼机(RBM)的理论和搭建方法, 如果稍微了解过的人, 肯定知道利用RBM可以堆叠构成深度信念网络(deep belief network, DBN)和深度玻尔兹曼机(deep Boltzmann machine), 这里就先学习一下DBN. 国际惯例, 参考博文: Deep Belief Networks A fast lear…

【Ogre-windows】实例配置

前言 折腾了好久才搞定教程实例, 主要是因为上一篇博客安装的具体版本是Ogre1.10.9, 而官方的Ogre Wiki Tutorial Framework没有指定具体版本, 如果单纯下载Ogre Wiki Tutorial Framework 1.10 - (Windows line endings, updated 2015-10-15) 运行, 基本会血崩. 所以, 在经过仔…

【Ogre-windows】旋转矩阵及位置解析

前言 这篇博客主要针对三种问题 如何创建动画帧如何获取全局位置如何计算全局旋转矩阵 仿真环境为VS2013Ogre1.10.9与matlab验证 创建动画帧 这里只做一个简单的实验: 将自带的人物模型Jaiqua的run运动给新创建的运动myrun中并播放&#xff0c;直接贴代码了 void JaiQua:…

BP推导——续

前言 之前有证明过一次人工神经网络——【BP】反向传播算法证明 &#xff0c;但是回头看的时候&#xff0c;有很多地方非常不严谨&#xff0c;特此拿出来再单独证明一次BP&#xff0c;并严格保证其严谨性。如果想看看粗略的证明&#xff0c;可以去看我之前的博客&#xff0c;毕…

matlab学习——强连通分量

前言 最近motion graph相关实验&#xff0c;发现实现运动过渡需要构建运动图&#xff0c;而为了避免运动过渡陷入死胡同&#xff0c;需要对图结构进行裁剪&#xff0c;方法就是计算图模型的极大强联通分量&#xff0c;但是自己懒得去实现&#xff0c;所以就去搜了一下matlab中…

【音频处理】离散傅里叶变换

前言 最近复现音乐驱动舞蹈的文章《Dancing-to-Music Character Animation》&#xff0c;用到了与傅里叶变换很相似的称为常Q变换的方法去分割音乐&#xff0c;所以对傅里叶变换做了一个小了解&#xff0c;本文不深入各种乱糟糟的理论&#xff0c;比如什么蝶形算法啥的&#x…

【音频处理】短时傅里叶变换

前言 上一篇博客讲了离散傅里叶变换&#xff0c;里面的实例是对整个信号进行计算&#xff0c;虽然理论上有N点傅里叶变换(本博客就不区分FFT和DFT了&#xff0c;因为它俩就是一个东东&#xff0c;只不过复杂度不同)&#xff0c;但是我个人理解是这个N点是信号前面连续的N个数值…

【theano-windows】学习笔记十九——循环神经网络

前言 前面已经介绍了RBM和CNN了&#xff0c;就剩最后一个RNN了&#xff0c;抽了一天时间简单看了一下原理&#xff0c;但是没细推RNN的参数更新算法BPTT&#xff0c;全名是Backpropagation Through Time。 【注】严谨来说RNN有两个称呼&#xff1a;①结构上递归的recursive n…