Your code works, if I just wrap it in a custom nn.Module:
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.a = nn.Parameter(torch.ones([1,1],dtype=torch.double), requires_grad=True)       ###
        self.b = nn.Parameter(torch.ones([1,1],dtype=torch.double)*torch.sqrt(torch.Tensor([4.]).double()), requires_grad=True)       ###
        self.register_parameter('aa',self.a)                                                                 ###
        self.register_parameter('bb',self.b) 
        
    def forward(self, x):
        x = x * self.aa * self.bb
        return x

model = MyModel()
print(model.a)
> Parameter containing:
tensor([[1.]], dtype=torch.float64, requires_grad=True)
print(model.b)
> Parameter containing:
tensor([[2.]], dtype=torch.float64, requires_grad=True)
print(model.aa)
> Parameter containing:
tensor([[1.]], dtype=torch.float64, requires_grad=True)
print(model.bb)
> Parameter containing:
tensor([[2.]], dtype=torch.float64, requires_grad=True)

As you see, you’ll get the expected values as well as types.