Thank you for your response. I now changed the function to this and used indexing on pair_p and pair_t.
def custom_loss(p, t):
    total = torch.zeros(1, dtype=torch.float, requires_grad=True)
    for pair_p2, pair_t2 in zip(torch.combinations(p, r=2), torch.combinations(t, r=2)):
        pair_p, _ = torch.sort(pair_p2)
        pair_t, _ = torch.sort(pair_t2)
        pair_p = pair_p.double()
        pair_t = pair_t.double()
        
        g1 = (pair_p[0] == pair_p[1]).type(torch.uint8)
        g2 = (pair_t[0] == pair_t[1]).type(torch.uint8)
        total = total + (torch.max(pair_t[g2.item()], g2.type(torch.double)) - torch.max(pair_p[g1.item()], g1.type(torch.double)))**2
    return total

t = torch.tensor([1, 1, 0, 0, 1])
x = torch.tensor([2, 3, 3], dtype=torch.double)

model = nn.Linear(3, 5)
output = model(x)

loss = custom_loss(output, t)
loss.backward()
print('loss = ', loss)
# loss = tensor([4.], device='cuda:0', grad_fn=<AddBackward0>)

Now I don’t get a list of Nones anymore, but instead I get this tensor full of zeros.
print([x.grad for x in model.parameters()])
#     [tensor([[0., 0., 0,],
#              [0., 0., 0.],
#              [0., 0., 0.],
#              [0., 0., 0.],
#              [0., 0., 0.]], device='cuda:0'), tensor([0., 0., 0., 0., 0.], device='cuda:0')]

Do you know what might cause this?