H2O
custom loss function
machine learning
data science
AI tools

Custom loss function in H2O

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

H2O gives you several built-in objectives for regression and classification, but the phrase custom loss can mean two different things. Some teams want a custom metric for reporting, while others want to change the training objective itself. Those are separate features in H2O, and the distinction matters.

Custom Metric Versus Custom Training Loss

A custom metric is computed during scoring and appears in model output, but it does not change how the optimizer updates the model. In H2O-3, that feature is exposed through custom_metric_func for several algorithms.

A true custom training loss is different. To change the gradients used during fitting, you need a custom distribution. In current H2O-3 documentation, that workflow is available for GBM through the Python client. That limitation is the main source of confusion: not every H2O estimator accepts an arbitrary user-defined loss during training.

Before reaching for a custom objective, check whether a built-in option already matches the behavior you need. For example, gaussian, laplace, quantile, and huber cover many regression scenarios, and class weights or row weights often solve asymmetric-cost problems without any custom code.

Implementing a Custom Distribution in GBM

When you really do need custom training behavior, the supported path is to define a custom distribution class and upload it to H2O. The example below creates an asymmetric squared-error style objective for regression. Under-prediction is penalized more heavily than over-prediction.

Save this class in a file named asymmetric_squared_error.py:

python
1from h2o.utils.distributions import CustomDistributionGaussian
2
3class AsymmetricSquaredError(CustomDistributionGaussian):
4    def gradient(self, y, f):
5        error = y - f
6        if error > 0:
7            return 2.0 * error
8        return 0.5 * error

Then upload the distribution and use it in a GBM model:

python
1import h2o
2from h2o.estimators.gbm import H2OGradientBoostingEstimator
3from asymmetric_squared_error import AsymmetricSquaredError
4
5h2o.init()
6
7train = h2o.H2OFrame(
8    {
9        "feature_1": [1, 2, 3, 4, 5, 6],
10        "feature_2": [0, 1, 0, 1, 0, 1],
11        "target": [1.1, 1.9, 3.2, 3.8, 5.4, 6.1],
12    }
13)
14
15custom_dist = h2o.upload_custom_distribution(
16    AsymmetricSquaredError,
17    func_name="asymmetric_squared_error",
18    func_file="asymmetric_squared_error.py",
19)
20
21model = H2OGradientBoostingEstimator(
22    distribution="custom",
23    custom_distribution_func=custom_dist,
24    ntrees=20,
25    max_depth=3,
26    learn_rate=0.1,
27    seed=42,
28)
29
30model.train(x=["feature_1", "feature_2"], y="target", training_frame=train)
31print(model.predict(train))

This is the right tool when the cost of being wrong is structurally asymmetric. Inventory forecasting is a good example: predicting too low can be more expensive than predicting too high because it can trigger stockouts.

When a Custom Metric Is the Better Choice

Many teams think they need a custom loss when they actually need a custom score. If your goal is to rank models by a business-specific measure while keeping optimization stable, a custom metric is often simpler and safer.

That separation can be useful. You can train with a standard loss such as squared error, then report a custom metric that reflects internal cost, service-level impact, or regulatory penalties. The model remains easier to explain and easier to maintain because the training objective is still a well-understood built-in function.

Another practical alternative is sample weighting. If some observations matter more than others, weights can shift the optimization without requiring a fully custom distribution. That keeps deployment simpler and reduces the chance of numerical problems.

Common Pitfalls

  • Expecting every H2O algorithm to support arbitrary custom training losses. In H2O-3, custom distributions are much narrower in scope than custom metrics.
  • Confusing custom_metric_func with a real optimization objective. The metric changes reporting, not gradient updates.
  • Forgetting to set distribution="custom" when you intend GBM to use the uploaded distribution.
  • Designing a loss with unstable gradients. Very steep or discontinuous behavior can make boosting hard to tune.
  • Ignoring built-in options such as Huber loss, quantile loss, or row weights, which are easier to test and maintain.

Summary

  • In H2O, custom metrics and custom training losses are different features.
  • A true custom training loss is implemented as a custom distribution, and the documented H2O-3 workflow centers on GBM in the Python client.
  • Many use cases can be solved with built-in distributions, weights, or a custom metric instead of a full custom objective.
  • If you implement a custom distribution, keep the gradient simple and numerically stable.
  • Choose the least complex option that matches the business requirement.

Course illustration
Course illustration

All Rights Reserved.