MLJFlux.jl
repository·dev·Indexed 41 days ago
https://github.com/fluxml/mljflux.jlAn interface that integrates Flux deep learning models into the MLJ machine learning framework, enabling standardized workflows for deep learning in Julia. The library provides support for architecture search, model composition, entity embeddings, hyperparameter tuning, incremental training, and live training.
What's inside MLJFlux
- MLJFlux.jl provides an interface to Flux deep learning models within the MLJ machine learning framework. It allows users to leverage the power of Flux for deep learning while using the standardized MLJ API for model loading, training, and evaluation.
What is MLJFlux and how does it work?
devMLJFlux.jl is an interface that connects the MLJ machine learning toolbox with the Flux.jl deep learning framework in Julia. It allows users to implement supervised deep learning models using the Flux syntax while adhering to the standard MLJ workflow.
Key Capabilities:
- MLJ Workflow Integration: Write models in Flux and use them with MLJ's model specification, including preprocessing pipelines and tuning.
- Warm Restarting: Implements the MLJ warm restart interface, allowing you to resume training from a previous state when modifying hyperparameters like the number of epochs or optimizer settings (e.g., learning rate).
- IteratedModel Support: Because MLJFlux models can be wrapped as MLJ
IteratedModels, you gain access to advanced training controls such as early stopping, model snapshots, callbacks, and cyclic learning rates. - Hardware Flexibility: Provides options to train models on different hardware configurations.
How warm restarts and incremental training work in MLJFlux
devMLJ machines cache state, allowing for "warm restarts" of model training. When calling
fit!(mach), a warm restart is automatically used if:- Only
model.epochshas changed since the last call. - Only
model.epochsormodel.optimiserhave changed, ANDmodel.optimiser_changes_trigger_retraining == false(the default). This allows you to dynamically modify learning rates without losing learned weights.
Note that the "state" part of the optimiser is ignored in the comparison for the second condition. You can access the associated MLJ model via
model = mach.model.- Only
How iteration controls work with MLJFlux models
devIterative
MLJFluxmodels can be wrapped usingMLJ.IteratedModelto implement sophisticated stopping criteria and monitoring. This is useful for preventing overfitting or stopping when training plateaus.Common Controls:
Step(n): Apply checks everynepochs.Patience(n): Stop afternconsecutive increases in loss.InvalidValue(): Stop if loss becomesNaNorInf.TimeLimit(t): Stop afterttime has elapsed.Save(path, predicate=n): Save a snapshot of the machine everyncontrol cycles.WithLossDo(callback): Execute a callback with the current loss.WithTrainingLossesDo(callback): Execute a callback with the current training loss.WithIterationsDo(callback): Execute a callback with the current epoch number.
Workflow:
- Define a list of
controls. - Wrap your classifier:
iterated_clf = IteratedModel(clf, controls=controls, ...). - Create a machine with the wrapped model and call
fit!.
using MLJ using MLJIteration # Example controls setup controls = [ Step(2), Patience(3), InvalidValue(), TimeLimit(5/60), MLJIteration.skip(Save(joinpath(tempdir(), "mnist.jls")), predicate=3), WithLossDo(update_loss), WithTrainingLossesDo(update_training_loss), WithIterationsDo(update_epochs) ] # Wrap the classifier iterated_clf = IteratedModel( clf, controls=controls, resampling=Holdout(fraction_train=0.7), measure=log_loss, ) # Train the wrapped model mach = machine(iterated_clf, images, labels) fit!(mach, rows=train)Handle Data Orientation (Rows vs Columns) for MLJFlux
devMLJ follows the convention that rows = observations. However, Flux (the underlying engine) uses the opposite convention (columns = observations).
If your data is a matrix where the column index represents the observation, you must present the
adjointortransposeof your matrix to MLJFlux models to ensure correct training. You can also usepermutedimsto transform the matrix before passing it to the model.How to wrap Flux models in MLJFlux containers
devTo use a Flux model within the MLJ ecosystem, you must wrap the neural network architecture in one of the four provided MLJFlux containers.
Each container uses a
builderattribute to define the neural network architecture (the Flux model) based on the shape of the input data. The containers are categorized by the type of task:- Deterministic models: Derived from
MLJModelInterface.Deterministic. - Probabilistic models: Derived from
MLJModelInterface.Probabilistic.
By wrapping your Flux model, you can specify hyperparameters such as the loss function, optimizer, and number of epochs, making the deep learning model behave like any other standard MLJ model.
- Deterministic models: Derived from
Use EntityEmbedder to transform categorical features for non-neural MLJ models
devMost MLJFlux models support categorical features by learning entity embeddings. To use these learned embeddings in standard MLJ pipelines—specifically for supervised models that are not neural networks and require features to be of type
Continuous—wrap your MLJFlux model withMLJFlux.EntityEmbedder. This allows the embeddings to function as transformer elements within an MLJ pipeline.# Wrap an MLJFlux model to use its learned embeddings as continuous features in an MLJ pipeline wrapped_model = MLJFlux.EntityEmbedder(mljflux_model)Access incremental training examples and notebooks
devThe
incremental_trainingdirectory contains various formats of the incremental training workflow for testing and demonstration purposes:- Jupyter Notebooks:
notebook.ipynb(executed) andnotebook.unexecuted.ipynb(unexecuted) for interactive exploration. - Static Documentation:
notebook.mdwhich is integrated into the official MLJFlux.jl documentation. - Julia Scripts:
notebook.jlwhich is an executable Julia script containing annotated comments explaining the workflow.
Note: To execute these scripts or notebooks, you must have the project environment configured. The required
Manifest.tomlandProject.tomlfiles are located at../../../docs/relative to this directory.# To run the executable script version: include("notebook.jl")- Jupyter Notebooks:
Perform Hyperparameter Tuning with MLJFlux
devTo tune hyperparameters in MLJFlux, you can use the
TunedModelconstructor from MLJ. This involves defining hyperparameter ranges using therangefunction, specifying a tuning strategy (likeGrid), and a resampling method (likeCVfor cross-validation).Note that MLJFlux models often require data to be in
Float32format for compatibility with Flux.jl. When defining ranges for optimisers, you should pass instances of optimisers (e.g., from theOptimisers.jlpackage) rather than just learning rate scalars.# 1. Instantiate the model NeuralNetworkClassifier = @load NeuralNetworkClassifier pkg=MLJFlux clf = NeuralNetworkClassifier( builder=MLJFlux.MLP(; hidden=(5,4), σ=Flux.relu), optimiser=Optimisers.Adam(0.01), batch_size=8, epochs=10, rng=stable_rng(), ) # 2. Define hyperparameter ranges r1 = range(clf, :batch_size, lower=1, upper=64) etas = [10^x for x in range(-4, stop=0, length=4)] optimisers = [Optimisers.Adam(eta) for eta in etas] r2 = range(clf, :optimiser, values=optimisers) # 3. Create the TunedModel tuned_model = TunedModel( model=clf, tuning=Grid(goal=25), resampling=CV(nfolds=5, rng=stable_rng()), range=[r1, r2], measure=cross_entropy, ) # 4. Fit the machine mach = machine(tuned_model, X, y) fit!(mach, verbosity=0) # 5. Access the best model best_model = fitted_params(mach).best_modelSetup requirements for MLJFlux incremental training
devWhen working with MLJFlux for incremental training, ensure you have the following packages imported. Note that
Optimisers.jlshould be used instead of the nativeFlux.jloptimisers, as the latter are no longer supported.Required imports:
MLJ: To access MLJFlux models.Flux: For model flexibility (e.g., activation functions).Optimisers: For model optimisers.StableRNGs: To ensure reproducibility across Julia versions.
using MLJ # Has MLJFlux models using Flux # For more flexibility import Optimisers # native Flux.jl optimisers no longer supported using StableRNGs # for reproducibility across Julia versions stable_rng() = StableRNGs.StableRNG(123)Access entity embedding workflow examples
devThe entity embeddings workflow is demonstrated through several file formats in the
docs/src/common_workflows/entity_embeddings/directory. You can use the following files to understand and implement the workflow:notebook.ipynb: An executed Jupyter notebook showing the full workflow results.notebook.unexecuted.ipynb: An unexecuted Jupyter notebook for local experimentation.notebook.md: A static markdown version included in the official MLJFlux.jl documentation.notebook.jl: An executable Julia script containing annotated code comments for step-by-step execution.
Execute MNIST example scripts and notebooks
devTo ensure the MNIST examples execute reliably, you must include the accompanying
Manifest.tomlandProject.tomlfiles in your environment. This ensures all dependency versions match the environment for which the examples were written.Available files in this directory:
notebook.ipynb: An executed Jupyter notebook.notebook.unexecuted.ipynb: An unexecuted Jupyter notebook.notebook.md: Static markdown version of the notebook.notebook.jl: An executable Julia script with annotated comments.