扩维 降维 squeeze和unsuqeeze
函数功能:去除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)。
注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。
功能:增加大小为1的维度,也就是返回一个新的张量,对输入的指定位置插入维度 1且必须指明维度
x = torch.unsqueeze(x, 3) # 在第3个维度上扩展 注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。
如果dim为负,则将会被转化dim+input.dim()+1
原文链接:https://blog.csdn.net/lj2048/article/details/114263912
举例:
Copy # 如我们有一组数据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])
TORCH.spilt()
torch.split
( tensor , split_size_or_sections , dim=0)
torch.split()作用将tensor分成块结构。
参数:
split_size_or_sections:需要切分的大小(int or list )
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型时
Copy 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型时。
Copy 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]
glob.glob()之返回路径的正反斜杆问题
Copy 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. 例子理解
Copy >>> 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
Copy 
里面用到4次torch.cat,其中copy and crop操作就是通过torch.cat来实现的。可以看到通过上采样(up-conv 2x2)将原始图像h和w变为原来2倍,再和左边直接copy过来的同样h,w的图像拼接。这样做,可以有效利用原始结构信息。
4.总结
使用torch.cat((A,B),dim)时,除拼接维数dim数值可不同外其余维数数值需相同,方能对齐。
拼接2 torch.stack
先用图示讲讲 torch.cat() 是在原先维度上进行拼接
我们用图+代码来举例
Copy import torch
x1 = torch.randn(1, 3)
x2 = torch.randn(1, 3)
Copy # 在 0 维(纵向)进行拼接
torch.cat((x1, x2), 0) # size [2, 3]
Copy # 在 1 维(横向)进行拼接
torch.cat((x1, x2), 1) # size [1, 6]
注意:对于cat拼接张量,==维度数量 (不是维度上的量)必须相同==;==进行拼接的维度的尺寸可以不同,但是其它维度的尺寸必须相同==。【简而言之,堆积木,对上了就可以拼】
我们继续用图+代码来举例
Copy import torch
x1 = torch.randn(3, 4)
x2 = torch.randn(3, 4)
Copy # 在 0 维插入一个维度,进行前后组合
torch.stack((x1, x2), 0)
# size [2, 3,4]
Copy # 在 1 维插入一个维度
torch.stack((x1, x2), 1)
# size [3, 2,4]
Copy # 在 2 维插入一个维度
torch.stack((x1, x2), 2)
# size [3, 4,2]
补充: 拼接多个向量,例如:torch.stack((x1, x2, x3, x4), 2),再上述的方法中接入需要拼接的向量就可以了
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,则因为上述原因报错
Copy one_img2 = tf.reshape(one_img, shape=[1, one_img.get_shape()[0].value, one_img.get_shape()[1].value, 1])
用下面的方法可以实现:
Copy one_img = tf.expand_dims(one_img, 0)
one_img = tf.expand_dims(one_img, -1) #-1表示最后一维
在最后,给出官方的例子和说明
Copy # '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]
举例:
Copy 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))
结果:
Copy [[1. 2.]
[3. 4.]
[5. 6.]]
------------
[[[1. 2.]
[3. 4.]
[5. 6.]]]
------------
[[[1. 2.]]
[[3. 4.]]
[[5. 6.]]]
------------
[[[1.]
[2.]]
[[3.]
[4.]]
[[5.]
[6.]]]
torch.flatten()
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维数据,如果只需要部分扁平化,那么有一维的数据不会进行扁平操作,具体看下面的案例分析。
Copy 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)
Copy # 部分扁平化
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代表的是列(想要变为几列)#这里所说并不严谨,只是为了更好理解,
取值代表行数,当不知道要变为几行,但知道要变为几列时可取-1
取值代表列数,当不知道要变为几列,但知道要变为几行时可取-1
注意:元素个数要能整除行和列
下面看几个例子就理解了。
1、把原先tensor中的数据进行排列,排成一行,然后根据所给的view()中的参数从一行中按顺序选择组成最终的tensor
Copy 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的行时:
Copy 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的列时:
Copy 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.]])
图像处理
张量存储为图片
三维张量转图片
Copy 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维度)
Copy 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)
随机数Rand
torch.rand
torch.rand(*sizes, out=None) → Tensor
返回一个张量,包含了从区间[0,1)的均匀分布中抽取的一组随机数 ,形状由可变参数sizes
定义。
Copy print(torch.rand(3))
print(torch.rand(3,2))
输出为:
Copy >>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
定义。
Copy print(torch.randn(3))
print(torch.randn(3,2))
torch.randperm
torch.randperm(n, out=None) → LongTensor
给定参数n
,返回一个从[0, n -1) 的随机整数排列 。
参数:n (int) – 上边界(不包含)
Copy print(torch.randperm(10))
Copy >>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
是一个张量 ,包含每个输出元素相关的正态分布的标准差。均值和标准差的形状不须匹配,但每个张量的元素个数须相同。
参数:
randn和normal的区别
虽然randn和normal都可以生成服从正态分布的随机数,但是normal可以自己设定均值和标准差。就这点区别。
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
比如:
Copy 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之间的浮点数。
Copy >>
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]])
这样看到话,两个都能取0-1之间的均匀分布,但是问题在于rand取不到1,uniform_可以取到1。
torch 检查
判断tensor中是否存在NAN, inf
在用torch搭建深度学习模型时,很容易在数据中存在inf与nan的情况,对应的数据类型分别时torch.inf与torch.nan。 大多数情况下,产生nan数据的原因基本上是出现了分母为0的情况,所以需要检查张量计算过程中是否有除法运算,比如softmax就有除法。
Copy 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]])
Copy >>> 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() 。
在使用 pytorch 构建神经网络,添加一句model.train()作用是 启用 batch normalization 和 dropout 。
如果模型中有BN层(Batch Normalization)和 Dropout ,需要在 训练时 添加 model.train()。
model.train() 是保证 BN 层能够用到 每一批数据 的均值和方差。
对于 Dropout,model.train() 是 随机取一部分 网络连接来训练更新参数。
model.eval()的作用是 不启用 Batch Normalization 和 Dropout 。
如果模型中有 BN 层(Batch Normalization)和 Dropout,在 测试时 添加 model.eval()。
model.eval() 是保证 BN 层能够用 全部训练数据 的均值和方差,即测试过程中要保证 BN 层的均值和方差不变。
对于 Dropout,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() 是利用到了所有网络连接。
参考链接
with torch.no_grad()
1.关于with
with
是python中上下文管理器,简单理解,当要进行固定的进入,返回操作时,可以将对应需要的操作,放在with
所需要的语句中。比如文件的写入(需要打开关闭文件)等。
以下为一个文件写入使用with的例子。
Copy 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():
在使用pytorch时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。而对于tensor的计算操作,默认是要进行计算图的构建的,在这种情况下,可以使用 with torch.no_grad():
,强制之后的内容不进行计算图构建。
以下分别为使用和不使用的情况:
(1)使用with torch.no_grad():
Copy 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)
运行结果:
Copy 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():
而对应的不使用的情况
Copy 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)
结果如下:
Copy 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>
属性,表示,计算的结果在一计算图当中,可以进行梯度反传等操作。但是,两者计算的结果实际上是没有区别的。
简单的说:
Copy 不用with时的代码:
try:
do A(something before work)
work
finally:
do B(something after work)
用with时:
with (A, B):
work
效果等同.
tf.placeholder
函数形式:
Copy 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()函数向占位符喂入数据 。
Copy 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.]}))
Copy 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}))
关于SELF理解
在使用tensorFlow2搭建神经网络模型的时候,除了Sequential的方法,还有就是自己写模型class,然后初始化。自己写模型类的优势就是可以自定义层与层之间的连接关系,自定义数据流x的流向。
这是为鸢尾花数据做的一个简单基础的神经网络模型代码:
Copy 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? 又不能省略,又感觉很累赘,它到底意义何在?
原文:博主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__()这样的父类初始化命令行。
Copy 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