torch.nn.BatchNorm2d 函数
什么是batch? ’
batch是整个训练集中的一部分,由于训练集往往过大不能一次性全部输入到网络中,所以需要分批次地输送所以每一批就是一个batch(批)
什么是Normalization?
Normalization翻译是归一化,归一化的引入是为了减少internal covariatie shift现象,其具体表现是在训 练深层网络的过程中,前面层参数的变化会影响后面每层的参数分布,
导致了训练时只能选用较低的学 习速率以及小心谨慎的参数初始化。而Batch Normalization层(BN)的引入允许我们使用更高的学习率以及不用太担心参数初始化的问题。
Batch Normalization的具体过程:
对于输入的一个batch数据,先计算出每个维度的平均值和方差,对于一个2*2的灰度图像来说,那么就要计算一个batch内每个像素通道的平均值和方差(共计算四次,得到四个平均值和方差)。
然后通过以下公式得到归一化之后的batch
注意:在测试阶段计算平均值和方差有两种模式:
第一种:通过训练阶段大量batch计算得到的平均值和方差的统计值来代替测试阶段的均值和方差
第二种:通过跟随测试阶段batch的平均值和方差来对第一种方法得到的均值和方差来进行修改
running_mean = momentum * running_mean + (1 - momentum) * train_mean
running_var = momentum * running_var + (1 - momentum) * train_var
其中momoentum为权重,train_mean是训练过程中所有batch的mean的统计量,running_mean是测试batch的简单平均
torch.nn.BatchNorm2d函数
形式:torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
返回一个shape与num_features相同的tensor
其中:
1.num_features为输入batch中图像的channle数(按每一个channle来做归一化)
2.eps是一个稳定系数
3.momentum为running_mean和running_var的权重
4.affine代表着是否可学习,True代表通过学习而来,False代表是固定值
5.track_running_stats代表测试阶段使用第一种还是第二种均值测试方法,True代表第二种,False代表第一种
nn.ReLU(inplace=True)
inplace=True
的意思是进行原地操作,例如x=x+5
,对x
就是一个原地操作,y=x+5
,x=y
,完成了与x=x+5
同样的功能但是不是原地操作,ReLU
中的inplace=True
的含义是一样的,是对于Conv2d
这样的上层网络传递下来的tensor直接进行修改,好处就是可以节省运算内存,不用多储存变量y
。作者:VanJordan
链接:https://www.jianshu.com/p/8385aa74e2de
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
.clone().detach()创建新的tensor
To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() "
"or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
如:
#self.mean = torch.tensor(mean).view(-1, 1, 1)#会出现警告
self.mean = mean.clone().detach().view(-1,1,1)
pytorch里面的detach()和clone()内存问题
pytorch里面的detach()和clone()内存是不同的,detach是内存共享的,而clone()是不内存共享的。
>>> import torch
>>> a = torch.randn(3,3)
>>> a
tensor([[ 0.5639, -1.1958, -1.1856],
[ 1.0022, -1.1584, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>> a
tensor([[ 0.5639, -1.1958, -1.1856],
[ 1.0022, -1.1584, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>> b=a.clone()
>>> b
tensor([[ 0.5639, -1.1958, -1.1856],
[ 1.0022, -1.1584, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>> c=a.detach()
>>> c
tensor([[ 0.5639, -1.1958, -1.1856],
[ 1.0022, -1.1584, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>> c[1][1]=0
>>> c
tensor([[ 0.5639, -1.1958, -1.1856],
[ 1.0022, 0.0000, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>> a
tensor([[ 0.5639, -1.1958, -1.1856],
[ 1.0022, 0.0000, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>> b
tensor([[ 0.5639, -1.1958, -1.1856],
[ 1.0022, -1.1584, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>> b[0][0]=2
>>> b
tensor([[ 2.0000, -1.1958, -1.1856],
[ 1.0022, -1.1584, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>> a
tensor([[ 0.5639, -1.1958, -1.1856],
[ 1.0022, 0.0000, -0.9377],
[ 2.0623, 1.7044, 0.2486]])
>>>
torch.squeeze() 和torch.unsqueeze()的用法
torch.squeeze() 这个函数主要对数据的维度进行压缩,去掉维数为1的的维度,比如是一行或者一列这种,一个一行三列(1,3)的数去掉第一个维数为一的维度之后就变成(3)行。
squeeze(a)就是将a中所有为1的维度删掉。不为1的维度没有影响。a.squeeze(N) 就是去掉a中指定的维数为一的维度。还有一种形式就是b=torch.squeeze(a,N) a中去掉指定的定的维数为一的维度。
import torch as t
>>> print(c)
tensor([[[ 1.0921, -1.0011, -0.7804]]])
>>> print(c.shape)
torch.Size([1, 1, 3])
>>> d = t.squeeze(c)
>>> print(d)
tensor([ 1.0921, -1.0011, -0.7804])
>>> print(d.shape)
torch.Size([3])
>>> h = c.squeeze(0)#或者 >>> h = t.squeeze(c,1)
>>> print(h)
tensor([[ 1.0921, -1.0011, -0.7804]])
>>> print(h.shape)
torch.Size([1, 3])
torch.unsqueeze()这个函数主要是对数据维度进行扩充。给指定位置加上维数为一的维度,比如原本有个三行的数据(3),在0的位置加了一维就变成一行三列(1,3)。a.unsqueeze(N) 就是在a中指定位置N加上一个维数为1的维度。
还有一种形式就是b=torch.unsqueeze(a,N) a就是在a中指定位置N加上一个维数为1的维度
>>> import torch as t
>>> a = t.randn(1,3)
>>> print(a)
tensor([[ 1.0921, -1.0011, -0.7804]])
>>> print(a.shape)
torch.Size([1, 3])
>>> b = t.unsqueeze(a,1)
>>> print(b)
tensor([[[ 1.0921, -1.0011, -0.7804]]])
>>> print(b.shape)
torch.Size([1, 1, 3])
>>> c =a.unsqueeze(0)
>>> print(c.shape)
torch.Size([1, 1, 3])
torch.manual_seed(args.seed) #为CPU设置种子用于生成随机数,以使得结果是确定的 if args.cuda: torch.cuda.manual_seed(args.seed)#为当前GPU设置随机种子; #如果使用多个GPU,应该使用torch.cuda.manual_seed_all()为所有的GPU设置种子
torch.backends.cudnn.deterministic
为什么使用相同的网络结构,跑出来的效果完全不同,用的学习率,迭代次数,batch size 都是一样?固定随机数种子是非常重要的。
但是如果你使用的是PyTorch等框架,还要看一下框架的种子是否固定了。还有,如果你用了cuda,别忘了cuda的随机数种子。这里还需要用到torch.backends.cudnn.deterministic. torch.backends.cudnn.deterministic是啥?顾名思义,将这个 flag 置为True的话,每次返回的卷积算法将是确定的,即默认算法。
如果配合上设置 Torch 的随机种子为固定值的话,应该可以保证每次运行网络的时候相同输入的输出是固定的,代码大致这样 def init_seeds(seed=0): torch.manual_seed(seed) # sets the seed for generating random numbers. torch.cuda.manual_seed(seed) # Sets the seed for generating random numbers for the current GPU. It’s safe to call this function if CUDA is not available; in that case, it is silently ignored. torch.cuda.manual_seed_all(seed) # Sets the seed for generating random numbers on all GPUs. It’s safe to call this function if CUDA is not available; in that case, it is silently ignored. if seed == 0: torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False
CuDNN
When running on the CuDNN backend, two further options must be set:
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
警告
确定性操作可能会对单次运行性能产生负面影响,具体取决于模型的组成。由于不同的底层操作(可能较慢),处理速度(例如每秒训练的批数)可能低于模型不确定运行时的速度。然而,即使单次运行的速度可能较慢,但取决于您的应用程序,确定性可以通过简化实验、调试和回归测试来节省时间。
torch.max()函数
a = torch.randn(3,3) torch.max(a,0) #返回每一列中最大值的那个元素,且返回索引(返回最大元素在这一列的行索引) torch.max(a,1) #返回每一行中最大值的那个元素,且返回其索引(返回最大元素在这一行的列索引) output.max(1, keepdim=True)--->返回每一行中最大的元素并返回索引,返回了两个数组 output.max(1, keepdim=True)[1] 就是取第二个数组,取索引数组。
torch.nn.Linear()函数
# 导库 import numpy as np import torch import torch.nn as nn x = torch.randn(56,10) m = torch.nn.Linear(10,20) output = m(x) print('m.weight.shape: ', m.weight.shape) print('m.bias.shape: ', m.bias.shape) print('output.shape: ', output.shape)
m.weight.shape:
torch.Size([20, 10])
m.bias.shape:
torch.Size([20])
output.shape:
torch.Size([56, 20])
为什么 m.weight.shape = (20,10)?
答:因为线性变换的公式是:
先生成一个(20,10)的weight,实际运算中再转置,这样就能和x做矩阵乘法了
torch.sort()
torch.sort(input, dim=None, descending=False, out=None)
返回值
1A tuple of (sorted_tensor, sorted_indices) is returned,
2where the sorted_indices are the indices of the elements in the original input tensor.
参数
input (Tensor) – the input tensor
形式上与 numpy.narray 类似
dim (int, optional) – the dimension to sort along
维度,对于二维数据:dim=0 按列排序,dim=1 按行排序,默认 dim=1
descending (bool, optional) – controls the sorting order (ascending or descending)
降序,descending=True 从大到小排序,descending=False 从小到大排序,默认 descending=Flase
import torch x = torch.randn(3,3) print(x) # y ,j = torch.sort(x)#按行从小到大排序 # print(y) # print(j) # tensor([[-0.6150, 0.7668, 1.0559], # [-0.9822, 1.2309, 1.2492], # [-0.9063, -0.0783, 1.1597]]) # tensor([[0, 2, 1],#每行分开考虑 # [0, 2, 1], # [0, 2, 1]]) # y , j = torch.sort(x,descending=True)#按行从大到小排序 # print(y) # print(j) # tensor([[-1.0390, -1.0751, 0.4301], # [ 0.3489, 0.5976, 2.0214], # [-0.1190, 0.1546, 0.7294]]) # tensor([[ 0.4301, -1.0390, -1.0751], # [ 2.0214, 0.5976, 0.3489], # [ 0.7294, 0.1546, -0.1190]]) # tensor([[2, 0, 1], # [2, 1, 0], # [2, 1, 0]]) # y , j = torch.sort(x,dim = 0)#按列从小到大排序 # print(y) # print(j) # tensor([[-0.1958, 0.8579, -0.5103], # [-0.9725, -0.3167, 0.2082], # [ 0.1473, -0.4125, -0.3321]]) # tensor([[-0.9725, -0.4125, -0.5103], # [-0.1958, -0.3167, -0.3321], # [ 0.1473, 0.8579, 0.2082]]) # tensor([[1, 2, 0], # [0, 1, 2], # [2, 0, 1]]) y , j = torch.sort(x,dim = 0,descending = True)#按列从大到小排序 print(y) print(j) # tensor([[ 1.8798, 0.4058, -0.5840], # [ 1.1803, -0.9680, -0.2581], # [ 0.4876, -1.6891, -0.5953]]) # tensor([[ 1.8798, 0.4058, -0.2581], # [ 1.1803, -0.9680, -0.5840], # [ 0.4876, -1.6891, -0.5953]]) # tensor([[0, 0, 1], # [1, 1, 0], # [2, 2, 2]])
torch.gt
torch.gt(input, other, out=None) → Tensor 逐元素比较input和other , 即是否input>other,input>other 如果两个张量有相同的形状和元素值,则返回True ,否则 False。
第二个参数可以为一个数或与第一个参数相同形状和类型的张量 参数: input (Tensor) – 要对比的张量 other (Tensor or float) –
要对比的张量或float值 out (Tensor, optional) – 输出张量。必须为ByteTensor或者与第一个参数tensor相同类型。
返回值: 一个 torch.ByteTensor 张量,包含了每个位置的比较结果(是否 input >= other )。 返回类型: Tensor
import torch # 比较前者张量是否大于后者 a = torch.Tensor([[1,2],[3,4]]) b = torch.Tensor([[1,2], [5,6]]) # print(a.abs().gt(2.0).float()) # tensor([[0., 0.], # [1., 1.]]) print(torch.gt(a,b)) # tensor([[False, False], # [False, False]]) print(torch.gt(a,b).float()) # tensor([[0., 0.], # [0., 0.]])
torch.ge基本和torch.gt相同,主要区别:是否input>=other
torch.narrow()
torch.
narrow
(input, dim, start, length) → Tensor
Returns a new tensor that is a narrowed version of input
tensor. The dimension dim
is input from start
to start +length
. The returned tensor and input
tensor share the same underlying storage.
- Parameters
Example:
x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) print(x) print(x[:,1:3]) print(x.narrow(1,2,1))#x[:,2:2+1] tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) tensor([[2, 3], [5, 6], [8, 9]]) tensor([[3], [6], [9]])
print(x.narrow(0,1,2))#x[1:1+2,:]
tensor([[4, 5, 6],
[7, 8, 9]])