机器学习笔记(九):Tensorflow 实战一 (Tensorflow入门)

1 - TsensorFlow计算模型 ——计算图

1.1- 计算图的概念

计算图是TensorFlow中最基本的一个概念,TensorFlow中的所有计算都会被转化为计算图上的节点。

在TensorFlow中,张量可以简单地理解为多为数组。如果说TensorFlow的第一个词Tensor表明了它的数据结构。那么Flow则体现了它的计算模型,Flow翻译成中文就是“流”,它直观地表达了张量之间通过计算相互转化的过程。

TensorFlow是一个通过计算图形式来表示计算的编程系统。TensorFlow中的每一个计算都是计算图上的一个节点,而节点之间的边描述了计算之间的依赖关系

1.2 - 计算图的使用

TensorFlow程序一般可以分为两个阶段

  • 第一个阶段需要定义计算图中所有的计算。
  • 第二个阶段为执行计算
import tensorflow as tf
a = tf.constant([1.0,2.0],name="a")
b = tf.constant([2.0,3.0],name="b")
result = a+b
#通过a.graph可以查看张量所属的计算图,因为没有特意指定,这个计算图应该等于当前默认的计算图
#所以下面这个操作输出值为True.
print(a.graph is tf.get_default_graph())

True

2 - TensorFlow数据模型——张量

2.1 - 张量的概念

从TensorFlow的名字可以看出张量(tensor)是一个重要的概念。在TensorFlow程序中,所有的数据都通过张量的形式来表示。从功能的角度上按,张量可以被简单的理解为多为数组。

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

以向量加法为例:

import tensorflow as tf
#tf.constant是一个计算,这个计算的结果为一个张量,保存在变量a中。
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)

  • 张量的第一个属性不仅是一个张量的唯一标识符,它同样也给出了这个张量是如何计算出来的。

  • 张量的第二个属性是张量的维度(shape),shape(2,)说明了张量result是一个一维数组,一个数组的长度为2

    扫描二维码关注公众号,回复: 4114690 查看本文章
  • 张量的第三个属性是类型(type),每一个张量会有一个唯一的类型。TensorFlow会对参与运算的所有张量进行类型的检查。

2.2 - 张量的使用

张量使用主要可以总结为两大类

**第一类:**对中间计算结果的引用,可以提高代码的可读性。

**第二类:**当计算图构造完成之后,张量可以用来获得计算结果,也就是得到真实的数字。虽然张量本身没有存储具体的数字,但是可以通过会画(session),就可以得到这些具体的数字。比如在上述代码中,可以使用tf.Session().run(result)语句来得到计算结果

3 - TensorFlow运行模型——会话

前面两节介绍了TensorFlow是如何组织数据和运算的。本节将介绍如何使用TensorFlow中的会话(session)来执行定义好的运算。会话拥有并管理TensorFlow程序运行时的所有资源。

TensorFlow中使用会话的模式一般有两种

**第一种:**需要明确调用会话生成函数和关闭会话函数,这种模式的代码流程如下。

#创建一个会话
sess = tf.Session()
#使用这个创建好的会话来得到关心运算的结果。比如可以调用sess.run(result)
##来的得到result 的取值
#关闭会话使得本次运行中使用的资源可以被释放
sess.close()

但是使用这种模式时,因为是在最后调用Session.close函数来关闭会话并关闭资源。然而当程序因为异常而退出时,关闭会话的函数可能就不会被执行从而导致资源泄露。为解决异常退出时资源释放的问题,TensorFlow可以通过Python上下文管理器来使用会话。

**第二组:**通过资源管理器来使用会话。

#创建一个会话,并通过Python中的上下文管理器来管理这个会话。
with tf.Session() as sess:
    #使用者创建好的会话来计算关心的结果。
    sess.run(...)
#不需要调用“Session.close()”函数来关闭会话
#当上下文退出时会话关闭和资源释放也自动完成了。

通过Python上下文管理器的机制,只要将所有的计算放在“with”的内部就可以。当上下文管理器退出的时候会自动释放所有资源。这样既解决了因为异常退出时资源释放的问题。同时也解决了忘记调用Session.close函数而产生的资源泄露。

4 - TensorFlow实现神经网络

上面3节从不同角度介绍了TensorFlow的基本概念。在这一节中,将结合神经网络的功能进一步介绍如何通过TensorFlow来实现神经网络。

4.1 - TensorFlow游乐场及神经网络简介

TensorFlow游乐场http://playground.tensorflow.org

是一个通过网页浏览器就可以训练的简单神经网络并实现了可视化训练过程的工具。默认截图如下:
2018-11-03_173701.png

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

1. 提取问题中实体的特征向量作为神经网络的输入。不同的实体可以提取不同的特征向量。

2. 定义神经网络结构,并且定义如何从神经网络的输入得到输出。这个过程就是神经网络的前向传播算法

3. 通过训练数据来调整神经网络中参数的取值,这就是训练神经网络的过程

**4. 使用训练好的神经网络来预测位置的数据 **

输入数据placeholder机制

TensorFlow提供了placeholder机制用于提供输入数据。

placeholder相当于定义了一个位置,这个位置中的数据在程序运行时再指定,

通过placeholder实现前向传播算法

import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

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_dict={x:[[0.7,0.9]]}))

[[0.07005829]]

在新的程序中计算前向传播结束时,需要提供一个feed_dict来指定x的取值,feed_dict是一个字典(map),在字典中需要给出每个用到的placeholder的取值

在得到前向传播结果之后,需要定义一个损失函数来刻画当前的预测值和真实答案之间的差距。然后通过反向传播算法来调整神经网络参数的取值使得差距可以被缩小。损失函数和反向传播算法将在后面更加详细地介绍。先定义了一个简单的损失函数,并通过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_AdamOptimizer(learning_rate).minimize(cross_entropy)

在上面的代码中,cross_entropy定义了真实值和预测值之间的交叉熵(cross entropy)

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

4.2 - 完整神经网络样例程序

下面给出一个完整的程序来训练神经网络解决二分类问题

import tensorflow as tf
from numpy.random import RandomState
#定义训练数据batch的大小
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
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的样例都被认为是正样本(比如零件合格)
#而其他为负样本(比如零件不合格)。和TensorFlow游乐场中的表示法不大一样的地方是,
#这里使用0来表示负样本,1来表示正样本。大部分解决分类问题的神经网络都会采用
#0和1的表示方法
Y = [[int(x1+x2<1)]for(x1,x2)in X]

#创建一个会话来运行TensorFlow程序
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    #初始化变量
    sess.run(init_op)
    print(sess.run(w1))
    print(sess.run(w2))
#设定训练轮数
    STEPS = 5000
    for i in range(STEPS):
        #每次选取batch_size个样本进行训练
        start = (i*batch_size)%dataset_size
        end = (i*batch_size) % dataset_size + batch_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), w1 is: " % (i))
            print(sess.run(w1), "\n")
            print("total_cross_entropy is :",total_cross_entropy)
    print("Final w1 is: \n", sess.run(w1))

[[-0.8113182 1.4845988 0.06532937]
[-2.4427042 0.0992484 0.5912243 ]]
[[-0.8113182 ]
[ 1.4845988 ]
[ 0.06532937]]
After 0 training step(s), w1 is:
[[-0.8123182 1.4855988 0.06632921]
[-2.4437041 0.1002484 0.59222424]]

total_cross_entropy is : 0.067492485
After 1000 training step(s), w1 is:
[[-1.2754936 1.9323932 0.7181832]
[-2.827644 0.4706616 1.1418985]]

total_cross_entropy is : 0.016338505
After 2000 training step(s), w1 is:
[[-1.5139761 2.1591146 1.0742906]
[-3.0170891 0.6484542 1.46365 ]]

total_cross_entropy is : 0.009075474
After 3000 training step(s), w1 is:
[[-1.6539441 2.292184 1.2743924]
[-3.1415606 0.7646775 1.6682037]]

total_cross_entropy is : 0.007144361
After 4000 training step(s), w1 is:
[[-1.7914352 2.4218476 1.4638877 ]
[-3.2893898 0.90241855 1.8852748 ]]

total_cross_entropy is : 0.005784708
Final w1 is:
[[-1.9618274 2.582354 1.6820377]
[-3.4681718 1.0698233 2.11789 ]]

可以看到随着训练的进行,交叉熵是逐渐变小的,交叉熵越小说明预测的结果和真实的结果差距越小。

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

1. 定义神经网络的结果和前向传播的输出结果。

** 2. 定义损失函数以及选择反向传播优化的算法**

** 3. 生成会话(tf.Session)并且在训练数据上反复运行反向传播优化算法。**

无论神经网络的结果如何变化,这3个步骤是不变的

猜你喜欢

转载自blog.csdn.net/HHH_ANS/article/details/83893581