Q1:
解惑(一) ----- super(XXX, self).__init__()到底是代表什么含义_奋斗の博客的博客-CSDN博客
class LocalCamNet(nn.Module):
def __init__(self, args=None):
super(LocalCamNet, self).__init__()
super(Net, self).__init__()指首先找到Net的父类(nn.Module),然后把类Net的对象self转换为类Module的对象,在子类init时会调用父类的_init_()
回过头来看看我们的我们最上面的代码,Net类继承nn.Module,super(Net, self).__init__()就是对继承自父类nn.Module的属性进行初始化。而且是用nn.Module的初始化方法来初始化继承的属性。
Q2:
if logit.dim() == 1:
logit = logit.unsqueeze(0)
unsqueeze()在对应维度上增加一维,示例实验,可以看到示例输出,维度数确实增加了。
output = torch.tensor([2.,3.])
print (output)
dim = output.dim()
print(dim)
if output.dim() == 1:
output = output.unsqueeze(0)
print (output)
dim = output.dim()
print(dim)
tensor([2., 3.])
1
tensor([[2., 3.]])
2
tensor([[2., 3.],
[4., 5.]])
2
tensor([[[2., 3.]],
[[4., 5.]]])
3
Q3:
/root/anaconda3/envs/cpcnn/lib/python3.8/site-packages/torch/nn/functional.py:3722: UserWarning: nn.functional.upsample is deprecated. Use nn.functional.interpolate instead.
warnings.warn("nn.functional.upsample is deprecated. Use nn.functional.interpolate instead.")
示例代码
import torch
import torch.nn as nn
import torch.nn.functional as F
# input = torch.tensor([[1.,1.],[2.,2.]])
x = torch.arange(1, 17, dtype=torch.float32).view(1,1,4,4)
y = torch.arange(1, 5, dtype=torch.float32).view(1,1,2,2)
print(y)
_, _, H, W = x.size()
m = F.upsample(y,size=(H, W), mode='bilinear', align_corners=True)
print (m)
n = F.interpolate(y,size=[H,W],mode='bilinear', align_corners=True)
print(n)
upsample 已经由interpolate替换,可以直接替换着写,得到的结果是一致的,参数的含义,upsample(input, size, scale_factor, mode, align_corners)
input:需要上采样的输入
size:上采样后的大小
scale_factor:空间大小的乘数。如果它是元组,则必须匹配输入大小。
mode:nearest 邻近 linear 线性 bilinear 双线性
align_corners:输入和输出tensor的角像素对齐,保留这些像素的值,默认Flase。
tensor([[[[1., 2.],
[3., 4.]]]])
tensor([[[[1.0000, 1.3333, 1.6667, 2.0000],
[1.6667, 2.0000, 2.3333, 2.6667],
[2.3333, 2.6667, 3.0000, 3.3333],
[3.0000, 3.3333, 3.6667, 4.0000]]]])
tensor([[[[1.0000, 1.3333, 1.6667, 2.0000],
[1.6667, 2.0000, 2.3333, 2.6667],
[2.3333, 2.6667, 3.0000, 3.3333],
[3.0000, 3.3333, 3.6667, 4.0000]]]])
Q4:
arange() 主要是用于生成数组
2.1 语法
numpy.arange(start, stop, step, dtype = None)
在给定间隔内返回均匀间隔的值。
值在半开区间 [开始,停止]内生成(换句话说,包括开始但不包括停止的区间),返回的是 ndarray 。
2.2 参数:
start —— 开始位置,数字,可选项,默认起始值为0
stop —— 停止位置,数字
step —— 步长,数字,可选项, 默认步长为1,如果指定了step,则还必须给出start。
dtype —— 输出数组的类型。 如果未给出dtype,则从其他输入参数推断数据类型。
Q5:
.detach() .clone
【python基础】PyTorch中clone()、detach()_Clark-dj的博客-CSDN博客_.clone().detach()
.detach()
Returns a new Tensor, detached from the current graph. The result will never require gradient.
即返回一个和源张量同shape、dtype和device的张量,与源张量共享数据内存,但不提供梯度计算。
操作后的tensor与原始tensor共享数据内存,当原始tensor在计算图中数值发生反向传播等更新之后,detach()的tensor值也会发生改变。
input_B = output_A.detach()
detach操作在共享数据内存的脱离计算图,所以常用在神经网络中仅要利用张量数值,而不需要追踪导数的场景下。
.clone()
返回一个和源张量同shape、dtype和device的张量,与源张量不共享数据内存,但提供梯度的回溯。
clone操作在一定程度上可以视为是一个identity-mapping函数。clone
作为一个中间variable,会将梯度传给源张量进行叠加。张量数据非共享
clone操作在不共享数据内存的同时支持梯度回溯,所以常用在神经网络中某个单元需要重复使用的场景下。
⭐: 在pytorch中不可直接使用id相等来判断tensor在共享内存,这是必要条件,因为也许底层共享数据内存,但是仍是新的tensor,比如detach(),如果打印id就会不同,但其共享内存。
一起使用 .clone().detach()
clone实现非数据共享,detach不追踪梯度,clone和detach一起使用可以实现只做简单的数据复制,既不数据共享,也不对梯度共享,从此两个张量无关联。
Q6:
GAP (global average pooling)
全局平均池化其实就是对每一个通道图所有像素值求平均值,然后得到一个新的1 * 1的通道图。
没有现成的包可以调用,但可以利用自适应平均池化/自适应最大池化来实现。
nn.AdaptiveAvgPool2d(1)
nn.AdaptiveMaxPool2d(1)
Q7:
简单的python语法,名为“list”的列表末尾添加新的对象a。
list.append(a)
Q8:
model.eval() 模型预测模式
会将一些加了Dropout的层和batch normalization的层恢复。 测试时dropout和batch normalization是没有意义的。
Q9:
参考python 中 __call__简单介绍_阿常呓语的博客-CSDN博客
python 中__call__。这是个很有趣的用法,是用于class的定义中。我们在定义类型的时候实现了__call__函数,这个类就变成了可以调用的。也就是说在类实现后,可以直接使用 示例对象() 来调用__call__方法。如一下例子,其实call_test(),和call_test.__call__()实现的功能一样。
class TestCall(object):
def __init__(self, name):
self.name = name
def __call__(self, *args, **kwargs):
print("self.name: %s. " % self.name, end=' ')
print('__call__() is running ')
if __name__ == '__main__':
call_test = TestCall(name='xiaoming')
call_test() # call_test.__call__()
call_test.__call__()
self.name: xiaoming. __call__() is running
self.name: xiaoming. __call__() is running
Q10:
torch.argmax(input, dim=0, keepdim=False)
上述代码意思是,返回input中第0维最大值的索引,dim=-1,则是返回最后一维的索引。
Q11:
numpy.squeeze(a,axis = None)
从矩阵中,去掉维度为1的维数。例如下面例子。
x = torch.arange(1, 17, dtype=torch.float32).view(4,4,1,1)
dim=x.dim()
print(x)
print(dim)
y= x.squeeze()
dim=y.dim()
print(y)
print(dim)
tensor([[[[ 1.]],
[[ 2.]],
[[ 3.]],
[[ 4.]]],
[[[ 5.]],
[[ 6.]],
[[ 7.]],
[[ 8.]]],
[[[ 9.]],
[[10.]],
[[11.]],
[[12.]]],
[[[13.]],
[[14.]],
[[15.]],
[[16.]]]])
4
tensor([[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.],
[13., 14., 15., 16.]])
2
Q12:
register_hook的使用。使用时register_hook(),括号中必须是一个函数。看到的是grad_cam中的代码
def save_gradient(self, grad):
self.gradients.append(grad)
def __call__(self, x):
outputs = []
self.gradients = []
# for name, module in self.model._modules.items():
for name, module in self.feature_extractor._modules.items():
x = module(x)
if name in self.target_layers:
x.register_hook(self.save_gradient)
outputs += [x]
return outputs, x
PyTorch反向传播时默认只保存叶子结点的梯度,非叶子节点的梯度不被保存,这样设计是为了节省内存,如果你想查看中间变量的梯度的话,使用register_hook