Machine Learning in Slow Motion

Building a physics model with fitted parameters is machine learning, but slower

Harys Dalvi

September 2026

Physics models are sometimes thought of as a cleaner alternative to machine learning: you get interpretable parameters and less overfitting. But when you have unknown parameters in a model, you have to fit them to data. That starts to look a lot like machine learning, only with a human slowly defining the rules and parameters instead of an algorithm.

Gru's plan meme in four panels: 'Build a physics model', 'Define assumptions and specify parameters', 'Fit parameters to data until it works', then the same line again as Gru realizes what it means.

In some cases, the choice of whether to use a physics model or a machine learning model is obvious. If you're modeling planets with Newton's laws, go for physics. If your goal is protein folding, physics is way too expensive and ML is the clear pick.

The ambiguous cases happen when:

One such example is predicting the flow of water in a creek given the time series of precipitation and temperature. We're going to do this with data for Blackwood Creek, near Lake Tahoe in California, and we'll see how the physics model measures up against a bitter lesson transformer, and how interpretable its parameters really are.

Three stacked charts over water years 1999 to 2001: daily precipitation, which falls mostly between November and April; daily temperature, from about −10 °C in winter to 20 °C in summer; and creek flow, which stays low through winter and peaks at 10 to 27 mm/day each May and June, months after most of the precipitation.
A graph of the data we are working with.[] Our target is predicting flow in the creek given the time series of precipitation and temperature.
Emerald Bay at Lake Tahoe, surrounded by trees and mountains
Lake Tahoe in California, which Blackwood Creek drains into.

The silly solution is: however much it flows on average, just guess that number. To make sure this isn't what's happening, the metric we'll use is NSE, which looks at the error we would get if we used the “predict the same as the average” strategy and computes how much of that we eliminated. 0 means we are no better than the silly strategy; 1.0 means we are perfect; a negative means we are actively worse than just guessing the average.[]

NSE formula

\[ \text{NSE} = 1 - \frac{\sum_t \left( Q_{\text{sim}}(t) - Q_{\text{obs}}(t) \right)^2}{\sum_t \left( Q_{\text{obs}}(t) - \bar{Q}_{\text{obs}} \right)^2} \]

where \(Q_{\text{obs}}(t)\) is the observed flow on day \(t\), \(Q_{\text{sim}}(t)\) is the model's prediction, and \(\bar{Q}_{\text{obs}}\) is the average observed flow. The fraction is the model's squared error divided by the squared error of always guessing the average. Because the errors are squared, days with high flow count much more than days with low flow.

Building the Model

To model the data, we'll use a simplified version of a standard model in hydrology.[][] You'll notice we keep adding new parameters and rules to improve the fit.

Let's start with the simplest possible model: a leaky bucket of water. When it rains, all that water collects in the bucket. Every day, a fraction \(k\) drains from the bucket — that's our flow. Let's simulate this, and fit the \(k\) that best models our data.

Observed and modeled daily flow for water year 2000. The observed flow is near zero until spring, then spikes up to 27 mm/day in May and June. The one-bucket model is a smooth hump between 2 and 6 mm/day all year: too high in winter and late summer, and far below the spring peaks.
The naïve leaky bucket model is very inaccurate.

As you can see from the chart, this model is far too simple. This is the point where a modeler typically adds more rules and parameters in order to better model the data.

Next, we are going to add snow and melting. If today's temperature \(T(t)\) is below a certain temperature \(T_{\text{melt}}\) then instead of rain going into the bucket, we get snow that piles up. When it gets above \(T_{\text{melt}}\), the snow melts at a rate \(M(t)\) in mm/day, set by a melt factor \(f_{\text{melt}}\):

\[ M(t) = f_{\text{melt}} \cdot \left(T(t) - T_{\text{melt}} \right). \]

The warmer it is, the faster the snow melts. When we add snow accumulation and melting to our model according to this rule, the results are much better.

Observed and modeled daily flow for water year 2000. With snow added, the model rises in April and peaks in May and June like the observed flow, but it undershoots the highest peak and adds false bumps of 2 to 4 mm/day in November, December and September.
With snow added, we get a much better fit to the observed data.

The cost is that now we have two new parameters to fit: \(f_{\text{melt}}\), the melting rate constant, and \(T_{\text{melt}}\), the daily mean temperature required for melting.

Until this point we had one leaky bucket with rate \(k\). Now let's try two leaky buckets: one fast-draining, and one slow-draining. Whatever drains out of these is the flow for the creek. We'll also add a third bucket, for the soil at the top.

Splitting the buckets is only a modeling choice: it doesn't tell us about real sections of the groundwater and their drainage times.

Soil and evaporation equations

If \(I(t)\) is the rain plus snowmelt on day \(t\) and \(S_{\text{soil}}(t)\) is the water in the soil, the amount \(F(t)\) that goes to the fast bucket is \[ F(t) = I(t) \cdot \left( \frac{S_{\text{soil}}(t)}{C_{\text{max soil}}} \right)^{\beta}, \] and the remaining \(I(t) - F(t)\) stays in the soil. \(C_{\text{max soil}}\) here is the soil's maximum water capacity. Evaporation and plant use take \[ E(t) = E_{\text{pot}}(t) \cdot \min\left( \frac{S_{\text{soil}}(t)}{f_{\text{LP}} \cdot C_{\text{max soil}}}, 1 \right) \] out of the soil each day, where \(E_{\text{pot}}(t)\) is the maximum evaporation rate. The evaporation threshold can't be more than the soil capacity, so it's written as a fraction \(f_{\text{LP}}\) of it, and \(f_{\text{LP}}\) is the fitted parameter.

The maximum rate \(E_{\text{pot}}\) is given by Hargreaves as \[ E_{\text{pot}}(t) = 0.0023 \cdot R_a(t) \cdot \left( T(t) + 17.8 \right) \cdot \sqrt{T_{\text{max}}(t) - T_{\text{min}}(t) } \] where \(R_a(t)\) is the sunlight energy at the top of the atmosphere at that latitude and time of year, expressed as mm/day of water it could evaporate; \(T(t)\) is the mean temperature that day; \(T_{\text{max}}\) is the high temperature that day; and \(T_{\text{min}}\) is the low temperature that day.

0.0023 and 17.8 aren't fundamental physical constants. 0.0023 combines a coefficient fit to eight years of grass measurements in Davis, California[] with a second fitted coefficient for estimating sunlight from temperature. 17.8 comes from converting the original Fahrenheit equation to Celsius.[]

Now that we added another six parameters, for eight total, is our fit any better?

Observed and modeled daily flow for water year 2000. The model now stays low through winter like the observed flow and matches the timing and rough height of the May and June spikes, but it falls off faster than the observed flow in June.
NSE reaches 0.65 with the new soil bucket, up from 0.53 in the previous model.

There's a noticeable improvement in the fit, especially around the fall and winter.

Choosing Parameters is Machine Learning

I used a technique called differential evolution[] in order to optimize this model. Although we have just 8 parameters instead of billions or trillions like in an LLM, using differential evolution to fit those eight parameters is machine learning.

Here we were able to do machine learning to find good parameters because each simulation takes milliseconds. In climate modeling, for example, each simulation takes so much time that exploring the full parameter space by algorithm is often too expensive, so you have to use slow-motion manual tuning. Tuning parameters is a difficult art and science, requiring expert judgment.[]

Fake Interpretability

You might think that having parameters with a clear physical meaning, like the snow melting temperature, improves the interpretability of the model. But this is often an illusion: parameter values can easily bend to compensate for missing structure in your model.[]

In our model, we constrained the leak rate to a standard range of 0-3 mm/day.[] But all the fits I found above 0.64 NSE pushed it all the way to 3 mm/day. If we remove the constraint, it jumps all the way up to 16 mm/day!

Removing that constraint doesn't overfit: it turned out to improve model performance on drought years, and on held-out years with 20 years of training data. It also shifted values for a lot of the other parameters like soil capacity.

This doesn't mean the real leak rate is that high, or that the new soil capacity is correct. The “leak rate” in our model is really just a parameter that does some math, not a claim on a real-world physical effect. Increasing this parameter happens to model the data better.

Since this kind of compensation is very possible even in a physically motivated model, it can be dangerous to assume the parameters that pop out of your model are “interpretable”. They could be doing math to model very different physical phenomena than what they're meant to represent.

Some Parameter Changes are Invisible

When we fit to the data, we end up with some parameters. But there might be another set of parameters that scores about the same, but has some very different values. We can't tell from the data and the physical model alone whether the parameters match the real-world quantities they're meant to represent.

I picked out some examples that are within 0.01 NSE of the best fit, but have very different parameters.

Top: daily flow for water year 2000, where the lines for sets A, B and C nearly overlap. Bottom: a table of their eight parameters. Melt threshold (1.1 °C), melt factor (2.4) and leak (3.0 mm/day) are the same in all three, and the store half-lives are close. Soil capacity (388, 259 and 233 mm), runoff curve shape β (4.5, 6.0 and 1.2) and the evaporation threshold (388, 78 and 233 mm) differ widely. NSE is 0.65, 0.64 and 0.64.
The best fit model (A) is compared to models B and C, which score almost as well but have very different parameter sets. Some parameters, like melt threshold, are similar in all; others, like runoff curve shape, are on opposite ends of the range.

While these parameter changes don't really affect the NSE score, that doesn't mean they don't matter. The three models behave very differently on the late summer subset of the dataset.

Models A and B are up to 8-11x below observed flow values in the late summer, while C is pretty close. This is almost invisible on the full chart because late summer flow is so small compared to the rest of the year.

Left: daily flow for water year 2000, where sets A, B and C are hard to tell apart. Right: July to September on a log scale, where they separate. Observed flow falls from about 2 to 0.16 mm/day by the end of September. Set C ends at 0.10, while A and B fall steadily to 0.02 and 0.01.
The three fits strongly disagree on late summer even though they have broadly similar performance by our metric. The best by far is actually Model C, not the overall best fit Model A.

Even though model A is up to 8x too low on these months of 2000, it's the best fit. That's because we're optimizing for NSE, which barely cares about data with small absolute values.

Finding Parameter Trade-offs

Once you have your model, how can you tell which parameters aren't very meaningful for the score?

Often, it's not that one parameter is totally useless, but that multiple parameter changes cancel out in a way that leaves the score about the same. There's a mathematical tool that can quantify these trade-offs: the Hessian, which is kind of a multivariable second derivative.

Its eigenvectors are directions in parameter space, and each one's eigenvalue says how fast the score changes as you move that way: a large eigenvalue means the fit pins that direction down, a small one means it can drift without doing much.

The math

We start with our loss \(L\) as function of our parameters, \(\theta\). In this case, \(L(\theta) = -\text{NSE}(\theta) \). What we want to do is find: if we change our parameters by some vector \(\Delta\), how much does the loss change? It would be especially interesting to know which parameter changes have the biggest impact and which have the smallest impact.

Now we define the Hessian. This is a square matrix, where the entries are partial derivatives like

\[ H_{ij} = \frac{\partial^2 L}{\partial \theta_i \, \partial \theta_j}. \]

So if we fill that out for parameters \(\theta_1,\dots,\theta_n\), we get a matrix like

\[ H = \begin{pmatrix} \frac{\partial^2 L}{\partial \theta_1^2} & \frac{\partial^2 L}{\partial \theta_1 \partial \theta_2} & \cdots & \frac{\partial^2 L}{\partial \theta_1 \partial \theta_n} \\ \frac{\partial^2 L}{\partial \theta_2 \partial \theta_1} & \frac{\partial^2 L}{\partial \theta_2^2} & \cdots & \frac{\partial^2 L}{\partial \theta_2 \partial \theta_n} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{\partial^2 L}{\partial \theta_n \partial \theta_1} & \frac{\partial^2 L}{\partial \theta_n \partial \theta_2} & \cdots & \frac{\partial^2 L}{\partial \theta_n^2} \end{pmatrix}. \]

Notice that \(H\) is symmetric: \(H = H^\top\). By the spectral theorem, this means it has real eigenvalues and orthogonal eigenvectors.

Let's use our best fit model as a reference. Since it's the best fit, it's a local minimum for loss, so the loss surface looks like a bowl nearby. It turns out that if we move a distance \(s\) along an eigenvector of this matrix, we can predict the change in loss from its eigenvalue \(\lambda_k\) using Taylor expansion:

\[ \Delta L \approx \tfrac{1}{2} \lambda_k s^2. \]

If we want to find how far we can go in a direction before the loss changes by some small amount, we can solve for \(s_k\).

This tells us something important: once we have the eigenvectors of the Hessian, we know which directions in parameter space the model pins down the most, and which can move around without doing much. A direction that matters a lot for the fit is called “stiff”, while one that's more flexible without changing much is called “sloppy”.[]

In our case, our stiffest eigenvector has \(\lambda_1=43.4\). It's 66% along the melt threshold direction and 34% along melt factor, indicating that these two parameters are similar for all the nearby best fits. We can only adjust the parameters by 2% of their range in this direction before our loss goes up by 0.01.

Meanwhile, the sloppiest eigenvector has \(\lambda_6=0.0115\). This is 91% along the runoff curve shape \(\beta\) direction and 9% along the soil capacity direction, indicating that choosing different values for these two parameters is less impactful for the loss. We can move parameters across the entire range in this direction and barely touch the loss.

And indeed, if we look at the difference between models A and C (both good fit models with very different parameters), the line between them is only 11° off from our sloppiest direction.

A 3D surface of NSE over two directions from the best fit, A. Along the stiffest direction, mostly melt threshold and melt factor, NSE drops steeply on both sides, forming a ridge. Along the line from A to C, mostly runoff curve shape β and soil capacity, the top of the ridge stays nearly level at about 0.65, and the region within 0.01 of A is a long, narrow band that reaches C.
The score slopes sharply downward in the direction of our stiffest eigenvector (adjusting melting parameters) but hardly moves at all on the line from A to C despite large changes in the parameters.

This means that once we have a best fit, it's cheap to use the Hessian eigenvectors to figure out which parameters are vital to a good fit, and which are more loose.

Physics vs ML

Some common claimed advantages for physics models over ML models are:

We saw that the interpretability of a physics model can sometimes be fake, since very different parameter choices can lead to similar accuracy. To see if the generalization claim holds up, I trained a transformer on the same dataset. No three buckets, no leak rate. Just a bitter-lesson-pilled transformer with 67,265 parameters. I trained three independent models and used their ensemble as the ML predictor.

Two line charts against years of training data (5, 10 and 20), each comparing the transformer, the physics model, and the physics model with the leak limit removed. Ordinary years: the transformer rises from 0.53 to 0.74 NSE, while the physics model stays between 0.56 and 0.60, and 0.57 to 0.63 with no leak limit. Drought years: the transformer jumps from 0.12 at 5 years to 0.58 at 10 and 0.54 at 20; the physics model stays near 0.52 and the version with no leak limit near 0.60.
Once we reach 10 years of training data, the transformer ensemble does better than the physics models on ordinary years. It also beats the standard physics model on drought years, but does not beat the physics model with leak limit removed.

With only five years of data, the physics models won on both tests, most clearly on drought years (0.54–0.59 NSE against 0.12 for the transformer). By 10 years the transformer had caught up: it beat both physics models on ordinary years and the standard one on drought years. However, even with 20 years of data, the best drought model overall was the physics model with the leak limit removed.

So how do we choose between physics models and less constrained ML?

If you're working with established physics and no parameters to fit, like Newton's laws, physics is definitely the better choice. You know it works and don't need a dataset.

Sometimes you need a dataset even for established laws, like Ohm's law \(V=IR\) when you don't know the resistance \(R\). Simple linear fits like these are usually helpful, interpretable, and useful for understanding the physics.

In other cases, where you're fitting quite a few parameters and making a lot of assumptions about the underlying physical model, machine learning can be the right choice even if you've found some equations that approximate the system.[] Here, it matched or beat the physics model on ordinary years once it had enough data, though a physics model still did best on drought years. And the physical interpretability of a model might be questionable anyway.

This doesn't apply only to physics either. You can run into the same issues anywhere you're fitting parameters to a mathematical model of something in the real world, like ecology, epidemiology, or some models of biology. If your model has a lot of fitted and unknown parameters, it's worthwhile to treat it as a machine learning model, because that's what it is. This means testing on held out data and edge cases, and comparing to other models of the data even if your initial model works well.

The process of defining assumptions, setting parameters, and measuring results has a lot more in common with machine learning than it seems. In fact, if you automate the parameter search instead of hand-tuning, it is machine learning. So before building a physically motivated model, it's worth checking if it really helps you understand the underlying system, or if you have enough data that you'd get a better result faster by just throwing some machine learning at it.

References

The GitHub for this project is at crackalamoo/blog-demos.

  1. Development of a large-sample watershed-scale hydrometeorological data set for the contiguous USA: data set characteristics and assessment of regional variability in hydrologic model performance (A. J. Newman et al., Hydrology and Earth System Sciences, 2015) ^
  2. Nash–Sutcliffe model efficiency coefficient (Wikipedia) ^
  3. Development and application of a conceptual runoff model for Scandinavian catchments (Sten Bergström, SMHI, 1976) ^
  4. Teaching hydrological modeling with a user-friendly catchment-runoff-model software package (Jan Seibert & Marc Vis, Hydrology and Earth System Sciences, 2012) ^
  5. Crop evapotranspiration: Guidelines for computing crop water requirements (FAO Irrigation and Drainage Paper 56) (Richard G. Allen, Luis S. Pereira, Dirk Raes & Martin Smith, FAO, 1998) ^
  6. Hargreaves Method (HEC-HMS Technical Reference Manual, US Army Corps of Engineers) ^
  7. Evapotranspiration (HEC-HMS User's Manual 4.8, US Army Corps of Engineers) ^
  8. Differential Evolution – A Simple and Efficient Heuristic for Global Optimization over Continuous Spaces (Rainer Storn & Kenneth Price, Journal of Global Optimization, 1997) ^
  9. The Art and Science of Climate Model Tuning (Frédéric Hourdin et al., Bulletin of the American Meteorological Society, 2017) ^
  10. Universally Sloppy Parameter Sensitivities in Systems Biology Models (Ryan N. Gutenkunst et al., PLOS Computational Biology, 2007) ^
  11. Towards learning universal, regional, and local hydrological behaviors via machine learning applied to large-sample datasets (Frederik Kratzert et al., Hydrology and Earth System Sciences, 2019) ^
  12. To bucket or not to bucket? Analyzing the performance and interpretability of hybrid hydrological models with dynamic parameterization (Eduardo Acuña Espinoza et al., Hydrology and Earth System Sciences, 2024) ^

Footnotes