TensorFlow:实战Google深度学习框架第二版——第三章

本文详细介绍了TensorFlow的基础概念,包括计算图、张量和会话。通过理解计算图的定义阶段和执行阶段,以及张量的属性和使用,读者能掌握TensorFlow的基本操作。此外,文章还讲解了会话如何管理和执行计算,以及如何通过会话获取计算结果。最后,文章探讨了神经网络的实现,包括前向传播算法、神经网络参数的TensorFlow变量表示以及训练神经网络的流程。
摘要由CSDN通过智能技术生成

目录

第三章——TensorFlow入门

3.1、Tensorflow计算模型——计算图

3.2、TensorFlow数据模型——张量

3.2.1张量的概念

3.2.2张量的使用

3.3、TensorFlow运行模型——会话

3.4 TensorFlow实现神经网络

3.4.1TensorFlow游乐场及神经网络简介

3.4.2前向传播算法简介

3.4.3神经网络参数与TensorFlow变量

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

3.4.5 完整的神经网络样例程序


第三章——TensorFlow入门

首先,TensorFlow中三个重要的模型:

  1. 计算模型:计算图
  2. 数据模型:Tensor
  3. 运行模型:session

理解TensorFlow是先定义各种运算,形成计算图,然后再执行!

Tensor是‘张量’,通俗理解为多维数组,表示的是数据结构,Flow体现的是计算模型,所以称为TensorFlow。

可以理解为TensorFlow中一切皆Tensor,然后各Tensor以及彼此间运算联系(即Flow)组成了计算图,然后在最后执行。


3.1、Tensorflow计算模型——计算图

在TensorFlow程序分两个阶段,定义+执行。

定义阶段定义各种Tensor以及各种运算,会自动被转换为计算图上节点。在TensorFlow程序中,系统会维护一个默认的计算图。

tf.get_default_graph()函数可以获得当前默认的计算图。

此外,可以获取一个Tensor所属的计算图

a=tf.constant([1.0,2.0],name='a')
b=a.graph
print(a.graph is tf.get_default_graph())  #True

支持使用tf.Graph()函数生成新的计算图,不同计算图上的张量和运算不会共享。

import tensorflow as tf

g1=tf.Graph()
with g1.as_default():
    #在计算图g1中定义变量v,并设置初始值为0
    v=tf.get_variable('v',shape=[1],initializer=tf.zeros_initializer)

g2=tf.Graph()
with g2.as_default():
    #在计算图g2中定义变量v,并设置初始值为1
    v=tf.get_variable('v',shape=[1],initializer=tf.ones_initializer)

#在计算图g1中读取变量v的取值
with tf.Session(graph=g1) as sess:
    tf.global_variables_initializer().run()
    with tf.variable_scope("",reuse=True):
        #在计算图g1中,v的值为0,故下面输出[0.]
        print(sess.run(tf.get_variable("v")))

#在计算图g2中读取变量v的取值
with tf.Session(graph=g2) as sess:
    tf.global_variables_initializer().run()
    with tf.variable_scope("",reuse=True):
        #在计算图g2中,v的值为1,故下面输出[1.]
        print(sess.run(tf.get_variable("v")))

上述代码还涉及到了变量管理,后面会学到。

计算图还可以通过tf.Graph.device()函数来指定运行计算的设备,这为TensorFlow使用GPU提供了机制,如:

a=tf.constant([1.0,2.0],name='a')
b=tf.constant([2.0,3.0],name='b')

g=tf.Graph()
#指定计算运行的设备
with g.device('/gpu:0'):
    result=a+b

在一个计算图中,可以通过集合(collection)来管理不同类别的资源,比如通过tf.add_to_collection函数可以将资源加入到一个或者多个集合中,然后通过tf.get_collection()获取一个集合里面的所有资源。这里的资源可以是张量,变量或者运行程序所需的队列资源等等。


3.2、TensorFlow数据模型——张量

3.2.1张量的概念

TensorFlow程序中,所有的数据都通过张量的形式来表示。

张量中并不保存真正的数字,保存的是如何得到这些数字的计算过程。

一个张量主要保存了三个属性:名字name,维度shape和类型type。

a=tf.constant([1.0,2.0],name='a')
b=tf.constant([2.0,3.0],name='b')
result=tf.add(a,b,name="add")
print(result)
#输出为:
#Tensor(“add:0”,shape=(2,),dtype=float32)

张量的命名name可以通过:node:src_output的形式给出,node为计算图上节点名称,src_output表示当前的张量来自节点的第几个输出(从0开始编号)。

张量的维度shape,描述了张量的维度信息。

张量的类型type包括tf.float32,tf.int8等等,对每个张量来说是唯一的。即最终张量所保存数据的类型。虽然前面说张量都不保存真正的数字,保存的是计算过程。而计算过程就组成了计算图,在计算图上一个节点表示一个计算,计算的结果会保存到张量中,所以张量和计算图上节点所代表的计算结果是对应的。要求参与同一节点计算的张量的类型相同,不然会报错。

3.2.2张量的使用

包括两大类

第一类用途是对中间计算结果的引用

#使用张量记录中间结果
a=tf.constant([1.0,2.0],name='a')
b=tf.constant([2.0,3.0],name='b')
result=a+b

#直接计算向量的和,可读性差
result=tf.constant([1.0,2.0],name='a')+tf.constant([2.0,3.0],name='b')

注意:tensor.shape与tensor.get_shape()可以得到相同的结果

第二类用途是当计算图构造完毕后,张量可以用来获取计算结果

虽然张量本身不存储具体数字,但是通过会话session可以得到具体数据。上述代码中,可以用tf.Session().run(result)语句得到计算结果。


3.3、TensorFlow运行模型——会话

通过会话session来制定定义好的计算。

会话拥有并管理TensorFlow程序运行时的所有资源,计算完成后需要关闭会话来帮助系统回收资源。

第一种使用会话方式:明确调用会话生成函数和关闭函数。

#创建一个会话
sess=tf.Session()
#使用创建好的会话来得到运算结果,如sess.run(result)
sess.run(...)
#关闭会话释放资源
sess.close()

第二种利用Python的上下文管理器来使用会话

#创建一个会话,并通过Python上下文管理器来管理这个会话
with tf.Session() as sess:
    #使用创建好的会话来得到运算结果,如sess.run(result)
    sess.run(...)
#不需要调用Session.close()来关闭会话释放资源
#当上下文退出时会话关闭和资源释放会自动完成

与3.1提到的计算图类似,TensorFlow会自动生成一个默认的计算图,如果没有特殊的指定,运算会自动加入这个计算图中。会话也类似,但不会自动生成默认的会话,需要手动指定。当默认的会话被指定后,可以调用tf.Tensor.eval()函数来计算一个张量的取值。

#方式一
sess=tf.Session()
with sess.as_default():
    print(result.eval())

#方式二
sess=tf.Session()
#下面两个命令功能相同
print(sess.run(result))    #相当于将该运算分配给这个会话
print(result.eval(session=sess))    #为这个运算提供一个会话

通过tf.InteracticeSession()函数,自动将生成的会话注册为默认会话

sess = tf.InteractiveSession()
print(result.eval())
sess.close()

通过ConfigProto Protocol Buffer来配置需要生成的会话,如:

config=tf.ConfigProto(allow_soft_placement=True,log_device_placement=True)
sess1=tf.InteractiveSession(config=config)
sess2=tf.Session(config=config)

tf.ConfigProto()可以配置并行的线程数,GPU分配策略,运算超时时间等参数。


3.4 TensorFlow实现神经网络

3.4.1TensorFlow游乐场及神经网络简介

tensorflow游乐场(http://playground.tensorflow.org)是一个通过网页浏览器就可以训练的简单神经网络并实现了可视化训练过程的工具。

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

  • 提取问题中实体的特征向量作为神经网络的输入。
  • 定义神经网络结构的结构,并定义如何从神经网络的输入种得到输出。——前向传播提取特征进行预测
  • 通过训练数据来调整神经网络中的参数的取值。(结构不变,变权重)——反向传播更新参数
  • 使用训练好的神经网络来预测未知的数据。

3.4.2前向传播算法简介

实际上就是线性加权运算的累积

两个基本公式:Z=WX+b,A=激活函数(Z)

3.4.3神经网络参数与TensorFlow变量

在TensorFlow种,变量(tf.Variable)的作用就是保存和更新神经网络中的参数,变量需要指定初始值。

变量声明函数:tf.Variable()

weights = tf.Variable(tf.random_normal([2,3], stddev = 2))
# 产生一个 2×3 的矩阵、元素均值是0,标准差为 2 的随机数矩阵, 满足正态分布

变量初始值可以设置成随机数,常数,或者是通过其他变量的初始值计算得到。

除了上例正态分布的随机数, TensorFlow 还提供了一些其他的随机数生成器。

TensorFlow 也支持通过常数来初始化一个变量。 

在 TensorFlow 中,一个变量在被使用之前, 这个变量的初始化过程需要被明确地调用(也就是被run)。以下代码介绍了如何通过变量实现神经网络地参数并实现前向传播地过程。

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))

#暂时将输入的特征向量定义为一个常量。
x = tf.constant([[0.7, 0.9]]) # 1×2

a = tf.matmul(x, w1) # 1×3
y = tf/matmul(a, w2) # 1×1

sess = tf.Session()

#与3.4.2不同的是,这里不能直接通过sess.run(y)来获取y的值。
#因为w1与w2两个变量仅仅定义了初始化过程,但初始化过程未被调用。
#初始化 w1 w2
sess.run(w1.initializer)
sess.run(w2.initializer)
print(sess.run(y))
sess.close()

上述方式对每个变量一个个进行初始化太麻烦,所以TensorFlow提供了一种便捷的方式来完成变量初始化过程,如下:

 #全局变量初始化函数
#因为所有的变量都被加入到GraphKeys.VARIABLES这个集合中
#通过tf.global_variables_initializer()函数可以得到当前计算图上所有的变量
init_op=tf.global_variables_initializer() 
sess.run(init_op)

若变量声明时参数trainable设置未True,则被加入到GraphKeys.TRAINABLE_VARIABLES集合,然后可以通过tf.trainable_variables()函数得到所有需要优化的参数。

TensorFlow中提供的神经网络优化算法会将GraphKeys.TRAINABLE_VARIABLES集合中的变量作为默认的优化对象。

注意:以上介绍的变量也为Tensor。变量和常量一样又名字,类型,维度三个属性,但类型一旦定义不可更改。维度只有设置参数validate_shape=False时才可更改,一般是不更改。

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

TensorFlow提供了占位符placeholder机制用于提供数据,placeholder相当于定义了一个位置,这个位置中的数据在程序运行时再指定。一般会将输入设为占位符。placeholder的类型也不可变,维度可以通过提供的实际数据推到得到,不一定需要明确指出。

反向传播算法训练神经网络。 定义损失函数刻画预测值与真实值的差距,反向传播使差距缩小。

# 定义损失函数
cross_entropy = -tf.reduce_mean(y_ * tf/log(tf.clip_by_value(y, 1e-10, 1.0)))
# 定义学习率
learning_rate = 0.01
#定义反响传播算法
train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)

TensorFlow提供了多种优化器,常用的优化方法有三种:

tf.train.GradientDescentOptimizer     tf.train.AdamOptimizer    tf.train.MomentumOptimizer

定义了反向传播算法后,通过sess.run(train_step)来运行。

完整代码参看3.4.5提供的完整神经网络样例程序。

3.4.5 完整的神经网络样例程序

训练神经网路的过程可以分为三个步骤:

  1. 定义神经网络结构以及前向传播的输出结果
  2. 定义损失函数以及反向传播优化算法
  3. 生成会话并在训练数据上反复运行反向传播优化算法
# -*- coding: utf-8 -*-
import tensorflow as tf
#NumPy是一个科学计算工具包,这里通过NumPy工具包生成模拟数据集
from numpy.random import RandomState

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,但在测试时候可以一次性使用全部数据
#注意,数据量大时,一次送太多数据会造成内存溢出
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)

#定义损失函数和反向传播算法
y=sigmoid(y)    #激活函数,结果被归一化到0-1范围
#交叉熵损失函数
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均被认为正样本,1表示正样本
Y = [[int(x1+ x2 < 1)] for (x1, x2) in X]

#创建一个会话来运行TensorFlow程序
with tf.Session() as sess:
    #初始化变量
    tf.global_variables_initializer().run()
    #打印结果,并不是初始化,可以看到初值是多少
    print(sess.run(w1))
    print(sess.run(w2))
    
    #训练论述
    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))

    #训练后的网络参数值(权重)
    print(sess.run(w1))
    print(sess.run(w2))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值