• Theano 基础


    如何安装Theano

     通过anaconda安装

    conda install theano

    安装过程要注意什么?

    建议使用python环境是3.6以下的,安装功能后就能使用

    如果通过 conda create 安装的道友,请参考我写的这个页面https://www.cnblogs.com/hardykay/p/12611460.html

    符号变量是什么

    1、内置变量类型

    目前Theano支持7种内置变量:scalar(标量)、vector(向量)、row(行向量)、col(列向量)、matrix(矩阵)、tensor3、tensor4等。当然这些变量统一叫张量,0阶的张量叫做标量,1阶叫向量,2阶叫矩阵等等。

    我们来看一个简单的方程式:y = 2x +b

    上述方程中y、2、x、b就是符号变量,可以表示为一个通用表达式:y = w*x + b;其中w是权重,d是偏移量,x是自变量,y因变量。下面是一段案例代码。

    import theano
    from theano import tensor as T
    
    # 初始化张量
    x = T.scalar(name='input', dtype='float32')
    w = T.scalar(name='weight', dtype='float32')
    b = T.scalar(name='bias', dtype='float32')
    z = w*x + b
    # 编译程序
    net_input = theano.function(inputs=[w, x, b], outputs=z)
    # 执行程序
    print('net_input:%2f' % net_input(2.0, 3.0, 0.5))

    2、自定义变量类型

    theano自定义变量类型通过TensorType来实现

    import theano
    from theano import tensor as T
    mytype = T.TensorType('float64', broadcastable=(), name=None, sparse_grad=False)

    如何设计符号计算图

    符号计算即为数据处理的数学模型,也叫方程式。

    import theano
    import numpy as np
    import theano.tensor as T
    
    
    x = T.dmatrices('x')
    y = T.dmatrices('y')
    z = x + y

    函数的功能

    函数的定义的格式

    def function(inputs, outputs=None, 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=None)

    常用参数:inputs(自变量)、outputs(因变量)、updates(神经网络共享变量参数更新)、givens

    多自变量、多因变量

    import theano
    import numpy as np
    import theano.tensor as T
    
    x, y = theano.tensor.fscalars('x', 'y')
    z1 = x + y
    z2 = x * y
    
    # 定义x、y为自变量, z1、z2为因变量
    f = theano.function([x, y], [z1, z2])
    
    print(f(2, 3))

    自动求导

    import theano
    import numpy as np
    import theano.tensor as T
    
    # 定义一个float类型的变量x
    x = theano.tensor.fscalar('x')
    # 定义变量y
    y = 1 / (1 + theano.tensor.exp(-x))
    # 偏导函数
    dx = theano.grad(y, x)
    # 定义函数f,输入x,输出
    f = theano.function([x], dx)
    
    print(f(3))

    更新共享变量(使用updates这个参数)

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

    逻辑回归->updates的用法

    import theano
    import numpy as np
    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())

    条件与循环

     在Theano中可以使用ifelse和switch来表示判定语句

    switch

    格式:switch(cond, ift, iff)

    如果满足条件则switch既执行ift也执行iff

    ifelse

    格式:if cond then ift else iff

    只执行ift或者iff

    from theano import tensor as T  
    from theano.ifelse import ifelse  
    import theano,time,numpy  
     
    a,b=T.scalars('a','b')  
    x,y=T.matrices('x','y')  
    z_switch=T.switch(T.lt(a,b),T.mean(x),T.mean(y))#lt:a < b?  
    z_lazy=ifelse(T.lt(a,b),T.mean(x),T.mean(y))  
     
    #optimizer:optimizer的类型结构(可以简化计算,增加计算的稳定性)  
    #linker:决定使用哪种方式进行编译(C/Python) 
    f_switch = theano.function([a, b, x, y], z_switch,mode=theano.Mode(linker='vm'))  
    f_lazyifelse = theano.function([a, b, x, y], z_lazy,mode=theano.Mode(linker='vm'))  
     
    val1 = 0.  
    val2 = 1.  
    big_mat1 = numpy.ones((1000, 100))  
    big_mat2 = numpy.ones((1000, 100))  
     
    n_times = 10  
     
    tic = time.clock()  
    for i in range(n_times):  
        f_switch(val1, val2, big_mat1, big_mat2)  
    print('time spent evaluating both values %f sec' % (time.clock() - tic))  
     
    tic = time.clock()  
    for i in range(n_times):  
        f_lazyifelse(val1, val2, big_mat1, big_mat2)  
    print('time spent evaluating one value %f sec' % (time.clock() - tic))

    scan是theano中构建循环Graph的方法,scan是个灵活复杂的函数,任何用循环、递归或者跟序列有关的计算,都可以用scan完成。其格式如下:
    theano.scan(fn, sequences=None, outputs_info=None, non_sequences=None, n_steps=None, truncate_gradient=-1, go_backwards=False, mode=None, name=None, profile=False, allow_gc=None, strict=False)
    参数说明:
    fn:函数类型,scan的一步执行。除了outputs_info,fn可以返回sequences变量的更新updates。fn的输入变量顺序为sequences中的变量,outputs_info的变量,non_sequences中的变量。如果使用了taps,则按照taps给fn喂变量。taps的详细介绍会在后面的例子中给出。
    sequences:scan进行迭代的变量,scan会在T.arange()生成的list上遍历,例如下面的polynomial 例子。
    outputs_info:初始化fn的输出变量,和输出的shape一致。如果初始化值设为None表示这个变量不需要初始值。
    non_sequences:fn函数用到的其他变量,迭代过程中不可改变(unchange)。
    n_steps:fn的迭代次数。
    下面通过一个例子解释scan函数的具体使用方法。
    代码实现思路是:先定义函数one_step,它就是scan里的fn,其任务就是计算多项式的一项,scan函数返回的result里会保存多项式每一项的值,然后我们对result求和,就得到了多项式的值。

    import theano
    import theano.tensor as T
    import numpy as np
     
    # 定义单步的函数,实现a*x^n
    # 输入参数的顺序要与下面scan的输入参数对应
    def one_step(coef, power, x):
        return coef * x ** power
     
    coefs = T.ivector()  # 每步变化的值,系数组成的向量
    powers = T.ivector() # 每步变化的值,指数组成的向量
    x = T.iscalar()      # 每步不变的值,自变量
     
    # seq,out_info,non_seq与one_step函数的参数顺序一一对应
    # 返回的result是每一项的符号表达式组成的list
    result, updates = theano.scan(fn = one_step,
                           sequences = [coefs, powers],
                           outputs_info = None,
                           non_sequences = x)
     
    # 每一项的值与输入的函数关系
    f_poly = theano.function([x, coefs, powers], result, allow_input_downcast=True)
     
    coef_val = np.array([2,3,4,6,5])
    power_val = np.array([0,1,2,3,4])
    x_val = 10
     
    print("多项式各项的值: ",f_poly(x_val, coef_val, power_val))
    #scan返回的result是每一项的值,并没有求和,如果我们只想要多项式的值,可以把f_poly写成这样:
    # 多项式每一项的和与输入的函数关系
    f_poly = theano.function([x, coefs, powers], result.sum(), allow_input_downcast=True)
     
    print("多项式和的值:",f_poly(x_val, coef_val, power_val))

    共享变量的妙用

    共享变量(shared variable)是实现机器学习算法参数更新的重要机制。shared函数会返回共享变量。这种变量的值在多个函数可直接共享。可以用符号变量的地方都可以用共享变量。但不同的是,共享变量有一个内部状态的值,这个值可以被多个函数共享。它可以存储在显存中,利用GPU提高性能。我们可以使用get_value和set_value方法来读取或者修改共享变量的值,使用共享变量实现累加操作。

    import theano
    import theano.tensor as T
    from theano import shared
    import numpy as np
     
    #定义一个共享变量,并初始化为0
    state = shared(0)
    inc = T.iscalar('inc')
    accumulator = theano.function([inc], state, updates=[(state, state+inc)])
    # 打印state的初始值
    print(state.get_value())
    accumulator(1) # 进行一次函数调用
    # 函数返回后,state的值发生了变化
    print(state.get_value()) 

    这里state是一个共享 变量,初始化为0,每次调用accumulator(),state都会加上inc。共享变量可以像普通张量一样用于符号表达式,另外,他还有自己的值,可以直接用.get_value()和.set_value()方法来访问和修改。
    上述代码引入了函数中updates参数。updates参数是一个list,其中每个元素是一个元组(tuple),这个tuple的第一个元素是一个共享变量,第二个元素是一个新的表达式。updatas中的共享变量会在函数返回后更新自己的值。updates的作用在于执行效率,updates多数时候可以用原地(in-place)算法快速实现,在GPU上,Theano可以更好地控制何时何地给共享变量分配空间,带来性能提升。最常见的神经网络权值更新,一般会用update实现。

  • 相关阅读:
    大家帮忙出几个招聘考试题目吧
    单元测试和设计模式在重构中的应用
    想起去年和女朋友第一次去吃饭的事情
    为什么我们常忘记使用正则表达式
    .NET实用设计模式:观察者模式(Observer)
    一个Outlook宏写的小程序,献给象我一样粗心大意的人
    单元测试应该测什么,不应该测什么?
    .NET实用设计模式:工厂模式(Factory)
    2021 系统架构设计师备考分享
    系统架构设计师论文企业集成
  • 原文地址:https://www.cnblogs.com/hardykay/p/12613354.html
Copyright © 2020-2023  润新知