zoukankan      html  css  js  c++  java
  • Tensorflow学习 day02

    Tensorflow实现神经网络

    使用神经网络解决分类问题可以分为以下四个步骤:

    1. 提取问题中实体的特征向量作为神经网络的输入,不同的实体提取不同的特征向量
    2. 定义神经网络的结构,并定义如何丛神经网络的输入得到输出,这个过程就是神经网络的前向传播算法
    3. 通过训练数据来调整神经网络中参数的取值,这就是训练神经网络的过程
    4. 使用训练好的神经网络来预测未知的数据

    前向传播算法

    一个简单神经元结构

    一个简单神经元有多个输入和一个输出,每个神经元的输入既可以是其他神经元的输出,也可以是整个神经网络的输入。所谓神经网络的结构就是指的不同神经元之间的连接结构,一个最简单神经元的输出就是输入的加权和,而不同输入的权重就是神经元的参数,神经网络的优化过程就是优化神经元中参数取值的过程

    上图是三层全连接神经网络,相邻两层之间任意两个节点之间都有连接

    根据权重和输入值可以确定每个神经元节点的值 

    给出输入层取值x1 = 0.7,x2 = 0.9

    a11 = w1.1(1)*x1 + w2.1(1)*x2 = 0.41 类似a12 a13都可以得出

    y= w1.1(2)a11 + w1.2(2)a12 + w1,3(2)a13 = 0.116

    这个输出值大于0 所以产品合格

    我们可以将它表示为矩阵乘法

    输入可以表示为x = [x1,x2]

    权重表示为w(1) = [w1,1(1)     w1,2(1)     w1,3(1)    一个2*3的矩阵

            w2,1(1)      w2,2(1)      w2,3(1)]

    a(1) = [a11, a12 , a13] = x*w(1)

    类似输出层也可以表示为:

    a = tf.matmul(x,w1)
    y = tf.matmul(a,w2)

    以上程序就实现了前向传播的过程   tf.matmul实现了矩阵乘法的功能 

    Tensorflow变量

    在Tensorflow中,变量tf.Variable的作用就是保存和更新神经网络中的参数。一般用随机数来给变量初始化

    以下代码生成一个2*3矩阵变量

    weights = tf.Variable(tf.random_normal([2,3], stddev = 2))

    产生的矩阵是个2*3的 矩阵中的元素是均值为0,标准差为2的随机数,tf.random_normal函数可以通过mean参数来制定平均值,没有是默认为0,通过满足正态分布的随机数来初始化神经网络比较常用

    Tensorflow随机数生成函数

    函数名称 

    随机数分布 主要参数
    tf.random_normal 正态分布 平均值、标准差、取值类型
    tf.truncated_normal 正态分布 产生的随机数偏离的值偏离平均值超过两个标准差将会被重新随机 平均值、标准差、取值类型
    tf.random_uniform 平均分布 最小、最大取值,取值类型
    tf.random_gamma Gamma分布 形状参数alpha、尺度参数beta、取值类型

    Tensorflow常数生成函数

    函数名称 功能 样列
    tf.zeros 产生全0的数组 tf.zeros([2,3],int32) -->[[0,0,0],[0,0,0]]
    tf.ones 产生全1的数组 tf.ones([2,3],int32)--->[[1,1,1],[1,1,1]]
    tf.fill 产生一个全部为给定数字的数组 tf.fill([2,3],9) -->[[9,9,9],[9,9,9]]
    tf.constant 产生一个给定值得常量 tf.constant([1,2,3])-->[1,2,3]

    在神经网络中,偏置项(bias)通常会使用常数来设置初始值 下面代码产生一个初始值全部为0,且长度为3的变量

    biases = tf.Variable(tf.zeros([3]))

    一些其他设置变量的方式 w3 中是w2初始值的两倍

    w2 = tf.Variable(weights.initialized_value())
    w3 = tf.Variable(weights.initialized_value() * 2.0)

    在Tensorflow中,一个变量的值在被使用之前,这个变量的初始化过程需要被明确的调用

    import tensorflow as tf
    #声明w1,w2两个变量,这里还通过seed设定了随机的种子
    #这样可以保证每次运行得到的结果是一样的
    w1 = tf.Variable(tf.random_normal([2,3], stddev =1,seed=1))
    w2 = tf.Variable(tf.random_normal([3,1], stddev=1,seed=1))
    print(w1)
    #暂时将输入的特征向量定义为一个常量,注意这里x是一个1* 2的矩阵
    x = tf.constant([[0.7, 0.9]])
    
    #前向传播算法获得神经网络的输出
    a = tf.matmul(x,w1)
    y = tf.matmul(a,w2)
    
    sess = tf.Session()
    #这里不能直接通过sess.run(y)来获取y的取值
    # 因为w1和w2都还没有运行初始化过程,以下两行分别初始化w1和w2两个变量
    sess.run(w1.initializer)# 初始化w1
    sess.run(w2.initializer)#初始化w2
    print(sess.run(y))
    sess.close()

    上述代码实现了神经网络的向前传播过程

    在计算y之前需要运行initializer方法来给变量赋值,虽然直接调用变量初始化也可行,单变量数目增多,或者变量间存在依赖关系,单个调用就会变的麻烦

    一种更加便捷的方式初始化所有变量

    init_op = tf.initialize_all_variables()
    sess.run(init_op)

    这个函数会自动处理变量之间的依赖关系

    变量的声明函数tf.Variable是一个运算,这个运算的输出结果就是一个张量,所以变量也是一种特殊的张量

    变量的类型在构建之后不可改变,维度可以改变

    通过Tensorflow训练神经网络模型

    监督学习最重要的思想就是:在已知答案的标注数据集上,模型给出的预测结果要尽量接近真实的答案。通过调整神经网络中的参数对训练数据进行拟合,可以使得模型对未知的样本提供预测的能力

    在神经网络优化算法中,最常用的方法是反向传播算法

    从图中可以看出,反向传播算法是实现了一个迭代过程,每次迭代开始需要选取小部分训练数据,这一小部分数据叫做一个batch,batch的样例会通过前向传播算法得到神经网络模型的预测结果,根据预测结果与训练数据的正确结果之间的差距,反向传播算法会相应更新神经网络参数的取值,使得在这个部分batch上神经网络模型的预测结果与真实答案的更接近。

    通过Tensorflow实现反向传播算法的第一步是使用Tensorflow表达一个batch的数据,如下:

    x = tf.constant([[0.7, 0.9]])

    但如果每轮迭代选取的数据都需要通过常量来表示,那么Tensorflow的计算图会太大,而且利用率非常低,为了避免这个问题,Tensorflow提供了placeholder机制用于提供输入数据。placeholder相当于定义一个位置,这个位置中的数据在程序运行时再指定。这样在程序程序中就不需要生成大量常量来提供输入数据,而只需要将数据通过placeholder传入Tensorflow计算图,在placeholder定义时,这个位置上的数据类型需要制定,类型也是不可改变。以下是通过placeholder实现前向传播算法的代码

    import tensorflow as tf
    w1 = tf.Variable(tf.random_normal([2,3],stddev=1))
    w2 = tf.Variable(tf.random_normal([3,1],stddev=1))
    
    #定义placeholder作为存放输入数据的地方,这里的维度也不一定要定义
    #但如果维度是确定的 可以降低维度出错的概率
    x = tf.placeholder(tf.float32, shape=(1,2),name="input")
    a = tf.matmul(x,w1)
    y = tf.matmul(a,w2)
    
    
    sess = tf.Session()
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    #print(sess.run(y)) 将报错 你必须feed一个值给placeholder
    
    print(sess.run(y,feed_dict={x:[[0.7,0.9]]}))

    这段程序替换了原来通过常量定义的输入x,在新的程序中计算前向传播结果时,需要提供一个feed_dict来制定x的取值,如果不给定将会报错

    如果将输入的1*2矩阵改为n*2矩阵,就可以得到n个样列的前向传播结果

    x = tf.placeholder(tf.float32, shape=(3,2),name="input")
    #更改输入x的维度
    #因为x在定义时指定了n为3,所以在前向传播过程中需要提供三个样例数据
    print(sess.run(y, feed_dict = {x: [[0.7,0.9],[0.1,0.4],[0.5,0.8]]}))

    运行结果得到的是一个3*1的矩阵 比如3.957578为样例[0.7,0.9]的前向传播结果

    在得到一个batch的前向传播结果之后,需要定义一个损失函数来刻画当前预测值和真实答案之间的差距,然后通过反向传播算法来调整神经网络参数的取值使得差距可以被缩小,以下代码定义了一个简单的损失函数,并通过Tensorflow定义了反向传播的算法

    #定义损失函数来刻画预测值与真是值得差距
    cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
    #定义学习率
    learning_rate = 0.001
    #定义反向传播算法来优化神经网络中的参数
    train_step = tf.train.AdagradOptimizer(learning_rate).minimize(cross_entropy)

    cross_entropy定义了真实值和预测值之间的交叉熵,这是分类问题中一个常用的损失函数。

    train_step定义了反向传播的优化方法 

    一个完整的神经网络样例程序

    #在一个模拟数据集上训练神经网络来解决二分类问题
    import tensorflow as tf
    
    from numpy.random import RandomState
    # 通过numpy生成模拟数据集
    
    #定义训练数据batch的大小
    batch_size = 8
    
    #定义神经网络的参数
    w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
    w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))
    
    #在shape的一个维度上使用None可以方便使用不大的batch大小。在训练时需要把数据分成比较小的batch
    #但是在测试时可以一次性使用全部的数据。当数据集比较小时这样方便测试,但数据及比较大时,将大量数据放到一个batch可能会导致内存溢出
    
    x = tf.placeholder(tf.float32, shape=(None, 2), name='x-input')
    y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input')
    
    #定义神经网络的前向传播过程
    a = tf.matmul(x , w1)
    y = tf.matmul(a, w2)
    
    #定义损失函数和反向传播算法
    cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
    train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
    
    #通过随机数生成一个模拟数据集
    rdm = RandomState(1)
    dataset_size = 128
    X = rdm.rand(dataset_size, 2)
    #定义规则来给出样本的标签。在这里所有x1+x2<1的样例都被认为是正样本(比如:零件合格)
    #而其他为负样本
    #在这里使用0表示负样本,1来表示正样本
    Y = [[int(x1 + x2 < 1)]for (x1,x2) in X]
    
    
    #创建一个会话来运行Tensorflow程序
    with tf.Session() as sess:
        init_op = tf.initialize_all_variables()
        #初始化变量
        sess.run(init_op)
        print (sess.run(w1)) 
        print (sess.run(w2))
    '''
    在训练之前神经网络参数的值
    w1 =
    [[-0.8113182 1.4845988 0.06532937] [-2.4427042 0.0992484 0.5912243 ]]
    w2 =[[-0.8113182 ][ 1.4845988 ][ 0.06532937]]
    '''
    #设定训练的轮数
    STEPS = 5000
    for i in range(STEPS):
    #每次选取batch_size个样本进行训练
    start = (i * batch_size) % dataset_size
    end = min(start+batch_size, dataset_size)

    #通过选取的样本训练神经网络并更新参数
    sess.run(train_step , feed_dict={x: X[start:end], y_: Y[start:end]})

    if i % 1000 == 0:
    #每隔一段时间计算在所有数据上的交叉熵并输出。
    total_cross_entropy = sess.run(cross_entropy,feed_dict={x: X ,y_: Y})
    print("After %d training step(s), cross entropy on all data is %g"%(i, total_cross_entropy))
    '''
    通过这个结果可以发现随着训练的进行,交叉熵是逐渐变小的。交叉熵越小说明预测的结果和真实的结果差距越小

    After 0 training step(s), cross entropy on all data is 0.0674925
    After 1000 training step(s), cross entropy on all data is 0.0163385
    After 2000 training step(s), cross entropy on all data is 0.00907547
    After 3000 training step(s), cross entropy on all data is 0.00714436
    After 4000 training step(s), cross entropy on all data is 0.00578471

    '''

    print(sess.run(w1))
    print(sess.run(w2))
    '''
    在训练之后神经网络参数的值
    [[-1.9618274 2.582354 1.6820377][-3.4681718 1.0698233 2.11789 ]]
    [[-1.8247149][ 2.6854665][ 1.418195 ]]
    ''' 

     训练神经网络可以分为三个步骤:

    1. 定义神经网络的结构和前向传播的输出结果
    2. 定义损失函数以及选择反向传播的优化算法
    3. 生成会话(tf.Session)并且在训练数据上反复运行反向传播优化算法
  • 相关阅读:
    HashMap
    Spring事务异常回滚,捕获异常不抛出就不会回滚(转载) 解决了我一年前的问题
    脏读 不可重复读 幻读
    冒泡优化
    Class.forName的作用以及为什么要用它【转】
    java反射入门
    Java异常分类 转载
    转载 【CSS进阶】伪元素的妙用--单标签之美
    转载文章 利用旋转正方形与图形的组合实现爱心
    Three.js基础学习【修改版】
  • 原文地址:https://www.cnblogs.com/suizhixxie/p/10358480.html
Copyright © 2011-2022 走看看