【tensorflow】张量Tensor的操作(创建,变换和分割)

参考链接:

https://blog.csdn.net/yeshang_lady/article/details/124615743?ops_request_misc=&request_id=&biz_id=102&utm_term=tensorflow%20%E5%BC%A0%E9%87%8F&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-5-124615743.142v52pc_rank_34_queryrelevant25,201v3add_ask&spm=1018.2226.3001.4187

TF中张量的操作

import tensorflow as tf
import numpy as np
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 不显示等级2以下的提示信息,去掉tf一些烦人的输出

1 张量的创建

1.1 使用tf.constant创建张量

可以直接在tf.constant中写入数组来构建tensor,此时如果指定数据类型,就会按照指定的创建.如果不指定数据类型,会自动分配数据类型.

如果都是整数,那么dtype就是int型,如果有一个元素是浮点,那么dtype就是float型.
整形当中,默认最小的类型是int32,不会使用int16,除非额外特别指定.
int16: -32768~32767
int32:-2147483648~2147483647
int64:-9223372036854775808~9223372036854775807

单精度:float32:精确到小数点后6位,4个字节
双精度:float64:精确到小数点后15位,8个字节

tf.constant([1,2,3,4,5,6])
<tf.Tensor: shape=(6,), dtype=int32, numpy=array([1, 2, 3, 4, 5, 6], dtype=int32)>

创建的变量类型都是EagerTensor

a  = tf.constant([1,2,3,4,5,6])
type(a)
tensorflow.python.framework.ops.EagerTensor

可以通过.numpy()来访问数组

a.numpy()
array([1, 2, 3, 4, 5, 6], dtype=int32)
tf.constant([1,2,3,4,5,6],dtype=tf.int16)
<tf.Tensor: shape=(6,), dtype=int16, numpy=array([1, 2, 3, 4, 5, 6], dtype=int16)>
tf.constant([1,2,3,4,5,6.1])
<tf.Tensor: shape=(6,), dtype=float32, numpy=array([1. , 2. , 3. , 4. , 5. , 6.1], dtype=float32)>

也可以先通过numpy创建数组a,然后通过tf.constant(a)创建tensor.

a = np.array([1,2,3,4,5,6])
tf.constant(a)
<tf.Tensor: shape=(6,), dtype=int32, numpy=array([1, 2, 3, 4, 5, 6], dtype=int32)>

如果设定了shape,那么会对value进行reshape.
当value是一个常数时,会被复制填充shape
当value本身就是一个数组时,则要求元素数量必须和reshape后的数量一致,否则会报错.

tf.constant(1,shape=(2,3))
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[1, 1, 1],
       [1, 1, 1]], dtype=int32)>
tf.constant([1,2,3,4,5,6],shape=(2,3))
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[1, 2, 3],
       [4, 5, 6]], dtype=int32)>

另外,如果value是一个eager值,则没有影响,还可以计算梯度

v= tf.Variable([0.0])
u=tf.Variable([1.1])
with tf.GradientTape()  as g:
    loss = tf.constant(3*v+u)  #等效于loss = 3*v + u
g.gradient(loss,v).numpy()

array([3.], dtype=float32)

但是如果value是一个符号张量,tf.constant(value)就会报错了.

所谓的符号张量可以理解为只是声明的为tf.graph,并没有实例化.只有在图流动时才进行实例化.

with tf.compat.v1.Graph().as_default():
    i=tf.compat.v1.placeholder(shape=[None, None], dtype=tf.float32)
    t=tf.constant(i)

其他相关操作:

(1)tf.convert_to_tensor()
也可以创建tensor,但是与tf.constant有两点不同

  1. 不能使用shape指定形状
  2. 允许使用符号张量
    例如同样value i 下面的转化就不会报错.
with tf.compat.v1.Graph().as_default():
    i=tf.compat.v1.placeholder(shape=[None, None], dtype=tf.float32)
    t=tf.convert_to_tensor(i)

(2)tf.fill()可以用于创建标量构成的tensor,但是与tf.constant有很大不同:

  1. tf.fill只支持标量常数tf.constant支持任意常数
  2. tf.fill可以在运行时任意修改,因此在表示大型tensor时效率更高
  3. tf.fill并不嵌入值,所以它可以产生动态的输出尺寸
tf.fill([2,3],9.1)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[9.1, 9.1, 9.1],
       [9.1, 9.1, 9.1]], dtype=float32)>

1.2 创建特殊张量

1.2.1 创建全0,1,自定义数值张量

这种创建出来的张量内元素值都是一样的.

tf.ones创建全1张量,tf.zeros创建全0张量

默认会采用tf.float32的变量类型存储

tf.ones([2,3],dtype=tf.int32)
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[1, 1, 1],
       [1, 1, 1]], dtype=int32)>
tf.zeros([2,3])
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[0., 0., 0.],
       [0., 0., 0.]], dtype=float32)>

当然,也可以使用1.1中的constant,fill,convert_to_tensor创建变量

tf.constant(0,shape=[2,3])
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[0, 0, 0],
       [0, 0, 0]], dtype=int32)>
tf.fill((2,3),1)
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[1, 1, 1],
       [1, 1, 1]], dtype=int32)>
a = np.zeros((2,3))
tf.convert_to_tensor(a)
<tf.Tensor: shape=(2, 3), dtype=float64, numpy=
array([[0., 0., 0.],
       [0., 0., 0.]])>

1.2.2 创建符合特殊分布的张量

都是通过tf.random函数进行构建

  • 符合[min,max]的均匀分布的张量
tf.random.uniform([1,5],minval=0,maxval=5)
<tf.Tensor: shape=(1, 5), dtype=float32, numpy=
array([[4.3903494 , 2.6431446 , 2.7990234 , 0.94691813, 3.3530939 ]],
      dtype=float32)>
  • 指定均值方差的正态分布
tf.random.normal([2,2],mean=5,stddev=0.1)
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[4.9246736, 4.816348 ],
       [4.970745 , 5.017907 ]], dtype=float32)>

创建一个连续的序列,和python自带的range函数基本一致

tf.range(1,10,2)
<tf.Tensor: shape=(5,), dtype=int32, numpy=array([1, 3, 5, 7, 9], dtype=int32)>
for i in range(1,10,2):
    print(i)
1
3
5
7
9

1.3 可变张量

前面可以知道,tf.constant创建的张量是不可优化的.而tf.variable建立的变量是可以优化的.

a = tf.constant([1,2,3])
b = tf.Variable([1,2,3])
c = tf.fill([1,2],0)
i = np.zeros((2,3))
d = tf.convert_to_tensor(i)

print(type(a))
print(type(b))
print(type(c))
print(type(d))
<class 'tensorflow.python.framework.ops.EagerTensor'>
<class 'tensorflow.python.ops.resource_variable_ops.ResourceVariable'>
<class 'tensorflow.python.framework.ops.EagerTensor'>
<class 'tensorflow.python.framework.ops.EagerTensor'>

可见,只有 通过tf.Variable建立的变量才是可以用于模型训练的变量.并且tf.Variable变量有特有的属性:

print(b.name,b.trainable)
Variable:0 True

1.4 其他tf.xx_initializer()类方法

Tensorflow中有几个以initializer结尾的方法,这几个方法的使用有一些特殊,因为这些方法得到的并不是张量,而是一个可调用对象。下面以tf.random_uniform_initializer()为例进行说明。具体如下:

组合起来,就可以创建一些具有特殊分布的张量,例如下面就是创建了一个具有均匀分布的tensor变量

a = tf.random_uniform_initializer(minval=0,maxval=5) #产生均匀分布的函数
print(type(a))
print(callable(a))
<class 'tensorflow.python.ops.init_ops_v2.RandomUniform'>
True
tf.constant(a(shape=[2,3],dtype=tf.int32))
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[0, 4, 2],
       [2, 3, 3]], dtype=int32)>

2.基础操作

2.1 维度变换

  • 增加新的维度:tf.expand_dims

a = tf.random.uniform([2,3],0,10,dtype=tf.int32)
print(a)
b=tf.expand_dims(a,axis=0)
print(b)
c= tf.expand_dims(a,axis=1)
print(c)
d= tf.expand_dims(a,axis=2)
print(d)
tf.Tensor(
[[7 5 2]
 [0 4 3]], shape=(2, 3), dtype=int32)
tf.Tensor(
[[[7 5 2]
  [0 4 3]]], shape=(1, 2, 3), dtype=int32)
tf.Tensor(
[[[7 5 2]]

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

 [[0]
  [4]
  [3]]], shape=(2, 3, 1), dtype=int32)
  • 删除维度 tf.squeeze ,会自动删除tensor size=1的维度
d = tf.squeeze(b)
print(d)

tf.Tensor(
[[7 5 2]
 [0 4 3]], shape=(2, 3), dtype=int32)

上面的两种方法: tf.expand_dims和tf.squeeze都不会改变张量的存储顺序和大小,值是改变了理解方式.

  • 复制张量

tf.tile()

a = tf.constant([1,2,3,4])
b = tf.tile(a,multiples=[2])
print(b)
tf.Tensor([1 2 3 4 1 2 3 4], shape=(8,), dtype=int32)
a = tf.constant([1,2,3,4],shape=[2,2])
b = tf.tile(a,multiples=[2,2])
print(b)
tf.Tensor(
[[1 2 1 2]
 [3 4 3 4]
 [1 2 1 2]
 [3 4 3 4]], shape=(4, 4), dtype=int32)

2.2 张量的合并

  • tf.concat()拼接

下面对a和b在axis=0的维度进行拼接

a = tf.random.uniform([2,3],1,10,dtype=tf.int32)
b= tf.random.uniform([1,3],1,10,dtype=tf.int32)
c = tf.concat([a,b],axis=0)
print(tf.shape(c))
print(c.shape)
tf.Tensor([3 3], shape=(2,), dtype=int32)
(3, 3)
  • tf.stack()拼接时的对象的shape必须完全一样
a = tf.random.uniform([2,3],1,10,dtype=tf.int32)
b= tf.random.uniform([2,3],1,10,dtype=tf.int32)
c = tf.stack([a,b],axis=0)
print(a)
print(b)
print(c)
tf.Tensor(
[[3 8 7]
 [9 8 6]], shape=(2, 3), dtype=int32)
tf.Tensor(
[[3 4 6]
 [3 9 4]], shape=(2, 3), dtype=int32)
tf.Tensor(
[[[3 8 7]
  [9 8 6]]

 [[3 4 6]
  [3 9 4]]], shape=(2, 2, 3), dtype=int32)

上述过程可以用expand_dim和concat来复现:

a = tf.expand_dims(a,axis=0)
b = tf.expand_dims(b,axis=0)
c = tf.concat([a,b],axis=0)
print(c)
tf.Tensor(
[[[3 8 7]
  [9 8 6]]

 [[3 4 6]
  [3 9 4]]], shape=(2, 2, 3), dtype=int32)

2.3 张量分割

张量分割就是张量合并的逆过程

a = tf.squeeze(a) 
print(a)
tf.Tensor(
[[3 8 7]
 [9 8 6]], shape=(2, 3), dtype=int32)

通过调整axis可以指定切片的维度.

a_split_1=tf.split(a,num_or_size_splits=[1,2],axis=1)
a_split_0=tf.split(a,num_or_size_splits=[1,1],axis=0)
print(a_split_1[0])
print(a_split_1[1])
print(a_split_0[0])
print(a_split_0[1])

tf.Tensor(
[[3]
 [9]], shape=(2, 1), dtype=int32)
tf.Tensor(
[[8 7]
 [8 6]], shape=(2, 2), dtype=int32)
tf.Tensor([[3 8 7]], shape=(1, 3), dtype=int32)
tf.Tensor([[9 8 6]], shape=(1, 3), dtype=int32)

同一个axis也可以有不同的切片方式,通过调整num_or_size_splits=[1,1,1],就可以把a张量切片成3分

a_split_1=tf.split(a,num_or_size_splits=[1,1,1],axis=1)
print(a_split_1[0])
print(a_split_1[1])
print(a_split_1[2])

tf.Tensor(
[[3]
 [9]], shape=(2, 1), dtype=int32)
tf.Tensor(
[[8]
 [8]], shape=(2, 1), dtype=int32)
tf.Tensor(
[[7]
 [6]], shape=(2, 1), dtype=int32)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值