nn.CrossEntropyLoss expects the output to contain raw logits not probabilities, thus you would have to remove the last sigmoid.
Also, unrelated to the issue, but you should directly call the model via model(x) instead of the .forward method. Otherwise hooks could be ignored (not important for your current code, but for future use cases).
After removing the sigmoid, switching to optim.Adam and increasing the epochs to >3000, your model seems to work fine.