《TensorFlow2深度学习》学习笔记(一)Tensorflow基础

本系列笔记记录了学习TensorFlow2的过程,主要依据

https://github.com/dragen1860/Deep-Learning-with-TensorFlow-book

进行学习

首先需要明确TensorFlow 是一个面向于深度学习算法的科学计算库,内部数据保存在张量(Tensor)对象上,所有的运算操作(Operation, OP)也都是基于张量对象进行。

数据类型

Tensorflow中的基本数据类型有三种,包括数值型、字符串型和布尔型。

数值型】又包括:(在 TensorFlow 中间,为了表达方便,一般把标量、向量、矩阵也统称为张量,不作区分,需要根据张量的维度数和形状自行判断。 )

1.Scalar(标量)

维度数(Dimension,也叫秩)为 0,shape 为[] 

a = tf.constant(1.2) # 创建标量 

2.Vector(向量)

维度数为 1,长度不定,shape 为[𝑛] 

x = tf.constant([1,2.,3.3]) 

3.Matrix(矩阵)

维度数为 2,每个维度上的长度不定,shape 为[𝑛,𝑚] (n 行 m 列)

b = tf.constant([[1,2],[3,4]]) 

4.Tensor(张量)

维度数dim > 2的数组统称为张量。

c = tf.constant([[[1,2],[3,4]],[[5,6],[7,8]]]) (三维张量定义)

字符串】类型:

a = tf.constant('Hello, Deep Learning.') 

在 tf.strings 模块中,提供了常见的字符串型的工具函数,如拼接 join(),长度 length(),切分 split()等等,如:tf.strings.lower(a) 

布尔】类型:

 a = tf.constant(True)

数值精度

常用的精度类型有 tf.int16, tf.int32, tf.int64, tf.float16, tf.float32, tf.float64,其中 tf.float64 即为 tf.double

对于大部分深度学习算法,一般使用 tf.int32, tf.float32 可满足运算精度要求,部分对精度要求较高的算法,如强化学习,可以选择使用 tf.int64, tf.float64 精度保存张量。

通过访问张量的 dtype 成员属性可以判断张量的保存精度: a = tf.constant(np.pi, dtype=tf.float16) ,print(a.dtype

转换精度 :a = tf.cast(a,tf.float32) 

布尔型与整形之间相互转换也是合法的,是比较常见的操作,一般默认 0 表示 False,1 表示 True,在 TensorFlow 中,将非 0 数字都视为 True

待优化张量 

为了区分需要计算梯度信息的张量与不需要计算梯度信息的张量,TensorFlow 增加了 一种专门的数据类型来支持梯度信息的记录:tf.Variable。tf.Variable 类型在普通的张量类 型基础上添加了 name,trainable 等属性来支持计算图的构建。由于梯度运算会消耗大量的 计算资源,而且会自动更新相关参数,对于不需要的优化的张量,如神经网络的输入 X, 不需要通过 tf.Variable 封装;相反,对于需要计算梯度并优化的张量,如神经网络层的W 和𝒃,需要通过 tf.Variable 包裹以便 TensorFlow 跟踪相关梯度信息。 通过 tf.Variable()函数可以将普通张量转换为待优化张量。

a = tf.constant([-1, 0, 1, 2])
aa = tf.Variable(a)
aa.name, aa.trainable

'''''''''''''''''''''''''''''''
Out[20]:
('Variable:0', True)

'''''''''''''''''''''''''''''''

创建 Variable 对象是默认启用优化标志,可以设置 trainable=False 来设置张量不需要优化。 

除了通过普通张量方式创建 Variable,也可以直接创建: a = tf.Variable([[1,2],[3,4]]) 

待优化张量可看做普通张量的特殊类型,普通张量也可以通过 GradientTape.watch()方法临 时加入跟踪梯度信息的列表。 

创建张量

 1.从 Numpy, List 对象创建 

通过 tf.convert_to_tensor 可以创建新 Tensor,并将保存在 Python List 对象或者 Numpy Array 对象中的数据导入到新 Tensor 中: tf.convert_to_tensor([1,2.])  |  tf.convert_to_tensor(np.array([[1,2.],[3,4]])) 

需要注意的是,Numpy 中浮点数数组默认使用 64-Bit 精度保存数据,转换到 Tensor 类型时 精度为 tf.float64,可以在需要的时候转换为 tf.float32 类型。 

tf.constant()和 tf.convert_to_tensor()都能够自动的把 Numpy 数组或者 Python List 数据类型转化为 Tensor 类型

2. 创建全 0,全 1 张量 

考虑线性变换 𝒚 = 𝑊𝒙 +𝒃,将权值矩阵 W 初始化为全 1 矩阵,偏置 b 初始化为全 0 向量,此时线性变 化层输出𝒚 = 𝒙,是一种比较好的层初始化状态。通过 tf.zeros()和 tf.ones()即可创建任意形 状全 0 或全 1 的张量。例如,创建为 0 和为 1 的标量张量:
 tf.zeros([2,2])   |    tf.ones([3,2]) 

通过 tf.zeros_like, tf.ones_like 可以方便地新建与某个张量 shape 一致,内容全 0 或全 1 的张量  :  tf.zeros_like(a) 

tf.*_like 是一个便捷函数,可以通过 tf.zeros(a.shape)等方式实现

3.创建自定义数值张量 

tf.fill([2,2], 99) 

4.创建已知分布的张量 

正态分布(Normal Distribution,或 Gaussian Distribution)和均匀分布(Uniform Distribution)是最常见的分布之一,创建采样自这 2 种分布的张量非常有用,比如在卷积神经网络中,卷积核张量 W 初始化为正态分布有利于网络的训练;在对抗生成网络中,隐藏变量 z 一般采样自均匀分布。 

通过 tf.random.normal(shape, mean=0.0, stddev=1.0)可以创建形状为 shape,均值为 mean,标准差为 stddev 的正态分布𝒩(𝑚𝑒𝑎𝑛,𝑠𝑡𝑑𝑑𝑒𝑣2)。

通过 tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32)可以创建采样自 [𝑚𝑖𝑛𝑣𝑎𝑙,𝑚𝑎𝑥𝑣𝑎𝑙]区间的均匀分布的张量。

5. 创建序列 

 tf.range(start, limit, delta=1)可以创建[𝑠𝑡𝑎𝑟𝑡,𝑙𝑖𝑚𝑖𝑡),步长为 delta 的序列,不包含 limit 本身:tf.range(1,10,delta=2) 

张量的典型应用 

1.标量

在 TensorFlow 中,标量最容易理解,它就是一个简单的数字,维度数为 0,shape 为 []。标量的典型用途之一是误差值的表示、各种测量指标的表示,比如准确度(Accuracy, acc),精度(Precision)和召回率(Recall)等。

out = tf.random.uniform([4,10]) #随机模拟网络输出

 

y = tf.constant([2,3,2,0]) # 随机构造样本真实标签

y = tf.one_hot(y, depth=10) # one-hot 编码

loss = tf.keras.losses.mse(y, out) # 计算每个样本的 MSE

loss = tf.reduce_mean(loss) # 平均 MSE

print(loss)

2.向量 

向量是一种非常常见的数据载体,如在全连接层和卷积神经网络层中,偏置张量𝒃就 使用向量来表示。如图 所示,每个全连接层的输出节点都添加了一个偏置值,把所有 输出节点的偏置表示成向量形式:𝒃 = [𝑏1,𝑏2]𝑇。 

 

# z=wx,模拟获得激活函数的输入 z

z = tf.random.normal([4,2])

b = tf.zeros([2]) # 模拟偏置向量

z = z + b # 累加偏置(到这里 shape 为[4,2]的𝒛和 shape 为[2]的𝒃张量可以直接相加,这是为什么呢?让我们在 Broadcasting 一节为大家揭秘)

 

通过高层接口类 Dense()方式创建的网络层,张量 W 和𝒃存储在类的内部,由类自动创 建并管理。可以通过全连接层的 bias 成员变量查看偏置变量𝒃

fc = tf.keras.layers.Dense(3)# 创建一层 Wx+b,输出节点为 3   (原书表述为:fc = layers.Dense(3) # 创建一层 Wx+b,输出节点为 3,此处前提是:)

fc.build(input_shape=(2,4))# 通过 build 函数创建 W,b 张量,输入节点为 4 

fc.bias # 查看偏置

3.矩阵

矩阵也是非常常见的张量类型,比如全连接层的批量输入𝑋 = [𝑏,𝑑𝑖𝑛],其中𝑏表示输入样本的个数,即 batch size,𝑑𝑖𝑛表示输入特征的长度。比如特征长度为 4,一共包含 2 个样本的输入可以表示为矩阵: x = tf.random.normal([2,4])

可以通过全连接层的 kernel 成员名查看其权值矩阵 W: 

fc =tf.keras.layers.Dense(3) # 定义全连接层的输出节点为 3(原书表述为layers.Dense(3)

fc.build(input_shape=(2,4)) # 定义全连接层的输入节点为 4

fc.kernel

4.三维张量 

三维的张量一个典型应用是表示序列信号,它的格式是 𝑋 = [𝑏,𝑠𝑒𝑞𝑢𝑒𝑛𝑐𝑒 𝑙𝑒𝑛,𝑓𝑒𝑎𝑡𝑢𝑟𝑒 𝑙𝑒𝑛] 其中𝑏表示序列信号的数量,sequence len 表示序列信号在时间维度上的采样点数,feature len 表示每个点的特征长度。 

为了能够方便字符串被神经网络处理,一般将单词通过嵌入层(Embedding Layer)编码为固定长度的向量,比如“a”编码为某个长度 3 的向量,那么 2 个 等长(单词数为 5)的句子序列可以表示为 shape 为[2,5,3]的 3 维张量,其中 2 表示句子个数,5 表示单词数量,3 表示单词向量的长度。

5.四维张量 

我们这里只讨论 3/4 维张量,大于 4 维的张量一般应用的比较少,如在元学习(meta learning)中会采用 5 维的张量表示方法,理解方法与 3/4 维张量类似。

4 维张量在卷积神经网络中应用的非常广泛,它用于保存特征图(Feature maps)数据, 格式一般定义为

[𝑏,ℎ,w,𝑐]

其中𝑏表示输入的数量,h/w分布表示特征图的高宽,𝑐表示特征图的通道数,部分深度学习框架也会使用[𝑏,𝑐,ℎ, ]格式的特征图张量,例如 PyTorch。图片数据是特征图的一种, 对于含有 RGB 3 个通道的彩色图片,每张图片包含了 h 行 w 列像素点,每个点需要 3 个数 值表示 RGB 通道的颜色强度,因此一张图片可以表示为[h,w,3]。

维度变换

 基本的维度变换包含了改变视图 reshape,插入新维度 expand_dims,删除维度squeeze,交换维度 transpose,复制数据 tile 等

1.Reshape

tf.reshape(x,[2,-1]) #其中的参数-1 表示当前轴上长度需要根据视图总元素不变的法则自动推导,从而方便用户书写。

2.增删维度

增加维度

一张 28x28 灰度图片的数据保存为 shape 为[28,28]的张量,在末尾给张量增加一新维度,定义为为通道数维度,此时张量的 shape 变为[28,28,1]:

x = tf.random.uniform([28,28],maxval=10,dtype=tf.int32) 

x = tf.expand_dims(x,axis=0) 

删除维度

x = tf.squeeze(x, axis=0) 

如果不指定维度参数 axis,即 tf.squeeze(x),那么他会默认删除所有长度为 1 的维度

3.交换维度

x = tf.random.normal([2,32,32,3])
tf.transpose(x,perm=[0,3,1,2])

'''

shape=(2, 3, 32, 32)

'''

4.数据复制 

通过 tf.tile(b, multiples=[2,1])即可在 axis=0 维度复制 1 次,在 axis=1 维度不复制。

 Broadcasting 

 Broadcasting 也叫广播机制(自动扩展也许更合适),它是一种轻量级张量复制的手段,在逻辑上扩展张量数据的形状,但是只要在需要时才会执行实际存储复制操作。对于大部分场景,Broadcasting 机制都能通过优化手段避免实际复制数据而完成逻辑运算,从而相对于 tf.tile 函数,减少了大量计算代价。

A = tf.random.normal([32,1])
tf.broadcast_to(A, [2,32,32,3])

'''out

<tf.Tensor: id=13, shape=(2, 32, 32, 3), .....>

数学运算 

1.加减乘除 

加减乘除是最基本的数学运算,分别通过 tf.add, tf.subtract, tf.multiply, tf.divide 函数实现,TensorFlow 已经重载了+ −∗ /运算符,一般推荐直接使用运算符来完成加减乘除运算。整除和余除也是常见的运算之一,分别通过//和%运算符实现。

2.乘方 

通过 tf.pow(x, a)可以方便地完成𝑦 = 𝑥𝑎乘方运算,也可以通过运算符**实现𝑥 ∗∗ 𝑎运

对于常见的平方和平方根运算,可以使用 tf.square(x)和 tf.sqrt(x)实现。

3.指数、对数

通过 tf.pow(a, x)或者**运算符可以方便实现指数运算𝑎𝑥,特别地,对于自然指数𝑒𝑥,可以通过 tf.exp(x)实现

自然对数 log𝑒 𝑥可以通过 tf.math.log(x)实现, 如果希望计算其他底数的对数,可以根据对数的换底公式

4.矩阵相乘

通过@运算符可以方便的实现矩阵相乘,还可以通过 tf.matmul(a, b)实现

TensorFlow 中的矩阵相乘可以使用批量方式,也就是张量 a,b 的维度数可以大于 2。当张量 a,b 维度数大于 2时,TensorFlow 会选择 a,b 的最后两个维度进行矩阵相乘,前面所有的维度都视作 Batch维度。

矩阵相乘函数支持自动 Broadcasting 机制

a = tf.random.normal([4,28,32])
b = tf.random.normal([32,16])
tf.matmul(a,b)

Out: 

<tf.Tensor: id=264, shape=(4, 28, 16)........>

posted @ 2019-11-19 23:30  I_am_an_AI  阅读(4049)  评论(0编辑  收藏  举报