ref: https://zhuanlan.zhihu.com/p/344846077
计算图模型由节点(nodes)和线(edges)组成,节点表示操作符/算子Operator,线表示计算间的依赖。实线表示有数据传递的依赖,传递的数据就是张量;虚线通常表示控制依赖,即执行的先后顺序。
Tensorflow会在内存中构建计算图,以表示程序执行的逻辑。整个计算图可以被分成多块,并且可以并行地运行在多个不同的CPU或GPU上,因而可以支持大规模神经网络。
Tensorflow中的计算图有三种:静态计算图、动态计算图、Autograph。其中tf1使用的是静态计算图,即先使用tf的各种算子创建计算图,再开启一个会话Session,显式执行。tf2默认使用的是动态计算图,即每使用一个算子后,该算子会被动态加入到隐含的默认计算图中立即执行。
动态图的好处是方便调试,运行时宛如Python原生代码,坏处是增加了Python进程和tf的C++进程之间的通信,因此会减慢速度;静态图是在图像构建完成后,再调用C++代码,并且会优化计算步骤(剪去与结果无关的计算步骤),因此效率更高。
Autograph是使用@tf.function装饰器将普通Python函数转换成tf1中对应的静态计算图构建代码。实践中可以先用动态图调试,再在需要提高性能的地方使用Autograph。
# 使用autograph构建静态图
@tf.function
def strjoin(x,y):
z = tf.strings.join([x,y],separator = " ")
tf.print(z) # hello world
return z
result = strjoin(tf.constant("hello"),tf.constant("world"))
print(result) # tf.Tensor(b'hello world', shape=(), dtype=string)
>>> import tensorflow as tf
>>> tf.constant(42)
<tf.Tensor: shape=(), dtype=int32, numpy=42>
>>> tf.constant([[1,2,3], [4,5,6]])
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[1, 2, 3],
[4, 5, 6]])>
>>> t = tf.constant([[1,2,3], [4,5,6]])
# 看维度
>>> t.shape
TensorShape([2, 3])
# 看数据类型
>>> t.dtype
tf.int32
# 切片
>>> t[:,1:]
<tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[2, 3],
[5, 6]])>
>>> t[..., 1, tf.newaxis]
<tf.Tensor: shape=(2, 1), dtype=int32, numpy=
array([[2],
[5]])>
# + 是对所有元素,等价于tf.add(t, 10)
# - 和 * 也支持
>>> t + 10
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[11, 12, 13],
[14, 15, 16]])>
>>> tf.square(t)
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[ 1, 4, 9],
[16, 25, 36]])>
# @ 是矩阵相乘,等价于tf.matmul()
>>> t @ tf.transpose(t)
<tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[14, 32],
[32, 77]])>
# tile是复制,第二个参数要跟t的维度对应。这个表示行维度复制两次,纵的3次
>>> tf.tile(t, [2, 3])
<tf.Tensor: shape=(4, 9), dtype=int32, numpy=
array([[1, 2, 3, 1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6, 4, 5, 6],
[1, 2, 3, 1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6, 4, 5, 6]])>
tf.reduce_mean = np.mean
tf.reduce_sum = np.sum
tf.reduce_max = np.max
rf.math.log = np.log
keras也实现了一些操作,调用时需要使用keras.backend
>>> from tensorflow import keras
>>> K = keras.backend
>>> K.square(K.transpose(t)) + 10
<tf.Tensor: shape=(3, 2), dtype=int32, numpy=
array([[11, 26],
[14, 35],
[19, 46]])>
tf和numpy的数据类型可以互转,操作也可以互通:
>>> import numpy as np
>>> a = np.array([2., 4., 5.])
>>> tf.constant(a)
<tf.Tensor: shape=(3,), dtype=float64, numpy=array([2., 4., 5.])>
# 转成numpy的np.array
>>> t.numpy()
array([[1, 2, 3],
[4, 5, 6]])
>>> tf.square(a)
<tf.Tensor: shape=(3,), dtype=float64, numpy=array([ 4., 16., 25.])>
>>> np.square(t)
array([[ 1, 4, 9],
[16, 25, 36]])
tf是不会自动转换类型的(因为自动转化可能会损失精度/效果),所以 tf.constant(2.) + tf.constant(40) 或者 tf.constant(2.) + tf.constant(40., dtype=tf.float64)都会报错:
tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a double tensor [Op:AddV2]
可以使用tf.cast转换为正确的类型:
>>> t2 = tf.constant(40., dtype=tf.float64)
>>> tf.constant(2.0) + tf.cast(t2, tf.float32)
<tf.Tensor: shape=(), dtype=float32, numpy=42.0>
tf的Variable属于可更改的对象,tensor是不能改的。Variable可以存储网络中的权重矩阵等变量,Tensor更多是存中间结果。Variable需要初始化,也会被分配内存空间,由Session管理,而Const, Zeros等创造的Tensor,是记录在Graph中的,所以没有单独的内存空间;而其他Tensor只会在程序运行中间出现。Tensor可以用的地方几乎都可以使用Variable。
>>> v = tf.Variable([[1., 2., 3.], [4., 5., 6.]])
>>> v
<tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=
array([[1., 2., 3.],
[4., 5., 6.]], dtype=float32)>
# 因为是可变的,所以能够赋值
>>> v.assign(2 * v)
<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=float32, numpy=
array([[ 2., 4., 6.],
[ 8., 10., 12.]], dtype=float32)>
>>> v[0, 1].assign(42)
<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=float32, numpy=
array([[ 2., 42., 6.],
[ 8., 10., 12.]], dtype=float32)>
>>> v[:, 2].assign([0., 1.])
<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=float32, numpy=
array([[ 2., 42., 0.],
[ 8., 10., 1.]], dtype=float32)>
>>> v.scatter_nd_update(indices=[[0,0], [1,2]], updates=[100,200])
<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=float32, numpy=
array([[100., 42., 0.],
[ 8., 10., 200.]], dtype=float32)>
不过只有很少情况需要手动更新变量。
其他数据结构还有: