A photo arriving at a finished model has to be prepared exactly the way every training photo was. Resizing has already happened here: every picture below has the same height, width and number of channels. What is left is the part that quietly goes wrong — scaling the values down and centring them.
Task: write preprocess(train_images, image), returning image ready for the network as a height × width × channels nested list, with every value rounded to 4 decimal places.
picture[r][c] is the pixel at row r, column c, and it is a list holding one value per channel — three for a colour picture (red, green, blue), one for a grayscale picture. Values are whole numbers from 0 to 255.train_images is a list of the pictures the model was trained on. image is one new picture arriving at prediction time. They all share the same height, width and number of channels.train_images alone. At prediction time there may be exactly one picture, and it has to be measured against the same yardstick as everything the model trained on — so the new picture never contributes to the averages it is centred with.The averages are worked out once, from the training set, and then frozen. Every picture the model sees afterwards is centred with those same numbers, which is what makes the steps identical at training and prediction time. A new picture that comes out mostly positive is not a bug: it is simply brighter than the photos the model learned from, and that difference is information the model is entitled to see.