TensorFlow 2 简介

TensorFlow 是由谷歌在 2015 年 11 月发布的深度学习开源工具,我们可以用它来快速构建深度神经网络,并训练深度学习模型。运用 TensorFlow 及其他开源框架的主要目的,就是为我们提供一个更利于搭建深度学习网络的模块工具箱,使开发时能够简化代码,最终呈现出的模型更加简洁易懂。

2019 年,TensorFlow 推出了 2.0 版本,也意味着 TensorFlow 从 1.x 正式过度到 2.x 时代。根据 TensorFlow 官方 介绍内容 显示,2.0 版本将专注于简洁性和易用性的改善,主要升级方向包括:

  • 使用 Keras 和 Eager Execution 轻松构建模型。
  • 在任意平台上实现稳健的生产环境模型部署。
  • 为研究提供强大的实验工具。
  • 通过清理废弃的 API。 和减少重复来简化 API。

当然,如果你对 TensorFlow 1.x 本来就不熟悉,可能无法看明白这些升级的内容。不用担心,本次课程将直接对 TensorFlow 2 进行学习,我们不再回首过去,直接展望未来。

安装 TensorFlow 2

  1. pip install -U tensorflow

接下来,我们将从 TensorFlow 基础概念语法入手,一步一步学习 TensorFlow 的使用。

张量

首先,你应该知道什么是向量和矩阵。我们把 1 维的数组称之为向量, 2 维的数组称之为矩阵。那么,现在告诉你张量其实代表着更大的范围,你也可以把其看作是N 维数组。

所以,如果现在重新描述向量和矩阵,就可以是:一阶张量为向量,二阶张量为矩阵。当然,零阶张量也就是标量,而更重要的是 N 阶张量,也就是 N 维数组。

所以,张量并不是什么晦涩难懂的概念。如果不严谨的讲,张量就是 NN 维数组。前面提到的向量、矩阵,也是张量。

后面将学习到的大多数深度学习框架都会使用张量的概念,这样做的好处是统一对数据的定义。NumPy 中,数据都使用 Ndarray 多维数组进行定义,TensorFlow 中,数据都会用张量进行表述。

下面就来学习 TensorFlow 中对张量的定义。在 TensorFlow 中,每一个 Tensor 都具备两个基础属性:数据类型(默认:float32)和形状。

其中,数据类型大致如下表所示:

另外,TensorFlow 通过三种符号约定来描述张量维度:阶,形状和维数。三者之间的关系如下:

值得注意的是,上表中的示例都是形容张量的形状。例如 [3, 4] 指的张量的形状为 [3, 4],而不是张量 [3, 4]。

根据不同的用途,TensorFlow 中主要有 2 种张量类型,分别是:

  1. tf.Variable :变量 Tensor,需要指定初始值,常用于定义可变参数,例如神经网络的权重。
  2. tf.constant :常量 Tensor,需要指定初始值,定义不变化的张量。

我们可以通过传入列表或 NumPy 数组来新建变量和常量类型的张量:

代码示例:

  1. import tensorflow as tf
  2. tf.__version__

输出

  1. '2.0.0'
  2. v = tf.Variable([[1, 2], [3, 4]]) # 形状为 (2, 2) 的二维变量
  3. v

输出

  1. <tf.Variable 'Variable:0' shape=(2, 2) dtype=int32, numpy=
  2. array([[1, 2],
  3. [3, 4]], dtype=int32)>
  4. c = tf.constant([[1, 2], [3, 4]]) # 形状为 (2, 2) 的二维常量
  5. c

输出

  1. <tf.Tensor: id=9, shape=(2, 2), dtype=int32, numpy=
  2. array([[1, 2],
  3. [3, 4]], dtype=int32)>

仔细观察,你会发现输出包含了张量的 3 部分属性,分别是形状 shape,数据类型 dtype,以及对应的 NumPy 数组。

你还可以直接通过 .numpy() 输出张量的 NumPy 数组。

  1. c.numpy()

输出

  1. array([[1, 2],
  2. [3, 4]], dtype=int32)

上面我们已经介绍了常量张量,这里再列举几个经常会用到的新建特殊常量张量的方法:

  • tf.zeros:新建指定形状且全为 0 的常量 Tensor
  • tf.zeros_like:参考某种形状,新建全为 0 的常量 Tensor
  • tf.ones:新建指定形状且全为 1 的常量 Tensor
  • tf.ones_like:参考某种形状,新建全为 1 的常量 Tensor
  • tf.fill:新建一个指定形状且全为某个标量值的常量 Tensor
  1. c = tf.zeros([3, 3]) # 3x3 全为 0 的常量 Tensor
  2. c

输出

  1. <tf.Tensor: id=12, shape=(3, 3), dtype=float32, numpy=
  2. array([[0., 0., 0.],
  3. [0., 0., 0.],
  4. [0., 0., 0.]], dtype=float32)>
  5. tf.ones_like(c) # 与 c 形状一致全为 1 的常量 Tensor

输出

  1. <tf.Tensor: id=15, shape=(3, 3), dtype=float32, numpy=
  2. array([[1., 1., 1.],
  3. [1., 1., 1.],
  4. [1., 1., 1.]], dtype=float32)>
  5. tf.fill([2, 3], 6) # 2x3 全为 6 的常量 Tensor

输出

  1. <tf.Tensor: id=18, shape=(2, 3), dtype=int32, numpy=
  2. array([[6, 6, 6],
  3. [6, 6, 6]], dtype=int32)>

除此之外,我们还可以创建一些序列,例如:

  • tf.linspace:创建一个等间隔序列。
  • tf.range:创建一个数字序列。
  1. tf.linspace(1.0, 10.0, 5, name="linspace")

输出

  1. <tf.Tensor: id=22, shape=(5,), dtype=float32, numpy=array([ 1\. , 3.25, 5.5 , 7.75, 10\. ], dtype=float32)>
  2. tf.range(start=1, limit=10, delta=2)

输出

  1. <tf.Tensor: id=26, shape=(5,), dtype=int32, numpy=array([1, 3, 5, 7, 9], dtype=int32)>

实际上,如果你熟悉 NumPy 的话,你会发现这与 NumPy 中创建各式各样的多维数组方法大同小异。数据类型是一切的基础,了解完张量我们就可以继续学习张量的运算了。

Eager Execution

TensorFlow 2 带来的最大改变之一是将 1.x 的 Graph Execution(图与会话机制)更改为 Eager Execution(动态图机制)。在 1.x 版本中,低级别 TensorFlow API 首先需要定义数据流图,然后再创建 TensorFlow 会话,这一点在 2.0 中被完全舍弃。TensorFlow 2 中的 Eager Execution 是一种命令式编程环境,可立即评估操作,无需构建图。

所以说,TensorFlow 的张量运算过程可以像 NumPy 一样直观且自然了。接下来,我们以最简单的加法运算为例:

  1. c + c # 加法计算

输出

  1. <tf.Tensor: id=27, shape=(3, 3), dtype=float32, numpy=
  2. array([[0., 0., 0.],
  3. [0., 0., 0.],
  4. [0., 0., 0.]], dtype=float32)>

如果你接触过 1.x 版本的 TensorFlow,你要知道一个加法运算过程十分复杂。我们需要初始化全局变量 → 建立会话 → 执行计算,最终才能打印出张量的运算结果。

  1. init_op = tf.global_variables_initializer() # 初始化全局变量
  2. with tf.Session() as sess: # 启动会话
  3. sess.run(init_op)
  4. print(sess.run(c + c)) # 执行计算

Eager Execution 带来的好处显而易见,其进一步降低了 TensorFlow 的入门门槛。之前的 Graph Execution 模式,实际上让很多人在入门时都很郁闷,因为完全不符合正常思维习惯。

TensorFlow 中提供的数学计算,包括线性代数计算方面的方法也是应有尽有,十分丰富。下面,我们再列举一个示例。

  1. a = tf.constant([1., 2., 3., 4., 5., 6.], shape=[2, 3])
  2. b = tf.constant([7., 8., 9., 10., 11., 12.], shape=[3, 2])
  3. c = tf.linalg.matmul(a, b) # 矩阵乘法
  4. c

输出

  1. <tf.Tensor: id=34, shape=(2, 2), dtype=float32, numpy=
  2. array([[ 58., 64.],
  3. [139., 154.]], dtype=float32)>
  4. tf.linalg.matrix_transpose(c) # 转置矩阵

输出

  1. <tf.Tensor: id=36, shape=(2, 2), dtype=float32, numpy=
  2. array([[ 58., 139.],
  3. [ 64., 154.]], dtype=float32)>

你应该能够感觉到,这些常用 API 都能在 NumPy 中找到对应的方法,这也就是课程需要你预先熟悉 NumPy 的原因。由于函数实在太多太多。一般来讲,除了自己经常使用到的,都会在需要某种运算的时候,查阅官方文档。

所以说,你可以把 TensorFlow 理解成为 TensorFlow 式的 NumPy + 为搭建神经网络而生的 API。

自动微分

在数学中,微分是对函数的局部变化率的一种线性描述。虽然微分和导数是两个不同的概念。但是,对一元函数来说,可微与可导是完全等价的。如果你熟悉神经网络的搭建过程,应该明白梯度的重要性。而对于复杂函数的微分过程是及其麻烦的,为了提高应用效率,大部分深度学习框架都有自动微分机制。

TensorFlow 中,你可以使用 tf.GradientTape 跟踪全部运算过程,以便在必要的时候计算梯度。

  1. w = tf.Variable([1.0]) # 新建张量
  2. with tf.GradientTape() as tape: # 追踪梯度
  3. loss = w * w
  4. grad = tape.gradient(loss, w) # 计算梯度
  5. grad

输出

  1. <tf.Tensor: id=52, shape=(1,), dtype=float32, numpy=array([2.], dtype=float32)>

上面,我们演示了一个自动微分过程,它的数学求导过程如下:

所以,当 w 等于 1 时,计算结果为 2。

tf.GradientTape 会像磁带一样记录下计算图中的梯度信息,然后使用 .gradient 即可回溯计算出任意梯度,这对于使用 TensorFlow 低阶 API 构建神经网络时更新参数非常重要。

常用模块

上面,我们已经学习了 TensorFlow 核心知识,接下来将对 TensorFlow API 中的常用模块进行简单的功能介绍。对于框架的使用,实际上就是灵活运用各种封装好的类和函数。由于 TensorFlow API 数量太多,迭代太快,所以大家要养成随时 查阅官方文档 的习惯。

  • tf.:包含了张量定义,变换等常用函数和类。
  • tf.data:输入数据处理模块,提供了像 tf.data.Dataset 等类用于封装输入数据,指定批量大小等。
  • tf.image:图像处理模块,提供了像图像裁剪,变换,编码,解码等类。
  • tf.keras:原 Keras 框架高阶 API。包含原 tf.layers 中高阶神经网络层。
  • tf.linalg:线性代数模块,提供了大量线性代数计算方法和类。
  • tf.losses:损失函数模块,用于方便神经网络定义损失函数。
  • tf.math:数学计算模块,提供了大量数学计算函数。
  • tf.saved_model:模型保存模块,可用于模型的保存和恢复。
  • tf.train:提供用于训练的组件,例如优化器,学习率衰减策略等。
  • tf.nn:提供用于构建神经网络的底层函数,以帮助实现深度神经网络各类功能层。
  • tf.estimator:高阶 API,提供了预创建的 Estimator 或自定义组件。

在构建深度神经网络时,TensorFlow 可以说提供了你一切想要的组件,从不同形状的张量、激活函数、神经网络层,到优化器、数据集等,一应俱全。由于 TensorFlow 包含的接口太多,每个都拿出来练习变得不切实际。关于TensorFlow 2.0 的基础内容就到这里!

想要了解新特性的详细内容,请学习课程:

《TensorFlow 2.0 新特性快速入门​》

想要进行实战项目,请学习课程:

《TensorFlow 2 深度学习入门与实践》​

知乎专栏同步:https://zhuanlan.zhihu.com/p/88829655

TensorFlow 2 快速教程,初学者入门必备的更多相关文章

  1. 【入门必备】最佳的 Node.js 学习教程和资料书籍

    Web 开发人员对 Node.js 的关注日益增多,更多的公司和开发者开始尝试使用 Node.js 来实现一些对实时性要求高,I/O密集型的业务.这篇文章中,我们整理了一批优秀的资源,你可以得到所有你 ...

  2. TensorFlow 中文资源全集,官方网站,安装教程,入门教程,实战项目,学习路径。

    Awesome-TensorFlow-Chinese TensorFlow 中文资源全集,学习路径推荐: 官方网站,初步了解. 安装教程,安装之后跑起来. 入门教程,简单的模型学习和运行. 实战项目, ...

  3. TensorFlow 中文资源精选,官方网站,安装教程,入门教程,实战项目,学习路径。

    Awesome-TensorFlow-Chinese TensorFlow 中文资源全集,学习路径推荐: 官方网站,初步了解. 安装教程,安装之后跑起来. 入门教程,简单的模型学习和运行. 实战项目, ...

  4. 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV

    这次博客园的排版彻底残了..高清版请移步: https://zhuanlan.zhihu.com/p/24425116 本篇是前面两篇教程: 给深度学习入门者的Python快速教程 - 基础篇 给深度 ...

  5. 给深度学习入门者的Python快速教程 - numpy和Matplotlib篇

    始终无法有效把word排版好的粘贴过来,排版更佳版本请见知乎文章: https://zhuanlan.zhihu.com/p/24309547 实在搞不定博客园的排版,排版更佳的版本在: 给深度学习入 ...

  6. AFNnetworking快速教程,官方入门教程译

    AFNnetworking快速教程,官方入门教程译 分类: IOS2013-12-15 20:29 12489人阅读 评论(5) 收藏 举报 afnetworkingjsonios入门教程快速教程 A ...

  7. OsharpNS轻量级.net core快速开发框架简明入门教程-Osharp.Redis使用

    OsharpNS轻量级.net core快速开发框架简明入门教程 教程目录 从零开始启动Osharp 1.1. 使用OsharpNS项目模板创建项目 1.2. 配置数据库连接串并启动项目 1.3. O ...

  8. OsharpNS轻量级.net core快速开发框架简明入门教程-从零开始启动Osharp

    OsharpNS轻量级.net core快速开发框架简明入门教程 教程目录 从零开始启动Osharp 1.1. 使用OsharpNS项目模板创建项目 1.2. 配置数据库连接串并启动项目 1.3. O ...

  9. OsharpNS轻量级.net core快速开发框架简明入门教程-代码生成器的使用

    OsharpNS轻量级.net core快速开发框架简明入门教程 教程目录 从零开始启动Osharp 1.1. 使用OsharpNS项目模板创建项目 1.2. 配置数据库连接串并启动项目 1.3. O ...

随机推荐

  1. 深入理解JVM虚拟机

    JVM平台上还可以运行其他语言,运行的是Class字节码.只要能翻译成Class的语言就OK了.挺强大的. JVM厂商很多 垃圾收集器.收集算法 JVM检测工具 关于类的加载: Java代码中,类型( ...

  2. vue aes

    npm install crypto-js import CryptoJS from "crypto-js/crypto-js"; const KEY = CryptoJS.enc ...

  3. Nexus上传python包

    参考 https://blog.csdn.net/m0_37607365/article/details/79998955 1.首先创建pypi仓库 其中,PyPI类的服务,支持三种: proxy,提 ...

  4. 在OpenShift 3.11环境开启多网络平面

    1.整体架构 Multus CNI是OpenShift的容器网络接口(CNI)插件,可将多个网络接口附加到Pod. 通常,在OpenShift中,每个Pod仅具有一个网络接口(除了回送),Multus ...

  5. linux驱动开发学习二:创建一个阻塞型的字符设备

    在Linux 驱动程序中,可以使用等待队列来实现阻塞进程的唤醒.等待队列的头部定义如下,是一个双向列表. struct list_head { struct list_head *next, *pre ...

  6. 深入Vue响应式原理

    深入Vue.js响应式原理 一.创建一个Vue应用 new Vue({ data() { return { name: 'yjh', }; }, router, store, render: h =& ...

  7. 026 SSM综合练习02--数据后台管理系统--数据库表创建及SSM环境搭建

    1.数据库准备 本项目我们Oracle数据库,Oracle 为每个项目创建单独user,oracle数据表存放在表空间下,每个用户有独立表空间. (1)采用数据库管理员账号:SYSTEM,再配合数据库 ...

  8. 带小伙伴手写 golang context

    前言 - context 源码 可以先了解官方 context.go 轮廓. 这里捎带保存一份当前 context 版本备份. // Copyright 2014 The Go Authors. Al ...

  9. LeetCode 1259. Handshakes That Don't Cross - Java - DP

    题目链接:https://leetcode-cn.com/problems/handshakes-that-dont-cross/ You are given an even number of pe ...

  10. datanode启动异常(Incompatible clusterIDs)

    问题: 正常start-all.sh无法启动datanode进程,但是./hadoop-daemon.sh start datanode又可以启动.过一会后datanode进程又莫名消失. 原理: 多 ...