Regularization in Machine Learning: The Complete 2026 Guide

|
16 min read
|
24 views
Regularization in Machine Learning

Your algorithm achieves 99% accuracy when trained on the data set. You deploy it on the actual data set and it performs badly. 71%, possibly even less. That’s what the need for regularization addresses.

Most articles on the internet talk about what regularization is. In this one, you’ll not only learn about what it is, but also the mathematics behind it, the Python code for every popular type of regularization, and most importantly, the one thing that every top article on this topic is missing.

What Is Regularization in Machine Learning?

This set of methods involves penalizing the model’s loss function with the purpose of preventing it from learning patterns present only in the training data. This is one sentence explanation of what regularization is. Now let’s discuss its importance.

The Problem Regularization Solves — Overfitting

Suppose your regression algorithm is designed based on data from 500 houses. Unconstrained, the regression algorithm will learn that one specific house in the Elm Street sells $200,000 above the median price of the neighborhood since the seller is in a rush to sell his property. However, it’s a rule that won’t be applied to any future house you will try to estimate its price.

It’s an example of overfitting – the algorithm learned noise instead of the signal.

Regularization adds a cost for complexity and forces the model to have good reasons for each pattern it learns.

Regularization in Machine Learning

The Bias-Variance Tradeoff in Plain English

Each model occupies a point on the continuum between two different failures.

When a model has high variance, it is highly sensitive to the training data. It memorizes, not learns, and fails when presented with new data. A model with high bias fails because it is too simple to learn the true pattern from the training set.

A regularized model purposefully biases a model in favor of having high bias in order to lower variance. In doing so, you sacrifice training set accuracy in favor of test set accuracy.

How Regularization Works — The Math Made Simple

In supervised learning, all models are based on minimizing a loss function. In the case of a regression problem, it is usually the mean squared error between predictions and observations.

Adding regularization makes the loss function become:

Total Cost = Prediction Error + λ × Penalty Term

The penalty parameter is obtained from the weights of the model. Lambda (λ) is the hyperparameter that is set by yourself. High value of lambda corresponds to high penalty and vice versa; this forces the model to have smaller weight values.

The particular form of this penalty parameter distinguishes L1, L2, and Elastic Net methods.

Types of Regularization

L1 Regularization — Lasso

L1 regularization adds the sum of absolute weight values to the loss function:

Cost = (1/n) Σ(yᵢ – ŷᵢ)² + λ Σ|wⱼ|

Unique features of L1: the ability to reduce weights to exactly zero.

Not nearly zero. Zero. Which means that L1 automatically excludes features from the model.

This type of modeling is called sparse modeling, and it is actually useful. Classifying texts using 50,000 features? Chances are that most of those words do not say anything about your target feature at all. L1 zeroes them out. And you get a smaller and more efficient model.

The term “LASSO” which stands for Least Absolute Shrinkage and Selection Operator was coined by Robert Tibshirani in 1996 paper and was based on geophysical work of Santosa and Symes from a decade before.

When to use L1: You have many features and suspect most are irrelevant. NLP, genomics, any high-dimensional problem where interpretability matters.

from sklearn.linear_model import Lasso

from sklearn.model_selection import train_test_split

from sklearn.datasets import make_regression

from sklearn.metrics import mean_squared_error

import numpy as np

X, y = make_regression(n_samples=200, n_features=20, noise=15, random_state=42)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

lasso = Lasso(alpha=0.1)

lasso.fit(X_train, y_train)

y_pred = lasso.predict(X_test)

print(f"MSE: {mean_squared_error(y_test, y_pred):.2f}")

print(f"Non-zero coefficients: {np.sum(lasso.coef_ != 0)} out of {X.shape[1]}")

# Shows which features L1 kept — the rest are zeroed out

The non-zero coefficient count is the useful output here. If 20 features go in and only 7 come out with nonzero weights, L1 just did your feature selection for you.

L2 Regularization — Ridge

L2 adds the sum of squared weight values to the loss:

Cost = (1/n) Σ(yᵢ – ŷᵢ)² + λ Σwⱼ²

Squared values cause the penalty to grow faster for larger weights than smaller weights. Therefore, L2 shrinks all weights to closer to zero, but not zero itself. All features remain in the model; however, with smaller weight coefficients.

It works well in situations where you know that all the features matter. Building a machine learning model to predict whether the patients would get re-admitted depending on such features as age, blood pressure, previous hospitalizations, and number of medications – dropping any of them would be incorrect.

The history of Ridge regression goes back to 1940s Tikhonov regularization method used to solve ill-posed inverse problems. It can be considered as Tikhonov regularization for least squares problem. Just something to know in case you encounter this term in some old books.

When to use L2: Features are correlated, or domain knowledge says they all contribute. Financial modeling, medical prediction, structural data with meaningful variables.

from sklearn.linear_model import Ridge

from sklearn.datasets import make_regression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error

X, y = make_regression(n_samples=200, n_features=20, noise=15, random_state=42)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

ridge = Ridge(alpha=1.0)

ridge.fit(X_train, y_train)

y_pred = ridge.predict(X_test)

print(f"MSE: {mean_squared_error(y_test, y_pred):.2f}")

print(f"Coefficient range: {ridge.coef_.min():.3f} to {ridge.coef_.max():.3f}")

# All coefficients exist but are pulled toward zero; none reach exactly zero

Practical point that is important to note: you must always scale your features before using L1 or L2 regularization. In both cases, there is a penalty based on the magnitude of the weights, and when features are not scaled correctly (e.g., income in thousands vs. 0/1), penalties will not be fair.

Elastic Net — Combining Both

Elastic Net puts L1 and L2 together in one penalty term:

Cost = (1/n) Σ(yᵢ – ŷᵢ)² + λ[(1-α)Σ|wⱼ| + αΣwⱼ²]

The l1_ratio parameter (alpha in the formula) controls the mix. Set it to 1.0 and you get pure Lasso. Set it to 0 and you get pure Ridge. Anywhere in between is a blend.

It’s here that it becomes applicable: you have lots of variables, but they are grouped into correlated groups. The L1 method will choose only one variable from each correlated group and set all others to zero, losing potentially valuable data. The L2 method will do no selection at all. Elastic Net can select correlated groups of variables as a whole.

from sklearn.linear_model import ElasticNet

from sklearn.model_selection import GridSearchCV, train_test_split

from sklearn.datasets import make_regression

from sklearn.metrics import mean_squared_error

X, y = make_regression(n_samples=200, n_features=20, noise=15, random_state=42)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

param_grid = {

    "alpha": [0.01, 0.1, 1.0, 10.0],

    "l1_ratio": [0.1, 0.3, 0.5, 0.7, 0.9]

}

en = ElasticNet(max_iter=5000)

grid = GridSearchCV(en, param_grid, cv=5, scoring="neg_mean_squared_error")

grid.fit(X_train, y_train)

print(f"Best params: {grid.best_params_}")

print(f"MSE: {mean_squared_error(y_test, grid.predict(X_test)):.2f}")

If you’re unsure whether L1 or L2 is right, start with Elastic Net. You can always narrow it down after you see where the l1_ratio settles.

Dropout — Regularization for Neural Networks

The above applies to linear models. Neural networks require something else entirely.

In 2014, Nitish Srivastava, Geoffrey Hinton, et al., introduced the dropout technique in the Journal of Machine Learning Research. It completely transformed how overfitting was handled in deep learning.

The idea is straightforward: In each training iteration, randomly drop out some portion of the neurons such that those neurons do not take part in the forward or backward pass at all. The network continues learning as if nothing happened.

Why should breaking down your network make it perform better? Because it forces the network to build redundant representations. There’s no one unique way in which a neural network can get to the answer because the burden is distributed among many other neurons. When testing the network, all the neurons are used to give an average performance of thousands of sub-networks trained along the way.

And that’s actually the key insight. Dropout isn’t just noise — it’s enforced redundancy.

import torch

import torch.nn as nn

class RegularizedNet(nn.Module):

    def __init__(self, input_dim, hidden_dim, output_dim, dropout_rate=0.3):

        super().__init__()

        self.net = nn.Sequential(

            nn.Linear(input_dim, hidden_dim),

            nn.ReLU(),

            nn.Dropout(p=dropout_rate),   # 30% of neurons dropped each step

            nn.Linear(hidden_dim, hidden_dim),

            nn.ReLU(),

            nn.Dropout(p=dropout_rate),

            nn.Linear(hidden_dim, output_dim)

        )

    def forward(self, x):

        return self.net(x)

model = RegularizedNet(input_dim=20, hidden_dim=128, output_dim=1)

# CRITICAL: disable dropout at inference time

model.eval()   # PyTorch switches dropout off automatically here

That model.eval() call is something beginners miss constantly. During inference, dropout must be off; the full network runs. PyTorch handles this automatically when you call model.eval(), but in custom training loops, you need to toggle it manually.

Typical dropout rates: 0.2 to 0.5 for dense hidden layers. Larger dense layers tolerate higher dropout rates; convolutional layers usually do better closer to 0.1 or 0.2.

Early Stopping

The most basic form of regularization. Stop training when your validation error starts deteriorating; that’s when you’ve stopped making progress on validation error.

There’s no penalty term and no penalty factor to adjust except for the patience factor.

from tensorflow import keras

model = keras.Sequential([

    keras.layers.Dense(128, activation='relu', input_shape=(20,)),

    keras.layers.Dense(64, activation='relu'),

    keras.layers.Dense(1)

])

model.compile(optimizer='adam', loss='mse')

early_stop = keras.callbacks.EarlyStopping(

    monitor='val_loss',

    patience=10,

    restore_best_weights=True   # revert to the best checkpoint, not the last

)

model.fit(

    X_train, y_train,

    validation_split=0.2,

    epochs=500,

    callbacks=[early_stop],

    verbose=0

)

restore_best_weights=True matters. Without it, you get the model from the last epoch, which is already starting to overfit. With it, you get the weights from the epoch where validation loss was lowest.

Data Augmentation as Regularization

Data augmentation does not punish the loss function but instead increases the training dataset by creating variations of the existing dataset.

For images: horizontal flips, slight rotations, changes in brightness. The model learns to see more diversity and cannot fixate on certain examples. For text: synthesize synonyms, back-translating into another language. For tabular data: add Gaussian noise to numerical features.

It is particularly beneficial in computer vision with smaller datasets. Without tens of thousands of images, augmentation will be more impactful than any other form of regularization that you could introduce.

L1 vs. L2 vs. Elastic Net vs. Dropout — Which Should You Actually Use?

This is the question every guide skips.

Your SituationBest Starting Point
Linear or logistic model; many features, most probably irrelevantL1 (Lasso)
Linear or logistic model; correlated features that all likely matterL2 (Ridge)
Linear or logistic model; unsure which of the above appliesElastic Net
Training a neural networkDropout + weight decay
Any model; want the simplest fix firstEarly stopping
Small dataset, especially imagesData augmentation first

A few decision rules worth internalizing:

Start with Ridge as your default for regression tasks. Use L2 in case you are uncertain about how the features behave in your problem. L2 makes everything smaller, but keeps it in – providing you with a robust starting point. Lasso or Elastic Net may be used after you understand your feature space better.

Use Lasso when interpretability matters. If there is a need to provide the stakeholder with the explanation of which features impact the prediction, and make such an explanation simple and concise, use L1 to shrink everything unimportant out of your model.

Use Elastic Net for correlated feature groups. Lasso is inclined to pick randomly only one feature from the group, while in case if such correlation is justified (for example, several blood parameters) it would be better to keep them all.

For neural networks, start with dropout. Then add weight decay on top if the model still overfits. These two stack well.

Regularization in Machine Learning

How to Choose Lambda — The Part Nobody Explains

All people know that lambda regulates the strength of the regularization. But almost no one knows where to start or how to get the right value.

A lambda value which is too low leads to overfitting because there is no effective penalty. And if it is too high then bias is too high and it cannot fit even training data. This means underfitting at first and overfitting later.

The solution is cross-validation. It is performed by default in RidgeCV and LassoCV from scikit-learn:

from sklearn.linear_model import RidgeCV, LassoCV

from sklearn.preprocessing import StandardScaler

from sklearn.pipeline import Pipeline

# Scale features first; L1 and L2 are both scale-sensitive

pipe_ridge = Pipeline([

    ("scaler", StandardScaler()),

    ("ridge", RidgeCV(alphas=[0.001, 0.01, 0.1, 1, 10, 100], cv=5))

])

pipe_ridge.fit(X_train, y_train)

print(f"Best alpha (Ridge): {pipe_ridge.named_steps['ridge'].alpha_}")

pipe_lasso = Pipeline([

    ("scaler", StandardScaler()),

    ("lasso", LassoCV(cv=5, max_iter=5000))

])

pipe_lasso.fit(X_train, y_train)

print(f"Best alpha (Lasso): {pipe_lasso.named_steps['lasso'].alpha_:.4f}")

Use the range of 0.001 to 100 in log scale for the starting values. Most of the time, the problem falls into the range of 0.01 to 10, but again it depends upon your features and the size of your dataset.

Over regularization: Training accuracy is bad, test accuracy is bad, and they are similar, which means high bias. Reduce lambda.

Moreover, Every time when there is any change in the pipeline, i.e., addition of features, new data or change in architecture of the model, tune lambda.

Regularization in Deep Learning and LLMs — What’s Changed in 2026

Here’s where all three top-ranking competitors on this keyword go quiet. So let’s cover what they missed.

Weight Decay vs. L2 Regularization — They’re Not the Same

Classically, in machine learning using plain SGD, L2 regularization and weight decay are mathematically equivalent and interchangeably used without any problem. Using adaptive optimizers such as Adam (and everybody does use Adam for training neural nets nowadays), they are not equivalent at all.

Adam optimizes individual learning rates for different model weights based on their gradient history. Since when you use an L2 penalty in the loss function, it becomes a part of the gradient signal optimized by Adam, the penalty is multiplied by its adaptive rates. As a result, frequently updated parameters have more significant regularization than those rarely updated. The coupling of regularization and optimizer behavior turns out to be quite detrimental to performance.

The solution, proposed in AdamW by Ilya Loshchilov and Frank Hutter in 2017, is simple: move the weight decay operation outside the gradient optimization routine so that it occurs after, rather than during, the adaptive gradient update step. By 2026, AdamW replaces plain Adam as a matter of course.

import torch.optim as optim

# Adam with L2 embedded in loss — decay is NOT properly decoupled

optimizer_adam = optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)

# AdamW — decay is decoupled from adaptive gradients

optimizer_adamw = optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)

# For modern deep learning, use AdamW

The same interface, yet radically different in terms of what it does. If you are already using Adam with weight decay, simply replace it with AdamW. Nothing else should be changed.

It is not really accurate to present it as an optional move. This is due to the fact that AdamW has practically become the standard for large-scale model training.

LoRA and Regularization in LLM Fine-Tuning

It’s also the thing that I think is most misunderstood by omission in many guides. Regularization in 2026 is not just a penalty anymore.

The thing is that when you are fine-tuning a language model of billions of parameters on a tiny task-specific dataset, overfitting would be absolutely catastrophic. This problem is solved by LoRA (low-rank adaptation): you don’t even try to update any full parameter matrices. Instead, each weight update is represented as the product of two smaller matrices. Because of the rank constraint (4 to 16 in practice), the number of parameters that can be learned goes down by multiple orders of magnitude.

This constraint is the implicit regularizer. The model simply can’t memorize the fine-tuning dataset because of the lack of parameter space and that was the goal in the first place. The technique used here belongs to the family of PEFT (parameter-efficient fine-tuning), which is currently the state of the art for LLM fine-tuning.

Common Regularization Mistakes

They will keep showing up, hence the need to know about them before getting to them.

Regularizing an already-underfit model. If the training accuracy is poor (e.g., 55% for a binary classifier), regularization worsens the situation. You will be increasing the bias of a model that already has high bias. Overfitting must be confirmed before regularization.

Skipping feature scaling. L1 and L2 regularization punish the magnitude of the weight. If there are disparities in the scale of features, the punishment is distributed unequally among the features because they have varying scales and not importance. Normalization is important here.

Leaving dropout on at inference time. Covered above, but worth repeating. PyTorch’s model.eval() handles this automatically. Custom loops need it set explicitly.

Treating lambda as permanent. The optimal lambda in the initial dataset may not be the same even after introducing new data, new features, and even when the model architecture changes.

Regularization by Domain — Quick Reference

Different fields tend to settle on different techniques, and the reasons make sense once you know the data structure.

Text classification and NLP: L1 is popular. The sparsity of vocabulary feature space is natural. Words seldom predict outcomes, and L1’s built-in feature selection is an advantage.

Medical prediction: L2 usually beats L1 when samples are few compared to features, since retaining all features with shrunken coefficients is less risky than setting coefficients to zero even though all the features are clinically significant.

Financial modeling: Elastic Net handles correlated financial features such as sector correlations and macro-factor correlations. Lasso will arbitrarily pick only one feature from each cluster, and financial models become unstable as the correlations change.

Computer vision and deep learning: Combining dropout with data augmentation is the default baseline. DropBlock is an improved version of drop-out, where clusters of neurons are dropped, rather than single neurons.

A Quick Implementation Reference

If you need the code without re-reading everything above:

# ── scikit-learn: L1, L2, Elastic Net ──────────────────────────────────────

from sklearn.linear_model import RidgeCV, LassoCV, ElasticNetCV

from sklearn.preprocessing import StandardScaler

from sklearn.pipeline import Pipeline

ridge_pipe = Pipeline([("sc", StandardScaler()), ("model", RidgeCV(cv=5))])

ridge_pipe.fit(X_train, y_train)

lasso_pipe = Pipeline([("sc", StandardScaler()), ("model", LassoCV(cv=5))])

lasso_pipe.fit(X_train, y_train)

en_pipe = Pipeline([

    ("sc", StandardScaler()),

    ("model", ElasticNetCV(l1_ratio=[.1, .5, .7, .9, .95, 1], cv=5))

])

en_pipe.fit(X_train, y_train)

# ── PyTorch: Dropout + AdamW ────────────────────────────────────────────────

import torch, torch.nn as nn, torch.optim as optim

class Net(nn.Module):

    def __init__(self):

        super().__init__()

        self.layers = nn.Sequential(

            nn.Linear(20, 128), nn.ReLU(), nn.Dropout(0.3),

            nn.Linear(128, 64),  nn.ReLU(), nn.Dropout(0.3),

            nn.Linear(64, 1)

        )

    def forward(self, x): return self.layers(x)

net = Net()

optimizer = optim.AdamW(net.parameters(), lr=1e-3, weight_decay=1e-4)

# Remember: call net.eval() before inference to disable dropout

# ── Keras: Early Stopping ───────────────────────────────────────────────────

from tensorflow import keras

early_stop = keras.callbacks.EarlyStopping(

    monitor='val_loss', patience=10, restore_best_weights=True

)

# Pass early_stop to model.fit() callbacks argument

Frequently Asked Questions

Q1. What is the difference between L1 and L2 regularization?

Ans. L1 regularization adds the sum of the absolute values of the weight coefficient to the loss function and is capable of reducing the coefficient value to zero, thus eliminating it from the model. On the other hand, L2 adds the square of the weight and pushes it towards zero but never completely eliminates it. So, all variables remain in the model.

Q2. Does regularization always improve model performance?

Ans. Wrong. In case of an underfitting model (inability to learn the underlying pattern from the training set itself), additional use of the regularization technique will increase the amount of bias and degrade its performance. Regularization technique is effective only after you ensure that there is overfitting.

Q3. What is a good starting value for lambda?

Ans. For both ridge and lasso, try [0.001, 0.01, 0.1, 1, 10, 100] using cross-validation. The majority of regression tasks fall somewhere between 0.01 and 10, but your optimal choice will depend on the scaling of the features and the amount of data you have. For dropout, 0.2 to 0.3

Q4. How is regularization different from normalization?

Ans. Regularization changes the criterion function which the algorithm tries to minimize. Feature normalization (or scaling) rescales the features of the dataset. They are different steps. However, one thing should be noted. The normalizing of the features should be done prior to regularization, as L1 and L2 regularization are very sensitive to feature scaling.

Q5. Is dropout a form of regularization?

Ans. Yes. Dropout regularizes neural networks by randomly dropping out neurons in the training process to ensure the network does not adapt to feature combinations that may exist only in the training data set. It was developed in 2014 by Srivastava, Hinton et al. and is still one of the most common regularization techniques in deep learning.

Q6. Does regularization work differently in neural networks than in linear models?

Ans. Notably, in linear models, it is quite neat and elegant to incorporate L1 or L2 in the loss function. Neural networks have many more parameters, non-linearity in the form of activation functions, and layers; hence the penalty space is quite complex. Methods such as dropout, weight decay (with proper decoupling using AdamW), and early stopping tend to work better than just incorporating L1 or L2 in the loss.

Bottom Line

The meaning of regularization itself is evolving continuously. Traditionally, regularization referred to the inclusion of a penalty term within the loss function. Then, regularization came to mean dropout in deep learning – an entirely different concept. The next phase of evolution was the introduction of AdamW that corrected a small flaw in the relationship between adaptive optimizers and weight penalties. Currently, in the case of fine-tuning LLMs, it refers to constraining the space of parameters using architectural design choices such as LoRA.

The core concept of regularization remains the same: do not allow your model to remember. It is just that your approach changes depending on the technology you work with at any point in time.

Gyansetu offers top professional training certification courses designed to enhance your skills and advance your career, providing industry-relevant knowledge and practical expertise.