Serialiazation of pytorch state_dict changes after loading into new model instance
Why do the bytes obtained from serializing pytorch state_dicts change after loading the a state_dict into a new instance of the same model architecture?
Have a look:
import binascii
import torch.nn as nn
import pickle

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

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

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

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

As you can see, the hashes of the (pickles of the) state_dicts are different whereas the weight is copied over correctly. I would assume that a state_dict from the new model equals the old one in every aspect. Seemingly, it does not, hence the different hashes.

This might be because pickle is not expected to produce a repr suitable for hashing (See Using pickle.dumps to hash mutable objects). It might be a better idea to compare keys, and then compare tensors stored in the dict-keys for equality/closeness.
Below is a rough implementation of that idea.
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

However, if you would still like to hash a state-dict and avoid using comparisons like isclose above, you can use a function like below.
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])))

