Thank you so very much for taking the time to explain this! I see indeed that my MaxPool didn’t do anything, so I upped it to 2 as you suggested. It took me a little while, but I was also able to use the dimension formulas to ensure the linear input size was correct. And lo and behold, it finally ran! 
The initial results were really poor, so I adjusted the model a litle bit, and this is what it looks like after some tweaking:
def __init__(self, n_classes):
    super.__init__()
    self.featurizer = nn.Sequential(
            # Convolutional part.
            nn.Conv2d(3, 25, kernel_size=4, stride=2, padding=1),
            nn.ReLU(),
            nn.Conv2d(25, 50, kernel_size=4, stride=2, padding=1),
            nn.ReLU(),
            nn.Conv2d(50, 100, kernel_size=4, stride=2, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),

    self.classifier = nn.Sequential(
            # Linear part.
            nn.Linear(100*16*16, 224),
            nn.Sigmoid(),
            nn.Linear(224, 112),
            nn.Sigmoid(),
            nn.Linear(112, 21)
    )

And of course, I made sure that the linear input was updated accordingly.
With this model, I was able to get a training loss of 2.681906. Still not ideal, probably, but I’m really happy with these results for my very first ever CNN.  I can continue to tweak the parameters now however I need.
I genuinely wouldn’t have been able to get this off the ground without your help. Thanks a lot again!