TBA
This is somewhat specific to getting setup on Azure at the Turing.
-
Github setup
git config --global user.name <your name> git config --global user.email <your email>
-
Ensure that you have your
HF_TOKENexported to Azure:echo 'export HF_TOKEN=<add HF token here>' >> ~/.bashrc source ~/.bashrc
this ensures that you can download from Hugging Face without being rate-limited (and can use gated models).
-
Install uv (used to manage dependencies for each sub-project below):
curl -LsSf https://astral.sh/uv/install.sh | sh -
Trained/merged models are pulled from the Azure ML model registry rather than committed to git (see Model storage below) — you'll need the Azure CLI with the
mlextension, logged in and scoped to thetire-2workspace:az extension remove -n azure-cli-ml # our Azure currently comes with v1 of azure-cli-ml and this conflicts with the new required ml extension az extension add -n ml az login az configure --defaults group=tire-1 workspace=tire-2Only the
ml(v2) extension is needed — do not also install the legacyazure-cli-mlextension, the two conflict with each other.
-
Clone the repo:
git clone https://github.com/alan-turing-institute/model-merging.git cd model-merging -
If you are on the Turing Azure, then you need to do the symlink trick to make uv fast (as per the TIRE Azure user guide).
mkdir ~/venvs && mkdir ~/venvs/model-merging mkdir ~/venvs/model-merging/train mkdir ~/venvs/model-merging/merge mkdir ~/venvs/model-merging/evaluate
Now make the symlinks from the model-merging directory:
ln –s ~/venvs/model-merging/train train/.venv ln –s ~/venvs/model-merging/merge merge/.venv ln –s ~/venvs/model-merging/evaluate evaluate/.venv
-
This repo isn't one Python project —
train/,merge/, andevaluate/are each a separate uv-managed environment (with different, sometimes conflicting, dependency versions — e.g.merge/needs a patchedtransformersthattrain/doesn't). Sync each one you plan to use:cd train && uv sync && cd .. cd merge && uv sync && cd .. cd evaluate && uv sync && cd ..
Commands in each sub-project's README assume you're running them via that sub-project's environment, e.g.
uv run axolotl train crime_gemma.yamlfrom insidetrain/.
This should be used if you have previously pulled the code from github, but are starting a new compute instance and want to set it up. We assume that you pulled it to Users/ANOther/model-merging.
-
To ensure that git works, go to the
model-mergingdirectory and rungit status
This will fail, claiming dubious ownership of the git repository (your other compute instance), but will suggest that you can add an exception by running a command, eg
git config --global --add safe.directory <your model-merging directory>
which you should run.
-
If you are on the Turing Azure, then you need to do the symlink trick to make uv fast (as per the TIRE Azure user guide). Since you have previously pulled the code, you should have symlinks already, but these will be broken. To check this, you can run
find . -maxdepth 2 -xdev -xtype lYou can then make the directories to where these symlinks already point, eg.
mkdir ~/venvs && mkdir ~/venvs/model-merging mkdir ~/venvs/model-merging/train mkdir ~/venvs/model-merging/merge mkdir ~/venvs/model-merging/evaluate
You do not need to remake the symlinks.
-
A CUDA GPU is required for training/merging/evaluation (this project was developed against both an A100 80GB and a T4 setup) — there's no CPU-only path.
-
To use gated models such as
google/gemma-3-4b-it, you need to accept its license on the model page with your HF account, then authenticate locally sotransformers/axolotlcan download it:uv run --project evaluate huggingface-cli login
-
The root-level prepare_data.py and Convert_to_full_model.py scripts aren't tied to a project of their own — run them with the
evaluateenvironment, which already hasdatasets/transformers/peft:uv run --project evaluate python Convert_to_full_model.py BASE_MODEL LORA_PATH OUTPUT_PATH
prepare_data.py is more ad hoc, since different models expect inputs in different forms (conversational etc.) and also the question asked depends on the task and give dataset. For this, run python in the environment and then copy/paste your own code into it:
uv run --project evaluate python
Overview of the process for a `poor-mans parallelism' model merging to train a classifier:
-
Split your dataset
$D$ into parts$D_i$ - see prepare data python script. -
Train different copies of your base model on the
$D_i$ to produce a LoRA adapter$L_i$ - see train readme. -
Combine the LoRA adapter
$L_i$ with the base model to produce a model$M_i$ - Use the conversion script. This takes as input:-
BASE_MODEL- a HG address, or path to the base model -
LORA_PATH- the path of the LoRA adapter trained in step 3 -
OUTPUT_PATH- an output path for the combined model
It should be run as
uv run --project evaluate python Convert_to_full_model.py BASE_MODEL LORA_PATH OUTPUT_PATH
(The evaluate environment already has some of the required dependencies.)
-
-
Use mergekit to combine the different
$M_i$ into one model$\tilde{M}$ - see merge readme. -
Test performance of
$\tilde{M}$ . - see evaluate readme.
Trained/converted/merged models are large (GBs each) and are not kept in models/ locally or committed to git (models/ is gitignored) — they're registered as Model assets in the tire-2 Azure ML workspace (resource group tire-1), backed by its default blob datastore. Register a new artifact with:
az ml model create --name <name> --version 1 --type custom_model --path <local-path> --resource-group tire-1 --workspace-name tire-2and fetch one back (or pass azureml:<name>:<version> directly to evaluate.py, which downloads automatically) with:
az ml model download --name <name> --version 1 --download-path <dir> --resource-group tire-1 --workspace-name tire-2Current registry name for each pipeline artifact:
| Pipeline artifact | Registered model name |
|---|---|
LoRA adapter trained on the full dataset (crime_gemma.yaml) |
gemma3-crime-full-lora |
LoRA adapter trained on half 1 (crime_gemma1.yaml) |
gemma3-crime-1-of-2-lora |
LoRA adapter trained on half 2 (crime_gemma2.yaml) |
gemma3-crime-2-of-2-lora |
| Full model = full-dataset adapter merged into the base model | gemma3-crime-full |
| Full model = half-1 adapter merged into the base model | gemma3-crime-1-of-2 |
| Full model = half-2 adapter merged into the base model | gemma3-crime-2-of-2 |
| Linear merge of the two half-dataset full models | gemma3-crime-merged-linear-2 |