MakeGLMModelHandler.make_model() builds the derived model's GLMOutput with model.dinfo() reused as-is (h2o-algos/src/main/java/hex/api/MakeGLMModelHandler.java:51), including the source's STANDARDIZE transform if the source was trained with standardize=True. The beta passed in a few lines above, however, is always in raw/denormalized coefficient space (line 40-42).
Because GLMOutput.isStandardized() reflects the DataInfo transform, it reports true for a model whose beta isn't actually standardized. Any downstream consumer gated on that flag — e.g. GLMModel.beta(lambda) → DataInfo.denormalizeBeta() — re-scales the already-raw beta a second time, silently producing wrong coefficients with no exception or warning.
Reproduction
- Train any GLM with standardize=True (the default).
- Call the public makeGLMModel API (h2o.makeGLMModel(model, beta) in Python/R, or /3/MakeGLMModel directly) with a custom beta.
- Read derived_model.beta(0.0) (or anything else that consults isStandardized()) — the returned coefficients are wrong.
Context
Found during review of #16838 (GH-16807). That PR fixed the identical bug in the newer, related make_derived_model() endpoint (clone model.dinfo() and reset the transform to NONE before constructing GLMOutput — see MakeGLMModelHandler.java:138-139) but left the older make_model() endpoint with the bug, flagged only by a // KNOWN BUG: code comment (lines 46-50) rather than a fix, since it's out of scope for that PR.
Suggested fix
Apply the same pattern used in make_derived_model(): clone model.dinfo() and call setPredictorTransform(TransformType.NONE) on the clone before constructing GLMOutput in make_model().
MakeGLMModelHandler.make_model() builds the derived model's GLMOutput with model.dinfo() reused as-is (h2o-algos/src/main/java/hex/api/MakeGLMModelHandler.java:51), including the source's STANDARDIZE transform if the source was trained with standardize=True. The beta passed in a few lines above, however, is always in raw/denormalized coefficient space (line 40-42).
Because GLMOutput.isStandardized() reflects the DataInfo transform, it reports true for a model whose beta isn't actually standardized. Any downstream consumer gated on that flag — e.g. GLMModel.beta(lambda) → DataInfo.denormalizeBeta() — re-scales the already-raw beta a second time, silently producing wrong coefficients with no exception or warning.
Reproduction
Context
Found during review of #16838 (GH-16807). That PR fixed the identical bug in the newer, related make_derived_model() endpoint (clone model.dinfo() and reset the transform to NONE before constructing GLMOutput — see MakeGLMModelHandler.java:138-139) but left the older make_model() endpoint with the bug, flagged only by a // KNOWN BUG: code comment (lines 46-50) rather than a fix, since it's out of scope for that PR.
Suggested fix
Apply the same pattern used in make_derived_model(): clone model.dinfo() and call setPredictorTransform(TransformType.NONE) on the clone before constructing GLMOutput in make_model().