我是Pytorch的新手。我想跟踪参数空间中的距离,我的模型通过其优化传播。这是我正在使用的代码。
class ParameterDiffer(object):
def __init__(self, network):
network_params = []
for p in network.parameters():
network_params.append(p.data.numpy())
self.network_params = network_params
def get_difference(self, network):
total_diff = 0.0
for i, p in enumerate(network.parameters()):
p_np = p.data.numpy()
diff = self.network_params[i] - p_np
# print(diff)
scalar_diff = np.sum(diff ** 2)
total_diff += scalar_diff
return total_diff
这个可以吗?我一直跟踪total_diff的时间,并正在记录它,但似乎总是为零。即使模型的性能正在改善,这使我非常困惑。
原因
这是因为Pytorch处理Numpy阵列和Torch Tensor
之间的转换方式。如果Numpy阵列和火炬张量之间的基本数据类型相同,则它们将共享内存。更改一个值也将更改另一个值的值。我将在这里显示一个具体示例
x = Variable(torch.rand(2, 2))
y = x.data.numpy()
x
Out[39]:
Variable containing:
0.8442 0.9968
0.7366 0.4701
[torch.FloatTensor of size 2x2]
y
Out[40]:
array([[ 0.84422851, 0.996831 ],
[ 0.73656738, 0.47010136]], dtype=float32)
然后,如果您更改X 在场并查看x和y中的值,您会发现它们仍然相同。
x += 2
x
Out[42]:
Variable containing:
2.8442 2.9968
2.7366 2.4701
[torch.FloatTensor of size 2x2]
y
Out[43]:
array([[ 2.84422851, 2.99683094],
[ 2.7365675 , 2.47010136]], dtype=float32)
因此,在模型更新期间,模型和类ParameterDiffer
中的参数始终相同。这就是为什么您看到零。
如何解决这个问题?
如果numpy阵列和火炬张量的基础数据类型不兼容,它将迫使火炬张量中的原始数据副本,这将使Numpy阵列和Torch Tensor具有单独的内存。
一种简单的方法只是将numpy数组转换为类型np.float64
。而不是
network_params.append(p.data.numpy())
您可以使用
network_params.append(p.data.numpy().astype(np.float64))
重要参考
- http://pytorch.org/tutorials/beginner/blitz/tensor_tutorial.html#numpy-bridge
- https://github.com/pytorch/pytorch/issues/2246