码迷,mamicode.com
首页 > 其他好文 > 详细

Theano Tutorials学习笔记(二)——More Examples

时间:2016-06-12 03:14:37      阅读:485      评论:0      收藏:0      [点我收藏+]

标签:

Logistic Function

  • 逻辑回归的形式如下:

技术分享

# -*- coding: utf-8 -*-
"""
Created on Mon Jun 06 10:38:45 2016
@author: zm
"""
import theano
import theano.tensor as T

x = T.dmatrix(‘x‘)          # 声明变量
s = 1 / (1 + T.exp(-x))     # 构造表达式
logistic = theano.function([x], s) # 构造函数
print logistic([[0, 1], [-1, -2]]) # 调用函数进行计算
‘‘‘
[[ 0.5         0.73105858]
 [ 0.26894142  0.11920292]]
‘‘‘
  • 逻辑回归也可以使用tanh双曲正弦函数表示:

技术分享

s2 = (1 + T.tanh(x / 2)) / 2
logistic2 = theano.function([x], s2)
print logistic2([[0, 1], [-1, -2]])
‘‘‘
[[ 0.5         0.73105858]
 [ 0.26894142  0.11920292]]
‘‘‘

Computing More than one Thing at the Same Time

  • 同时申明多个变量,利用相同的输入计算多个表达式
a, b = T.dmatrices(‘a‘, ‘b‘) # 声明变量
diff = a - b                 # 构造表达式一
abs_diff = abs(diff)         # 构造表达式二
diff_squared = diff**2       # 构造表达式三

# 一次性定义了三个函数,利用同样两个变量
f = theano.function([a, b], [diff, abs_diff, diff_squared])
# 调用时,产生三个结果
print f([[1, 1], [1, 1]], [[0, 1], [2, 3]])
‘‘‘
[array([[ 1.,  0.],
       [-1., -2.]]), array([[ 1.,  0.],
       [ 1.,  2.]]), array([[ 1.,  0.],
       [ 1.,  4.]])]
‘‘‘

Setting a Default Value for an Argument

  • 我们在定义函数的时候,有的时候会定义默认参数的值:
‘‘‘
创建一个In对象,可以指定一个参数的详细信息。比如将y的值默认值设为1,这样可以给参数设置一个默认的值
‘‘‘
from theano import In
import theano.tensor as T
from theano import function
x, y = T.dscalars(‘x‘, ‘y‘) # 声明两个变量
z = x + y                   # 构造表达式
# 函数中的y参数是个In对象,有默认值
f = function([x, In(y, value=1)], z) 
print f(33) # 34.0
print f(33, 2) # 35.0
‘‘‘
当有多个默认值时,在赋值时,先将值传给没有默认值的参数
‘‘‘
x, y, w = T.dscalars(‘x‘, ‘y‘, ‘w‘) # 声明三个变量
z = (x + y) * w                     # 构造表达式
# y和z都含有默认值,并且w的名字定义为w_by_name
f = function([x, In(y, value=1), In(w, value=2, name=‘w_by_name‘)], z)
print f(33) # 68.0
print f(33, 2) # 70.0       33—>x,2->y
print f(33, 0, 1) # 33.0    33—>x,0->y,1->w
print f(33, w_by_name=1) # 34.0  1->w_by_name
# 不按顺序赋值时,需要指明参数的名称,注意此处的w_by_name相当于是w的别名
print f(33, w_by_name=1, y=0) #  33—>x,0->y,1->w_by_name

Using Shared Variables

  • 我们希望构造一个函数,并且这个函数有一个内部状态(internal state)。在每次函数被调用的时候,这个内部状态就会改变。我们可以给函数添加一个共享变量,并且使用updates参数定义更新共享变量的规则。
  • 共享变量通过 .get_value()和.set_value()函数获取以及设置共享变量的值,updates参数中,必须是(shared-variable, new expression)的形式,可以是变量也可以是键值对的形式new expression的值将会替换shared变量的值。
import theano.tensor as T
from theano import shared
from theano import function

state = shared(0)  # shared函数构造了shared变量,类似全局变量
inc = T.iscalar(‘inc‘)  # 声明一个32位标量
accumulator = function([inc], state, updates=[(state, state+inc)])
print state.get_value() # 0
print accumulator(1) # 0
print state.get_value() # 1
print accumulator(300) # 1
print state.get_value() # 301

state.set_value(-1) 
print accumulator(3) # -1
print state.get_value() # 2
# 观察发现,accumulator(1)返回的是shared变量updates之前的值,而使用get_value()可以获取其当前值

# 创建另一个函数来共享这个state变量,此时state变量的值沿用前面的为2
decrementor = function([inc], state, updates=[(state, state-inc)])
print decrementor(2) # 2
print state.get_value() # 0

‘‘‘
使用updates表达式是为了语法方便,有的时候你使用了一个shared变量,但是不想使用它的值,可以在function函数中使用given参数。我们使用given是为了动态的改变一个函数的参数。
‘‘‘
fn_of_state = state * 2 + inc     # 构造表达式
# 后面会使用foo替换state,因此foo变量类型必须设置得和state一样
foo = T.scalar(dtype=state.dtype) # 
‘‘‘
在givens参数里,让foo的值替换了state来进行计算fn_of_state的值,但是并没有对state的值做修改。given参数可以替换任何符号变量或者表达式,不仅仅是共享变量。
‘‘‘
skip_shared = function([inc, foo], fn_of_state, givens=[(state, foo)])
print skip_shared(1, 3) # 7
print state.get_value() # 0  # old state still there, but we didn‘t use it

Copying functions

  • Theano的函数是可以被复制的,通过复制函数,在函数里面指定不同的共享变量或者updates
import theano
import theano.tensor as T

state = theano.shared(0)  # 声明共享变量
inc = T.iscalar(‘inc‘)    # 申明符号变量
# 构造一个update函数
accumulator = theano.function([inc], state, updates=[(state, state+inc)])  
print accumulator(10) # 0
print state.get_value() # 10

‘‘‘
在copy函数中使用swap参数将共享变量替换成新的共享变量,复制了一个功能相同,但是参数不同的函数,类似多态
‘‘‘
new_state = theano.shared(0)  # 声明一个新的共享变量
# 构造一个新的update函数,通过替换新的共享变量
new_accumulator = accumulator.copy(swap={state:new_state})
print new_accumulator(100) # [array(0)]
print new_state.get_value() # 100

# 又复制了一个函数,但是删掉了原函数中的updates参数,表示state不会更新
null_accumulator = accumulator.copy(delete_updates=True)
print null_accumulator(9000) # [array(10)]
print state.get_value() # 10

Using Random Numbers

  • 在theano中我们通常首先创建符号变量和表达式,然后传进function中获得一个函数,调用伪随机数不像numpy中那么简单,但也不会太复杂.Theanos中的随机对象是由 RandomStreams这个类实现的:
from theano.tensor.shared_randomstreams import RandomStreams
from theano import function

srng = RandomStreams(seed=234)   # 定义一个随机数生成器
# rv_u代表一个2*2的随机流矩阵,服从均匀分布
# rv_n代表一个2*2的随机流矩阵,服从正态分布,这些分布都在RandomStreams实现了
rv_u = srng.uniform((2,2))
rv_n = srng.normal((2,2))
# 这个函数就是返回rv_u的值,调用一次,就从随机数序列中取值
f = function([], rv_u) 
‘‘‘
当我们在function中添加了一个参数no_default_updates=True时,每次调用产生相同的随机数,因为随机数生成器的状态不变,相当于每次从随机数序列开头重新取值
‘‘‘
g = function([], rv_n, no_default_updates=True)    #Not updating rv_n.rng
‘‘‘
值得注意的是一个随机变量在一个函数调用期间只产生一个随机数,尽管在下面的表达式rv_u出现了三次,但只取一个值,因此nearly_zeros的值为0
‘‘‘
nearly_zeros = function([], rv_u + rv_u - 2 * rv_u)

# 现在来使用这些函数
print f()
‘‘‘
[[ 0.12672381  0.97091597]
 [ 0.13989098  0.88754825]]
‘‘‘
print f()  #different numbers from f_val0
‘‘‘
[[ 0.31971415  0.47584377]
 [ 0.24129163  0.42046081]]
‘‘‘
print g() # different numbers from f_val0 and f_val1
‘‘‘
[[ 0.37328447 -0.65746672]
 [-0.36302373 -0.97484625]]
‘‘‘
print g() # same numbers as g_val0!
‘‘‘
[[ 0.37328447 -0.65746672]
 [-0.36302373 -0.97484625]]
‘‘‘
print nearly_zeros()
‘‘‘
[[ 0.  0.]
 [ 0.  0.]]
‘‘‘

Seeding Streams

  • 随机变量的种子可以单独设置也可以统一设置,使用.seed()或者.rng.set_value()函数给某个随机变量对应的随机数生成器设置种子。.seed()用于给一个临时随机数发生器做种子,可以为每个随机数变量轮流做种子。对于所有变量使用srng.seed()会使得每个变量的种子都不同。
# 获取rv_u的随机数生成器的状态
rng_val = rv_u.rng.get_value(borrow=True)   # Get the rng for rv_u
# rv_u的随机生成器重新设置种子
rng_val.seed(89234)                         # seeds the generator
# 还原为原来的种子,两种设置种子的方法
rv_u.rng.set_value(rng_val, borrow=True)    # Assign back seeded rng
srng.seed(902340)  # seeds rv_u and rv_n with different seeds each

Sharing Streams Between Functions

  • 与共享变量类似,随机数生成器在变量之间也是共享的,因此在调用了nearly_zeros函数后,生成器状态改变,f()调用时就会不一样。
‘‘‘
由于随机树生成器是在函数之间共享的,因此调用nearly_zeros后生成器的状态就被更新了
‘‘‘
state_after_v0 = rv_u.rng.get_value().get_state()
print nearly_zeros()       # this affects rv_u‘s generator
‘‘‘
[[ 0.  0.]
 [ 0.  0.]]
‘‘‘
print f()
‘‘‘
[[ 0.5025809   0.99544429]
 [ 0.75073355  0.17926032]]
‘‘‘
# 将rv_u的生成器状态还原到nearly_zeros调用之前
rng = rv_u.rng.get_value(borrow=True)
rng.set_state(state_after_v0)
rv_u.rng.set_value(rng, borrow=True)
print f()           # v2 != v1
‘‘‘
[[ 0.33919835  0.85344878]
 [ 0.14881562  0.79659413]]
‘‘‘
print f()           # v3 == v1
‘‘‘
[[ 0.5025809   0.99544429]
 [ 0.75073355  0.17926032]]
‘‘‘

Copying Random State Between Theano Graphs

  • 在某些情况下,可能想要转移相关的theano图的所有随机数发生器的状态给另外的theano图。这个可能出现,比如如果你想要初始化一个模型,一个先前系列化的模型的参数。theano.tensor.shared_randomstreams.RandomStreamsheano.sandbox.rng_mrg.MRG_RandomStreams可以通过拷贝元素的state_updates参数达到。每次从RandomStreams对象获取的随机变量,一个元组就会添加到state_updates中。第一个元素是共享的变量,表示与这个变量相关的随机数发生器的状态,第二个元素表示与随机数发生器过程一直的theano图(比如RandomFunction{uniform}.0)。
from __future__ import print_function
import theano
import numpy
import theano.tensor as T
from theano.sandbox.rng_mrg import MRG_RandomStreams
from theano.tensor.shared_randomstreams import RandomStreams

# 定义一个theano图,其随机数生成器为rng
class Graph(): 
    def __init__(self, seed=123):
        self.rng = RandomStreams(seed)
        self.y = self.rng.uniform(size=(1,))

g1 = Graph(seed=123)           # 创建一个theano图实例,重新设置种子
f1 = theano.function([], g1.y) # 调用了随机数生成器
g2 = Graph(seed=987)           # 又创建一个theano图实例,重新设置种子
f2 = theano.function([], g2.y) # 调用了随机数生成器

‘‘‘
在文件开头调用过from __future__ import print_function后,print时必须要加()
‘‘‘
# By default, the two functions are out of sync.(不同步)
print(f1()) # [ 0.72803009] 
print(f2()) # [ 0.55056769]

# 复制一个theano图的随机数生成器
def copy_random_state(g1, g2):
    if isinstance(g1.rng, MRG_RandomStreams):
        g2.rng.rstate = g1.rng.rstate
    for (su1, su2) in zip(g1.rng.state_updates, g2.rng.state_updates):
        su2[0].set_value(su1[0].get_value())

# We now copy the state of the theano random number generators.
copy_random_state(g1, g2)
print(f1()) # [ 0.59044123]
# 由于将g1的随机生成器复制给g2,因此这两个实例是相同的,随机数序列相同
# 注意这两个实例各自维护着一个随机数生成器,不共享
print(f2()) # [ 0.59044123]

A Real Example: Logistic Regression

  • 使用theano符号表达式来完成一个逻辑回归分类问题。
import numpy
import theano
import theano.tensor as T
rng = numpy.random

N = 400                                   # training sample size
feats = 784                               # number of input variables

# 随机生成400条784维的训练数据集以及其类标签
D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
training_steps = 10000

# 声明Theano符号变量
x = T.dmatrix("x")
y = T.dvector("y")

# 初始化w和b,并且由于在训练过程中要进行修改,因此要将其设置为共享变量
# w的大小与数据维度一致,randn生成(784,),b是偏差值,同样都是符号变量
w = theano.shared(rng.randn(feats), name="w")
b = theano.shared(0., name="b")

print("Initial model:")
print(w.get_value())
print(b.get_value())

# 构建Theano表达式图:一系列表达式(表达式参数是前面声明的符号变量)
p_1 = 1 / (1 + T.exp(-T.dot(x, w) - b))       # Probability that target = 1
prediction = p_1 > 0.5                        # The prediction thresholded
xent = -y * T.log(p_1) - (1-y) * T.log(1-p_1) # Cross-entropy loss function
cost = xent.mean() + 0.01 * (w ** 2).sum()    # The cost to minimize
gw, gb = T.grad(cost, [w, b])                 # Compute the gradient of the cost

# 构造函数:w,b是更新变量,需要updates.
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)

# 训练多个周期
for i in range(training_steps):
    pred, err = train(D[0], D[1])

print("Final model:")
print(w.get_value())
print(b.get_value())
print("target values for D:")
print(D[1])
print("prediction on D:")
print(predict(D[0]))

Theano Tutorials学习笔记(二)——More Examples

标签:

原文地址:http://blog.csdn.net/zm714981790/article/details/51606055

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!