Parent: apr-spec.md §4
Status: Active
CLI: apr merge
Implementation: crates/apr-cli/src/commands/merge.rs
Library: aprender::format::apr_merge
Model merging combines multiple trained models into a single model by interpolating weights in parameter space. This is the fastest way to create a new capable model without any training compute.
Goal: Full parity with MergeKit plus sovereign-native features (APR format, SIMD acceleration, offline-only).
apr merge <FILE1> <FILE2> [FILE3...] \
--strategy <STRATEGY> \
--output <PATH> \
[--weights <W1,W2,...>] \
[--base-model <PATH>] \
[--drop-rate <0.0-1.0>] \
[--density <0.0-1.0>] \
[--seed <N>] \
[--config <YAML>] \
[--plan] \
[--parallel] \
[--layer-config <YAML>]
Simple arithmetic mean of all model weights. No base model required.
apr merge model-a.apr model-b.apr --strategy average -o merged.aprUser-specified per-model weights. Must sum to ~1.0 (warning if not).
apr merge model-a.apr model-b.apr --strategy weighted --weights 0.7,0.3 -o merged.aprSmooth interpolation on the unit hypersphere. Only 2 models. First weight is
interpolation factor t (default 0.5).
apr merge model-a.apr model-b.apr --strategy slerp --weights 0.3 -o merged.aprComputes task vectors (delta from base model), trims small values, resolves
sign conflicts by majority vote, then merges. Requires --base-model.
apr merge model-a.apr model-b.apr --strategy ties \
--base-model base.apr --density 0.2 -o merged.aprRandomly drops elements of task vectors with probability --drop-rate, then
rescales remaining values. Combines with TIES sign election.
apr merge model-a.apr model-b.apr --strategy dare \
--base-model base.apr --drop-rate 0.9 --seed 42 -o merged.aprLinear combination of task vectors: θ_merged = θ_base + Σ λ_i * (θ_i - θ_base).
Simplest task vector method. Foundation for TIES, DARE, DELLA, Breadcrumbs.
CLI:
apr merge model-a.apr model-b.apr --strategy task-arithmetic \
--base-model base.apr --weights 0.5,0.5 -o merged.aprComplexity: Low — subtract base, scale, add.
Enhanced SLERP with optimized numerical stability and support for batch processing. Handles degenerate cases (near-parallel vectors) more gracefully.
CLI:
apr merge model-a.apr model-b.apr --strategy nuslerp --weights 0.3 -o merged.aprBarycentric SLERP for >2 models. Iteratively applies SLERP along barycentric coordinates in the weight simplex.
CLI:
apr merge a.apr b.apr c.apr --strategy multi-slerp --weights 0.4,0.3,0.3 -o merged.aprTask arithmetic with adaptive per-parameter pruning based on magnitude. Parameters with larger task-vector magnitude are retained with higher probability. More principled than DARE's uniform random drop.
CLI:
apr merge a.apr b.apr --strategy della \
--base-model base.apr --drop-rate 0.7 -o merged.aprReference: Extends DARE with magnitude-aware retention.
Task arithmetic with outlier removal: trims both very small AND very large parameter deltas (unlike TIES which only trims small). Retains the "moderate signal" range.
CLI:
apr merge a.apr b.apr --strategy breadcrumbs \
--base-model base.apr --density 0.2 --trim-top 0.01 -o merged.aprAdaptive matrix-level weighting based on parameter variance across models. High-variance parameters (where models disagree) get different treatment than low-variance (consensus) parameters.
CLI:
apr merge a.apr b.apr c.apr --strategy sce -o merged.aprComplexity: Medium — requires variance computation per parameter matrix.
Direct tensor copy for layer stacking. Combines layers from different models into a single model (e.g., layers 0-15 from model A, layers 16-31 from model B). No interpolation — pure surgical assembly.
CLI:
apr merge a.apr b.apr --strategy passthrough \
--layer-config franken.yaml -o merged.aprConfig (franken.yaml):
slices:
- model: model-a.apr
layers: [0, 16]
- model: model-b.apr
layers: [16, 32]CMA-ES optimization of merge config parameters (strategy, weights, density, drop_rate) against evaluation benchmarks. Requires eval harness integration.
CLI:
apr merge evolve \
--config evolve.yaml \
--eval-tasks hellaswag,winogrande \
--budget 50 \
--seed 42 \
-o best-merge.aprConfig (evolve.yaml):
models:
- path: model-a.apr
- path: model-b.apr
base_model: base.apr
strategies: [ties, dare, della]
search_space:
density: [0.1, 0.5]
drop_rate: [0.5, 0.95]
weights: [[0.3, 0.7], [0.7, 0.3]]Complexity: High — requires eval harness + CMA-ES optimizer.
Combine N dense models into a Mixture-of-Experts architecture. Each model becomes an expert. Adds a router layer trained on calibration data.
CLI:
apr merge moe \
--experts model-a.apr model-b.apr model-c.apr model-d.apr \
--router-data calibration.jsonl \
--num-experts-per-token 2 \
--output-format mixtral \
-o moe-model.aprComplexity: High — requires router training + architecture transformation.
Trainable per-column merge coefficients. Uses gradient descent on a small calibration dataset to learn optimal per-parameter merge weights.
CLI:
apr merge dam \
model-a.apr model-b.apr \
--base-model base.apr \
--data calibration.jsonl \
--dam-epochs 5 \
--dam-lr 0.01 \
-o merged.aprComplexity: Medium-High — requires forward pass through merged model.
Transplant tokenizers between models. Required for speculative decoding where the draft model must share vocabulary with the target model.
CLI:
apr merge tokenizer-transplant \
--source source-model.apr \
--target target-model.apr \
--align-embeddings \
-o target-with-new-tokenizer.aprSpecify different merge strategies or weights per layer or layer group.
CLI:
apr merge a.apr b.apr --strategy slerp \
--layer-config per-layer.yaml -o merged.aprConfig:
default:
strategy: slerp
weight: 0.5
layers:
"0-8": { weight: 0.3 } # Early layers: favor model A
"24-31": { weight: 0.8 } # Late layers: favor model B
"self_attn": { weight: 0.6 }
"mlp": { weight: 0.4 }Parallelize merge operations across GPUs. Near-linear speedup for large models.
apr merge a.apr b.apr --strategy ties --parallel --gpus 0,1,2,3 -o merged.aprFull merge specification in YAML for reproducibility and CI integration.
apr merge --config merge-config.yaml -o merged.aprAll merge operations validate:
- Input model compatibility (architecture, tensor shapes, vocab size)
- Weight count/sum constraints
- Output model integrity (100-point quality score)
- Plan mode for dry-run estimation
- Unit tests for each strategy with known-good reference outputs
- Property tests: merge(A, B, t=0) ≈ A, merge(A, B, t=1) ≈ B
- Roundtrip: merge → eval → assert quality within tolerance
- Mutation testing: >80% mutation score on merge logic
Extends lora-algebra-v1.yaml which already covers task vectors and DARE.
metadata:
description: "Model merging — weight-space interpolation strategies"
references:
- "Wortsman et al. (2022) Model Soups"
- "Yadav et al. (2023) TIES-Merging"
- "Yu et al. (2023) DARE"
depends_on:
- "lora-algebra-v1"
- "tensor-shape-flow-v1"
equations:
weighted_average:
formula: "θ_merged = Σ w_i * θ_i"
invariants:
- "Σ w_i = 1 (normalization)"
- "w_i >= 0 (non-negative weights)"
- "shape(θ_merged) == shape(θ_i)"
slerp:
formula: "SLERP(A, B, t) = sin((1-t)Ω)/sin(Ω) * A + sin(tΩ)/sin(Ω) * B"
invariants:
- "t=0 → output = A"
- "t=1 → output = B"
- "||output|| interpolates between ||A|| and ||B||"
ties_merge:
formula: "trim(δ) → elect_sign(δ) → disjoint_merge(δ)"
invariants:
- "Only top-density fraction of task vector retained"
- "Sign conflicts resolved by majority vote"
- "Requires base model for task vector computation"
proof_obligations:
- type: invariant
property: "SLERP boundary t=0"
formal: "slerp(A, B, 0) == A"
- type: invariant
property: "SLERP boundary t=1"
formal: "slerp(A, B, 1) == B"
- type: invariant
property: "Shape preservation"
formal: "shape(merge(models)) == shape(models[0])"
- type: invariant
property: "Weight non-negativity"
formal: "∀ w_i in weighted_merge: w_i >= 0"
- type: invariant
property: "TIES requires base"
formal: "ties without base_model → validation error"
falsification_tests:
- id: FALSIFY-MCORE-001
rule: "SLERP boundary t=0"
prediction: "slerp(A, B, 0.0) == A within ULP"
if_fails: "SLERP formula or degenerate case bug"
- id: FALSIFY-MCORE-002
rule: "SLERP boundary t=1"
prediction: "slerp(A, B, 1.0) == B within ULP"
if_fails: "SLERP formula or boundary handling bug"
- id: FALSIFY-MCORE-003
rule: "Shape preservation"
prediction: "merged model has same tensor shapes as inputs"
if_fails: "Accumulation or reshape bug"
- id: FALSIFY-MCORE-004
rule: "Negative weight rejection"
prediction: "negative weight returns validation error"
if_fails: "Weight validation missing"
- id: FALSIFY-MCORE-005
rule: "TIES base model required"
prediction: "ties without --base-model returns error"
if_fails: "Base model check missing for TIES strategy"
kani_harnesses:
- id: KANI-MCORE-001
obligation: "Shape preservation"
property: "output shape == input shape for bounded dims"
bound: 8
strategy: exhaustive - contract: merge-core-v1.yaml
equation: weighted_average
module_path: "aprender::format::apr_merge"
function: merge_weighted
status: implemented
- contract: merge-core-v1.yaml
equation: slerp
module_path: "aprender::format::apr_merge"
function: merge_slerp
status: implemented
- contract: merge-core-v1.yaml
equation: ties_merge
module_path: "aprender::format::apr_merge"
function: merge_ties
status: implemented