7 Python Mistakes in AI Workflows to Avoid

Python Mistakes in AI Workflows
Python Mistakes in AI Workflows

Python mistakes in AI workflows can be easy to miss, especially when your code runs without showing any errors. Even after a machine learning model trains and returns terrific accuracy, there could be a significant issue lurking somewhere in the workflow. The problem might be a hidden mismatch: data leakage, wrong split of data for example; or preprocessing applied in an inconsistent way; or the shape of the tensor not matching/being different than expected later on; or we have built a model that if used to reproduce later fails.

Python is the one of the most popular language for artificial intelligence and machine learning. This allows the construction of AI development with ease due to its simple syntax and powerful libraries, without writing huge amounts of code. However, there is a world of difference between code that works and an AI workflow around it producing trustworthy results.

It is one of the most popular languages ​​for AI and machine learning. Straightforward to learn, huge ecosystem and gives access to fashionable libraries as NumPy, pandas, scikit-learn and PyTorch for devs.

But there is a small catch.

Writing python code that does something is one thing, but stable ai workflow creation is another ball game altogether.

Even a well trained machine learning algorithm that makes no mistakes may still lead to negative outcomes. Often how we split our data is the issue. Preprocessing could be the cause of this problem sometimes. The shape of a tensor in python is often incorrect and python allows you to move on with it anyway.

And out of these errors, the most deceptive is that it does not invariably show up as such.

You guessed your accuracy is 95% and you thought everything is working well?? But this transforms into a disillusionment due to poor performance when the model is deployed in production.

You learnt that knowing about python mistakes common to AI workflows is as important a skill as understanding the machine learning algorithm itself.

In this article, we are going for a deep dive into few things which could silently kill an AI project; not just that also how to defend yourself from these as well.


It was, as we found out later, one of the rookie mistakes.

Say you have a dataset where there are some columns having customer information. Think, What If: Is a customer going to churn due to an aspect of the subscription?

Then suppose that you decide to standardise your numerical features prior to fitting the model.

A tempting approach is:

scaler.fit_transform(X)

and only after that:

We have sklearn for the train_test_split function which enables you to create a training, testing partition of the data.

It looks harmless.

But there is a problem.

That means, the public scaler has fit all of your data until October 2023 which also includes your future test dataset.

Like we did with StandardScaler where it is fit on the train data to compute mean, variance need to have this way since these are taken from the train data. This is very much of concern for your fit because you have fitted a scaler and both your test (and val) are in the data you pass, leaking data from the test set into fit.

This is called data leakage.

The correct approach is to split the dataset first:

X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) scaler.fit(X_train) X_train = scaler.transform(X_train) X_test = scaler.transform(X_test)

Notice the difference.

And write one classifier and performs training on X_train, that is it! This same transformation is used to transform X_test.

And as similar to this pipeline functionality of it which is built exactly to prevent from such type of leak happen in first place, it simply warns scikit-learn users explicitly that do only fit or fit_transform on train (number of features should be tested, avoid calibration on the test) Jan 10, 2017•5 min read

Remember the simple rule:

Fit on training data. Transform training and test data.

Machine learning tip – This Habit(Which is good) => can cure many ailments


The function to split train_test_split() is very handy. Take your dataset, pick a test size and bam! You have a training set and, a testing set.

But a convenient but sometimes an assumption may be hidden away.

Random splitting rows is correct strategy if the observations are reasonably independend.

And what happens if they are not?

Imagine a dataset with daily sales data.

You might have:

January 1
January 2
January 3
...
December 31

You are training the model on rows from December and then testing it against rows in February if you were to randomly split.

However, this is not a very realistic simulation in terms of how the model will actually be used.

The same issue may arise with:

  • Time-series data
  • Logs from the same client
  • Medical records from the same patient
  • Same person shown in different pictures
  • Repeated measurements from a single machine
  • Transactions from the same account

Say, a customer is 10 times in your data set.

So training have the seven records and testing three.

This is why, despite your model being extremely accurate, it may still look the same because it has previously seen data for that customer which looks very similar.

Now your test set is not painting an accurate picture of how the model generalises to true out-of-sample data.

A chronological split is typically more suitable for time-dependent problems.

If your data is grouped, you might want a strategy based on that grouping to split.

And sometimes stratification matters when you want to keep class proportions.

Random splitting:Scikit-learn’s train_test_split() supports random splitting, random_state, shuffling and stratification but right strategy yet depends on your data structure.

So before writing:

train_test_split(X, y)

ask yourself one question:

Are these rows really independent?

If so, no, get By agree forget the split.


Overly ambitious thinking has been a frequent mistake for some time (overrealistic production projects).

These include, for instance – missing values management, scaling of numerical features and conversion of categorical columns while in training.

Everything worked.

Then one thing leads to the next, modelling save and pass into the app.

So the next thing the developer did was, added one more preprocessing function which will be called for incoming data.

And to do this, and that, and this as well.

But the operative word is supposed to

Maybe the training code used:

StandardScaler()

The inference code does some basic normalization by hand.

For example, let’s say that throughout training you used one-hot encoding for your categories but during inference, the order is not returned the same way.

For example, lets say you filled in the missing values using the training median but when you implemented it to run on production you fill a 0.

Best model there is, probably.

The input is the problem.

When you ask the AI to work with data, it wants that data in precisely the format it learned during training. And when that representation changes, predictions are baseless.

Its one of the reasons I like using scikit-learn Pipelines — Pipeline : It just combines the pre-processing in with a final estimator and discards the rest of execution stages, also makes sure all transforms are proper.

For example:

from sklearn. pipeline import Pipeline from sklearn. preprocessing import StandardScaler from sklearn. from sklearn.

Here, processing is linked to the model itself.

So don t see the preprocessing as something you do prior to the model, but rather part of that same process.

Changing this way of thinking will be a great boon for the safety of production systems.


You run an experiment.

You get an accuracy of 91%.

You run it again.

90%.

Again.

92%.

Then you add:

import numpy as np

np.random.seed(42)

You run it again and get a different result.

“What happened?”

This is where reproducibility gets misunderstood.

AI workflows often involve randomness in more than one place.

You might use:

  • Python’s random module
  • NumPy
  • scikit-learn
  • PyTorch
  • CUDA
  • DataLoader workers
  • Random data augmentation
  • Random initialization

Seeding only one library does not automatically make the entire experiment deterministic.

For example, PyTorch documents that completely reproducible results are not guaranteed across different releases, platforms, or CPU and GPU executions, although several steps can reduce nondeterministic behavior.

So instead of simply saying:

“I used seed 42, therefore my experiment is reproducible.”

be more careful.

Record things such as:

Python version
Library versions
Random seeds
Dataset version
Model configuration
Hardware
Training parameters

For scikit-learn models, use random_state wherever appropriate.

For example:

model = RandomForestClassifier(random_state=42)

and:

train_test_split(
    X, y,
    test_size=0.2,
    random_state=42
)

Reproducibility is not just about getting exactly the same number every time.

It is about making an experiment understandable and repeatable enough that another run can be investigated properly.

That is a much more useful definition.


If you work with PyTorch, this mistake is worth paying attention to.

You may see code such as:

model.eval()

and assume that gradients have now been disabled.

They have not.

model.eval() changes the model’s behavior to evaluation mode. This matters for layers such as Dropout and Batch Normalization.

But evaluation mode and gradient tracking are two different concepts.

For inference, you will often see:

model.eval()

with torch.no_grad():
    output = model(input)

The first line tells the model:

“We are evaluating, not training.”

The second tells autograd:

“Do not track gradients for this operation.”

PyTorch documentation explicitly distinguishes evaluation mode from gradient computation, and recommends evaluation mode before inference for models containing layers such as dropout and batch normalization.

This distinction becomes especially important when you are measuring inference performance or deploying a model.

A simple way to remember it:

eval() changes model behavior.

no_grad() changes gradient tracking.

They solve different problems.


This one can be especially frustrating.

Your PyTorch code runs.

There is no obvious exception.

But the result is wrong.

Why?

Broadcasting.

Broadcasting allows compatible tensors with different shapes to participate in certain operations. PyTorch follows broadcasting rules similar to NumPy, automatically expanding dimensions when the shapes are compatible.

This is useful.

Very useful, actually.

But it can also hide a mistake.

Imagine you intended to multiply a tensor representing a batch of values by a vector representing one value per batch item.

You might accidentally have:

tensor shape:  [32, 10]
weight shape:  [10]

when you actually needed:

weight shape: [32, 1]

The operation may still be mathematically valid, depending on the shapes.

Python does not know what you intended.

It only knows what the tensor dimensions allow.

This is why checking shapes during development is such a good habit:

print(x.shape)
print(weight.shape)

For more serious projects, assertions are even better:

assert x.shape[0] == batch_size

You can also make tensor transformations explicit rather than relying on implicit broadcasting.

The important lesson is not “avoid broadcasting.”

Broadcasting is a useful feature.

The lesson is:

Do not assume that code producing a tensor is necessarily producing the tensor you intended.

In AI development, shape checking is often as important as syntax checking.


Saving a model can feel like the end of the project.

You train it.

You save it.

You send the file to another computer.

Done.

Not quite.

A saved model is not always a completely self-contained, universally portable object.

Depending on how it was saved, you may need the correct model architecture, compatible library versions, preprocessing logic, tokenizer, feature definitions, configuration and sometimes hardware-specific considerations.

This becomes especially important with PyTorch.

For inference, PyTorch recommends saving the model’s learned parameters through its state_dict approach:

torch.save(model.state_dict(), "model.pth")

Then recreate the model architecture and load the parameters:

model = MyModel()

model.load_state_dict(
    torch.load("model.pth", weights_only=True)
)

model.eval()

PyTorch’s documentation recommends the state_dict approach for saving model weights because it provides flexibility when restoring the model.

But even this does not mean the .pth file contains everything your application needs.

Imagine you trained a model using:

Age
Salary
Credit Score
Account Balance

and then the production application sends:

Salary
Age
Account Balance
Credit Score

The file loaded successfully.

The model runs.

But the feature order is different.

That can be a serious problem.

Similarly, if you trained a text model using a particular tokenizer and then deploy it with another tokenizer, the model may receive completely different inputs from what it learned.

So when you save a model, think beyond the model file.

A production package may need:

  • Model weights
  • Model architecture
  • Preprocessing steps
  • Feature names and order
  • Tokenizer
  • Configuration
  • Dependency versions
  • Metadata
  • Input validation rules
  • Version information

A model is not just a file.

It is part of a workflow.


The seven errors stated above make appearances in various forms, yet they have one platform in common.

Ideally, this would mean that your code is correct and/or workflow — most of them happen because you were too focused on whether it runs or not.

One of the better AI workflows should answer questions like:

How was test data injected into this process?

To fit the preprocessing, which data was used?

So the first question is, are you using the same transformations for training and inference.

Is the split of data suitable for the task?

Can the experiment be reproduced by another developer?

Tensor Shapes: Are these what we expect?

Rather, can the model be restored and working properly six months from now?

These questions are not glamorous.

I mean, debut videos are always lackluster.

However, they are the things that distinguish a fast machine learning prototype from a reliable AI system.

This is something that you should get in the habit of doing early on if you are learning Python for AI or Data Science. When the project reaches a larger size, your future self will be thanking you.

If you want to learn more on Python apart from this, SARAMBH has a dedicated technology and learning section for that too covering topics such as python, Ai, Data Science etc.


the common problems found in Python-based AI projects.


Benefits As we mentioned above the main time python is used in data science.

It gives you the ability to load data, train a model and use it for prediction in only few lines of code. This is what makes Python one of the greatest and most effective programming languages.

But it also make us feel soothe at false times.

Data leakage are not solely determined by successful execution of a script. Even from a random split the results may vary immensely. It is the trickiest part of all because you may load a model correctly but with features in wrong order. A tensor operation can also actually succeed while doing something completely different from what you think it is doing.

The good news though is that most of these mistakes can be avoided.

Split your data carefully. Perform fit preprocessing at the right location. Keep training and inference consistent. Reproducibility should be treated as a workflow and not just random seed. Check tensor shapes. Understanding the difference between eval mode vs gradient-tracking And when you specifically save a model — we actually only saving model portion of the entire system.

And although all these habits might NOT seem like fRead more here.

Later, they become extremely valuable.

And you see, in the world of AI development, fixing a quiet failure typically means more than solving a loud one.


What are the common Python mistakes in AI workflows?

Here is a list of mistakes: Data leakage, Wrong train-test splitting, Inconsistency in preprocessing, Poor reproduce practice, Misunderstanding PyTorch evaluation mode, and incorrect tensor shapes and incomplete model packaging.

Why should we perform preprocessing after dataset split?

Well, preprocessing methods like scaling or feature selection may learn from data. If they are fitted on the entire dataset before splitting, test set information can seep into the training pipeline and provide unrealistically high evaluation results. Scikit-learn recommends splitting before preprocessing.

Is random_state=42 enough for reproducibility?

No. So when you do this, certain of your operations are now reproducible, but a full AI experiment may have randomness from multiple libraries, hardware etc. PyTorch also states that identical seeds will not ensure reproducibility between platforms and releases.

Returning back to the question of difference between model. eval() and torch. no_grad()?

model. eval() is used to set a given PyTorch model (in our case, the neural network) to evaluation mode, which matters for layers like Dropout and BatchNorm. torch. no_grad() disables gradient tracking in the context of your operations. They are separate mechanisms and are commonly applied together at inference time.

Why tensor broadcasting can be dangerous?

Broadcasting feature allows compatible tensors with different shapes to work together automatically. This is convenient but sometimes an invalid shape can perform a valid operation instead giving the impression of no fault when in reality simply returning an error. We can explicitly check the dimensions of tensors in order to catch these mistakes.

Should I use Full PyTorch Model?

However, in many inference use-cases the standard solution is to save only the state_dict of the model and then recreate its architecture. You must keep the preprocessing and configurations necessary to use your model properly.

Are AI Workflows Errors Just a Beginner Problem in Python?

No – these mistakes happen more often at the beginner level, but even few years of experience have been guilty here, especially when growing a project from the initial notebook paper to production system. For bigger projects, writing puro python code is not the issue, keeping everything consistent through the entire workflow is.


Useful Resources

Internal SARAMBH resources:

External authoritative resources:

Leave a Comment

Your email address will not be published. Required fields are marked *