Tensorflow array ops 2019-04-22 # Tensorflow array ops 本文的目的是梳理一下 Tensorflow 实现的的各种 array 相关的 operation ## Identity 输入: 1. input: tensor类型 2. name : 字符串 tensor 的名字 输出: 和 input 一样的 tensor 文档并没有描述清楚这个操作有何用处,输入一个 tensor 然后输出一个一样的 tensor 好像什么都没做。其实不然,Identity会在计算图中添加一个新的节点因为这是一个 operation ,如果直接用 Python 的赋值运算不会在图上有任何的节点产生。下面举个例子 ``` import tensorflow as tf def python_assign(): x = tf.Variable(0.0, name="x") x_plus_1 = tf.assign_add(x, 1, name="plus") with tf.control_dependencies([x_plus_1]): y = x init = tf.initialize_all_variables() with tf.Session() as session: init.run() writer = tf.summary.FileWriter( './python_assign', session.graph) for i in range(5): print(y.eval()) def tf_identity(): x = tf.Variable(0.0, name="x") x_plus_1 = tf.assign_add(x, 1, name="plus") with tf.control_dependencies([x_plus_1]): y = tf.identity(x) init = tf.initialize_all_variables() with tf.Session() as session: writer = tf.summary.FileWriter( './tf_identity', session.graph) init.run() for i in range(5): print(y.eval()) ``` 分别运行下面这两个函数,python_assign y 的值一值都是 0 不会发生变化,对应的计算图分别如下,明显的看到会多出一个节点,Tensorflow 的机制是先构造好图然后才会计算,所以没有节点是不会每次都计算的。  (python_assgin)  (tf_identity) 在构建 graph 的时候需要把某个临时变量比如 loss 加入到图中就可以使用这个函数。 ## expand_dims 作用:给一个 tensor 插入一个维度, 可以简单理解为对 expand 前 tensorflow 的 shape 的 list 是 l = [2,3] 。 expand_dim 的作用就是在 shape 的某个位置上 insert 一个 1 对应的 tensor 也随着发生相应的变化。本质上是和 reshape 是 特殊的 reshape 的操作。 看例子. t 是一个一维向量,t2 在 0 添加一个维度,就变成了 [1,2],t3 变成[2,1 ] 。 ``` import tensorflow as tf import numpy as np t = tf.constant(np.array([1,2, 3])) t2 = tf.expand_dims(t, 0) t3 = tf.expand_dims(t, 1) with tf.Session() as session: print("t:") print(session.run(t), "shape: ",t.get_shape().as_list()) print("t_shape: ") print(t.get_shape().as_list()) print("") print("t2: ") print(session.run(t2)) print("t2_shape: ") print(t2.get_shape().as_list()) print("") print("t3:") print(session.run(t3)) print("t3_shape:") print(t3.get_shape().as_list()) ``` ## slice 在 numpy 可以对矩阵进行切片,tensorflow 也实现了类似的功能通过 slice 。 slice(input_, begin, size, name=None) 参数 input_ 是一个 被切片的 tensor, begin 是开始位置,是一个和 input_的 shape 数组一样大小的数组, size 是一个同样长度的数组,每个元素标注了每个维度需要的元素个数,只不过开始元素是从1 开始的。 换算成 numpy 的方式可以如下计算: ``` t = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], [6, 6, 6]]]) a = np.array([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], [6, 6, 6]]]) with tf.Session() as sess: print("t.shape:", t.get_shape().as_list()) print("") # a[1:2, :1, :] print(sess.run(tf.slice(t, [1, 0, 0], [1, 1, 3]))) print("") # a[1:2, 0:2, 0: 3] print(sess.run(tf.slice(t, [1, 0, 0], [1, 2, 3]))) print("") # a[1:2, 0:1, 0:3] print(sess.run(tf.slice(t, [1, 0, 0], [2, 1, 3]))) ``` 如果 t 是 三维的, a 是对应的numpy 矩阵,slice 的转换方式: a[begin[0]: begin[0] + size[0], begin[1]: begin[1]+ size[1], begin[2]:begin[2]+ size[2]] ## strided_slice 和 slice 相似,只是多了一个取元素的步长,还有就是参数换成了,begin, end, 增加了一个 stride 参数 ## stack 把多个 tensor 拼在一起,最终的输出的 Rank 会增加 给定 N 个元素的 tensor 每个 tensor 的 shape 是(A, B, C) stack 的 axis = 0 的输出维度为 (N, A, B, C) stack 的 axis=1 的输出维度为 (A, N, B, C) ``` x = tf.constant([1, 4]) y = tf.constant([2, 5]) z = tf.constant([3, 6]) tf.stack([x, y, z]) # [[1, 4], [2, 5], [3, 6]] (Pack along first dim.) tf.stack([x, y, z], axis=1) # [[1, 2, 3], [4, 5, 6]] ``` ## parallel_stack 和 stack 的区别是在计算的时候需要所有的元素都被计算出来,我们知道 tensorflow 的计算图是有依赖关系的。而且少了个 axis 参数。 ## unstack stack 的反向操作 ``` import tensorflow as tf t = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], [6, 6, 6]]]) ut = tf.unstack(t, axis=2) with tf.Session() as sess: t1 = sess.run(ut[0]) t2 = sess.run(ut[1]) t3 = sess.run(ut[2]) print('t1:') print(t1) print('t2:') print(t2) print('t3:') print(t3) ``` ## concat 拼接多个 tensor 和 stack 的区别是 tensor 的 Rank 不会发生变化 ``` t1 = [[[1, 2], [2, 3]], [[4, 4], [5, 3]]] t2 = [[[7, 4], [8, 4]], [[2, 10], [15, 11]]] tf.concat([t1, t2], -1) ``` ## boolean_mask 可以用某种条件从 tensor 中取元素 ``` tensor = [0, 1, 2, 3] mask = np.array([True, False, True, False]) boolean_mask(tensor, mask) # [0, 2] ``` 还可以指定 aixs ``` tensor = [[1, 2], [3, 4], [5, 6]] mask = np.array([True, False ]) m = tf.boolean_mask(tensor, mask, axis=1) #[[1],[3],[5]] with tf.Session() as sess: print(sess.run(m)) ``` ## sparse_mask [TODO] ## unique ## split ## transpose ## matrix_transpose ## pad ## meshgrid ## edit_distance ## gather 根据坐标获取 tensor 中的元素, ``` import tensorflow as tf x = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) idx = tf.constant([[1,2]]) y = tf.gather(x, idx ) with tf.Session(''): print(y.eval()) ``` ## reverse_sequence ## one_hot 根据 indices 产生 one_hot 的矩阵 ``` indices = [0, 1, 2] depth = 3 tf.one_hot(indices, depth) # output: [3 x 3] # [[1., 0., 0.], # [0., 1., 0.], # [0., 0., 1.]] ``` ## squeeze 删掉 tensor 的 shape 中是 1 的 元素 如 tensor t的 shape 是 (1,2,3,1) tf.squeeze(t) 的 shape 是(2,3) ## where ## reverse_sequence ## zeros ## zeros_like ## ones_like ## ones ## shape 计算 tensor 的 shape 返回一个 1-D tensor ## size 计算 tensor 中元素的个数 ## rank 计算 tensor 的 rank