# Share-Inspired LoRA Subspace Memory for RWKV-X **Status:** Research / Future Work **Date:** 2026-02-26 **Based on:** [Shared LoRA Subspaces for almost Strict Continual Learning](https://arxiv.org/abs/2602.06043) (Kaushik et al., Feb 2026) --- ## Summary Replace independent per-topic LoRA adapters (the LoRA HybridMem proposal) with a single shared SVD-derived basis + tiny per-topic coefficient vectors. Achieves ~11,000x storage reduction per topic while solving the B=C problem from HybridMem research. **Core idea:** LoRA adapters across tasks converge to a shared low-rank subspace (>0.95 alignment by task 5). One set of basis vectors can represent all task-specific knowledge through per-task coefficient vectors alone. Merging new topics is gradient-free (SVD + analytical reprojection). --- ## Prior Research (This Repo) ### HybridMem Research (Completed) **Directory:** `RWKV-x_HybridMemory_Research/` | File | What | |------|------| | `README.md` | Project overview | | `TestPlan.md` | 7-phase viability test suite definition | | `RandomInsights.md` | Why RWKV-X is suited to HybridMem | | `results/TestPlan_run1_20260220.md` | Run 1 (abandoned, HDC regression found) | | `results/TestPlan_run2_20260221.md` | Run 2 (0.2B complete, 3.6B partial) | | `results/TestPlan_run3_20260221.md` | Run 3 (3.6B complete, definitive results) | | `dev_research/inference-integration-results.md` | Integration test results | | `dev_research/attention-lora-training.md` | Proposed fine-tuning approach | **Key results (Run 3, 3.6B INT8):** - Phases 1-4: PASS (HDC projection r=0.9667, attention heads use injected entries, single-fact recall works) - Phase 5: FAIL (multi-fact: 1/10 improved, 2/10 worse) - Phase 7b: **B=C** (random retrieval = HDC retrieval, both 2/3) **Conclusion:** HDC overhead adds zero value over random injection. The model treats injected KV entries as generic extra window regardless of content. ### LoRA HybridMem Research (Proposal Only) **Directory:** `RWKV-x_LoRA_HybridMemory_Research/` | File | What | |------|------| | `README.md` | Architecture proposal, 16 open research questions | | `dev_research/` | Empty (planned) | | `lora_research/` | Empty (planned) | | `results/` | Empty (planned) | **Proposed:** Disk-backed LoRA pages (~160 KB each) as memory, trained online during conversation. This spec supersedes that approach with Share's shared subspace. ### hash-hdc (HDC + ASIC Retrieval) **Directory:** `hash-hdc/` | File | What | |------|------| | `examples/hdc_retrieval.py` | HDC document indexing/search (68.4% recall@5) | | `examples/rag_query.py` | RAG query bridge | | `firmware/esp32-sha256/` | Custom ESP32 SHA-256 firmware | | `lib/asic/asic.h` | ASIC hardware abstraction (header only) | | `lib/hdc/` | HDC core (headers, C not implemented) | | `lib/bridge/` | Bridge layer (headers, C not implemented) | **Relevant to subspace:** The HDC projection and LSH infrastructure in `foundry/hdc/` and `foundry/hybridmem/` can be repurposed for topic routing (selecting which subspace coefficients to activate). ### Foundry HDC/HybridMem Implementation | File | What | |------|------| | `foundry/hdc/hdc.h` | HDC vector API (fv_vector, fv_projector, fv_similarity) | | `foundry/hdc/hdc.c` | Dense Gaussian projection, Hamming similarity, LSH | | `foundry/hybridmem/hybridmem.h` | HybridMem store API (fm_store, fm_query, fm_put) | | `foundry/hybridmem/hybridmem.c` | Disk-backed KV store with LSH indexing, shard management | | `foundry/hdc/tests/test_hdc.c` | HDC unit tests | | `foundry/hybridmem/tests/test_hybridmem.c` | HybridMem unit tests | --- ## Why Share Solves B=C The B=C problem: pretrained attention layers treat injected KV entries as generic extra context regardless of relevance. Random retrieval performs identically to HDC-matched retrieval. Share avoids this because knowledge goes INTO the weights via LoRA (`y = (W + BA)x`), not into the KV cache as foreign entries. Different topics produce different weight modifications. The model doesn't need to "distinguish" relevant context — each topic's coefficients encode different learned knowledge in the computation path itself. --- ## Storage Comparison (per LoRA layer, d=3584, rank=32) | Method | Per-Topic Storage | Shared Overhead | |--------|------------------|-----------------| | Standard LoRA | 917 KB | -- | | LoRA HybridMem (proposed) | ~160 KB (rank 8) | -- | | **Share (k=10, p=1)** | **80 bytes** | 286 KB (one-time) | For 24 LoRA layers (6 per block x 4 attention blocks): - Standard LoRA: 22 MB/topic - **Share: 1.9 KB/topic + 6.8 MB shared basis** --- ## Existing Infrastructure | Component | File | Status | |-----------|------|--------| | SVD (power iteration) | `tensor/tensor.c:7144` `tm_svd()` | Works, tested | | LoRA A/B storage | `lora/lora.h` `fl_layer` | Done | | Adapter save/load | `lora/lora.c` `fl_adapter_save/load` | Safetensors I/O | | Adapter averaging (FedAvg) | `rwkvx/rfa_train.c:1093` `rfa_lora_average()` | Done | | Training forward+backward | `rwkvx/rx_train.c` `rx_train_step()` | 8/8 tests | | AdamW optimizer | `optim/optim.h` `fo_adamw_new()` | Done | | HDC projection + LSH | `hdc/hdc.c` `fv_project()`, `hybridmem/` | Done | | LAPACK via Accelerate | Makefile: `-DACCELERATE_NEW_LAPACK` | Linked | --- ## Architecture ### Data Structure ```c typedef struct { int k; // Number of basis vectors (principal factors) int p; // Pseudo-rank per topic (typically 1) int n_topics; // Number of topics stored int topic_capacity; // Allocated capacity for topics int n_layers; struct fl_subspace_layer { char *name; int d_in, d_out; tm_tensor *beta; // [d_out x k] shared B basis (orthonormal columns) tm_tensor *alpha; // [d_in x k] shared A basis (orthonormal columns) // Per-topic coefficients (dynamic array, grows with topics) tm_tensor **eps_beta; // [n_topics] each [k x p] tm_tensor **eps_alpha; // [n_topics] each [k x p] } *layers; float scale; char **topic_names; fv_vector **topic_sigs; // HDC signatures for routing (optional) } fl_subspace; ``` ### API ```c // Build subspace from T trained adapters fl_subspace* fl_subspace_from_adapters(fl_adapter **adapters, int n_adapters, int k, int p); // Forward: output += scale * (beta * eps_beta[t]) @ (alpha * eps_alpha[t])^T @ input void fl_subspace_forward_add(fl_subspace *sub, int topic_id, const float *input, float *output, int layer_idx); // Reconstruct full fl_adapter for topic t (compatibility with existing training) fl_adapter* fl_subspace_reconstruct(fl_subspace *sub, int topic_id); // Begin new topic: returns temporary adapter for training fl_adapter* fl_subspace_begin_topic(fl_subspace *sub); // Merge trained adapter back into subspace (SVD + analytical reprojection) int fl_subspace_commit_topic(fl_subspace *sub, fl_adapter *trained, const char *name); // Recalculate all coefficients (gradient-free) void fl_subspace_reproject(fl_subspace *sub); // Save/load bool fl_subspace_save(fl_subspace *sub, const char *path); fl_subspace* fl_subspace_load(const char *path); void fl_subspace_free(fl_subspace *sub); // Route: find best topic(s) for current input via HDC similarity int* fl_subspace_route(fl_subspace *sub, const float *embedding, int embed_dim, int top_k, float *scores_out); ``` ### SVD Basis Extraction (core algorithm) For each LoRA layer across T adapters: ``` 1. Stack B matrices: B_tilde = [scale*B_1, ..., scale*B_T] in R^(d_out x T*r) 2. SVD: U, S, V = tm_svd(B_tilde) 3. Choose k: smallest k where sum(S[:k]^2) / sum(S^2) >= 0.60 4. Extract basis: beta = U[:, :k] // [d_out x k] 5. Compute coefficients: eps_beta[t] = beta^T @ (scale*B_t) // [k x r] If p=1: eps_beta[t] = beta^T @ (scale*B_t @ ones) // [k x 1] 6. Same for A -> alpha, eps_alpha ``` ### Forward Pass **Option A (general, any p):** ```c effective_B = beta @ eps_beta[t] // [d_out x k] @ [k x p] -> [d_out x p] effective_A = alpha @ eps_alpha[t] // [d_in x k] @ [k x p] -> [d_in x p] output += scale * effective_B @ effective_A^T @ input ``` **Option B (optimized, p=1):** ```c b_vec = beta @ eps_beta[t] // [d_out] vector a_vec = alpha @ eps_alpha[t] // [d_in] vector output += scale * b_vec * dot(a_vec, input) // rank-1 outer product ``` ### New Topic Training **Step 1 — Temporary expansion:** - Create standard LoRA adapter with rank phi = k/4 - Initialize from top-phi basis directions - Return adapter for training via existing `rx_train_step()` **Step 2 — Train using existing infrastructure (no changes needed):** ```c rx_train_step(model, state, temp_adapter, optimizer, &example, &config); ``` **Step 3 — Merge back (gradient-free):** ```c // For each layer: // 1. Reconstruct old: B_hat_i = beta @ eps_beta[i] // 2. Stack with new: B_tilde = [B_hat_1, ..., B_hat_T, trained_B] // 3. SVD -> new beta, new k // 4. Analytical reprojection: eps_beta[i] = beta^T @ B_hat_i (no gradients!) // 5. Same for A ``` ### Topic Routing (reuse HDC) ```c // When topic is committed: mean-pool effective embeddings -> fv_project() -> signature // At inference: mean-pool input -> fv_project() -> query // fv_similarity(query, topic_sigs[i]) for each topic -> activate top-k ``` Reuses `fv_projector` and `fv_similarity` from `hdc/hdc.c`, and LSH from `hybridmem/` for sub-linear search when topic count grows large. ### Persistence Format (safetensors) ``` Metadata: "type": "fl_subspace" "k": "10", "p": "1", "n_topics": "25", "scale": "2.0" "topic_names": "topic_0,topic_1,..." Tensors: "layer.0.beta": [d_out, k] "layer.0.alpha": [d_in, k] "layer.0.eps_beta.0": [k, p] "layer.0.eps_beta.1": [k, p] ... "layer.0.eps_alpha.0": [k, p] ... "topic_sigs": [n_topics, hdc_dim/64] ``` --- ## Validation Test Suite Extends the HybridMem 7-phase framework: | Phase | Test | Pass Criterion | |-------|------|----------------| | 1 | Subspace convergence | Alignment >0.90 by topic 5 (reproduce Share Fig. 1) | | 2 | Reconstruction error | norm(B_hat - beta * eps) / norm(B) < 0.10 at 60% variance | | 3 | Forward equivalence | Subspace output ~ original LoRA output (RMSE < 0.01) | | 4 | B != C test | Correct topic coefficients outperform random topic | | 5 | Online learning | New topic doesn't degrade existing topic quality | | 6 | Storage efficiency | Measure actual bytes: subspace vs N separate adapters | | 7 | Routing accuracy | HDC routing selects correct topic >80% | --- ## New Files | File | Purpose | |------|---------| | `lora/lora_subspace.h` | fl_subspace API | | `lora/lora_subspace.c` | Implementation | | `lora/tests/test_lora_subspace.c` | Unit tests | ## Modified Files | File | Change | |------|--------| | `Makefile` | Add lora_subspace build and test targets | | `tensor/tensor.c` | Optional: LAPACK SVD path for larger matrices | --- ## Implementation Order 1. `lora_subspace.h` -- API definition 2. `lora_subspace.c` -- `fl_subspace_from_adapters` (SVD extraction) 3. Unit tests -- basis extraction + reconstruction error 4. Forward pass -- `fl_subspace_forward_add` + equivalence test 5. Commit/merge -- `fl_subspace_commit_topic` + reprojection 6. Save/load -- safetensors persistence 7. Topic routing -- HDC signature integration 8. Validation -- 7-phase test suite against 3.6B model ## Prerequisites - 2-3 trained LoRA adapters (train on different OASST1 topic splits) - Training infrastructure works (rx_train_step, 8/8 tests) - SVD works (tm_svd, tested) ## Risks 1. **SVD accuracy** -- Power iteration (100 iter) may need LAPACK upgrade for larger matrices. Accelerate LAPACK already linked. 2. **p=1 capacity** -- Share shows p=1 works for NLU/classification. Conversation memory may need p=2-4. 3. **Training data** -- Need topic-diverse adapters to seed subspace. Can use synthetic splits. --- ## Share Paper Details **Title:** Shared LoRA Subspaces for almost Strict Continual Learning **Authors:** Prakhar Kaushik, Ankit Vaidya, Shravan Chaudhari, Rama Chellappa, Alan Yuille **ArXiv:** [2602.06043](https://arxiv.org/abs/2602.06043) (Feb 5, 2026) ### Key Results from Paper - 100x parameter reduction vs standard LoRA - 281x memory savings - Matches jointly-trained baseline on GLUE, CIFAR-100, Pascal3D+, Flux - CIFAR-100: 94.20% accuracy (= upper bound), 0.40% forgetting - Processes 500 LoRA adapters incrementally, maintains 90-99% on IID tasks - Subspace alignment >0.95 by task 5 (empirically validated) ### Share Algorithm Summary **Step 1 (Build subspace):** Stack LoRA B matrices -> SVD -> top-k basis vectors (beta). Coefficients: eps = beta^T @ B_hat (pseudoinverse, gradient-free). **Step 2 (New task):** Expand basis temporarily by phi directions. Train on new data. Only coefficients are learned. **Step 3 (Merge):** Stack reconstructed old + new -> SVD -> updated basis. Analytical reprojection for all existing topics (no replay, no gradients). **Forward:** h = W_0 * x + (beta * eps_beta) @ (alpha * eps_alpha)^T @ x **Key insight:** When beta has orthonormal columns, reprojection is just eps = beta^T @ B_hat -- a single matrix multiply, no optimization needed.