So the problem is that layer_dict['params'] is not a list, but just a Tensor.
So when you do for p in layer_data['params']:, you actually slice the Tensor along the 0th dimension. Since this returns new Tensors, the .grad field is not set for them.
You can either do layer_dict['params']=[layer_params,] or replace for p in layer_data['params']: by p =  layer_data['params'].