记录一些自己遇到的有关 PyTroch 的问题。
关于Mask梯度的方法
- 自己尝试过两种实现方式:
- 模型 layer 使用自定义的
MaskedConv
等 layer 实现,layer中自带一个mask的tensor,在init()
中定义backward_hook(grad)
,并在其中执行register_hook()
。之后只要改动 mask就好; - 不改动模型,在训练结束后手动添加
layer.mask
,手动register_hook()
- 模型 layer 使用自定义的
关于数组 Index
- Pytorch 1.3之后如果要使用
Tensor_1[Tensor_2]
的写法,Tensor_2的dtype必须是torch.bool
(以前可以是uint8),不然会疯狂报错。正确写法Tensor_1[Tensor_2.bool()]
- 此类错误不会给出traceback。手动开启traceback方法:
1 | import traceback |
关于 backward
- 需要一步内多次
backward()
的情况:loss.backward(retain_graph=True)
否则无法在之后再次loss.backward()
。注意此类型报错通常能以更高效的方式解决(?)
关于 apply(fn)
1 | for module in self.children(): |
关于 tensor与numpy的转换
1 | 5] a = torch.ones[ |
两者指向同一地址。
对b进行改动时应使用inplace操作,否则b地址会被替换。
1 | 5]) c = numpy.zeros_like([ |
- 需要注意的是,显卡上的tensor(device=GPU)需要取到cpu上才能转换为numpy
A.cpu().numpy()
否则报错。 - 还有一点是,注意维持其为同一个ndarray数组对象,否则仍然会替换地址(如
b = 1
则b不再和a共享地址)
关于 copy_(), clone(), detach(), = 的区别
后两者复制地址,detach不复制梯度
注意转换
A.cpu().detach().numpy()
所detach的是cpu上的临时tensor,不会对A (此时A的device是显卡) 造成任何影响,也不会对其他Tensor有影响。A.cpu()
是函数返回值,本身创造的临时tensor在创造完numpy数组后会被释放(大概吧)所以需要重新 register_buffer不需要,用
A.data.copy_(torch.as_tensor(A_np))
。在
W.required_grad==True
的情况下不能使用W.cpu().numpy()
,必须detach()