TensorTlow2张量运算基础

TensorFlow 数值类型

标量(Scalar)

定义:
单个实数,如1,2,3,维度(Dimension)为0,shape为[]
创建一个标量:

a=1.2 #python标准类型
aa=tf.constant(1.2) #tf标量

向量(Vector)

定义:
n个实数得有序集合,如[1,2,3],维度为1,shape为[n]
创建一个向量:

aa=tf.constant([1,2,3]) #通过传入list类型创建tf向量

矩阵(Matrix)

定义:
m行n列实数的有序集合,如[[1,2],[3,4]],维度为2,shape[m,n]
创建一个矩阵:

aa=tf.constant([[1,2],[3,4]]) #通过传入2维list类型创建

张量(Tensor)

定义:维度大于2的数组,每个维度也称为轴(Axis),TensorFlow把标量、向量、矩阵也统称为张量
创建一个张量:

aa=tf.constant([[[1,2],[3,4]][[1,2],[3,4]]]) #通过传入多维list类型创建

其他类型

字符串类型

a=tf.constant('hello')

布尔类型

a=tf.constant(True)

类型小结

TensorFlow的数值类型都有python的基本类型与之对应,但是python的基本类型并不与tf类型相同(特别是tf的布尔类型与python的布尔类型),二者无法隐式转换,不过可以通过tf.constant()显式将python的基本类型转换为tf类型

tf类型的属性

输出一tf类型变量,可得

<tf.Tensor:id=,shape=,dtype=,numpy=>

其中,id是一个整数,标识TensorFlow中内部索引号;shape是一个集合,表示张量的形状,每个元素表示对应轴的长度;dtype表示张量的精度;numpy表示当使用张量名.numpy()方法时返回的numpy对象,方便观察张量中的具体数值。

可以通过张量名.属性名的方法查看具体某一个属性

a=tf.constant([1,2])
a.shape

精度控制

在创建张量时,可以使用dtype指定张量的保存精度:

tf.constant(12345,dtype=tf.int16)

常用的精度有:tf.int16 , tf.int32 , tf.int64 , tf.float16 , tf.float32 , tf.float64(即tf.double)

一般使用int32和float32即可满足运算需求,对精度要求比较高时(如强化学习)可选择64精度得类型

类型转换

tf类型之间可以使用,tf.cast()进行类型转换

a=tf.constant([True,False])
tf.cast(a.tf.int32) #将a的类型转换为int32

布尔类型会被转成1/0,将数值类型转换为布尔类型时,将非0数字视为True

张量

创建张量

从Numpy和List对象创建

tensorflow可以通过tf.convert_to_tensortf.constant()方法将Numpy Array与python List转化为tf张量

a=tf.convert_to_tensor([1,2])
b=tf.constant()

创建全0,全1张量

a=tf.zeros(shape) #创建全0张量
b=tf.ones(shape) #创建全1张量
#shape为list类型,元素个数即维度个数,元素大小即维度长度,为[]时表示创建标量

a=tf.zeros_like(a) #创建一个与a的shape相同的全0张量
b=tf.ones_like(b)#创建一个与shape相同的全1张量

创建自定义数值张量

a=tf.fill(shape,value) #创建一个形为shape,值全都为value的张量

创建已知分布的张量

a=tf.random.normal(shape,mean=0.0,stddev=1.0) #创建正态分布张量
b=tf.random.uniform(shape,minval=0,maxval=None,dtype=tf.float32) #创建均匀分布张量

创建序列向量

a=tf.range(limit,delta=1) #创建一个在[0,limit)之间,步长为delta的整形序列,不包括limit本身

张量索引

TensorFlow可将张量近似理解为多维数据,可以通过a[i][j]..的方式对张量中的元素进行访问,对于shape=[4,3,2,1]的张量a来说,a[0]的shape=[3,2,1]
访问第一维度为0,第二维度为1,第三维度为0,第四维度为0的元素可用a[0][1][0][0]
tf还支持[i,j,…,k]的索引方法

a[0,1,0,0]与上述方法等价

切片

tf支持切片操作,与python切片相同,a[start:end:step]可以左闭右开的、按照一定步长的提取一段数据,start,end,step可全部省略,全部省略时书写为a[::]或者a[:]表示选取该维度上的全部数据,start默认为0,end默认为张量该维度长度,step默认是1
例如:

a[0,::] #第一维度只取0,第二维度全都要
b[:,0:28:2,:] #标识第一维度都取,第二维度取[0,28),步长为2,第三维度都取

切片的自动推断:用...代替多个..,:,:,;,..,具体为:当切片方式出现...符号时,符号左边作用于第一个维度,符号右边作用于最后一个维度,中间的纬度都按[:]的规则选取,即全部都取
例如

#假设a.shape=(4,3,2,3)
a[0:2,...,1:]#标识第一个维度取0和1,第二个维度与第三个维度都取,最后一个维度取1和2

维度变换

Reshape

a=tf.reshape(x,new_shape)可改变张量x的维度数与维度大小,将改变后的结果返回。
tf张量是逻辑上的多维数组,从存储上讲,它的元素是线性存储于一段连续的内存上的数据,即物理意义上,张量的元素线性有序,所以reshape会改变张量的的shape,但是张量的储存结构与各维度的乘积不会变。
例如:

x=tf.range(96)
x=tf.reshape(x,[2,4,4,-1])#-1为自动推断,因为维度长度积不变,所以这里可自动推断出第四个维度为3
x.ndim #返回x的维度数 4
x.shape #返回x的shape [2,4,4,3]

增删维度

增删维度,都是操作长度为1的维度,从而保证维度长度总积不变。

x=tf.expand_dims(x,axis) #在x的axis轴(从0开始)前插入一个新维度
x=tf.squeeze(x,axis)#删除x的axis轴(从0开始)维度
x=tf.squeeze(x) #不指定轴,默认删除所有长度为1的维度

交换维度

x=tf.transpose(x,perm) #交换x的维度,perm内是新维度顺序List,列表内的元素值是原维度索引号,元素顺序即新顺序

例如交换x的第二和第三维度

x=tf.transpose(x,[0,2,1,3])

注意tf.transpose()并非简单的交换维度长度,而是会改变张量的储存顺序,保证旧shape的x[a][b]与新维度的x[b][a]是同一个元素

在指定维度上复制

x=tf.tile(x,multiples) # multiple接受一个list,list中的下标对应元素下标,list中元素数值大小表示倍数

tf.tile()的复制是指某一维度的内容再复制一边,增加的是维度长度,而非数值本身
例如

b=tf.constant([1,2])
b=tf.expand_dims(b,axis=o)
b.shape #shape=(1,2)
b=tf.tile(b,multiples=[2,1]) #b第一个维度复制1次,第二个纬度不复制
b.shape #shape=(2,2)

BroadCasting

BroadCasting也叫广播机制或者自动扩展机制,它在逻辑上扩展张量数据的形状,但是只在需要时才去改变实际存储,比tf.tile更高效
当进行张量的按元素运算时,如+ - * / 如果两张量形状不同,则会通过Broadcasting隐式扩充至一个公共shape进行运算
扩充扩充规则:

  1. 有效维度右对齐,认为存在数据的维度都是新shape最右边的维度
  2. 总得有一个维度和目标维度相同,要求这个相同的纬度要么原维度是的最右维度,要么原维度的右边全是长度为1的维度
  3. 维度数为1和维度数不存在都是一样的,会默认用当前数据进行扩充(复制到满足新shape为止)
  4. 1的作用是在右对齐时,起到占位作用:如原shape=(3,1),目标shape=(2,3,5),进行扩充时,将原shape的最右维度复制4次变成(3,5),再将整体赋值一次与原数据组成新的张量,即shape=(2,3,5)
    可以通过x=tf.broadcast_to(x,shape)显式的将一个现有张量扩充至新的维度
a=tf.random.normal([2,32,32,1])
b=tf.random.normal([32,32])
a+b #扩充至公共shape=(2,32,32,32)

也可以显式转换

a=tf.boradcast_to(a,[2,32,32,32])
b=tf.boradcast_to(b,[2,32,32,32])

张量的合并与分割

张量的合并有拼接与堆叠两种方式,拼接不会产生新的维度,只是在已有的维度上扩充,堆叠会产生新的维度。

拼接

可以用x=tf.concat(tensors,axis)实现拼接,tensors是一个list对象,保存需要拼接的张量,axis指需要拼接的维度,拼接的要求是非拼接维度必须一致

a=tf.random.normal([4,35,8])
b=tf.random.normaal([6,35,8])
c=tf.concat([a,b],axis=0) #合并a和b
c.shape #(10,35,8)

堆叠

堆叠是将数据在新的维度上合并,所以会创建新的维度,使用tf.stack(tensors,axis)tensors同样是指需要堆叠的张量列表,堆叠所创建的维度将会插入到axis所指定的维度之前,堆叠的条件也是非堆叠维度长度一致

a=tf.random.normal([35,8])
b=tf.random.normal([35,8])
c=tf.stack([a,b],axis=0)
c.shape #(2,35,8)

分割

分割可以将一个张量拆分成多个张量,返回序列类型。
tensors=tf.split(x,axis,num_or_size_splits)
x是待分割张量
axis是分割的维度索引号
num_or_size_splits如果接受的是单个数值,则表示平均分割为几份,如果接受的是list对象,则每个元素表示每份的长度,如果[2,4,2,2]表示分4份,每份长度分别为2,4,2,2。

张量的0元素扩充

为了让不同shape的张量进行运算,需要将其转化成相同的shape,如果不想破坏原有的结构,可以选择用0元素扩充(padding)
x=tf.pad(x,paddings)可实现上述需求,x为待填充张量,paddings一个两层嵌套的list,最外层list用于决定对哪个维度进行操作,最里层list有两个元素,第一个元素表示左边填充几个单元,第二个元素表示右边填充几个单元。
例如

x=tf.pad(x,[[0,0],[1,2]])
#即为,张量x的第一个维度不填充,第二个纬度,在做左边天一个0,右边填2个0

数学运算

按元素运算

c=tf.add(a,b) #按元素加
c=a+b #也可以直接用操作符

c=tf.subtract(a,b) #按元素减
c=a-b

c=tf.multiply(a,b) #按元素乘
c=a*b

c=tf.divide(a,b) #按元素除
c=a/b

c=a//b #按元素整除
c=a%b #按元素求模

c=tf.pow(x,a) #按元素乘方,a为指数,a小于1则为开根号
c=x**a

x=tf.square(x) #平方
x=tf.sqrt(x) #平方根

c=tf.pow(a,x) #指数运算,a为底数
c=a**x

c=tf.math.log(x) #e为底的对数运算,即lnx

张量相乘

c=tf.matmul(a,b)
c=a@b

当维度等于2时,张量相乘即矩阵相乘;维度当张量维度大于2时,将最后两个维度视作矩阵,其他维度视为batch维度,对最后两个维度进行矩阵乘法运算。

数据统计

向量范数

范数是表示向量“长度”的一种度量方法,在神经网络中,常用来表示张量的权值大小,梯度大小等。
p范数,即为所有元素的绝对值的p次方之和,再开p次根

∣ ∣ x ∣ ∣ p = ( ∑ ∣ x i ∣ p ) 1 / p ||x||_p = (\sum{|x_i|^p})^{1/p} xp=(xip)1/p

1范数为向量各元素绝对值之和
2范数为向量各元素平方和再开根号,即距原点的欧式距离
特殊的,无穷范数为向量中所有元素绝对值的最大值。
对于矩阵和张量,也可以进行范数运算,其结果等价于将矩阵、张量打平成向量后的计算结果
tensorflow中,可以使用a=tf.norm(x,ord)来计算张量x的ord范数,ord可填1,2,np.inf,分别对应1范数,2范数,无穷范数

最大值最小值、均值、和

tf.reduce_max(x,axis) #计算x张量在axis维度上的最大值
tf.reduce_min(x,axis) #计算x张量在axis维度上的最小值
tf.reduce_mean(x,axis) #计算x张量在axis维度上的平均值
tf.reduce_sum(x,axis)#计算x张量在axis上的和

tf.reduce_*返回一个张量,其统计哪个维度,哪个维度大小变为1,其他维度大小不变,即将其他维度视为批
tf.reduce_*不指定axis参数时,则返回一个标量,其值为全局的统计值

张量比较

比较两个张量是否相等,可以用tf.equal(a,b)tf.math,equal(a,b),该方法令张量按元素比较,返回true/false张量,返回结果中的true说明a、b中对应位置的元素值相等,false则反之
例如计算分类问题的准确度:

out=tf.equal(pred,y)
out=tf.cast(out,dtype=tf.float32)
correct=tf.reduce_sum(out) #correct即预测正确的数目,除以总数即为准确度

常用比较函数有

tf.math.greater(a,b) #a>b
tf.math.less(a,b) #a=b
tf.math.less_equal(a,b) #a<=b
tf.math.not_equal(a,b) #a!=b
tf.math.is_nan(a,b) # a=nan 

它们用法与equal相同,返回true/false矩阵

数据限幅

x=tf.maximum(x,a) #将张量x中大于a的元素替换成a
x=tf.minimum(x,b) #将张量x中小于b的元素替换成b
x=tf.clip_by_value(x,a,b) #合并上述操作,使数据在[a,b]之间

张量的采样

tf.gather

x=tf.gather(x,indices,axis=0)类似切片,根据indices和axis对张量x进行采样,indices接受一个list对象,list中每个元素值代表下标,axis指定indices中的下标作用的维度
例如

x=tf.gather(x,[0,2,4,6],axis=1) #返回张量,取x张量中,第二维度为0,2,4,6的数据

tf.gather_nd可以实现对坐标点的采样

x=tf.gather_nd(x,[[1,2,3],[4,5,6]])#即取出x[1,2,3]与x[4,5,6]堆叠为张量返回

tf.boolean_mask

tf.boolean_mask(x,mask,axis)通过掩码进行采样,mask是true/false向量或张量,当mask是向量时,需要指定axis,其结果类似tf.gather,取axis维度里,mask向量中true元素对应位置的数据堆叠成张量;当mask为张量时,类似tf.gather_nd,对mask中true元素对应坐标点采样。

tf.boolean_mask(x,mask=[True,False],axis=0) #x[0][0]
tf.boolean_mask(x,mask=[[True,False],[False,True]]) #x[0][0]与x[1][1]堆叠

tf.where

通过tf.where(cond,a,b)操作可以根据cond条件张量的真假,从a或b中读取数据。
其中cond是true/false张量,cond中true元素对应位置取a的对应元素,false元素对应位置,取b的对应元素,当不指定a和b时,tf.where会返回cond张量中所有true元素得索引坐标。

x=tf.where(tf.greater(a,b),a,b) #若a[...]大于b[...]取a[...],若b[...]更大,则取b[...]

本文摘录自

《TensorFlow 2.0深度学习算法实战教材》

你可能感兴趣的:(python,tensorflow,神经网络,机器学习,深度学习)