《28天玩转TensorFlow2》第1天:张量(tensor)——TensorFlow的基本数据结构

张量(tensor)

TensorFlow的基本数据结构

  • 按属性而言,张量可分为常量(constant)和变量(Variable)。常量就是值不会发生变化的量,而变量是开始给定初始值,但是值会发生变化的量。

  • 张量在概念上等同于数组,这一点和numpy中的array数组类似。可以用来表示数学中的标量(scalar)、向量(vector)、矩阵(matrix)以及多维数组。

# 导入tensorflow
import tensorflow as tf
print('tensorflow版本', tf.__version__, sep=':')

输出:

tensorflow版本:2.1.0

对于张量,其主要属性包括维度、值和类型(值的类型),可分别通过张量的 .shape.numpy()dtype方法获得。对于变量张量,还有名称和是否参与训练的属性,前者可通过 .name获得,后者默认是参与训练,也就是trainable=True

# 常量
ctensor = tf.constant(1024.)
print(ctensor)
print('维度:', ctensor.shape)
print('值:', ctensor.numpy())
print('类型:', ctensor.dtype)

输出:

tf.Tensor(1024.0, shape=(), dtype=float32)
维度: ()
值: 1024.0
类型: 
# 变量
vtensor = tf.Variable(2)
print(vtensor)
print('维度:', vtensor.shape)
print('值:', vtensor.numpy())
print('类型:', vtensor.dtype)
print('名称:', vtensor.name)
print('是否参与训练:', vtensor.trainable)

输出:


维度: ()
值: 2
类型: 
名称: Variable:0
是否参与训练: True

当然,这几个属性也可以在定义张量时直接给出,注意给出的维度应该可以由给出的值转化得到,给出的类型也要符合给出的值的类型,否则会出现错误。并且变量张量设定的维度要和给定的值的维度一样,在实际的机器学习操作中,变量的初始值都是根据需要的维度随机给定的,基本不会涉及这样的维度转换操作。

ctensor = tf.constant([[[3, 3]]], dtype=tf.int64, shape=(2, 1))
print(ctensor)
vtensor = tf.Variable([3, 3], dtype=tf.int64, shape=(2,), name='v_0', trainable=False)
print(vtensor)

输出:

tf.Tensor(
[[3]
 [3]], shape=(2, 1), dtype=int64)

1、维度

  • 标量
  • 向量
  • 矩阵
  • 立方体
  • 多维数组

数、列表、numpy的array形式都可以直接作为张量的值。张量的维度其实就是张量的值的维度。

# 标量,例如机器学习房价预测数据集中一个房子的价格,或者猫狗大战中一个图片的标签。
tensor_0 = tf.constant(1024000)
print('标量')
print('维度:', tensor_0.shape, '\n', '值:', tensor_0.numpy(), sep='')

输出:

标量
维度:()
值:1024000
# 向量,例如机器学习房价预测数据集中很多个房子的价格列表,或者猫狗大战中很多图片的标签集合
#  或者房价预测数据集中表示一个房子很多属性值的集合
tensor_1 = tf.constant(['cats', 'dogs', 'cats'])
print('向量')
print('维度:', tensor_1.shape, '\n', '值:', tensor_1.numpy(), sep='')

输出:

向量
维度:(3,)
值:[b'cats' b'dogs' b'cats']
# 矩阵, 例如房价预测数据集中表示很多房子属性值组成的矩阵,其中每一行表示一个房子
#  或者一个图片单通道的数字矩阵,矩阵的行数和列数就是该图片高度和宽度上的像素数
tensor_2 = tf.constant([[1, 3500, 9], [0, 6700, 12]])
print('矩阵')
print('维度:', tensor_2.shape,  '\n','值:', '\n', tensor_2.numpy(), sep='')

输出:

矩阵
维度:(2, 3)
值:
[[   1 3500    9]
 [   0 6700   12]]
# 立方体,例如单张图片的三通道的数字矩阵
import numpy as np
tensor_3 = tf.constant(np.arange(12).reshape(3, 2, 2))
print('立方体')
print('维度:', tensor_3.shape,  '\n','值:', '\n', tensor_3.numpy(), sep='')

输出:

立方体
维度:(3, 2, 2)
值:
[[[ 0  1]
  [ 2  3]]

 [[ 4  5]
  [ 6  7]]

 [[ 8  9]
  [10 11]]]
# 4维,例如卷积神经网络模型批量训练时,多张图片的三通道数字矩阵组成的数组
import numpy as np
tensor_4 = tf.constant(np.arange(48).reshape(4, 3, 2, 2))
print('多维度')
print('维度:', tensor_4.shape,  '\n', '值:', '\n', tensor_4.numpy(), sep='')

# 多维度如何看:
# 该例子中的值可以看成4个立方体
# 每个立方体包括3个矩阵
# 每个矩阵是一个2行2列的矩阵

输出:

多维度
维度:(4, 3, 2, 2)
值:
[[[[ 0  1]
   [ 2  3]]

  [[ 4  5]
   [ 6  7]]

  [[ 8  9]
   [10 11]]]


 [[[12 13]
   [14 15]]

  [[16 17]
   [18 19]]

  [[20 21]
   [22 23]]]


 [[[24 25]
   [26 27]]

  [[28 29]
   [30 31]]

  [[32 33]
   [34 35]]]


 [[[36 37]
   [38 39]]

  [[40 41]
   [42 43]]

  [[44 45]
   [46 47]]]]

2、类型

这里的类型指的是张量中值的类型,下面给出所有的数值类型:

  • 浮点型
    • tf.float16: 16-bit half-precision floating-point.
    • tf.float32: 32-bit single-precision floating-point.
    • tf.float64: 64-bit double-precision floating-point.
    • tf.bfloat16: 16-bit truncated floating-point.
  • 复数型
    • tf.complex64: 64-bit single-precision complex.
    • tf.complex128: 128-bit double-precision complex.
  • 带符号整型
    • tf.int8: 8-bit signed integer.
    • tf.int16: 16-bit signed integer.
    • tf.int32: 32-bit signed integer.
    • tf.int64: 64-bit signed integer.
  • 无符号整型
    • tf.uint8: 8-bit unsigned integer.
    • tf.uint16: 16-bit unsigned integer.
    • tf.uint32: 32-bit unsigned integer.
    • tf.uint64: 64-bit unsigned integer.
  • 布尔型
    • tf.bool: Boolean.
  • 字符串
    • tf.string: String.
  • 量化Ops整型
    • tf.qint8: Quantized 8-bit signed integer.
    • tf.qint16: Quantized 16-bit signed integer.
    • tf.qint32: Quantized 32-bit signed integer.
    • tf.quint8: Quantized 8-bit unsigned integer.
    • tf.quint16: Quantized 16-bit unsigned integer.
  • 可变资源型
    • tf.resource: Handle to a mutable resource.
  • 任意类型
    • tf.variant: Values of arbitrary types.

3、值

  • 创建值为同一个数
    • 全0:tf.zeros()
    • 全1:tf.ones()
    • 其他数:tf.fill()
# 全0
v0 = tf.Variable(tf.zeros((3, 4)), name='v0')
v0

输出:


# 全1
v1 = tf.Variable(tf.ones((1, 5)), name='v1')
v1

输出:


# 全为同一个数
vs = tf.constant(tf.fill((4, ), -2))
vs

输出:


  • 创建值满足已知分布
    • 正态分布,tf.random.normal(),该分布适用于卷积神经网络中的卷积核参数
    • 均匀分布,tf.random.uniform(),该分布适用于对抗生成网络中的隐藏参数
# 值服从均值为0,方差为1的标准正态分布
vn = tf.Variable(tf.random.normal((4, 2)), name='vn')
vn

输出:


# 值服从均值为mean,方差为stddev的正态分布
vn1 = tf.Variable(tf.random.normal((2, 6), mean=3, stddev=2), name='vn1')
vn1

输出:


# 值服从[0, 1)的均匀分布
va = tf.Variable(tf.random.uniform((2, 5)), name='va')
va

输出:


# 值服从[minval, maxval)的均匀分布
va1 = tf.constant(tf.random.uniform((2, 5), minval=2, maxval=8))
va1

输出:


# 其他形式的值
print(tf.range(12, 19))  # 序列值

输出:

tf.Tensor([12 13 14 15 16 17 18], shape=(7,), dtype=int32)
print(tf.linspace(6., 10, 5)) # 间隔线性序列值,开始的数必须为为浮点形式
# print(tf.linspace(6, 10., 5)) # 报错

输出:

tf.Tensor([ 6.  7.  8.  9. 10.], shape=(5,), dtype=float32)
d = tf.constant(tf.random.uniform((4, 3), minval=2, maxval=8))
print(tf.zeros_like(d)) # 和张量d具体相同维度的,全是0值
print(tf.ones_like(d)) # 和张量d具体相同维度的,全是1值

输出:

tf.Tensor(
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]], shape=(4, 3), dtype=float32)
tf.Tensor(
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]], shape=(4, 3), dtype=float32)
print(tf.random.truncated_normal([3, 5], mean=0.0, stddev=1.0)) # 截断正态分布,如果这个数值超过了2个标准差,那么将会被重新随机

输出:

tf.Tensor(
[[-0.73157704  0.7439553  -1.2554983  -1.0538561   0.8017968 ]
 [ 1.7552785   1.8312547  -0.8315044  -1.1748996  -1.5099645 ]
 [-1.482948   -1.0407513   0.19603679 -0.35750923  1.8271962 ]], shape=(3, 5), dtype=float32)
print(tf.random.gamma([3, 2], [0.5, -6, 9])) # Gamma分布

输出:

tf.Tensor(
[[[7.7962823e-02 1.1754944e-38 9.0213766e+00]
  [2.1591300e-01 1.1754944e-38 4.2087584e+00]]

 [[7.8149560e-06 1.1754944e-38 5.8359337e+00]
  [6.5450810e-02 1.1754944e-38 1.6036793e+01]]

 [[2.7894831e-01 1.1754944e-38 1.0213203e+01]
  [1.0374104e-01 1.1754944e-38 1.3485026e+01]]], shape=(3, 2, 3), dtype=float32)
print(tf.eye(3,3)) #单位矩阵
print(tf.linalg.diag([1,2,3])) #对角阵

输出:

tf.Tensor(
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]], shape=(3, 3), dtype=float32)
tf.Tensor(
[[1 0 0]
 [0 2 0]
 [0 0 3]], shape=(3, 3), dtype=int32)

4、变换张量维度

在机器学习模型中,很多情况下会涉及变换维度,下面介绍几种比较常用的导致维度变化的方法:

  • 维度转换:reshape

reshape 就是将原来的数据转换维度,注意前后维度中数字的乘积要保持相同。例如下面示例中的数据的维度为(24,),维度中数字的乘积为24。因为2*12=24,因此该数据可以转换为维度(2, 12)(见data0);也可以转化为维度(1, 4, 6)(见data1),因为1*4*6=24。并且维度转化前后,按照从上到下,从左到右的顺序排列数字,得到的数字序列是不变得。

# 示例张量
etensor = tf.constant(tf.range(24), dtype=tf.int32)
data = etensor.numpy()
print('维度:', data.shape)
print('示例数据:', data, sep='\n')

输出:

维度: (24,)
示例数据:
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
# 2*12=24
data0 = data.reshape(2, 12)
data0

输出:

array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])
# 1*4*6=24
data1 = data.reshape(1, 4, 6)
data1

输出:

array([[[ 0,  1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10, 11],
        [12, 13, 14, 15, 16, 17],
        [18, 19, 20, 21, 22, 23]]])
# 1*4*6=3*2*4
data2 = data1.reshape(3, 2, 4)
data2

输出:

array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]],

       [[16, 17, 18, 19],
        [20, 21, 22, 23]]])
  • 增加维度:expand_dims

在原数据的axis维度上,增加一个长度为1的维度。注意数据的顺序也没有发生变化。

# 示例张量
etensor1 = tf.constant(tf.range(5), dtype=tf.int32)
data1 = etensor1.numpy()
print('维度:', data1.shape)
print('示例数据:', data1, sep='\n')

输出:

维度: (5,)
示例数据:
[0 1 2 3 4]
data_e0 = tf.expand_dims(data1, axis=0)  # 原来的维度为(5,),在0维度上增加一个长度为1的维度,维度变为(1,5)
data_e0

输出:


data_e1 = tf.expand_dims(data1, axis=1)  # 原来的维度为(5,),在1维度上增加一个长度为1的维度,维度变为(5, 1)
data_e1

输出:


# data_e2 = tf.expand_dims(data1, axis=2)  # 运行错误,因为原来的维度(5,),没有维度2
# data_e2
data_e3 = tf.expand_dims(data_e1, axis=2) # 原来的维度为(5,1),在2维度上增加一个长度为1的维度,维度变为(5, 1, 1)
data_e3

输出:


data_e4 = tf.constant(tf.eye(3,3))
data_e5 = tf.expand_dims(data_e4, axis=1)  # 原来的维度为(3, 3),在1维度上增加一个长度为1的维度(3, 1, 3)
print(data_e4, data_e5, sep='\n')

输出:

tf.Tensor(
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]], shape=(3, 3), dtype=float32)
tf.Tensor(
[[[1. 0. 0.]]

 [[0. 1. 0.]]

 [[0. 0. 1.]]], shape=(3, 1, 3), dtype=float32)
  • 删除维度:squeeze

注意只能删除长度为1的维度,否则会报错。如果不指定维度参数axis,那么它会默认删除所有长度为1的维度。和增加维度一样,删除维度也不会导致数据序列发生变化。

data_e6 = tf.squeeze(data_e5, axis=1) # data_e5维度为(3, 1, 3),删除1维度上的维度,变为(3, 3)
data_e6

输出:


datarr = tf.constant(tf.linspace(10., 12, 4).numpy().reshape(1, -1))  
print(datarr)
dataee = tf.squeeze(datarr, axis=0)# datarr维度为(1, 4),删除0维度上的维度,变为(4,)
dataee

输出:

tf.Tensor([[10.       10.666667 11.333333 12.      ]], shape=(1, 4), dtype=float32)

datarr = tf.constant(tf.linspace(10., 12, 4).numpy().reshape(1, 1, -1, 1))  
print(datarr)
dataee = tf.squeeze(datarr) # 参数axis没有给定值,datarr维度为(1, 1, 4, 1),删除所有为1的维度,变为(4,)
dataee

输出:

tf.Tensor(
[[[[10.      ]
   [10.666667]
   [11.333333]
   [12.      ]]]], shape=(1, 1, 4, 1), dtype=float32)

  • 维度交换 transpose

前面的操作都不会影响数据序列的变化,而维度交换会导致张量中值的数据序列发生变化。

# 示例
data_init = tf.constant(tf.random.normal([3, 4]))
print(data_init)

输出:

tf.Tensor(
[[-1.1893342  -1.2580125   0.1104317  -0.20893542]
 [ 1.0300606   0.8565788   0.31826663 -1.8314791 ]
 [ 0.47821558  1.7594677   0.4862449   0.37529895]], shape=(3, 4), dtype=float32)
data_trans = tf.transpose(data_init, perm=[0, 1])  # 和原始数据一样
print(data_trans)

输出:

tf.Tensor(
[[-1.1893342  -1.2580125   0.1104317  -0.20893542]
 [ 1.0300606   0.8565788   0.31826663 -1.8314791 ]
 [ 0.47821558  1.7594677   0.4862449   0.37529895]], shape=(3, 4), dtype=float32)
data_trans = tf.transpose(data_init, perm=[1, 0])  # 此时perm的意思就是,维度1和维度0互换。维度发生变化,数据序列的顺序也发生了变化。
print(data_trans)

输出:

tf.Tensor(
[[-1.1893342   1.0300606   0.47821558]
 [-1.2580125   0.8565788   1.7594677 ]
 [ 0.1104317   0.31826663  0.4862449 ]
 [-0.20893542 -1.8314791   0.37529895]], shape=(4, 3), dtype=float32)
data_init = tf.constant(tf.random.normal([3, 4, 2]))
data_trans = tf.transpose(data_init, perm=[2, 0, 1])  # 此时维度变为(2, 3, 4),在实际应用中要注意数据序列是怎么变化的
print(data_init, data_trans, sep='\n')

输出:

tf.Tensor(
[[[ 0.0407722   1.3907919 ]
  [-0.67140126 -0.20485616]
  [ 0.28857562  0.38259038]
  [ 0.46668136 -0.9853797 ]]

 [[ 0.5792685  -0.72501785]
  [ 1.882685   -0.01522868]
  [-1.0789716   0.91662246]
  [ 0.32646975  0.77869964]]

 [[ 0.690978    0.84885603]
  [-1.0967898  -1.5899065 ]
  [ 1.7856964   2.6775556 ]
  [ 0.3747548  -0.09259129]]], shape=(3, 4, 2), dtype=float32)
tf.Tensor(
[[[ 0.0407722  -0.67140126  0.28857562  0.46668136]
  [ 0.5792685   1.882685   -1.0789716   0.32646975]
  [ 0.690978   -1.0967898   1.7856964   0.3747548 ]]

 [[ 1.3907919  -0.20485616  0.38259038 -0.9853797 ]
  [-0.72501785 -0.01522868  0.91662246  0.77869964]
  [ 0.84885603 -1.5899065   2.6775556  -0.09259129]]], shape=(2, 3, 4), dtype=float32)
  • 拼接 concat

拼接操作不会使得拼接后的张量在维度上发生越级的变化,也就是2个值为矩阵的张量拼接的结果不会出现值为立方体的张量。只是在具体的维度数字上发生了变化。 参数axis表示在哪个维度上拼接,拼接后该维度上的数字为2个张量的值的和,此时2个张量其他维度数字必须是相同的。拼接的两个张量的值的类型应该是一致的。

a = tf.constant([2., 3], dtype=tf.float64)  
b = tf.constant([4., 6, 5, 5], dtype=tf.float64)
c = tf.concat([a, b], axis=0)  
print('a的维度:%s' % a.shape, 'b的维度:%s' % b.shape, '在维度0上拼接得到',c, sep='\n')

输出:

a的维度:(2,)
b的维度:(4,)
在维度0上拼接得到
tf.Tensor([2. 3. 4. 6. 5. 5.], shape=(6,), dtype=float64)
a = tf.constant([[1., 2, 3, 4]])  
b = tf.constant([[5., 6, 7, 8], [9, 10, 11, 12]])
c = tf.concat([a, b], axis=0) 
print('a的维度:%s' % a.shape, 'b的维度:%s' % b.shape, '在维度0上拼接得到',c, sep='\n')

输出:

a的维度:(1, 4)
b的维度:(2, 4)
在维度0上拼接得到
tf.Tensor(
[[ 1.  2.  3.  4.]
 [ 5.  6.  7.  8.]
 [ 9. 10. 11. 12.]], shape=(3, 4), dtype=float32)
a = tf.constant([[1., 2, 3, 4, 5], [6, 7, 8, 9, 10]])  
b = tf.constant([[5., 6, 7, 8], [9, 10, 11, 12]])
c = tf.concat([a, b], axis=1) 
print('a的维度:%s' % a.shape, 'b的维度:%s' % b.shape, '在维度1上拼接得到',c, sep='\n')

输出:

a的维度:(2, 5)
b的维度:(2, 4)
在维度1上拼接得到
tf.Tensor(
[[ 1.  2.  3.  4.  5.  5.  6.  7.  8.]
 [ 6.  7.  8.  9. 10.  9. 10. 11. 12.]], shape=(2, 9), dtype=float32)
a = tf.constant(tf.range(24).numpy().reshape(2, 3, 4))  
b = tf.constant(tf.range(16).numpy().reshape(2, 2, 4))
c = tf.concat([a, b], axis=1) 
print('a的维度:%s' % a.shape, 'b的维度:%s' % b.shape, '在维度1上拼接得到',c, sep='\n')

输出:

a的维度:(2, 3, 4)
b的维度:(2, 2, 4)
在维度1上拼接得到
tf.Tensor(
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]
  [ 0  1  2  3]
  [ 4  5  6  7]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]
  [ 8  9 10 11]
  [12 13 14 15]]], shape=(2, 5, 4), dtype=int32)
  • 堆叠 stack

和拼接不同,堆叠会导致维度发生越级。其中axis默认为0,堆叠必须保证2个张量的维度是一致的,也就是可以在越级后的任意维度上实现堆叠。需要注意观察在某个维度上是如何完成堆叠的。

x = tf.constant([[2., 3, 4], [4, 5, 4]])  
y = tf.constant([[4., 6, 4], [5, 6, 0]])
z = tf.stack([x, y], axis=2)  
print('x的维度:%s' % x.shape, 'y的维度:%s' % y.shape, '在维度1上堆叠得到',z, sep='\n')

输出:

x的维度:(2, 3)
y的维度:(2, 3)
在维度1上堆叠得到
tf.Tensor(
[[[2. 4.]
  [3. 6.]
  [4. 4.]]

 [[4. 5.]
  [5. 6.]
  [4. 0.]]], shape=(2, 3, 2), dtype=float32)
x = tf.constant(tf.range(60).numpy().reshape(5, 3, 4))  
y = tf.constant(tf.range(100, 160).numpy().reshape(5, 3, 4))
print('x的维度:%s' % x.shape, 'y的维度:%s' % y.shape, '升级后的维度形式为(axis0,, axis1, axis2, axis3)')
for i in range(4):
    z = tf.stack([x, y], axis=i) 
    print('在维度%d上堆叠得到:%s' % (i, z.shape), sep='\n')

输出:

x的维度:(5, 3, 4) y的维度:(5, 3, 4) 升级后的维度形式为(axis0,, axis1, axis2, axis3)
在维度0上堆叠得到:(2, 5, 3, 4)
在维度1上堆叠得到:(5, 2, 3, 4)
在维度2上堆叠得到:(5, 3, 2, 4)
在维度3上堆叠得到:(5, 3, 4, 2)
  • 分割 split

tf.split(x, axis, num_or_size_splits)可以完成张量的分割操作,返回的是列表形式。其中

  • x:待分割张量
  • axis:分割的维度索引号
  • num_or_size_splits:切割方案。当num_or_size_splits 为单个数值时,如6,表示切割为6份;当分割的那个维度数值不能被该数字整除时会报错;当num_or_size_splits 为List 时,每个元素表示每份的长度,如[2, 1, 1, 2]表示切割为4 份,每份的长度分别为2,1,1,2。

该操作可用于机器学习中数据集的划分,划分为训练数据集、测试数据集、验证数据集。

x = tf.random.normal([6, 3, 2])
y = tf.split(x,axis=0,num_or_size_splits=6)
print(type(y))
print(y)

输出:


[, , , , , ]
y = tf.split(x,axis=1,num_or_size_splits=[2, 1]) # 维度1上数字为3,所以可以划分为2和1的2份。
for k in y:
    print(k)

输出:

tf.Tensor(
[[[-1.6093986  -1.1092653 ]
  [ 1.8113784  -0.88262904]]

 [[-1.5421635  -1.2405977 ]
  [ 0.23959504 -0.6319787 ]]

 [[ 2.6677513  -1.015126  ]
  [-1.4229087   0.947736  ]]

 [[ 2.2470863  -0.2636285 ]
  [-1.0136322  -0.30603406]]

 [[ 1.1257079  -0.03071762]
  [ 0.4726098  -2.1097198 ]]

 [[-1.8244735   1.3874811 ]
  [-0.745719    0.14895873]]], shape=(6, 2, 2), dtype=float32)
tf.Tensor(
[[[ 1.7928717  -0.5655064 ]]

 [[ 0.5162947   0.12239873]]

 [[ 2.3775442   0.32105592]]

 [[ 0.42018703  0.839727  ]]

 [[-0.69796985  0.1200094 ]]

 [[ 1.3949952   2.3773785 ]]], shape=(6, 1, 2), dtype=float32)
  • 分解 unstack

直接在axis上全部按长度为1的方式分割。

x = tf.random.normal([6, 3])
y = tf.unstack(x,axis=1)
for k in y:
    print(k)

输出:

tf.Tensor([-1.068996    0.78755    -1.6862708  -1.1415191   0.79779094  0.54102904], shape=(6,), dtype=float32)
tf.Tensor([-0.4848505   1.4189752   0.96606773 -2.255599    0.53675944  0.35354418], shape=(6,), dtype=float32)
tf.Tensor([-0.37911695 -0.08008205  0.24171692 -1.3721107  -1.3534086  -0.71941084], shape=(6,), dtype=float32)

点击获得更多项目源码。欢迎Follow,感谢Star!!! 扫描关注微信公众号pythonfan,获取更多。
《28天玩转TensorFlow2》第1天:张量(tensor)——TensorFlow的基本数据结构_第1张图片
《28天玩转TensorFlow2》第1天:张量(tensor)——TensorFlow的基本数据结构_第2张图片

你可能感兴趣的:(《28天玩转TensorFlow2》第1天:张量(tensor)——TensorFlow的基本数据结构)