前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TensorFlow 2.0 概述

TensorFlow 2.0 概述

作者头像
石璞东
发布2020-07-03 14:11:03
8250
发布2020-07-03 14:11:03
举报
文章被收录于专栏:石璞东 | haha石璞东 | haha

阅读本文大概需要 16 分钟。

前言

在本文中将介绍与我的毕设论文演示案例相关的TensorFlow的一些基础知识,包括张量计算图操作数据类型和维度以及模型的保存,接着在第二部分,本文将介绍演示案例代码中用到的一些TensorFlow 2.0中的高阶API,代码中不会涉及像TensorFlow 1.x版本中的Session等一些较为复杂的东西,所有的代码都是基于高阶API中的tf.keras.models来构建的(具体模型构建使用Sequential按层顺序构建),可以大大的方便读者更好的理解代码。

需要注意的一点,本论文中所实现的两个案例均在本机CPU上进行运算,对于更大数量级的数据训练建议采用添加GPU的方法或者托管在Google cloud、AWS云平台上进行数据的处理。

1.1 基础知识概述

1.1.1 张量

第一次看到TensorFlow这个名词,第一反应是去翻译一下这代表什么意思,通过查阅相关字典可以知道,Tensor被翻译为张量,Flow被翻译为流或者流动,组合起来TensorFlow可以被翻译为张量流。那什么是张量,什么又是流呢?

一般来将,把任意维度的数据称为张量,比如说一维数组(任意一门编程语言里都会学到一维数组的概念)、二维矩阵(我们在线性代数中学过关于矩阵的概念,这里不做赘述)以及N维数据。而是指让数据在不同的计算设备上进行传输并计算(因为只有Tensor形式的数据可以实现在不同的设备之间进行传递)。

总结起来,我们可以认为TensorFlow的意思就是:让Tensor类型的数据在各个计算设备之间进行流动并完成计算。那为什么要让数据流动起来呢?Tensor类型又具体包括什么呢?接下来先来看一段演示代码:

代码语言:javascript
复制
# 将通过清华镜像下载的tensorflow包导入
import tensorflow as tf
a = tf.constant([[1.0,-2],[-3,4]])
print(a)

控制台输出结果如下:

代码语言:javascript
复制
tf.Tensor(
[[ 1. -2.]
 [-3.  4.]], shape=(2, 2), dtype=float32)```

在上述代码中规定了一个2*2的矩阵,并将其打印在控制台。通过结果可以发现控制台输出的Tensor里面有三个参数:

  1. 第一个参数是一个2*2的矩阵,且矩阵中的元素全部为浮点类型。
  2. 第二个参数是shape,也就是输出矩阵的类型,很明显shape(2,2)表示输出矩阵为一个2*2的矩阵;举个例子,一个二阶张量a=[[1,1,1],[2,2,2]]的形状是两行三列,即shape=(2,3)。
  3. dtype=float32表示输出矩阵中元素的数据类型为浮点型(32为浮点数)

【注】:在上述对于代码部分的解释中提到一个名词二阶张量,接下来将通过表格的形式来区分一下标量、向量、矩阵的阶数的细微差异:

表1-1 标量向量和矩阵的阶数

rank(阶)

实例

例子

0

标量(只有大小)

a=1

1

向量(有大小和方向)

b=[1,1,1,1]

2

矩阵(数据表)

c=[[1,1],[1,1]]

3

3阶张量(数据立体)

d=[[[1],[1]],[[1],[1]]]

n

n阶

n层括号

简单解释一下,阶指的就是维度,它与矩阵的阶不同。

举个例子,对于a=[[1,1,1],[2,2,2],[3,3,3]]从矩阵的角度看,这是一个3*3的方阵,也就是说它的阶数为3,而从张量的角度看,它的阶数为2,即维度为2,因为它只有两层中括号。

1.1.2 计算图

首先来看看TensorFlow官网中的这幅图,一方面是帮助我们理解的概念,另一方面是为我们理解的概念做下铺垫。

【注】TensorFlow官网中的动图演示请参考如下网址:

http://www.shipudong.com/2020/03/24/bi-ye-she-ji-nei-rong-bu-chong/

图1.1 TensorFlow官网流图演示

将图一般分为两种,包括动态计算图静态计算图。我以中铁某局修建地铁为例来讲解这两种图的区别:

修建一条地铁需要设计图纸和施工队:

第一种情况,当设计师在设计图纸的时候(包括隧道走向、站点设置等,具体细节不予赘述)施工队什么也不干,必须等到设计工作完成之后,施工队才开始工作,(我们可以把这种情况理解为计算机中的同步方式,把设计工作和施工操作看作两个任务,当前任务未完成之前,不能进行其他操作)也就是说设计工作和具体施工完全分开,这就是所谓的静态计算图,我们称能够支持静态计算图的为静态框架,主要包括TensorFlow、Theano等;

第二种情况,设计工作和施工操作一起进行,设计方要求开凿隧道,施工队立即完成任务,如此下去,一经设计方下达任务,施工队必须立即完成操作,如此良性循环直到项目完成(我们把这种情况理解为计算机中的异步方式),这就是所谓的动态计算图,我们称能够支持动态计算图的为动态框架,主要包括Torch等。

在了解了动态计算图和静态计算图的例子之后,我们很明显的可以看出两种图的差异:静态计算图在未执行之前就必须定义好执行顺序和内存分配,简单来说,在程序未执行之前就知道了所有操作,有助于较快地执行计算操作;相比动态计算图,每次的执行顺序规划和内存分配都是局部的,并非全局最优,虽然灵活性较静态计算图有很大提升,但是代价太高,所以在现在流行的框架中,还是以静态框架为主,比如本论文中的由谷歌公司开源的TensorFlow。

1.1.3 操作

从图1.1可以观察到,数据一经输入(Input),会被进行不同的操作,首先会将数据进行预处理(比如图中的reshape操作),接着给处理好的数据中加入非线性操作(ReLU操作)等,使数据更符合自然界中的普遍关系,然后我们根据输入数据的类型进而采取比较合适的交叉熵函数(Crossentropy),用来衡量真实值与预测值的偏差,最后我们我们将根据项目真实情况选取合适的优化器(图中选用的为sgd,即随机梯度下降法)。图中的一个节点就代表一个操作,我们从计算图中了解到,TensorFlow属于静态计算图,也就是说在未执行前就已经定义好了执行的顺序,简单来讲,图中的各个操作之间是存在执行顺序的,而这些操作之间的依赖就是图中的。我们以一个非常简单的图示来讲解这个关系,首先来看一段代码:

代码语言:javascript
复制
# 定义变量a
a = tf.Variable(1.0,name="a")
# 定义操作b为a+1
b = tf.add(a,1,name="b")
# 定义操作c为b+1
c = tf.add(b,1,name="c")
# 定义操作d为b+10
d = tf.add(b,10,name="d")

上述代码认为a、b、c和d均为需要进行的操作,下图中的x表示一个常数,值为1。

图1.2 操作之间的依赖关系

首先定义a=1.0,b=a+1,即b=2.0,以此类推,c=3.0,d=11.0,可以这样理解,操作b的进行需要依赖操作a,操作c的进行需要依赖操作b的完成,操作d的进行需要依赖操作b,且操作c和d之间没有依赖关系。

1.1.4 数据类型和维度

对于任意一门编程语言都会有数据类型,区别就在于每一门编程语言定义不同数据类型的方式不一样,在本章开始的时候了解过,在TensorFlow中,用张量(Tensor)来表示数据结构,接下来我们就将TensorFlow中的的数据类型与Python中的数据类型作以简单的对比,并通过表格的形式清晰的展现出来:

表1-2 TensorFlow和Python中数据类型的对应关系

TensorFlow数据类型

Python中的表示

说明

DT_FLOAT

tf.float32

32位浮点数

DT_DOUBLE

tf.float64

64位浮点数

DT_INT8

tf.int8

8位有符号整数

DT_INT16

tf.int16

16位有符号整数

DT_INT32

tf.int32

32位有符号整数

DT_INT64

tf.int64

64位有符号整数

DT_UINT8

tf.uint8

8位无符号整数

DT_UINT16

tf.uint16

16位无符号整数

DT_STRING

tf.string

byte类型数组

DT_BOOL

tf.bool

布尔型

DT_COMPLEX64

tf.complex64

复数类型,由32位浮点数的实部和虚部组成

DT_COMPLEX128

tf.complex128

复数类型,由64位浮点数的实部和虚部组成

DT_QINT8

tf.qint8

量化操作的8位有符号整数

DT_QINT32

tf.quint32

量化操作的32位有符号整数

DT_QUINT8

tf.quint8

量化操作的8位无符号整数

维度的相关概念,在上述文章中的张量部分已经详细讲过,此处不再赘述。一般来说张量的阶数(维度)就是看有几层中括号,接下来看一段代码:

代码语言:javascript
复制
import tensorflow as tf
value_shape_0 = tf.Variable(1002)
value_shape_1 = tf.Variable([1,2,3])
value_shape_2 = tf.Variable([[1,2,3],[3,4,5],[5,6,7]])
print(value_shape_0.get_shape())
print(value_shape_1.get_shape())
print(value_shape_2.get_shape())

控制台输出结果如下:

代码语言:javascript
复制
()
(3,)
(3, 3)
(2, 3, 2)

代码解释:

  • value_shape_0:定义了一个标量(只有大小),其维度为0;
  • value_shape_1:定义了一个一维向量(有大小和方向),其维度为3;
  • value_shape_2:定义了一个二维的矩阵,矩阵大小为3*2;
  • value_shape_3:定义了一个三维张量,第一维的维度是2,第二维的维度是3,第三维的维度是2,可以简单理解为:这是一个大小为2*3且深度为2的矩阵。

1.1.5 模型保存

当我们完成一个案例之后,我们想要把当前训练好的模型保存下来(保存模型是指把训练的参数保存下来),方便我们之后重新使用。当我们重新使用的时候,我们只需要重新载入模型即可。

首先我们来看一下保存模型的代码:

代码语言:javascript
复制
# 保存模型
model.save("my_model.h5")

在关于MNIST手写字的例子中将我们训练好的模型保存下来,并命名为my_model.h5,接下来我们看一段载入模型的代码:

代码语言:javascript
复制
# 加载模型文件
model = tf.keras.models.load_model("my_model.h5")

同样是在MNIST手写字的例子中,我们将保存好的模型导入,并通过matplotlib函数画出模型图,具体模型图我会在本毕设系列推文的案例讲解部分中进行展示。

2. 相关API介绍

一般来讲,TensorFlow共有5个不同的层次结构,从低到高分别是硬件层内核层低阶API中阶API高阶API,我们对每一层作以简单的介绍:

  1. 硬件层:我们知道TensorFlow可以支持CPU、GPU、TPU(受限于硬件条件,我们本文中的项目是在本机CPU上运行的)加入计算资源池,作为一种计算设备参与运算;
  2. 内核层:该层是由C++语言实现的内核,可以支持跨平台的分布运行;
  3. 低阶API:该层主要提供了由Python实现的一些操作符,并对由内核层实现的一些低阶API进行封装,包括各种Tensor(张量)操作算子、计算图、自动微分等;
  4. 中阶API:该层是由Python实现的模型组件,并对低阶API进行了函数封装,主要包括各种模型层(tf.keras.layers)、损失函数(tf.keras.losses)、优化器(tf.keras.optimizers)、数据管道(tf.data.Dataset)等;
  5. 高阶API:该层为由Python实现的模型成品,主要为tf.keras.models提供的模型的类接口,在第四章中实现MNIST手写字识别的例子我们主要使用它。

图2.1 API详解

上述内容是我们对TensorFlow中的API做了宏观的描述,接下来我将着重介绍5个代码案例中较为重要的API:

  • tf.keras.models.Sequential:我们可以通过Sequential按层顺序来构建模型,也可以通过add方法一层一层添加模型(不建议使用),以下为代码演示:
代码语言:javascript
复制
model = tf.keras.models.Sequential([
#  里面是添加的模型层,比如说卷积层、池化层等
])
  • tf.keras.layers:我们可以通过此API添加我们需要的不同的模型层(卷积层、池化层等),通过查阅TensorFlow官网关于此API的介绍可以知道,读者可以通过此API添加如下模型层:

图2.2 TensorFlow官网tf.keras.layers部分API

以下是代码演示:

代码语言:javascript
复制
tf.keras.layers.Conv2D(input_shape = (28,28,1),filters = 32,kernel_size = 5,strides = 1,padding = "same",activation = "relu"),  # 28*28
  • tf.keras.datasets:用如下代码来加载MNIST收据集:
代码语言:javascript
复制
mnist = tf.keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
  • model.compile:可以通过此API来编译经Sequential构建好的模型,同时也可以定义优化器、损失函数、如何对网络参数进行优化以及在训练过程中是否要计算准确率等,我们来看看官网中对此API的解释:

图2.3 compile函数官网介绍

具体代码如下:

代码语言:javascript
复制
tf.keras.layers.Conv2D(input_shape = (28,28,1),filters = 32,kernel_size = 5,strides = 1,padding = "same",activation = "relu"),  # 28*28# 编译模型   优化器--adam  (sgd--随机梯度下降法)损失函数---均方误差   metrics---训练过程中计算准确率accuracy
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',metrics=['accuracy'])
  • model.fit:通过此API来训练模型,同时可以定义训练的迭代周期以及每次训练获取样本集的数量(一般默认batch_size=32),我们来看看官网对此API的解释:

图2.4 fit函数官网介绍

具体代码如下:

代码语言:javascript
复制
# 训练模型      epochs --- 迭代周期   batch_size默认为32
model.fit(x_train, y_train, batch_size=32,epochs=5)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 hahaCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1.1.1 张量
  • 1.1.2 计算图
  • 1.1.3 操作
  • 1.1.4 数据类型和维度
  • 1.1.5 模型保存
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档