x = self.fc3(x)
    logit = torch.sigmoid(x)
    proba = F.softmax(logit, dim=1)
    return proba, logit

You would still have the same issue. The logits are the outputs before the non-linear activation function. Or in other words, they are the weighted inputs of a given layer. I.e., you would do it as follows:
    logits = self.fc3(x)
    probas = F.softmax(logits, dim=1)
    return logits, probas

The reason is that F.binary_cross_entropy applies the softmax internally for numerical stability reasons.
An alternative would be using the negative log likelihood loss on the softmax’s. Or in other words, in PyTorch, F.cross_entropy does log(softmax) + negative log likelihood internally.
This naming convention is actually one of the confusing parts of PyTorch. For your reference, there is:


F,binary_cross_entropy that  takes sigmoid outputs as inputs

F.binary_cross_entropy_with_logits that takes logits as inputs

F.cross_entropy that takes logits as inputs

F.nll_loss that  takes softmax outputs as inputs

In my opinion, F.cross_entropy should have been names F.cross_entropy_with_logits similar to the binary cross entropy variant for consistency. (Since this is something that trips up beginners often, it’s maybe worth thinking about the naming convention for future versions of PyTorch @smth)