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型时
import torch
x = torch.rand(4,8,6)
y = torch.split(x,2,dim=0) #按照4这个维度去分,每大块包含2个小块
for i in y :
print(i.size())
output:
torch.Size([2, 8, 6])
torch.Size([2, 8, 6])
y = torch.split(x,3,dim=0)#按照4这个维度去分,每大块包含3个小块
for i in y:
print(i.size())
output:
torch.Size([3, 8, 6])
torch.Size([1, 8, 6])
split_size_or_sections为list型时。
import torch
x = torch.rand(4,8,6)
y = torch.split(x,[2,3,3],dim=1)
for i in y:
print(i.size())
output:
torch.Size([4, 2, 6])
torch.Size([4, 3, 6])
torch.Size([4, 3, 6])
y = torch.split(x,[2,1,3],dim=1) #2+1+3 等于6 != 8 ,报错
for i in y:
print(i.size())
output:
split_with_sizes expects split_sizes to sum exactly to 8 (input tensor's size at dimension 1), but got split_sizes=[2, 1, 3]
本文转自 https://blog.csdn.net/qq_42518956/article/details/103882579,如有侵权,请联系删除。
glob.glob()之返回路径的正反斜杆问题
import glob
li = glob.glob("E:\\datasets\\DAVIS\\ImageSets\\*\\*")
for item in li:
print(item)
# li = glob.glob("E:\datasets\DAVIS\ImageSets\*\*") 正确方式1
# E:\datasets\DAVIS\ImageSets\480p\tmp_val.txt
# E:\datasets\DAVIS\ImageSets\480p\train.txt
# li = glob.glob("E:\\datasets\\DAVIS\\ImageSets\\*\\*") 正确方式2
# E:\datasets\DAVIS\ImageSets\480p\trainval.txt
# E:\datasets\DAVIS\ImageSets\480p\val.txt
# li = glob.glob("E:/datasets/DAVIS/ImageSets/*/*")
# E:/datasets/DAVIS/ImageSets\480p\trainval.txt
# E:/datasets/DAVIS/ImageSets\480p\val.txt
# li = glob.glob(r"E:\\datasets\\DAVIS\\ImageSets\\*\\*")
# E:\\datasets\\DAVIS\\ImageSets\480p\trainval.txt
# E:\\datasets\\DAVIS\\ImageSets\480p\val.txt
拼接1 torch.cat()
1. 字面理解:torch.cat是将两个张量(tensor)拼接在一起,cat是concatenate的意思,即拼接,联系在一起。
2. 例子理解
>>> import torch
>>> A=torch.ones(2,3) #2x3的张量(矩阵)
>>> A
tensor([[ 1., 1., 1.],
[ 1., 1., 1.]])
>>> B=2*torch.ones(4,3)#4x3的张量(矩阵)
>>> B
tensor([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])
>>> C=torch.cat((A,B),0)#按维数0(行)拼接
>>> C
tensor([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])
>>> C.size()
torch.Size([6, 3])
>>> D=2*torch.ones(2,4) #2x4的张量(矩阵)
>>> C=torch.cat((A,D),1)#按维数1(列)拼接
>>> C
tensor([[ 1., 1., 1., 2., 2., 2., 2.],
[ 1., 1., 1., 2., 2., 2., 2.]])
>>> C.size()
torch.Size([2, 7])
上面给出了两个张量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() 是在原先维度上进行拼接
我们用图+代码来举例
import torch
x1 = torch.randn(1, 3)
x2 = torch.randn(1, 3)

# 在 0 维(纵向)进行拼接
torch.cat((x1, x2), 0) # size [2, 3]

# 在 1 维(横向)进行拼接
torch.cat((x1, x2), 1) # size [1, 6]

注意:对于cat拼接张量,==维度数量 (不是维度上的量)必须相同==;==进行拼接的维度的尺寸可以不同,但是其它维度的尺寸必须相同==。【简而言之,堆积木,对上了就可以拼】
torch.stack() 新增一个维度
我们继续用图+代码来举例
import torch
x1 = torch.randn(3, 4)
x2 = torch.randn(3, 4)

# 在 0 维插入一个维度,进行前后组合
torch.stack((x1, x2), 0)
# size [2, 3,4]

# 在 1 维插入一个维度
torch.stack((x1, x2), 1)
# size [3, 2,4]

# 在 2 维插入一个维度
torch.stack((x1, x2), 2)
# size [3, 4,2]

补充: 拼接多个向量,例如: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,则因为上述原因报错
one_img2 = tf.reshape(one_img, shape=[1, one_img.get_shape()[0].value, one_img.get_shape()[1].value, 1])
用下面的方法可以实现:
one_img = tf.expand_dims(one_img, 0)
one_img = tf.expand_dims(one_img, -1) #-1表示最后一维
在最后,给出官方的例子和说明
# 't' is a tensor of shape [2]
shape(expand_dims(t, 0)) ==> [1, 2]
shape(expand_dims(t, 1)) ==> [2, 1]
shape(expand_dims(t, -1)) ==> [2, 1]
# 't2' is a tensor of shape [2, 3, 5]
shape(expand_dims(t2, 0)) ==> [1, 2, 3, 5]
shape(expand_dims(t2, 2)) ==> [2, 3, 1, 5]
shape(expand_dims(t2, 3)) ==> [2, 3, 5, 1]
举例:
import tensorflow as tf
a = tf.constant([[1, 2], [3, 4], [5, 6]], dtype=tf.float32)
a0 = tf.expand_dims(a, 0)
a1 = tf.expand_dims(a, 1)
a2 = tf.expand_dims(a, 2)
with tf.Session() as sess:
print(sess.run(a))
print('------------')
print(sess.run(a0))
print('------------')
print(sess.run(a1))
print('------------')
print(sess.run(a2))
结果:
[[1. 2.]
[3. 4.]
[5. 6.]]
------------
[[[1. 2.]
[3. 4.]
[5. 6.]]]
------------
[[[1. 2.]]
[[3. 4.]]
[[5. 6.]]]
------------
[[[1.]
[2.]]
[[3.]
[4.]]
[[5.]
[6.]]]
本文转自 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维数据,如果只需要部分扁平化,那么有一维的数据不会进行扁平操作,具体看下面的案例分析。
import numpy as np
import torch
x = np.arange(27)
x = np.reshape(x, (3,3,3))
x = torch.from_numpy(x)
print('before flatten', x)
x = torch.flatten(x) # 默认扁平化程度为最高
print('after flatten', x)
# 部分扁平化
x = np.arange(27)
x = np.reshape(x, (3, 3, 3))
x = torch.from_numpy(x)
print('before flatten', x)
print(x.shape)
x = torch.flatten(x, start_dim=1, end_dim=2)
print('after flatten', x)
torch.view()
view()的原理很简单,其实就是把原先tensor中的数据进行排列,排成一行,然后根据所给的view()中的参数从一行中按顺序选择组成最终的tensor。
view()可以有多个参数,这取决于你想要得到的是几维的tensor,一般设置两个参数,也是神经网络中常用的(一般在全连接之前),代表二维。
view(h,w),h代表行(想要变为几行),w代表的是列(想要变为几列)#这里所说并不严谨,只是为了更好理解,
h
取值代表行数,当不知道要变为几行,但知道要变为几列时可取-1
w
取值代表列数,当不知道要变为几列,但知道要变为几行时可取-1
注意:元素个数要能整除行和列
下面看几个例子就理解了。 1、把原先tensor中的数据进行排列,排成一行,然后根据所给的view()中的参数从一行中按顺序选择组成最终的tensor
import torch
a=torch.Tensor([[[1,2,3],[4,5,6],[7,8,9]]])
b=torch.Tensor([1,2,3,4,5,6,7,8,9])
#结果:
torch.Size([1, 3, 3])
tensor([[[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]]])
torch.Size([9])
tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.])
#a是[1,3,3]的tensor向量:
b是[9]的tensor向量
a1 = a.view(3,-1)
b1 = b.view(3,-1)
#a1和b1的结果:
torch.Size([3, 3])
tensor([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
torch.Size([3, 3])
tensor([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
结果一样
2、当知道要变成的tensor的行时:
import torch
a=torch.Tensor([[[1,2,3],[4,5,6]]])
b=a.view(3,-1)
#a的结果:2行3列
tensor([[[1., 2., 3.],
[4., 5., 6.]]])
#b的结果:变为了3行2列
tensor([[1., 2.],
[3., 4.],
[5., 6.]])
2、当知道要变成的tensor的列时:
import torch
a=torch.Tensor([[[1,2,3],[4,5,6]]])
b=a.view(-1,1)
#a的结果:2行三列
tensor([[[1., 2., 3.],
[4., 5., 6.]]])
#b的结果:变为了6行1列
tensor([[1.],
[2.],
[3.],
[4.],
[5.],
[6.]])
图像处理
张量存储为图片
三维张量转图片
import torchvision
import torchvision.transforms as transforms
import cv2 as cv
import matplotlib.pyplot as plt
import os
import torch
# 读取图片
img = cv.imread('./1.jpg')
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
print(img.shape) # (405, 405, 3)
# 图片转张量
img_tensor = transforms.ToTensor()(img) # tensor数据格式是torch(C,H,W)
print(img_tensor.size()) # torch.Size([3, 405, 405])
## 方法1
# 用torchvision.utils.save_image()直接把张量保存成图片
input_tensor_1 = img_tensor.clone().detach().to(torch.device('cpu'))
# torchvision.utils.save_image(input_tensor_1, "out_x.jpg")
## 方法2: 转换为数组再保存
input_tensor_2 = img_tensor.cpu().numpy().transpose(1, 2, 0)
path = os.path.join('./', '_test_' + '.png')
plt.imsave(path, input_tensor_2)
四维张量转图片(卷积神经网络的输出,多了一个batch_size维度)
for (x, _) in zip(data_loader):
x, z = x.to(device), z.to(device) # x.shape = torch.Size([1, 3, 256, 256])
k = x.permute(0, 2, 3, 1)
k = k.cpu().detach().numpy()
path = os.path.join('./result/', str(epoch+1) + '_epoch' + '.jpg')
plt.imsave(path, (k[0] + 1) / 2)
本文转自 https://blog.csdn.net/everyxing1007/article/details/126881242,如有侵权,请联系删除。
随机数Rand
torch.rand
torch.rand(*sizes, out=None) → Tensor
返回一个张量,包含了从区间[0,1)的均匀分布中抽取的一组随机数,形状由可变参数sizes
定义。
print(torch.rand(3))
print(torch.rand(3,2))
输出为:
>>tensor([0.3445, 0.9567, 0.7707])
tensor([[0.7644, 0.5776],
[0.4379, 0.5460],
[0.1860, 0.2946]])
torch.randn
torch.randn(*sizes, out=None) → Tensor
返回一个张量,包含了服从标准正态分布(均值为0,方差为 1,即高斯白噪声)中抽取一组随机数,形状由可变参数sizes
定义。
参数:sizes (int…) – 整数序列,定义了输出形状;out (Tensor, optinal) - 结果张量
print(torch.randn(3))
print(torch.randn(3,2))
>>tensor([ 0.7186, -1.4286, 0.6510])
tensor([[ 1.1820, -0.4163],
[-1.2188, 1.3141],
[ 0.9691, 0.2682]])
torch.randperm
torch.randperm(n, out=None) → LongTensor
给定参数n
,返回一个从[0, n -1) 的随机整数排列。
参数:n (int) – 上边界(不包含)
print(torch.randperm(10))
>>tensor([2, 4, 8, 5, 0, 9, 6, 1, 7, 3])
可以回想一下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
比如:
a = torch.Tensor(2,3).uniform_(5,6)
b = torch.zeros(2,3).uniform_(5,6)
c = torch.ones(2,3).uniform_(5,6)
print(a,b,c,sep="\n")
三种都是,生成一个2×3的张量,将其中的值改为5-6之间的浮点数。
>>
tensor([[5.5388, 5.6403, 5.2553],
[5.0379, 5.8440, 5.0334]])
tensor([[5.0001, 5.2357, 5.4277],
[5.9316, 5.4877, 5.3986]])
tensor([[5.4156, 5.6199, 5.4743],
[5.4273, 5.4571, 5.6763]])
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就有除法。
torch.isnan(tensor).any() # 有一个True(非NAN)则都为 True
torch.isnan(tensor).all() # 有一个 NAN 则为 False
# 与之类似,用tensor.isinf()方法也可以查看有没有无穷数在张量里。
torch.isinf(tensor).any()
torch.isinf(tensor).all()
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]])
>>> import numpy as np
>>> b = np.array([[1, 2], [3, 4]]) # (2,2)
>>> np.tile(b,2) #沿X轴复制2倍
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
>>> np.tile(b,(2,1)) #沿X轴复制1倍(相当于没有复制),再沿Y轴复制2倍
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
>>> a=np.array([0,1,2])
>>> np.tile(a,2)
array([0, 1, 2, 0, 1, 2])
>>> np.tile(a,(2,2))
array([[0, 1, 2, 0, 1, 2],
[0, 1, 2, 0, 1, 2]])
>>> np.tile(a,(2,1,2))
array([[[0, 1, 2, 0, 1, 2]],
[[0, 1, 2, 0, 1, 2]]])
>>>
原文链接:https://blog.csdn.net/qq_18433441/article/details/54897250
torch的model.train()和eval()
两种模式
pytorch可以给我们提供两种方式来切换训练和评估(推断)的模式,分别是:model.train()
和 model.eval()
。
一般用法是:在训练开始之前写上 model.trian() ,在测试时写上 model.eval() 。
功能
==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
with
是python中上下文管理器,简单理解,当要进行固定的进入,返回操作时,可以将对应需要的操作,放在with
所需要的语句中。比如文件的写入(需要打开关闭文件)等。
以下为一个文件写入使用with的例子。
with open (filename,'w') as sh:
sh.write("#!/bin/bash\n")
sh.write("#$ -N "+'IC'+altas+str(patientNumber)+altas+'\n')
sh.write("#$ -o "+pathSh+altas+'log.log\n')
sh.write("#$ -e "+pathSh+altas+'err.log\n')
sh.write('source ~/.bashrc\n')
sh.write('. "/home/kjsun/anaconda3/etc/profile.d/conda.sh"\n')
sh.write('conda activate python27\n')
sh.write('echo "to python"\n')
sh.write('echo "finish"\n')
sh.close()
with
后部分,可以将with
后的语句运行,将其返回结果给到as
后的变量(sh
),之后的代码块对close进行操作。
2.关于with torch.no_grad():
with torch.no_grad():
在使用pytorch时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。而对于tensor的计算操作,默认是要进行计算图的构建的,在这种情况下,可以使用 with torch.no_grad():
,强制之后的内容不进行计算图构建。
以下分别为使用和不使用的情况:
(1)使用with torch.no_grad():
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
print(outputs)
运行结果:
Accuracy of the network on the 10000 test images: 55 %
tensor([[-2.9141, -3.8210, 2.1426, 3.0883, 2.6363, 2.6878, 2.8766, 0.3396,
-4.7505, -3.8502],
[-1.4012, -4.5747, 1.8557, 3.8178, 1.1430, 3.9522, -0.4563, 1.2740,
-3.7763, -3.3633],
[ 1.3090, 0.1812, 0.4852, 0.1315, 0.5297, -0.3215, -2.0045, 1.0426,
-3.2699, -0.5084],
[-0.5357, -1.9851, -0.2835, -0.3110, 2.6453, 0.7452, -1.4148, 5.6919,
-6.3235, -1.6220]]
此时的outputs
没有 属性。
(2)不使用with torch.no_grad():
而对应的不使用的情况
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
print(outputs)
结果如下:
Accuracy of the network on the 10000 test images: 55 %
tensor([[-2.9141, -3.8210, 2.1426, 3.0883, 2.6363, 2.6878, 2.8766, 0.3396,
-4.7505, -3.8502],
[-1.4012, -4.5747, 1.8557, 3.8178, 1.1430, 3.9522, -0.4563, 1.2740,
-3.7763, -3.3633],
[ 1.3090, 0.1812, 0.4852, 0.1315, 0.5297, -0.3215, -2.0045, 1.0426,
-3.2699, -0.5084],
[-0.5357, -1.9851, -0.2835, -0.3110, 2.6453, 0.7452, -1.4148, 5.6919,
-6.3235, -1.6220]], grad_fn=<AddmmBackward>)
可以看到,此时有grad_fn=<AddmmBackward>
属性,表示,计算的结果在一计算图当中,可以进行梯度反传等操作。但是,两者计算的结果实际上是没有区别的。
简单的说:
不用with时的代码:
try:
do A(something before work)
work
finally:
do B(something after work)
用with时:
with (A, B):
work
效果等同.
本文转自 https://blog.csdn.net/weixin_44134757/article/details/105775027,如有侵权,请联系删除。
tf.placeholder
函数形式:
tf.placeholder(
dtype, # dtype:数据类型。常用的是tf.float32,tf.float64等数值类型
shape=None, # shape:数据形状。默认是None,就是一维值,也可以是多维(比如\[2,3\], \[None, 3\]表示列是3,行不定)
name=None # name:名称
)
为什么要用placeholder?
Tensorflow的设计理念称之为计算流图,在编写程序时,首先构筑整个系统的graph,代码并不会直接生效,这一点和python的其他数值计算库(如Numpy等)不同,graph为静态的,类似于docker中的镜像。然后,在实际的运行时,启动一个session,程序才会真正的运行。这样做的好处就是:避免反复地切换底层程序实际运行的上下文,tensorflow帮你优化整个系统的代码。我们知道,很多python程序的底层为C语言或者其他语言,执行一行脚本,就要切换一次,是有成本的,tensorflow通过计算流图的方式,帮你优化整个session需要执行的代码,还是很有优势的。
所以placeholder()函数是在神经网络构建graph的时候在模型中的占位,此时并没有把要输入的数据传入模型,它只会分配必要的内存。等建立session,在会话中,运行模型的时候通过feed_dict()函数向占位符喂入数据。
代码示例:
import tensorflow as tf
import numpy as np
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = tf.multiply(input1, input2)
with tf.Session() as sess:
print(sess.run(output, feed_dict = {input1:[3.], input2: [4.]}))
import tensorflow as tf
import numpy as np
x = tf.placeholder(tf.float32, shape=(1024, 1024))
y = tf.matmul(x, x)
with tf.Session() as sess:
#print(sess.run(y)) # ERROR:此处x还没有赋值
rand_array = np.random.rand(1024, 1024)
print(sess.run(y, feed_dict={x: rand_array}))
本文转自 https://blog.csdn.net/kdongyi/article/details/82343712,如有侵权,请联系删除。
关于SELF理解
在使用tensorFlow2搭建神经网络模型的时候,除了Sequential的方法,还有就是自己写模型class,然后初始化。自己写模型类的优势就是可以自定义层与层之间的连接关系,自定义数据流x的流向。
这是为鸢尾花数据做的一个简单基础的神经网络模型代码:
class IrisModel(Model): #继承TF的Model类
def __init__(self): #在这里定义网络结构块
super(IrisModel, self).__init__()
self.d1 = Dense(3, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2()) #定义网络结构块
def call(self, x): #在这里实现前向传播
y = self.d1(x) #调用网络结构块,实现前向传播
return y
model = IrisModel() #类实例化
我在第一次学习用类来写这个代码的时候,有几个地方觉得很奇怪,不习惯。
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
class Module(tracking.AutoTrackable):
def __init__(self, name=None):
if name is None: #模型名称
name = camel_to_snake(type(self).__name__)
else:
if not valid_identifier(name):
raise ValueError(
"%r is not a valid module name. Module names must be valid Python "
"identifiers (e.g. a valid class name)." % name)
self._name = name
if tf2.enabled():
with ops.name_scope_v2(name) as scope_name: #TF命名空间
self._name_scope = ops.name_scope_v2(scope_name)
else:
with ops.name_scope(name, skip_on_eager=False) as scope_name:
self._scope_name = scope_name
本文转自 https://blog.csdn.net/eylier/article/details/118931908,如有侵权,请联系删除。
Last updated