Repository files navigation

GPart

End-to-End Isometric Fine-Tuning via Global Parameter Partitioning

PaperPythonLicense: Apache 2.0PEFT

Official implementation of the paper
"GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Authors:Paolo Mandica, Michał Brzozowski, Zuzanna Dubanowska, Neo Christopher Chung
Samsung AI Center, Warsaw, Poland

PaperInstallationQuick StartCitation

GPart is implemented following the standard interface of the 🤗 Hugging Face Parameter-Efficient Fine-Tuning (PEFT) library and is fully compatible with PEFT.


Teaser

GPart is a parameter-efficient fine-tuning method that removes the low-rank bottleneck entirely.
Instead of factorizing updates as in LoRA-style approaches, GPart optimizes a $d$-dimensional vector and maps it directly into the full model weight space through a single global partition generated from a random seed.

Diagram 1

This yields a fine-tuning pipeline with:

  • End-to-end isometry in the trainable subspace.
  • A single clean capacity hyperparameter: d.
  • Minimal storage cost: the trainable vector plus one seed.

Diagram 2


Table of contents


Overview

GPart is a parameter-efficient fine-tuning (PEFT) method introduced in the paper
“GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning.”

The method is built on a simple idea: instead of constraining updates through a low-rank matrix parameterization, optimize a low-dimensional vector $\theta_d \in \mathbb{R}^d$ and map it directly into the full weight space using a global partition matrix $P$:

$$ \Delta W = P\theta_d $$

The paper motivates this formulation by arguing that low-rank adapters distort geometry through bilinear reconstruction, while GPart preserves distances in the trainable subspace and offers a cleaner parameterization for PEFT.


Why GPart

Compared with low-rank PEFT methods, GPart is designed to be structurally simpler and more direct.

  • No low-rank bottleneck: updates are not reconstructed through a bilinear factorization.
  • End-to-end isometric mapping: the trainable subspace preserves Euclidean geometry.
  • Minimal state: the adapter can be reconstructed from the trainable vector and a random seed.
  • One main capacity knob: d controls the size of the trainable subspace.

This repository contains the code used to evaluate GPart on:

  • Natural language understanding with RoBERTa on GLUE.
  • Computer vision with ViT on multiple image classification benchmarks.
  • Mathematical reasoning with decoder-only LLMs fine-tuned on MetaMathQA and evaluated on GSM8K and MATH.

Installation

This repository uses uv for dependency and environment management.

uv sync
source .venv/bin/activate

Quick start

RoBERTa on GLUE

# RoBERTa-base with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart
# RoBERTa-large with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart --model_size large
# Selected tasks with a fixed seed
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--tasks sst2 qnli \
--seed 123
# Parameter count only
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--compute_params_only

Command-Line Overrides

Override default hyperparameters directly from the command line. Arguments after the main flags are captured as key-value pairs:

python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
adapter.d 16384 \
adapter.isometric False \
training.lr 0.001 \
training.head_lr 0.002 \
training.batch_size 16

Aggregate Results

python src/scripts/glue/collect_results_glue.py logs/roberta_glue_gpart

Configuration System

This project uses a dataclass-based configuration system — no YAML files. All configs are Python dataclasses with type safety, IDE autocomplete, and a single source of truth. Adding a new field to any config class automatically propagates everywhere without manual updates.

Config Hierarchy

Values are resolved with the following precedence (later overrides earlier):

1. Dataclass defaults ← Python default values in the dataclass definition
2. Adapter-specific configs ← Pre-defined instances per adapter type (e.g., GPART_BASE_CONFIG)
3. Task-specific configs ← Per-adapter, per-task overrides (e.g., epochs=60 for SST2)
4. Model-size configs ← Large-model variants when --model_size large (e.g., GPART_LARGE_CONFIG)
5. CLI overrides ← Key-value pairs after the main flags

Assignment Backends

For the standard GPart partition projection with grouping_strategy="random", choose the random-assignment backend that fits the available memory budget:

BackendTrade-offUse when
materializedSlightly faster, but stores a persistent group ID for every adapted parameter. Its extra memory grows with the number of adapted weights.Memory is available and you want the fastest assignment lookup.
stateless (default)Recomputes group IDs deterministically from proj_seed and global parameter position. It has no persistent per-parameter assignment buffer, with a small compute cost.Fine-tuning large models or minimizing adapter memory overhead.

Select a backend with a CLI override:

python src/scripts/math/finetune_metamath.py \
--adapter_type gpart \
adapter.assignment_backend stateless

stateless is supported only with grouping_strategy="random". Deprecated aliases legacy_streaming and implicit_stateless_v1 remain accepted with a FutureWarning; use materialized and stateless in new configurations.

Config Structure

The central object is ExperimentConfig, which composes three sub-configs:

@dataclassclassExperimentConfig:
adapter: AdapterConfig# Adapter hyperparameters (d, r, dropout, etc.)training: TrainingConfig# Training hyperparameters (lr, batch_size, etc.)task_metadata: dict# Dataset info, metrics, num_labels per tasktask_configs: dict# Task-specific overrides per adapter

TrainingConfig controls the training loop:

FieldDefaultDescription
batch_size32Training batch size
max_seq_length512Maximum sequence length
weight_decay0.1Weight decay for regularization
warmup_ratio0.06Fraction of steps for LR warmup
model_selection"best"Model selection strategy (see below)
lr1e-3Base learning rate (overridden by task configs)
head_lr1e-3Learning rate for classifier head

AdapterConfig is the base class extended by each adapter type. Each subclass adds its own fields (e.g., d for GPart, r and alpha for LoRA). Fields are automatically included in logging and serialization — no manual listing needed.

TaskConfig provides per-task overrides that take precedence over training defaults:

FieldDescription
epochsNumber of training epochs for this task
lrTask-specific base learning rate
head_lrTask-specific head learning rate
batch_sizeTask-specific batch size

Model Size Awareness

When you pass --model_size large, the system selects:

  1. Large adapter instance — e.g., GPART_LARGE_CONFIG instead of GPART_BASE_CONFIG
  2. Large task configs — e.g., GPART_LARGE_TASK_CONFIGS with different epochs/lrs (if defined)

Adding a New Adapter

  1. Create a config file in src/configs/adapter_configs/:
# src/configs/adapter_configs/my_adapter.pyfromdataclassesimportdataclass, fieldfromtypingimportDict, Listfromconfigs.base_configimportAdapterConfig, TaskConfig@dataclassclassMyAdapterConfig(AdapterConfig):
type: str="my_adapter"my_param: int=42MY_ADAPTER_BASE_CONFIG=MyAdapterConfig()
MY_ADAPTER_LARGE_CONFIG=MyAdapterConfig(my_param=84)
MY_ADAPTER_TASK_CONFIGS: Dict[str, TaskConfig] = { ... }
  1. Register it in src/configs/adapter_configs/__init__.py:
from .my_adapterimportMyAdapterConfig, MY_ADAPTER_BASE_CONFIG, ...
ADAPTER_CONFIG_REGISTRY["my_adapter"] = {
"config_class": MyAdapterConfig,
"base": MY_ADAPTER_BASE_CONFIG,
"large": MY_ADAPTER_LARGE_CONFIG,
"task_configs": MY_ADAPTER_TASK_CONFIGS,
}
  1. It's readymy_adapter automatically appears in --adapter_type choices and ALLOWED_ADAPTERS.

Two Config Layers

The system has two separate configuration layers:

LayerClassPurpose
Experiment configGPARTConfig(AdapterConfig)What experiment to run (defaults, task overrides)
PEFT configGPartConfig(PeftConfig)How to construct the adapter model

The get_peft_config() function in src/utils/adapter_utils.py bridges them — it renames fields (e.g., dropoutgpart_dropout), adds PEFT-specific fields, and constructs the GPartConfig object that get_peft_model() expects. This separation keeps the experiment system decoupled from PEFT library internals.


ViT on vision benchmarks

Supported datasets:

  • cifar10
  • cifar100
  • fgvc
  • flowers102
  • eurosat
  • resisc45
  • oxfordpets
  • standfordcars
  • dtd

Data preparation

All datasets are downloaded automatically by the finetuning script, except dtd, which must be manually downloaded from the DTD website.

After downloading, extract the archive into the data/ directory. The expected structure is:

data/
└── dtd/
├── images/
├── imdb/
└── labels/

Run experiments

# ViT-Base on FGVC Aircraft
python src/scripts/vision/finetune_ViT.py --dataset fgvc --model_size base
# ViT-Large on CIFAR-100
python src/scripts/vision/finetune_ViT.py --dataset cifar100 --model_size large
# Custom optimization settings
python src/scripts/vision/finetune_ViT.py \
--dataset flowers102 \
--model_size base \
--head_lr 5e-3 \
--base_lr 6e-3 \
--num_train_epochs 30

Aggregate multi-seed results:

python src/scripts/vision/collect_results_ViT.py

LLMs on MetaMathQA

Supported base models include:

  • google/gemma-7b
  • Qwen/Qwen2.5-0.5B
  • Qwen/Qwen2.5-3B
  • Qwen/Qwen2.5-7B
  • meta-llama/Llama-3.1-8B
# Qwen2.5-0.5B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072
# Qwen2.5-7B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-7B \
--adapter_type gpart \
--d 524288
# With custom training settings
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--learning_rate 2e-4

Evaluation on GSM8K and MATH

# Base model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--dataset gsm8k
# GPart fine-tuned model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--adapter_path logs/metamath_qwen-qwen2.5-0.5b_gpart_d131072_drop0.05_lr0.0002_bs4_ga4_ep2_seq2048_nosysprompt_seed42_131k \
--dataset math

Integrating GPart into Your Project

To use GPart in your own repository, follow these steps:

Step 1: Copy the PEFT folder

Copy the peft folder from this repository into your project:

# From your project root
cp -r /path/to/GPart/peft .

Step 2: Configure uv for local PEFT

If you're using uv for dependency management, you can configure it to use the local PEFT copy instead of downloading from PyPI. Add the following to your pyproject.toml:

# Add peft to the dependenciesdependencies = [
"peft"
]
# Add the peft local path as source
[tool.uv.sources]
peft = { path = "peft", editable = true }

This tells uv to use the local peft package from the specified path.

Step 3: Import and use GPart

Once the PEFT folder is in your project, you can use GPart just like any other PEFT adapter:

importtorchfromtransformersimportAutoModelForCausalLMfrompeftimportTaskType, get_peft_modelfrompeft.tuners.gpartimportGPartConfig# 1. Define the GPart adapter configurationadapter_config=GPartConfig(
d=131072, # Capacity parameter (adjust for your use case)target_modules=["q_proj", "v_proj"], # Modules to adapttask_type=TaskType.CAUSAL_LM, # Task type (CAUSAL_LM, SEQ_CLS, etc.)
)
# 2. Load your base modelmodel=AutoModelForCausalLM.from_pretrained(
args.model_name,
trust_remote_code=True,
torch_dtype=torch_dtype,
)
# 3. Wrap the model with GPart adaptermodel=get_peft_model(model, adapter_config)
# 4. Train as usual with your preferred training loop# The model now has GPart adapters injected and ready for training

Reproducibility

For reproducible results:

  • Run multiple seeds for each setting.
  • Track the model checkpoint, task, and d.
  • Preserve the random seed used for partition generation.
  • Use the provided result collection scripts for final aggregation.

Because the GPart adapter is reconstructed from the trainable vector and the partition seed, the seed is part of the effective model state.


Contributing

We welcome contributions! This repository uses a fork-based workflow — fork the repo, create a branch, and submit a pull request.

Quick summary:

  1. Fork the repository
  2. Create a branch in your fork for each feature/experiment
  3. Format your code with Black before submitting
  4. Submit a Pull Request when you're ready to merge into main
  5. PR review required — at least one approval before merging

See CONTRIBUTING.md for the complete guide including setup instructions, branch naming conventions, and PR templates.

Branch Protection

The main branch is protected:

  • ✅ No direct pushes — all changes via pull requests only
  • ✅ At least 1 approving review required
  • ✅ Branch must be up to date before merging
  • ✅ No force pushes allowed

Citation

If you use this repository in academic work, please cite:

@misc{mandica2026gpart,
title={GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning}, author={Paolo Mandica and Michał Brzozowski and Zuzanna Dubanowska and Neo Christopher Chung},
year={2026},
eprint={2605.14841},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.14841}, }

License

This project is licensed under the Apache-2.0 License.

About

Official implementation of the paper "GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

GPart

End-to-End Isometric Fine-Tuning via Global Parameter Partitioning

PaperPythonLicense: Apache 2.0PEFT

Official implementation of the paper
"GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Authors:Paolo Mandica, Michał Brzozowski, Zuzanna Dubanowska, Neo Christopher Chung
Samsung AI Center, Warsaw, Poland

PaperInstallationQuick StartCitation

GPart is implemented following the standard interface of the 🤗 Hugging Face Parameter-Efficient Fine-Tuning (PEFT) library and is fully compatible with PEFT.


Teaser

GPart is a parameter-efficient fine-tuning method that removes the low-rank bottleneck entirely.
Instead of factorizing updates as in LoRA-style approaches, GPart optimizes a $d$-dimensional vector and maps it directly into the full model weight space through a single global partition generated from a random seed.

Diagram 1

This yields a fine-tuning pipeline with:

  • End-to-end isometry in the trainable subspace.
  • A single clean capacity hyperparameter: d.
  • Minimal storage cost: the trainable vector plus one seed.

Diagram 2


Table of contents


Overview

GPart is a parameter-efficient fine-tuning (PEFT) method introduced in the paper
“GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning.”

The method is built on a simple idea: instead of constraining updates through a low-rank matrix parameterization, optimize a low-dimensional vector $\theta_d \in \mathbb{R}^d$ and map it directly into the full weight space using a global partition matrix $P$:

$$ \Delta W = P\theta_d $$

The paper motivates this formulation by arguing that low-rank adapters distort geometry through bilinear reconstruction, while GPart preserves distances in the trainable subspace and offers a cleaner parameterization for PEFT.


Why GPart

Compared with low-rank PEFT methods, GPart is designed to be structurally simpler and more direct.

  • No low-rank bottleneck: updates are not reconstructed through a bilinear factorization.
  • End-to-end isometric mapping: the trainable subspace preserves Euclidean geometry.
  • Minimal state: the adapter can be reconstructed from the trainable vector and a random seed.
  • One main capacity knob: d controls the size of the trainable subspace.

This repository contains the code used to evaluate GPart on:

  • Natural language understanding with RoBERTa on GLUE.
  • Computer vision with ViT on multiple image classification benchmarks.
  • Mathematical reasoning with decoder-only LLMs fine-tuned on MetaMathQA and evaluated on GSM8K and MATH.

Installation

This repository uses uv for dependency and environment management.

uv sync
source .venv/bin/activate

Quick start

RoBERTa on GLUE

# RoBERTa-base with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart
# RoBERTa-large with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart --model_size large
# Selected tasks with a fixed seed
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--tasks sst2 qnli \
--seed 123
# Parameter count only
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--compute_params_only

Command-Line Overrides

Override default hyperparameters directly from the command line. Arguments after the main flags are captured as key-value pairs:

python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
adapter.d 16384 \
adapter.isometric False \
training.lr 0.001 \
training.head_lr 0.002 \
training.batch_size 16

Aggregate Results

python src/scripts/glue/collect_results_glue.py logs/roberta_glue_gpart

Configuration System

This project uses a dataclass-based configuration system — no YAML files. All configs are Python dataclasses with type safety, IDE autocomplete, and a single source of truth. Adding a new field to any config class automatically propagates everywhere without manual updates.

Config Hierarchy

Values are resolved with the following precedence (later overrides earlier):

1. Dataclass defaults ← Python default values in the dataclass definition
2. Adapter-specific configs ← Pre-defined instances per adapter type (e.g., GPART_BASE_CONFIG)
3. Task-specific configs ← Per-adapter, per-task overrides (e.g., epochs=60 for SST2)
4. Model-size configs ← Large-model variants when --model_size large (e.g., GPART_LARGE_CONFIG)
5. CLI overrides ← Key-value pairs after the main flags

Assignment Backends

For the standard GPart partition projection with grouping_strategy="random", choose the random-assignment backend that fits the available memory budget:

BackendTrade-offUse when
materializedSlightly faster, but stores a persistent group ID for every adapted parameter. Its extra memory grows with the number of adapted weights.Memory is available and you want the fastest assignment lookup.
stateless (default)Recomputes group IDs deterministically from proj_seed and global parameter position. It has no persistent per-parameter assignment buffer, with a small compute cost.Fine-tuning large models or minimizing adapter memory overhead.

Select a backend with a CLI override:

python src/scripts/math/finetune_metamath.py \
--adapter_type gpart \
adapter.assignment_backend stateless

stateless is supported only with grouping_strategy="random". Deprecated aliases legacy_streaming and implicit_stateless_v1 remain accepted with a FutureWarning; use materialized and stateless in new configurations.

Config Structure

The central object is ExperimentConfig, which composes three sub-configs:

@dataclassclassExperimentConfig:
adapter: AdapterConfig# Adapter hyperparameters (d, r, dropout, etc.)training: TrainingConfig# Training hyperparameters (lr, batch_size, etc.)task_metadata: dict# Dataset info, metrics, num_labels per tasktask_configs: dict# Task-specific overrides per adapter

TrainingConfig controls the training loop:

FieldDefaultDescription
batch_size32Training batch size
max_seq_length512Maximum sequence length
weight_decay0.1Weight decay for regularization
warmup_ratio0.06Fraction of steps for LR warmup
model_selection"best"Model selection strategy (see below)
lr1e-3Base learning rate (overridden by task configs)
head_lr1e-3Learning rate for classifier head

AdapterConfig is the base class extended by each adapter type. Each subclass adds its own fields (e.g., d for GPart, r and alpha for LoRA). Fields are automatically included in logging and serialization — no manual listing needed.

TaskConfig provides per-task overrides that take precedence over training defaults:

FieldDescription
epochsNumber of training epochs for this task
lrTask-specific base learning rate
head_lrTask-specific head learning rate
batch_sizeTask-specific batch size

Model Size Awareness

When you pass --model_size large, the system selects:

  1. Large adapter instance — e.g., GPART_LARGE_CONFIG instead of GPART_BASE_CONFIG
  2. Large task configs — e.g., GPART_LARGE_TASK_CONFIGS with different epochs/lrs (if defined)

Adding a New Adapter

  1. Create a config file in src/configs/adapter_configs/:
# src/configs/adapter_configs/my_adapter.pyfromdataclassesimportdataclass, fieldfromtypingimportDict, Listfromconfigs.base_configimportAdapterConfig, TaskConfig@dataclassclassMyAdapterConfig(AdapterConfig):
type: str="my_adapter"my_param: int=42MY_ADAPTER_BASE_CONFIG=MyAdapterConfig()
MY_ADAPTER_LARGE_CONFIG=MyAdapterConfig(my_param=84)
MY_ADAPTER_TASK_CONFIGS: Dict[str, TaskConfig] = { ... }
  1. Register it in src/configs/adapter_configs/__init__.py:
from .my_adapterimportMyAdapterConfig, MY_ADAPTER_BASE_CONFIG, ...
ADAPTER_CONFIG_REGISTRY["my_adapter"] = {
"config_class": MyAdapterConfig,
"base": MY_ADAPTER_BASE_CONFIG,
"large": MY_ADAPTER_LARGE_CONFIG,
"task_configs": MY_ADAPTER_TASK_CONFIGS,
}
  1. It's readymy_adapter automatically appears in --adapter_type choices and ALLOWED_ADAPTERS.

Two Config Layers

The system has two separate configuration layers:

LayerClassPurpose
Experiment configGPARTConfig(AdapterConfig)What experiment to run (defaults, task overrides)
PEFT configGPartConfig(PeftConfig)How to construct the adapter model

The get_peft_config() function in src/utils/adapter_utils.py bridges them — it renames fields (e.g., dropoutgpart_dropout), adds PEFT-specific fields, and constructs the GPartConfig object that get_peft_model() expects. This separation keeps the experiment system decoupled from PEFT library internals.


ViT on vision benchmarks

Supported datasets:

  • cifar10
  • cifar100
  • fgvc
  • flowers102
  • eurosat
  • resisc45
  • oxfordpets
  • standfordcars
  • dtd

Data preparation

All datasets are downloaded automatically by the finetuning script, except dtd, which must be manually downloaded from the DTD website.

After downloading, extract the archive into the data/ directory. The expected structure is:

data/
└── dtd/
├── images/
├── imdb/
└── labels/

Run experiments

# ViT-Base on FGVC Aircraft
python src/scripts/vision/finetune_ViT.py --dataset fgvc --model_size base
# ViT-Large on CIFAR-100
python src/scripts/vision/finetune_ViT.py --dataset cifar100 --model_size large
# Custom optimization settings
python src/scripts/vision/finetune_ViT.py \
--dataset flowers102 \
--model_size base \
--head_lr 5e-3 \
--base_lr 6e-3 \
--num_train_epochs 30

Aggregate multi-seed results:

python src/scripts/vision/collect_results_ViT.py

LLMs on MetaMathQA

Supported base models include:

  • google/gemma-7b
  • Qwen/Qwen2.5-0.5B
  • Qwen/Qwen2.5-3B
  • Qwen/Qwen2.5-7B
  • meta-llama/Llama-3.1-8B
# Qwen2.5-0.5B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072
# Qwen2.5-7B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-7B \
--adapter_type gpart \
--d 524288
# With custom training settings
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--learning_rate 2e-4

Evaluation on GSM8K and MATH

# Base model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--dataset gsm8k
# GPart fine-tuned model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--adapter_path logs/metamath_qwen-qwen2.5-0.5b_gpart_d131072_drop0.05_lr0.0002_bs4_ga4_ep2_seq2048_nosysprompt_seed42_131k \
--dataset math

Integrating GPart into Your Project

To use GPart in your own repository, follow these steps:

Step 1: Copy the PEFT folder

Copy the peft folder from this repository into your project:

# From your project root
cp -r /path/to/GPart/peft .

Step 2: Configure uv for local PEFT

If you're using uv for dependency management, you can configure it to use the local PEFT copy instead of downloading from PyPI. Add the following to your pyproject.toml:

# Add peft to the dependenciesdependencies = [
"peft"
]
# Add the peft local path as source
[tool.uv.sources]
peft = { path = "peft", editable = true }

This tells uv to use the local peft package from the specified path.

Step 3: Import and use GPart

Once the PEFT folder is in your project, you can use GPart just like any other PEFT adapter:

importtorchfromtransformersimportAutoModelForCausalLMfrompeftimportTaskType, get_peft_modelfrompeft.tuners.gpartimportGPartConfig# 1. Define the GPart adapter configurationadapter_config=GPartConfig(
d=131072, # Capacity parameter (adjust for your use case)target_modules=["q_proj", "v_proj"], # Modules to adapttask_type=TaskType.CAUSAL_LM, # Task type (CAUSAL_LM, SEQ_CLS, etc.)
)
# 2. Load your base modelmodel=AutoModelForCausalLM.from_pretrained(
args.model_name,
trust_remote_code=True,
torch_dtype=torch_dtype,
)
# 3. Wrap the model with GPart adaptermodel=get_peft_model(model, adapter_config)
# 4. Train as usual with your preferred training loop# The model now has GPart adapters injected and ready for training

Reproducibility

For reproducible results:

  • Run multiple seeds for each setting.
  • Track the model checkpoint, task, and d.
  • Preserve the random seed used for partition generation.
  • Use the provided result collection scripts for final aggregation.

Because the GPart adapter is reconstructed from the trainable vector and the partition seed, the seed is part of the effective model state.


Contributing

We welcome contributions! This repository uses a fork-based workflow — fork the repo, create a branch, and submit a pull request.

Quick summary:

  1. Fork the repository
  2. Create a branch in your fork for each feature/experiment
  3. Format your code with Black before submitting
  4. Submit a Pull Request when you're ready to merge into main
  5. PR review required — at least one approval before merging

See CONTRIBUTING.md for the complete guide including setup instructions, branch naming conventions, and PR templates.

Branch Protection

The main branch is protected:

  • ✅ No direct pushes — all changes via pull requests only
  • ✅ At least 1 approving review required
  • ✅ Branch must be up to date before merging
  • ✅ No force pushes allowed

Citation

If you use this repository in academic work, please cite:

@misc{mandica2026gpart,
title={GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning}, author={Paolo Mandica and Michał Brzozowski and Zuzanna Dubanowska and Neo Christopher Chung},
year={2026},
eprint={2605.14841},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.14841}, }

License

This project is licensed under the Apache-2.0 License.

About

Official implementation of the paper "GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

GPart

End-to-End Isometric Fine-Tuning via Global Parameter Partitioning

PaperPythonLicense: Apache 2.0PEFT

Official implementation of the paper
"GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Authors:Paolo Mandica, Michał Brzozowski, Zuzanna Dubanowska, Neo Christopher Chung
Samsung AI Center, Warsaw, Poland

PaperInstallationQuick StartCitation

GPart is implemented following the standard interface of the 🤗 Hugging Face Parameter-Efficient Fine-Tuning (PEFT) library and is fully compatible with PEFT.


Teaser

GPart is a parameter-efficient fine-tuning method that removes the low-rank bottleneck entirely.
Instead of factorizing updates as in LoRA-style approaches, GPart optimizes a $d$-dimensional vector and maps it directly into the full model weight space through a single global partition generated from a random seed.

Diagram 1

This yields a fine-tuning pipeline with:

  • End-to-end isometry in the trainable subspace.
  • A single clean capacity hyperparameter: d.
  • Minimal storage cost: the trainable vector plus one seed.

Diagram 2


Table of contents


Overview

GPart is a parameter-efficient fine-tuning (PEFT) method introduced in the paper
“GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning.”

The method is built on a simple idea: instead of constraining updates through a low-rank matrix parameterization, optimize a low-dimensional vector $\theta_d \in \mathbb{R}^d$ and map it directly into the full weight space using a global partition matrix $P$:

$$ \Delta W = P\theta_d $$

The paper motivates this formulation by arguing that low-rank adapters distort geometry through bilinear reconstruction, while GPart preserves distances in the trainable subspace and offers a cleaner parameterization for PEFT.


Why GPart

Compared with low-rank PEFT methods, GPart is designed to be structurally simpler and more direct.

  • No low-rank bottleneck: updates are not reconstructed through a bilinear factorization.
  • End-to-end isometric mapping: the trainable subspace preserves Euclidean geometry.
  • Minimal state: the adapter can be reconstructed from the trainable vector and a random seed.
  • One main capacity knob: d controls the size of the trainable subspace.

This repository contains the code used to evaluate GPart on:

  • Natural language understanding with RoBERTa on GLUE.
  • Computer vision with ViT on multiple image classification benchmarks.
  • Mathematical reasoning with decoder-only LLMs fine-tuned on MetaMathQA and evaluated on GSM8K and MATH.

Installation

This repository uses uv for dependency and environment management.

uv sync
source .venv/bin/activate

Quick start

RoBERTa on GLUE

# RoBERTa-base with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart
# RoBERTa-large with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart --model_size large
# Selected tasks with a fixed seed
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--tasks sst2 qnli \
--seed 123
# Parameter count only
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--compute_params_only

Command-Line Overrides

Override default hyperparameters directly from the command line. Arguments after the main flags are captured as key-value pairs:

python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
adapter.d 16384 \
adapter.isometric False \
training.lr 0.001 \
training.head_lr 0.002 \
training.batch_size 16

Aggregate Results

python src/scripts/glue/collect_results_glue.py logs/roberta_glue_gpart

Configuration System

This project uses a dataclass-based configuration system — no YAML files. All configs are Python dataclasses with type safety, IDE autocomplete, and a single source of truth. Adding a new field to any config class automatically propagates everywhere without manual updates.

Config Hierarchy

Values are resolved with the following precedence (later overrides earlier):

1. Dataclass defaults ← Python default values in the dataclass definition
2. Adapter-specific configs ← Pre-defined instances per adapter type (e.g., GPART_BASE_CONFIG)
3. Task-specific configs ← Per-adapter, per-task overrides (e.g., epochs=60 for SST2)
4. Model-size configs ← Large-model variants when --model_size large (e.g., GPART_LARGE_CONFIG)
5. CLI overrides ← Key-value pairs after the main flags

Assignment Backends

For the standard GPart partition projection with grouping_strategy="random", choose the random-assignment backend that fits the available memory budget:

BackendTrade-offUse when
materializedSlightly faster, but stores a persistent group ID for every adapted parameter. Its extra memory grows with the number of adapted weights.Memory is available and you want the fastest assignment lookup.
stateless (default)Recomputes group IDs deterministically from proj_seed and global parameter position. It has no persistent per-parameter assignment buffer, with a small compute cost.Fine-tuning large models or minimizing adapter memory overhead.

Select a backend with a CLI override:

python src/scripts/math/finetune_metamath.py \
--adapter_type gpart \
adapter.assignment_backend stateless

stateless is supported only with grouping_strategy="random". Deprecated aliases legacy_streaming and implicit_stateless_v1 remain accepted with a FutureWarning; use materialized and stateless in new configurations.

Config Structure

The central object is ExperimentConfig, which composes three sub-configs:

@dataclassclassExperimentConfig:
adapter: AdapterConfig# Adapter hyperparameters (d, r, dropout, etc.)training: TrainingConfig# Training hyperparameters (lr, batch_size, etc.)task_metadata: dict# Dataset info, metrics, num_labels per tasktask_configs: dict# Task-specific overrides per adapter

TrainingConfig controls the training loop:

FieldDefaultDescription
batch_size32Training batch size
max_seq_length512Maximum sequence length
weight_decay0.1Weight decay for regularization
warmup_ratio0.06Fraction of steps for LR warmup
model_selection"best"Model selection strategy (see below)
lr1e-3Base learning rate (overridden by task configs)
head_lr1e-3Learning rate for classifier head

AdapterConfig is the base class extended by each adapter type. Each subclass adds its own fields (e.g., d for GPart, r and alpha for LoRA). Fields are automatically included in logging and serialization — no manual listing needed.

TaskConfig provides per-task overrides that take precedence over training defaults:

FieldDescription
epochsNumber of training epochs for this task
lrTask-specific base learning rate
head_lrTask-specific head learning rate
batch_sizeTask-specific batch size

Model Size Awareness

When you pass --model_size large, the system selects:

  1. Large adapter instance — e.g., GPART_LARGE_CONFIG instead of GPART_BASE_CONFIG
  2. Large task configs — e.g., GPART_LARGE_TASK_CONFIGS with different epochs/lrs (if defined)

Adding a New Adapter

  1. Create a config file in src/configs/adapter_configs/:
# src/configs/adapter_configs/my_adapter.pyfromdataclassesimportdataclass, fieldfromtypingimportDict, Listfromconfigs.base_configimportAdapterConfig, TaskConfig@dataclassclassMyAdapterConfig(AdapterConfig):
type: str="my_adapter"my_param: int=42MY_ADAPTER_BASE_CONFIG=MyAdapterConfig()
MY_ADAPTER_LARGE_CONFIG=MyAdapterConfig(my_param=84)
MY_ADAPTER_TASK_CONFIGS: Dict[str, TaskConfig] = { ... }
  1. Register it in src/configs/adapter_configs/__init__.py:
from .my_adapterimportMyAdapterConfig, MY_ADAPTER_BASE_CONFIG, ...
ADAPTER_CONFIG_REGISTRY["my_adapter"] = {
"config_class": MyAdapterConfig,
"base": MY_ADAPTER_BASE_CONFIG,
"large": MY_ADAPTER_LARGE_CONFIG,
"task_configs": MY_ADAPTER_TASK_CONFIGS,
}
  1. It's readymy_adapter automatically appears in --adapter_type choices and ALLOWED_ADAPTERS.

Two Config Layers

The system has two separate configuration layers:

LayerClassPurpose
Experiment configGPARTConfig(AdapterConfig)What experiment to run (defaults, task overrides)
PEFT configGPartConfig(PeftConfig)How to construct the adapter model

The get_peft_config() function in src/utils/adapter_utils.py bridges them — it renames fields (e.g., dropoutgpart_dropout), adds PEFT-specific fields, and constructs the GPartConfig object that get_peft_model() expects. This separation keeps the experiment system decoupled from PEFT library internals.


ViT on vision benchmarks

Supported datasets:

  • cifar10
  • cifar100
  • fgvc
  • flowers102
  • eurosat
  • resisc45
  • oxfordpets
  • standfordcars
  • dtd

Data preparation

All datasets are downloaded automatically by the finetuning script, except dtd, which must be manually downloaded from the DTD website.

After downloading, extract the archive into the data/ directory. The expected structure is:

data/
└── dtd/
├── images/
├── imdb/
└── labels/

Run experiments

# ViT-Base on FGVC Aircraft
python src/scripts/vision/finetune_ViT.py --dataset fgvc --model_size base
# ViT-Large on CIFAR-100
python src/scripts/vision/finetune_ViT.py --dataset cifar100 --model_size large
# Custom optimization settings
python src/scripts/vision/finetune_ViT.py \
--dataset flowers102 \
--model_size base \
--head_lr 5e-3 \
--base_lr 6e-3 \
--num_train_epochs 30

Aggregate multi-seed results:

python src/scripts/vision/collect_results_ViT.py

LLMs on MetaMathQA

Supported base models include:

  • google/gemma-7b
  • Qwen/Qwen2.5-0.5B
  • Qwen/Qwen2.5-3B
  • Qwen/Qwen2.5-7B
  • meta-llama/Llama-3.1-8B
# Qwen2.5-0.5B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072
# Qwen2.5-7B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-7B \
--adapter_type gpart \
--d 524288
# With custom training settings
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--learning_rate 2e-4

Evaluation on GSM8K and MATH

# Base model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--dataset gsm8k
# GPart fine-tuned model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--adapter_path logs/metamath_qwen-qwen2.5-0.5b_gpart_d131072_drop0.05_lr0.0002_bs4_ga4_ep2_seq2048_nosysprompt_seed42_131k \
--dataset math

Integrating GPart into Your Project

To use GPart in your own repository, follow these steps:

Step 1: Copy the PEFT folder

Copy the peft folder from this repository into your project:

# From your project root
cp -r /path/to/GPart/peft .

Step 2: Configure uv for local PEFT

If you're using uv for dependency management, you can configure it to use the local PEFT copy instead of downloading from PyPI. Add the following to your pyproject.toml:

# Add peft to the dependenciesdependencies = [
"peft"
]
# Add the peft local path as source
[tool.uv.sources]
peft = { path = "peft", editable = true }

This tells uv to use the local peft package from the specified path.

Step 3: Import and use GPart

Once the PEFT folder is in your project, you can use GPart just like any other PEFT adapter:

importtorchfromtransformersimportAutoModelForCausalLMfrompeftimportTaskType, get_peft_modelfrompeft.tuners.gpartimportGPartConfig# 1. Define the GPart adapter configurationadapter_config=GPartConfig(
d=131072, # Capacity parameter (adjust for your use case)target_modules=["q_proj", "v_proj"], # Modules to adapttask_type=TaskType.CAUSAL_LM, # Task type (CAUSAL_LM, SEQ_CLS, etc.)
)
# 2. Load your base modelmodel=AutoModelForCausalLM.from_pretrained(
args.model_name,
trust_remote_code=True,
torch_dtype=torch_dtype,
)
# 3. Wrap the model with GPart adaptermodel=get_peft_model(model, adapter_config)
# 4. Train as usual with your preferred training loop# The model now has GPart adapters injected and ready for training

Reproducibility

For reproducible results:

  • Run multiple seeds for each setting.
  • Track the model checkpoint, task, and d.
  • Preserve the random seed used for partition generation.
  • Use the provided result collection scripts for final aggregation.

Because the GPart adapter is reconstructed from the trainable vector and the partition seed, the seed is part of the effective model state.


Contributing

We welcome contributions! This repository uses a fork-based workflow — fork the repo, create a branch, and submit a pull request.

Quick summary:

  1. Fork the repository
  2. Create a branch in your fork for each feature/experiment
  3. Format your code with Black before submitting
  4. Submit a Pull Request when you're ready to merge into main
  5. PR review required — at least one approval before merging

See CONTRIBUTING.md for the complete guide including setup instructions, branch naming conventions, and PR templates.

Branch Protection

The main branch is protected:

  • ✅ No direct pushes — all changes via pull requests only
  • ✅ At least 1 approving review required
  • ✅ Branch must be up to date before merging
  • ✅ No force pushes allowed

Citation

If you use this repository in academic work, please cite:

@misc{mandica2026gpart,
title={GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning}, author={Paolo Mandica and Michał Brzozowski and Zuzanna Dubanowska and Neo Christopher Chung},
year={2026},
eprint={2605.14841},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.14841}, }

License

This project is licensed under the Apache-2.0 License.

About

Official implementation of the paper "GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

GPart

End-to-End Isometric Fine-Tuning via Global Parameter Partitioning

PaperPythonLicense: Apache 2.0PEFT

Official implementation of the paper
"GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Authors:Paolo Mandica, Michał Brzozowski, Zuzanna Dubanowska, Neo Christopher Chung
Samsung AI Center, Warsaw, Poland

PaperInstallationQuick StartCitation

GPart is implemented following the standard interface of the 🤗 Hugging Face Parameter-Efficient Fine-Tuning (PEFT) library and is fully compatible with PEFT.


Teaser

GPart is a parameter-efficient fine-tuning method that removes the low-rank bottleneck entirely.
Instead of factorizing updates as in LoRA-style approaches, GPart optimizes a $d$-dimensional vector and maps it directly into the full model weight space through a single global partition generated from a random seed.

Diagram 1

This yields a fine-tuning pipeline with:

  • End-to-end isometry in the trainable subspace.
  • A single clean capacity hyperparameter: d.
  • Minimal storage cost: the trainable vector plus one seed.

Diagram 2


Table of contents


Overview

GPart is a parameter-efficient fine-tuning (PEFT) method introduced in the paper
“GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning.”

The method is built on a simple idea: instead of constraining updates through a low-rank matrix parameterization, optimize a low-dimensional vector $\theta_d \in \mathbb{R}^d$ and map it directly into the full weight space using a global partition matrix $P$:

$$ \Delta W = P\theta_d $$

The paper motivates this formulation by arguing that low-rank adapters distort geometry through bilinear reconstruction, while GPart preserves distances in the trainable subspace and offers a cleaner parameterization for PEFT.


Why GPart

Compared with low-rank PEFT methods, GPart is designed to be structurally simpler and more direct.

  • No low-rank bottleneck: updates are not reconstructed through a bilinear factorization.
  • End-to-end isometric mapping: the trainable subspace preserves Euclidean geometry.
  • Minimal state: the adapter can be reconstructed from the trainable vector and a random seed.
  • One main capacity knob: d controls the size of the trainable subspace.

This repository contains the code used to evaluate GPart on:

  • Natural language understanding with RoBERTa on GLUE.
  • Computer vision with ViT on multiple image classification benchmarks.
  • Mathematical reasoning with decoder-only LLMs fine-tuned on MetaMathQA and evaluated on GSM8K and MATH.

Installation

This repository uses uv for dependency and environment management.

uv sync
source .venv/bin/activate

Quick start

RoBERTa on GLUE

# RoBERTa-base with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart
# RoBERTa-large with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart --model_size large
# Selected tasks with a fixed seed
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--tasks sst2 qnli \
--seed 123
# Parameter count only
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--compute_params_only

Command-Line Overrides

Override default hyperparameters directly from the command line. Arguments after the main flags are captured as key-value pairs:

python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
adapter.d 16384 \
adapter.isometric False \
training.lr 0.001 \
training.head_lr 0.002 \
training.batch_size 16

Aggregate Results

python src/scripts/glue/collect_results_glue.py logs/roberta_glue_gpart

Configuration System

This project uses a dataclass-based configuration system — no YAML files. All configs are Python dataclasses with type safety, IDE autocomplete, and a single source of truth. Adding a new field to any config class automatically propagates everywhere without manual updates.

Config Hierarchy

Values are resolved with the following precedence (later overrides earlier):

1. Dataclass defaults ← Python default values in the dataclass definition
2. Adapter-specific configs ← Pre-defined instances per adapter type (e.g., GPART_BASE_CONFIG)
3. Task-specific configs ← Per-adapter, per-task overrides (e.g., epochs=60 for SST2)
4. Model-size configs ← Large-model variants when --model_size large (e.g., GPART_LARGE_CONFIG)
5. CLI overrides ← Key-value pairs after the main flags

Assignment Backends

For the standard GPart partition projection with grouping_strategy="random", choose the random-assignment backend that fits the available memory budget:

BackendTrade-offUse when
materializedSlightly faster, but stores a persistent group ID for every adapted parameter. Its extra memory grows with the number of adapted weights.Memory is available and you want the fastest assignment lookup.
stateless (default)Recomputes group IDs deterministically from proj_seed and global parameter position. It has no persistent per-parameter assignment buffer, with a small compute cost.Fine-tuning large models or minimizing adapter memory overhead.

Select a backend with a CLI override:

python src/scripts/math/finetune_metamath.py \
--adapter_type gpart \
adapter.assignment_backend stateless

stateless is supported only with grouping_strategy="random". Deprecated aliases legacy_streaming and implicit_stateless_v1 remain accepted with a FutureWarning; use materialized and stateless in new configurations.

Config Structure

The central object is ExperimentConfig, which composes three sub-configs:

@dataclassclassExperimentConfig:
adapter: AdapterConfig# Adapter hyperparameters (d, r, dropout, etc.)training: TrainingConfig# Training hyperparameters (lr, batch_size, etc.)task_metadata: dict# Dataset info, metrics, num_labels per tasktask_configs: dict# Task-specific overrides per adapter

TrainingConfig controls the training loop:

FieldDefaultDescription
batch_size32Training batch size
max_seq_length512Maximum sequence length
weight_decay0.1Weight decay for regularization
warmup_ratio0.06Fraction of steps for LR warmup
model_selection"best"Model selection strategy (see below)
lr1e-3Base learning rate (overridden by task configs)
head_lr1e-3Learning rate for classifier head

AdapterConfig is the base class extended by each adapter type. Each subclass adds its own fields (e.g., d for GPart, r and alpha for LoRA). Fields are automatically included in logging and serialization — no manual listing needed.

TaskConfig provides per-task overrides that take precedence over training defaults:

FieldDescription
epochsNumber of training epochs for this task
lrTask-specific base learning rate
head_lrTask-specific head learning rate
batch_sizeTask-specific batch size

Model Size Awareness

When you pass --model_size large, the system selects:

  1. Large adapter instance — e.g., GPART_LARGE_CONFIG instead of GPART_BASE_CONFIG
  2. Large task configs — e.g., GPART_LARGE_TASK_CONFIGS with different epochs/lrs (if defined)

Adding a New Adapter

  1. Create a config file in src/configs/adapter_configs/:
# src/configs/adapter_configs/my_adapter.pyfromdataclassesimportdataclass, fieldfromtypingimportDict, Listfromconfigs.base_configimportAdapterConfig, TaskConfig@dataclassclassMyAdapterConfig(AdapterConfig):
type: str="my_adapter"my_param: int=42MY_ADAPTER_BASE_CONFIG=MyAdapterConfig()
MY_ADAPTER_LARGE_CONFIG=MyAdapterConfig(my_param=84)
MY_ADAPTER_TASK_CONFIGS: Dict[str, TaskConfig] = { ... }
  1. Register it in src/configs/adapter_configs/__init__.py:
from .my_adapterimportMyAdapterConfig, MY_ADAPTER_BASE_CONFIG, ...
ADAPTER_CONFIG_REGISTRY["my_adapter"] = {
"config_class": MyAdapterConfig,
"base": MY_ADAPTER_BASE_CONFIG,
"large": MY_ADAPTER_LARGE_CONFIG,
"task_configs": MY_ADAPTER_TASK_CONFIGS,
}
  1. It's readymy_adapter automatically appears in --adapter_type choices and ALLOWED_ADAPTERS.

Two Config Layers

The system has two separate configuration layers:

LayerClassPurpose
Experiment configGPARTConfig(AdapterConfig)What experiment to run (defaults, task overrides)
PEFT configGPartConfig(PeftConfig)How to construct the adapter model

The get_peft_config() function in src/utils/adapter_utils.py bridges them — it renames fields (e.g., dropoutgpart_dropout), adds PEFT-specific fields, and constructs the GPartConfig object that get_peft_model() expects. This separation keeps the experiment system decoupled from PEFT library internals.


ViT on vision benchmarks

Supported datasets:

  • cifar10
  • cifar100
  • fgvc
  • flowers102
  • eurosat
  • resisc45
  • oxfordpets
  • standfordcars
  • dtd

Data preparation

All datasets are downloaded automatically by the finetuning script, except dtd, which must be manually downloaded from the DTD website.

After downloading, extract the archive into the data/ directory. The expected structure is:

data/
└── dtd/
├── images/
├── imdb/
└── labels/

Run experiments

# ViT-Base on FGVC Aircraft
python src/scripts/vision/finetune_ViT.py --dataset fgvc --model_size base
# ViT-Large on CIFAR-100
python src/scripts/vision/finetune_ViT.py --dataset cifar100 --model_size large
# Custom optimization settings
python src/scripts/vision/finetune_ViT.py \
--dataset flowers102 \
--model_size base \
--head_lr 5e-3 \
--base_lr 6e-3 \
--num_train_epochs 30

Aggregate multi-seed results:

python src/scripts/vision/collect_results_ViT.py

LLMs on MetaMathQA

Supported base models include:

  • google/gemma-7b
  • Qwen/Qwen2.5-0.5B
  • Qwen/Qwen2.5-3B
  • Qwen/Qwen2.5-7B
  • meta-llama/Llama-3.1-8B
# Qwen2.5-0.5B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072
# Qwen2.5-7B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-7B \
--adapter_type gpart \
--d 524288
# With custom training settings
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--learning_rate 2e-4

Evaluation on GSM8K and MATH

# Base model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--dataset gsm8k
# GPart fine-tuned model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--adapter_path logs/metamath_qwen-qwen2.5-0.5b_gpart_d131072_drop0.05_lr0.0002_bs4_ga4_ep2_seq2048_nosysprompt_seed42_131k \
--dataset math

Integrating GPart into Your Project

To use GPart in your own repository, follow these steps:

Step 1: Copy the PEFT folder

Copy the peft folder from this repository into your project:

# From your project root
cp -r /path/to/GPart/peft .

Step 2: Configure uv for local PEFT

If you're using uv for dependency management, you can configure it to use the local PEFT copy instead of downloading from PyPI. Add the following to your pyproject.toml:

# Add peft to the dependenciesdependencies = [
"peft"
]
# Add the peft local path as source
[tool.uv.sources]
peft = { path = "peft", editable = true }

This tells uv to use the local peft package from the specified path.

Step 3: Import and use GPart

Once the PEFT folder is in your project, you can use GPart just like any other PEFT adapter:

importtorchfromtransformersimportAutoModelForCausalLMfrompeftimportTaskType, get_peft_modelfrompeft.tuners.gpartimportGPartConfig# 1. Define the GPart adapter configurationadapter_config=GPartConfig(
d=131072, # Capacity parameter (adjust for your use case)target_modules=["q_proj", "v_proj"], # Modules to adapttask_type=TaskType.CAUSAL_LM, # Task type (CAUSAL_LM, SEQ_CLS, etc.)
)
# 2. Load your base modelmodel=AutoModelForCausalLM.from_pretrained(
args.model_name,
trust_remote_code=True,
torch_dtype=torch_dtype,
)
# 3. Wrap the model with GPart adaptermodel=get_peft_model(model, adapter_config)
# 4. Train as usual with your preferred training loop# The model now has GPart adapters injected and ready for training

Reproducibility

For reproducible results:

  • Run multiple seeds for each setting.
  • Track the model checkpoint, task, and d.
  • Preserve the random seed used for partition generation.
  • Use the provided result collection scripts for final aggregation.

Because the GPart adapter is reconstructed from the trainable vector and the partition seed, the seed is part of the effective model state.


Contributing

We welcome contributions! This repository uses a fork-based workflow — fork the repo, create a branch, and submit a pull request.

Quick summary:

  1. Fork the repository
  2. Create a branch in your fork for each feature/experiment
  3. Format your code with Black before submitting
  4. Submit a Pull Request when you're ready to merge into main
  5. PR review required — at least one approval before merging

See CONTRIBUTING.md for the complete guide including setup instructions, branch naming conventions, and PR templates.

Branch Protection

The main branch is protected:

  • ✅ No direct pushes — all changes via pull requests only
  • ✅ At least 1 approving review required
  • ✅ Branch must be up to date before merging
  • ✅ No force pushes allowed

Citation

If you use this repository in academic work, please cite:

@misc{mandica2026gpart,
title={GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning}, author={Paolo Mandica and Michał Brzozowski and Zuzanna Dubanowska and Neo Christopher Chung},
year={2026},
eprint={2605.14841},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.14841}, }

License

This project is licensed under the Apache-2.0 License.

About

Official implementation of the paper "GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

GPart

End-to-End Isometric Fine-Tuning via Global Parameter Partitioning

PaperPythonLicense: Apache 2.0PEFT

Official implementation of the paper
"GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Authors:Paolo Mandica, Michał Brzozowski, Zuzanna Dubanowska, Neo Christopher Chung
Samsung AI Center, Warsaw, Poland

PaperInstallationQuick StartCitation

GPart is implemented following the standard interface of the 🤗 Hugging Face Parameter-Efficient Fine-Tuning (PEFT) library and is fully compatible with PEFT.


Teaser

GPart is a parameter-efficient fine-tuning method that removes the low-rank bottleneck entirely.
Instead of factorizing updates as in LoRA-style approaches, GPart optimizes a $d$-dimensional vector and maps it directly into the full model weight space through a single global partition generated from a random seed.

Diagram 1

This yields a fine-tuning pipeline with:

  • End-to-end isometry in the trainable subspace.
  • A single clean capacity hyperparameter: d.
  • Minimal storage cost: the trainable vector plus one seed.

Diagram 2


Table of contents


Overview

GPart is a parameter-efficient fine-tuning (PEFT) method introduced in the paper
“GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning.”

The method is built on a simple idea: instead of constraining updates through a low-rank matrix parameterization, optimize a low-dimensional vector $\theta_d \in \mathbb{R}^d$ and map it directly into the full weight space using a global partition matrix $P$:

$$ \Delta W = P\theta_d $$

The paper motivates this formulation by arguing that low-rank adapters distort geometry through bilinear reconstruction, while GPart preserves distances in the trainable subspace and offers a cleaner parameterization for PEFT.


Why GPart

Compared with low-rank PEFT methods, GPart is designed to be structurally simpler and more direct.

  • No low-rank bottleneck: updates are not reconstructed through a bilinear factorization.
  • End-to-end isometric mapping: the trainable subspace preserves Euclidean geometry.
  • Minimal state: the adapter can be reconstructed from the trainable vector and a random seed.
  • One main capacity knob: d controls the size of the trainable subspace.

This repository contains the code used to evaluate GPart on:

  • Natural language understanding with RoBERTa on GLUE.
  • Computer vision with ViT on multiple image classification benchmarks.
  • Mathematical reasoning with decoder-only LLMs fine-tuned on MetaMathQA and evaluated on GSM8K and MATH.

Installation

This repository uses uv for dependency and environment management.

uv sync
source .venv/bin/activate

Quick start

RoBERTa on GLUE

# RoBERTa-base with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart
# RoBERTa-large with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart --model_size large
# Selected tasks with a fixed seed
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--tasks sst2 qnli \
--seed 123
# Parameter count only
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--compute_params_only

Command-Line Overrides

Override default hyperparameters directly from the command line. Arguments after the main flags are captured as key-value pairs:

python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
adapter.d 16384 \
adapter.isometric False \
training.lr 0.001 \
training.head_lr 0.002 \
training.batch_size 16

Aggregate Results

python src/scripts/glue/collect_results_glue.py logs/roberta_glue_gpart

Configuration System

This project uses a dataclass-based configuration system — no YAML files. All configs are Python dataclasses with type safety, IDE autocomplete, and a single source of truth. Adding a new field to any config class automatically propagates everywhere without manual updates.

Config Hierarchy

Values are resolved with the following precedence (later overrides earlier):

1. Dataclass defaults ← Python default values in the dataclass definition
2. Adapter-specific configs ← Pre-defined instances per adapter type (e.g., GPART_BASE_CONFIG)
3. Task-specific configs ← Per-adapter, per-task overrides (e.g., epochs=60 for SST2)
4. Model-size configs ← Large-model variants when --model_size large (e.g., GPART_LARGE_CONFIG)
5. CLI overrides ← Key-value pairs after the main flags

Assignment Backends

For the standard GPart partition projection with grouping_strategy="random", choose the random-assignment backend that fits the available memory budget:

BackendTrade-offUse when
materializedSlightly faster, but stores a persistent group ID for every adapted parameter. Its extra memory grows with the number of adapted weights.Memory is available and you want the fastest assignment lookup.
stateless (default)Recomputes group IDs deterministically from proj_seed and global parameter position. It has no persistent per-parameter assignment buffer, with a small compute cost.Fine-tuning large models or minimizing adapter memory overhead.

Select a backend with a CLI override:

python src/scripts/math/finetune_metamath.py \
--adapter_type gpart \
adapter.assignment_backend stateless

stateless is supported only with grouping_strategy="random". Deprecated aliases legacy_streaming and implicit_stateless_v1 remain accepted with a FutureWarning; use materialized and stateless in new configurations.

Config Structure

The central object is ExperimentConfig, which composes three sub-configs:

@dataclassclassExperimentConfig:
adapter: AdapterConfig# Adapter hyperparameters (d, r, dropout, etc.)training: TrainingConfig# Training hyperparameters (lr, batch_size, etc.)task_metadata: dict# Dataset info, metrics, num_labels per tasktask_configs: dict# Task-specific overrides per adapter

TrainingConfig controls the training loop:

FieldDefaultDescription
batch_size32Training batch size
max_seq_length512Maximum sequence length
weight_decay0.1Weight decay for regularization
warmup_ratio0.06Fraction of steps for LR warmup
model_selection"best"Model selection strategy (see below)
lr1e-3Base learning rate (overridden by task configs)
head_lr1e-3Learning rate for classifier head

AdapterConfig is the base class extended by each adapter type. Each subclass adds its own fields (e.g., d for GPart, r and alpha for LoRA). Fields are automatically included in logging and serialization — no manual listing needed.

TaskConfig provides per-task overrides that take precedence over training defaults:

FieldDescription
epochsNumber of training epochs for this task
lrTask-specific base learning rate
head_lrTask-specific head learning rate
batch_sizeTask-specific batch size

Model Size Awareness

When you pass --model_size large, the system selects:

  1. Large adapter instance — e.g., GPART_LARGE_CONFIG instead of GPART_BASE_CONFIG
  2. Large task configs — e.g., GPART_LARGE_TASK_CONFIGS with different epochs/lrs (if defined)

Adding a New Adapter

  1. Create a config file in src/configs/adapter_configs/:
# src/configs/adapter_configs/my_adapter.pyfromdataclassesimportdataclass, fieldfromtypingimportDict, Listfromconfigs.base_configimportAdapterConfig, TaskConfig@dataclassclassMyAdapterConfig(AdapterConfig):
type: str="my_adapter"my_param: int=42MY_ADAPTER_BASE_CONFIG=MyAdapterConfig()
MY_ADAPTER_LARGE_CONFIG=MyAdapterConfig(my_param=84)
MY_ADAPTER_TASK_CONFIGS: Dict[str, TaskConfig] = { ... }
  1. Register it in src/configs/adapter_configs/__init__.py:
from .my_adapterimportMyAdapterConfig, MY_ADAPTER_BASE_CONFIG, ...
ADAPTER_CONFIG_REGISTRY["my_adapter"] = {
"config_class": MyAdapterConfig,
"base": MY_ADAPTER_BASE_CONFIG,
"large": MY_ADAPTER_LARGE_CONFIG,
"task_configs": MY_ADAPTER_TASK_CONFIGS,
}
  1. It's readymy_adapter automatically appears in --adapter_type choices and ALLOWED_ADAPTERS.

Two Config Layers

The system has two separate configuration layers:

LayerClassPurpose
Experiment configGPARTConfig(AdapterConfig)What experiment to run (defaults, task overrides)
PEFT configGPartConfig(PeftConfig)How to construct the adapter model

The get_peft_config() function in src/utils/adapter_utils.py bridges them — it renames fields (e.g., dropoutgpart_dropout), adds PEFT-specific fields, and constructs the GPartConfig object that get_peft_model() expects. This separation keeps the experiment system decoupled from PEFT library internals.


ViT on vision benchmarks

Supported datasets:

  • cifar10
  • cifar100
  • fgvc
  • flowers102
  • eurosat
  • resisc45
  • oxfordpets
  • standfordcars
  • dtd

Data preparation

All datasets are downloaded automatically by the finetuning script, except dtd, which must be manually downloaded from the DTD website.

After downloading, extract the archive into the data/ directory. The expected structure is:

data/
└── dtd/
├── images/
├── imdb/
└── labels/

Run experiments

# ViT-Base on FGVC Aircraft
python src/scripts/vision/finetune_ViT.py --dataset fgvc --model_size base
# ViT-Large on CIFAR-100
python src/scripts/vision/finetune_ViT.py --dataset cifar100 --model_size large
# Custom optimization settings
python src/scripts/vision/finetune_ViT.py \
--dataset flowers102 \
--model_size base \
--head_lr 5e-3 \
--base_lr 6e-3 \
--num_train_epochs 30

Aggregate multi-seed results:

python src/scripts/vision/collect_results_ViT.py

LLMs on MetaMathQA

Supported base models include:

  • google/gemma-7b
  • Qwen/Qwen2.5-0.5B
  • Qwen/Qwen2.5-3B
  • Qwen/Qwen2.5-7B
  • meta-llama/Llama-3.1-8B
# Qwen2.5-0.5B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072
# Qwen2.5-7B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-7B \
--adapter_type gpart \
--d 524288
# With custom training settings
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--learning_rate 2e-4

Evaluation on GSM8K and MATH

# Base model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--dataset gsm8k
# GPart fine-tuned model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--adapter_path logs/metamath_qwen-qwen2.5-0.5b_gpart_d131072_drop0.05_lr0.0002_bs4_ga4_ep2_seq2048_nosysprompt_seed42_131k \
--dataset math

Integrating GPart into Your Project

To use GPart in your own repository, follow these steps:

Step 1: Copy the PEFT folder

Copy the peft folder from this repository into your project:

# From your project root
cp -r /path/to/GPart/peft .

Step 2: Configure uv for local PEFT

If you're using uv for dependency management, you can configure it to use the local PEFT copy instead of downloading from PyPI. Add the following to your pyproject.toml:

# Add peft to the dependenciesdependencies = [
"peft"
]
# Add the peft local path as source
[tool.uv.sources]
peft = { path = "peft", editable = true }

This tells uv to use the local peft package from the specified path.

Step 3: Import and use GPart

Once the PEFT folder is in your project, you can use GPart just like any other PEFT adapter:

importtorchfromtransformersimportAutoModelForCausalLMfrompeftimportTaskType, get_peft_modelfrompeft.tuners.gpartimportGPartConfig# 1. Define the GPart adapter configurationadapter_config=GPartConfig(
d=131072, # Capacity parameter (adjust for your use case)target_modules=["q_proj", "v_proj"], # Modules to adapttask_type=TaskType.CAUSAL_LM, # Task type (CAUSAL_LM, SEQ_CLS, etc.)
)
# 2. Load your base modelmodel=AutoModelForCausalLM.from_pretrained(
args.model_name,
trust_remote_code=True,
torch_dtype=torch_dtype,
)
# 3. Wrap the model with GPart adaptermodel=get_peft_model(model, adapter_config)
# 4. Train as usual with your preferred training loop# The model now has GPart adapters injected and ready for training

Reproducibility

For reproducible results:

  • Run multiple seeds for each setting.
  • Track the model checkpoint, task, and d.
  • Preserve the random seed used for partition generation.
  • Use the provided result collection scripts for final aggregation.

Because the GPart adapter is reconstructed from the trainable vector and the partition seed, the seed is part of the effective model state.


Contributing

We welcome contributions! This repository uses a fork-based workflow — fork the repo, create a branch, and submit a pull request.

Quick summary:

  1. Fork the repository
  2. Create a branch in your fork for each feature/experiment
  3. Format your code with Black before submitting
  4. Submit a Pull Request when you're ready to merge into main
  5. PR review required — at least one approval before merging

See CONTRIBUTING.md for the complete guide including setup instructions, branch naming conventions, and PR templates.

Branch Protection

The main branch is protected:

  • ✅ No direct pushes — all changes via pull requests only
  • ✅ At least 1 approving review required
  • ✅ Branch must be up to date before merging
  • ✅ No force pushes allowed

Citation

If you use this repository in academic work, please cite:

@misc{mandica2026gpart,
title={GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning}, author={Paolo Mandica and Michał Brzozowski and Zuzanna Dubanowska and Neo Christopher Chung},
year={2026},
eprint={2605.14841},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.14841}, }

License

This project is licensed under the Apache-2.0 License.

About

Official implementation of the paper "GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

GPart

End-to-End Isometric Fine-Tuning via Global Parameter Partitioning

PaperPythonLicense: Apache 2.0PEFT

Official implementation of the paper
"GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Authors:Paolo Mandica, Michał Brzozowski, Zuzanna Dubanowska, Neo Christopher Chung
Samsung AI Center, Warsaw, Poland

PaperInstallationQuick StartCitation

GPart is implemented following the standard interface of the 🤗 Hugging Face Parameter-Efficient Fine-Tuning (PEFT) library and is fully compatible with PEFT.


Teaser

GPart is a parameter-efficient fine-tuning method that removes the low-rank bottleneck entirely.
Instead of factorizing updates as in LoRA-style approaches, GPart optimizes a $d$-dimensional vector and maps it directly into the full model weight space through a single global partition generated from a random seed.

Diagram 1

This yields a fine-tuning pipeline with:

  • End-to-end isometry in the trainable subspace.
  • A single clean capacity hyperparameter: d.
  • Minimal storage cost: the trainable vector plus one seed.

Diagram 2


Table of contents


Overview

GPart is a parameter-efficient fine-tuning (PEFT) method introduced in the paper
“GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning.”

The method is built on a simple idea: instead of constraining updates through a low-rank matrix parameterization, optimize a low-dimensional vector $\theta_d \in \mathbb{R}^d$ and map it directly into the full weight space using a global partition matrix $P$:

$$ \Delta W = P\theta_d $$

The paper motivates this formulation by arguing that low-rank adapters distort geometry through bilinear reconstruction, while GPart preserves distances in the trainable subspace and offers a cleaner parameterization for PEFT.


Why GPart

Compared with low-rank PEFT methods, GPart is designed to be structurally simpler and more direct.

  • No low-rank bottleneck: updates are not reconstructed through a bilinear factorization.
  • End-to-end isometric mapping: the trainable subspace preserves Euclidean geometry.
  • Minimal state: the adapter can be reconstructed from the trainable vector and a random seed.
  • One main capacity knob: d controls the size of the trainable subspace.

This repository contains the code used to evaluate GPart on:

  • Natural language understanding with RoBERTa on GLUE.
  • Computer vision with ViT on multiple image classification benchmarks.
  • Mathematical reasoning with decoder-only LLMs fine-tuned on MetaMathQA and evaluated on GSM8K and MATH.

Installation

This repository uses uv for dependency and environment management.

uv sync
source .venv/bin/activate

Quick start

RoBERTa on GLUE

# RoBERTa-base with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart
# RoBERTa-large with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart --model_size large
# Selected tasks with a fixed seed
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--tasks sst2 qnli \
--seed 123
# Parameter count only
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--compute_params_only

Command-Line Overrides

Override default hyperparameters directly from the command line. Arguments after the main flags are captured as key-value pairs:

python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
adapter.d 16384 \
adapter.isometric False \
training.lr 0.001 \
training.head_lr 0.002 \
training.batch_size 16

Aggregate Results

python src/scripts/glue/collect_results_glue.py logs/roberta_glue_gpart

Configuration System

This project uses a dataclass-based configuration system — no YAML files. All configs are Python dataclasses with type safety, IDE autocomplete, and a single source of truth. Adding a new field to any config class automatically propagates everywhere without manual updates.

Config Hierarchy

Values are resolved with the following precedence (later overrides earlier):

1. Dataclass defaults ← Python default values in the dataclass definition
2. Adapter-specific configs ← Pre-defined instances per adapter type (e.g., GPART_BASE_CONFIG)
3. Task-specific configs ← Per-adapter, per-task overrides (e.g., epochs=60 for SST2)
4. Model-size configs ← Large-model variants when --model_size large (e.g., GPART_LARGE_CONFIG)
5. CLI overrides ← Key-value pairs after the main flags

Assignment Backends

For the standard GPart partition projection with grouping_strategy="random", choose the random-assignment backend that fits the available memory budget:

BackendTrade-offUse when
materializedSlightly faster, but stores a persistent group ID for every adapted parameter. Its extra memory grows with the number of adapted weights.Memory is available and you want the fastest assignment lookup.
stateless (default)Recomputes group IDs deterministically from proj_seed and global parameter position. It has no persistent per-parameter assignment buffer, with a small compute cost.Fine-tuning large models or minimizing adapter memory overhead.

Select a backend with a CLI override:

python src/scripts/math/finetune_metamath.py \
--adapter_type gpart \
adapter.assignment_backend stateless

stateless is supported only with grouping_strategy="random". Deprecated aliases legacy_streaming and implicit_stateless_v1 remain accepted with a FutureWarning; use materialized and stateless in new configurations.

Config Structure

The central object is ExperimentConfig, which composes three sub-configs:

@dataclassclassExperimentConfig:
adapter: AdapterConfig# Adapter hyperparameters (d, r, dropout, etc.)training: TrainingConfig# Training hyperparameters (lr, batch_size, etc.)task_metadata: dict# Dataset info, metrics, num_labels per tasktask_configs: dict# Task-specific overrides per adapter

TrainingConfig controls the training loop:

FieldDefaultDescription
batch_size32Training batch size
max_seq_length512Maximum sequence length
weight_decay0.1Weight decay for regularization
warmup_ratio0.06Fraction of steps for LR warmup
model_selection"best"Model selection strategy (see below)
lr1e-3Base learning rate (overridden by task configs)
head_lr1e-3Learning rate for classifier head

AdapterConfig is the base class extended by each adapter type. Each subclass adds its own fields (e.g., d for GPart, r and alpha for LoRA). Fields are automatically included in logging and serialization — no manual listing needed.

TaskConfig provides per-task overrides that take precedence over training defaults:

FieldDescription
epochsNumber of training epochs for this task
lrTask-specific base learning rate
head_lrTask-specific head learning rate
batch_sizeTask-specific batch size

Model Size Awareness

When you pass --model_size large, the system selects:

  1. Large adapter instance — e.g., GPART_LARGE_CONFIG instead of GPART_BASE_CONFIG
  2. Large task configs — e.g., GPART_LARGE_TASK_CONFIGS with different epochs/lrs (if defined)

Adding a New Adapter

  1. Create a config file in src/configs/adapter_configs/:
# src/configs/adapter_configs/my_adapter.pyfromdataclassesimportdataclass, fieldfromtypingimportDict, Listfromconfigs.base_configimportAdapterConfig, TaskConfig@dataclassclassMyAdapterConfig(AdapterConfig):
type: str="my_adapter"my_param: int=42MY_ADAPTER_BASE_CONFIG=MyAdapterConfig()
MY_ADAPTER_LARGE_CONFIG=MyAdapterConfig(my_param=84)
MY_ADAPTER_TASK_CONFIGS: Dict[str, TaskConfig] = { ... }
  1. Register it in src/configs/adapter_configs/__init__.py:
from .my_adapterimportMyAdapterConfig, MY_ADAPTER_BASE_CONFIG, ...
ADAPTER_CONFIG_REGISTRY["my_adapter"] = {
"config_class": MyAdapterConfig,
"base": MY_ADAPTER_BASE_CONFIG,
"large": MY_ADAPTER_LARGE_CONFIG,
"task_configs": MY_ADAPTER_TASK_CONFIGS,
}
  1. It's readymy_adapter automatically appears in --adapter_type choices and ALLOWED_ADAPTERS.

Two Config Layers

The system has two separate configuration layers:

LayerClassPurpose
Experiment configGPARTConfig(AdapterConfig)What experiment to run (defaults, task overrides)
PEFT configGPartConfig(PeftConfig)How to construct the adapter model

The get_peft_config() function in src/utils/adapter_utils.py bridges them — it renames fields (e.g., dropoutgpart_dropout), adds PEFT-specific fields, and constructs the GPartConfig object that get_peft_model() expects. This separation keeps the experiment system decoupled from PEFT library internals.


ViT on vision benchmarks

Supported datasets:

  • cifar10
  • cifar100
  • fgvc
  • flowers102
  • eurosat
  • resisc45
  • oxfordpets
  • standfordcars
  • dtd

Data preparation

All datasets are downloaded automatically by the finetuning script, except dtd, which must be manually downloaded from the DTD website.

After downloading, extract the archive into the data/ directory. The expected structure is:

data/
└── dtd/
├── images/
├── imdb/
└── labels/

Run experiments

# ViT-Base on FGVC Aircraft
python src/scripts/vision/finetune_ViT.py --dataset fgvc --model_size base
# ViT-Large on CIFAR-100
python src/scripts/vision/finetune_ViT.py --dataset cifar100 --model_size large
# Custom optimization settings
python src/scripts/vision/finetune_ViT.py \
--dataset flowers102 \
--model_size base \
--head_lr 5e-3 \
--base_lr 6e-3 \
--num_train_epochs 30

Aggregate multi-seed results:

python src/scripts/vision/collect_results_ViT.py

LLMs on MetaMathQA

Supported base models include:

  • google/gemma-7b
  • Qwen/Qwen2.5-0.5B
  • Qwen/Qwen2.5-3B
  • Qwen/Qwen2.5-7B
  • meta-llama/Llama-3.1-8B
# Qwen2.5-0.5B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072
# Qwen2.5-7B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-7B \
--adapter_type gpart \
--d 524288
# With custom training settings
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--learning_rate 2e-4

Evaluation on GSM8K and MATH

# Base model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--dataset gsm8k
# GPart fine-tuned model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--adapter_path logs/metamath_qwen-qwen2.5-0.5b_gpart_d131072_drop0.05_lr0.0002_bs4_ga4_ep2_seq2048_nosysprompt_seed42_131k \
--dataset math

Integrating GPart into Your Project

To use GPart in your own repository, follow these steps:

Step 1: Copy the PEFT folder

Copy the peft folder from this repository into your project:

# From your project root
cp -r /path/to/GPart/peft .

Step 2: Configure uv for local PEFT

If you're using uv for dependency management, you can configure it to use the local PEFT copy instead of downloading from PyPI. Add the following to your pyproject.toml:

# Add peft to the dependenciesdependencies = [
"peft"
]
# Add the peft local path as source
[tool.uv.sources]
peft = { path = "peft", editable = true }

This tells uv to use the local peft package from the specified path.

Step 3: Import and use GPart

Once the PEFT folder is in your project, you can use GPart just like any other PEFT adapter:

importtorchfromtransformersimportAutoModelForCausalLMfrompeftimportTaskType, get_peft_modelfrompeft.tuners.gpartimportGPartConfig# 1. Define the GPart adapter configurationadapter_config=GPartConfig(
d=131072, # Capacity parameter (adjust for your use case)target_modules=["q_proj", "v_proj"], # Modules to adapttask_type=TaskType.CAUSAL_LM, # Task type (CAUSAL_LM, SEQ_CLS, etc.)
)
# 2. Load your base modelmodel=AutoModelForCausalLM.from_pretrained(
args.model_name,
trust_remote_code=True,
torch_dtype=torch_dtype,
)
# 3. Wrap the model with GPart adaptermodel=get_peft_model(model, adapter_config)
# 4. Train as usual with your preferred training loop# The model now has GPart adapters injected and ready for training

Reproducibility

For reproducible results:

  • Run multiple seeds for each setting.
  • Track the model checkpoint, task, and d.
  • Preserve the random seed used for partition generation.
  • Use the provided result collection scripts for final aggregation.

Because the GPart adapter is reconstructed from the trainable vector and the partition seed, the seed is part of the effective model state.


Contributing

We welcome contributions! This repository uses a fork-based workflow — fork the repo, create a branch, and submit a pull request.

Quick summary:

  1. Fork the repository
  2. Create a branch in your fork for each feature/experiment
  3. Format your code with Black before submitting
  4. Submit a Pull Request when you're ready to merge into main
  5. PR review required — at least one approval before merging

See CONTRIBUTING.md for the complete guide including setup instructions, branch naming conventions, and PR templates.

Branch Protection

The main branch is protected:

  • ✅ No direct pushes — all changes via pull requests only
  • ✅ At least 1 approving review required
  • ✅ Branch must be up to date before merging
  • ✅ No force pushes allowed

Citation

If you use this repository in academic work, please cite:

@misc{mandica2026gpart,
title={GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning}, author={Paolo Mandica and Michał Brzozowski and Zuzanna Dubanowska and Neo Christopher Chung},
year={2026},
eprint={2605.14841},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.14841}, }

License

This project is licensed under the Apache-2.0 License.

About

Official implementation of the paper "GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

GPart

End-to-End Isometric Fine-Tuning via Global Parameter Partitioning

PaperPythonLicense: Apache 2.0PEFT

Official implementation of the paper
"GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Authors:Paolo Mandica, Michał Brzozowski, Zuzanna Dubanowska, Neo Christopher Chung
Samsung AI Center, Warsaw, Poland

PaperInstallationQuick StartCitation

GPart is implemented following the standard interface of the 🤗 Hugging Face Parameter-Efficient Fine-Tuning (PEFT) library and is fully compatible with PEFT.


Teaser

GPart is a parameter-efficient fine-tuning method that removes the low-rank bottleneck entirely.
Instead of factorizing updates as in LoRA-style approaches, GPart optimizes a $d$-dimensional vector and maps it directly into the full model weight space through a single global partition generated from a random seed.

Diagram 1

This yields a fine-tuning pipeline with:

  • End-to-end isometry in the trainable subspace.
  • A single clean capacity hyperparameter: d.
  • Minimal storage cost: the trainable vector plus one seed.

Diagram 2


Table of contents


Overview

GPart is a parameter-efficient fine-tuning (PEFT) method introduced in the paper
“GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning.”

The method is built on a simple idea: instead of constraining updates through a low-rank matrix parameterization, optimize a low-dimensional vector $\theta_d \in \mathbb{R}^d$ and map it directly into the full weight space using a global partition matrix $P$:

$$ \Delta W = P\theta_d $$

The paper motivates this formulation by arguing that low-rank adapters distort geometry through bilinear reconstruction, while GPart preserves distances in the trainable subspace and offers a cleaner parameterization for PEFT.


Why GPart

Compared with low-rank PEFT methods, GPart is designed to be structurally simpler and more direct.

  • No low-rank bottleneck: updates are not reconstructed through a bilinear factorization.
  • End-to-end isometric mapping: the trainable subspace preserves Euclidean geometry.
  • Minimal state: the adapter can be reconstructed from the trainable vector and a random seed.
  • One main capacity knob: d controls the size of the trainable subspace.

This repository contains the code used to evaluate GPart on:

  • Natural language understanding with RoBERTa on GLUE.
  • Computer vision with ViT on multiple image classification benchmarks.
  • Mathematical reasoning with decoder-only LLMs fine-tuned on MetaMathQA and evaluated on GSM8K and MATH.

Installation

This repository uses uv for dependency and environment management.

uv sync
source .venv/bin/activate

Quick start

RoBERTa on GLUE

# RoBERTa-base with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart
# RoBERTa-large with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart --model_size large
# Selected tasks with a fixed seed
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--tasks sst2 qnli \
--seed 123
# Parameter count only
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--compute_params_only

Command-Line Overrides

Override default hyperparameters directly from the command line. Arguments after the main flags are captured as key-value pairs:

python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
adapter.d 16384 \
adapter.isometric False \
training.lr 0.001 \
training.head_lr 0.002 \
training.batch_size 16

Aggregate Results

python src/scripts/glue/collect_results_glue.py logs/roberta_glue_gpart

Configuration System

This project uses a dataclass-based configuration system — no YAML files. All configs are Python dataclasses with type safety, IDE autocomplete, and a single source of truth. Adding a new field to any config class automatically propagates everywhere without manual updates.

Config Hierarchy

Values are resolved with the following precedence (later overrides earlier):

1. Dataclass defaults ← Python default values in the dataclass definition
2. Adapter-specific configs ← Pre-defined instances per adapter type (e.g., GPART_BASE_CONFIG)
3. Task-specific configs ← Per-adapter, per-task overrides (e.g., epochs=60 for SST2)
4. Model-size configs ← Large-model variants when --model_size large (e.g., GPART_LARGE_CONFIG)
5. CLI overrides ← Key-value pairs after the main flags

Assignment Backends

For the standard GPart partition projection with grouping_strategy="random", choose the random-assignment backend that fits the available memory budget:

BackendTrade-offUse when
materializedSlightly faster, but stores a persistent group ID for every adapted parameter. Its extra memory grows with the number of adapted weights.Memory is available and you want the fastest assignment lookup.
stateless (default)Recomputes group IDs deterministically from proj_seed and global parameter position. It has no persistent per-parameter assignment buffer, with a small compute cost.Fine-tuning large models or minimizing adapter memory overhead.

Select a backend with a CLI override:

python src/scripts/math/finetune_metamath.py \
--adapter_type gpart \
adapter.assignment_backend stateless

stateless is supported only with grouping_strategy="random". Deprecated aliases legacy_streaming and implicit_stateless_v1 remain accepted with a FutureWarning; use materialized and stateless in new configurations.

Config Structure

The central object is ExperimentConfig, which composes three sub-configs:

@dataclassclassExperimentConfig:
adapter: AdapterConfig# Adapter hyperparameters (d, r, dropout, etc.)training: TrainingConfig# Training hyperparameters (lr, batch_size, etc.)task_metadata: dict# Dataset info, metrics, num_labels per tasktask_configs: dict# Task-specific overrides per adapter

TrainingConfig controls the training loop:

FieldDefaultDescription
batch_size32Training batch size
max_seq_length512Maximum sequence length
weight_decay0.1Weight decay for regularization
warmup_ratio0.06Fraction of steps for LR warmup
model_selection"best"Model selection strategy (see below)
lr1e-3Base learning rate (overridden by task configs)
head_lr1e-3Learning rate for classifier head

AdapterConfig is the base class extended by each adapter type. Each subclass adds its own fields (e.g., d for GPart, r and alpha for LoRA). Fields are automatically included in logging and serialization — no manual listing needed.

TaskConfig provides per-task overrides that take precedence over training defaults:

FieldDescription
epochsNumber of training epochs for this task
lrTask-specific base learning rate
head_lrTask-specific head learning rate
batch_sizeTask-specific batch size

Model Size Awareness

When you pass --model_size large, the system selects:

  1. Large adapter instance — e.g., GPART_LARGE_CONFIG instead of GPART_BASE_CONFIG
  2. Large task configs — e.g., GPART_LARGE_TASK_CONFIGS with different epochs/lrs (if defined)

Adding a New Adapter

  1. Create a config file in src/configs/adapter_configs/:
# src/configs/adapter_configs/my_adapter.pyfromdataclassesimportdataclass, fieldfromtypingimportDict, Listfromconfigs.base_configimportAdapterConfig, TaskConfig@dataclassclassMyAdapterConfig(AdapterConfig):
type: str="my_adapter"my_param: int=42MY_ADAPTER_BASE_CONFIG=MyAdapterConfig()
MY_ADAPTER_LARGE_CONFIG=MyAdapterConfig(my_param=84)
MY_ADAPTER_TASK_CONFIGS: Dict[str, TaskConfig] = { ... }
  1. Register it in src/configs/adapter_configs/__init__.py:
from .my_adapterimportMyAdapterConfig, MY_ADAPTER_BASE_CONFIG, ...
ADAPTER_CONFIG_REGISTRY["my_adapter"] = {
"config_class": MyAdapterConfig,
"base": MY_ADAPTER_BASE_CONFIG,
"large": MY_ADAPTER_LARGE_CONFIG,
"task_configs": MY_ADAPTER_TASK_CONFIGS,
}
  1. It's readymy_adapter automatically appears in --adapter_type choices and ALLOWED_ADAPTERS.

Two Config Layers

The system has two separate configuration layers:

LayerClassPurpose
Experiment configGPARTConfig(AdapterConfig)What experiment to run (defaults, task overrides)
PEFT configGPartConfig(PeftConfig)How to construct the adapter model

The get_peft_config() function in src/utils/adapter_utils.py bridges them — it renames fields (e.g., dropoutgpart_dropout), adds PEFT-specific fields, and constructs the GPartConfig object that get_peft_model() expects. This separation keeps the experiment system decoupled from PEFT library internals.


ViT on vision benchmarks

Supported datasets:

  • cifar10
  • cifar100
  • fgvc
  • flowers102
  • eurosat
  • resisc45
  • oxfordpets
  • standfordcars
  • dtd

Data preparation

All datasets are downloaded automatically by the finetuning script, except dtd, which must be manually downloaded from the DTD website.

After downloading, extract the archive into the data/ directory. The expected structure is:

data/
└── dtd/
├── images/
├── imdb/
└── labels/

Run experiments

# ViT-Base on FGVC Aircraft
python src/scripts/vision/finetune_ViT.py --dataset fgvc --model_size base
# ViT-Large on CIFAR-100
python src/scripts/vision/finetune_ViT.py --dataset cifar100 --model_size large
# Custom optimization settings
python src/scripts/vision/finetune_ViT.py \
--dataset flowers102 \
--model_size base \
--head_lr 5e-3 \
--base_lr 6e-3 \
--num_train_epochs 30

Aggregate multi-seed results:

python src/scripts/vision/collect_results_ViT.py

LLMs on MetaMathQA

Supported base models include:

  • google/gemma-7b
  • Qwen/Qwen2.5-0.5B
  • Qwen/Qwen2.5-3B
  • Qwen/Qwen2.5-7B
  • meta-llama/Llama-3.1-8B
# Qwen2.5-0.5B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072
# Qwen2.5-7B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-7B \
--adapter_type gpart \
--d 524288
# With custom training settings
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--learning_rate 2e-4

Evaluation on GSM8K and MATH

# Base model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--dataset gsm8k
# GPart fine-tuned model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--adapter_path logs/metamath_qwen-qwen2.5-0.5b_gpart_d131072_drop0.05_lr0.0002_bs4_ga4_ep2_seq2048_nosysprompt_seed42_131k \
--dataset math

Integrating GPart into Your Project

To use GPart in your own repository, follow these steps:

Step 1: Copy the PEFT folder

Copy the peft folder from this repository into your project:

# From your project root
cp -r /path/to/GPart/peft .

Step 2: Configure uv for local PEFT

If you're using uv for dependency management, you can configure it to use the local PEFT copy instead of downloading from PyPI. Add the following to your pyproject.toml:

# Add peft to the dependenciesdependencies = [
"peft"
]
# Add the peft local path as source
[tool.uv.sources]
peft = { path = "peft", editable = true }

This tells uv to use the local peft package from the specified path.

Step 3: Import and use GPart

Once the PEFT folder is in your project, you can use GPart just like any other PEFT adapter:

importtorchfromtransformersimportAutoModelForCausalLMfrompeftimportTaskType, get_peft_modelfrompeft.tuners.gpartimportGPartConfig# 1. Define the GPart adapter configurationadapter_config=GPartConfig(
d=131072, # Capacity parameter (adjust for your use case)target_modules=["q_proj", "v_proj"], # Modules to adapttask_type=TaskType.CAUSAL_LM, # Task type (CAUSAL_LM, SEQ_CLS, etc.)
)
# 2. Load your base modelmodel=AutoModelForCausalLM.from_pretrained(
args.model_name,
trust_remote_code=True,
torch_dtype=torch_dtype,
)
# 3. Wrap the model with GPart adaptermodel=get_peft_model(model, adapter_config)
# 4. Train as usual with your preferred training loop# The model now has GPart adapters injected and ready for training

Reproducibility

For reproducible results:

  • Run multiple seeds for each setting.
  • Track the model checkpoint, task, and d.
  • Preserve the random seed used for partition generation.
  • Use the provided result collection scripts for final aggregation.

Because the GPart adapter is reconstructed from the trainable vector and the partition seed, the seed is part of the effective model state.


Contributing

We welcome contributions! This repository uses a fork-based workflow — fork the repo, create a branch, and submit a pull request.

Quick summary:

  1. Fork the repository
  2. Create a branch in your fork for each feature/experiment
  3. Format your code with Black before submitting
  4. Submit a Pull Request when you're ready to merge into main
  5. PR review required — at least one approval before merging

See CONTRIBUTING.md for the complete guide including setup instructions, branch naming conventions, and PR templates.

Branch Protection

The main branch is protected:

  • ✅ No direct pushes — all changes via pull requests only
  • ✅ At least 1 approving review required
  • ✅ Branch must be up to date before merging
  • ✅ No force pushes allowed

Citation

If you use this repository in academic work, please cite:

@misc{mandica2026gpart,
title={GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning}, author={Paolo Mandica and Michał Brzozowski and Zuzanna Dubanowska and Neo Christopher Chung},
year={2026},
eprint={2605.14841},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.14841}, }

License

This project is licensed under the Apache-2.0 License.

About

Official implementation of the paper "GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

GPart

End-to-End Isometric Fine-Tuning via Global Parameter Partitioning

PaperPythonLicense: Apache 2.0PEFT

Official implementation of the paper
"GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Authors:Paolo Mandica, Michał Brzozowski, Zuzanna Dubanowska, Neo Christopher Chung
Samsung AI Center, Warsaw, Poland

PaperInstallationQuick StartCitation

GPart is implemented following the standard interface of the 🤗 Hugging Face Parameter-Efficient Fine-Tuning (PEFT) library and is fully compatible with PEFT.


Teaser

GPart is a parameter-efficient fine-tuning method that removes the low-rank bottleneck entirely.
Instead of factorizing updates as in LoRA-style approaches, GPart optimizes a $d$-dimensional vector and maps it directly into the full model weight space through a single global partition generated from a random seed.

Diagram 1

This yields a fine-tuning pipeline with:

  • End-to-end isometry in the trainable subspace.
  • A single clean capacity hyperparameter: d.
  • Minimal storage cost: the trainable vector plus one seed.

Diagram 2


Table of contents


Overview

GPart is a parameter-efficient fine-tuning (PEFT) method introduced in the paper
“GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning.”

The method is built on a simple idea: instead of constraining updates through a low-rank matrix parameterization, optimize a low-dimensional vector $\theta_d \in \mathbb{R}^d$ and map it directly into the full weight space using a global partition matrix $P$:

$$ \Delta W = P\theta_d $$

The paper motivates this formulation by arguing that low-rank adapters distort geometry through bilinear reconstruction, while GPart preserves distances in the trainable subspace and offers a cleaner parameterization for PEFT.


Why GPart

Compared with low-rank PEFT methods, GPart is designed to be structurally simpler and more direct.

  • No low-rank bottleneck: updates are not reconstructed through a bilinear factorization.
  • End-to-end isometric mapping: the trainable subspace preserves Euclidean geometry.
  • Minimal state: the adapter can be reconstructed from the trainable vector and a random seed.
  • One main capacity knob: d controls the size of the trainable subspace.

This repository contains the code used to evaluate GPart on:

  • Natural language understanding with RoBERTa on GLUE.
  • Computer vision with ViT on multiple image classification benchmarks.
  • Mathematical reasoning with decoder-only LLMs fine-tuned on MetaMathQA and evaluated on GSM8K and MATH.

Installation

This repository uses uv for dependency and environment management.

uv sync
source .venv/bin/activate

Quick start

RoBERTa on GLUE

# RoBERTa-base with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart
# RoBERTa-large with GPart
python src/scripts/glue/finetune_roberta_glue.py --adapter_type gpart --model_size large
# Selected tasks with a fixed seed
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--tasks sst2 qnli \
--seed 123
# Parameter count only
python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
--compute_params_only

Command-Line Overrides

Override default hyperparameters directly from the command line. Arguments after the main flags are captured as key-value pairs:

python src/scripts/glue/finetune_roberta_glue.py \
--adapter_type gpart \
adapter.d 16384 \
adapter.isometric False \
training.lr 0.001 \
training.head_lr 0.002 \
training.batch_size 16

Aggregate Results

python src/scripts/glue/collect_results_glue.py logs/roberta_glue_gpart

Configuration System

This project uses a dataclass-based configuration system — no YAML files. All configs are Python dataclasses with type safety, IDE autocomplete, and a single source of truth. Adding a new field to any config class automatically propagates everywhere without manual updates.

Config Hierarchy

Values are resolved with the following precedence (later overrides earlier):

1. Dataclass defaults ← Python default values in the dataclass definition
2. Adapter-specific configs ← Pre-defined instances per adapter type (e.g., GPART_BASE_CONFIG)
3. Task-specific configs ← Per-adapter, per-task overrides (e.g., epochs=60 for SST2)
4. Model-size configs ← Large-model variants when --model_size large (e.g., GPART_LARGE_CONFIG)
5. CLI overrides ← Key-value pairs after the main flags

Assignment Backends

For the standard GPart partition projection with grouping_strategy="random", choose the random-assignment backend that fits the available memory budget:

BackendTrade-offUse when
materializedSlightly faster, but stores a persistent group ID for every adapted parameter. Its extra memory grows with the number of adapted weights.Memory is available and you want the fastest assignment lookup.
stateless (default)Recomputes group IDs deterministically from proj_seed and global parameter position. It has no persistent per-parameter assignment buffer, with a small compute cost.Fine-tuning large models or minimizing adapter memory overhead.

Select a backend with a CLI override:

python src/scripts/math/finetune_metamath.py \
--adapter_type gpart \
adapter.assignment_backend stateless

stateless is supported only with grouping_strategy="random". Deprecated aliases legacy_streaming and implicit_stateless_v1 remain accepted with a FutureWarning; use materialized and stateless in new configurations.

Config Structure

The central object is ExperimentConfig, which composes three sub-configs:

@dataclassclassExperimentConfig:
adapter: AdapterConfig# Adapter hyperparameters (d, r, dropout, etc.)training: TrainingConfig# Training hyperparameters (lr, batch_size, etc.)task_metadata: dict# Dataset info, metrics, num_labels per tasktask_configs: dict# Task-specific overrides per adapter

TrainingConfig controls the training loop:

FieldDefaultDescription
batch_size32Training batch size
max_seq_length512Maximum sequence length
weight_decay0.1Weight decay for regularization
warmup_ratio0.06Fraction of steps for LR warmup
model_selection"best"Model selection strategy (see below)
lr1e-3Base learning rate (overridden by task configs)
head_lr1e-3Learning rate for classifier head

AdapterConfig is the base class extended by each adapter type. Each subclass adds its own fields (e.g., d for GPart, r and alpha for LoRA). Fields are automatically included in logging and serialization — no manual listing needed.

TaskConfig provides per-task overrides that take precedence over training defaults:

FieldDescription
epochsNumber of training epochs for this task
lrTask-specific base learning rate
head_lrTask-specific head learning rate
batch_sizeTask-specific batch size

Model Size Awareness

When you pass --model_size large, the system selects:

  1. Large adapter instance — e.g., GPART_LARGE_CONFIG instead of GPART_BASE_CONFIG
  2. Large task configs — e.g., GPART_LARGE_TASK_CONFIGS with different epochs/lrs (if defined)

Adding a New Adapter

  1. Create a config file in src/configs/adapter_configs/:
# src/configs/adapter_configs/my_adapter.pyfromdataclassesimportdataclass, fieldfromtypingimportDict, Listfromconfigs.base_configimportAdapterConfig, TaskConfig@dataclassclassMyAdapterConfig(AdapterConfig):
type: str="my_adapter"my_param: int=42MY_ADAPTER_BASE_CONFIG=MyAdapterConfig()
MY_ADAPTER_LARGE_CONFIG=MyAdapterConfig(my_param=84)
MY_ADAPTER_TASK_CONFIGS: Dict[str, TaskConfig] = { ... }
  1. Register it in src/configs/adapter_configs/__init__.py:
from .my_adapterimportMyAdapterConfig, MY_ADAPTER_BASE_CONFIG, ...
ADAPTER_CONFIG_REGISTRY["my_adapter"] = {
"config_class": MyAdapterConfig,
"base": MY_ADAPTER_BASE_CONFIG,
"large": MY_ADAPTER_LARGE_CONFIG,
"task_configs": MY_ADAPTER_TASK_CONFIGS,
}
  1. It's readymy_adapter automatically appears in --adapter_type choices and ALLOWED_ADAPTERS.

Two Config Layers

The system has two separate configuration layers:

LayerClassPurpose
Experiment configGPARTConfig(AdapterConfig)What experiment to run (defaults, task overrides)
PEFT configGPartConfig(PeftConfig)How to construct the adapter model

The get_peft_config() function in src/utils/adapter_utils.py bridges them — it renames fields (e.g., dropoutgpart_dropout), adds PEFT-specific fields, and constructs the GPartConfig object that get_peft_model() expects. This separation keeps the experiment system decoupled from PEFT library internals.


ViT on vision benchmarks

Supported datasets:

  • cifar10
  • cifar100
  • fgvc
  • flowers102
  • eurosat
  • resisc45
  • oxfordpets
  • standfordcars
  • dtd

Data preparation

All datasets are downloaded automatically by the finetuning script, except dtd, which must be manually downloaded from the DTD website.

After downloading, extract the archive into the data/ directory. The expected structure is:

data/
└── dtd/
├── images/
├── imdb/
└── labels/

Run experiments

# ViT-Base on FGVC Aircraft
python src/scripts/vision/finetune_ViT.py --dataset fgvc --model_size base
# ViT-Large on CIFAR-100
python src/scripts/vision/finetune_ViT.py --dataset cifar100 --model_size large
# Custom optimization settings
python src/scripts/vision/finetune_ViT.py \
--dataset flowers102 \
--model_size base \
--head_lr 5e-3 \
--base_lr 6e-3 \
--num_train_epochs 30

Aggregate multi-seed results:

python src/scripts/vision/collect_results_ViT.py

LLMs on MetaMathQA

Supported base models include:

  • google/gemma-7b
  • Qwen/Qwen2.5-0.5B
  • Qwen/Qwen2.5-3B
  • Qwen/Qwen2.5-7B
  • meta-llama/Llama-3.1-8B
# Qwen2.5-0.5B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072
# Qwen2.5-7B with GPart
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-7B \
--adapter_type gpart \
--d 524288
# With custom training settings
python src/scripts/math/finetune_metamath.py \
--model_name Qwen/Qwen2.5-0.5B \
--adapter_type gpart \
--d 131072 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--learning_rate 2e-4

Evaluation on GSM8K and MATH

# Base model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--dataset gsm8k
# GPart fine-tuned model
python src/scripts/math/eval_math.py \
--model_path Qwen/Qwen2.5-0.5B \
--adapter_path logs/metamath_qwen-qwen2.5-0.5b_gpart_d131072_drop0.05_lr0.0002_bs4_ga4_ep2_seq2048_nosysprompt_seed42_131k \
--dataset math

Integrating GPart into Your Project

To use GPart in your own repository, follow these steps:

Step 1: Copy the PEFT folder

Copy the peft folder from this repository into your project:

# From your project root
cp -r /path/to/GPart/peft .

Step 2: Configure uv for local PEFT

If you're using uv for dependency management, you can configure it to use the local PEFT copy instead of downloading from PyPI. Add the following to your pyproject.toml:

# Add peft to the dependenciesdependencies = [
"peft"
]
# Add the peft local path as source
[tool.uv.sources]
peft = { path = "peft", editable = true }

This tells uv to use the local peft package from the specified path.

Step 3: Import and use GPart

Once the PEFT folder is in your project, you can use GPart just like any other PEFT adapter:

importtorchfromtransformersimportAutoModelForCausalLMfrompeftimportTaskType, get_peft_modelfrompeft.tuners.gpartimportGPartConfig# 1. Define the GPart adapter configurationadapter_config=GPartConfig(
d=131072, # Capacity parameter (adjust for your use case)target_modules=["q_proj", "v_proj"], # Modules to adapttask_type=TaskType.CAUSAL_LM, # Task type (CAUSAL_LM, SEQ_CLS, etc.)
)
# 2. Load your base modelmodel=AutoModelForCausalLM.from_pretrained(
args.model_name,
trust_remote_code=True,
torch_dtype=torch_dtype,
)
# 3. Wrap the model with GPart adaptermodel=get_peft_model(model, adapter_config)
# 4. Train as usual with your preferred training loop# The model now has GPart adapters injected and ready for training

Reproducibility

For reproducible results:

  • Run multiple seeds for each setting.
  • Track the model checkpoint, task, and d.
  • Preserve the random seed used for partition generation.
  • Use the provided result collection scripts for final aggregation.

Because the GPart adapter is reconstructed from the trainable vector and the partition seed, the seed is part of the effective model state.


Contributing

We welcome contributions! This repository uses a fork-based workflow — fork the repo, create a branch, and submit a pull request.

Quick summary:

  1. Fork the repository
  2. Create a branch in your fork for each feature/experiment
  3. Format your code with Black before submitting
  4. Submit a Pull Request when you're ready to merge into main
  5. PR review required — at least one approval before merging

See CONTRIBUTING.md for the complete guide including setup instructions, branch naming conventions, and PR templates.

Branch Protection

The main branch is protected:

  • ✅ No direct pushes — all changes via pull requests only
  • ✅ At least 1 approving review required
  • ✅ Branch must be up to date before merging
  • ✅ No force pushes allowed

Citation

If you use this repository in academic work, please cite:

@misc{mandica2026gpart,
title={GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning}, author={Paolo Mandica and Michał Brzozowski and Zuzanna Dubanowska and Neo Christopher Chung},
year={2026},
eprint={2605.14841},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.14841}, }

License

This project is licensed under the Apache-2.0 License.

About

Official implementation of the paper "GPart: End-to-End Isometric Fine-Tuning via Global Parameter Partitioning"

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages