Skip to main content

Compress multiple PEFT LoRA adapters into a shared subspace using the SHARE method

Project description

lorashare

A Python library that lets you use multiple LoRA adapters with 100x memory savings.

Based on the SHARE paper (Kaushik et al., 2026).

The Key Insight

LoRA adapters trained on different tasks share a common low-rank subspace.

Instead of storing N separate adapters, you can extract the shared principal components through PCA and keep only tiny per-adapter coefficients.

lorashare lets you train your LoRAs and then compress them so you can store several task-specific models with the memory size of one adapter.

Use Cases

Use lorashare if you have:

  • Multiple LoRA adapters (2+)
  • Same base model
  • Same rank
  • Same target modules
  • Want to store them together

Install

pip install lorashare

More on the package: https://pypi.org/project/lorashare/

Quick Start

Python API

from lorashare import SHAREModel

# Compress multiple LoRA adapters into shared subspace
share = SHAREModel.from_adapters(
    ["path/to/cola_lora", "path/to/mrpc_lora", "path/to/rte_lora"],
    num_components=32,  # or "auto" for explained-variance selection
)

# See compression stats
share.summary()

# Reconstruct any adapter as standard PEFT LoRA
share.reconstruct("cola_lora", output_dir="./reconstructed/cola")

# Apply to base model for inference (returns standard PeftModel)
from transformers import AutoModelForSequenceClassification, AutoTokenizer
import torch

base_model = AutoModelForSequenceClassification.from_pretrained("roberta-base")
tokenizer = AutoTokenizer.from_pretrained("roberta-base")
model = share.apply(base_model, adapter_name="cola_lora")

# Run inference with the reconstructed adapter
text = "The movie was fantastic and I really enjoyed it!"
inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=512)

model.eval()
with torch.no_grad():
    outputs = model(**inputs)
    predictions = torch.softmax(outputs.logits, dim=-1)
    print(f"Predictions: {predictions}")

# Save / load
share.save_pretrained("./my_share_checkpoint")
share = SHAREModel.from_pretrained("./my_share_checkpoint")

# Push to HuggingFace Hub
share.push_to_hub("username/my-share-model")

CLI

# Compress
lorashare compress adapter1/ adapter2/ adapter3/ -o ./compressed -k 32

# With GPU acceleration (10-100x faster)
lorashare compress adapter1/ adapter2/ adapter3/ -o ./compressed -k 32 --device cuda

# For large models (reduced memory)
lorashare compress adapter1/ adapter2/ adapter3/ -o ./compressed -k 32 --layer-by-layer

# For 100+ adapters (chunked processing)
lorashare compress adapter1/ ... adapter100/ -o ./compressed -k 32 --chunk-size 10

# Inspect
lorashare info ./compressed

# Reconstruct single adapter
lorashare reconstruct ./compressed --adapter cola -o ./reconstructed

# Reconstruct all
lorashare reconstruct ./compressed --all -o ./reconstructed

Scalability Features (v0.2.0)

# GPU Acceleration (10-100x speedup)
share = SHAREModel.from_adapters(
    adapters,
    num_components=32,
    device="cuda",  # or "cpu" or None for auto
)

# Layer-by-layer processing (70% less memory)
share = SHAREModel.from_adapters(
    adapters,
    num_components=32,
    layer_by_layer=True,  # Process one layer at a time
)

# Chunked loading (enables 100+ adapters)
share = SHAREModel.from_adapters(
    many_adapters,  # 100+ adapters
    num_components=32,
    chunk_size=10,  # Process 10 at a time
)

# Combine features
share = SHAREModel.from_adapters(
    many_adapters,
    num_components=32,
    device="cuda",
    chunk_size=10,
)

From HuggingFace Hub

share = SHAREModel.from_adapters(
    ["org/cola_lora", "org/mrpc_lora", "org/rte_lora"],
    num_components="auto",
    variance_threshold=0.95,
)

How It Works

For each layer and side (A/B) across all adapters:

  1. Stack all adapters' LoRA weights into a matrix
  2. Center and compute covariance
  3. Eigendecompose via torch.linalg.eigh to find principal components
  4. Project each adapter onto the top-k components to get compact loadings
  5. Reconstruct on demand: original ~= components @ loadings

Classifier Heads: Task-specific output layers (e.g., classifier.weight, classifier.bias) are automatically separated during compression and stored alongside each adapter's loadings. During reconstruction, they're merged back in, so reconstructed adapters work immediately for inference without additional setup.

Memory Savings

6 LoRA adapters SHARE (k=32)
Storage 6 x full adapter 1 shared basis + 6 tiny loadings
Params per layer 6 x (r x d) 1 x (k x d) + 6 x (k x r)
Example (d=768, r=8) 73,728 52,224 (1.4x)
Example (d=768, r=8, N=100) 1,228,800 74,752 (16x)

Savings increase with more adapters. The paper reports 281x savings with 6 GLUE tasks.

Save Format

checkpoint/
  share_config.json              # Compression metadata
  shared_components.safetensors  # Shared PCA basis vectors
  adapters/
    cola/
      loadings.safetensors         # Per-adapter projections (tiny)
      classifier_head.safetensors  # Task-specific classifier heads (if present)
      adapter_meta.json            # Original PEFT config
    mrpc/
      loadings.safetensors
      classifier_head.safetensors
      adapter_meta.json

Note: Task-specific classifier heads (like classifier.weight) are automatically preserved and merged back during reconstruction, ensuring reconstructed adapters can do inference immediately.

Requirements

  • Python >= 3.9
  • PyTorch >= 1.13
  • peft >= 0.6.0
  • transformers >= 4.30.0
  • safetensors >= 0.3.0

Logging

Enable progress logging to see what's happening:

import logging
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')

from lorashare import SHAREModel
share = SHAREModel.from_adapters(adapters, num_components=32)
# INFO: Loading 3 adapters...
# INFO: Validating adapter compatibility...
# INFO: Grouping weights by layer...
# INFO: Computing shared components (k=32)...
# INFO: Selected 32 components
# INFO: Computing per-adapter loadings...

Use logging.DEBUG for more detailed output (per-adapter progress).

API Reference

SHAREModel.from_adapters(adapters, num_components=32, variance_threshold=0.95)

Compress multiple PEFT LoRA adapters. Accepts local paths or HuggingFace Hub IDs.

  • adapters: list[str] or dict[str, str] (name -> path mapping)
  • num_components: int or "auto" for explained-variance selection
  • variance_threshold: target explained variance when using "auto" (default 0.95)

SHAREModel.from_pretrained(path)

Load a saved SHARE checkpoint.

share.reconstruct(adapter_name, output_dir=None)

Reconstruct a single adapter's LoRA weights. Optionally save as standard PEFT format.

share.apply(base_model, adapter_name)

Reconstruct and apply adapter to a base model. Returns a standard peft.PeftModel.

share.save_pretrained(output_dir)

Save SHARE checkpoint to disk.

share.summary()

Print compression statistics.

share.reconstruction_error(adapter_name, original_weights=None, original_path=None)

Compute per-layer reconstruction error (relative Frobenius norm).

Citation

@article{kaushik2026share,
  title={Shared LoRA Subspaces for Almost Strict Continual Learning},
  author={Kaushik, Prakhar and Vaidya, Ankit and Chaudhari, Shravan and Chellappa, Rama and Yuille, Alan},
  journal={arXiv preprint arXiv:2602.06043},
  year={2026}
}

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lorashare-0.1.2.tar.gz (37.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lorashare-0.1.2-py3-none-any.whl (23.5 kB view details)

Uploaded Python 3

File details

Details for the file lorashare-0.1.2.tar.gz.

File metadata

  • Download URL: lorashare-0.1.2.tar.gz
  • Upload date:
  • Size: 37.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lorashare-0.1.2.tar.gz
Algorithm Hash digest
SHA256 f2cbc2f5b9c92f934292358d5010ef9b95b12e7e7ec51ef9f28e1b08f2bd83a4
MD5 ec0dda2742bd4c5e48ae678fa95cfe0b
BLAKE2b-256 9cbaf1e501bf95e1c0b0eade6ec02a74ef8a1de55df70c2d6b21334e2daede83

See more details on using hashes here.

Provenance

The following attestation bundles were made for lorashare-0.1.2.tar.gz:

Publisher: publish.yml on ronantakizawa/lorashare

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lorashare-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: lorashare-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 23.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lorashare-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 ec4ccdb7dc5353859d37265130298cfdceb04b3f8ad5f51b93fae12423804dab
MD5 6a4697de3e44593dfc38e19a4edee647
BLAKE2b-256 d033057d55d74e0ab13fe9f02b73b6c0da7f79e9e23916e94754bce25f0011c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for lorashare-0.1.2-py3-none-any.whl:

Publisher: publish.yml on ronantakizawa/lorashare

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page