前言

上一篇博客中学到了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(⋅)ln(\cdot)区分开,logistic函数公式如下:

s(x)=11+e−x

s(x)=\frac{1}{1+e^{-x}}
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+e−x=1+tanh(x/2)2

s(x)=\frac{1}{1+e^{-x}}=\frac{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

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

  1. ES6学习笔记二arrow functions 箭头函数、template string、destructuring

    接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...

  2. springmvc学习笔记二:重定向,拦截器,参数绑定

    springmvc学习笔记二:重定向,拦截器,参数绑定 Controller方法返回值 返回ModelAndView controller方法中定义ModelAndView对象并返回,对象中可添加mo ...

  3. JS学习笔记——高级编程中compose函数的介绍和基本实现

    1.前言 在之前探讨redux的中间件的时候,applyMiddleware源码中有遇到过compose()函数,当时不太明白起作用,所以就上网好好查了一下,做了个总结. 2.普通函数 在函数式编程当 ...

  4. python中argsort_(学习笔记)numpy中argsort函数用法

    在Python中使用help帮助 >>> import numpy >>> help(numpy.argsort) Help on function argsort ...

  5. python3.4学习笔记(二十) python strip()函数 去空格\n\r\t函数的用法

    https://www.cnblogs.com/zdz8207/p/python_learn_note_20.html

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

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

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

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

  8. css中怎么加入立体模型,CSS学习笔记二:css 画立体图形

    继上一次学了如何去运用css画平面图形,这一次学如何去画正方体,从2D向着3D学习,虽然有点满,但总是一个过程,一点一点积累,然后记录起来. Transfrom3D 在这一次中运用到了一下几种属性: ...

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

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

最新文章

  1. 聊天软件系统测试用例,QQ聊天框测试用例设计
  2. 为何Java中子类重写方法的访问权限不能低于父类中权限
  3. python查询数据库带逗号_浅谈pymysql查询语句中带有in时传递参数的问题
  4. 《机器学习实战》chapter03 决策树
  5. 预处理器命令必须作为第一个非空白空间启动_第三章 图形处理器(上)
  6. mysql run sql files_如何在Eclipse DTP中運行多個.sql文件
  7. 用Python去除扫描型PDF中的水印
  8. c语言课设报告函数的比较,c语言课程设计设计报告函数的调用关系图及主要算法.doc...
  9. 2017.6.5 YY的GCD 失败总结
  10. 华为FreeBuds 3耳机更新推送:新增支持骨声纹识别特征
  11. 深入浅出Yolo系列之Yolox核心基础完整讲解
  12. Oracle数据库表空间数据文件最大容量以及存满时处理方法
  13. 量化交易 米筐 策略评价指标
  14. 数据库事务Transaction)那点事
  15. 系统架构师—软件架构设计(二)CS/BS/SOA/DSSA/ABSD
  16. 读书笔记:PHP和MySQL高性能应用开发 (2019.2.20-2019.3.4)
  17. 长期坐着不动会得什么病?
  18. Java进阶学习资料,java小程序开发面试题
  19. Python-修改密码功能
  20. [AWS] dynamodb-local本地数据库安装以及dynamoose模块连接dynamodb-local

热门文章

  1. k5b型计算机联锁知识,DS6-K5B计算机联锁系统日常维护注意事项
  2. 五大特点_探究干细胞五大特点:(五)不成瘤
  3. New Year and Ascent Sequence(二分)
  4. 并发请求数_nginx如何限制并发连接和请求数?
  5. 1001 A+B Format (20point(s))(Java和C++)
  6. 大一高数下册笔记整理_初中化学期中重难点解读,复习不用愁啦,建议抄笔记...
  7. python 逗号作用 语句间_Python 逗号的几种作用
  8. 全网最简单明了的MySQL连接Eclipse方法(JDBC详细安装方式及简单操作)2020新版
  9. 数学--数论--Hdu 5793 A Boring Question (打表+逆元)
  10. Eigen入门之密集矩阵 3 - Array操作