TensorFlow 是由谷歌在 2015 年 11 月发布的深度学习开源工具,咱们能够用它来快速构建深度神经网络,并训练深度学习模型。运用 TensorFlow 及其余开源框架的主要目的,就是为咱们提供一个更利于搭建深度学习网络的模块工具箱,使开发时可以简化代码,最终呈现出的模型更加简洁易懂。编程
2019 年,TensorFlow 推出了 2.0 版本,也意味着 TensorFlow 从 1.x 正式过分到 2.x 时代。根据 TensorFlow 官方 介绍内容 显示,2.0 版本将专一于简洁性和易用性的改善,主要升级方向包括:数组
固然,若是你对 TensorFlow 1.x 原本就不熟悉,可能没法看明白这些升级的内容。不用担忧,本次课程将直接对 TensorFlow 2 进行学习,咱们再也不回首过去,直接展望将来。网络
pip install -U tensorflow
接下来,咱们将从 TensorFlow 基础概念语法入手,一步一步学习 TensorFlow 的使用。框架
首先,你应该知道什么是向量和矩阵。咱们把 1 维的数组称之为向量, 2 维的数组称之为矩阵。那么,如今告诉你张量其实表明着更大的范围,你也能够把其看做是N 维数组。函数
因此,若是如今从新描述向量和矩阵,就能够是:一阶张量为向量,二阶张量为矩阵。固然,零阶张量也就是标量,而更重要的是 N 阶张量,也就是 N 维数组。工具
因此,张量并非什么晦涩难懂的概念。若是不严谨的讲,张量就是 NN 维数组。前面提到的向量、矩阵,也是张量。学习
后面将学习到的大多数深度学习框架都会使用张量的概念,这样作的好处是统一对数据的定义。NumPy 中,数据都使用 Ndarray 多维数组进行定义,TensorFlow 中,数据都会用张量进行表述。优化
下面就来学习 TensorFlow 中对张量的定义。在 TensorFlow 中,每个 Tensor 都具有两个基础属性:数据类型(默认:float32)和形状。编码
其中,数据类型大体以下表所示:spa
另外,TensorFlow 经过三种符号约定来描述张量维度:阶,形状和维数。三者之间的关系以下:
值得注意的是,上表中的示例都是形容张量的形状。例如 [3, 4] 指的张量的形状为 [3, 4],而不是张量 [3, 4]。
根据不一样的用途,TensorFlow 中主要有 2 种张量类型,分别是:
咱们能够经过传入列表或 NumPy 数组来新建变量和常量类型的张量:
代码示例:
import tensorflow as tf tf.__version__
输出
'2.0.0' v = tf.Variable([[1, 2], [3, 4]]) # 形状为 (2, 2) 的二维变量 v
输出
<tf.Variable 'Variable:0' shape=(2, 2) dtype=int32, numpy= array([[1, 2], [3, 4]], dtype=int32)> c = tf.constant([[1, 2], [3, 4]]) # 形状为 (2, 2) 的二维常量 c
输出
<tf.Tensor: id=9, shape=(2, 2), dtype=int32, numpy= array([[1, 2], [3, 4]], dtype=int32)>
仔细观察,你会发现输出包含了张量的 3 部分属性,分别是形状 shape,数据类型 dtype,以及对应的 NumPy 数组。
你还能够直接经过 .numpy() 输出张量的 NumPy 数组。
c.numpy()
输出
array([[1, 2], [3, 4]], dtype=int32)
上面咱们已经介绍了常量张量,这里再列举几个常常会用到的新建特殊常量张量的方法:
c = tf.zeros([3, 3]) # 3x3 全为 0 的常量 Tensor c
输出
<tf.Tensor: id=12, shape=(3, 3), dtype=float32, numpy= array([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], dtype=float32)> tf.ones_like(c) # 与 c 形状一致全为 1 的常量 Tensor
输出
<tf.Tensor: id=15, shape=(3, 3), dtype=float32, numpy= array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], dtype=float32)> tf.fill([2, 3], 6) # 2x3 全为 6 的常量 Tensor
输出
<tf.Tensor: id=18, shape=(2, 3), dtype=int32, numpy= array([[6, 6, 6], [6, 6, 6]], dtype=int32)>
除此以外,咱们还能够建立一些序列,例如:
tf.linspace(1.0, 10.0, 5, name="linspace")
输出
<tf.Tensor: id=22, shape=(5,), dtype=float32, numpy=array([ 1\. , 3.25, 5.5 , 7.75, 10\. ], dtype=float32)> tf.range(start=1, limit=10, delta=2)
输出
<tf.Tensor: id=26, shape=(5,), dtype=int32, numpy=array([1, 3, 5, 7, 9], dtype=int32)>
实际上,若是你熟悉 NumPy 的话,你会发现这与 NumPy 中建立各式各样的多维数组方法大同小异。数据类型是一切的基础,了解完张量咱们就能够继续学习张量的运算了。
TensorFlow 2 带来的最大改变之一是将 1.x 的 Graph Execution(图与会话机制)更改成 Eager Execution(动态图机制)。在 1.x 版本中,低级别 TensorFlow API 首先须要定义数据流图,而后再建立 TensorFlow 会话,这一点在 2.0 中被彻底舍弃。TensorFlow 2 中的 Eager Execution 是一种命令式编程环境,可当即评估操做,无需构建图。
因此说,TensorFlow 的张量运算过程能够像 NumPy 同样直观且天然了。接下来,咱们以最简单的加法运算为例:
c + c # 加法计算
输出
<tf.Tensor: id=27, shape=(3, 3), dtype=float32, numpy= array([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], dtype=float32)>
若是你接触过 1.x 版本的 TensorFlow,你要知道一个加法运算过程十分复杂。咱们须要初始化全局变量 → 创建会话 → 执行计算,最终才能打印出张量的运算结果。
init_op = tf.global_variables_initializer() # 初始化全局变量 with tf.Session() as sess: # 启动会话 sess.run(init_op) print(sess.run(c + c)) # 执行计算
Eager Execution 带来的好处显而易见,其进一步下降了 TensorFlow 的入门门槛。以前的 Graph Execution 模式,实际上让不少人在入门时都很郁闷,由于彻底不符合正常思惟习惯。
TensorFlow 中提供的数学计算,包括线性代数计算方面的方法也是应有尽有,十分丰富。下面,咱们再列举一个示例。
a = tf.constant([1., 2., 3., 4., 5., 6.], shape=[2, 3]) b = tf.constant([7., 8., 9., 10., 11., 12.], shape=[3, 2]) c = tf.linalg.matmul(a, b) # 矩阵乘法 c
输出
<tf.Tensor: id=34, shape=(2, 2), dtype=float32, numpy= array([[ 58., 64.], [139., 154.]], dtype=float32)> tf.linalg.matrix_transpose(c) # 转置矩阵
输出
<tf.Tensor: id=36, shape=(2, 2), dtype=float32, numpy= array([[ 58., 139.], [ 64., 154.]], dtype=float32)>
你应该可以感受到,这些经常使用 API 都能在 NumPy 中找到对应的方法,这也就是课程须要你预先熟悉 NumPy 的缘由。因为函数实在太多太多。通常来说,除了本身常用到的,都会在须要某种运算的时候,查阅官方文档。
因此说,你能够把 TensorFlow 理解成为 TensorFlow 式的 NumPy + 为搭建神经网络而生的 API。
在数学中,微分是对函数的局部变化率的一种线性描述。虽然微分和导数是两个不一样的概念。可是,对一元函数来讲,可微与可导是彻底等价的。若是你熟悉神经网络的搭建过程,应该明白梯度的重要性。而对于复杂函数的微分过程是及其麻烦的,为了提升应用效率,大部分深度学习框架都有自动微分机制。
TensorFlow 中,你可使用 tf.GradientTape 跟踪所有运算过程,以便在必要的时候计算梯度。
w = tf.Variable([1.0]) # 新建张量 with tf.GradientTape() as tape: # 追踪梯度 loss = w * w grad = tape.gradient(loss, w) # 计算梯度 grad
输出
<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 数量太多,迭代太快,因此你们要养成随时 查阅官方文档 的习惯。
在构建深度神经网络时,TensorFlow 能够说提供了你一切想要的组件,从不一样形状的张量、激活函数、神经网络层,到优化器、数据集等,包罗万象。因为 TensorFlow 包含的接口太多,每一个都拿出来练习变得不切实际。关于TensorFlow 2.0 的基础内容就到这里!
想要了解新特性的详细内容,请学习课程:
想要进行实战项目,请学习课程: 《TensorFlow 2 深度学习入门与实践》