Skip to content

add serialization features to be able to robustly load and save models - #102

Closed
ericphanson wants to merge 7 commits into
JuliaStats:masterfrom
ericphanson:eph/add-serialization
Closed

add serialization features to be able to robustly load and save models#102
ericphanson wants to merge 7 commits into
JuliaStats:masterfrom
ericphanson:eph/add-serialization

Conversation

@ericphanson

@ericphanson ericphanson commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

to use Lasso.jl for my use cases, I need to be able to persist trained models and run inference later with them.

This PR adds:

  • InferenceModel: a struct that stores only the essential information needed to predict from a model
    • this can be constructed from another model or from a Dict
  • to_dict: turn an InferenceModel into a Dict in a stable way, for serialization

and a package extension for JSON.jl, so if the user also loads JSON.jl, then they can use write_json, and read_json to simply load/save models.


I have seen various ways model serialization can go wrong in the past and have tried to make a simple and robust system for it to work here.

For example:

  • don't use "generic" serialization like BSON/JLD2/Serialization etc that attempts to save the entire type hierarchy / in-memory julia representation, because if the types change (new package version), even internal details, deserialization will fail. Instead, extract the key values in basic Dict/Vector/etc types that are robust.
  • don't use nameof or printed representation of Julia objects (show, print, etc), because that may change in non-breaking package or julia versions
  • the semantics of the serialized format are different from that of the package. The package can move around internal fields, rename them, etc, and its fine as long as the public API is stable. The serialized format typically cannot, otherwise old models can't be deserialized. So it helps to have an indirection step, which here is done by to_dict and InferenceModel(d::Dict) because those bits can be modified to preserve compatibility as needed. I.e. if we add a field or remove a field in InferenceModel, we can modify InferenceModel(d::Dict) and to_dict at the same time to preserve compatibility, because we have this extra bit of indirection.
  • add a test to check old models can still be deserialized and give same results

I have not added a serialization_format key to the dictionary or similar. If we do need to support multiple formats, we can add that later, and the absence of the key can be interpreted as v1. I think for now it is unnecessary complexity and probably we won't need multiple incompatible formats anyway.


cowritten with claude sonnet 5

>In the case where one wants to use an extension (without worrying about the feature of the extension being available on older Julia versions) while still supporting older Julia versions without workspace support, the packages under [weakdeps] should be duplicated into [extras]. This is an unfortunate duplication, but without doing this the project verifier under older Julia versions will throw an error if it finds packages under [compat] that is not listed in [extras].
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.44444% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.10%. Comparing base (0fed8fb) to head (c5bcb15).
⚠️ Report is 15 commits behind head on master.

Files with missing lines Patch % Lines
src/inference_model.jl 92.85% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #102      +/-   ##
==========================================
+ Coverage   86.94%   92.10%   +5.15%     
==========================================
  Files           8       10       +2     
  Lines        1218     1203      -15     
==========================================
+ Hits         1059     1108      +49     
+ Misses        159       95      -64     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AsafManela

Copy link
Copy Markdown
Collaborator

Thanks for this.

  1. seems like a test is failing.
  2. more importantly, a selected segment of a Lasso model is effectively a GLM, no? If so, perhaps the best place for the InferenceModel is in GLM.jl? Does GLM.jl not have something like this to avoid the memory footprint?

@ericphanson

ericphanson commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Yeah, this isn't really specific to Lasso.jl at all, and I don't think GLM has it. But I will just use this code internally in my project. It is here if someone wants to adopt it.

(test failure was unrelated I believe)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants