AI in Python: 7 Boundaries to Secure to Avoid False Positives

Flattering scores can mask failing pipelines. Leaks between training and validation, inappropriate separation, biases between training and serving, misleading seeds, poorly managed PyTorch states, silent broadcasting, and unsafe artifacts are among the causes. Targeted checks can detect these errors at the exact point where they arise.
Securing Artifacts: Risky Loading and Version Drift
A model saved with pickle, joblib, or cloudpickle can execute code upon loading. A five-line file with a malicious reduce method can trigger a payload when calling pickle.load without raising an exception. Therefore, it is imperative never to load an artifact that has not been verified by a trusted source. Furthermore, scikit-learn does not guarantee the compatibility of saved models across different versions of the library. Each artifact must be accompanied by its training recipe, a data reference, dependency versions, and the claimed validation score. Before any promotion, it is recommended to load the artifact in the actual serving environment and run a fixed fixture through preprocessing and prediction. Changing format does not eliminate these risks but shifts them. It is essential to load only from trusted sources and to test validation in the serving environment.
Leaks and Separations: Avoid Training on "Invisible" Lines
Adjusting transformations before data separation causes information leakage: out of 100 noise samples with 1,000 features and randomly drawn labels, a SelectKBest fitted on the entire set and then validated through cross-validation shows an accuracy of 0.83. Moving the selection into a scikit-learn pipeline so that each fold fits its own transformation brings the accuracy down to 0.49, which corresponds to the expected performance on noise. This rule also applies to scaling, imputation, and dimensionality reduction. The diagnosis involves spotting each fit and fit_transform and documenting which lines were visible at that moment. Separations must also correspond to the true boundary to generalize. For example, a synthetic dataset with 60 users and nearly duplicated lines per user achieves 0.97 with train_test_split, then drops to 0.89 with GroupShuffleSplit that isolates each user on one side: the eight-point gap reflects memorization. Grouped data requires GroupKFold or GroupShuffleSplit; time series require TimeSeriesSplit, as random separation can train on the future to predict the past. Stratification on the label does not resolve the issue of groups, and train_test_split does not account for this notion. The separator must be chosen after deciding whether to generalize to entities or time points.
Le brief IA que les pros lisent chaque soir
Les 7 actus IA du jour, décryptées en 5 min. Gratuit.
Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.
Choisissez votre rythme
Gratuit · Pas de spam · Désabonnement en 1 clic
Aligning Training and Serving to Eliminate Preprocessing Bias
Reimplementing preprocessing on the serving side can introduce significant discrepancies. For example, relearning a scaler on five production lines instead of reusing the one fitted during training can shift the same fixture by nearly four standard units. Inference must reuse the learned parameters, feature order, data types, and rules on missing values defined during training. The most reliable solution is to ship the fitted pipeline object along both paths. Verification is done by pushing a raw fixture through the training and serving paths, then comparing names, order, types, shapes, and values of the outputs: any divergence indicates a discrepancy on the serving side.
Reproducibility: One Seed is Not Enough, Everything Must Be Recorded
Setting random.seed(42) is not sufficient to make an experiment reproducible: Python, NumPy, and PyTorch each have their own random number generator, and a multi-process DataLoader applies its own seeding rules. Deterministic kernels must be explicitly requested, and this can affect performance, as noted in PyTorch's reproducibility notes. Even with defined seeds, identical results are not guaranteed across versions of PyTorch, between platforms, or between CPU and GPU. Reproducibility depends on recording seeds, data, code version, configuration, and dependencies. A fast course from Weights & Biases offers a method to automate this recording.
PyTorch Modifies Modules with model.eval While torch.no_grad Acts on Autograd
model.eval() switches modules like dropout and batch norm into inference mode, while torch.no_grad() disables autograd without changing the state of the modules. If dropout is active, two passes under no_grad but in training mode can produce different outputs, as illustrated by the values -0.1410 and 0.0071. With eval(), two calls on the same input yield an identical response. In evaluation mode without no_grad, gradients continue to be recorded. Therefore, a validation loop must combine eval() and no_grad(), then return the model to training mode. When no gradient is required, torch.inference_mode() more strictly locks the absence of gradients. Even without dropout currently, it is recommended to explicitly call eval().
Tensor Shapes: Prevent Broadcasting from Distorting Loss
If the prediction has the shape [batch, 1] and the target [batch], MSELoss broadcasts into a batch × batch matrix. With a batch of 32, this creates a 32 by 32 grid; a loss of 1.63 may seem plausible while the correctly shaped version gives 1.85 on the same tensors. PyTorch then issues a UserWarning, which tests should turn into an error. MSELoss requires the target to have the same shape as the input: thus, one must decide on the shape contract and apply it, for example by using squeeze(1) to obtain [batch] and asserting shape equality before calculating the loss. Not all broadcasts are bugs, but implicit expansion is faulty at boundaries where an exact agreement is required.
Brief IA — L'actualité IA en français
L'essentiel de l'actualité de l'intelligence artificielle, décrypté et expliqué chaque jour.