|
Download README.md from Angshul/TensorPEFT: direct link, hf CLI and curl.
- Browser
- Download file 7.53 kB
-
https://huggingface.co/Angshul/TensorPEFT/resolve/main/README.md
- Command line
-
hf download hf://Angshul/TensorPEFT/README.md
-
curl -L -o README.md https://huggingface.co/Angshul/TensorPEFT/resolve/main/README.md
7.53 kB
| # TensorPEFT | |
| --- | |
| license: apache-2.0 | |
| library_name: tensorpeft | |
| tags: | |
| - peft | |
| - fine-tuning | |
| - tensor-decomposition | |
| - lora-alternative | |
| --- | |
| Parameter-efficient fine-tuning with **tensor gradient-pursuit adapters**. TensorPEFT is a drop-in | |
| alternative to LoRA for Hugging Face models, designed for very small trainable-parameter budgets. | |
| LoRA gives every weight matrix its own low-rank update. TensorPEFT instead stacks all | |
| equal-shaped matrices of the network into one tensor, for example | |
| `layers x {q,k,v,o} x d_in x d_out`, and learns a few **rank-one CP atoms** of that tensor: | |
| dW = sum_i a_i u_i(layer) o u_i(role) o u_i(in) o u_i(out) | |
| Each atom couples every layer and projection while costing only | |
| `L + P + d_in + d_out + 1` parameters. The atoms are not random. They are the leading rank-one | |
| CP components of the negative gradient tensor (higher-order power iteration with deflation), | |
| computed from **one gradient probe** before training. The coefficients start at zero, so the | |
| model is unchanged at step 0, and every atom starts on a steepest-descent direction. After that, | |
| training is ordinary: any optimiser and the HF `Trainer` both work. | |
| ## Install | |
| pip install tensorpeft # once published; until then: pip install . | |
| It requires `torch>=2.1`, `transformers>=4.40`, `safetensors` and `huggingface_hub`. | |
| ## Quick start | |
| ```python | |
| from transformers import AutoModelForCausalLM | |
| from tensorpeft import TensorPEFTConfig, get_tensorpeft_model, TensorPEFTModel | |
| base = AutoModelForCausalLM.from_pretrained("gpt2") | |
| model = get_tensorpeft_model(base, TensorPEFTConfig(atoms_per_group=4)) | |
| model.init_atoms(train_dataloader, n_batches=4) # the one step LoRA does not have | |
| model.print_trainable_parameters() # trainable params: 37,036 || ... || 0.0298% | |
| # train as usual: AdamW, lr ~3e-3, short warm-up, weight_decay 0 (or TensorPEFTTrainer below) | |
| model.save_pretrained("my-adapter") # adapter_config.json + adapter_model.safetensors | |
| model.push_to_hub("your-name/my-adapter") | |
| base = AutoModelForCausalLM.from_pretrained("gpt2") | |
| model = TensorPEFTModel.from_pretrained(base, "your-name/my-adapter") # local dir or Hub id | |
| merged = model.merge_and_unload() # plain HF model, zero inference overhead | |
| ``` | |
| `train_dataloader` can yield dicts (`input_ids`, optional `attention_mask` / `labels`) or plain | |
| input-id tensors. For causal LMs, labels default to the inputs. | |
| ### With the Hugging Face Trainer | |
| ```python | |
| from tensorpeft import TensorPEFTTrainer | |
| trainer = TensorPEFTTrainer(model=model, args=training_args, train_dataset=ds, data_collator=collator) | |
| trainer.train() # checkpoints contain only the adapter | |
| ``` | |
| `TensorPEFTTrainer` is the stock `Trainer` except that it saves adapters instead of full model | |
| weights. A complete script is in `examples/train_with_trainer.py`. | |
| ## Configuration | |
| | `TensorPEFTConfig` field | default | meaning | | |
| |---|---|---| | |
| | `atoms_per_group` | 4 | rank-one atoms per tensor group; this sets the budget | | |
| | `target_modules` | `"all-linear"` | or a list of name suffixes, e.g. `["q_proj", "v_proj"]` (`"c_attn.q"` for GPT-2) | | |
| | `exclude_modules` | `lm_head`, embeddings | never adapted | | |
| | `split_fused_qkv` | True | split GPT-2's fused `c_attn` into q, k and v | | |
| | `init_batches` | 4 | batches used by `init_atoms` | | |
| | `hopm_iters` | 30 | power-iteration sweeps per atom | | |
| | `alpha_scale` | 33.3 | coefficient reparametrisation so that one learning rate (~3e-3) fits coefficients and factors | | |
| **Budget.** Groups are formed automatically by matrix shape. GPT-2 small has three groups: | |
| `{q,k,v,o}` (12x4x768x768), MLP-in (12x768x3072) and MLP-out (12x3072x768). One atom per group | |
| is 9,259 parameters, four per group is 37,036, and six per group is 55,554. | |
| `print_trainable_parameters()` shows the exact count for any model. | |
| **Recipe.** Use AdamW at lr 3e-3 with about 10 warm-up steps, then a constant schedule and | |
| weight decay 0. Use all atoms from the start: adding atoms gradually during training was clearly | |
| worse in our tests. | |
| ## Results | |
| Setup: GPT-2 124M (English base) fine-tuned on Bengali news (3M tokens), 300 AdamW steps, | |
| batch 8 x 128 tokens. Validation cross-entropy is in nats/token, lower is better; the base model | |
| scores 1.708. All methods saw identical data, and baseline learning rates follow their papers. | |
| Three seeds, best baseline per budget: | |
| | budget | TensorPEFT | best baseline | difference | seeds won | p (paired t) | | |
| |---|---:|---|---:|:---:|---:| | |
| | ~9k params | **1.3245 ± 0.004** | prompt tuning: 1.3684 ± 0.010 | **-0.044** | 3/3 | 0.008 | | |
| | ~37k | 1.2558 ± 0.010 | LayerNorm tuning (38.4k): 1.2504 ± 0.003 | +0.005 | 1/3 | 0.37 (tie) | | |
| | ~55k | **1.2368 ± 0.017** | (IA)³: 1.2880 ± 0.003 | **-0.051** | 3/3 | 0.026 | | |
| All baselines at each budget (seed 0): | |
| | budget | TensorPEFT | LoRA | QLoRA | VeRA | (IA)³ | prompt tuning | LayerNorm tuning | BitFit | | |
| |---|---:|---:|---:|---:|---:|---:|---:|---:| | |
| | ~1.5k | **1.461** | - | - | - | - | 1.493 (768 params) | 1.600 | - | | |
| | ~9k | **1.327** | 1.430 | - | - | 1.432 | 1.370 | 1.407 | - | | |
| | ~37k | 1.255 | 1.318 | 1.335 | 1.393 (24.6k) | - | 1.327 | **1.253** | - | | |
| | ~55k | **1.231** | - | - | - | 1.289 | - | - | - | | |
| | ~83k | - | - | - | - | - | - | - | 1.326 | | |
| TensorPEFT budgets map to configs as follows: ~1.5k is one atom on the attention tensor only | |
| (`target_modules=["c_attn.q", "c_attn.k", "c_attn.v", "attn.c_proj"]`, `atoms_per_group=1`), | |
| ~9k is `atoms_per_group=1`, ~37k is 4 and ~55k is 6. A dash means the method cannot be | |
| configured at that budget on GPT-2, or was not run there. | |
| LoRA's smallest all-layer configuration is r=1 on q,v (37k parameters). At 9k it is LoRA r=1 on | |
| q,v of the last 3 layers. | |
| **What this does and does not show.** TensorPEFT beats every baseline from about 1.5k to | |
| about 9k parameters and at about 55k, and ties LayerNorm tuning at about 37k. With larger | |
| budgets (≥ 115k) LoRA was better in our tests. The evidence covers one base model, one task and | |
| short training. Results on other models and downstream tasks are not yet available. | |
| `examples/reproduce_gpt2_bengali.py` reruns these benchmarks with this package | |
| (`--atoms-per-group 1 | 4 | 6`). The | |
| data comes from the Bengali news corpus at github.com/soham96/Bengali_news_classifier, | |
| tokenised with the GPT-2 tokenizer. | |
| ## Supported models | |
| Any model whose transformer blocks use `nn.Linear` or GPT-2-style `Conv1D` layers inside | |
| numbered blocks (`...layers.N...` / `...h.N...`). Tested on GPT-2, Llama (GQA), Qwen2, Mistral, | |
| Phi and Gemma configurations. Fused projections other than GPT-2's `c_attn` are treated as a | |
| single matrix. | |
| ## Limitations (v0.1) | |
| - **GPU support is untested.** The code is device- and dtype-agnostic (adapter parameters in | |
| fp32, bf16/fp16 bases supported), but all tests and benchmarks so far ran on CPU. | |
| - **Probe memory.** `init_atoms` needs one backward pass with gradients on the targeted weights, | |
| plus an fp32 copy of each group's gradient tensor. That is roughly 2x the size of the targeted | |
| weights, temporarily. Use `target_modules` to limit it for large models. | |
| - **Quantised bases** (bitsandbytes 4/8-bit) are not supported yet, because the probe needs | |
| weight gradients. | |
| - **No checkpoint resume.** `Trainer` resume-from-checkpoint is not implemented; reload with | |
| `TensorPEFTModel.from_pretrained(..., is_trainable=True)`. | |
| ## Tests | |
| pip install .[test] | |
| pytest tests | |
| ## License | |
| Apache-2.0. Copyright 2026 Angshul Majumdar. | |