I just built a toy linear regression model with gradient descent, coding it from scratch. It was doing fine on test data, but it was off on training data. In the end I figured that I was normalizing new data according to its own mean and range, instead of using the mean and range of the training data.
And I realized that I never understood why this doesn't work, and I never found an explainer. Intuitively, I see normalization as a way of "rewriting" the data, without changing its structure. When I get the test data, I can easily calculate its mean and range and standard deviation. So shouldn't I "rewrite" it in terms of itself? Doing it with the statistics of the training data also feels a bit like cheating, since we typically avoid any contact between training set and testing set.