如何在局域网上做网站,怎么做家教网站,室内设计图网站有哪些,湖北城乡和建设官方网站前言
上一篇博客中学到了theano中的变量类型#xff0c;也就是dscalar、dvector之类的, 然后还有一个theano.function和eval函数, 将我们所定义的操作转换成theano可执行的函数#xff0c;类似于def, 还有就是简单的线性代数运算操作。
在神经网络(NN)中, 我们声明了权重、…前言
上一篇博客中学到了theano中的变量类型也就是dscalar、dvector之类的, 然后还有一个theano.function和eval函数, 将我们所定义的操作转换成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)11e−xs(x)=\frac{1}{1+e^{-x}}用
theano可执行的函数来实现就是xT.dvector(x)
y1/(1T.exp(-x))
logistictheano.function([x],y)
x_ticknp.arange(-6,6,0.1)
y_ticklogistic(x_tick)
画出来瞅瞅
#把坐标轴移到中间
axplt.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)11e−x1tanh(x/2)2s(x)=\frac{1}{1+e^{-x}}=\frac{1+\tanh(x/2)}{2}所以函数也可以这样写y2(1T.tanh(x/2))/2
logistic2theano.function([x],y2)
y2_ticklogistic2(x_tick)
plt.plot(x_tick,y_tick,r-)
plt.show()
同时进行多种运算
上面的theano.function都只定义了一种运算操作然而theano还支持多输出, 比如我们可以同时计算两个矩阵的差, 差的绝对值, 差的平方
#多个操作同时进行
a,bT.dmatrices(a,b)
diffa-b
diff_absabs(diff)
diff_squarediff**2
ftheano.function([a,b],[diff,diff_abs,diff_square])
x1np.array([[1,1],[1,1]])
y1np.array([[0,1],[2,3]])
c,d,ef(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, nameNone, valueNone, updateNone, mutableFalse, strictFalse, autonameTrue, implicitNone)
value: 变量名类似于上面用T.dvector声明的变量x
name: 默认就是变量名,也可将此变量设置为其它名字后面就可以用这个名字访问或者赋值了, 其实就是方便了你不用严格按照function中参数的输入顺序也能使用变量名来进行输入
value: 变量的默认值, 当updateNone的时候, 这个值就是参数默认值反之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,wT.dscalars(x,y,w)
z(xy)*w
#为y设置默认值1,为w设置默认值2和名字w_by_name
# f theano.function([x, TIO.In(y, value1), TIO.In(w, value2, namew_by_name)], z)
f theano.function([x, In(y, value1), In(w, value2, namew_by_name)], z)
#使用y和z的默认值计算
f(33)
#使用z的默认参数
f(33,2)
#利用变量名不按照function中参数顺序赋值
f(33,w_by_name1,y0)
使用共享变量
例子: 做一个加法器, 每次调用函数就会加上所输入的值
思路: 先定义输入变量(每次需要加的数), 将每次返回的加和以后的数设置为共享变量, 利用update更新当前加和值在取结果的时候要注意使用get_value()函数
from theano import shared
stateshared(0.0)#和的初始值为0,并且为共享变量
incT.dscalar(inc)#每次的增量加法减法共享这个和
accumulatortheano.function([inc],state,updates[(state,stateinc)])#加法
decrementortheano.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变量类型一定要相同如果把stateshared(0.0)改成stateshared(0),就会报错typeError: (An update must have the same type as the original shared variable (shared_varTensorType(int32, scalar), shared_var.typeTensorType(int32, scalar), update_valElemwise{add,no_inplace}.0, update_val.typeTensorType(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一般就是定义的一个操作, 比如zx**2之类的, 但是这种想法可能是错的. 因为在这节的实例中state仅仅是一个共享变量而已, 其操作都在update中, 所以目前可以把第二个参数当成返回的结果值不管此结果值是一个变量(如共享变量)还是一个表达式结果(比如zxy)
这里接触了function中的另一个参数update, 此参数必须提供以对的形式提供(共享变量, 新表达式), 它也可以是一个字典, 字典的keys就是共享变量, 字典的values就是新的表达式. 无论哪种方式只要函数运行共享变量的值就会被表达式的结果替代. 注意一定要用get_value()的方式获取结果值, 否则获取到的就是未进行表达式运算的值
有时候我们在表达式中不想更新某个变量就可以使用givens(variable1,variable2)用variable2暂时替换variable1,这时候就不会更新variable1了
state.set_value(0.0)
fooT.scalar(dtypestate.dtype)#替换变量必须与被替换变量类型相同
temp_expressstateinc
skip_sharedtheano.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_statetheano.shared(0.0)#定义新的共享变量
new_accmulatoraccumulator.copy(swap{state:new_state})#拷贝函数并替换共享变量
new_accmulator(100)
print new_state.get_value()
#100.0
我们也可以在拷贝的时候把updates删掉
new_state1theano.shared(1.0)
#移除拷贝函数的updates操作
null_accmulatoraccumulator.copy(delete_updatesTrue,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
#生成随机数种子
srngRandomStreams(seed234)
rv_usrng.uniform((2,2))#从均匀分布中采样出一个2*2矩阵
rv_nsrng.normal((2,2))#从正太分布中采样出一个2*2矩阵
ftheano.function([],rv_u)
gtheano.function([],rv_n,no_default_updatesTrue)#加入了no_default_updates每次生成的随机数都一样
nearlytheano.function([],rv_urv_u-2*rv_u)
#分别利用f和g生成随机数
f_val0f()
f_val1f()#与f_val0不一样
g_val0g()
g_val1g()#与g_val0一样
nearly()array([[ 0., 0.],[ 0., 0.]], dtypefloat32)no_default_updates表示每次生成的随机数都一样。需要注意的一点是在任意一个函数执行的时候, 一个随机变量最多获取一次, 也就是说虽然rv_u在输出表达式中出现了三次, nearly函数仍能够保证返回接近0的值(除去化整误差)
随机数种子
单独为每个变量设置随机数种子, 比如为rv_u设置随机数种子需要三步, 先获取其种子, 随后赋予其一个种子值, 最后将此种子值设置入此rv_u的种子流中即可
rng_valrv_u.rng.get_value(borrowTrue)
rng_val.seed(89234)
rv_u.rng.set_value(rng_val,borrowTrue)
也可以为设置所有变量的随机数种子一样
srng.seed(902340)#这个srng是一个RandomStreams变量
当然这样还不足够, 因为我们说过所有的更新都必须放入到function中走一遍才能生效紧接着的下个例子能体现出这一点
函数间共享随机流
下面的几行代码实现的就是先第一次使用随机数生成器生成一组数据, 然后将第一次使用的随机数状态赋给下一次生成随机数的生成器所以第一次执行function f()只是将随机数种子重置为第一次的种子而它生成随机变量时此重置效果并未执行,所以虽然接连两次执行f(), 却看到了v2!v1而v3v1的结果
state_after_v0rv_u.rng.get_value().get_state()#获取随机数生成器状态
nearly()#执行函数影响当前rv_u的随机数生成器
v1f()#第一次生成随机数
#为某个变量设置随机数种子三部曲
rngrv_u.rng.get_value(borrowTrue)
rng.set_state(state_after_v0)
rv_u.rng.set_value(rng,borrowTrue)
v2f()#调用一次函数使重新赋值的随机数生成器种子生效
v3f()#利用重新赋值的种子生成随机数
print v2v1
print v3v1[[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,seed123):self.rngRandomStreams(seed)self.yself.rng.uniform(size(1,))
随后生成两个实例看看不同随机数种子生成结果
#实例化第一个对象
g1Graph(seed123)
f1theano.function([],g1.y)
#实例化第二个对象
g2Graph(seed987)
f2theano.function([],g2.y)
af1()
bf2()
print a
#[ 0.72803009]
print b
#[ 0.55056769]
接着定义一个拷贝随机数生成器种子的函数并生效, 然后再分别生成两个实例的随机数, 看看是否相等
#共享g1和g2的随机数种子
def copy_random_state(g1,g2):if isinstance(g1.rng,MRG_RandomStreams):g2.rng.rstateg1.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)
cf1()
df2()
print cd
#True
【注】这一部分消化不了没关系毕竟这么多乱糟糟的随机数定义和生成器种子拷贝方法还设计到变量或者图之间的各种函数熟悉一点点再后面看到它知道就行了以后哪个用的多就记哪个
总结
这一章节首先注意的是共享变量的定义, 然后是function比较重要的两个参数updates()和givens()它俩都是后一个值取代前一个值只不过前者用于共享变量的更新后者是不想更新共享变量时候用其它东西替代共享变量进行运算。还有一个就是copy()函数用于拷贝定义的函数, swap替换变量和delete_updates取消操作的使用要记住。还有就是随机数生成以及变量或者图间随机数生成器的种子共享也就是说如何让两次调用随机数生成器得到相同的随机数
从NN的设计来看我们大概已经知道了如何定义权重、偏置以及它们的随机初始化赋值, 如何进行它们之间的函数操作(加减乘除, 函数激活), 如何让之前计算的权重、偏置共享到下一次计算中也就是说用新的权重覆盖旧的权重, 剩下的就是损失函数的梯度计算问题了。 代码地址链接: https://pan.baidu.com/s/1pLMBQYZ 密码: f6f8