Instructions to use moncefem/memory-lora-gemma4 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use moncefem/memory-lora-gemma4 with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
| # Memory-LoRA App β repo URL β personalized model β coding-CLI endpoint | |
| A Next.js app around the Memory-LoRA hypernetwork. Paste a git URL; it clones | |
| the repo, embeds it, asks the trained hypernetwork for a LoRA adapter, merges | |
| that adapter into frozen Gemma, and serves the result behind an endpoint your | |
| coding CLI can talk to. | |
| No fine-tuning happens per repo β the adapter is produced in **one forward pass** | |
| of the hypernetwork. | |
| --- | |
| ## Pipeline | |
| ``` | |
| repo URL | |
| β | |
| ββ clone shallow git clone (depth 80) | |
| ββ embed 6 views β frozen Qwen3-Embedding-0.6B β 12288-d vector | |
| ββ model ensure a local snapshot of the base model (first run only) | |
| ββ adapter MemoryLoRAHead(emb) β (A,B) per module type β the hypernetwork | |
| ββ merge materialize a PEFT adapter β merge_and_unload β merged weights | |
| ββ serve vLLM OpenAI-compatible server (fallback: transformers) | |
| ββ ready endpoint live | |
| ``` | |
| Each heavy stage runs as its own subprocess so the ~1 GB encoder and the ~10 GB | |
| base model are never resident at the same time. | |
| ### Why the adapter conversion is exact | |
| The trained head emits, per shape-qualified module type, an update | |
| ``` | |
| delta = (alpha / rank) Β· (xΒ·Aα΅)Β·Bα΅ A:[r, in] B:[out, r] | |
| ``` | |
| which is *identically* PEFT's LoRA convention (`lora_A:[r,in]`, `lora_B:[out,r]`, | |
| `scaling = lora_alpha / r`). So the head's output can be copied straight into a | |
| standard PEFT adapter β no re-derivation, no approximation. The head shares one | |
| (A, B) pair across every layer of the same shape, exactly as during training | |
| (`inject_lora_weights`), so the copy reproduces training-time behavior. | |
| Targets are resolved by **full module name** (`model.language_model.layers.N...`), | |
| which keeps `vision_tower` / `audio_tower` untouched even though they contain | |
| identically-named projections. | |
| --- | |
| ## Setup | |
| ```bash | |
| cd app | |
| npm install | |
| cp .env.example .env.local # optional; defaults work | |
| # The base model is NOT in this repo β pull it once from the official HF repo. | |
| # (~10 GB. The pipeline does this automatically too, but doing it up front | |
| # means the first build isn't dominated by the download.) | |
| python engine/fetch_base_model.py | |
| npm run dev # http://localhost:3000 | |
| ``` | |
| Requires the training repo's Python deps (`torch`, `transformers`, `peft`, | |
| `pyarrow`) importable from `MLORA_PYTHON`. | |
| ### Serving backend | |
| `vllm` is used when importable. On Apple Silicon vLLM has no GPU backend, so the | |
| pipeline falls back to `engine/serve_fallback.py` β a stdlib OpenAI-compatible | |
| server (`/v1/models`, `/v1/completions`, `/v1/chat/completions`, streaming and | |
| non-streaming) backed by transformers. Same API surface either way, so the app | |
| and your CLI don't care which one is running. | |
| To serve with vLLM explicitly: | |
| ```bash | |
| MODEL=app/.workspaces/<job>/merged PORT=8000 ./engine/serve_vllm.sh | |
| # or skip merging and hot-load the adapter: | |
| MODE=lora BASE=google/gemma-4-E2B ADAPTER=app/.workspaces/<job>/adapter ./engine/serve_vllm.sh | |
| ``` | |
| --- | |
| ## Connecting a coding CLI | |
| The app exposes **both** API dialects on the same port, so it works with | |
| Anthropic-style and OpenAI-style CLIs. | |
| **Claude Code** (Anthropic Messages API β translated by the app): | |
| ```bash | |
| export ANTHROPIC_BASE_URL="http://localhost:3000" | |
| export ANTHROPIC_API_KEY="local-demo" | |
| export ANTHROPIC_MODEL="memory-lora:<jobId>" | |
| claude | |
| ``` | |
| **vibe / aider / any OpenAI-compatible CLI:** | |
| ```bash | |
| export OPENAI_BASE_URL="http://localhost:3000/v1" | |
| export OPENAI_API_KEY="local-demo" | |
| aider --model openai/memory-lora:<jobId> | |
| ``` | |
| The `:<jobId>` suffix picks which repo's model to route to; you can also use | |
| `?job=<id>` or an `x-mlora-job` header. Without one, the most recently ready | |
| build is used. | |
| ### API surface | |
| | Route | Behavior | | |
| |---|---| | |
| | `POST /v1/messages` | Anthropic Messages β translated to OpenAI chat, and back. Streaming SSE, tool definitions, `tool_use` / `tool_result` round-trips. | | |
| | `POST /v1/chat/completions` | Proxied to the inference server. | | |
| | `POST /v1/completions` | Proxied. | | |
| | `GET /v1/models` | Proxied. | | |
| | `POST /api/build` | `{repoUrl}` β starts a build, returns `{jobId, port}`. | | |
| | `GET /api/build` | All jobs + status. | | |
| | `GET /api/status/:jobId` | One job's status. | | |
| Set `MLORA_API_KEY` to require a bearer token (`Authorization: Bearer β¦` or | |
| `x-api-key`); unset means open, which is the sane default for a local endpoint. | |
| --- | |
| ## Layout | |
| ``` | |
| app/ | |
| engine/ | |
| config.py paths, device resolution, base-model resolution | |
| fetch_base_model.py pull the base model from the official HF repo | |
| build_embedding.py repo β 12288-d 6-view embedding | |
| generate_and_merge.py hypernetwork β PEFT adapter β merged model | |
| serve_vllm.sh vLLM OpenAI-compatible server | |
| serve_fallback.py transformers OpenAI-compatible server (MPS/CPU) | |
| pipeline.py orchestrates all stages, writes status.json | |
| src/ | |
| lib/jobs.ts spawn pipeline, allocate ports, read status | |
| lib/anthropic.ts Anthropic β OpenAI translation (incl. streaming/tools) | |
| app/api/β¦ build + status routes | |
| app/v1/[...path]/ the CLI-facing endpoint | |
| .workspaces/<jobId>/ repo/, embedding.npy, adapter/, merged/, status.json, | |
| pipeline.log (gitignored) | |
| ``` | |
| ## The base model | |
| `google/gemma-4-E2B` is **not** in this repo and is not a dependency you can | |
| `pip install` β it is pulled separately from the official Hugging Face | |
| repository (10.25 GB, a single `model.safetensors`) by | |
| `engine/fetch_base_model.py`, into `models/gemma-4-E2B/` (gitignored). | |
| That script doesn't just call `snapshot_download`: on this shard the Hub | |
| connection reliably stalls part-way through β throughput goes to zero while the | |
| socket stays open, so nothing times out and the download hangs forever. The CDN | |
| itself is fine (~10 MB/s on raw range requests). So metadata files go through | |
| `huggingface_hub` and the large shard goes through `curl` with | |
| `--speed-limit/--speed-time` (turns a stall into a non-zero exit) plus `-C -` | |
| (resumes from the partial file). Set `HF_TOKEN` if you hit rate limits; the | |
| model is public, so it isn't required. | |
| **It is a base checkpoint, not an instruction-tuned one.** It ships no chat | |
| template at all (`apply_chat_template` raises; the template section of the model | |
| card refers to the `-it` variants). That is deliberate here: the hypernetwork | |
| was trained to emit adapters for *this* model, so an `-it` variant would be a | |
| mismatch. Consequences: | |
| - `serve_fallback.py` renders chat messages as a plain role-tagged transcript, | |
| and still prefers a real chat template when one exists β so pointing the | |
| server at an `-it` model later just works. | |
| - Expect base-model behavior through a coding CLI: the API compatibility is | |
| exact, but a 2B-effective base model will not follow instructions or emit | |
| tool calls the way an instruction-tuned model does. The adapter's job is repo | |
| *recall*, not instruction following. | |
| - Gemma-4 emits `<|channel>thought β¦ <channel|>` when thinking; the server | |
| strips that block so clients receive only the final answer. | |
| ## Notes | |
| - The checkpoint defaults to `runs/sixview_v2/head.best.pt` (`input_dim=12288`, | |
| `rank=16`, `alpha=32`). Override with `MLORA_CHECKPOINT` when a newer run | |
| finishes β the embedding dim must match the head's `input_dim`. | |
| - The merge loads and merges in bf16 by default. The generated delta has RMS | |
| ~2e-3 against weights of ~2e-2 β about 25x bf16's resolution there β so the | |
| adapter survives; `--load-dtype float32` is available if you want headroom | |
| (~20 GB resident instead of ~10 GB). Every merge reports the relative error | |
| between the applied delta and the hypernetwork's output. | |
| - First build downloads the base model (~10 GB); later builds reuse it. | |
| - Merging writes a full copy of the model per job under `.workspaces/<job>/merged`. | |
| For many repos, prefer the un-merged path (`--no-merge` + vLLM `MODE=lora`), | |
| which keeps one base model in memory and swaps small adapters. | |