本系列为tensorflow官方教程与文档学习笔记,结合个人理解提取其中的关键内容,便于日后复习。
张量
张量和高维数组是等价的,tensorflow有丰富的API用以生产和消费张量数据。与Numpy类型的数组不同的是,Tensors具备两个特点:
- Tensors可以通过GPU和TPU进行计算加速
- Tensors是不可变的(immutable)
1.1 张量的生成
1.1.1 通过numpy和list生成
通过tf.convert_to_tensor()
实现:
tf.convert_to_tensor(np.ones([3, 3]))
tf.convert_to_tensor([1,2,3])
Tensor与Numpy类型的数据在操作时具备自动转换特性:即numpy中的操作可以运用在Tensor上,tensorflow的操作可以运用在numpy的array上,如:
np.mean(tf.convert_to_tensor([1,2,3]))
tf.add(np.array([1,2]), np.array([1,2]))
想要显式地将Tensor转为numpy类型,使用.numpy()
方法。
1.1.2 通过相关方法生成
tf.zeros([2, 2])
:生成全零张量;tf.zeros_like([1, 2, 3])
:生成与参数形状相同的全零张量;tf.fill([2, 3], 1.5)
:生成填充的张量,第一个参数为张量形状,第二个参数为填充的数值;tf.ones([2, 2])
:生成全一张量;tf.random.normal([2, 2], mean=1, stddev=1)
:生成指定均值与方差下的随机张量;tf.random.uniform([2, 2], minval = 0, maxval = 1)
:生成指定区间的均匀分布张量;
1.2 GPU加速
很多Tensorflow中的操作都可以通过GPU加速,Tensorflow会自动决定使用CPU还是GPU,如:
x = tf.random.uniform([3, 3])
print("Is there a GPU available: "),
print(tf.config.experimental.list_physical_devices("GPU"))
print("Is the Tensor on GPU #0: "),
print(x.device.endswith('GPU:0'))
#Is there a GPU available:
#[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
#Is the Tensor on GPU #0:
#True
然而,通过tf.device
上下文管理器,可以手动决定操作是基于CPU还是GPU:
import time
def matmul(x):
start = time.time()
for loop in range(1000):
tf.matmul(x, x)
result = 1000 * (time.time() - start)
print("1000 loops: {:0.2f}ms".format(result))
# Force execution on CPU
print("On CPU:")
with tf.device("CPU:0"):
x = tf.random.uniform([1000, 1000])
assert x.device.endswith("CPU:0")
matmul(x)
# Force execution on GPU #0 if available
if tf.config.experimental.list_physical_devices("GPU"):
print("On GPU:")
with tf.device("GPU:0"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.
x = tf.random.uniform([1000, 1000])
assert x.device.endswith("GPU:0")
matmul(x)
1.3 张量的索引与切片
-
最基础的索引方式:
a = tf.random.uniform([2, 2], minval = 0, maxval = 1) a[0][0]
-
numpy风格的索引方式:
a = tf.random.uniform([2, 2], minval = 0, maxval = 1) a[0, 0]
-
使用
:
符号切片:a = tf.random.uniform([2, 2, 2], minval = 0, maxval = 1) a[1, :, :] == a[1, :]
-
使用
start:end:step
格式a = tf.range(10) a[1:10:2] #<tf.Tensor: shape=(5,), dtype=int32, numpy=array([1, 3, 5, 7, 9])>
-
使用
tf.gather()
进行灵活切片a = tf.Variable([[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15]]) # 取出第一列和第二列 print(tf.gather(a, axis=1, indices=[0,1]).numpy()) # 取出第三行 print(tf.gather(a, axis=0, indices=[2]).numpy())
1.4 张量的维度变换
-
通过
tf.reshape(tensor, shape, name=None)
改变张量形状tf.reshape([[1,2,3], [4,5,6]], [6]) # <tf.Tensor: shape=(6,), dtype=int32, numpy=array([1, 2, 3, 4, 5, 6])>
-
tf.transpose(a, perm=None, conjugate=False, name='transpose')
进行维度的变换(若不加perm
参数即为张量转置)a = tf.Variable([[1,2,3], [4,5,6]]) tf.transpose(a).numpy() # array([[1, 4], # [2, 5], # [3, 6]])
-
在指定的axis增加维度
tf.expand_dims(input, axis, name=None)
tf.expand_dims([[1,2,3], [4,5,6]], axis=1).shape # TensorShape([2, 1, 3])
-
使用
tf.squeeze(input, axis=None, name=None)
缩小张量维度(只能作用于shape=1的维度)a = tf.Variable([[1],[2]]) tf.squeeze(a).numpy() # array([1, 2])
1.5 张量的合并与分割
-
使用
tf.concat(values, axis, name='concat')
在指定的axis上进行合并(合并后维度不变)t1 = tf.eye(5) t2 = tf.eye(5) tf.concat([tf.expand_dims(t1, axis=0), tf.expand_dims(t2, axis=0)], axis=0) # <tf.Tensor: shape=(2, 5, 5), dtype=float32, numpy= # array([[[1., 0., 0., 0., 0.], # [0., 1., 0., 0., 0.], # [0., 0., 1., 0., 0.], # [0., 0., 0., 1., 0.], # [0., 0., 0., 0., 1.]], # [[1., 0., 0., 0., 0.], # [0., 1., 0., 0., 0.], # [0., 0., 1., 0., 0.], # [0., 0., 0., 1., 0.], # [0., 0., 0., 0., 1.]]], dtype=float32)>
-
使用
tf.split(value, num_or_size_splits, axis=0, num=None, name='split')
进行张量的分割(分割后维度不变)a, b = tf.split(tf.stack([t1, t2], axis=0), num_or_size_splits=2) # tf.Tensor( # [[[1. 0. 0. 0. 0.] # [0. 1. 0. 0. 0.] # [0. 0. 1. 0. 0.] # [0. 0. 0. 1. 0.] # [0. 0. 0. 0. 1.]]], shape=(1, 5, 5), dtype=float32)
-
使用
tf.stack(values, axis=0, name='stack')
在新建维度上合并(合并后维度增加)# 与上例为同样效果 t1 = tf.eye(5) t2 = tf.eye(5) tf.stack([t1, t2], axis=0)
-
通过
tf.unstack(value, num=None, axis=0, name='unstack')
进行张量的分割(分割后维度减少)# 将合并后的张量重新拆分为t1和t2 t1, t2 = tf.unstack(tf.stack([t1, t2], axis=0))