TensorFlow学习——基本概念(1)

版权声明:转载请注明出处,谢谢!!! https://blog.csdn.net/tszupup/article/details/88752506

        最近在学深度学习的编程实现,以博客的形式把每天学到的东西总结一下,相信会有所收获。
        注:写这篇博客时参考了《TensorFlow实战Google深度学习框架》第二版,主要对其中的第三章“TensorFlow入门”中的内容进行总结。

目录

1 TensorFlow的计算模型——计算图

2 TensorFlow的数据模型——张量

3 TensorFlow的运行模型——会话

4 使用TensorFlow实现一个简单的神经网络


1 TensorFlow的计算模型——计算图

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

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

第一阶段:定义计算图中所有的计算;

第二阶段:执行计算

        TensorFlow会自动将定义的计算转化为计算图上的节点,在TensorFlow程序中,系统会自动维护一个默认的计算图,同时我们也可以通过tf.Graph()函数来生成新的计算图。不同计算图上的张量和运算都不会共享

        TensorFlow中的计算图不仅可以用来隔离张量和计算,它还提供了管理张量和计算的机制,计算图可以通过tf.Graph.device()函数来指定运行计算的设备。有效地整理TensorFlow程序中的资源也是计算图的一个重要功能,在一个计算图中,可以通过集合collection来管理不同类型的资源,如tf.GraphKeys.TRAINABLE_VARIABLES集合中包含了模型中的所有可学习变量。

2 TensorFlow的数据模型——张量

        在TensorFlow程序中,所有的数据都通过张量的形式来表示。从功能的角度上看,张量可以被简单为多维数组,其中零阶张量表示标量;一阶张量为向量,也就是一维数组;n阶张量可以理解为一个n维数组。但张量在TensorFlow中的实现并不是直接采用数组的形式,它只是对TensorFlow中运算结果的引用。即在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程

        一个张量中主要保存了三个属性:名字、维度和类型。

名字不仅是一个张量的唯一标识符,也给出了这个张量是如何被计算出来的;

维度这个属性描述了一个张量的维度信息;

每一个张量会有一个唯一的类型,TensorFlow会对参与计算的所有张量进行类型的检查,当发现类型不匹配时会报错。

        因为使用默认类型有可能会导致潜在的类型不匹配问题,所以一般建议通过指定dtype来明确指出变量或者常量的类型

        张量的第一类用途是对中间计算结果的引用,通过张量来存储中间结果;第二类情况是当计算图构造完成之后,张量可以用来获取计算结果

3 TensorFlow的运行模型——会话

        计算图和会话是TensorFlow中关于如何组织数据和计算的概念,TensorFlow使用会话(session)来执行定义好的运算会话拥有并管理TensorFlow程序运行时的所有资源,当所有计算完成之后需要关闭会话来帮助系统回收资源,否则就可能出现资源泄露的问题。

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

第一种模式需要明确调用会话生成函数和关闭会话函数

第二章模式通过Python的上下文管理器来使用会话,当上下文管理器退出时会自动释放所有资源。

        在交互式环境下,通过设置默认会话的方式来获取张量的取值更加方便,所以TensorFlow提供了一种在交互式环境下直接构建默认会话的函数tf.InteractiveSession()。

4 使用TensorFlow实现一个简单的神经网络

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

1) 提取问题中的实体的特征向量作为神经网络的输入;

2) 定义神经网络的结构,并定义如何从神经网络的输入得到输出,即神经网络的前向传播算法;

3) 通过训练数据来调整神经网络中参数的取值,即神经网络的训练过程;

4) 使用训练好的神经网络来预测未知的数据。

        神经网络中的变量

        在TensorFlow中,变量的作用就是保存和更新神经网络中的参数。TensorFlow中的变量需要指定初始值,在神经网络模型中,一般使用随机数给TensorFlow中的变量初始化。除了使用随机数或常数进行初始化,TensorFlow也支持通过其他变量的初始值来初始化新的变量。一个变量的值在被使用之前,这个变量的初始化过程需要被明确地调用,因为虽然在变量定义时给出了变量初始化的方法,但是这个方法并没有被真正执行。我们可以通过sess.run(w.initializer)来逐个初始化变量,也可以通过tf.global_variables_initializer()函数来实现所有变量的初始化

        在TensorFlow中,变量的声明函数tf.Variable()是一个运算,这个运算的输出结果是一个张量

        如前所述,在TensorFlow中可以通过tf.trainable_variables函数得到所有需要优化的参数,TensorFlow中提供的神经网络优化算法会将GraphKeys.TRAINABLE_VARIABLES集合中的变量作为默认的优化对象。

        维度和类型是变量最重要的两个属性,其中变量的类型是不可改变的,但变量的维度在程序运行时是有可能改变的,尽管这种用法很少见。

        占位符placeholder:

        TensorFlow提供了placeholder机制用于提供输入数据。placeholder相当于定义了一个位置,这个位置中的数据在程序运行时再指定。这样在程序中就不需要生成大量常量来提供输入数据,而只需要将数据通过placeholder传入TensorFlow计算图。在placeholder定义时,这个位置上的数据的类型是需要指定的,且类型不可更改

        在程序运行时,通过提供一个feed_dict来指定输入的取值,feed_dict是一个字典,在字典中需要给出每个用到的plcaeholder的取值。

        下面将以一个完整的二分类程序说明以上三个概念:

#-*-coding:utf-8-*-
"""
@author:taoshouzheng
@time:2018/9/28 19:15
@email:[email protected]
"""

import tensorflow as tf

# 导入Numpy包中的伪随机数生成器
from numpy.random import RandomState

# 首先定义计算图中所有的计算
# 定义训练数据BATCH_SIZE的大小
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))

# 定义占位符placeholder作为存放输入数据的地方
# 在shape的第一个维度上使用None可以方便使用不同的BATCH大小
# 注意定义占位符placeholder时,这个位置上的数据类型是需要指定的,placeholder的类型也是不可以改变的
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 = tf.sigmoid(y)		# 使用sigmoid函数将y转换为0~1之间的数值,转换后y代表预测为正例的概率,1-y代表为负例的概率
# 定义二分类的交叉熵损失函数
# tf.reduce_mean()函数:用于计算张量tensor沿着指定数轴(tensor的某一维度)上的平均值,主要用作降维或者计算tensor的平均值
# tf.log():定义某元素的自然对数
# tf.clip_by_value(A, min, max):输入一个张量A,把A中每一个元素的值都压缩在min和max之间,小于min的让它等于min,大于max的元素的值等于max
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)) + (1 - y_) *
								tf.log(tf.clip_by_value(1 - y, 1e-10, 1.0)))
# 定义Adam优化器
train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)

# 通过随机数生成一个模拟数据集
rdm = RandomState(1)
dataset_size = 128		# 数据集规模
# RandomState创建一个给定形状的数组,数组中的值使用[0, 1)上的均匀分布填充
X = rdm.rand(dataset_size, 2)
# 定义规则来给出样本的标签,这里x1 + x2 < 1的样例被认为是正样本,其他的被认为是负样本
# 0表示负样本,1表示正样本
Y = [[int(x1 + x2 < 1)] for (x1, x2) in X]
# 打印样本,看看其格式
print("打印第一条样本")
print(X[0], Y[0])

# 执行计算
# 创建一个会话来运行TensorFlow程序
with tf.Session() as sess:		# 使用上下文管理器创建会话
	# 使用tf.global_variables_initializer()初始化所有变量
	init_op = tf.global_variables_initializer()
	# 初始化变量
	sess.run(init_op)
	# 打印初始化后的权值
	print("训练之前的权值")
	print(sess.run(w1))
	print(sess.run(w2))
	# 设定训练的轮数
	STEPS = 5000
	for i in range(STEPS):
		# 每次选取BATCH_SIZE个样本进行训练
		# %在Python中用于取模,返回除法的余数
		start = (i * BATCH_SIZE) % dataset_size		# 批次中第一个样本的索引
		end = min(start + BATCH_SIZE, dataset_size)		# 批次中最后一个样本的索引
		# 通过选取的样本训练神经网络并更新参数c
		# 注意feed_dict是一个字典,字典中的键是占位符placeholder的名字,值是占位符的取值
		sess.run(train_step, feed_dict={x_: X[start: end], y_: Y[start: end]})
		if i % 500 == 0:
			# 每个500轮计算神经网络模型在所有数据上的交叉熵并输出
			total_cross_entropy = sess.run(cross_entropy, feed_dict={x_: X, y_: Y})
			print("在训练了 %d 轮之后,在所有数据上的交叉熵为:% g" % (i, total_cross_entropy))
	# 打印训练完之后的权值用于比较
	print("训练之后的权值")
	print(sess.run(w1))
	print(sess.run(w2))

        运行结果截图如下:

        这里可以看到经过训练后,神经网络模型在全部数据上的交叉熵损失逐渐变小,这是因为在训练过程中优化器优化了神经网络的权值,使得神经网络能够更好地拟合训练数据。

        总结一下训练神经网络的三个步骤

1) 定义神经网络的结构和前向传播的输出结果;

2) 定义损失函数、选择反向传播优化的算法;

3) 生成会话,并在训练数据上反复运行反向传播优化算法。

        谢谢!

猜你喜欢

转载自blog.csdn.net/tszupup/article/details/88752506