购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.4 函数

上节我们介绍了如何把一个符号表达式转化为符号计算图,这节我们介绍函数的功能,函数是Theano的一个核心设计模块,它提供一个接口,把函数计算图编译为可调用的函数对象。前面介绍了如何定义自变量x(不需要赋值),这节介绍如何编写函数方程。

1.函数定义的格式

先来看一下函数格式示例:


theano.function(inputs, outputs, mode=None, updates=None, givens=None, no_default_updates=False, accept_inplace=False, name=None,rebuild_strict=True, allow_input_downcast=None, profile=None, on_unused_input='raise')。

这里参数看起来很多,但一般只用到三个:inputs表示自变量;outputs表示函数的因变量(也就是函数的返回值);还有一个比较常用的是updates参数,它一般用于神经网络共享变量参数更新,通常以字典或元组列表的形式指定。此外,givens是一个字典或元组列表,记为[(var1,var2)],表示在每一次函数调用时,在符号计算图中,把符号变量var1节点替换为var2节点,该参数常用来指定训练数据集的batch大小。

下面我们看一个有多个自变量,同时又有多个因变量的函数定义例子:


import theano  
x, y =theano.tensor.fscalars('x', 'y')  
z1= x + y  
z2=x*y  
#定义x、y为自变量,z1、z2为函数返回值(因变量)
f =theano.function([x,y],[z1,z2])  

#返回当x=2,y=3的时候,函数f的因变量z1,z2的值
print(f(2,3))

打印结果:


[array(5.0, dtype=float32), array(6.0, dtype=float32)]

在执行theano.function()时,Theano进行了编译优化,得到一个end-to-end的函数,传入数据调用f(2,3)时,执行的是优化后保存在图结构中的模型,而不是我们写的那行z=x+y,尽管二者结果一样。这样的好处是Theano可以对函数f进行优化,提升速度;坏处是不方便开发和调试,由于实际执行的代码不是我们写的代码,所以无法设置断点进行调试,也无法直接观察执行时中间变量的值。

2.自动求导

有了符号计算,自动计算导数就很容易了。tensor.grad()唯一需要做的就是从outputs逆向遍历到输入节点。对于每个op,它都定义了怎么根据输入计算出偏导数。使用链式法则就可以计算出梯度了。利用Theano求导时非常方便,可以直接利用函数theano.grad(),比如求s函数的导数:

以下代码实现当x=3的时候,求s函数的导数:


import theano  
x =theano.tensor.fscalar('x')#定义一个float类型的变量x  
y= 1 / (1 + theano.tensor.exp(-x))#定义变量y  
dx=theano.grad(y,x)#偏导数函数  
f= theano.function([x],dx)#定义函数f,输入为x,输出为s函数的偏导数  
print(f(3))#计算当x=3的时候,函数y的偏导数

打印结果:


0.045176658779382706

3.更新共享变量参数

在深度学习中通常需要迭代多次,每次迭代都需要更新参数。Theano如何更新参数呢?在theano.function函数中,有一个非常重要的参数updates。updates是一个包含两个元素的列表或tuple,一般示例为updates=[old_w,new_w],当函数被调用的时候,会用new_w替换old_w,具体看下面这个例子。


import theano
w= theano.shared(1)#定义一个共享变量w,其初始值为1  
x=theano.tensor.iscalar('x')  
f=theano.function([x], w, updates=[[w, w+x]])#定义函数自变量为x,因变量为w,当函数执行完毕后,更新参数w=w+x  
print(f(3))#函数输出为w  
print(w.get_value())#这个时候可以看到w=w+x为4

打印结果:


1、4

在求梯度下降的时候,经常用到updates这个参数。比如updates=[w,w-α*(dT/dw)],其中dT/dw就是梯度下降时,代价函数对参数w的偏导数,α是学习速率。为便于大家更全面地了解Theano函数的使用方法,下面我们通过一个逻辑回归的完整实例来说明: FM6fUifyjco+frimWXAxD/B++2csv3D5BD7OA0Z43UCIWX9tVhg/azoELNVhA6s+


import numpy  as np
import theano  
import theano.tensor as T  
rng = np.random  

# 我们为了测试,自己生成10个样本,每个样本是3维的向量,然后用于训练 
N = 10
feats = 3
D = (rng.randn(N, feats).astype(np.float32), rng.randint(size=N, low=0, high=2).astype(np.float32))

# 声明自变量x、以及每个样本对应的标签y(训练标签)  
x = T.matrix("x")
y = T.vector("y")

#随机初始化参数w、b=0,为共享变量  
w = theano.shared(rng.randn(feats), name="w")  
b = theano.shared(0., name="b")

#构造代价函数
p_1 = 1 / (1 + T.exp(-T.dot(x, w) - b))   # s激活函数  
xent = -y * T.log(p_1) - (1-y) * T.log(1-p_1) # 交叉商代价函数
cost = xent.mean() + 0.01 * (w ** 2).sum()# 代价函数的平均值+L2正则项以防过拟合,其中权重衰减系数为0.01  
gw, gb = T.grad(cost, [w, b])             #对总代价函数求参数的偏导数  
prediction = p_1 > 0.5                    # 大于0.5预测值为1,否则为0.
train = theano.function(inputs=[x,y],outputs=[prediction, xent],updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb)))#训练所需函数
predict = theano.function(inputs=[x], outputs=prediction)#测试阶段函数  

#训练  
training_steps = 1000  
for i in range(training_steps):  
    pred, err = train(D[0], D[1])  
    print (err.mean())#查看代价函数下降变化过程

点击中间区域
呼出菜单
上一章
目录
下一章
×