计算 PyTorch 网络参数 Space 中的距离

Calculating Distance in Parameter Space for PyTorch Network

我是 PyTorch 的新手。我想跟踪参数-space 中的距离,我的模型经过优化。这是我正在使用的代码。

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 array 和 torch Tensor 之间的底层数据类型相同,它们将共享内存。改变一个的值也会改变另一个的值。我将在这里展示一个具体的例子,

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)

因此在您的模型更新期间,模型中的参数和 class ParameterDiffer 中的参数将始终相同。这就是您看到零的原因。

如何解决这个问题?

如果numpy数组和torch Tensor底层数据类型不兼容,会强制复制torch Tensor中的原始数据,使n​​umpy数组和torch Tensor内存分离

一个简单的方法就是将 numpy 数组转换为 np.float64 类型。而不是

network_params.append(p.data.numpy())

您可以使用

network_params.append(p.data.numpy().astype(np.float64))

重要参考资料

  1. http://pytorch.org/tutorials/beginner/blitz/tensor_tutorial.html#numpy-bridge
  2. https://github.com/pytorch/pytorch/issues/2246