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
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:
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):
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:
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.pyrenders chat messages as a plain role-tagged transcript, and still prefers a real chat template when one exists β so pointing the server at an-itmodel 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 withMLORA_CHECKPOINTwhen a newer run finishes β the embedding dim must match the head'sinput_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;20 GB resident instead of ~10 GB). Every merge reports the relative error between the applied delta and the hypernetwork's output.--load-dtype float32is available if you want headroom ( - 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+ vLLMMODE=lora), which keeps one base model in memory and swaps small adapters.