【问题标题】:Serialiazation of pytorch state_dict changes after loading into new model instance加载到新模型实例后,pytorch state_dict 的序列化更改
【发布时间】:2021-06-25 20:41:37
【问题描述】:

为什么在将 a state_dict 加载到相同模型架构的新实例后,序列化 pytorch state_dicts 获得的字节会发生变化?

看看:

import binascii
import torch.nn as nn
import pickle

lin1 = nn.Linear(1, 1, bias=False)
lin1s = pickle.dumps(lin1.state_dict())
print("--- original model ---")
print(f"hash of state dict: {hex(binascii.crc32(lin1s))}")
print(f"weight: {lin1.state_dict()['weight'].item()}")

lin2 = nn.Linear(1, 1, bias=False)
lin2.load_state_dict(pickle.loads(lin1s))
lin2s = pickle.dumps(lin2.state_dict())
print("\n--- model from deserialized state dict ---")
print(f"hash of state dict: {hex(binascii.crc32(lin2s))}")
print(f"weight: {lin2.state_dict()['weight'].item()}")

打印

--- original model ---
hash of state dict: 0x4806e6b6
weight: -0.30337071418762207

--- model from deserialized state dict ---
hash of state dict: 0xe2881422
weight: -0.30337071418762207

如您所见,state_dicts 的(泡菜)的哈希值不同,而权重被正确复制。我会假设新模型中的state_dict 在各个方面都等于旧模型。看起来,它没有,因此哈希值不同。

【问题讨论】:

  • 这可能是因为 pickle 不会产生适合散列的 repr。 stackoverflow.com/questions/12727571/… 比较键可能是一个更好的主意,然后比较存储在 dict-keys 中的张量是否相等/接近。
  • @UmangGupta 这听起来很合理,我不知道。谢谢!我不知道你的答案(这仍然是一种假设)是否算作“真实”答案,但如果你这样发布,我会将其标记为解决方案。
  • 我在答案中进一步阐述了我的回答。希望对您有所帮助。

标签: python pytorch pickle


【解决方案1】:

这可能是因为 pickle 不会产生适合散列的 repr(请参阅 Using pickle.dumps to hash mutable objects)。比较键可能是一个更好的主意,然后比较存储在 dict-keys 中的张量是否相等/接近。

下面是这个想法的粗略实现。

def compare_state_dict(dict1, dict2):
    # compare keys
    for key in dict1:
        if key not in dict2:
            return False
    
    for key in dict2:
        if key not in dict1:
            return False

    for (k,v) in dict1.items():
        if not torch.all(torch.isclose(v, dict2[k]))
            return False
    
    return True

但是,如果您仍想对 state-dict 进行哈希处理并避免使用上述 isclose 之类的比较,则可以使用如下所示的函数。

def dict_hash(dictionary):
    for (k,v) in dictionary.items():
        # it did not work without hashing the tensor
        dictionary[k] = hash(v)

    # dictionaries are not hashable and need to be converted to frozenset. 
    return hash(frozenset(sorted(dictionary.items(), key=lambda x: x[0])))

【讨论】:

  • 谢谢,但我偶然发现了一个问题:散列相等的张量会产生不同的散列(我猜它不会散列内容而是内存地址(?))。这可以通过散列来解决,如下所示: hash(v.numpy().tobytes())
  • 我 100% 确定,但您可能是正确的。此外,isclose 可能是一个更好的选择,因为它几乎需要相同数量的工作来散列和比较......一/两次通过数据。
猜你喜欢
  • 2020-10-17
  • 2020-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 2020-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多