美文网首页
tf2.0学习(一)——基础知识

tf2.0学习(一)——基础知识

作者: 雪糕遇上夏天 | 来源:发表于2021-04-01 14:16 被阅读0次

    类型

    通过tf.constant()可以创建3中数据类型,分别是数值、布尔、字符串

    # 标量
    tf.constant(2., dtype=tf.float16)
    
    # 向量
    tf.constant([2,3], dtype=tf.int16)
    
    # 张量 维度>2
    tf.constant([[[1,2], [3,4]], [[5,6], [7,8]]])
    

    数值精度

    TensorFlow支持一下几种数据类型,一般在数据定义的时候指定dtype来确定数据类型。

    1. tf.float16
    2. tf.float32
    3. tf.float64 也是tf.double
    4. tf.int16
    5. tf.int32
    6. tf.int64
    tf.constant([1,2,3], dtype=tf.float32)
    <tf.Tensor: shape=(3,), dtype=float32, numpy=array([1., 2., 3.], dtype=float32)>
    

    类型转换

    进行类型转换时,需要保证转换的合法性,例如从高精度转换为低精度时,可能会出现数据溢出

    a = tf.constant(123456789, dtype=tf.int32) tf.cast(a, tf.int16) # 转换为低精度整型
    
    <tf.Tensor: id=38, shape=(), dtype=int16, numpy=-13035>
    

    待优化的张量

    有些数值型数据需要计算张量,而有些不需要。TensorFlow增加了一种专门的数据类型来记录支持梯度信息的数据:tf.Variable(),包含name,trainable等属性来支持计算图的构建。

    a = tf.Variable(12, name='hahatest')
    a.name
        'hahatest:0'
    a.trainable
        True
    

    其中trainble属性用来表示当前数据是否需要被优化,默认值是True,也可设置成False来确保该数据不被优化。

    创建张量

    在TensorFlow中有多种方式创建张量:

    1. python列表
    2. numpy数组
    3. 采样自某种已知分布

    从numpy数组或python列表等容器中创建

    tf.convert_to_tensor([1, 2.])
    <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 2.], dtype=float32)>
    
    
    tf.convert_to_tensor(np.array([[1, 2.], [3,4]]))
    <tf.Tensor: shape=(2, 2), dtype=float64, numpy=
    array([[1., 2.],
           [3., 4.]])>
    

    numpy的浮点数默认是64位

    创建全0/全1张量

    通过tf.ones()/tf.zeros()来快速创建全0/全1的张量。

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

    还可一通过tf.zeros_like(),创建与某张量shape一致的全0张量。
    tf.ones_like()同理。

    自定义数值张量

    实际上除了初始化全0,全1向量外,我们偶尔也会用到其他数值的向量,TensorFlow同样提供了函数快速创建, tf.fill()。

    tf.fill([2, 3], -1)
    <tf.Tensor: shape=(2, 3), dtype=int32, numpy=
    array([[-1, -1, -1],
           [-1, -1, -1]], dtype=int32)>
    

    创建已知分布的张量

    在深度学习中创建采样自某种分布的张量非常有用。例如在卷积网络中卷积核W初始化为正太分布会有利于神经网络的训练。
    通过tf.random.nomal(shape, mean=0.0, stddev=1.0)可以创建形状为shape,均值为mean,标准差为stddev的正态分布张量。
    通过tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32)可以创建采样自 [minval, maxval)区间的均匀分布的张量。

    tf.random.uniform([2,3], minval=0, maxval=10)
    <tf.Tensor: shape=(2, 3), dtype=float32, numpy=
    array([[7.98023  , 5.8388844, 3.1424844],
           [1.8403566, 5.9672403, 4.1040087]], dtype=float32)>
    

    创建序列

    在python中可以通过range(limit)创建一个[0,limit)的列表,在TensorFlow中可以通过tf.range()实现类似的功能。

    tf.range(10)
    <tf.Tensor: shape=(10,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)>
    
    # 同下
    tf.constant([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=tf.int32)
    <tf.Tensor: shape=(10,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)>
    

    张量的应用

    前面介绍了张量的创建和部分属性,后面将介绍下不同张量的典型应用,希望能够直观的理解不同张量的无力意义和用途。

    标量

    标量是指没有维度的,简单的一个数字。可以用作各种测量指标的表示,例如loss值,准确率(Accuracy,acc),精度(Precision)和召回率(Recall)等。
    经过 tf.keras.losses.mse(或 tf.keras.losses.MSE,两者相同功能)返回每个样本上的误差值:

    out = tf.random.uniform([4, 10])
    <tf.Tensor: shape=(4, 10), dtype=float32, numpy=
    array([[0.84483695, 0.93099034, 0.5165094 , 0.36359835, 0.45167565,
            0.53549457, 0.35292995, 0.72738886, 0.86134624, 0.926762  ],
           [0.60033536, 0.4691106 , 0.15967238, 0.84809935, 0.01495636,
            0.9536545 , 0.9755062 , 0.08139396, 0.2499156 , 0.99979615],
           [0.42064786, 0.6357846 , 0.11822903, 0.13693142, 0.02659714,
            0.9410871 , 0.49241388, 0.2925855 , 0.08305645, 0.7115592 ],
           [0.33314943, 0.9935945 , 0.5966996 , 0.23640716, 0.6664102 ,
            0.09254563, 0.1807183 , 0.08634591, 0.10667193, 0.32951713]],
          dtype=float32)>
    
    y = tf.constant([2,3,1,0])
    y = tf.one_hot(y, depth=10)
    <tf.Tensor: shape=(4, 10), dtype=float32, numpy=
    array([[0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
           [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
           [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
           [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>
    
    loss = tf.keras.losses.mse(out, y)
    <tf.Tensor: shape=(4,), dtype=float32, numpy=array([0.46916837, 0.35590047, 0.20699708, 0.24566011], dtype=float32)>
    
    loss = tf.reduce_sum(loss)  # 此时loss即为标量
    <tf.Tensor: shape=(), dtype=float32, numpy=1.2777259>
    

    向量

    向量也是一种非常常用的数据,如全连接层中的偏置bias就是使用向量来表示的。

    fc = tf.keras.layers.Dense(3)
    fc.build(input_shape=(2,4))
    
    fc.bias
    <tf.Variable 'bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>
    

    全连接层中的bias就是一种典型的向量,而且是Variable的数据,即默认可优化的数据。

    矩阵

    全连接层中的W就是一种典型的矩阵,而且是Variable的数据,即默认可优化的数据。

    fc = tf.keras.layers.Dense(3)
    fc.build(input_shape=(2,4))
    
    fc.kernel
    <tf.Variable 'kernel:0' shape=(4, 3) dtype=float32, numpy=
    array([[ 0.09304154,  0.7754861 , -0.6330199 ],
           [-0.68237156,  0.8677367 , -0.6535898 ],
           [-0.33738226, -0.44297722,  0.3789575 ],
           [ 0.31737828,  0.08265066,  0.33587444]], dtype=float32)>
    

    三维张量

    三维张量的一个典型应用就是序列数据。例如信号数据、文本数据等。

    X = [batch_size, sequence_len, feature_len]

    其中sequence_len表示数据在时间维度上的采样点数,例如文本里的文字长度。
    feature_len表示每个时间步的特征长度,例如每个单词的embedding长度。

    (x_train, y_train), (x_test, y_test) = tf.keras.datasets.imdb.load_data(num_words=10000)
    # 将文本填充/截取成等长的
    x_train = tf.keras.preprocessing.sequence.pad_sequences(x_train, max_len=100)
    x_train.shape
    (25000, 100)
    
    embedding=tf.keras.layers.Embedding(10000, 80)
    out = embedding(x_train)
    out.shape
    TensorShape([25000, 100, 80])
    

    其中out即为三维张量,维度分别表示文本的数量,每个文本的单词长度,每个单词的embedding维度。

    四维张量

    神经网络中,一般将n张彩色图片用张量表示成:[n, h, w, 3],其中3维通道数量。在卷积的过程中,通道数还会发生变化。

    x = tf.random.normal([4,32,32,3])
    layer = tf.keras.layers.Conv2D(16,kernel_size=3)
    out = layer(x)
    
    x.shape
    TensorShape([4, 32, 32, 3])
    
    out.shape
    TensorShape([4, 30, 30, 16])
    

    索引与切片

    索引和切片可以很方便的提取张量的部分数据。

    索引

    在TensorFlow中支持两种索引方式:

    • 标准索引方式:[i][j]...
    • 通过都好分隔索引号的方式

    如下所示,两种方式显示结果是一样的

    x = tf.random.normal([4,32,32,3])
    x[0][1]
    x[0, 1]
    

    切片

    切片只有一种方式,即start: end: step

    x = tf.random.normal([4,32,32,3])
    
    # 取第一张图片的所有信息
    x[0,::]  
    
    # 取第一,二,三张图片
    x[0:3]
    

    维度变换

    在神经网络中,维度变换是最核心的操作之一,通过维度变换可以将数据任意的切换形式,满足不同的计算需要。
    TensorFlow中基本的维度变换函数包括:

    1. 改变视图reshape
    2. 插入新维度expand_dim
    3. 删除维度squeeze
    4. 交换维度transpose
    5. 复制数据tile等

    改变视图

    张量中存在两个很重要的概念,存储(Storage)和视图(View)。
    张量的视图就是我们理解张量的方式,比如shape为[2,4,4,3]的张量,我们从逻辑上可以理解为有两张图片,每张图片有RGB三个通道,每个通道是4x4个像素。
    张量的存储体现在张量在内存上保存为一段连续的内存区域。
    同一个存储,从不同的角度观察数据,可以产生不同的视图。这就是存储和视图的关系。视图的产生是十分灵活的,但必须是合理的。

    x = tf.range(10)
    x = tf.reshape(x, shape=[2,5])
    x
    <tf.Tensor: shape=(2, 5), dtype=int32, numpy=
    array([[0, 1, 2, 3, 4],
           [5, 6, 7, 8, 9]], dtype=int32)>
    
    x = tf.reshape(x, shape=[2,5,1])
    x
    array([[[0],
            [1],
            [2],
            [3],
            [4]],
    
           [[5],
            [6],
            [7],
            [8],
            [9]]], dtype=int32)>
    

    增删维度

    增加维度,是指增加一个长度为1的维度,也就是给原有的数据增加一个维度。通过tf.expand_dims(x, axis)实现。

    x = tf.random.uniform([28, 28])
    x.shape
    TensorShape([28, 28])
    
    x = tf.expand_dims(x, axis=2)
    x.shape
    TensorShape([28, 28, 1])
    

    当axis为正时,是指在指定的位置之前加一个维度。
    当axis为负时,是指在指定的位置之后加一个维度。

    删除维度可以理解为增加维度的逆操作。只能删除长度为1的维度,不会改变张量的存储。通过tf.squeeze(x, axis)实现。

    x.shape
    TensorShape([28, 28, 1])
    
    tf.squeeze(x, axis=2).shape
    TensorShape([28, 28])
    

    axis为要删除的维度。如果不指定axis,那么将默认删除所有长度为1的维度。

    维度交换

    改变视图,增删维度都是在保持维度顺序不变的条件下进行的,因此这些操作仅仅是改变了张量的理解方式,并没有改变张量的存储。但有时候我们需要改变张量的维度顺序,改变其存储。例如在TensorFlow中图片的默认默认存储格式是通道后行格式[b, h, w, c],但有些数据库中提供的图片是通道先行格式[b, c, h, w],需要[b, c, h, w]到[b, h, w, c]的转换。需要使用tf.transpose(x, perm),其中perm为新维度的顺序list。

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

    复制数据

    当我们对数据增加维度后,可能会希望在新的维度上复制若干份数据,来满足后续算法的格式要求。
    tf.tile(x, multiples)可以实现以上操作,其中multiples 分别指 定了每个维度上面的复制倍数。

    b = tf.constant([1, 2])
    b = tf.expand_dims(b, axis=0)
    b.shape
    TensorShape([1, 2])
    
    b = tf.tile(b, multiples=[2,1])
    b
    <tf.Tensor: shape=(2, 2), dtype=int32, numpy=
    array([[1, 2],
           [1, 2]], dtype=int32)>
    

    其中multiples=[2, 1]是说,对第0维数据复制1份,对第1维数据维持原样,即数量*1(不变)。

    Broadcasting

    Broadcasting称为广播机制(自动扩展机制),它是一种轻量级的张量复制手段,在逻辑上扩展张量数据的形式,但只有在需要时才会执行实际的存储复制操作。

    x = tf.random.uniform([2, 4])
    w = tf.random.uniform([4, 3])
    b = tf.random.normal([3])
    
    y = x @ w + b
    
    tf.broadcast_to(b, [2,3])
    <tf.Tensor: shape=(2, 3), dtype=float32, numpy=
    array([[-0.5195319 ,  2.6407762 ,  0.00587736],
           [-0.5195319 ,  2.6407762 ,  0.00587736]], dtype=float32)>
    

    上例中b的shape与x@w的shape并不相同,但却能相加,没有发生逻辑错误。因为自动调用了tf.broadcast_to(x, new_shape),将两者的shape扩展成一样的。
    注意:tf.broadcast_to()操作是自动进行的。

    数学运算

    • TensorFlow 已经重载了+、 − 、 ∗ 、/运算符,一般推荐直接使用运算符来完成 加、减、乘、除运算。
    • 整除和余除也是常见的运算之一,分别通过//和%运算符实现。
    • tf.pow(x, a) 与x ** a都为乘方运算。
    • 对于常见的平方和平方根运算,可以使用 tf.square(x)和 tf.sqrt(x)实现。
    • 对于自然指数e𝑥,可以通过 tf.exp(x)实现。
    • 自然对数loge 可以通过 tf.math.log(x)实现。

    矩阵相乘

    特别要注意一下矩阵相乘
    通过@运算符可以方便的实现矩阵相乘
    还可以通过 tf.matmul(a, b)函数实现
    根据矩阵相乘的定义,𝑨和𝑩能够矩阵相乘的条件是,𝑨的倒数第一个维度长度(列)和𝑩 的倒数第二个维度长度(行)必须相等

    相关文章

      网友评论

          本文标题:tf2.0学习(一)——基础知识

          本文链接:https://www.haomeiwen.com/subject/twgohltx.html