You can just return a tuple (but you’d want x.chunk(2, dim=-1) or somesuch to split into two chunks. One fc probably works if your optimizer considers tensor entries individually (e.g. Adam is OK, but LAMB will consider parameters as large tensors and the “size” of the change is proportional to the “length” (both Frobenius norm) of the parameters as vectors).
It doesn’t make much much sense to do the backpropagation completely separate, it is usually much better to scale the loss terms to some sort of equilibrium (either of the losses or the gradients or so) and then backpropagate in one go.
Best regards
Thomas