Model_ComFuc

扩维 降维 squeeze和unsuqeeze

squeeze(input, dim=None, out=None) 降维

函数功能:去除size为1的维度,包括行和列。当维度大于等于2时,squeeze()无作用。

input (Tensor) – 输入张量 dim (int, optional) – 如果给定,则input只会在给定维度挤压,维度的索引(从0开始) out (Tensor, optional) – 输出张量

当给定dim时,那么挤压操作只在给定维度上。注意这里dim指定的维度,其size必须为1

其中squeeze(0)代表若第一维度值为1则去除第一维度,squeeze(1)代表若第二维度值为1则去除第二维度;-1,去除最后维度值为1的维度 当不给定dim时,将输入张量形状中的1 去除并返回。

例如:如果输入是形如(A×1×B×1×C×1×D)(A×1×B×1×C×1×D),squeeze()那么输出形状就为: (A×B×C×D)(A×B×C×D) 例如:输入形状为: (A×1×B)(A×1×B), squeeze(input, 0) 将会保持张量不变(因为A≠1),只有用 squeeze(input, 1),形状会变成 (A×B)(A×B)。

注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。

unsqueeze(input, dim, out=None) 增维

功能:增加大小为1的维度,也就是返回一个新的张量,对输入的指定位置插入维度 1且必须指明维度

x = torch.unsqueeze(x, 3) # 在第3个维度上扩展 注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。

如果dim为负,则将会被转化dim+input.dim()+1


原文链接:https://blog.csdn.net/lj2048/article/details/114263912

举例:

# 如我们有一组数据3,7,2,5,6,8。我们想用一个变量来表示它,那么可以把它们放在一个数组里,相当于把这六个元素(小球)投到了一个箱子里
a= torch.tensor([3,7,2,5,6,8])
print(a.size()) # torch.Size([6])

# 我们希望这组小球里,把3,7单独放在一个箱子里,2,5放在一个箱子,6,8放在一个箱子:
a = torch.tensor([[3,7],[2,5],[6,8]])
print(a.size()) # torch.Size([3, 2])
 
# 图省略,比如最外层的箱子起名为a,里面一层的3个箱子起名a\[0\],a\[1\]和a\[2\],这三个箱子里分别有2的小球.分别对其命名 
# unsqueeze(i)表示用一个箱子把第i层的箱子都包起来;
a= a.unsqueeze(0)
print(a.size()) # torch.Size([1, 3, 2])

#  而squeeze(i)表示把第i层的箱子去掉(第i层只有一个箱子时才能用这个函数)
a = a.squeeze(0)
print(a.size()) # torch.Size([3, 2])

本文转自 https://blog.csdn.net/kuan__/article/details/109209709,如有侵权,请联系删除。

TORCH.spilt()

torch.split(tensor, split_size_or_sections, dim=0)

torch.split()作用将tensor分成块结构。

参数:

  • tesnor:input,待分输入

  • split_size_or_sections:需要切分的大小(int or list )

  • dim:切分维度

  • output:切分后块结构 <class 'tuple'>

  • 当split_size_or_sections为int时,tenor结构和split_size_or_sections,正好匹配,那么ouput就是大小相同的块结构。如果按照split_size_or_sections结构,tensor不够了,那么就把剩下的那部分做一个块处理。

  • 当split_size_or_sections 为list时,那么tensor结构会一共切分成len(list)这么多的小块,每个小块中的大小按照list中的大小决定,其中list中的数字总和应等于该维度的大小,否则会报错(注意这里与split_size_or_sections为int时的情况不同)。

split_size_or_sections为int型时

split_size_or_sections为list型时。

本文转自 https://blog.csdn.net/qq_42518956/article/details/103882579,如有侵权,请联系删除。

glob.glob()之返回路径的正反斜杆问题

拼接1 torch.cat()

1. 字面理解:torch.cat是将两个张量(tensor)拼接在一起,cat是concatenate的意思,即拼接,联系在一起。

2. 例子理解

上面给出了两个张量A和B,分别是2行3列,4行3列。即他们都是2维张量。因为只有两维,这样在用torch.cat拼接的时候就有两种拼接方式:按行拼接和按列拼接。即所谓的维数0和维数1.

C=torch.cat((A,B),0)就表示按维数0(行)拼接A和B,也就是竖着拼接,A上B下。此时需要注意:列数必须一致,即维数1数值要相同,这里都是3列,方能列对齐。拼接后的C的第0维是两个维数0数值和,即2+4=6.

C=torch.cat((A,B),1)就表示按维数1(列)拼接A和B,也就是横着拼接,A左B右。此时需要注意:行数必须一致,即维数0数值要相同,这里都是2行,方能行对齐。拼接后的C的第1维是两个维数1数值和,即3+4=7.

从2维例子可以看出,使用torch.cat((A,B),dim)时,除拼接维数dim数值可不同外其余维数数值需相同,方能对齐。

3.实例

在深度学习处理图像时,常用的有3通道的RGB彩色图像及单通道的灰度图。张量size为cxhxw,即通道数x图像高度x图像宽度。在用torch.cat拼接两张图像时一般要求图像大小一致而通道数可不一致,即h和w同,c可不同。当然实际有3种拼接方式,另两种好像不常见。比如经典网络结构:U-Net

里面用到4次torch.cat,其中copy and crop操作就是通过torch.cat来实现的。可以看到通过上采样(up-conv 2x2)将原始图像h和w变为原来2倍,再和左边直接copy过来的同样h,w的图像拼接。这样做,可以有效利用原始结构信息。

4.总结

使用torch.cat((A,B),dim)时,除拼接维数dim数值可不同外其余维数数值需相同,方能对齐。

本文转自 https://blog.csdn.net/qq_39709535/article/details/80803003,如有侵权,请联系删除。

拼接2 torch.stack

  • 先用图示讲讲 torch.cat() 是在原先维度上进行拼接

我们用图+代码来举例

在这里插入图片描述
在这里插入图片描述
pic

注意:对于cat拼接张量,==维度数量 (不是维度上的量)必须相同==;==进行拼接的维度的尺寸可以不同,但是其它维度的尺寸必须相同==。【简而言之,堆积木,对上了就可以拼】

  • torch.stack() 新增一个维度

我们继续用图+代码来举例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

补充: 拼接多个向量,例如:torch.stack((x1, x2, x3, x4), 2),再上述的方法中接入需要拼接的向量就可以了

本文转自 https://blog.csdn.net/weixin_42516475/article/details/119084904,如有侵权,请联系删除。

tf.expand_dims

TensorFlow中,想要维度增加一维,可以使用tf.expand_dims(input, dim, name=None)函数。当然,我们常用tf.reshape(input, shape=[])也可以达到相同效果,但是有些时候在构建图的过程中,placeholder没有被feed具体的值,这时就会包下面的错误:TypeError: Expected binary or unicode string, got 1 在这种情况下,我们就可以考虑使用expand_dims来将维度加1。比如我自己代码中遇到的情况,在对图像维度降到二维做特定操作后,要还原成四维[batch, height, width, channels],前后各增加一维。如果用reshape,则因为上述原因报错

用下面的方法可以实现:

在最后,给出官方的例子和说明

举例:

结果:

本文转自 https://blog.csdn.net/duanlianvip/article/details/96448393,如有侵权,请联系删除。

torch.flatten()

(14条消息) torch.flatten()函数_torch.flatten(x,1)_行者无疆哇的博客-CSDN博客

1)flatten(x,1)是按照x的第1个维度拼接(按照列来拼接,横向拼接); 2)flatten(x,0)是按照x的第0个维度拼接(按照行来拼接,纵向拼接); 3)有时候会遇到flatten里面有两个维度参数,flatten(x, start_dim, end_dimension),此时flatten函数执行的功能是将从start_dim到end_dim之间的所有维度值乘起来,其他的维度保持不变。例如x是一个size为[4,5,6]的tensor, flatten(x, 0, 1)的结果是一个size为[20,6]的tensor。

flatten的中文含义为“扁平化”,具体怎么理解呢?我们可以尝试这么理解,假设你的数据为1维数据,那么这个数据天然就已经扁平化了,如果是2维数据,那么扁平化就是将2维数据变为1维数据,如果是3维数据,那么就要根据你自己所选择的“扁平化程度”来进行操作,假设需要全部扁平化,那么就直接将3维数据变为1维数据,如果只需要部分扁平化,那么有一维的数据不会进行扁平操作,具体看下面的案例分析。

在这里插入图片描述

在这里插入图片描述

torch.view()

view()的原理很简单,其实就是把原先tensor中的数据进行排列,排成一行,然后根据所给的view()中的参数从一行中按顺序选择组成最终的tensor

view()可以有多个参数,这取决于你想要得到的是几维的tensor,一般设置两个参数,也是神经网络中常用的(一般在全连接之前),代表二维。

view(h,w),h代表行(想要变为几行),w代表的是列(想要变为几列)#这里所说并不严谨,只是为了更好理解,

view()的参数
作用

h

取值代表行数,当不知道要变为几行,但知道要变为几列时可取-1

w

取值代表列数,当不知道要变为几列,但知道要变为几行时可取-1

注意:元素个数要能整除行和列

下面看几个例子就理解了。 1、把原先tensor中的数据进行排列,排成一行,然后根据所给的view()中的参数从一行中按顺序选择组成最终的tensor

2、当知道要变成的tensor的行时:

2、当知道要变成的tensor的列时:

图像处理

张量存储为图片

三维张量转图片

四维张量转图片(卷积神经网络的输出,多了一个batch_size维度)

本文转自 https://blog.csdn.net/everyxing1007/article/details/126881242,如有侵权,请联系删除。

随机数Rand

torch.rand

torch.rand(*sizes, out=None) → Tensor

返回一个张量,包含了从区间[0,1)的均匀分布中抽取的一组随机数,形状由可变参数sizes 定义。

输出为:

torch.randn

torch.randn(*sizes, out=None) → Tensor

返回一个张量,包含了服从标准正态分布(均值为0,方差为 1,即高斯白噪声)中抽取一组随机数,形状由可变参数sizes定义。

参数:sizes (int…) – 整数序列,定义了输出形状;out (Tensor, optinal) - 结果张量

torch.randperm

torch.randperm(n, out=None) → LongTensor

给定参数n,返回一个从[0, n -1) 的随机整数排列

参数:n (int) – 上边界(不包含)

可以回想一下range或者arrange。他们俩是返回有序的数列并且可以设定步长,官方建议是使用函数 torch.arange()

介绍完上边的rand*函数再介绍一个torch.normal()

torch.normal()

torch.normal(means, std, out=None)

返回一个张量,包含从给定参数means,std的离散正态分布中抽取随机数

均值means是一个张量,包含每个输出元素相关的正态分布的均值。

std是一个张量,包含每个输出元素相关的正态分布的标准差。均值和标准差的形状不须匹配,但每个张量的元素个数须相同。

参数:

  • means (Tensor) – 均值

  • std (Tensor) – 标准差

  • out (Tensor) – 可选的输出张量

randn和normal的区别

虽然randn和normal都可以生成服从正态分布的随机数,但是normal可以自己设定均值和标准差。就这点区别。

torch.Tensor.uniform_()

A.uniform_(-10,20)将会把A里面的每个值都从[-10, 20]里面重新随机取一次,即在[-10, 20]的随机均匀分布里面取值并重新赋值

uniform_(),不是uniform()!以下划线结尾的是inplace方法。 什么是inplace方法:将会**==改变调用者本身值的方法==**。如a, b = torch.rand(2,2), torch.rand(2,2),如果a.add(b),那么a值不变;如果a.add_(b),a值就会变为a+b

比如:

三种都是,生成一个2×3的张量,将其中的值改为5-6之间的浮点数。

torch.rand和torch.Tensor.uniform_

这样看到话,两个都能取0-1之间的均匀分布,但是问题在于rand取不到1,uniform_可以取到1。

torch 检查

判断tensor中是否存在NAN, inf

在用torch搭建深度学习模型时,很容易在数据中存在inf与nan的情况,对应的数据类型分别时torch.inf与torch.nan。 大多数情况下,产生nan数据的原因基本上是出现了分母为0的情况,所以需要检查张量计算过程中是否有除法运算,比如softmax就有除法。

Numpy函数

numpy.tile()

numpy.tile()是个什么函数呢,说白了,就是把数组沿各个方向复制

比如 a = np.array([0,1,2]), np.tile(a,(2,1))就是把a先沿x轴(就这样称呼吧)复制1倍,即没有复制,仍然是 [0,1,2]。 再把结果沿y方向复制2倍,即最终得到

array([[0,1,2], [0,1,2]])

原文链接:https://blog.csdn.net/qq_18433441/article/details/54897250

torch的model.train()和eval()

  1. 两种模式

pytorch可以给我们提供两种方式来切换训练和评估(推断)的模式,分别是:model.train()model.eval()

一般用法是:在训练开始之前写上 model.trian() ,在测试时写上 model.eval() 。

  1. 功能

  • ==model.train()==

在使用 pytorch 构建神经网络,添加一句model.train()作用是 启用 batch normalization 和 dropout

如果模型中有BN层(Batch Normalization)和 Dropout ,需要在 训练时 添加 model.train()。

model.train() 是保证 BN 层能够用到 每一批数据 的均值和方差。

对于 Dropout,model.train() 是 随机取一部分 网络连接来训练更新参数。

  • ==model.eval()==

model.eval()的作用是 不启用 Batch Normalization 和 Dropout

如果模型中有 BN 层(Batch Normalization)和 Dropout,在 测试时 添加 model.eval()。

model.eval() 是保证 BN 层能够用 全部训练数据 的均值和方差,即测试过程中要保证 BN 层的均值和方差不变。

对于 Dropout,model.eval() 是利用到了 所有 网络连接,即不进行随机舍弃神经元。


  • 为什么测试时要用 model.eval() ?

训练完 train 样本后,生成的模型 model 要用来测试样本了。在 model(test) 之前,需要加上model.eval(),否则的话,有输入数据,即使不训练,它也会改变权值。这是 model 中含有 BN 层和 Dropout 所带来的的性质。

eval() 时,pytorch 会自动把 BN 和 DropOut 固定住,不会取平均,而是用训练好的值。 不然的话,一旦 test 的 batch_size 过小,很容易就会被 BN 层导致生成图片颜色失真极大。 eval() 在非训练的时候是需要加的,没有这句代码,一些网络层的值会发生变动,不会固定,你神经网络每一次生成的结果也是不固定的,生成质量可能好也可能不好。

也就是说,测试过程中使用model.eval(),这时神经网络会 沿用 batch normalization 的值,而并 不使用 dropout

  • 总结与对比

如果模型中有 BN 层(Batch Normalization)和 Dropout,需要在训练时添加 model.train(),在测试时添加 model.eval()。

其中 model.train() 是保证 BN 层用每一批数据的均值和方差,而 model.eval() 是保证 BN 用全部训练数据的均值和方差;

而对于 Dropout,model.train() 是随机取一部分网络连接来训练更新参数,而 model.eval() 是利用到了所有网络连接。


参考链接

本文转自 https://blog.csdn.net/weixin_44211968/article/details/123774649,如有侵权,请联系删除。

with torch.no_grad()

1.关于with

with是python中上下文管理器,简单理解,当要进行固定的进入,返回操作时,可以将对应需要的操作,放在with所需要的语句中。比如文件的写入(需要打开关闭文件)等。

以下为一个文件写入使用with的例子。

with后部分,可以将with后的语句运行,将其返回结果给到as后的变量(sh),之后的代码块对close进行操作。

2.关于with torch.no_grad():

在使用pytorch时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。而对于tensor的计算操作,默认是要进行计算图的构建的,在这种情况下,可以使用 with torch.no_grad():,强制之后的内容不进行计算图构建。

以下分别为使用和不使用的情况:

(1)使用with torch.no_grad():

运行结果:

此时的outputs没有 属性。

(2)不使用with torch.no_grad():

而对应的不使用的情况

结果如下:

可以看到,此时有grad_fn=<AddmmBackward>属性,表示,计算的结果在一计算图当中,可以进行梯度反传等操作。但是,两者计算的结果实际上是没有区别的。

简单的说:

本文转自 https://blog.csdn.net/weixin_44134757/article/details/105775027,如有侵权,请联系删除。

tf.placeholder

函数形式:

  • 为什么要用placeholder?

    Tensorflow的设计理念称之为计算流图,在编写程序时,首先构筑整个系统的graph,代码并不会直接生效,这一点和python的其他数值计算库(如Numpy等)不同,graph为静态的,类似于docker中的镜像。然后,在实际的运行时,启动一个session,程序才会真正的运行。这样做的好处就是:避免反复地切换底层程序实际运行的上下文,tensorflow帮你优化整个系统的代码。我们知道,很多python程序的底层为C语言或者其他语言,执行一行脚本,就要切换一次,是有成本的,tensorflow通过计算流图的方式,帮你优化整个session需要执行的代码,还是很有优势的。

    所以placeholder()函数是在神经网络构建graph的时候在模型中的占位,此时并没有把要输入的数据传入模型,它只会分配必要的内存。等建立session,在会话中,运行模型的时候通过feed_dict()函数向占位符喂入数据


  • 代码示例:

参考资料:https://www.jianshu.com/p/ec261a65e3c9


本文转自 https://blog.csdn.net/kdongyi/article/details/82343712,如有侵权,请联系删除。

关于SELF理解

在使用tensorFlow2搭建神经网络模型的时候,除了Sequential的方法,还有就是自己写模型class,然后初始化。自己写模型类的优势就是可以自定义层与层之间的连接关系,自定义数据流x的流向。

这是为鸢尾花数据做的一个简单基础的神经网络模型代码:

我在第一次学习用类来写这个代码的时候,有几个地方觉得很奇怪,不习惯。

1、为什么要定义 def __init__()

2、为什么要有 super(MyModel ,self).__init__()

3、为什么到处都有一个self? 又不能省略,又感觉很累赘,它到底意义何在?

原文:博文:self参数 - __ init__ ()方法 super(Net, self).__init__()是什么

原文:博主Chou_pijiang,原文链接:https://blog.csdn.net/zyh19980527/article/details/107206483

总结下来,有这样几点:

1、self参数

self指的是实例Instance本身,在Python类中规定,函数的第一个参数是实例对象本身,并且约定俗成,把其名字写为self,也就是说,类中的方法的第一个参数一定要是self,而且不能省略。 我觉得关于self有三点是很重要的: self指的是实例本身,而不是类 self可以用this替代,但是不要这么去写 类的方法中的self不可以省略

2、__ init__ ()方法

在python中创建类后,通常会创建一个 __ init__ ()方法,这个方法会在创建类的实例的时候自动执行。 __ init__ ()方法必须包含一个self参数,而且要是第一个参数

__ init__ ()方法在实例化的时候就已经自动执行了,但是如果不是 __ init__ ()方法,那肯定就只有调用才执行。如果 __ init__ ()方法中还需要传入另一个参数name,但是我们在创建Bob的实例的时候没有传入name,那么程序就会报错, 说我们少了一个__ init__ ()方法的参数,因为__ init__ ()方法是会在创建实例的过程中自动执行的,这个时候发现没有name参数,肯定就报错了。

那么什么需要在__ init__ ()方法中定义?就是当我们认为一些属性、操作是在创建实例的时候就有的时候,就应该把这个量定义在__ init__ ()方法中。我们写神经网络的代码的时候,一些网络结构的设置,也最好放在__ init__ ()方法中。

3、super(MyModel, self).__init__()

简单理解就是子类把父类的__init__()放到自己的__init__()当中,这样子类就有了父类的__init__()的那些东西。

Net类继承nn.Module,super(Net, self).__init__()就是对继承自父类nn.Module的属性进行初始化。而且是用nn.Module的初始化方法来初始化继承的属性。

子类继承了父类的所有属性和方法,父类属性自然会用父类方法来进行初始化。 当然,如果初始化的逻辑与父类的不同,不使用父类的方法,自己重新初始化也是可以的。

写神经网络模型的时候,父类Modle中还有一些属性我们不用再自己手写了,直接将其初始化就好,另外Model也是有继承的父类network.Network,这里也有一些我们不知道、不知如何自己写的属性和方法。所以最好都加上 super(MyModel,self).__init__()这样的父类初始化命令行。

参考TensorFLow官方API中Model的代码,我们来看看Model初始化__init__()中都定义了什么:https://github.com/tensorflow/tensorflow/blob/v2.5.0/tensorflow/python/module/module.py#L286-L317

本文转自 https://blog.csdn.net/eylier/article/details/118931908,如有侵权,请联系删除。

Last updated