tensorflow2深度学习从入门到精通第四章—TensorFlow 基础(1)

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

print(“b”,b)

在这里插入图片描述

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

4.4 创建张量


  • Numpy Array 数组和 Python List 是 Python 程序中间非常重要的数据载体容器

  • 很多数据都是通过 Python 语言将数据加载至 Array 或者 List 容器,再转换到 Tensor 类型

  • 通过TensorFlow 运算处理后导出到 Array 或者 List 容器,方便其他模块调用。

4.4.1 从 从 Numpy, List 对象 创建

通过 tf.convert_to_tensor 可以创建新 Tensor,并将保存在 Python List 对象或者 NumpyArray 对象中的数据导入到新 Tensor 中

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

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

aa=tf.convert_to_tensor(np.array([[1,2.],[3,4]]))

print(“a:”,a)

print(“aa:”,aa)

在这里插入图片描述

4.4.2 创建全 0 ,全 1 张量

b=tf.zeros([])

b1=tf.ones([])

b2=tf.ones([1])

b3=tf.zeros([1])

print(“b:”,b)

print(“b1”,b1)

print(“b2”,b2)

print(“b3”,b3)

在这里插入图片描述

写到此处忘记解释print(x)显示shape=(2,)和shape=(2,1)的区别了,下面解释一下:

  • shape=(2,)表示x是一个一位数组,数组里面有两个元素
  • shape=(2,1)表示x是一个矩阵,表示的是一个两行一列的矩阵

希望大家不要混淆

创建全 0 的矩阵:

b4=tf.zeros([2,3])

print(“b4”,b4)

在这里插入图片描述

创建全1矩阵:

b5=tf.ones([6,6])

print(“b5”,b5)

在这里插入图片描述

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

例如,创建与张量 b6 形状一样的全 0 张量:

b6=tf.ones([2,3])

b7=tf.zeros_like(b6)

print(“b7”,b7)

在这里插入图片描述

4.4.3 创建 创建 自定义数值

除了初始化为全 0,或全 1 的张量之外,有时也需要全部初始化为某个自定义数值的张量,比如将张量的数值全部初始化为-1 等。

通过 tf.fill(shape, value)可以创建全为自定义数值 value 的张量。例如,创建元素为-1的标量:

c=tf.fill([3,4],-1)

print(“C:”,c)

在这里插入图片描述

4.4.4 创建已知分布的张量

  • 正态分布(Normal Distribution,或 Gaussian Distribution)

  • 均匀分布(UniformDistribution)是最常见的分布之一,创建采样自这 2 种分布的张量非常有用

  • 比如在卷积神经网络中,卷积核张量 W 初始化为正态分布有利于网络的训练;

  • 在对抗生成网络中,隐藏变量 z 一般采样自均匀分布。

  • 通过 tf.random.normal(shape, mean=0.0, stddev=1.0)可以创建

  • 形状为 shape,均值为mean,标准差为 stddev 的正态分布𝒩(𝑛𝑓𝑏𝑜,𝑡𝑢𝑒𝑒𝑓𝑤 2 )。

下面创建一个均值为0,标准差为1的正态分布:

d=tf.random.normal([2,2])

print(“d:”,d)

在这里插入图片描述

创建均值为 1,标准差为 2 的正太分布:

d1=tf.random.normal([2,2], mean=1,stddev=2)

print(“d1”,d1)

在这里插入图片描述

通过 tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32)可以创建采样自[𝑛𝑗𝑜𝑤𝑏𝑚,𝑛𝑏𝑦𝑤𝑏𝑚]区间的均匀分布的张量。

例如创建采样自区间[0,1],shape 为[2,2]的矩阵:

d2=tf.random.uniform([2,2])

print(“d2”,d2)

在这里插入图片描述

创建采样自区间[0,10],shape 为[2,2]的矩阵:

d3=tf.random.uniform([2,2],maxval=10)

print(“d3”,d3)

在这里插入图片描述

如果需要均匀采样整形类型的数据,必须指定采样区间的最大值 maxval 参数,同时制定数据类型为 tf.int*型:

d4=tf.random.uniform([2,2],maxval=100,dtype=tf.int32)

print(“d4”,d4)

在这里插入图片描述

4.4.5 创建序列

  • 在循环计算或者对张量进行索引时,经常需要创建一段连续的整形序列

  • 可以通过tf.range()函数实现。

  • tf.range(limit, delta=1)可以创建[0,𝑚𝑗𝑛𝑗𝑢)之间,步长为 delta 的整形序列,不包含 limit 本身。例如,创建 0~9,步长为 1 的整形序列

e=tf.range(10,delta=1)

print(“e”,e)

在这里插入图片描述

创建 0~9,步长为 2 的整形序列:

e1=tf.range(10,delta=2)

print(“e1”,e1)

在这里插入图片描述

tf.range(start, limit, delta=1)可以创建[𝑡𝑢𝑏𝑠𝑢,𝑚𝑗𝑛𝑗𝑢),步长为 delta 的序列,不包含 limit本身:

e2=tf.range(1,limit=10,delta=1)

print(“e2”,e2)

在这里插入图片描述

4.5 张量的典型应用


4.5.1 标量

在 TensorFlow 中,标量最容易理解,它就是一个简单的数字,维度数为 0,shape 为[]。

标量的典型用途之一是误差值的表示、各种测量指标的表示,比如准确度(Accuracy,acc),精度(Precision)和召回率(Recall)等

以均方差误差函数为例,经过 tf.keras.losses.mse(或 tf.keras.losses.MSE)返回每个样本上的误差值,最后取误差的均值作为当前 batch 的误差,它是一个标量:

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)

在这里插入图片描述

下面解释tf.one_hot函数

  • tf.one_hot

tf.one_hot()函数是将input转化为one-hot类型数据输出,相当

将多个数值联合放在一起作为多个相同类型的向量,可用于表示各自的概率分布,通常用于分类任务中作为最后的FC层的输出,有时翻译成“独热”编码。

tensorflow的help中相关说明如下:

one_hot(indices, depth, on_value=None, off_value=None, axis=None, dtype=None, name=None)

Returns a one-hot tensor.

  • indices表示输入的多个数值,通常是矩阵形式;depth表示输出的尺寸。
  • 由于one-hot类型数据长度为depth位,其中只用一位数字表示原输入数据,这里的on_value就是这个数字,默认值为1,one-hot数据的其他位用off_value表示,默认值为0。
  • tf.one_hot()函数规定输入的元素indices从0开始,最大的元素值不能超过(depth - 1),因此能够表示depth个单位的输入。若输入的元素值超出范围,输出的编码均为 [0, 0 … 0, 0]。
  • indices = 0 对应的输出是[1, 0 … 0, 0], indices = 1 对应的输出是[0, 1 … 0, 0], 依次类推,最大可能值的输出是[0, 0 … 0, 1]。

4.5.2 向量

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

在这里插入图片描述

在这里插入图片描述

考虑 2 个输出节点的网络层,我们创建长度为 2 的偏置向量𝒃,并累加在每个输出节点

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

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

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

z = z + b # 累加偏执

print(“b:”,b)

print(“z:”,z)

在这里插入图片描述

注意:这里 shape 为[4,2]和 shape 为[2]的𝒃张量可以直接相加,这是为什么呢?

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

例如创建输入节点数为 4,输出节点数为 3 的线性层网络,那么它的偏置向量 b 的长度应为 3:

from tensorflow_core.python.layers import layers

fc = layers.Dense(3) # 创建一层wx+b,输出节点为3

通过build函数创建w,b张量,输入节点为4

fc.build(input_shape=(2, 4))

bias=fc.bias # 查看偏置

print(bias)

在这里插入图片描述

可以看到,类的偏置成员 bias 初始化为全 0,这也是偏置𝒃的默认初始化方案。

4.5.3 矩阵

矩阵也是非常常见的张量类型,比如全连接层的批量输入在这里插入图片描述

,其中b表示输入样本的个数,即 batch size, d i n d_in di​n表示输入特征的长度。

比如特征长度为 4,一共包含 2 个样本的输入可以表示为矩阵:

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

在这里插入图片描述

令全连接层的输出节点数为 3,则它的权值张量 W 的 shape 为[4,3]:

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

w = tf.ones([4, 3]) # 定义w张量

b = tf.zeros([3]) # 定义b张量

o = x @ w + b # x@w+b运算 @ 等价于tf.matmul表示矩阵相乘

print(o)

在这里插入图片描述

下面解释几行代码

  • o = x @ w + b

@ 等价于tf.matmul表示矩阵相乘

其中 X,W 张量均是矩阵。x@w+b 网络层称为线性层,在 TensorFlow 中可以通过 Dense类直接实现,Dense 层也称为全连接层。

写到此处解释一下全连接层

在这里插入图片描述

最后的两列小圆球就是两个全连接层,在最后一层卷积结束后,进行了最后一次池化,输出了20个12_12的图像,然后通过了一个全连接层变成了1_100的向量。

我们通过 Dense 类创建输入 4 个节点,输出 3 个节点的网络层,可以通过全连接层的 kernel 成员名查看其权值矩阵 W:

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

fc=layers.Dense(3) #定义全连接层的输出节点为3

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

print(“fc.kernel:”,fc.kernel)

在这里插入图片描述

4.5.4 3 维张量

三维的张量一个典型应用是表示序列信号,它的格式是

在这里插入图片描述

  • b表示序列信号的数量

  • sequence len 表示序列信号在时间维度上的采样点数

  • feature len 表示每个点的特征长度。

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

在这里插入图片描述

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

(x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=10000) # 自动加载 IMDB 电影评价数据集

x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=80) # 将句子填充、截断为等长 80 个单词的句子

print(x_train.shape)

embedding = layers.Embedding(10000, 100) # 创建词向量 Embedding 层类

out = embedding(x_train) # 将数字编码的单词转换为词向量

print(out.shape)

在这里插入图片描述

可以看到,经过 Embedding 层编码后,句子张量的 shape 变为[25000,80,100],其中 100 表示每个单词编码为长度 100 的向量

对于特征长度为 1 的序列信号,比如商品价格在 60 天内即可表示商品的价格,因此 2 件商品的价格变化趋势可以使用 shape 为[2,60]的张量表示。为了方便统一格式,也将价格变化趋势表达为 shape 为 [2,60,1]的张量,其中的 1 表示特征长度为 1

4.5.5 4 维张量

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

  • b表示输入的数量

  • h/w:特征图的宽高

  • c:特征图的通道数

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

x = tf.random.normal([4, 32, 32, 3]) # 创建32*32的彩色图片,个数为4

layer = layers.Conv2D(16, kernel_size=3) # 创建卷积神经网络

out = layer(x) # 前向计算

print(out.shape) # 计算输出大小

print(layer.kernel.shape) # 卷积核张量也是 4 维张量,可以通过 kernel 成员变量访问

在这里插入图片描述

4.6 索引与切片


通过索引与切片操作可以提取张量的部分数据,使用频率非常高。

4.6.1 索引

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

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

print(“第一张图片的数据”, x[0])

print(“第一张图片的第二行数据:”, x[0][1])

print(“第一张图片的第二行第三列的像素:”, x[0][1][2])

print(“取第 3 张图片,第 2 行,第 1 列的像素,B 通道(第 2 个通道)颜色强度值:”, x[2][1][0][1])

在这里插入图片描述

当张量的维度数较高时,使用[𝑗][𝑘]…[𝑙]的方式书写不方便,可以采用[𝑗,𝑘,…,𝑙]的方式索引,它们是等价的。

print(“取第 2 张图片,第 10 行,第 3 列:”,x[1,9,2])

在这里插入图片描述

4.6.2 切片

通过start : end:step切片方式可以方便地提取一段数据

  • start 为开始读取位置的索引

  • end 为结束读取位置的索引(不包含 end 位)

  • step 为读取步长

以 shape 为[4,32,32,3]的图片张量为例:

print(“读取第 2,3 张图片:”,x[1:3])

如 x[0,::]表示读取第 1 张图片的所有行,其中::表示在行维度上读取所有行,它等于x[0]的写法

print(“读取第 1 张图片的所有行:”, x[0,::])

我们来总结start : end:step切片的简写方式,其中从第一个元素读取时 start 可以省略,即 start=0 是可以省略,取到最后一个元素时 end 可以省略,步长为 1 时 step 可以省略,简写方式总结如表格 4.1:

在这里插入图片描述

特别地,step 可以为负数,考虑最特殊的一种例子,step = −1时,start : end:−1表示从 start 开始,逆序读取至 end 结束(不包含 end),索引号end<=start

x = tf.range(9)

print(“x:”, x)

print(“x[8:0:-1]”, x[8:0:-1])

print(“逆序取全部元素:”,x[::-1])

print(“逆序间隔采样:”,x[::-2])

在这里插入图片描述

当张量的维度数量较多时,不需要采样的维度一般用单冒号:表示采样所有元素,此时有可能出现大量的:出现

我们继续考虑[4,32,32,3]的图片张量,当需要读取 G 通道上的数据时,前面所有维度全部提取,此时需要写为:

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

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

print(x[:, :, :, 1])

在这里插入图片描述

为了避免出现像x[:,:,:,1]这样出现过多冒号的情况,可以使用⋯符号表示取多个维度上所有的数据,其中维度的数量需根据规则自动推断:当切片方式出现⋯符号时,⋯符号,左边的维度将自动对齐到最左边,⋯符号右边的维度将自动对齐到最右边,此时系统再自动推断⋯符号代表的维度数量,它的切片方式总结如表格4.2

在这里插入图片描述

比如读取第 1-2 张图片的 G/B 通道数据:

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

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

print(“读取第 1-2 张图片的 G/B 通道数据:”,x[0:2,…,1:])

在这里插入图片描述

读取最后 2 张图片:

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

print(“读取最后 2 张图片:”, x[2:,…])

在这里插入图片描述

读取 R/G 通道数据:

print(“读取最后 2 张图片:”, x[2:, …])

在这里插入图片描述

4.6.3 小结

张量的索引与切片方式多种多样,尤其是切片操作,初学者容易犯迷糊。但其实本质上切片操作只有start : end : step这一种基本形式,通过这种基本形式有目的地省略掉默认参数,从而衍生出多种简写方法,这也是很好理解的。它衍生的简写形式熟练后一看就能推测出省略掉的信息,书写起来也更方便快捷。由于深度学习一般处理的维度数在 4 维以内,⋯操作符完全可以用:符号代替,因此理解了这些就会发现张量切片操作并不复杂。

4.7 维度变换


在神经网络运算过程中,维度变换是最核心的张量操作,通过维度变换可以将数据任意地切换形式,满足不同场合的运算需求。

那么为什么需要维度变换呢?考虑线性层的批量形式:

在这里插入图片描述

其中 X 包含了 2 个样本,每个样本的特征长度为 4,X 的 shape 为[2,4]。线性层的输出为3个节点,即 W 的 shape 定义为[4,3],偏置𝒃的 shape 定义为[3]。那么X@W的运算张量shape 为[2,3],需要叠加上 shape 为[3]的偏置𝒃。

在这里插入图片描述

对于 2 个样本的输入 X,我们需要将 shape 为[3]的偏置𝒃

b = [ b 0 b 1 b 2 ] (2) b= \left[ \begin{matrix} b0 \\ b1 \\ b2 \end{matrix} \right]\tag{2} b=⎣⎡​b0b1b2​⎦⎤​(2)

按样本数量复制 1 份,变成矩阵形式𝐵 ′ :

B ′ = [ b 0 b 1 b 2 b 0 b 1 b 2 ] (2) B’= \left[ \begin{matrix} b0 & b1 & b2 \\ b0 & b1 & b2 \\ \end{matrix} \right]\tag{2} B′=[b0b0​b1b1​b2b2​](2)

通过与X′ = X@W

在这里插入图片描述

相加,此时X′与𝐵 ′ shape 相同,满足矩阵相加的数学条件:

在这里插入图片描述

通过这种方式,既满足了数学上矩阵相加需要 shape 一致的条件,又达到了给每个输入样本的输出节共享偏置的逻辑。

为了实现这种运算方式,我们将𝒃插入一个新的维度,并把它定义为 batch 维度,然后在 batch 维度将数据复制 1 份,得到变换后的B′,新的 shape 为[2,3]

4.7.1 Reshape

在介绍改变视图操作之前,我们先来认识一下张量的存储和视图(View)的概念

  • 张量的视图:就是我们理解张量的方式

比如 shape 为[2,4,4,3]的张量 A,我们从逻辑上可以理解为 2 张图片,每张图片 4 行 4 列,每个位置有 RGB 3 个通道的数据

  • 张量的存储:张量在内存上保存为一段连续的内存区域,对于同样的存储,我们可以有不同的理解方式

比如上述 A,我们可以在不改变张量的存储下,将张量 A 理解为 2 个样本,每个样本的特征为长度 48 的向量。这就是存储与视图的关系。

我们通过 tf.range()模拟生成 x 的数据:

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

x=tf.range(96)

x=tf.reshape(x,[2,4,4,3])

print(x)

在这里插入图片描述

在存储数据时,内存并不支持这个维度层级概念,只能以平铺方式按序写入内存,因此这种层级关系需要人为管理,也就是说,每个张量的存储顺序需要人为跟踪。

为了方便表达,我们把张量 shape 中相对靠左侧的维度叫做大维度,shape 中相对靠右侧的维度叫做小维度

比如[2,4,4,3]的张量中,图片数量维度与通道数量相比,图片数量叫做大维度,通道数叫做小维度。在优先写入小维度的设定下,上述张量的内存布局为

在这里插入图片描述

数据在创建时按着初始的维度顺序写入,改变张量的视图仅仅是改变了张量的理解方式,并不会改变张量的存储顺序,这在一定程度上是从计算效率考虑的,大量数据的写入操作会消耗较多的计算资源。

改变视图操作在提供便捷性的同时,也会带来很多逻辑隐患,这主要的原因是张量的视图与存储不同步造成的。

我们先介绍合法的视图变换操作,再介绍不合法的视图变换。

比如张量按着初始视图[b,h,w,c]写入的内存布局,我们改变初始视图[b,h,w,c]的理解方式,它可以有多种合法理解方式:

  • [b,h*w,c ] 张量理解为 b 张图片,h * w 个像素点,c 个通道

  • [b,h,w * c ]张量理解为 b 张图片,h 行,每行的特征长度为 w*c

  • [b,h * w * c ]张量理解为 b 张图片,每张图片的特征长度为 h_w_c

从语法上来说,视图变换只需要满足新视图的元素总量与内存区域大小相等即可,即新视图的元素数量等于b * h * w *c,而恰恰由于视图的约束很少,完全由用户定义,使得在改变视图时容易出现逻辑隐患

接下来我们继续讨论不合法的视图变换:

例如,如果定义新视图为[b,w,h,c],[b,c,h * w]或者[b,c,h,w]等时,与张量的存储顺序相悖,如果不同步更新张量的存储顺序,那么恢复出的数据将与新视图不一致,从而导致数据错乱。

为了能够正确恢复出数据,必须保证张量的存储顺序与新视图的维度顺序一致

  • 根据 图片数量 - 行 - 列 - 通道 初始视图保存的张量,按照 图片数量 - 行 - 列 - 通道(b-h-w-c)的顺序可以获得合法数据。

  • 如果按着 图片数量 - 像素 - 通道(b-h * w-c)的恢复视图,也可以获取合法数据

  • 如果按着 图片数量 - 通道 - 像素(b-c-h * w)的方式恢复数据,由于内存布局是按着 图片数量 - 行 - 列 - 通道 的顺序,视图维度与存储维度顺序相悖,提取的数据将是错乱的。

改变视图是神经网络中非常常见的操作,可以通过串联多个 Reshape 操作来实现复杂逻辑,但是在通过 Reshape 改变视图时,必须始终记住张量的存储顺序,新视图的维度顺序不能与存储顺序相悖,否则需要通过交换维度操作将存储顺序同步过来。

举个例子:

对于shape 为[4,32,32,3]的图片数据,通过 Reshape 操作将 shape 调整为[4,1024,3],此时视图的维度顺序为b-piexl-c,张量的存储顺序为[b,h,w,c]。

可以将[4,1024,3]恢复为

在这里插入图片描述

在 TensorFlow 中,可以通过张量的 ndim 和 shape 成员属性获得张量的维度数和形状:

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

x = tf.range(96)

x = tf.reshape(x, [2, 4, 4, 3])

print(“x.ndim”,x.ndim)

print(“x.shape”,x.shape)

在这里插入图片描述

通过 tf.reshape(x, new_shape),可以将张量的视图任意的合法改变:

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

x = tf.range(96)

x = tf.reshape(x, [2, 4, 4, 3])

x=tf.reshape(x, [2, -1])

print(“reshape——x.ndim”, x.ndim)

print(“reshape——x.shape”, x.shape)

print(“reshape——x”, x)

在这里插入图片描述

下面解释一下相应的参数:

  • 参数-1 :表示当前轴上长度需要根据视图总元素不变的法则自动推导,从而方便用户书写。

比如,上面的-1 可以推导为 2 ∗ 4 ∗ 4 ∗ 3 2 \frac{2*4*4*3}{2} 22∗4∗4∗3​

再次改变数据的视图为[2,4,12]:

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

x = tf.range(96)

x = tf.reshape(x, [2, 4, 12])

print(“reshape[2,4,12]——x.ndim”, x.ndim)

print(“reshape[2,4,12]——x.shape”, x.shape)

print(“reshape[2,4,12]——x”, x)

在这里插入图片描述

下面解释一下[2,4,12]的含义:这是将x的形状变为2行4列,其中每一行有12个元素

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

x = tf.range(96)

x = tf.reshape(x, [2, -1, 3])

print(“reshape[2, -1, 3]——x.ndim”, x.ndim)

print(“reshape[2, -1, 3]——x.shape”, x.shape)

print(“reshape[2, -1, 3]——x”, x)

在这里插入图片描述

下面在解释一下 [2, -1, 3]中-1的含义,它表示: 2 ∗ 4 ∗ 4 ∗ 3 2 ∗ 3 \frac{2*4*4*3}{2*3} 2∗32∗4∗4∗3​

经过上面的一系列变换视图,张量的存储顺序始终没有发生任何改变,仍然是在内存中仍然是按着初始写入的顺序0,1,2,…,95保存的。

4.7.2 增删维度

增加维度

增加一个长度为 1 的维度相当于给原有的数据增加一个新维度的概念,维度长度为 1,故数据并不需要改变,仅仅是改变数据的理解方式,因此它其实可以理解为改变视图的一种特殊方式

下面我们考虑一个具体的例子:

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

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

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

print(x)

在这里插入图片描述

通过 tf.expand_dims(x, axis)可在指定的 axis 轴前可以插入一个新的维度:

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

在这里插入图片描述

我们先对比一下插入前和插入后的数据:

  • 插入前:

在这里插入图片描述

  • 插入后:

在这里插入图片描述

可以看到,插入一个新维度后,数据的存储顺序并没有改变,依然按着5,2,3,3,1…的顺序保存,仅仅是在插入一个新的维度后,改变了数据的视图

同样的方法,我们可以在最前面插入一个新的维度,并命名为图片数量维度,长度为1,此时张量的 shape 变为[1,28,28,1]

在这里插入图片描述

注意:tf.expand_dims 的 axis

  • 为正时,表示在当前维度之前插入一个新维度

  • 为负时,表示当前维度之后插入一个新的维度

以[𝑐,ℎ, ,𝑑]张量为例,不同 axis 参数的实际插入位置如下图 4.6 所示:

在这里插入图片描述

删除维度

是增加维度的逆操作,与增加维度一样,删除维度只能删除长度为 1 的维

度,也不会改变张量的存储。继续考虑增加维度后 shape 为[1,28,28,1]的例子。

如果希望将图片数量维度删除,可以通过 tf.squeeze(x, axis)函数,axis 参数为待删除的维度的索引号,图片数量的维度轴 axis=0:

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

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

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

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

删除维度

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

print(x)

在这里插入图片描述

继续删除通道数维度,由于已经删除了图片数量维度,此时的x的shape 为[28,28,1],因此删除通道数维度时指定 axis=2:

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

print(“tf.squeeze(x,axis=2)”,x)

在这里插入图片描述

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

import tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

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

print(“未删除前:”, x.shape)

x = tf.squeeze(x)

print(“删除后:”,x.shape)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

Vue 编码基础

2.1.1. 组件规范

2.1.2. 模板中使用简单的表达式

2.1.3 指令都使用缩写形式

2.1.4 标签顺序保持一致

2.1.5 必须为 v-for 设置键值 key

2.1.6 v-show 与 v-if 选择

2.1.7 script 标签内部结构顺序

2.1.8 Vue Router 规范

Vue 项目目录规范

2.2.1 基础

2.2.2 使用 Vue-cli 脚手架

2.2.3 目录说明

2.2.4注释说明

2.2.5 其他

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

port tensorflow as tf

from tensorflow_core.python import keras

from tensorflow.keras import layers

import numpy as np

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

print(“未删除前:”, x.shape)

x = tf.squeeze(x)

print(“删除后:”,x.shape)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-E5vgeoe6-1712769010023)]
[外链图片转存中…(img-jhKjfwXs-1712769010024)]
[外链图片转存中…(img-R1F5Ke3M-1712769010024)]
[外链图片转存中…(img-8c8SIU0X-1712769010024)]
[外链图片转存中…(img-HzIzSPu8-1712769010025)]
[外链图片转存中…(img-CMZ7icqC-1712769010025)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-PKd8hMua-1712769010025)]

Vue 编码基础

2.1.1. 组件规范

2.1.2. 模板中使用简单的表达式

2.1.3 指令都使用缩写形式

2.1.4 标签顺序保持一致

2.1.5 必须为 v-for 设置键值 key

2.1.6 v-show 与 v-if 选择

2.1.7 script 标签内部结构顺序

2.1.8 Vue Router 规范

Vue 项目目录规范

2.2.1 基础

2.2.2 使用 Vue-cli 脚手架

2.2.3 目录说明

2.2.4注释说明

2.2.5 其他

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-M3NvlFDy-1712769010026)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值