《Tensorflow 实战Google深度学习框架》学习笔记(二)

第三章 TensorFlow入门

TensorFlow最重要的概念就是Tensor和Flow。Tensor就是张量,可以被简单地理解为多维数组;Flow就是流,直观地表达了张量之间通过计算相互转化的过程。

3.1 TensorFlow计算模型——计算图

3.2 TensorFlow数据模型——张量

3.3 TensorFlow运行模型——会话

3.4 TensorFlow实现神经网络

3.4.1 TensorFlow游乐场网页界面解读

3.4.2 前向传播算法简介

全连接神经网络为例,全连接神经网络是指相邻两层之间任意两个节点之间都有连接,如下所示:
在这里插入图片描述
计算神经网络的前向传播的结果需要三部分的信息:

  • 第一部分是神经网络的输入,这个输入就是从实体中提取的特征向量;

  • 第二部分是神经网络的连接结构,即不同神经元之间输入输出的连接关系;

  • 第三部分是神经网络中神经元之间的边的权重

设X为某一层结点的值所组成的矩阵,W为该层和下一层之间的边的权重所组成的矩阵,Y为下一层结点的值的矩阵,则Y可通过TensorFlow程序得到:

#实际上是实现了矩阵的乘法
Y = tf.matmul(X,W)

3.4.3 初步了解TensorFlow的变量

3.4.4 通过TensorFlow训练神经网络模型

在神经网络优化算法中,最常用的就是反向传播算法,反向传播算法实现了一个迭代的过程:

  1. 在每次迭代的开始,都选取一小部分的数据,这一小部分数据叫做一个batch

  2. 这个batch的样例会通过前向传播算法得到神经网络模型的预测结果,因为训练数据都是有真实标签的,所以可以计算当前神经网络模型的预测结果和真实结果的差距;

  3. 基于预测结果和真实结果的差距,反向传播算法会相应更新神经网络模型参数的取值,使模型的预测结果在这个batch上更接近真实结果

反向传播算法的流程如下图所示:
在这里插入图片描述
通过TensorFlow实现反向传播算法:

第一步,使用TensorFlow表达一个batch的数据。如果每轮迭代中选取的数据都要通过常量来表示,那么TensorFlow的计算图将会太大。因为每生成一个常量,TensorFlow都会在计算图中增加一个节点。一般来说,一个神经网络的训练过程会需要经过几百万轮甚至几亿轮的迭代,这样计算图就会非常大,而且利用率很低。为了避免这个问题,TensorFlow提供了 placeholder机制用于提供输入数据。placeholder相当于定义了一个位置,这个位置中的数据在程序运行时再指定。这样在程序中就不需要生成大量常量来提供输入数据,而只需要将数据通过placeholder传入TensorFlow计算图。在placeholder定义时,这个位置上的数据类型是需要指定的。和其他张量一样,placeholder的类型也是不可以改变的。placeholder中数据的维度信息可以根据提供的数据推导得出,所以不一定要给出。下面给出了通过placeholder实现前向传播算法的代码:

import tensorflow as tf

with tf.Session() as sess:
    #声明wl、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))
    
    #定义placeholder作为存放输入数据的地方,这里维度也不一定要定义,但如果维度是确定的,那么给出维度可以降低出错的概率
    x = tf.placeholder(tf.float32, shape=[3,2], name="input")

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

    #初始化变量
    init_op = tf.global_variables_initializer()
    sess.run(init_op)

    '''输出结果:
    [[3.957578 ]
     [1.1537654]
     [3.1674924]]'''
    print(sess.run(y, feed_dict={x:[[0.7,0.9], [0.1,0.4], [0.5,0.8]]}))

在这段程序中替换了原来通过常量定义的输入x。在新的程序中计算前向传播结果时,需要提供一个feed_dict来指定x的取值,feed_dict是一个字典(map),在字典中需要给出每个用到的placeholder的取值。如果某个需要的placeholder没有被指定取值,那么程序在运行时将会报错。

第二步,在得到一个batch的前向传播结果之后,需要定义一个损失函数来刻画当前的预测值
和真实值之间的差距:

#定义真实值与预测值之间的交叉熵损失函数,来刻画真实值与预测值之间的差距
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.AdamOptimizer(learning_rate).minimize(cross_entropy)

TensorFlow支持7种不同的优化器,可以根据具体的应用选择不同的优化算法。比较常用的优化方法有三种:tf.train.GradientDescentOptimizer、tf.train.AdamOptimizer和tf.train.MomentumOptimizer。在定义了反向传播算法之后,通过运行sess.run(train_step)就可以对所有在GraphKeys.TRAINABLE_VARIABLES集合中的变量进行优化,使得在当前batch下损失函数更小。

3.4.5 完整神经网络样例程序

用神经网络模型解决二分类问题:

import tensorflow as tf
#NumPy是一个科学计算的工具包,这里通过NumPy工具包生成模拟数据集
from numpy.random import RandomState


#声明wl、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))


'''定义placeholder作为存放输入数据的地方,在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(learning_rate=0.001).minimize(cross_entropy)


#设置随机数种子
rdm = RandomState(seed=1)
#设置随机数据集大小
dataset_size = 128
'''设置随机数据集,定义规则来给出样本的标签
在这里所有x1+x2<1的样例都被认为是正样本,而其他为负样本
在这里使用0来表示负样本,1来表示正样本。'''
X = rdm.rand(dataset_size, 2)
Y = [[int(x1 + x2 < 1)] for x1,x2 in X]


#创建会话
with tf.Session() as sess:

    #初始化变量
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    
    #设置batch训练数据的大小
    batch_size = 8
    
    #设置训练得轮数
    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]})
        
        '''输出结果:
        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
        通过这个结果可以发现随着训练的进行,交叉熵是逐渐变小的,交叉嫡越小说明预测的结果和真实的结果差距越小'''
        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))

代码中有关numpy.random的使用可以参照:https://blog.csdn.net/jieshaoxiansen/article/details/82255191

上面的程序实现了训练神经网络的全部过程,从这段程序可以总结出训练神经网络的过程可以分为以下3个步骤:

  • 第一步,定义神经网络的结构和前向传播的输出结果

  • 第二步,定义损失函数以及选择反向传播优化的算法

  • 第三步,生成会话(Session)并且在训练数据上反复运行反向传播优化算法

3.5 学习资源

该书样例代码网址:https://github.com/caicloud/tensorflow-tutorial

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值