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
moncefem Claude Opus 4.8 commited on
Commit ·
481fbb6
0
Parent(s):
Memory-LoRA hypernetwork for Gemma-4-E2B: code, curated data, sixview checkpoints
Browse filesHypernetwork that generates repo-specific LoRA adapters for a frozen
google/gemma-4-E2B (zero inference-time token overhead). Includes the
memory_lora package, all data/build/train/eval scripts, the aligned
6-view dataset, and the sixview_v1/v2 checkpoints.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CeUvTz4vLw4ni2ZNR6pS1p
- .gitattributes +2 -0
- .gitignore +51 -0
- README.md +581 -0
- data/docs/documents.jsonl +0 -0
- data/docs/multiview_sources.jsonl +0 -0
- data/docs/multiview_sources_balanced.jsonl +0 -0
- data/docs/techlead_sources.jsonl +0 -0
- data/docs/techlead_sources_commitpack.jsonl +0 -0
- data/embeddings/aligned6_embeddings.parquet +3 -0
- data/embeddings/multiview_embeddings.parquet +3 -0
- data/multilang_repo_list.txt +3150 -0
- data/qna/aligned6_qna.jsonl +0 -0
- data/qna/repo_scoped_qa.jsonl +0 -0
- data/repo_list.txt +800 -0
- memory_lora/codegraph.py +221 -0
- memory_lora/core.py +434 -0
- memory_lora/data_paths.py +32 -0
- memory_lora/encoder.py +268 -0
- requirements.txt +22 -0
- runs/sixview_v1/head.best.pt +3 -0
- runs/sixview_v1/head.latest.pt +3 -0
- runs/sixview_v1/metrics.jsonl +11 -0
- runs/sixview_v1/tb/events.out.tfevents.1784911625.MAC-722851.16547.0 +0 -0
- runs/sixview_v2/head.snapshot.pt +3 -0
- runs/sixview_v2/head.t0030m.pt +3 -0
- runs/sixview_v2/tb/events.out.tfevents.1784929857.MAC-722851.35539.0 +0 -0
- scripts/assemble_6view_dataset.py +88 -0
- scripts/augment_paraphrases.py +120 -0
- scripts/build_doc_embeddings.py +78 -0
- scripts/build_repo_multiview.py +245 -0
- scripts/consolidate_qa.py +59 -0
- scripts/convert_real_code2lora.py +209 -0
- scripts/diag_mps_leak.py +101 -0
- scripts/eval_memory_lora.py +231 -0
- scripts/generate_commitpack_qa.py +153 -0
- scripts/generate_repo_scoped_qa.py +133 -0
- scripts/generate_synthetic_dataset.py +545 -0
- scripts/generate_techlead_qa.py +146 -0
- scripts/merge_corpora.py +85 -0
- scripts/show_eval_examples.py +71 -0
- scripts/test_embed_this_repo.py +43 -0
- scripts/test_recall_this_repo.py +99 -0
- scripts/train_direct_lora.py +277 -0
- scripts/train_memory_lora.py +668 -0
.gitattributes
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# === Secrets & environment (NEVER commit) =================================
|
| 2 |
+
.env
|
| 3 |
+
.env.*
|
| 4 |
+
*.key
|
| 5 |
+
*.pem
|
| 6 |
+
|
| 7 |
+
# === Python virtualenv & caches ===========================================
|
| 8 |
+
venv/
|
| 9 |
+
.venv/
|
| 10 |
+
env/
|
| 11 |
+
__pycache__/
|
| 12 |
+
*.py[cod]
|
| 13 |
+
*.egg-info/
|
| 14 |
+
.ipynb_checkpoints/
|
| 15 |
+
.DS_Store
|
| 16 |
+
|
| 17 |
+
# === Large raw / intermediate data we deliberately DON'T publish ===========
|
| 18 |
+
# (kept local; regenerable from scripts. See README §8 Datasets inventory.)
|
| 19 |
+
data/commitpack/
|
| 20 |
+
data/real_code2lora/
|
| 21 |
+
data/openrouter_cache/
|
| 22 |
+
data/embeddings/combined_embeddings.parquet
|
| 23 |
+
data/embeddings/real_code2lora_embeddings.parquet
|
| 24 |
+
data/embeddings/real_code2lora_diffs.parquet
|
| 25 |
+
data/embeddings/doc_embeddings.parquet
|
| 26 |
+
data/qna/combined_qna.jsonl
|
| 27 |
+
data/qna/real_code2lora_qna.jsonl
|
| 28 |
+
data/qna/qna.jsonl
|
| 29 |
+
|
| 30 |
+
# === Superseded / exploratory training runs (see README §9) ================
|
| 31 |
+
# Published checkpoints are the current sixview_* line only.
|
| 32 |
+
runs/full2/
|
| 33 |
+
runs/full_real_v4/
|
| 34 |
+
runs/full1/
|
| 35 |
+
runs/full3_priority/
|
| 36 |
+
runs/smoke_combined/
|
| 37 |
+
runs/direct_paper/
|
| 38 |
+
runs/direct_paper_v2/
|
| 39 |
+
runs/direct_cah_baseline/
|
| 40 |
+
runs/full_real_v1_train.log
|
| 41 |
+
runs/*.log
|
| 42 |
+
runs/*.npy
|
| 43 |
+
runs/test_ckpt.pt
|
| 44 |
+
|
| 45 |
+
# Actively-written live checkpoint (overwritten every 50 steps during training;
|
| 46 |
+
# we publish a verified snapshot + the write-once timestamped checkpoints instead)
|
| 47 |
+
runs/sixview_v2/head.latest.pt
|
| 48 |
+
|
| 49 |
+
# === Scratch ===============================================================
|
| 50 |
+
scratchpad/
|
| 51 |
+
*.tmp
|
README.md
ADDED
|
@@ -0,0 +1,581 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Memory-LoRA: A Hypernetwork that Writes Repo-Specific Adapters for Gemma-4-E2B
|
| 2 |
+
|
| 3 |
+
> **One line:** we train a small neural network (a *hypernetwork*) that reads an
|
| 4 |
+
> embedding of a codebase and **emits a LoRA adapter** for a frozen
|
| 5 |
+
> `google/gemma-4-E2B`. The adapter injects repo-specific knowledge into the
|
| 6 |
+
> model with **zero extra tokens at inference time** — no RAG, no context stuffing.
|
| 7 |
+
> Everything runs **locally on an Apple-Silicon Mac** (M4 Pro, 64 GB).
|
| 8 |
+
|
| 9 |
+
This document is the onboarding bible for the project. It covers *what* we built,
|
| 10 |
+
*why* every non-obvious choice was made, *what data* we used, *every experiment we
|
| 11 |
+
ran and its result*, and the **hard-won lessons** (the MPS memory leak alone cost
|
| 12 |
+
us hours). Read it top to bottom once; after that use it as a reference.
|
| 13 |
+
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
## Table of Contents
|
| 17 |
+
|
| 18 |
+
1. [The idea in 60 seconds](#1-the-idea-in-60-seconds)
|
| 19 |
+
2. [Origin: the Code2LoRA paper](#2-origin-the-code2lora-paper)
|
| 20 |
+
3. [Architecture](#3-architecture)
|
| 21 |
+
4. [The target model: Gemma-4-E2B specifics](#4-the-target-model-gemma-4-e2b-specifics)
|
| 22 |
+
5. [Data pipeline: the 6 views](#5-data-pipeline-the-6-views)
|
| 23 |
+
6. [Data pipeline: QA generation](#6-data-pipeline-qa-generation)
|
| 24 |
+
7. [What is learnable — Tier A / B / C](#7-what-is-learnable--tier-a--b--c)
|
| 25 |
+
8. [Datasets inventory](#8-datasets-inventory)
|
| 26 |
+
9. [Experiments & results](#9-experiments--results)
|
| 27 |
+
10. [Key decisions & lessons learned](#10-key-decisions--lessons-learned)
|
| 28 |
+
11. [Repository map](#11-repository-map)
|
| 29 |
+
12. [How to run it](#12-how-to-run-it)
|
| 30 |
+
13. [Evaluation methodology](#13-evaluation-methodology)
|
| 31 |
+
14. [Costs & budget discipline](#14-costs--budget-discipline)
|
| 32 |
+
15. [Current status & roadmap](#15-current-status--roadmap)
|
| 33 |
+
16. [Glossary](#16-glossary)
|
| 34 |
+
|
| 35 |
+
---
|
| 36 |
+
|
| 37 |
+
## 1. The idea in 60 seconds
|
| 38 |
+
|
| 39 |
+
A coding agent (Claude Code, Codex, etc.) is great at reasoning but knows nothing
|
| 40 |
+
about *your* repo until you paste files into its context — which is slow, expensive,
|
| 41 |
+
and capped by the context window. The usual fix is RAG (retrieve chunks at query
|
| 42 |
+
time). We do something different and complementary:
|
| 43 |
+
|
| 44 |
+
**We bake the repo's "personality" directly into the model's weights, once, as a
|
| 45 |
+
LoRA adapter — and we generate that adapter with a neural network instead of
|
| 46 |
+
training it.**
|
| 47 |
+
|
| 48 |
+
```
|
| 49 |
+
┌─────────────────────────────┐
|
| 50 |
+
repo on disk ──────► │ 6-view extractor + Qwen3 │ ──► 12288-d
|
| 51 |
+
│ frozen embedding encoder │ repo embedding
|
| 52 |
+
└─────────────────────────────┘ │
|
| 53 |
+
▼
|
| 54 |
+
┌──────────────────────────┐
|
| 55 |
+
│ HYPERNETWORK (our head) │
|
| 56 |
+
│ MLP → per-module A,B │
|
| 57 |
+
└──────────────────────────┘
|
| 58 |
+
│ LoRA weights
|
| 59 |
+
▼
|
| 60 |
+
Q: "what layer owns auth in this repo?" ──► ┌──────────────────────────────┐
|
| 61 |
+
│ FROZEN Gemma-4-E2B + injected │ ──► "the middleware
|
| 62 |
+
│ LoRA (zero extra tokens) │ layer, via ..."
|
| 63 |
+
└──────────────────────────────┘
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
The magic: **the hypernetwork is trained across hundreds of repos**, so it learns
|
| 67 |
+
the *mapping* `repo embedding → good adapter`. At inference on a brand-new repo it
|
| 68 |
+
has never seen, it embeds the repo once and produces an adapter in a single forward
|
| 69 |
+
pass. This is the same reason the source paper needed 400+ repos, not 1: breadth is
|
| 70 |
+
what makes the mapping generalize.
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
## 2. Origin: the Code2LoRA paper
|
| 75 |
+
|
| 76 |
+
We reverse-engineered **Code2LoRA** (arXiv 2606.06492v1) and found its released
|
| 77 |
+
code (`anonymous.4open.science/r/code2lora-6857`, MIT). The paper's contribution:
|
| 78 |
+
a *static hypernetwork* that maps a **repository** embedding → a LoRA adapter for a
|
| 79 |
+
frozen code LLM, evaluated on **RepoPeftBench** with IR (in-repo) / CR (cross-repo)
|
| 80 |
+
splits. On a full H100 setup they report **63.8 % cross-repo Exact Match**.
|
| 81 |
+
|
| 82 |
+
Our project is the **Doc2LoRA variant** the paper itself cites — hypernetwork maps a
|
| 83 |
+
*document/repo view* → LoRA — reimplemented against **Gemma-4-E2B**, trained fully
|
| 84 |
+
**locally on MPS** (no CUDA/H100), and extended in two directions the paper does not
|
| 85 |
+
cover:
|
| 86 |
+
|
| 87 |
+
- **Memory / recall**: the adapter should let the model *recall facts* about the
|
| 88 |
+
repo, not just complete code.
|
| 89 |
+
- **Tech-Lead judgment**: architecture, data-flow, conventions, contracts, ops —
|
| 90 |
+
the things a 20-year senior engineer "just knows" about a codebase.
|
| 91 |
+
|
| 92 |
+
We keep the paper's proven autograd trick almost verbatim (see §3) and change only
|
| 93 |
+
what Gemma-4 and Apple Silicon force us to change.
|
| 94 |
+
|
| 95 |
+
---
|
| 96 |
+
|
| 97 |
+
## 3. Architecture
|
| 98 |
+
|
| 99 |
+
Three frozen/learned pieces. Only the middle one (the head) is trained.
|
| 100 |
+
|
| 101 |
+
### 3.1 Frozen encoder — `memory_lora/encoder.py`
|
| 102 |
+
|
| 103 |
+
- **Qwen3-Embedding-0.6B**, frozen, no gradient flows through it.
|
| 104 |
+
- Each repo view is chunked into token windows (2048 tokens, 128 overlap), each
|
| 105 |
+
chunk mean-pooled, then chunks combined with **mean + max pooling** → a **2048-d**
|
| 106 |
+
vector *per view*.
|
| 107 |
+
- Embeddings are **precomputed once and cached** to parquet — the encoder never runs
|
| 108 |
+
during training.
|
| 109 |
+
|
| 110 |
+
### 3.2 The hypernetwork head — `memory_lora/core.py :: MemoryLoRAHead`
|
| 111 |
+
|
| 112 |
+
The only trained component. Design (kept close to the paper):
|
| 113 |
+
|
| 114 |
+
- **2-layer GELU MLP trunk** (`input_dim → hidden_dim → hidden_dim`), followed by
|
| 115 |
+
**L2-normalize + √hidden_dim rescale** (stabilizes the magnitude of generated
|
| 116 |
+
weights).
|
| 117 |
+
- **Per-module-type output heads**: for each target module *type* it emits an
|
| 118 |
+
`A ∈ [rank, in_features]` and `B ∈ [out_features, rank]`. **One (A,B) pair per
|
| 119 |
+
type, shared across all layers of that type** — this is what keeps the head
|
| 120 |
+
tractable (188.6 M params) instead of exploding per-layer.
|
| 121 |
+
- **Squashing**: `tanh(raw) * exp(log_scale)` with a learned per-type `log_scale`
|
| 122 |
+
(init **-3.5**). This starts the generated adapter near-zero (so training begins
|
| 123 |
+
close to the base model) and lets each type learn its own output scale.
|
| 124 |
+
- **Defaults**: `hidden_dim=128`, `rank=16`, `dropout=0.1`.
|
| 125 |
+
- *Why hidden_dim=128 and not the paper's 512/1024?* A 745 M-param head
|
| 126 |
+
(hidden_dim=512) barely moved eval loss (~1.9 → ~2.7) but was far heavier to
|
| 127 |
+
train on MPS. 128 cuts head size dramatically with negligible quality loss
|
| 128 |
+
locally. Bump it later on real GPUs.
|
| 129 |
+
|
| 130 |
+
### 3.3 The LoRA injection — `memory_lora/core.py :: LoRA`
|
| 131 |
+
|
| 132 |
+
```
|
| 133 |
+
base nn.Linear (FROZEN) hypernetwork output
|
| 134 |
+
│ │
|
| 135 |
+
x ──►│ Wx ────────────────┐ │
|
| 136 |
+
│ (input detached +──► y = Wx + scaling · B (A x)
|
| 137 |
+
│ into base) │ ▲ ▲
|
| 138 |
+
x ──────────────────────────┘ │ │
|
| 139 |
+
A,B are NON-detached tensors so
|
| 140 |
+
autograd flows LM-loss → head
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
Critical detail (straight from the paper's code): **A and B are plain, non-buffer
|
| 144 |
+
tensor attributes, not `nn.Parameter` and not detached**, so the gradient of the LM
|
| 145 |
+
loss flows *through* the injected weights *into the hypernetwork*. The base
|
| 146 |
+
`nn.Linear` is frozen and its input is detached. Get this wrong and the head never
|
| 147 |
+
learns.
|
| 148 |
+
|
| 149 |
+
### 3.4 Shape-qualified module types — the heterogeneity fix
|
| 150 |
+
|
| 151 |
+
Gemma-4-E2B is **not** a uniform stack (see §4). Two `q_proj`s can have different
|
| 152 |
+
shapes. If you key the head by bare type name (`q_proj`) you get
|
| 153 |
+
*"type q_proj inconsistent dims"* crashes. Fix: key by **shape-qualified type**,
|
| 154 |
+
e.g. `q_proj_1536x2048` vs `q_proj_1536x4096`. The v2 run discovered **14 shape
|
| 155 |
+
types** across **205 target modules**:
|
| 156 |
+
|
| 157 |
+
```
|
| 158 |
+
down_proj_12288x1536 down_proj_6144x1536 gate_proj_1536x12288 gate_proj_1536x6144
|
| 159 |
+
k_proj_1536x256 k_proj_1536x512 o_proj_2048x1536 o_proj_4096x1536
|
| 160 |
+
q_proj_1536x2048 q_proj_1536x4096 up_proj_1536x12288 up_proj_1536x6144
|
| 161 |
+
v_proj_1536x256 v_proj_1536x512
|
| 162 |
+
```
|
| 163 |
+
|
| 164 |
+
`get_module_specs(root_prefix="model.language_model.")` restricts wrapping to the
|
| 165 |
+
text decoder — the **vision and audio towers are never touched** (not even
|
| 166 |
+
inspected), so the multimodal forward path stays intact and they cost only idle RAM.
|
| 167 |
+
|
| 168 |
+
---
|
| 169 |
+
|
| 170 |
+
## 4. The target model: Gemma-4-E2B specifics
|
| 171 |
+
|
| 172 |
+
Verified by reading the actual safetensors header, not guessed:
|
| 173 |
+
|
| 174 |
+
- **Real model.** Google shipped Gemma 4 in March 2026. Apache-2.0, ungated.
|
| 175 |
+
Class `Gemma4ForConditionalGeneration`, `model_type: "gemma4"`. Loaded via
|
| 176 |
+
`AutoModelForImageTextToText`.
|
| 177 |
+
- **Requires `transformers >= 5.5.0.dev0`** — install from the `main` branch, not a
|
| 178 |
+
pinned PyPI release (this is the single biggest environment risk; smoke-test first).
|
| 179 |
+
- **Decoder is nested**: layers live at `model.language_model.layers.{i}.*`, *not*
|
| 180 |
+
`model.layers.*`. The layer-index regex had to change accordingly.
|
| 181 |
+
- **35 text layers, heterogeneous:**
|
| 182 |
+
- Aggressive KV sharing — **20 of 35 layers lack their own `k_proj`/`v_proj`**
|
| 183 |
+
(`num_kv_shared_layers=20`).
|
| 184 |
+
- **Every 5th layer is wider** (the `*_4096`, `*_12288` shape variants above).
|
| 185 |
+
- **Device `mps`, precision bf16** (fall back to fp16 if unstable). No
|
| 186 |
+
`flash_attention_2` on MPS — use `sdpa`, fall back to `eager`.
|
| 187 |
+
|
| 188 |
+
---
|
| 189 |
+
|
| 190 |
+
## 5. Data pipeline: the 6 views
|
| 191 |
+
|
| 192 |
+
`scripts/build_repo_multiview.py` clones a repo and extracts **6 complementary
|
| 193 |
+
views**, embeds each with Qwen3 → 2048-d, and **concatenates to a 12288-d** repo
|
| 194 |
+
vector. The views encode the different "lenses" a senior engineer uses:
|
| 195 |
+
|
| 196 |
+
| View | What it captures | Source signals |
|
| 197 |
+
|-----------------|----------------------------------------------------|----------------|
|
| 198 |
+
| `v_graph` | call / import / dependency structure | AST for Python (`memory_lora/codegraph.py`); `IMPORT_RE`/`DEF_RE` regex fallback for other languages |
|
| 199 |
+
| `v_arch` | architecture & layout | README, folder tree |
|
| 200 |
+
| `v_history` | how the code evolved | `git log`, recent diffs |
|
| 201 |
+
| `v_contracts` | behavioral contracts | test files |
|
| 202 |
+
| `v_conventions` | idioms & style | representative source files |
|
| 203 |
+
| `v_ops` | build / deploy / runtime | CI config, Dockerfile, build files |
|
| 204 |
+
|
| 205 |
+
**Multi-language from the start.** `CODE_EXTS` + regex fallbacks mean the graph view
|
| 206 |
+
works for 9 languages, not just Python (this was a deliberate correction — see §10).
|
| 207 |
+
Repos with < 3 code files are skipped. The build is **resume-safe** (skips repos
|
| 208 |
+
already in `multiview_sources.jsonl`) and **flushes the embeddings parquet every 10
|
| 209 |
+
repos**, so a crash never loses more than 10 repos of work.
|
| 210 |
+
|
| 211 |
+
---
|
| 212 |
+
|
| 213 |
+
## 6. Data pipeline: QA generation
|
| 214 |
+
|
| 215 |
+
The repo embedding is the *input*; the *target* is repo-scoped Q&A. Two generators,
|
| 216 |
+
both parallelized (`ThreadPoolExecutor`, `--workers 10`) with a **per-prompt disk
|
| 217 |
+
cache** (idempotent reruns) and a `--model` flag:
|
| 218 |
+
|
| 219 |
+
- **`scripts/generate_repo_scoped_qa.py`** — reads the same 6 views and asks the LLM
|
| 220 |
+
for **8–12 repo-level judgment questions** ("what layer owns X", "what convention
|
| 221 |
+
does this repo use for Y", "how does data flow through Z", "why is it structured
|
| 222 |
+
this way"). Target scope = input scope (repo-level embedding ↔ repo-level QA).
|
| 223 |
+
- **`scripts/generate_commitpack_qa.py`** — **breadth** generator: one commit per
|
| 224 |
+
*distinct* repo across CommitPackFT (25k+ distinct repos), 3–4 commit-scoped
|
| 225 |
+
judgment questions (why / conventions / contracts / impact). For a hypernetwork,
|
| 226 |
+
**distinct-repo count is the currency of generalization**, so we favor 1 commit ×
|
| 227 |
+
many repos over many commits × one repo.
|
| 228 |
+
|
| 229 |
+
**Discipline (both):** answers are **short judgment**, never file-path/line-number
|
| 230 |
+
lists. This is deliberate — see Tier A/B/C next.
|
| 231 |
+
|
| 232 |
+
**Models used (OpenRouter, OpenAI-compatible API):**
|
| 233 |
+
|
| 234 |
+
| Model | Role | Notes | Cost |
|
| 235 |
+
|-------|------|-------|------|
|
| 236 |
+
| `google/gemini-3.6-flash` | high-quality QA | **reasoning is mandatory** → needs generous `max_tokens` (3000–4000) or it returns empty | ~$0.0021 / QA |
|
| 237 |
+
| `google/gemma-4-31b-it` | bulk / cheap QA | non-reasoning, clean JSON | ~$0.001 / repo (~$1 per 1000 repos) |
|
| 238 |
+
|
| 239 |
+
The OpenRouter key lives in a **git-ignored `.env` (mode 600)** and is never pasted
|
| 240 |
+
into a command line.
|
| 241 |
+
|
| 242 |
+
---
|
| 243 |
+
|
| 244 |
+
## 7. What is learnable — Tier A / B / C
|
| 245 |
+
|
| 246 |
+
A LoRA adapter has finite capacity. We classify repo knowledge by whether a LoRA can
|
| 247 |
+
hold it — this drives the entire QA design:
|
| 248 |
+
|
| 249 |
+
- **Tier A — Judgment & conventions** (LEARNABLE). "This repo puts business logic in
|
| 250 |
+
services, not views." Compressible, generalizes. → **This is what we train on.**
|
| 251 |
+
- **Tier B — Structural gist** (LEARNABLE). "Auth flows through middleware." The kind
|
| 252 |
+
of thing, not the exact file.
|
| 253 |
+
- **Tier C — Exact recall & multi-hop** (NOT reliably learnable). "Line 412 of
|
| 254 |
+
`foo.py` calls `bar()`." This needs **retrieval (RAG)**, not weights.
|
| 255 |
+
|
| 256 |
+
So Memory-LoRA and RAG are **complementary**: the adapter carries Tier A/B judgment
|
| 257 |
+
for free (zero tokens); RAG handles Tier C exact lookups. The QA prompts forbid exact
|
| 258 |
+
file/line answers precisely so we never ask the LoRA to do a job it structurally
|
| 259 |
+
can't.
|
| 260 |
+
|
| 261 |
+
---
|
| 262 |
+
|
| 263 |
+
## 8. Datasets inventory
|
| 264 |
+
|
| 265 |
+
Everything lives under `data/` (git-ignored blobs). Sizes are approximate.
|
| 266 |
+
|
| 267 |
+
| Path | What | Scale |
|
| 268 |
+
|------|------|-------|
|
| 269 |
+
| `data/real_code2lora/` | **RepoPeftBench** from the `code2lora` HF org — 500 Python repos, repo-commit embeddings + diffs | 73,849 repo-commit rows; ~1.2 GB |
|
| 270 |
+
| `data/commitpack/multilang_commits.jsonl` | **CommitPackFT** shards, 9 languages | 25k+ distinct repos |
|
| 271 |
+
| `data/docs/multiview_sources.jsonl` | 6-view `view_text` per repo (input to QA gen) | growing (1000s of repos) |
|
| 272 |
+
| `data/embeddings/multiview_embeddings.parquet` | 12288-d multi-view repo embeddings | 1000+ repos |
|
| 273 |
+
| `data/embeddings/aligned6_embeddings.parquet` | **assembled training inputs** (repos with ≥1 QA) | 1058 repos (current) |
|
| 274 |
+
| `data/qna/repo_scoped_qa.jsonl` | repo-level judgment QA | 11,232 QA |
|
| 275 |
+
| `data/qna/techlead_qa_commitpack.jsonl` | commit-scoped breadth QA | 9,245 QA |
|
| 276 |
+
| `data/qna/techlead_qa.jsonl` | SWE-bench tech-lead QA | 2,786 QA |
|
| 277 |
+
| `data/qna/aligned6_qna.jsonl` | **assembled training targets** | 8,540 QA (current) |
|
| 278 |
+
| `data/openrouter_cache/` | per-prompt response cache | ~19 MB |
|
| 279 |
+
|
| 280 |
+
**Language balancing.** SWE-bench is ~79 % Django. Left alone, the dataset was 46 %
|
| 281 |
+
Django. `scripts/consolidate_qa.py` applies a **per-repo cap** (default 12–15 QA/repo)
|
| 282 |
+
which collapses Django to **~2.0 %** while preserving the 2400+ distinct repos'
|
| 283 |
+
diversity. `assemble_6view_dataset.py` applies the same cap when building the final
|
| 284 |
+
aligned set.
|
| 285 |
+
|
| 286 |
+
---
|
| 287 |
+
|
| 288 |
+
## 9. Experiments & results
|
| 289 |
+
|
| 290 |
+
Chronological, with the actual numbers we measured. Two families of runs.
|
| 291 |
+
|
| 292 |
+
### 9.1 Reproducing the paper (single-view, real RepoPeftBench)
|
| 293 |
+
|
| 294 |
+
| Run | What | Result |
|
| 295 |
+
|-----|------|--------|
|
| 296 |
+
| `full1` (early) | first end-to-end hypernetwork on converted real data | CR **EM 0.056–0.083**, EditSim ~0.27 — pipeline works, undertrained |
|
| 297 |
+
| `sixview`/converted-real (best single-view ckpt) | after more training | **CR EM 0.524, EditSim 0.635** |
|
| 298 |
+
| Paper (reference, H100) | their full run | CR EM **0.638** |
|
| 299 |
+
|
| 300 |
+
**Headline:** on real code, after only ~2.4 % of one epoch of local MPS training, we
|
| 301 |
+
reached **52.4 % cross-repo Exact Match** vs the paper's 63.8 % on a full H100 setup.
|
| 302 |
+
The mechanism demonstrably works — the generated adapter recovers repo-specific
|
| 303 |
+
identifiers the base model does not know.
|
| 304 |
+
|
| 305 |
+
### 9.2 The 6-view Tech-Lead model (the current line of work)
|
| 306 |
+
|
| 307 |
+
Loss is causal-LM cross-entropy on QA targets; lower is better. Three eval suites:
|
| 308 |
+
`cr_val` / `cr_test` (held-out *repos*) and `ir_test` (held-out *QA* of train repos).
|
| 309 |
+
|
| 310 |
+
| Run | Dataset | Best held-out `cr_test` loss | Notes |
|
| 311 |
+
|-----|---------|------------------------------|-------|
|
| 312 |
+
| `sixview_v1` | 515 repos / 3,988 QA (415 train repos) | **2.848** (step ~1060) | Overfit afterward: train loss fell to 1.75 while `cr_test` drifted to 3.35. Classic small-dataset ceiling. |
|
| 313 |
+
| `sixview_v2` | **1,058 repos / 8,540 QA (858 train repos)** | *in progress* | Resumed from `sixview_v1/head.best.pt`; 2× the data specifically to break v1's ceiling. |
|
| 314 |
+
|
| 315 |
+
`sixview_v1` metrics trajectory (from `runs/sixview_v1/metrics.jsonl`):
|
| 316 |
+
|
| 317 |
+
```
|
| 318 |
+
step 1245 cr_test 2.962 ir_test 2.535 (end of epoch 2 — near best)
|
| 319 |
+
step 1400 cr_test 3.245 ir_test 2.593 (overfitting begins)
|
| 320 |
+
step 1600 cr_test 3.352 ir_test 2.655 (train loss still falling → ceiling hit)
|
| 321 |
+
```
|
| 322 |
+
|
| 323 |
+
The v1→v2 story is the core empirical lesson: **the small aligned set was the
|
| 324 |
+
bottleneck, not the architecture** — hence the push to build 1000+ more repos.
|
| 325 |
+
|
| 326 |
+
---
|
| 327 |
+
|
| 328 |
+
## 10. Key decisions & lessons learned
|
| 329 |
+
|
| 330 |
+
The expensive knowledge. Read this section twice.
|
| 331 |
+
|
| 332 |
+
### 10.1 ⚠️ The MPS gradient-checkpointing memory leak (the big one)
|
| 333 |
+
|
| 334 |
+
**Symptom:** training with `gradient_checkpointing_enable()` (`use_reentrant=False`)
|
| 335 |
+
**leaked ~12 GB per step** and OOM'd the whole machine within a few steps.
|
| 336 |
+
|
| 337 |
+
**Diagnosis** (`scripts/diag_mps_leak.py`): forward-only was stable; train + checkpoint
|
| 338 |
+
leaked 39 GB → 18 GB free in 2 steps. Isolated the checkpointing path as the cause.
|
| 339 |
+
|
| 340 |
+
**Fix:** **`--no-gradient-checkpointing`.** We have enough unified memory to hold
|
| 341 |
+
activations without it once the multimodal towers sit idle. This is documented as a
|
| 342 |
+
standing memory (`mps-gradient-checkpointing-leak.md`).
|
| 343 |
+
|
| 344 |
+
### 10.2 ⚠️ `psutil` RSS is blind to MPS memory
|
| 345 |
+
|
| 346 |
+
Our first memory safety-net used `psutil` RSS / `ps -o rss` — it reported **< 1 GB**
|
| 347 |
+
while `top` showed **55–83 GB** actually in use. MPS (GPU) allocations don't show up
|
| 348 |
+
in process RSS.
|
| 349 |
+
|
| 350 |
+
**Fix:** the safety check uses **`psutil.virtual_memory().available`** (system-wide)
|
| 351 |
+
with a `--min-available-gb` floor (default 5). To *observe* MPS memory, use
|
| 352 |
+
`top -l 1 -pid <PID> -stats mem`, not `ps`.
|
| 353 |
+
|
| 354 |
+
### 10.3 Memory competition between concurrent jobs
|
| 355 |
+
|
| 356 |
+
Three concurrent jobs once pushed available memory under the 10 GB floor and training
|
| 357 |
+
self-stopped. **Lesson:** during MPS training, run data builds/embedding on **CPU**
|
| 358 |
+
(`--device cpu`) so they don't contend for the GPU/unified memory. We now routinely
|
| 359 |
+
run training (MPS) + QA gen (network) + multiview build (CPU) together without
|
| 360 |
+
contention.
|
| 361 |
+
|
| 362 |
+
### 10.4 Don't lose hours of training
|
| 363 |
+
|
| 364 |
+
Every long run writes **checkpoints every 50 steps** (overwriting `head.latest.pt`),
|
| 365 |
+
**every 30 minutes** (timestamped `head.tNNNNm.pt`), **per-epoch** (`head.epN.pt`),
|
| 366 |
+
and a **`head.best.pt`** on eval improvement. Runs are launched with `nohup … &
|
| 367 |
+
disown` so they survive terminal/session death. `sixview_v1` in fact survived a full
|
| 368 |
+
session interruption and kept training. Resume with `--resume-from <ckpt>` (loads head
|
| 369 |
+
weights; optimizer restarts fresh).
|
| 370 |
+
|
| 371 |
+
### 10.5 Data-quality corrections (user-driven)
|
| 372 |
+
|
| 373 |
+
- **"I still see lots of Django."** SWE-bench is Django-dominated. → per-repo cap +
|
| 374 |
+
multi-language sourcing dropped Django 46 % → 2.0 %.
|
| 375 |
+
- **"It must be good for any programming language."** → 9-language diversity via
|
| 376 |
+
CommitPackFT and language-agnostic view extraction.
|
| 377 |
+
- **"Where's the code context in the QA?"** → clarified the two-channel design: the
|
| 378 |
+
**repo embedding is the context channel**, the QA is only the target. They are
|
| 379 |
+
joined by `doc_id` at assembly time.
|
| 380 |
+
|
| 381 |
+
### 10.6 OpenRouter gotchas
|
| 382 |
+
|
| 383 |
+
- `gemini-3.6-flash` **returned empty** until we raised `max_tokens` — it's a
|
| 384 |
+
mandatory-reasoning model that spends tokens on hidden reasoning before content.
|
| 385 |
+
Reasoning **cannot be disabled** (400 error).
|
| 386 |
+
- CommitPackFT's HF loader is deprecated → fetch raw `data.jsonl` directly.
|
| 387 |
+
- `global MODEL` after use is a `SyntaxError` → set via `globals()["MODEL"] = ...`.
|
| 388 |
+
|
| 389 |
+
### 10.7 Performance fix worth knowing
|
| 390 |
+
|
| 391 |
+
Loading embeddings was 5+ min because `_list_to_f32_array` used a Python loop.
|
| 392 |
+
Vectorized via `col.combine_chunks().flatten().to_numpy()` → **~220× faster**.
|
| 393 |
+
|
| 394 |
+
---
|
| 395 |
+
|
| 396 |
+
## 11. Repository map
|
| 397 |
+
|
| 398 |
+
```
|
| 399 |
+
memory_lora/ # the library (importable package)
|
| 400 |
+
core.py # LoRA wrapper, MemoryLoRAHead hypernetwork,
|
| 401 |
+
# get_module_specs / replace_with_lora / inject_lora_weights,
|
| 402 |
+
# load_doc_rows / load_qna_rows
|
| 403 |
+
encoder.py # Qwen3 chunk + embed + mean/max pool (frozen)
|
| 404 |
+
codegraph.py # Python AST extractor (imports, sigs, call graph)
|
| 405 |
+
data_paths.py # local parquet/jsonl path resolver
|
| 406 |
+
|
| 407 |
+
scripts/
|
| 408 |
+
build_repo_multiview.py # clone → 6 views → 12288-d embeddings (multi-language, resume-safe)
|
| 409 |
+
generate_repo_scoped_qa.py # repo-level judgment QA (aligned to the 6 views)
|
| 410 |
+
generate_commitpack_qa.py # commit-scoped breadth QA across 1000s of distinct repos
|
| 411 |
+
generate_techlead_qa.py # SWE-bench tech-lead QA
|
| 412 |
+
generate_synthetic_dataset.py # original synthetic doc + QA generator
|
| 413 |
+
consolidate_qa.py # per-repo cap → language/domain balancing
|
| 414 |
+
assemble_6view_dataset.py # join embeddings ↔ all QA by repo → aligned6_{embeddings,qna}
|
| 415 |
+
augment_paraphrases.py # QA paraphrase augmentation
|
| 416 |
+
convert_real_code2lora.py # RepoPeftBench → our schema
|
| 417 |
+
build_doc_embeddings.py # encoder pass over documents
|
| 418 |
+
merge_corpora.py # combine multiple corpora
|
| 419 |
+
train_memory_lora.py # THE trainer (MPS, one-repo-per-step, checkpoints, TensorBoard)
|
| 420 |
+
train_direct_lora.py # baseline: plain per-repo LoRA (no hypernetwork)
|
| 421 |
+
eval_memory_lora.py # EM / EditSim recall eval on cr/ir splits
|
| 422 |
+
show_eval_examples.py # dump concrete base-vs-adapted examples
|
| 423 |
+
test_embed_this_repo.py # embed the current repo (pipeline demo)
|
| 424 |
+
test_recall_this_repo.py # query the adapted model about this repo
|
| 425 |
+
diag_mps_leak.py # the memory-leak isolation harness
|
| 426 |
+
|
| 427 |
+
data/ # git-ignored: embeddings, qna, sources, caches
|
| 428 |
+
runs/ # git-ignored: checkpoints, logs, metrics.jsonl, tb/
|
| 429 |
+
requirements.txt # torch 2.13 (MPS), transformers@main, openai, pyarrow, tensorboard…
|
| 430 |
+
.env # git-ignored, mode 600: OPENROUTER_API_KEY
|
| 431 |
+
```
|
| 432 |
+
|
| 433 |
+
---
|
| 434 |
+
|
| 435 |
+
## 12. How to run it
|
| 436 |
+
|
| 437 |
+
### Setup
|
| 438 |
+
|
| 439 |
+
```bash
|
| 440 |
+
python3 -m venv venv && source venv/bin/activate
|
| 441 |
+
pip install -r requirements.txt # installs transformers from git main
|
| 442 |
+
echo "OPENROUTER_API_KEY=sk-or-..." > .env && chmod 600 .env
|
| 443 |
+
```
|
| 444 |
+
|
| 445 |
+
Smoke-test the environment first (gates everything): confirm `transformers` main
|
| 446 |
+
loads `google/gemma-4-E2B` on `mps` and runs a text-only forward pass.
|
| 447 |
+
|
| 448 |
+
### Build data
|
| 449 |
+
|
| 450 |
+
```bash
|
| 451 |
+
# 1) multi-view embeddings for a repo list (CPU to stay off the GPU during training)
|
| 452 |
+
python scripts/build_repo_multiview.py \
|
| 453 |
+
--repos-file data/multilang_repo_list.txt --max-repos 1000 --device cpu
|
| 454 |
+
|
| 455 |
+
# 2) repo-scoped QA (cheap model) — appends, resume-safe, cached
|
| 456 |
+
./venv/bin/python scripts/generate_repo_scoped_qa.py \
|
| 457 |
+
--model google/gemma-4-31b-it --workers 10
|
| 458 |
+
|
| 459 |
+
# 3) balance + assemble the aligned training set
|
| 460 |
+
python scripts/consolidate_qa.py --per-repo-cap 12
|
| 461 |
+
python scripts/assemble_6view_dataset.py
|
| 462 |
+
# -> data/embeddings/aligned6_embeddings.parquet + data/qna/aligned6_qna.jsonl
|
| 463 |
+
```
|
| 464 |
+
|
| 465 |
+
### Train (the exact `sixview_v2` command)
|
| 466 |
+
|
| 467 |
+
```bash
|
| 468 |
+
nohup ./venv/bin/python scripts/train_memory_lora.py --output-dir sixview_v2 \
|
| 469 |
+
--resume-from runs/sixview_v1/head.best.pt \
|
| 470 |
+
--embeddings-path data/embeddings/aligned6_embeddings.parquet \
|
| 471 |
+
--qna-path data/qna/aligned6_qna.jsonl --epochs 100 --max-hours 8 \
|
| 472 |
+
--checkpoint-every-steps 50 --checkpoint-every-minutes 30 --epoch-ckpt-every 5 \
|
| 473 |
+
--eval-every-steps 300 --limit-eval-docs 40 --max-seq-len 512 --fixed-seq-len \
|
| 474 |
+
--max-qna-per-doc 12 --lm-micro-batch 2 --device mps --no-gradient-checkpointing \
|
| 475 |
+
--rank 16 --head-hidden-dim 128 --head-dropout 0.1 --weight-decay 0.05 \
|
| 476 |
+
--early-stop-patience 25 --lr 8e-5 --lr-total-steps 9000 --min-available-gb 5 \
|
| 477 |
+
> runs/sixview_v2_train.log 2>&1 &
|
| 478 |
+
disown
|
| 479 |
+
```
|
| 480 |
+
|
| 481 |
+
**Flags you must not forget:** `--no-gradient-checkpointing` (the leak),
|
| 482 |
+
`--device cpu` for builds during training (contention), `--min-available-gb`
|
| 483 |
+
(system-wide memory floor).
|
| 484 |
+
|
| 485 |
+
### Watch it
|
| 486 |
+
|
| 487 |
+
```bash
|
| 488 |
+
tensorboard --logdir runs/sixview_v2/tb # train/loss, train/lr, eval/{suite}_loss
|
| 489 |
+
tail -f runs/sixview_v2_train.log
|
| 490 |
+
```
|
| 491 |
+
|
| 492 |
+
### Evaluate & inspect
|
| 493 |
+
|
| 494 |
+
```bash
|
| 495 |
+
python scripts/eval_memory_lora.py --ckpt runs/sixview_v2/head.best.pt # EM / EditSim
|
| 496 |
+
python scripts/show_eval_examples.py # base vs adapted
|
| 497 |
+
```
|
| 498 |
+
|
| 499 |
+
---
|
| 500 |
+
|
| 501 |
+
## 13. Evaluation methodology
|
| 502 |
+
|
| 503 |
+
- **Splits (deterministic, by `md5(repo) % 100`):** 80 % train / 10 % `cr_val` /
|
| 504 |
+
10 % `cr_test` **by repo**, so cross-repo suites are **entirely held-out
|
| 505 |
+
repositories** the hypernetwork never trained on. Within train repos, ~15 % of QA
|
| 506 |
+
is held out → `ir_test` (in-repo generalization to unseen questions of seen repos).
|
| 507 |
+
- **Metrics:** causal-LM **eval loss** during training (fast, every N steps on
|
| 508 |
+
`--limit-eval-docs` docs to stay cheap on CPU), plus generation-time **Exact Match
|
| 509 |
+
(EM)** and **EditSim** for the recall eval.
|
| 510 |
+
- **The proof spot-check:** query the *adapted* model with repo-specific questions and
|
| 511 |
+
confirm the *base* (un-adapted) model gets them wrong/vague — proving the
|
| 512 |
+
**adapter**, not the base model's pretraining, does the work.
|
| 513 |
+
|
| 514 |
+
CPU eval of a float32 5B model is slow (~20 min for a full pass) → we cap eval docs
|
| 515 |
+
(e.g. 10–40) for in-loop evals and run full EM eval separately.
|
| 516 |
+
|
| 517 |
+
---
|
| 518 |
+
|
| 519 |
+
## 14. Costs & budget discipline
|
| 520 |
+
|
| 521 |
+
- **Spend baseline:** $31.00 (`runs/spend_baseline.txt`); ~**$33.90 total** to date;
|
| 522 |
+
~**$11 remaining**. The project is run under explicit budget caps ("spend at most
|
| 523 |
+
$4 more") with spend-guards.
|
| 524 |
+
- **Unit economics:** `gemini-3.6-flash` ≈ **$0.0021/QA**; `gemma-4-31b-it` ≈
|
| 525 |
+
**$0.001/repo (~$1 per 1000 repos)** — which is exactly why the 1000-repo expansion
|
| 526 |
+
uses the gemma model.
|
| 527 |
+
- **Free levers:** the per-prompt cache makes reruns free; embedding and training are
|
| 528 |
+
local (electricity only).
|
| 529 |
+
|
| 530 |
+
---
|
| 531 |
+
|
| 532 |
+
## 15. Current status & roadmap
|
| 533 |
+
|
| 534 |
+
**Live right now (three jobs in parallel, no contention):**
|
| 535 |
+
|
| 536 |
+
- **`sixview_v2` training** — resumed from `head.best.pt` on the doubled
|
| 537 |
+
**1,058-repo / 8,540-QA** dataset (858 steps/epoch), MPS. First held-out eval at
|
| 538 |
+
step 300 tells us whether doubling the data broke v1's 2.848 ceiling.
|
| 539 |
+
- **QA generation** — `gemma-4-31b-it` filling in all ~1,032 new repos for the
|
| 540 |
+
**complete** dataset (next training run).
|
| 541 |
+
- **Multiview build** — cloning/embedding toward the full +1,000-new target (CPU).
|
| 542 |
+
|
| 543 |
+
**Roadmap:**
|
| 544 |
+
|
| 545 |
+
1. Finish the complete 1000-new-repo dataset (embeddings + QA).
|
| 546 |
+
2. Assemble the full aligned set (~1,650 repos) and train **`sixview_v3`** on it.
|
| 547 |
+
3. Run generation-time **EM/EditSim** on the 6-view model (base vs adapted).
|
| 548 |
+
4. Push `head_hidden_dim` back up once on real GPUs; the 128 default was an
|
| 549 |
+
MPS-locality compromise.
|
| 550 |
+
5. Broaden Tier-A/B QA toward agent-harness use cases (Jira/ticket tracking,
|
| 551 |
+
diff/impact reasoning) already scaffolded in `generate_techlead_qa.py`.
|
| 552 |
+
|
| 553 |
+
**Open questions:**
|
| 554 |
+
|
| 555 |
+
- Does the 12288-d 6-view embedding actually beat the single 2048-d view on
|
| 556 |
+
generation EM, or only on loss? (loss says yes; EM eval pending)
|
| 557 |
+
- What's the real Tier-B ceiling — how much structural gist fits in rank-16?
|
| 558 |
+
- Optimal per-repo QA cap for the breadth/depth trade-off.
|
| 559 |
+
|
| 560 |
+
---
|
| 561 |
+
|
| 562 |
+
## 16. Glossary
|
| 563 |
+
|
| 564 |
+
- **Hypernetwork** — a network that outputs the weights of another network. Here:
|
| 565 |
+
repo embedding → LoRA (A,B) matrices.
|
| 566 |
+
- **LoRA** — Low-Rank Adaptation: `y = Wx + scaling · B(Ax)`, with `A,B` low-rank
|
| 567 |
+
(rank 16). We *generate* A,B instead of training them per-repo.
|
| 568 |
+
- **6 views** — graph / arch / history / contracts / conventions / ops; each 2048-d,
|
| 569 |
+
concatenated to 12288-d.
|
| 570 |
+
- **CR / IR** — cross-repo (held-out repos) / in-repo (held-out QA of seen repos).
|
| 571 |
+
- **EM / EditSim** — Exact Match / edit-distance similarity of generated vs gold.
|
| 572 |
+
- **Tier A/B/C** — judgment (learnable) / structural gist (learnable) / exact recall
|
| 573 |
+
(needs RAG).
|
| 574 |
+
- **MPS** — Apple's Metal Performance Shaders GPU backend for PyTorch.
|
| 575 |
+
- **RepoPeftBench** — the paper's benchmark; 500 Python repos, repo-commit
|
| 576 |
+
embeddings + diffs, IR/CR splits.
|
| 577 |
+
|
| 578 |
+
---
|
| 579 |
+
|
| 580 |
+
*Maintained as living documentation. If you change a default, a path, or a flag,
|
| 581 |
+
update the matching section here — onboarding depends on it.*
|
data/docs/documents.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/docs/multiview_sources.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/docs/multiview_sources_balanced.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/docs/techlead_sources.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/docs/techlead_sources_commitpack.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/embeddings/aligned6_embeddings.parquet
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4c86fc8e4a4abe8e47415e0ecd876627623fb02f9c9aabd3740a878319609e14
|
| 3 |
+
size 68653613
|
data/embeddings/multiview_embeddings.parquet
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:deb4c9f45b62fb7b552f27795054cfaf4ab5a511e94350eab1651e4941fbb3a9
|
| 3 |
+
size 88090938
|
data/multilang_repo_list.txt
ADDED
|
@@ -0,0 +1,3150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
RangeeGmbH/FreeRDP c
|
| 2 |
+
SpectoLabs/hoverfly go
|
| 3 |
+
saidie/plantuml-api java
|
| 4 |
+
teampopong/pokr.kr javascript
|
| 5 |
+
trevormunoz/katherine-anne php
|
| 6 |
+
imankulov/sentry python
|
| 7 |
+
waxpoetic/brotherly ruby
|
| 8 |
+
alerque/casile rust
|
| 9 |
+
geofffilippi/angular-cli typescript
|
| 10 |
+
pivotaltracker/PivotalCoreKit c
|
| 11 |
+
kubernetes-retired/cluster-registry go
|
| 12 |
+
palmfjord/twig-java java
|
| 13 |
+
TimBek2/phase-0 javascript
|
| 14 |
+
i-lateral/silverstripe-catalogue php
|
| 15 |
+
rnyberg/pyfibot python
|
| 16 |
+
neotericdesign/pubdraft ruby
|
| 17 |
+
osa1/tiny rust
|
| 18 |
+
sebastienbarbier/sebastienbarbier.com typescript
|
| 19 |
+
melonmanchan/k-and-r c
|
| 20 |
+
jehrhardt/bowling-game-go go
|
| 21 |
+
CS2103AUG2016-T15-C1/main java
|
| 22 |
+
motion/motion javascript
|
| 23 |
+
etu/0bRSS php
|
| 24 |
+
artefactual/archivematica-history python
|
| 25 |
+
mirego/rack-locale-root-redirect ruby
|
| 26 |
+
CryZe/livesplit-core rust
|
| 27 |
+
crossroads-education/eta-front typescript
|
| 28 |
+
vespa-engine/vespa c
|
| 29 |
+
bitly/go-hostpool go
|
| 30 |
+
edx/edx-app-android java
|
| 31 |
+
tesfaldet/bluebird javascript
|
| 32 |
+
Ecodev/gims php
|
| 33 |
+
caleb531/automata python
|
| 34 |
+
jtribe/redirector ruby
|
| 35 |
+
jgilchrist/rslike rust
|
| 36 |
+
auth0-blog/ng2-dinos typescript
|
| 37 |
+
Baltoli/peggo c
|
| 38 |
+
polydawn/refmt go
|
| 39 |
+
cbornet/generator-jhipster java
|
| 40 |
+
hanford/filepizza javascript
|
| 41 |
+
spatie/laravel-permission php
|
| 42 |
+
Antiun/account-invoicing python
|
| 43 |
+
tenforwardconsulting/crantastic ruby
|
| 44 |
+
xfix/enum-map rust
|
| 45 |
+
itchio/itch typescript
|
| 46 |
+
peteruhnak/pharo-vm c
|
| 47 |
+
prometheus/client_golang go
|
| 48 |
+
Yakindu/statecharts java
|
| 49 |
+
mbland/hubot-slack-github-issues javascript
|
| 50 |
+
anawatom/lavandula php
|
| 51 |
+
ElementalAlchemist/txircd python
|
| 52 |
+
arkon/Markus ruby
|
| 53 |
+
zanesterling/fatr rust
|
| 54 |
+
rcjsuen/dockerfile-language-server-nodejs typescript
|
| 55 |
+
carp-lang/Carp c
|
| 56 |
+
jabley/cf-metrics go
|
| 57 |
+
s-case/s-case-core java
|
| 58 |
+
grncdr/node-any-db javascript
|
| 59 |
+
routetopa/auth-server-2 php
|
| 60 |
+
kmee/stock-logistics-warehouse python
|
| 61 |
+
sophsec/wordlist ruby
|
| 62 |
+
sunjay/turtle rust
|
| 63 |
+
jonbern/fetch-retry typescript
|
| 64 |
+
Ultimaker/CuraEngine c
|
| 65 |
+
lucapette/deloominator go
|
| 66 |
+
smartnews/presto java
|
| 67 |
+
jonathanargentiero/istanbul-instrumenter-loader javascript
|
| 68 |
+
aedart/scaffold php
|
| 69 |
+
BT-rmartin/partner-contact python
|
| 70 |
+
davengeo/github ruby
|
| 71 |
+
matthiasbeyer/task-hookrs rust
|
| 72 |
+
rafaell-lycan/sabesp-mananciais-api typescript
|
| 73 |
+
iondbproject/iondb c
|
| 74 |
+
cburkert/go-statusbar go
|
| 75 |
+
realityforge/replicant java
|
| 76 |
+
itsananderson/cascadiafest javascript
|
| 77 |
+
herloct/pinger php
|
| 78 |
+
yuzie007/upho python
|
| 79 |
+
agrimm/resume ruby
|
| 80 |
+
zsiciarz/24daysofrust rust
|
| 81 |
+
JiraGoggles/jiragoggles-frontend typescript
|
| 82 |
+
llvm-mirror/clang c
|
| 83 |
+
ryanclarke/hugo go
|
| 84 |
+
bwyap/java-familyfeud java
|
| 85 |
+
ProseMirror/prosemirror-markdown javascript
|
| 86 |
+
Payum/Payum php
|
| 87 |
+
bfaludi/daprot python
|
| 88 |
+
joyent/lx-brand-image-tests ruby
|
| 89 |
+
dcoles/experiments rust
|
| 90 |
+
dainst/idai-components-2 typescript
|
| 91 |
+
basho-labs/riak-c-client c
|
| 92 |
+
goaltools/goal go
|
| 93 |
+
flanglet/kanzi java
|
| 94 |
+
asennikov/ember-g-map javascript
|
| 95 |
+
orchestral/config php
|
| 96 |
+
angr/cle python
|
| 97 |
+
yutarody/homebrew-cask ruby
|
| 98 |
+
bash/radium rust
|
| 99 |
+
sly7-7/ember.js typescript
|
| 100 |
+
geoffgarside/cocoagit c
|
| 101 |
+
nylar/wally go
|
| 102 |
+
rigregs/ez-rules java
|
| 103 |
+
GitbookIO/plugin-katex javascript
|
| 104 |
+
Kunstmaan/KunstmaanArticleBundle php
|
| 105 |
+
jmenglund/CollectionBatchTool python
|
| 106 |
+
dphaener/kanji ruby
|
| 107 |
+
onefrankguy/chifir rust
|
| 108 |
+
PRX/publish.prx.org typescript
|
| 109 |
+
wmadill/grant-lighting c
|
| 110 |
+
jessecarl/goDLX go
|
| 111 |
+
marques-work/gocd java
|
| 112 |
+
fleetlog/gmaps-signer javascript
|
| 113 |
+
stakx-io/stakx php
|
| 114 |
+
coleifer/scout python
|
| 115 |
+
SumOfUs/Champaign ruby
|
| 116 |
+
badboy/rustup-version-name rust
|
| 117 |
+
AzureAD/microsoft-authentication-library-for-js typescript
|
| 118 |
+
MattDevo/edk2 c
|
| 119 |
+
nicolasmccurdy/run go
|
| 120 |
+
cucumber/cucumber-jvm java
|
| 121 |
+
cletusw/eslint-plugin-local-rules javascript
|
| 122 |
+
Respect/Foundation php
|
| 123 |
+
hsercanatli/adaptivetuning python
|
| 124 |
+
AustenLamacraft/austenlamacraft.github.io ruby
|
| 125 |
+
google/serde_json_lenient rust
|
| 126 |
+
BibleBot/BibleBot typescript
|
| 127 |
+
elsys/po-homework c
|
| 128 |
+
perrito666/juju go
|
| 129 |
+
GlowstonePlusPlus/GlowstonePlusPlus java
|
| 130 |
+
jstransformers/jstransformer-reshape javascript
|
| 131 |
+
wandersonwhcr/romans php
|
| 132 |
+
krmaxwell/TRX python
|
| 133 |
+
vonconrad/cabinet ruby
|
| 134 |
+
jmacdonald/scribe rust
|
| 135 |
+
gamejolt/frontend-lib typescript
|
| 136 |
+
mesham/ndm c
|
| 137 |
+
VonC/gopanic go
|
| 138 |
+
b0noI/TicTacToe java
|
| 139 |
+
thoughtpalette/gulp-replace javascript
|
| 140 |
+
darimpulso/koala-framework php
|
| 141 |
+
svieira/Flask-HipPocket python
|
| 142 |
+
blinkboxbooks/common_config.rb ruby
|
| 143 |
+
diesel-rs/diesel rust
|
| 144 |
+
cardstack/cardstack typescript
|
| 145 |
+
spotify/JniHelpers c
|
| 146 |
+
jolshevski/chester go
|
| 147 |
+
sebastiansokolowski/ReservationSystem-BJ java
|
| 148 |
+
then/then-request javascript
|
| 149 |
+
M6Web/AmqpBundle php
|
| 150 |
+
capybaralet/fuel python
|
| 151 |
+
osaris/sp-gestion ruby
|
| 152 |
+
frewsxcv/tiny-http rust
|
| 153 |
+
Shopify/tinymce typescript
|
| 154 |
+
lis-epfl/MAVRIC_Library c
|
| 155 |
+
voxelbrain/pixelpixel go
|
| 156 |
+
SleeplessAcorn/DimensionallyTranscendentalTents java
|
| 157 |
+
mmalecki/package-json-dependencies-to-array javascript
|
| 158 |
+
KilikFr/TableBundle php
|
| 159 |
+
openstack/akanda-rug python
|
| 160 |
+
PRX/cms.prx.org ruby
|
| 161 |
+
fede1024/rust-rdkafka rust
|
| 162 |
+
orbitjs/orbit.js typescript
|
| 163 |
+
felipejfc/xserver-xorg-input-synaptics c
|
| 164 |
+
moncho/dry go
|
| 165 |
+
torodb/server java
|
| 166 |
+
patientslikeme/react-select-test-utils javascript
|
| 167 |
+
nicksagona/PopPHP php
|
| 168 |
+
glyph/txsni python
|
| 169 |
+
tsub/dotfiles ruby
|
| 170 |
+
lise-henry/crowbook-text-processing rust
|
| 171 |
+
glimmerjs/glimmer-vm typescript
|
| 172 |
+
fabriciofmsilva/labs c
|
| 173 |
+
art4711/bsearch go
|
| 174 |
+
tectronics/stickycode java
|
| 175 |
+
seattletimes/newsapp-template javascript
|
| 176 |
+
Becklyn/SearchBundle php
|
| 177 |
+
tiddlyweb/tiddlywebplugins.atom python
|
| 178 |
+
deep-cover/deep-cover ruby
|
| 179 |
+
Vectorious/geom-rs rust
|
| 180 |
+
agdsn/pycroft typescript
|
| 181 |
+
DBOTW/pick c
|
| 182 |
+
WarCluster/warcluster-server go
|
| 183 |
+
DadanielZ/incubator-eagle java
|
| 184 |
+
civicsource/knockout-place-picker javascript
|
| 185 |
+
khounnouk/ScnSocialAuth php
|
| 186 |
+
grimwm/py-dictobj python
|
| 187 |
+
rackspace-cookbooks/varnish ruby
|
| 188 |
+
Sgeo/hlist-old rust
|
| 189 |
+
pkarw/vue-storefront typescript
|
| 190 |
+
GPUOpen-Drivers/llvm c
|
| 191 |
+
kevinclark/indexer go
|
| 192 |
+
Distrotech/intellij-community java
|
| 193 |
+
pburtchaell/react-notification javascript
|
| 194 |
+
rogermelich/Auth php
|
| 195 |
+
amorison/qjobs python
|
| 196 |
+
silvermind/bookyt ruby
|
| 197 |
+
rlustin/lugh rust
|
| 198 |
+
anthonynsimon/parrot typescript
|
| 199 |
+
Smartling/ios-i18n c
|
| 200 |
+
julianec/justanotherircbot go
|
| 201 |
+
googleinterns/step43-2020 java
|
| 202 |
+
ShieldBattery/ShieldBattery javascript
|
| 203 |
+
KRDS/Validator php
|
| 204 |
+
blancltd/blanc-basic-pages python
|
| 205 |
+
Swirrl/digitalsocial ruby
|
| 206 |
+
iankronquist/rustyvisor rust
|
| 207 |
+
kamilmysliwiec/nest typescript
|
| 208 |
+
dancxjo/spell-dollars c
|
| 209 |
+
johnny-morrice/godless go
|
| 210 |
+
prophile/ludum-dare-30 java
|
| 211 |
+
SidKH/angular-starter-kit javascript
|
| 212 |
+
Sheco/cdda-itembrowser php
|
| 213 |
+
zchee/python-client python
|
| 214 |
+
jmfieldman/Mortar ruby
|
| 215 |
+
hwchen/keyring-rs rust
|
| 216 |
+
Anveio/mturk-engine typescript
|
| 217 |
+
webmaster128/botan c
|
| 218 |
+
sluceno/chuper go
|
| 219 |
+
xdrop/PassLock java
|
| 220 |
+
u-wave/hub javascript
|
| 221 |
+
markstory/mini-asset php
|
| 222 |
+
CBitLabs/django-globals python
|
| 223 |
+
jkotests/watir ruby
|
| 224 |
+
nwoeanhinnogaehr/llvm-rs rust
|
| 225 |
+
Kurtz1993/ionic-minify typescript
|
| 226 |
+
JuliaPackageMirrors/ParallelAccelerator.jl c
|
| 227 |
+
robbiev/ui go
|
| 228 |
+
loxal/FreeEthereum java
|
| 229 |
+
elliotaplant/tanks javascript
|
| 230 |
+
TypiCMS/Slides php
|
| 231 |
+
rgardner/ouimeaux python
|
| 232 |
+
project-octopus/octopodes ruby
|
| 233 |
+
rust-gnome/gtk rust
|
| 234 |
+
Jameskmonger/dependument typescript
|
| 235 |
+
nathanielng/code-templates c
|
| 236 |
+
golang/lint go
|
| 237 |
+
oscartu2/magical-kf java
|
| 238 |
+
Dynalon/Rainy javascript
|
| 239 |
+
Ben-Ho/koala-framework php
|
| 240 |
+
hsolbrig/SNOMEDToOWL python
|
| 241 |
+
azumakuniyuki/make-server ruby
|
| 242 |
+
uni-rs/uni.rs rust
|
| 243 |
+
cynicaloptimist/improved-initiative typescript
|
| 244 |
+
bbannier/ROOT c
|
| 245 |
+
go-gl/glfw go
|
| 246 |
+
hpautonomy/java-hod-client java
|
| 247 |
+
Sage/carbon javascript
|
| 248 |
+
swisnl/laravel-fulltext php
|
| 249 |
+
kevinschaul/open-in-github python
|
| 250 |
+
FlavourSys/rails-better-filters ruby
|
| 251 |
+
dskecse/rust_for_rubyists rust
|
| 252 |
+
RenovoSolutions/TypeScript-Angular-Utilities typescript
|
| 253 |
+
SteveCaine/MBTA-RestKit c
|
| 254 |
+
hackedu/website go
|
| 255 |
+
Azure-Samples/documentdb-java-todo-app java
|
| 256 |
+
kylestev/vue-animated-number javascript
|
| 257 |
+
enlim/core php
|
| 258 |
+
TangledWeb/tangled.auth python
|
| 259 |
+
bisscomm/refinerycms-products ruby
|
| 260 |
+
vhbit/lmdb-rs rust
|
| 261 |
+
JosephDuffy/josephduffy.co.uk typescript
|
| 262 |
+
tywkeene/Shell c
|
| 263 |
+
andybalholm/redwood go
|
| 264 |
+
fabiohxcx/socialbooksapi java
|
| 265 |
+
jbmusso/tinkergraph-js javascript
|
| 266 |
+
tastyigniter/TastyIgniter php
|
| 267 |
+
bbangert/retools python
|
| 268 |
+
wecohere/capacitor ruby
|
| 269 |
+
mbrubeck/rust-azure rust
|
| 270 |
+
manuth/MarkdownConverter typescript
|
| 271 |
+
jefbed/xstatus c
|
| 272 |
+
elves/elvish go
|
| 273 |
+
bsalimi/myria java
|
| 274 |
+
sqlectron/sqlectron-gui javascript
|
| 275 |
+
DanCassiano/App php
|
| 276 |
+
czpython/aldryn-faq python
|
| 277 |
+
mzazrivec/manageiq ruby
|
| 278 |
+
oli-obk/rust-pandoc rust
|
| 279 |
+
dolanmiu/docx typescript
|
| 280 |
+
bobrippling/ucc-c-compiler c
|
| 281 |
+
thoughtworks/talisman go
|
| 282 |
+
TeamTotemic/Totemic java
|
| 283 |
+
chiehwen/Node-Exercises javascript
|
| 284 |
+
TeamTyro/teamtyro.com php
|
| 285 |
+
alama/PSO2Proxy python
|
| 286 |
+
fpgentil/toy-robot-simulator ruby
|
| 287 |
+
kylewlacy/glitter rust
|
| 288 |
+
fabianweb/hue typescript
|
| 289 |
+
madf/jwtxx c
|
| 290 |
+
jaceju/go-md go
|
| 291 |
+
eshioji/trident-tutorial java
|
| 292 |
+
chi-bobolinks-2015/TheGoldenRecord javascript
|
| 293 |
+
alexcw234/feyAnthology php
|
| 294 |
+
10gen-labs/mongo-connector python
|
| 295 |
+
xpsurgery/shopping-cart ruby
|
| 296 |
+
nipunn1313/cargo rust
|
| 297 |
+
log0ymxm/node-harvest typescript
|
| 298 |
+
Zeacone/PlayPlan c
|
| 299 |
+
xgfone/go-tools go
|
| 300 |
+
tmaret/sling java
|
| 301 |
+
Plantia/app javascript
|
| 302 |
+
php-school/php-workshop php
|
| 303 |
+
makinacorpus/reportlab-ecomobile python
|
| 304 |
+
omise/girlscout ruby
|
| 305 |
+
kkawakam/rustyline rust
|
| 306 |
+
codarchlab/idai-field-client typescript
|
| 307 |
+
8l/ucc-c-compiler c
|
| 308 |
+
brettbuddin/campfire go
|
| 309 |
+
tuxetuxe/pchud java
|
| 310 |
+
flubstep/engvalues javascript
|
| 311 |
+
sampleOmont/quick php
|
| 312 |
+
devinmcgloin/advent python
|
| 313 |
+
kmerz/graveio ruby
|
| 314 |
+
indiv0/ferrum rust
|
| 315 |
+
invicticide/fractive typescript
|
| 316 |
+
appcom-interactive/MFSideMenu c
|
| 317 |
+
rocwong/neko go
|
| 318 |
+
basho/riak-java-client java
|
| 319 |
+
alphagov/static javascript
|
| 320 |
+
chriscohen/codeception-module-drupal-user-registry php
|
| 321 |
+
problemshift/kf5py python
|
| 322 |
+
reuven/modelingcommons ruby
|
| 323 |
+
nafarlee/thoughtfuck rust
|
| 324 |
+
GreenPix/dilia typescript
|
| 325 |
+
llvm-mirror/llvm c
|
| 326 |
+
oipwg/media-protocol go
|
| 327 |
+
cflint/CFLint java
|
| 328 |
+
SputterPuttRedux/storyvine_clone javascript
|
| 329 |
+
vladab/KnpTimeBundle php
|
| 330 |
+
PyO3/setuptools-rust python
|
| 331 |
+
aelogica/express_admin ruby
|
| 332 |
+
dorayakikun/alfred_jira_workflow rust
|
| 333 |
+
sMteX/WoWAnalyzer typescript
|
| 334 |
+
apple/swift-clang c
|
| 335 |
+
SpirentOrion/turnpike go
|
| 336 |
+
premkumarbalu/scsb-etl java
|
| 337 |
+
tmiller/network javascript
|
| 338 |
+
kaltar/Notify php
|
| 339 |
+
apoorvemohan/haas python
|
| 340 |
+
samasti/noosfero ruby
|
| 341 |
+
lyuboraykov/rust-exercises rust
|
| 342 |
+
arangodb/arangojs typescript
|
| 343 |
+
mnunberg/subjson c
|
| 344 |
+
equinox-io/equinox go
|
| 345 |
+
MXProgrammingClub/Chem-Helper java
|
| 346 |
+
sussol/mobile javascript
|
| 347 |
+
DoSomething/messagebroker-ds-PHP php
|
| 348 |
+
crsmithdev/arrow python
|
| 349 |
+
benjaminhyw/ArrayLists ruby
|
| 350 |
+
zummenix/mprovision rust
|
| 351 |
+
zuzusik/DefinitelyTyped typescript
|
| 352 |
+
onkwon/yaos c
|
| 353 |
+
polydawn/repeatr go
|
| 354 |
+
albertoruibal/gwt_android_emu java
|
| 355 |
+
t3b/t3b_template javascript
|
| 356 |
+
Metalaka/Central php
|
| 357 |
+
c4fcm/CLIFF-API-Client python
|
| 358 |
+
DynamoMTL/spree_gateway ruby
|
| 359 |
+
ekarlso/rust-metrics rust
|
| 360 |
+
FountainJS/generator-fountain-react typescript
|
| 361 |
+
jrobhoward/SCADAbase c
|
| 362 |
+
tendermint/tmsp go
|
| 363 |
+
kelemen/JTrim java
|
| 364 |
+
peplin/redmine_create_wiki_page javascript
|
| 365 |
+
nsams/koala-framework php
|
| 366 |
+
martinrusev/imbox python
|
| 367 |
+
PopulateTools/gobierto-dev ruby
|
| 368 |
+
SirRade/sbb-telegram-bot rust
|
| 369 |
+
akserg/ng2-toasty typescript
|
| 370 |
+
aacoppa/final c
|
| 371 |
+
gsamokovarov/jump go
|
| 372 |
+
shengmin/coding-problem java
|
| 373 |
+
holmwell/circle-blvd javascript
|
| 374 |
+
orocrm/platform php
|
| 375 |
+
favien/favien python
|
| 376 |
+
chef-cookbooks/memcached ruby
|
| 377 |
+
andschwa/rust-genetic-algorithm rust
|
| 378 |
+
blackbaud/skyux2 typescript
|
| 379 |
+
tulindanil/SEUIKit c
|
| 380 |
+
dominichamon/gotrace go
|
| 381 |
+
stelar7/L4J8 java
|
| 382 |
+
saurabh6790/frappe javascript
|
| 383 |
+
WellCommerce/CurrencyBundle php
|
| 384 |
+
thomwiggers/django-mongodbforms python
|
| 385 |
+
tablexi/restforce-db ruby
|
| 386 |
+
AndrewBrinker/rust-www rust
|
| 387 |
+
Microsoft/TypeScript typescript
|
| 388 |
+
approach0/search-engine c
|
| 389 |
+
duckbrain/ldss go
|
| 390 |
+
tobiasheine/Movies java
|
| 391 |
+
Mangopay/mangopay2-nodejs-sdk javascript
|
| 392 |
+
robobalasko/OpenEstateAgent php
|
| 393 |
+
anthonysandrin/kafka-utils python
|
| 394 |
+
mlomnicki/rails_event_store ruby
|
| 395 |
+
aetherknight/fractal-rs rust
|
| 396 |
+
XavierGuichet/bemoove-front typescript
|
| 397 |
+
kmuzalewska/j-pet-framework c
|
| 398 |
+
anacrolix/torrent go
|
| 399 |
+
box/mojito java
|
| 400 |
+
janga1997/Patterns javascript
|
| 401 |
+
lenar/assetic php
|
| 402 |
+
dplucenio/heat_diffusion_experiment python
|
| 403 |
+
things23/infoblox_client ruby
|
| 404 |
+
thenyeguy/oxcable rust
|
| 405 |
+
artsy/eigen typescript
|
| 406 |
+
cs50sacramento/source-code-1617 c
|
| 407 |
+
Symantec/Dominator go
|
| 408 |
+
aureliano/e-docs java
|
| 409 |
+
jmeas/gistbook javascript
|
| 410 |
+
bendubuisson/silverstripe-cacheinclude php
|
| 411 |
+
bgyori/bioagents python
|
| 412 |
+
divoxx/ruby-php-serialization ruby
|
| 413 |
+
asomers/mockall rust
|
| 414 |
+
nteract/nteract typescript
|
| 415 |
+
bewuethr/stroustrup_ppp c
|
| 416 |
+
ninchat/ninchat-go go
|
| 417 |
+
blackberry/cordova-blackberry java
|
| 418 |
+
nyc-island-foxes-2016/kiwi-overflow javascript
|
| 419 |
+
webfactorybulgaria/Core php
|
| 420 |
+
plainas/tq python
|
| 421 |
+
kbrock/rubygems.org ruby
|
| 422 |
+
redox-os/kernel rust
|
| 423 |
+
Microsoft/vscode-comment typescript
|
| 424 |
+
swarmer/restnotifier c
|
| 425 |
+
bmorton/deployster go
|
| 426 |
+
helycopternicht/elazarev java
|
| 427 |
+
xdv/gatewayd javascript
|
| 428 |
+
za419/GAMR php
|
| 429 |
+
vesln/robber.py python
|
| 430 |
+
unepwcmc/SAPI ruby
|
| 431 |
+
despawnerer/langid-rs rust
|
| 432 |
+
yuki24/force typescript
|
| 433 |
+
goblint/analyzer c
|
| 434 |
+
ReactiveGo/rx go
|
| 435 |
+
cisco-system-traffic-generator/trex-java-sdk java
|
| 436 |
+
heroku/cli javascript
|
| 437 |
+
zachgibson/thewhitneypaige.com php
|
| 438 |
+
dirn/Simon python
|
| 439 |
+
walle/gas ruby
|
| 440 |
+
Marwes/embed_lang rust
|
| 441 |
+
sysgears/apollo-universal-starter-kit typescript
|
| 442 |
+
wiiudev/pyGecko c
|
| 443 |
+
brightbox/gobrightbox go
|
| 444 |
+
Shyri/long-task-service java
|
| 445 |
+
dennisfrank/patternlab-scaffolding javascript
|
| 446 |
+
wunderkraut/WunderTools php
|
| 447 |
+
plone/plone.server python
|
| 448 |
+
cysjonathan/coursemology2 ruby
|
| 449 |
+
rsertelon/habitat rust
|
| 450 |
+
start/up typescript
|
| 451 |
+
skarnet/s6-rc c
|
| 452 |
+
mattheath/kraken go
|
| 453 |
+
ming13/gambit java
|
| 454 |
+
jdthomas718/ClassRat javascript
|
| 455 |
+
andreas22/omnipay-fasapay php
|
| 456 |
+
lauft/timew-report python
|
| 457 |
+
jurrick/mighty_grid ruby
|
| 458 |
+
rust-av/rust-av rust
|
| 459 |
+
seokju-na/geeks-diary typescript
|
| 460 |
+
rbsexton/sockpuppet c
|
| 461 |
+
k0pernicus/goyave go
|
| 462 |
+
Blackrush/Rocket java
|
| 463 |
+
tum-ase-33/rest-server javascript
|
| 464 |
+
rowanhill/wiremock-php php
|
| 465 |
+
AmiiThinks/amii-tf-nn python
|
| 466 |
+
yous/sawarineko ruby
|
| 467 |
+
ragnese/exercism-rust rust
|
| 468 |
+
Nersent/Wexond typescript
|
| 469 |
+
xNUTs/MIT-Mobile-for-iOS c
|
| 470 |
+
osuripple/api go
|
| 471 |
+
metova/privvy java
|
| 472 |
+
uiheros/react-native-redux-todo-list javascript
|
| 473 |
+
ppy/osu-web php
|
| 474 |
+
ludwiktrammer/django-tagging-autocomplete python
|
| 475 |
+
paulelliott/authem ruby
|
| 476 |
+
aturon/async-benches rust
|
| 477 |
+
shioyang/StatsBar typescript
|
| 478 |
+
htcondor/htcondor c
|
| 479 |
+
mojotech/situation-room go
|
| 480 |
+
KeithYokoma/Amalgam java
|
| 481 |
+
mwilliamson/mammoth.js javascript
|
| 482 |
+
talib570/LazyRecord php
|
| 483 |
+
pyinvoke/invocations python
|
| 484 |
+
rrrene/inch ruby
|
| 485 |
+
graydon/rust rust
|
| 486 |
+
treylon/node-secure-password typescript
|
| 487 |
+
SoylentGraham/libmv c
|
| 488 |
+
captncraig/caddy go
|
| 489 |
+
kierarad/gocd java
|
| 490 |
+
uw-it-aca/myuw javascript
|
| 491 |
+
jdesrosiers/resourceful php
|
| 492 |
+
jaylett/django_exceptional_middleware python
|
| 493 |
+
influitive/markety ruby
|
| 494 |
+
vojtechkral/cargo rust
|
| 495 |
+
gpbl/react-day-picker typescript
|
| 496 |
+
radare/spp c
|
| 497 |
+
magic003/alice go
|
| 498 |
+
stevenpost/beaform java
|
| 499 |
+
sindresorhus/ava javascript
|
| 500 |
+
pollopolea/core php
|
| 501 |
+
nosamanuel/dj-queryset-manager python
|
| 502 |
+
rapid7/metasploit-credential ruby
|
| 503 |
+
daboross/fern-rs rust
|
| 504 |
+
StoDevX/AAO-React-Native typescript
|
| 505 |
+
actinium/cppMatrix c
|
| 506 |
+
antham/envh go
|
| 507 |
+
bink81/java-experiments java
|
| 508 |
+
Orodan/Hilary javascript
|
| 509 |
+
barryvdh/laravel-debugbar php
|
| 510 |
+
ap--/python-oceanoptics python
|
| 511 |
+
key-amb/poloxy ruby
|
| 512 |
+
sourrust/flac rust
|
| 513 |
+
microsoft/vscode typescript
|
| 514 |
+
enverarslan/DataStructures c
|
| 515 |
+
efritz/reception go
|
| 516 |
+
ozwillo/ozwillo-kernel java
|
| 517 |
+
frocher/bnb_app javascript
|
| 518 |
+
jjjjcccjjf/davao-aguilas php
|
| 519 |
+
millerdev/django-nose python
|
| 520 |
+
alcesleo/lasp ruby
|
| 521 |
+
faern/rips rust
|
| 522 |
+
andrerpena/react-mde typescript
|
| 523 |
+
TeamVee-Kanas/android_kernel_samsung_kanas c
|
| 524 |
+
viciious/go-tarantool go
|
| 525 |
+
VKCOM/vk-java-sdk java
|
| 526 |
+
satyavh/meteor-emails javascript
|
| 527 |
+
devmophp/DevmoPHP php
|
| 528 |
+
ssanderson/interface python
|
| 529 |
+
DigitalCurationCentre/roadmap ruby
|
| 530 |
+
cosmo0920/ruroonga_command rust
|
| 531 |
+
AgentME/DefinitelyTyped typescript
|
| 532 |
+
abanaiyan/sniper c
|
| 533 |
+
polydawn/go-sup go
|
| 534 |
+
micheljung/downlords-faf-client java
|
| 535 |
+
i-lateral/silverstripe-stripe-forms javascript
|
| 536 |
+
grrr-amsterdam/garp3 php
|
| 537 |
+
ryanraaum/oldowan.mtdna python
|
| 538 |
+
ctti-clinicaltrials/aact ruby
|
| 539 |
+
rust-lang/miri rust
|
| 540 |
+
influxdata/influxdb typescript
|
| 541 |
+
svn2github/webrtc-Revision-8758 c
|
| 542 |
+
kusabashira/acgen go
|
| 543 |
+
i-net-software/JWebAssembly java
|
| 544 |
+
HPI-Hackathon/find-my-car javascript
|
| 545 |
+
onticsoluciones/nofraud php
|
| 546 |
+
oemof/feedinlib python
|
| 547 |
+
negativetwelve/react-native-lookback ruby
|
| 548 |
+
zonyitoo/bson-rs rust
|
| 549 |
+
DTU-R3/ArloBot typescript
|
| 550 |
+
kenhys/fake-lock-screen-pattern c
|
| 551 |
+
dylanvee/libtorrent-go go
|
| 552 |
+
Aeronica/mxTune java
|
| 553 |
+
medikoo/es5-ext javascript
|
| 554 |
+
Khan/phabricator php
|
| 555 |
+
madmaze/pytesseract python
|
| 556 |
+
thogg4/spree ruby
|
| 557 |
+
SBSTP/rust-igd rust
|
| 558 |
+
blockstack/opendig typescript
|
| 559 |
+
LTD-Beget/dovecot c
|
| 560 |
+
jimmified/jimmify-server go
|
| 561 |
+
mbrossard/cryptonit-cloud java
|
| 562 |
+
mpalourdio/SpringBootAngularHTML5 javascript
|
| 563 |
+
DoSomething/rogue php
|
| 564 |
+
timraasveld/ansible-string-split-filter python
|
| 565 |
+
kstarsinic/homebrew-versions ruby
|
| 566 |
+
google/rrg rust
|
| 567 |
+
ProtonMail/WebClient typescript
|
| 568 |
+
smaccm/camkes-tool c
|
| 569 |
+
weaviate/weaviate go
|
| 570 |
+
parzonka/prm4j java
|
| 571 |
+
serverboards/serverboards javascript
|
| 572 |
+
DerManoMann/acache php
|
| 573 |
+
otknoy/michishiki_api_server python
|
| 574 |
+
eregon/mspec ruby
|
| 575 |
+
copy/v86 rust
|
| 576 |
+
BeSite/jQuery.mmenu typescript
|
| 577 |
+
SiftScience/sift-ios c
|
| 578 |
+
kwagdy/koding-1 go
|
| 579 |
+
steve1rm/busbymovies java
|
| 580 |
+
donlink1/jolliTestSideBar javascript
|
| 581 |
+
christopher-johnson/phabricator php
|
| 582 |
+
alexmilesyounger/ds_basics python
|
| 583 |
+
BinaryMuse/rforce-wrapper ruby
|
| 584 |
+
carols10cents/sassers rust
|
| 585 |
+
ChronusEU/lib-tminus.js typescript
|
| 586 |
+
erwango/zephyr c
|
| 587 |
+
icambridge/gomposer go
|
| 588 |
+
iychoi/biospectra java
|
| 589 |
+
stencila/node javascript
|
| 590 |
+
WWXD/WorldWeb-XD php
|
| 591 |
+
adampiskorski/lpr_poc python
|
| 592 |
+
airslie/renalware-core ruby
|
| 593 |
+
yupferris/rustendo64 rust
|
| 594 |
+
sammydre/ts-for-gjs typescript
|
| 595 |
+
mcschroeder/ghc c
|
| 596 |
+
herald-it/goncord go
|
| 597 |
+
CS2103JAN2017-T16-B4/main java
|
| 598 |
+
nossas/bonde-client javascript
|
| 599 |
+
jordanv215/moparvinson-jordanpwp php
|
| 600 |
+
ranisalt/enigma python
|
| 601 |
+
GCorbel/smart_management ruby
|
| 602 |
+
pgrzesik/learning-rust rust
|
| 603 |
+
crowi/crowi typescript
|
| 604 |
+
royel21/STM32F103GNU c
|
| 605 |
+
90TechSAS/libgo-docker-guard go
|
| 606 |
+
robolectric/deckard-maven java
|
| 607 |
+
kayaelle/msol-badger javascript
|
| 608 |
+
dadish/ProcessGraphQL php
|
| 609 |
+
infOpen/ansible-role-vsftpd python
|
| 610 |
+
rapid7/sonar-client ruby
|
| 611 |
+
attilahorvath/exercism-rust rust
|
| 612 |
+
Workable/aggregator-eip typescript
|
| 613 |
+
vinamarora8/IAAI c
|
| 614 |
+
madhanrm/hcsshim go
|
| 615 |
+
OpenAMEE/amee.platform.api java
|
| 616 |
+
tomanistor/osprey javascript
|
| 617 |
+
jolantis/altair php
|
| 618 |
+
chubbymaggie/asap python
|
| 619 |
+
riyad/homebrew-cask ruby
|
| 620 |
+
Grieverheart/dsfmt-rs rust
|
| 621 |
+
videogular/videogular2 typescript
|
| 622 |
+
agacek/util_libs c
|
| 623 |
+
nekikara/flagparse go
|
| 624 |
+
nisrulz/android-examples java
|
| 625 |
+
Flieral/Announcer-Service javascript
|
| 626 |
+
borNfreee/tactician-domain-events php
|
| 627 |
+
girder/girder_worker python
|
| 628 |
+
cohei/homebrew-cask ruby
|
| 629 |
+
vickenty/perl-xs rust
|
| 630 |
+
AArnott/Nerdbank.GitVersioning typescript
|
| 631 |
+
showcode/tools c
|
| 632 |
+
Anaminus/rbxmk go
|
| 633 |
+
capergroup/bayou java
|
| 634 |
+
ayrtonvwf/lite-admin javascript
|
| 635 |
+
fashionweb/moraso php
|
| 636 |
+
atiberghien/makerscience-server python
|
| 637 |
+
hakanensari/peddler ruby
|
| 638 |
+
w4tson/early-tea rust
|
| 639 |
+
ashwinr/DefinitelyTyped typescript
|
| 640 |
+
benjic/web-server c
|
| 641 |
+
daemonl/go_lib go
|
| 642 |
+
indr/335 java
|
| 643 |
+
jwadhams/json-logic-js javascript
|
| 644 |
+
tehoko/lane php
|
| 645 |
+
KuChanTung/Python python
|
| 646 |
+
clappr/clappr-ios ruby
|
| 647 |
+
algorithm-ninja/task-wizard rust
|
| 648 |
+
Atyantik/react-pwa typescript
|
| 649 |
+
artem-ogre/simpson c
|
| 650 |
+
cloudfoundry/cli go
|
| 651 |
+
mickkay/MinecraftForge java
|
| 652 |
+
alfredoem/gulp-prelude javascript
|
| 653 |
+
jasny/formbuilder-angular php
|
| 654 |
+
globocom/database-as-a-service python
|
| 655 |
+
hotvulcan/whitehall ruby
|
| 656 |
+
brianp/muxed rust
|
| 657 |
+
unional/ava-fixture typescript
|
| 658 |
+
ecaselles/Kiwi c
|
| 659 |
+
pasinskim/deployments go
|
| 660 |
+
grayben/10K-item-extractor java
|
| 661 |
+
benrowe/laravel-config javascript
|
| 662 |
+
anomalylabs/users-module php
|
| 663 |
+
Stark-Mountain/meetup-facebook-bot python
|
| 664 |
+
Shopify/shipit-engine ruby
|
| 665 |
+
nbigaouette/rust-sorting rust
|
| 666 |
+
mixitconf/mixit typescript
|
| 667 |
+
grigaci/BIObjCHelpers c
|
| 668 |
+
pgombola/gomad go
|
| 669 |
+
core9/module-authentication-standard java
|
| 670 |
+
ecohealthalliance/GoodQuestion javascript
|
| 671 |
+
SlateFoundation/slate php
|
| 672 |
+
claudiopastorini/claudiopastorini.github.io python
|
| 673 |
+
linkedin/cassette ruby
|
| 674 |
+
veorq/oee rust
|
| 675 |
+
Dart-Code/Dart-Code typescript
|
| 676 |
+
conformal/spectrwm c
|
| 677 |
+
tbroyer/ocspd go
|
| 678 |
+
castle/castle-java java
|
| 679 |
+
meisyal/MIM javascript
|
| 680 |
+
Viktor-s/f php
|
| 681 |
+
b123400/purescript-ide-sublime python
|
| 682 |
+
bengler/tiramisu ruby
|
| 683 |
+
BonsaiDen/discord-bot rust
|
| 684 |
+
ecsnavarretemit/sarai-ng2 typescript
|
| 685 |
+
Zaladar/PPM c
|
| 686 |
+
SteelSeries/golisp go
|
| 687 |
+
Techern/carpentersblocks java
|
| 688 |
+
martindale/fabric javascript
|
| 689 |
+
RoboJackets/apiary php
|
| 690 |
+
bshaffer/appengine-python-vm-hello python
|
| 691 |
+
jwt/ruby-jwt ruby
|
| 692 |
+
DualSpark/rust-aws rust
|
| 693 |
+
fqqb/yamcs typescript
|
| 694 |
+
jsventek/Cache c
|
| 695 |
+
rainycape/gondola go
|
| 696 |
+
obidea/semantika-cli2 java
|
| 697 |
+
tightenco/ziggy javascript
|
| 698 |
+
phpgt/webengine php
|
| 699 |
+
chop-dbhi/django-webhooks python
|
| 700 |
+
stanclai/redmine_git_hosting ruby
|
| 701 |
+
mrobinson/rust-layers rust
|
| 702 |
+
dpmcmlxxvi/turf typescript
|
| 703 |
+
skarnet/skalibs c
|
| 704 |
+
irwansyahwii/Pattern-Oriented-Software-Architecture-With-Go go
|
| 705 |
+
FAForever/faf-java-api java
|
| 706 |
+
rafaelstz/regenerator javascript
|
| 707 |
+
scherersoftware/cake-monitor php
|
| 708 |
+
jwarshaw/RaspberryDrive python
|
| 709 |
+
jinutm/silverprod ruby
|
| 710 |
+
aidancully/rust rust
|
| 711 |
+
shlomiassaf/DefinitelyTyped typescript
|
| 712 |
+
Tatsh/libbinarycookies c
|
| 713 |
+
lsk-kun/lantern go
|
| 714 |
+
wbknez/schelling java
|
| 715 |
+
rogierslag/mjml javascript
|
| 716 |
+
IronSummitMedia/startbootstrap-freelancer php
|
| 717 |
+
aikramer2/spaCy python
|
| 718 |
+
patatepartie/local_apt ruby
|
| 719 |
+
Twinklebear/tray_rust rust
|
| 720 |
+
lathonez/clicker typescript
|
| 721 |
+
wistoch/meego-app-browser c
|
| 722 |
+
pachyderm/pfs go
|
| 723 |
+
nearit/Android-SDK java
|
| 724 |
+
trevormunoz/katherine-anne javascript
|
| 725 |
+
APaikens/GoalioForgotPassword php
|
| 726 |
+
alexgarciac/scrapi python
|
| 727 |
+
fgrehm/chef-dokku ruby
|
| 728 |
+
BurntSushi/regexp rust
|
| 729 |
+
raviqqe/code2d typescript
|
| 730 |
+
llvm-mirror/compiler-rt c
|
| 731 |
+
sgeb/go-tuikit go
|
| 732 |
+
thatafischer/feevale-multiuserchat-2015 java
|
| 733 |
+
LLK/scratch-vm javascript
|
| 734 |
+
juriansluiman/SlmQueueBeanstalkd php
|
| 735 |
+
karel-brinda/prophyle python
|
| 736 |
+
stevenhaddox/cookbook-rvm_fw ruby
|
| 737 |
+
OJFord/tapioca rust
|
| 738 |
+
terascope/teraslice typescript
|
| 739 |
+
HenryRLee/PokerHandEvaluator c
|
| 740 |
+
FurqanSoftware/papyrus go
|
| 741 |
+
zafarella/java-design-patterns java
|
| 742 |
+
jpartogi/projexion javascript
|
| 743 |
+
sitkoru/context-cache php
|
| 744 |
+
etataurov/pytest python
|
| 745 |
+
code-management/netrc ruby
|
| 746 |
+
oconnor0/system-zero rust
|
| 747 |
+
driftyco/ionic-cli typescript
|
| 748 |
+
strazzere/dexterity c
|
| 749 |
+
vonwenm/fnlog go
|
| 750 |
+
smithkm/gcs java
|
| 751 |
+
ShawnTe/guardian javascript
|
| 752 |
+
aginev/datagrid php
|
| 753 |
+
khchine5/opal python
|
| 754 |
+
hashicorp/vault-rails ruby
|
| 755 |
+
ddevlin/rustlings rust
|
| 756 |
+
Retrospring/retrospring typescript
|
| 757 |
+
gumpt/cilium c
|
| 758 |
+
Southern/async go
|
| 759 |
+
Slikey/EffectLib java
|
| 760 |
+
c4fcm/Promise-Tracker-Builder javascript
|
| 761 |
+
friendica/friendica php
|
| 762 |
+
hatbot-team/hatbot_resources python
|
| 763 |
+
weddingparty/epicify ruby
|
| 764 |
+
DarkEld3r/match_any rust
|
| 765 |
+
bkimminich/juice-shop typescript
|
| 766 |
+
LiuShulong/Kiwi c
|
| 767 |
+
mistsys/tuntap go
|
| 768 |
+
microsoftgraph/msgraph-sdk-java java
|
| 769 |
+
TrueCar/gluestick javascript
|
| 770 |
+
Programie/AlbumShowcase php
|
| 771 |
+
ellmetha/machina-singlepageapp python
|
| 772 |
+
zettajs/ZettaKit ruby
|
| 773 |
+
jorendorff/cell-gc rust
|
| 774 |
+
orangain/kifu-notebook typescript
|
| 775 |
+
Lavesson/api-mock c
|
| 776 |
+
bragr/dns go
|
| 777 |
+
m4tx/arroch java
|
| 778 |
+
BOZ2323/virun javascript
|
| 779 |
+
cedricziel/l5-shariff php
|
| 780 |
+
seibert/numba python
|
| 781 |
+
CharlesMilam/tatalog ruby
|
| 782 |
+
Laastine/zombie-shooter rust
|
| 783 |
+
gamejolt/widgets typescript
|
| 784 |
+
sjinks/qt_eventdispatcher_epoll c
|
| 785 |
+
janos/httputils go
|
| 786 |
+
cstroe/spendhawk-java java
|
| 787 |
+
Chan4077/angular-rss-reader javascript
|
| 788 |
+
WaveHack/OpenDominion php
|
| 789 |
+
earlwlkr/POICrawler python
|
| 790 |
+
aarongustafson/jekyll-crosspost_to_medium ruby
|
| 791 |
+
wahn/Rust_Examples rust
|
| 792 |
+
graywolf336/temporary-rocketlets-ts-definition typescript
|
| 793 |
+
LuboO/iCalendar-parser_PA193_Rteam c
|
| 794 |
+
mmstick/i3gostatusbar go
|
| 795 |
+
DarkMorford/BetterThanWeagles java
|
| 796 |
+
wycats/blue-ridge javascript
|
| 797 |
+
marcoraddatz/activecollab-slack php
|
| 798 |
+
ideascube/ideascube python
|
| 799 |
+
cosmo0920/homebrew-cask-coreclr ruby
|
| 800 |
+
rust-fuzz/cargo-fuzz rust
|
| 801 |
+
the-concierge/concierge typescript
|
| 802 |
+
saminiir/level-ip c
|
| 803 |
+
dpb587/metalink go
|
| 804 |
+
AdamsTHDev/mgl-planlv-project java
|
| 805 |
+
getfrank/tachyons javascript
|
| 806 |
+
mb-projects/mbtheme-mtalents php
|
| 807 |
+
group-policy/rally python
|
| 808 |
+
tsuru/homebrew-tsuru ruby
|
| 809 |
+
danylaporte/node-rust-resemble rust
|
| 810 |
+
2muchcoffeecom/ngx-restangular typescript
|
| 811 |
+
HPCToolkit/hpctoolkit c
|
| 812 |
+
cloudfoundry/staticfile-buildpack go
|
| 813 |
+
gernd/simple-site-mon java
|
| 814 |
+
keybase/client javascript
|
| 815 |
+
WyriHaximus/TwigView php
|
| 816 |
+
funkybob/paws python
|
| 817 |
+
travis-ci/packer-templates ruby
|
| 818 |
+
Sgeo/hlist rust
|
| 819 |
+
ikr/react-period-of-stay-input typescript
|
| 820 |
+
biosbits/libffi c
|
| 821 |
+
jimthematrix/fabric go
|
| 822 |
+
billy93/forplay java
|
| 823 |
+
zdfs/bliss javascript
|
| 824 |
+
Exercise/FOQElasticaBundle php
|
| 825 |
+
analyst-collective/dbt python
|
| 826 |
+
thecartercenter/elmo ruby
|
| 827 |
+
google/tock-on-titan rust
|
| 828 |
+
NakedObjectsGroup/NakedObjectsFramework typescript
|
| 829 |
+
leapmotion/autowiring c
|
| 830 |
+
cerana/cerana go
|
| 831 |
+
ganymedes01/Et-Futurum java
|
| 832 |
+
Dermah/pulsar javascript
|
| 833 |
+
nachopro/followlink php
|
| 834 |
+
scanner-research/scanner python
|
| 835 |
+
amatriain/feedbunch ruby
|
| 836 |
+
jpypi/rustix rust
|
| 837 |
+
ruedap/alfred-font-awesome-workflow typescript
|
| 838 |
+
Tricertops/Objective-Chain c
|
| 839 |
+
brandur/sorg go
|
| 840 |
+
balazspete/crystal-game java
|
| 841 |
+
marynganga/FunSquare javascript
|
| 842 |
+
naturalsciences/Darwin php
|
| 843 |
+
ScanOC/trunk-player python
|
| 844 |
+
qnyp/smiling ruby
|
| 845 |
+
dpc/slog-rs rust
|
| 846 |
+
slackapi/node-slack-sdk typescript
|
| 847 |
+
dmtaylor/cmps111-proj4 c
|
| 848 |
+
oshothebig/goflow go
|
| 849 |
+
MC-U-Team/U-Team-Core java
|
| 850 |
+
bbcyyb/on-tasks javascript
|
| 851 |
+
dilawar/ncbs-minion php
|
| 852 |
+
saltstack/salt python
|
| 853 |
+
yumingjuan/selenium ruby
|
| 854 |
+
emk/credentials rust
|
| 855 |
+
jsse-2017-ph23/web-frontend typescript
|
| 856 |
+
yamnikov-oleg/cgo-callback c
|
| 857 |
+
hajimehoshi/ebiten go
|
| 858 |
+
boundary/meter-plugin-sdk-java java
|
| 859 |
+
Darkrender/raptor-ads javascript
|
| 860 |
+
graphp/plaintext php
|
| 861 |
+
cherba/apitools python
|
| 862 |
+
theodi/csvlint ruby
|
| 863 |
+
Wandalen/wTools rust
|
| 864 |
+
romancow/ts-geometry typescript
|
| 865 |
+
simonpf/root c
|
| 866 |
+
golang/appengine go
|
| 867 |
+
jahed/crowd-play java
|
| 868 |
+
megos/asagao javascript
|
| 869 |
+
Pikkulahti/leijonaa php
|
| 870 |
+
RainCity471/lyCompiler python
|
| 871 |
+
crowdAI/crowdai ruby
|
| 872 |
+
owaspjocur/servo rust
|
| 873 |
+
KamiKillertO/vscode-colorize typescript
|
| 874 |
+
bloom-lang/c4 c
|
| 875 |
+
F5Networks/k8s-bigip-ctlr go
|
| 876 |
+
gramboid/RxAppFocus java
|
| 877 |
+
ajacksified/reddit-mobile javascript
|
| 878 |
+
stratedge/passport-facebook php
|
| 879 |
+
chiphogg/vim-vtd python
|
| 880 |
+
ManageIQ/manageiq-ui-classic ruby
|
| 881 |
+
magum/rust-rosetta rust
|
| 882 |
+
google/chicago-brick typescript
|
| 883 |
+
jamespearce2006/CefSharp c
|
| 884 |
+
wickedchicken/dwd-go go
|
| 885 |
+
NUBIC/psc-mirror java
|
| 886 |
+
iTerminate/traveler javascript
|
| 887 |
+
phoenixgao/laravel-postgres-extended-schema php
|
| 888 |
+
patrickspencer/mathdeck python
|
| 889 |
+
iiet/iiet-git ruby
|
| 890 |
+
raineszm/rust-blas rust
|
| 891 |
+
tsg-ut/slackbot typescript
|
| 892 |
+
nickolasburr/git-stashd c
|
| 893 |
+
mrekucci/epi go
|
| 894 |
+
apache/commons-jexl java
|
| 895 |
+
RakanNimer/react-google-charts javascript
|
| 896 |
+
garciaf/fabbook php
|
| 897 |
+
brainwane/zulip python
|
| 898 |
+
svcastaneda/phase-0 ruby
|
| 899 |
+
kkimdev/autograd rust
|
| 900 |
+
wiktor-k/infrastructure-tests typescript
|
| 901 |
+
Payshare/libsodium c
|
| 902 |
+
thaJeztah/distribution go
|
| 903 |
+
nulab/zxcvbn4j java
|
| 904 |
+
FleetOnRails/fleet-web-app javascript
|
| 905 |
+
danielsan80/MeasureBundle php
|
| 906 |
+
handroll/handroll python
|
| 907 |
+
thoughtbot/neat ruby
|
| 908 |
+
d-unseductable/ruru rust
|
| 909 |
+
deegles/cookietime typescript
|
| 910 |
+
DDVTECH/mistserver c
|
| 911 |
+
chadev/Chadev_ircbot go
|
| 912 |
+
benmfaul/XRTB java
|
| 913 |
+
tddbin/tddbin-frontend javascript
|
| 914 |
+
tailwindlabs/tailwindcss php
|
| 915 |
+
sl2017/campos python
|
| 916 |
+
teeparham/gemdiff ruby
|
| 917 |
+
servo/rust-http rust
|
| 918 |
+
SimonSchick/EliteDangerousUtils typescript
|
| 919 |
+
Kromey/roglick c
|
| 920 |
+
ninjasphere/hc go
|
| 921 |
+
EBIBioSamples/biosamples-v4 java
|
| 922 |
+
worldbank-cdrp/disaster-risk-explorer javascript
|
| 923 |
+
wowtransfer/chdphp php
|
| 924 |
+
wiliamsouza/hystrix-py python
|
| 925 |
+
eventide-project/log ruby
|
| 926 |
+
godcoin/godcoin rust
|
| 927 |
+
jovotech/jovo-framework-nodejs typescript
|
| 928 |
+
dawehner/root c
|
| 929 |
+
ewbankkit/terraform go
|
| 930 |
+
ablenesi/ELTEProjectToolsTeam09 java
|
| 931 |
+
RaphaelDeLaGhetto/gebo-registrant-hai javascript
|
| 932 |
+
tonightsystems/alf-cms php
|
| 933 |
+
dimagi/commcare-hq python
|
| 934 |
+
solidusio-contrib/solidus_subscriptions ruby
|
| 935 |
+
cosmo0920/ruroonga rust
|
| 936 |
+
michaelbull/zoom.ts typescript
|
| 937 |
+
shockkolate/shockk-os c
|
| 938 |
+
google/mtail go
|
| 939 |
+
SOM-st/black-diamonds java
|
| 940 |
+
codeforamerica/streetmix javascript
|
| 941 |
+
simplesamlphp/simplesamlphp-module-openid php
|
| 942 |
+
thiderman/network-kitten python
|
| 943 |
+
jspizziri/spree ruby
|
| 944 |
+
WPO-Foundation/gnirehtet rust
|
| 945 |
+
emugaya/bucketlist_frontend typescript
|
| 946 |
+
wnh/prompt_utils c
|
| 947 |
+
photoshelf/photoshelf-storage go
|
| 948 |
+
CS2103AUG2016-W14-C1/main java
|
| 949 |
+
skidding/flatris javascript
|
| 950 |
+
WeMoveEU/bsd_api php
|
| 951 |
+
kefir500/ghstats python
|
| 952 |
+
adamthedeveloper/wepay-rails ruby
|
| 953 |
+
skade/leveldb rust
|
| 954 |
+
gluons/font-awesome-openui5 typescript
|
| 955 |
+
muxi/grpc c
|
| 956 |
+
keep94/Dominator go
|
| 957 |
+
c-rack/czmq java
|
| 958 |
+
gefs-plugins/fmc-requirejs javascript
|
| 959 |
+
symfony/HttpKernel php
|
| 960 |
+
JungeAlexander/cocoscore python
|
| 961 |
+
key-amb/fireap ruby
|
| 962 |
+
gyn/exercism rust
|
| 963 |
+
Discordius/Lesswrong2 typescript
|
| 964 |
+
adobe/chromium c
|
| 965 |
+
mtibben/confusables go
|
| 966 |
+
mgenov/sitebricks java
|
| 967 |
+
kiwiirc/irc-framework javascript
|
| 968 |
+
swt83/php-inline php
|
| 969 |
+
ohsu-qin/qipipe python
|
| 970 |
+
railsmachine/lita-ext ruby
|
| 971 |
+
anthgur/servo rust
|
| 972 |
+
mike-north/ember-api-actions typescript
|
| 973 |
+
AppliedLogicSystems/ALSProlog c
|
| 974 |
+
materials-commons/mcstore go
|
| 975 |
+
phoenixnudt/OWL2VOWL java
|
| 976 |
+
EricCat/Node-File-Delete javascript
|
| 977 |
+
beberlei/AzureDistributionBundle php
|
| 978 |
+
sergey-dryabzhinsky/dedupsqlfs python
|
| 979 |
+
eloy/debox_server ruby
|
| 980 |
+
erickt/cargo rust
|
| 981 |
+
GoogleChrome/web-vitals typescript
|
| 982 |
+
thinnect/tos-groundlib c
|
| 983 |
+
orifinkelman/incubator-trafficcontrol go
|
| 984 |
+
imCodePartnerAB/iVIS java
|
| 985 |
+
imiric/usearch javascript
|
| 986 |
+
facilis/users php
|
| 987 |
+
t-miyamae/teuthology python
|
| 988 |
+
vinsol/Spree-Unified-Payments ruby
|
| 989 |
+
hackndev/zinc rust
|
| 990 |
+
opennode/waldur-homeport typescript
|
| 991 |
+
groonga/groonga c
|
| 992 |
+
cloudfoundry-incubator/runtime-schema go
|
| 993 |
+
dhanji/sitebricks java
|
| 994 |
+
jeremyruppel/vmplate javascript
|
| 995 |
+
VitSalis/endofcodes php
|
| 996 |
+
0xPoly/ooni-probe python
|
| 997 |
+
frc-frecon/frecon ruby
|
| 998 |
+
kassens/relay rust
|
| 999 |
+
faddiv/budget-keeper typescript
|
| 1000 |
+
eaburns/pbnf c
|
| 1001 |
+
yorickdewid/gocraw go
|
| 1002 |
+
davido/gerrit-reviewers-plugin java
|
| 1003 |
+
dollarshaveclub/ember-cli-anybar javascript
|
| 1004 |
+
sgmendez/example_api_rest php
|
| 1005 |
+
sorgerlab/indra python
|
| 1006 |
+
bugsnag/bugsnag-js ruby
|
| 1007 |
+
mhallin/juniper rust
|
| 1008 |
+
drumonii/LeagueTrollBuild typescript
|
| 1009 |
+
PeterWangIntel/chromium-crosswalk c
|
| 1010 |
+
abiosoft/ishell go
|
| 1011 |
+
fimtra/datafission java
|
| 1012 |
+
pipedrive/client-nodejs javascript
|
| 1013 |
+
evanmaastrigt/kwetal-workdays php
|
| 1014 |
+
nvbn/thefuck python
|
| 1015 |
+
fureigh/change-my-record ruby
|
| 1016 |
+
serde-rs/serde rust
|
| 1017 |
+
Alfresco/alfresco-ng2-components typescript
|
| 1018 |
+
joel-porquet/tsar-uclibc c
|
| 1019 |
+
owulveryck/google-app-example go
|
| 1020 |
+
groupon/Selenium-Grid-Extras java
|
| 1021 |
+
kpdecker/next.js javascript
|
| 1022 |
+
million12/M12.Foundation php
|
| 1023 |
+
aosp-mirror/platform_external_skia python
|
| 1024 |
+
leonid-shevtsov/knife-solo ruby
|
| 1025 |
+
edunham/regex rust
|
| 1026 |
+
mollie/mollie-api-node typescript
|
| 1027 |
+
utahiosmac/Marshal c
|
| 1028 |
+
vektorlab/otter go
|
| 1029 |
+
repeats/Repeat java
|
| 1030 |
+
benjamn/offgrid-lights javascript
|
| 1031 |
+
OParl/dev-website php
|
| 1032 |
+
masasin/spirit python
|
| 1033 |
+
nurelm/quickbooks_integration ruby
|
| 1034 |
+
warricksothr/dft rust
|
| 1035 |
+
endeavourhealth/EDS typescript
|
| 1036 |
+
iTermin/app_iOS c
|
| 1037 |
+
shiena/go-gitbucket go
|
| 1038 |
+
philippsied/smartcard-course java
|
| 1039 |
+
vekat/vcat javascript
|
| 1040 |
+
M2Mobi/lunr php
|
| 1041 |
+
benedicteb/outcast python
|
| 1042 |
+
ashrafuzzaman/stips ruby
|
| 1043 |
+
stewart/rff rust
|
| 1044 |
+
debugworkbench/hydragon typescript
|
| 1045 |
+
aaronmjacobs/openal-soft c
|
| 1046 |
+
mgutz/logxi go
|
| 1047 |
+
shineM/gh4a java
|
| 1048 |
+
TarrinRos/PizzaShop javascript
|
| 1049 |
+
vrap/project-b php
|
| 1050 |
+
SEL-Columbia/commcare-hq python
|
| 1051 |
+
thredup/sidekiq-grouping ruby
|
| 1052 |
+
corragon/rust-raytracer rust
|
| 1053 |
+
madigan/ncounter-ng2 typescript
|
| 1054 |
+
cdzombak/thingshub c
|
| 1055 |
+
l1jiang/govmomi go
|
| 1056 |
+
pivotal-bank/portfolio-service java
|
| 1057 |
+
sblask/firefox-open-tabs-next-to-current javascript
|
| 1058 |
+
hiqdev/hipanel-module-finance php
|
| 1059 |
+
OCA/stock-logistics-warehouse python
|
| 1060 |
+
jmespath/jmespath.rb ruby
|
| 1061 |
+
philyoon/rust rust
|
| 1062 |
+
V-Paranoiaque/Ellas-War typescript
|
| 1063 |
+
FreeScienceCommunity/PLPlot c
|
| 1064 |
+
v2tec/watchtower go
|
| 1065 |
+
UweTrottmann/thetvdb-java java
|
| 1066 |
+
indexzero/read-ssl javascript
|
| 1067 |
+
Clidus/dumplog-website php
|
| 1068 |
+
lemming52/white_knight python
|
| 1069 |
+
SvetoslavKuzmanov/asteroids ruby
|
| 1070 |
+
dcuddeback/libudev-rs rust
|
| 1071 |
+
citizenlabsgr/voter-engagement typescript
|
| 1072 |
+
aldebaran/libport c
|
| 1073 |
+
ghmeier/coinage go
|
| 1074 |
+
codecop/ugly-trivia-kata java
|
| 1075 |
+
fernandocanizo/choodo javascript
|
| 1076 |
+
axton21/voting-app php
|
| 1077 |
+
egafford/sahara python
|
| 1078 |
+
Joel-B-Williams/Meandr ruby
|
| 1079 |
+
saulius/croaring-rs rust
|
| 1080 |
+
jacobjojan/angular2-webpack-starter typescript
|
| 1081 |
+
tomdev2008/energy c
|
| 1082 |
+
DataDog/go-datadog-api go
|
| 1083 |
+
devhub-tud/devhub-prototype java
|
| 1084 |
+
nicolasmccurdy/procrastinate javascript
|
| 1085 |
+
DoSomething/aurora php
|
| 1086 |
+
jdevera/subdue python
|
| 1087 |
+
mbj/axiom-arango-adapter ruby
|
| 1088 |
+
dbrodie/rex rust
|
| 1089 |
+
davidsidlinger/DefinitelyTyped typescript
|
| 1090 |
+
shahedmolla/test c
|
| 1091 |
+
eriol/piken go
|
| 1092 |
+
kashike/SpongeAPI java
|
| 1093 |
+
ForbesLindesay/thread-sleep javascript
|
| 1094 |
+
michaelletzgus/nextcloud-server php
|
| 1095 |
+
VirusTotal/misp-modules python
|
| 1096 |
+
page-io/middleman-s3_sync ruby
|
| 1097 |
+
dwillmer/rust rust
|
| 1098 |
+
devonzuegel/clarity typescript
|
| 1099 |
+
iree-org/iree c
|
| 1100 |
+
mmcgrana/pg2librato go
|
| 1101 |
+
Gamealition/SignShopExport java
|
| 1102 |
+
acingraham/AwwFrame javascript
|
| 1103 |
+
lwiesel/delivery-tracking php
|
| 1104 |
+
benedfit/SublimeLinter-contrib-pug-lint python
|
| 1105 |
+
NYULibraries/rooms ruby
|
| 1106 |
+
pnkfelix/mon-artiste rust
|
| 1107 |
+
DAXaholic/vscode-edifact typescript
|
| 1108 |
+
redforks/thermostat c
|
| 1109 |
+
albfan/gdblib go
|
| 1110 |
+
OpenMods/OpenPeripheral-Addons java
|
| 1111 |
+
IonicaBizau/arc-assembler javascript
|
| 1112 |
+
xemlock/htmlpurifier-html5 php
|
| 1113 |
+
thebinarypenguin/SublimeLinter-contrib-raml-cop python
|
| 1114 |
+
osu-cascades/ecotone-web ruby
|
| 1115 |
+
ruma/ruma rust
|
| 1116 |
+
PakL/TTVStreamerTool typescript
|
| 1117 |
+
reeFridge/learn-oop-through-cpp c
|
| 1118 |
+
revl/autoforge go
|
| 1119 |
+
joonhocho/react-native-linkedin-sdk java
|
| 1120 |
+
roschaefer/rundfunk-mitbestimmen javascript
|
| 1121 |
+
hardywen/captcha php
|
| 1122 |
+
csrocha/account_journal_payment_subtype python
|
| 1123 |
+
yeban/sequenceserver ruby
|
| 1124 |
+
GBGamer/rust rust
|
| 1125 |
+
ikatyang/dts-element typescript
|
| 1126 |
+
atropelando/terceiro-ano-programacao c
|
| 1127 |
+
strivecast/hcl go
|
| 1128 |
+
VisualDataWeb/OntoBench java
|
| 1129 |
+
Leko/WEB-EGG javascript
|
| 1130 |
+
bearsunday/BEAR.Resource php
|
| 1131 |
+
pombreda/seascope python
|
| 1132 |
+
hpcloud/unix_cli ruby
|
| 1133 |
+
iKevinY/ultra rust
|
| 1134 |
+
ravendb/ravendb-nodejs-client typescript
|
| 1135 |
+
Roadagain/Calculator c
|
| 1136 |
+
luci/luci-go go
|
| 1137 |
+
NCIP/psc java
|
| 1138 |
+
joaquindev/learning-mongoose javascript
|
| 1139 |
+
aalfiann/reSlim php
|
| 1140 |
+
tanayseven/personal_website python
|
| 1141 |
+
teespring/envm ruby
|
| 1142 |
+
amongil/bluenine rust
|
| 1143 |
+
edhager/widget-core typescript
|
| 1144 |
+
elupus/osek c
|
| 1145 |
+
1and1/soma go
|
| 1146 |
+
Enoro/commons-compress java
|
| 1147 |
+
firebug/firebug.next javascript
|
| 1148 |
+
Sylius/Cart php
|
| 1149 |
+
pinry/pinry python
|
| 1150 |
+
mthssdrbrg/kafka-cookbook ruby
|
| 1151 |
+
ConnyOnny/Cursive-Break rust
|
| 1152 |
+
grafana/grafana typescript
|
| 1153 |
+
honux77/practice c
|
| 1154 |
+
phalaaxx/ratemilter go
|
| 1155 |
+
snowble/vertical-stepper java
|
| 1156 |
+
pinittome/proxy javascript
|
| 1157 |
+
romhut/criterion php
|
| 1158 |
+
geelweb/laposte-python-sdk python
|
| 1159 |
+
opscode-cookbooks/partial_search ruby
|
| 1160 |
+
fabianschuiki/moore rust
|
| 1161 |
+
fsahmad/tsuml-demo typescript
|
| 1162 |
+
mihaimaruseac/dphcar c
|
| 1163 |
+
billhathaway/webcounter go
|
| 1164 |
+
Mahtimursut/ohtu java
|
| 1165 |
+
webkom/eslint-config-webkom javascript
|
| 1166 |
+
app-zap/PHPFramework php
|
| 1167 |
+
phil-lopreiato/the-blue-alliance python
|
| 1168 |
+
bdunne/manageiq-automation_engine ruby
|
| 1169 |
+
bpowers1215/MoneyMap rust
|
| 1170 |
+
Picturepark/Picturepark.SDK.TypeScript typescript
|
| 1171 |
+
barbagroup/cuIBM c
|
| 1172 |
+
pierrre/mangadownloader go
|
| 1173 |
+
UweTrottmann/trakt-java java
|
| 1174 |
+
franvarney/franvarney-api javascript
|
| 1175 |
+
Parabot/BDN-V3 php
|
| 1176 |
+
EnvGen/toolbox python
|
| 1177 |
+
gocardless/que ruby
|
| 1178 |
+
dtolnay/thiserror rust
|
| 1179 |
+
spinnaker/deck typescript
|
| 1180 |
+
Lightricks/ocmock c
|
| 1181 |
+
bdastur/utils go
|
| 1182 |
+
bdezonia/zorbage java
|
| 1183 |
+
georapbox/jsEssentials javascript
|
| 1184 |
+
Lecturize/Laravel-Taxonomies php
|
| 1185 |
+
openaustralia/publicwhip-matthew python
|
| 1186 |
+
KarmaHater/WikiEduDashboard ruby
|
| 1187 |
+
Ticki/libterm rust
|
| 1188 |
+
denismaster/dcs typescript
|
| 1189 |
+
nadirs/dmgemu c
|
| 1190 |
+
nono/cozy-stack go
|
| 1191 |
+
Ullink/slack4gerrit java
|
| 1192 |
+
agustim/fiberfy-server javascript
|
| 1193 |
+
RhubarbPHP/Website php
|
| 1194 |
+
thorgate/django-project-template python
|
| 1195 |
+
ontohub/ontohub ruby
|
| 1196 |
+
mbrubeck/servo rust
|
| 1197 |
+
sanity-io/sanity typescript
|
| 1198 |
+
tjarratt/twIRCk c
|
| 1199 |
+
oftc-ftw/stove go
|
| 1200 |
+
elBukkit/MagicPlugin java
|
| 1201 |
+
wh1tney/recordly javascript
|
| 1202 |
+
okulbilisim/ojs php
|
| 1203 |
+
monostable/haskell-kicad-data python
|
| 1204 |
+
theresaboard/theres-a-board ruby
|
| 1205 |
+
tempbottle/ProjectEulerRust rust
|
| 1206 |
+
third774/ng-bootstrap-form-validation typescript
|
| 1207 |
+
btrask/hash-archive c
|
| 1208 |
+
rgooch/Dominator go
|
| 1209 |
+
xkrogen/gobblin java
|
| 1210 |
+
Syncano/syncano-dashboard javascript
|
| 1211 |
+
digitalkaoz/BetterReflection php
|
| 1212 |
+
OpenSpace/OpenSpace python
|
| 1213 |
+
obsidian-btc/data-aggregation-index ruby
|
| 1214 |
+
zaeleus/rust rust
|
| 1215 |
+
hansl/devkit typescript
|
| 1216 |
+
Chase-san/libspec c
|
| 1217 |
+
ying32/govcl go
|
| 1218 |
+
fabzo/kraken java
|
| 1219 |
+
eamonnbell/sortzzi javascript
|
| 1220 |
+
guzzle/guzzle3 php
|
| 1221 |
+
planetlabs/datalake-ingester python
|
| 1222 |
+
deathwish/absinthe ruby
|
| 1223 |
+
shepmaster/sxd-rust rust
|
| 1224 |
+
minestarks/TypeScript typescript
|
| 1225 |
+
sbc100/native_client c
|
| 1226 |
+
wanelo/image-server go
|
| 1227 |
+
mysangle/algorithm-study java
|
| 1228 |
+
yannickglt/esreflect javascript
|
| 1229 |
+
GeneaLabs/Phpgmaps php
|
| 1230 |
+
yamatt/bonfiremanager python
|
| 1231 |
+
integrallis/stripe_event ruby
|
| 1232 |
+
ThomasColliers/age-of-rust rust
|
| 1233 |
+
hychen/ke-e typescript
|
| 1234 |
+
postmodern/libBERT c
|
| 1235 |
+
liggitt/osin go
|
| 1236 |
+
klausw/hackerskeyboard java
|
| 1237 |
+
albburtsev/talaria javascript
|
| 1238 |
+
Shopify/theme-sync php
|
| 1239 |
+
wkentaro/chainer python
|
| 1240 |
+
Shopify/Hermann ruby
|
| 1241 |
+
stepancheg/rust-protobuf rust
|
| 1242 |
+
BillWagner/TypeScriptAngular2 typescript
|
| 1243 |
+
JFLarvoire/SysToolsLib c
|
| 1244 |
+
jacobsa/aws go
|
| 1245 |
+
watsonarw/twu-biblioteca-andrewwatson java
|
| 1246 |
+
Calvin-Huang/LiveAPIExplore-Server javascript
|
| 1247 |
+
kicks-app/kicks-app-wordpress php
|
| 1248 |
+
Dybov/real_estate_agency python
|
| 1249 |
+
satoryu/tepco_usage_api ruby
|
| 1250 |
+
shssoichiro/oxipng rust
|
| 1251 |
+
Team-CHAD/DevDecks typescript
|
| 1252 |
+
chaoran/fast-wait-free-queue c
|
| 1253 |
+
ninjasphere/go-openzwave go
|
| 1254 |
+
duckAsteroid/osgi-test java
|
| 1255 |
+
mfgea/grunt-dredd javascript
|
| 1256 |
+
Sylius/Currency php
|
| 1257 |
+
Astroua/aws_controller python
|
| 1258 |
+
henrinormak/NSDateComponents-HNExtensions ruby
|
| 1259 |
+
l1048576/fbx_direct rust
|
| 1260 |
+
kulshekhar/ts-jest typescript
|
| 1261 |
+
Juniper/libslax c
|
| 1262 |
+
cortesi/devd go
|
| 1263 |
+
edaubert/jongo java
|
| 1264 |
+
rubenv/grunt-mkdir javascript
|
| 1265 |
+
ku2ma2/design_pattern php
|
| 1266 |
+
nagilum/script.rndmov python
|
| 1267 |
+
mission-of-mercy/momma_dashboard ruby
|
| 1268 |
+
servo/sharegl rust
|
| 1269 |
+
misoukrane/did-or-wish typescript
|
| 1270 |
+
Herbstein/kernel-of-truth c
|
| 1271 |
+
gcapizzi/moka go
|
| 1272 |
+
n-zeplo/TW101_Exercises java
|
| 1273 |
+
edi9999/jsqrcode javascript
|
| 1274 |
+
DoSomething/northstar php
|
| 1275 |
+
lsgunth/rapidsms python
|
| 1276 |
+
srcclr/commit-watcher ruby
|
| 1277 |
+
knsd/from-ascii rust
|
| 1278 |
+
christophd/citrus-admin typescript
|
| 1279 |
+
BeImprovised/gambit c
|
| 1280 |
+
cloudfoundry-community/asp.net5-buildpack go
|
| 1281 |
+
sormuras/bach java
|
| 1282 |
+
thatPamIAm/weathrly javascript
|
| 1283 |
+
mantisbt-plugins/source-integration php
|
| 1284 |
+
yeasy/robot_tool python
|
| 1285 |
+
mkllnk/openfoodnetwork ruby
|
| 1286 |
+
amhk/lokatt rust
|
| 1287 |
+
lit/lit.dev typescript
|
| 1288 |
+
telefonicaid/fiware-cosmos-platform c
|
| 1289 |
+
QuentinPerez/scaleway-cli go
|
| 1290 |
+
cloudfoundry/cf-java-client java
|
| 1291 |
+
WhitestormJS/whs.js javascript
|
| 1292 |
+
Korko/SecretSanta.fr php
|
| 1293 |
+
ShivamSarodia/ShivyC python
|
| 1294 |
+
insight-meditation-center/imc-bootstrap-sass ruby
|
| 1295 |
+
benstreb/astroids-rust rust
|
| 1296 |
+
rishii7/vscode typescript
|
| 1297 |
+
timkettering/SwitecX25 c
|
| 1298 |
+
containers/storage go
|
| 1299 |
+
freeVM/freeVM java
|
| 1300 |
+
stuartkeith/webaudiosequencer javascript
|
| 1301 |
+
nordsoftware/yii-paytrail php
|
| 1302 |
+
stefanklug/plata python
|
| 1303 |
+
daynix/rebuild ruby
|
| 1304 |
+
nickbabcock/boxcars rust
|
| 1305 |
+
DSI-HUG/dejajs-components typescript
|
| 1306 |
+
Luminarys/synapse c
|
| 1307 |
+
celrenheit/lion go
|
| 1308 |
+
bitcoin-solutions/multibit-hd java
|
| 1309 |
+
Brightspace/jquery-valence-ui-more-less javascript
|
| 1310 |
+
DarvinStudio/darvin-utils php
|
| 1311 |
+
willdavidc/piel python
|
| 1312 |
+
knapo/jquery-colorbox-rails ruby
|
| 1313 |
+
kmcallister/rust rust
|
| 1314 |
+
crdschurch/crds-signin-checkin typescript
|
| 1315 |
+
coreux/liberrno c
|
| 1316 |
+
donatj/explainer go
|
| 1317 |
+
smartcommunitylab/sco.carpooling java
|
| 1318 |
+
myntra/react-native javascript
|
| 1319 |
+
jordandukart/islandora_xacml_editor php
|
| 1320 |
+
henriquebastos/virtualenv-bootstrap python
|
| 1321 |
+
chrisfinazzo/homebrew-core ruby
|
| 1322 |
+
lipanski/trello-rs rust
|
| 1323 |
+
yysun/apprun typescript
|
| 1324 |
+
lglucin/Halide c
|
| 1325 |
+
dotcominternet/platform go
|
| 1326 |
+
matco/simcity java
|
| 1327 |
+
jackrzhang/boardsession javascript
|
| 1328 |
+
SolidInvoice/SolidInvoice php
|
| 1329 |
+
ianfieldhouse/number_to_words python
|
| 1330 |
+
vaneyckt/Jently ruby
|
| 1331 |
+
dtolnay/syn rust
|
| 1332 |
+
thenickreynolds/popcorngif typescript
|
| 1333 |
+
duckinator/boreutils c
|
| 1334 |
+
lukevers/go-and-hack go
|
| 1335 |
+
benbenw/jmeter java
|
| 1336 |
+
ufocoder/redux-universal-boilerplate javascript
|
| 1337 |
+
wiltosoft/laravel php
|
| 1338 |
+
sindrig/spoppy python
|
| 1339 |
+
k0kubun/specinfra ruby
|
| 1340 |
+
Gyscos/Cursive rust
|
| 1341 |
+
webcomponents/polyfills typescript
|
| 1342 |
+
GNOME/libchamplain c
|
| 1343 |
+
landonia/landotube go
|
| 1344 |
+
zsoltii/dss java
|
| 1345 |
+
proglottis/oyster javascript
|
| 1346 |
+
jonuy/dosomething php
|
| 1347 |
+
rlee287/pyautoupdate python
|
| 1348 |
+
alphagov/publishing-api ruby
|
| 1349 |
+
am0d/rust-projects rust
|
| 1350 |
+
yadomi/lastagram typescript
|
| 1351 |
+
zwaldowski/AZCoreRecord c
|
| 1352 |
+
kalafut/finiki go
|
| 1353 |
+
Ghostlyr/MinecraftForge java
|
| 1354 |
+
TheLudd/unary javascript
|
| 1355 |
+
KnpLabs/KnpRadBundle php
|
| 1356 |
+
bharling/django-pint python
|
| 1357 |
+
TechnoGate/contao ruby
|
| 1358 |
+
Nicoretti/xxd-rs rust
|
| 1359 |
+
notbakaneko/osu-web typescript
|
| 1360 |
+
syscoin/syscoin c
|
| 1361 |
+
mingrammer/go-codelab go
|
| 1362 |
+
miguel250/Robotics java
|
| 1363 |
+
gldraphael/chordsheet javascript
|
| 1364 |
+
benignware/wp-bootstrap-hooks php
|
| 1365 |
+
jackromo/RandTerrainPy python
|
| 1366 |
+
stephenbm/chef-server ruby
|
| 1367 |
+
jimmycuadra/rust-etcd rust
|
| 1368 |
+
pbraunstein/trackercise typescript
|
| 1369 |
+
digama0/lean c
|
| 1370 |
+
groob/micromdm go
|
| 1371 |
+
DBCG/cql_measure_processor java
|
| 1372 |
+
emberjs/ember-legacy-controllers javascript
|
| 1373 |
+
silverorange/swat php
|
| 1374 |
+
ayushgoel/LongShot python
|
| 1375 |
+
danielfarrell/common_event_formatter ruby
|
| 1376 |
+
jinnjuice/solicit rust
|
| 1377 |
+
FernCreek/tinymce typescript
|
| 1378 |
+
dpt/Containers c
|
| 1379 |
+
schmichael/metafora go
|
| 1380 |
+
jypma/lambda-behave java
|
| 1381 |
+
burninggarden/pirc javascript
|
| 1382 |
+
silverstripe-labs/silverstripe-environmentcheck php
|
| 1383 |
+
reedstrm/Pyrseas python
|
| 1384 |
+
zoocasa/geos-extensions ruby
|
| 1385 |
+
Stebalien/udev-rs rust
|
| 1386 |
+
kdechant/eamon typescript
|
| 1387 |
+
svn2github/libpqxx c
|
| 1388 |
+
maxamillion/flamingo go
|
| 1389 |
+
Addepar/buck java
|
| 1390 |
+
fi-ksi/web-frontend javascript
|
| 1391 |
+
eustasy/browning-a-mailgun-script php
|
| 1392 |
+
andylytical/brewpi-scripts python
|
| 1393 |
+
milewdev/power ruby
|
| 1394 |
+
ron-rs/ron rust
|
| 1395 |
+
ryanluker/vscode-coverage-gutters typescript
|
| 1396 |
+
Atom058/ArduinoLithiumCharger c
|
| 1397 |
+
FriendlyLinuxPlayers/flip.earth go
|
| 1398 |
+
hal/elemento java
|
| 1399 |
+
sauravmndl/service-fabrik-broker javascript
|
| 1400 |
+
nordsoftware/lumen-doctrine php
|
| 1401 |
+
HHS-IntroProgramming/Multiplication-table python
|
| 1402 |
+
lpichler/manageiq ruby
|
| 1403 |
+
kkirstein/hdf5-rs rust
|
| 1404 |
+
upfluence/oss-components typescript
|
| 1405 |
+
llvm-mirror/libcxx c
|
| 1406 |
+
aabizri/navitia go
|
| 1407 |
+
CRollin/ptiChat java
|
| 1408 |
+
gocd/gocd.github.io javascript
|
| 1409 |
+
pantheon-systems/cli php
|
| 1410 |
+
wyager/IHaskell python
|
| 1411 |
+
leandroo/flexi_generators ruby
|
| 1412 |
+
ebfe/syscall.rs rust
|
| 1413 |
+
looker-open-source/embed-sdk typescript
|
| 1414 |
+
dscho/dovecot c
|
| 1415 |
+
walac/taskcluster-worker go
|
| 1416 |
+
JetBrains/teamcity-azure-plugin java
|
| 1417 |
+
khwang/plum javascript
|
| 1418 |
+
bar5z6/swe2015groupl php
|
| 1419 |
+
opnfv/functest python
|
| 1420 |
+
gocardless/business ruby
|
| 1421 |
+
carols10cents/adventofcode-rs rust
|
| 1422 |
+
easyfuckingpeasy/chrome-reddit-comment-highlights typescript
|
| 1423 |
+
jeremiedecock/snippets c
|
| 1424 |
+
gu-bin/bosh-agent go
|
| 1425 |
+
iEli2tyree011/EllyCheat java
|
| 1426 |
+
mstange/cleopatra javascript
|
| 1427 |
+
Piou-piou/ribs-framework php
|
| 1428 |
+
amolenaar/gaphor python
|
| 1429 |
+
abenson/sweep ruby
|
| 1430 |
+
Armavica/99-Problems-Rust rust
|
| 1431 |
+
fvilers/angular2-training typescript
|
| 1432 |
+
plast-lab/cclyzer c
|
| 1433 |
+
delta24/gist go
|
| 1434 |
+
trivago/Heimdall.droid java
|
| 1435 |
+
henrikra/gym-diary javascript
|
| 1436 |
+
meng-tian/php-soap-interpreter php
|
| 1437 |
+
potatolondon/contentious python
|
| 1438 |
+
chefspec/chefspec ruby
|
| 1439 |
+
olajep/gcc-explorer rust
|
| 1440 |
+
ghidello/cli typescript
|
| 1441 |
+
talk-to/Chocolate c
|
| 1442 |
+
mrtazz/checkmake go
|
| 1443 |
+
CCI-MIT/XCoLab java
|
| 1444 |
+
fbaumgardt/arethusa javascript
|
| 1445 |
+
TypiCMS/Pages php
|
| 1446 |
+
pavel-paulau/perfrunner python
|
| 1447 |
+
labocho/action_mailer_config ruby
|
| 1448 |
+
martica/rusty rust
|
| 1449 |
+
guyellis/plant-image-lambda typescript
|
| 1450 |
+
ycaihua/skim-app c
|
| 1451 |
+
carlmjohnson/junix go
|
| 1452 |
+
havarunner/havarunner java
|
| 1453 |
+
cyberkoi/discourse-spoiler-alert javascript
|
| 1454 |
+
freephile/qb php
|
| 1455 |
+
AlexHill/mezzanine python
|
| 1456 |
+
ddrmanxbxfr/active_fulfillment ruby
|
| 1457 |
+
termoshtt/ndarray-linalg rust
|
| 1458 |
+
wikimigrate/wikimigrate typescript
|
| 1459 |
+
zhuhaow/libnekit c
|
| 1460 |
+
khlieng/name_pending go
|
| 1461 |
+
StubbornJava/StubbornJava java
|
| 1462 |
+
mtheoryx/react-redux-es6 javascript
|
| 1463 |
+
boonex/trident php
|
| 1464 |
+
sassoftware/mint python
|
| 1465 |
+
zuku/bmff ruby
|
| 1466 |
+
mcarton/rust-plague rust
|
| 1467 |
+
hjobrien/desktop typescript
|
| 1468 |
+
vidya-ranganathan/algorithms c
|
| 1469 |
+
brooklyncentral/brooklyn-cli go
|
| 1470 |
+
ESSICS/org.csstudio.display.builder java
|
| 1471 |
+
publiclab/Leaflet.DistortableImage javascript
|
| 1472 |
+
mcrumm/phlack php
|
| 1473 |
+
hackerspace-ntnu/website python
|
| 1474 |
+
rohanpm/rcov-cobertura ruby
|
| 1475 |
+
djc/askama rust
|
| 1476 |
+
richmondwang/string-to-obj typescript
|
| 1477 |
+
yusuga/YSProcessTimer c
|
| 1478 |
+
sstark/droguedrums go
|
| 1479 |
+
pentaho/pentaho-commons-xul java
|
| 1480 |
+
foam-framework/foam2 javascript
|
| 1481 |
+
mpociot/reauthenticate php
|
| 1482 |
+
paylogic/py2deb python
|
| 1483 |
+
Schniz/mail ruby
|
| 1484 |
+
cjgreenaway/rubbem rust
|
| 1485 |
+
harksys/HawkEye typescript
|
| 1486 |
+
eikel/EScript c
|
| 1487 |
+
mewkiz/flac go
|
| 1488 |
+
queshaw/dita-ot java
|
| 1489 |
+
tijmenb/spotlight javascript
|
| 1490 |
+
MelcherSt/HTweb php
|
| 1491 |
+
oliverlee/antlia python
|
| 1492 |
+
gmcculloug/sprint_statistics ruby
|
| 1493 |
+
sacherjj/rust rust
|
| 1494 |
+
DeborahK/Angular-Routing typescript
|
| 1495 |
+
Staance/tailproduce c
|
| 1496 |
+
life1347/fission go
|
| 1497 |
+
spring-cloud/spring-cloud-cloudfoundry-service-broker java
|
| 1498 |
+
1flow/1flow javascript
|
| 1499 |
+
symphonists/markdown_typography php
|
| 1500 |
+
voer-platform/vp.repo python
|
| 1501 |
+
greg5green/homebrew-cask ruby
|
| 1502 |
+
yinyanlv/runner rust
|
| 1503 |
+
storybooks/storybook typescript
|
| 1504 |
+
dafrito/alpha c
|
| 1505 |
+
alecthomas/chroma go
|
| 1506 |
+
mrdon/SAL java
|
| 1507 |
+
Cwejman/martina javascript
|
| 1508 |
+
ansendu/php-libevent php
|
| 1509 |
+
exekias/django-achilles python
|
| 1510 |
+
nju520/pry ruby
|
| 1511 |
+
SirRade/homepage rust
|
| 1512 |
+
dotCMS/dotJS typescript
|
| 1513 |
+
globbie/knowdy c
|
| 1514 |
+
ibrt/go-oauto go
|
| 1515 |
+
realityforge/arez java
|
| 1516 |
+
materials-commons/materialscommons.org javascript
|
| 1517 |
+
kubernetes/examples php
|
| 1518 |
+
ikaruswill/vector-space-model python
|
| 1519 |
+
empirical-org/Empirical-Core ruby
|
| 1520 |
+
cuviper/rayon rust
|
| 1521 |
+
michaelgira23/MyMICDS-v2 typescript
|
| 1522 |
+
chmorgan/libesphttpd c
|
| 1523 |
+
miketheprogrammer/go-thrust go
|
| 1524 |
+
ChestShop-authors/ChestShop-3 java
|
| 1525 |
+
schaui6/yodalize javascript
|
| 1526 |
+
wappr/digitalocean php
|
| 1527 |
+
goldmann/docker-scripts python
|
| 1528 |
+
CannyFoxx/gallery ruby
|
| 1529 |
+
Nukesor/Pueue rust
|
| 1530 |
+
googleinterns/step250-2020 typescript
|
| 1531 |
+
coldfix/setcapslock c
|
| 1532 |
+
grooveshark/golib go
|
| 1533 |
+
codenvy/plugin-datasource java
|
| 1534 |
+
qgrid/ng javascript
|
| 1535 |
+
emgiezet/errbitPHP php
|
| 1536 |
+
tzengyuxio/python-five91 python
|
| 1537 |
+
eregon/rubyspec ruby
|
| 1538 |
+
eqrion/cbindgen rust
|
| 1539 |
+
MurhafSousli/ng2-sharebuttons typescript
|
| 1540 |
+
eingaeph/pip.imbue.hood c
|
| 1541 |
+
kyleterry/tenyks go
|
| 1542 |
+
braintree/braintree_android java
|
| 1543 |
+
substance/texture javascript
|
| 1544 |
+
cachethq/Laravel-Segment php
|
| 1545 |
+
Doist/todoist-python python
|
| 1546 |
+
Pitt-CSC/handy ruby
|
| 1547 |
+
ratel-rust/ratel-server rust
|
| 1548 |
+
hasman16/rent-a-ref typescript
|
| 1549 |
+
Billy4195/Simple_Chatroom c
|
| 1550 |
+
instana/golang-sensor go
|
| 1551 |
+
perdona/titanium_mobile java
|
| 1552 |
+
tenevdev/beacon-valley-hackathon javascript
|
| 1553 |
+
stdtabs/phptabs php
|
| 1554 |
+
datasciencebr/serenata-toolbox python
|
| 1555 |
+
pvalena/rails ruby
|
| 1556 |
+
matt-thomson/github-sweep rust
|
| 1557 |
+
mustpax/sortmybox typescript
|
| 1558 |
+
lefou/kdepim-noakonadi c
|
| 1559 |
+
barnardb/nomad go
|
| 1560 |
+
mohamad-z/dnsjava java
|
| 1561 |
+
MyPureCloud/skype-for-business-purecloud-app javascript
|
| 1562 |
+
orchestral/resources php
|
| 1563 |
+
jeanmask/opps-admin python
|
| 1564 |
+
hubert/comptroller ruby
|
| 1565 |
+
LukasKalbertodt/xswag-syntax-java rust
|
| 1566 |
+
aredotna/ervell typescript
|
| 1567 |
+
fxsjy/galaxy c
|
| 1568 |
+
ymichael/sessions go
|
| 1569 |
+
smartlogic/smartchat-android java
|
| 1570 |
+
bbondy/bloom-filter-js javascript
|
| 1571 |
+
paulboco/laravelerator php
|
| 1572 |
+
fprimex/zdesk python
|
| 1573 |
+
DigitalReflow/spina-projects ruby
|
| 1574 |
+
cmr/ioctl rust
|
| 1575 |
+
mihailik/TypeScript typescript
|
| 1576 |
+
leecrest/luv c
|
| 1577 |
+
wwitzel3/juju go
|
| 1578 |
+
rgupta1234/jboss-eap-quickstarts java
|
| 1579 |
+
bolinfest/line-ending-selector javascript
|
| 1580 |
+
mfairchild365/wubbles php
|
| 1581 |
+
praekelt/go-contacts-api python
|
| 1582 |
+
fsek/web ruby
|
| 1583 |
+
quvarxa/basic2d rust
|
| 1584 |
+
studieresan/overlord typescript
|
| 1585 |
+
kasper93/sanear c
|
| 1586 |
+
johnny-morrice/godelbrot go
|
| 1587 |
+
ralscha/eds-starter6-mongodb java
|
| 1588 |
+
klambycom/Skissa-och-gissa javascript
|
| 1589 |
+
dshafik/markua php
|
| 1590 |
+
MisanthropicBit/bibpy python
|
| 1591 |
+
ausaccessfed/saml-service ruby
|
| 1592 |
+
johannhof/markdown.rs rust
|
| 1593 |
+
dainst/idai-field-web typescript
|
| 1594 |
+
AMechler/AliPhysics c
|
| 1595 |
+
vektra/cypress go
|
| 1596 |
+
bitsquare/bitsquare java
|
| 1597 |
+
twisty/formsy-react-components javascript
|
| 1598 |
+
monooso/glossary.craft-plugin php
|
| 1599 |
+
thismachinechills/save_skype python
|
| 1600 |
+
AlexLittlejohn/ALCameraViewController ruby
|
| 1601 |
+
RustAudio/synth rust
|
| 1602 |
+
jupyter/jupyterlab typescript
|
| 1603 |
+
Icenowy/RUtil2 c
|
| 1604 |
+
sosedoff/envd go
|
| 1605 |
+
commonmark/commonmark-java java
|
| 1606 |
+
UTD-CSLLC/Door-Karma-Client javascript
|
| 1607 |
+
etsy/phan php
|
| 1608 |
+
lucianovdveekens/jiradoc python
|
| 1609 |
+
MLSDev/the_bullet-generator ruby
|
| 1610 |
+
endoli/disassemble.rs rust
|
| 1611 |
+
laodice/ionic-conference-app-session2 typescript
|
| 1612 |
+
Checkcoin/checkcoin c
|
| 1613 |
+
DarthSim/imgproxy go
|
| 1614 |
+
CompilerWorks/spliceengine java
|
| 1615 |
+
BBLN/data javascript
|
| 1616 |
+
jlorente/yii2-notification-module php
|
| 1617 |
+
ckan/ckanext-qa python
|
| 1618 |
+
stas/methane ruby
|
| 1619 |
+
febeling/edit-distance rust
|
| 1620 |
+
toladata/TolaProfile typescript
|
| 1621 |
+
simonaw/cutelyst c
|
| 1622 |
+
status-im/status-go go
|
| 1623 |
+
Genymobile/scrcpy java
|
| 1624 |
+
ImageMarkup/isic-archive javascript
|
| 1625 |
+
renothing/kanboard php
|
| 1626 |
+
hyunchel/redis-dump-load python
|
| 1627 |
+
ljfranklin/middleman-homepage ruby
|
| 1628 |
+
pduval/rustic_hal rust
|
| 1629 |
+
ngx-rocket/generator-ngx-rocket typescript
|
| 1630 |
+
lechkulina/RealmsOfSteel c
|
| 1631 |
+
alienth/go-fastly go
|
| 1632 |
+
m039/beacon-keeper java
|
| 1633 |
+
3-Round-Stones/callimachus javascript
|
| 1634 |
+
Yubico/u2fval-client-php php
|
| 1635 |
+
ondergetekende/python-panavatar python
|
| 1636 |
+
boutil/roxml ruby
|
| 1637 |
+
nabijaczleweli/chattium-oxide-lib rust
|
| 1638 |
+
skatejs/skatejs typescript
|
| 1639 |
+
sferik/libxml-ruby c
|
| 1640 |
+
atlassian/git-lob go
|
| 1641 |
+
retest/recheck java
|
| 1642 |
+
GreenImp/rpg-dice-roller javascript
|
| 1643 |
+
marcaube/oauth2-server php
|
| 1644 |
+
tarpas/pytest-testmon python
|
| 1645 |
+
ubpb/metacrunch-mab2 ruby
|
| 1646 |
+
dtolnay/anyhow rust
|
| 1647 |
+
cloudevents/sdk-javascript typescript
|
| 1648 |
+
aclements/sv6 c
|
| 1649 |
+
vardius/go-api-boilerplate go
|
| 1650 |
+
AvaIre/AvaIre java
|
| 1651 |
+
davidrayoussef/full-screen-gif-slider javascript
|
| 1652 |
+
lossendae/Previously-on php
|
| 1653 |
+
yola/proxyprefix python
|
| 1654 |
+
alphagov/whitehall ruby
|
| 1655 |
+
dirvine/rust-utp rust
|
| 1656 |
+
tscholl2/smc typescript
|
| 1657 |
+
hxptls/P0000 c
|
| 1658 |
+
kusabashira/prod go
|
| 1659 |
+
telefonicaid/fiware-cosmos-platform java
|
| 1660 |
+
developer239/workbox-webpack-react javascript
|
| 1661 |
+
StealThisShow/StealThisTracker php
|
| 1662 |
+
ScatterHQ/eliot python
|
| 1663 |
+
1337807/rubygems.org ruby
|
| 1664 |
+
naoty/table rust
|
| 1665 |
+
Sarah-Seo/Inpad typescript
|
| 1666 |
+
tizoc/chibi-shen c
|
| 1667 |
+
shiftky/go-tmsh go
|
| 1668 |
+
synchrotron-soleil-ica/continuous-materials java
|
| 1669 |
+
lm-tools/work-you-could-do javascript
|
| 1670 |
+
LidskaSila/Glow php
|
| 1671 |
+
NewKnowledge/punk python
|
| 1672 |
+
PagerDuty/lita-pagerduty ruby
|
| 1673 |
+
ms705/nom-sql rust
|
| 1674 |
+
daveross/catalogopolis-api typescript
|
| 1675 |
+
MTG/essentia c
|
| 1676 |
+
ninjasphere/go-ninja go
|
| 1677 |
+
mrts/vaadin-javaee-clinic-patient-queue-example java
|
| 1678 |
+
fma2/nyc-high-school-programs javascript
|
| 1679 |
+
nailsapp/module-comment php
|
| 1680 |
+
rdo-management/ironic-discoverd python
|
| 1681 |
+
daxadax/quotes ruby
|
| 1682 |
+
softprops/hyperlocal rust
|
| 1683 |
+
jacwright/typewriter typescript
|
| 1684 |
+
viccc/AHKNavigationController c
|
| 1685 |
+
AdamIsrael/juju go
|
| 1686 |
+
mcada/syndesis-qe java
|
| 1687 |
+
openspending/subsidystories.eu javascript
|
| 1688 |
+
joindin/joindin-web2 php
|
| 1689 |
+
igstan/redis-grep python
|
| 1690 |
+
dark-panda/ncsa-parser ruby
|
| 1691 |
+
glyn/jvmkill rust
|
| 1692 |
+
awayjs/awayjs-player typescript
|
| 1693 |
+
llvm-mirror/libclc c
|
| 1694 |
+
sttts/elastic-etcd go
|
| 1695 |
+
ChrisLMerrill/muse java
|
| 1696 |
+
jonsuh/hamburgers javascript
|
| 1697 |
+
soilby/queue-http-endpoint-bundle php
|
| 1698 |
+
opencord/voltha python
|
| 1699 |
+
deliveroo/ravelin-ruby ruby
|
| 1700 |
+
Rust-SDL2/rust-sdl2 rust
|
| 1701 |
+
pancho111203/JsonFormsEditor typescript
|
| 1702 |
+
xhochy/libfuzzymatch c
|
| 1703 |
+
jroimartin/syscallinfo go
|
| 1704 |
+
AxonFramework/AxonFramework java
|
| 1705 |
+
sanity-io/sanity javascript
|
| 1706 |
+
noopable/zf2 php
|
| 1707 |
+
xandr2/blynkapi python
|
| 1708 |
+
jphager2/pakyow ruby
|
| 1709 |
+
mvdnes/element76 rust
|
| 1710 |
+
BD2K-DDI/ddi-web-app typescript
|
| 1711 |
+
MarcoFalke/bitcoin c
|
| 1712 |
+
smkell/resolutionizerd go
|
| 1713 |
+
ryanbrainard/shoehorn java
|
| 1714 |
+
ceolter/ag-grid javascript
|
| 1715 |
+
delighted/delighted-php php
|
| 1716 |
+
exoanalytic/python-skyfield python
|
| 1717 |
+
ekylibre/ekylibre ruby
|
| 1718 |
+
hoodie/iso8601 rust
|
| 1719 |
+
flubstep/engvalues typescript
|
| 1720 |
+
mlatham/AFToolkit c
|
| 1721 |
+
kusabashira/catn go
|
| 1722 |
+
NCIP/national-biomedical-image-archive java
|
| 1723 |
+
bpsinc-native/src_third_party_trace-viewer javascript
|
| 1724 |
+
DOut4Harambe/starter-quotes php
|
| 1725 |
+
hobarrera/django-afip python
|
| 1726 |
+
bboe/sync_issues ruby
|
| 1727 |
+
justinas/gettext rust
|
| 1728 |
+
craft-ai/most-utils typescript
|
| 1729 |
+
gribozavr/swift c
|
| 1730 |
+
cnejame/ygor go
|
| 1731 |
+
reportportal/commons-dao java
|
| 1732 |
+
Tokimon/vanillajs-helpers javascript
|
| 1733 |
+
dwightwatson/autologin php
|
| 1734 |
+
Connexions/cnx-publishing python
|
| 1735 |
+
nycdot/transam_core ruby
|
| 1736 |
+
portier/portier-broker rust
|
| 1737 |
+
georgemarshall/DefinitelyTyped typescript
|
| 1738 |
+
raoulh/Enna-Media-Server c
|
| 1739 |
+
bobtfish/docker-consul-awsnycast go
|
| 1740 |
+
vsplf/vsplf-dynamic-i18n java
|
| 1741 |
+
ethan605/react-native-zero javascript
|
| 1742 |
+
letsdrink/ouzo php
|
| 1743 |
+
Charcoal-SE/SmokeDetector python
|
| 1744 |
+
jhilde/studentinsights ruby
|
| 1745 |
+
exonum/exonum rust
|
| 1746 |
+
gcriva/gcriva-frontend typescript
|
| 1747 |
+
gsamokovarov/chip8.c c
|
| 1748 |
+
brettchalupa/dat go
|
| 1749 |
+
ebi-uniprot/QuickGOBE java
|
| 1750 |
+
yamb/yamb javascript
|
| 1751 |
+
hypothesis/wordpress-theme-hypothesis php
|
| 1752 |
+
pfmoore/invoke python
|
| 1753 |
+
tutsplus/build-a-ruby-product-for-the-long-run ruby
|
| 1754 |
+
gnuvince/ppbert rust
|
| 1755 |
+
kactus-io/kactus typescript
|
| 1756 |
+
giginet/CCMessageWindow c
|
| 1757 |
+
mdlayher/goat go
|
| 1758 |
+
squix78/esp8266-oled-ssd1306-font-converter java
|
| 1759 |
+
navjobs/upload javascript
|
| 1760 |
+
foodsharing-dev/foodsharing-api php
|
| 1761 |
+
Calysto/metakernel python
|
| 1762 |
+
smtlaissezfaire/active_conductor ruby
|
| 1763 |
+
cwandrews/ed rust
|
| 1764 |
+
flybayer/next.js typescript
|
| 1765 |
+
AlexanderMazaletskiy/UICountingLabel c
|
| 1766 |
+
nlopes/slack go
|
| 1767 |
+
malikov/platform-android java
|
| 1768 |
+
marihachi/CrystalResonance javascript
|
| 1769 |
+
justcarakas/forkcms php
|
| 1770 |
+
CCI-MOC/GUI-Backend python
|
| 1771 |
+
marxarelli/vagrant ruby
|
| 1772 |
+
mattgreen/watchexec rust
|
| 1773 |
+
witheve/eve-starter typescript
|
| 1774 |
+
binlaten/framework c
|
| 1775 |
+
pointlander/peg go
|
| 1776 |
+
aureliano/achmed java
|
| 1777 |
+
taoger/highlight.js javascript
|
| 1778 |
+
dilawar/moodle php
|
| 1779 |
+
harvard-lil/h2o python
|
| 1780 |
+
jpmat296/homebrew-cask ruby
|
| 1781 |
+
uptech/alt rust
|
| 1782 |
+
vvfosprojects/sovvf typescript
|
| 1783 |
+
NLP/NLP c
|
| 1784 |
+
fimad/ggircd go
|
| 1785 |
+
ngageoint/mage-android java
|
| 1786 |
+
SomeoneWeird/new.nodejs.org javascript
|
| 1787 |
+
rinvex/cortex-foundation php
|
| 1788 |
+
binoculars/osf.io python
|
| 1789 |
+
theablefew/goodyear ruby
|
| 1790 |
+
felipesere/icepick rust
|
| 1791 |
+
AlexChesters/ukpd typescript
|
| 1792 |
+
Morphux/lib c
|
| 1793 |
+
rancherio/go-rancher go
|
| 1794 |
+
jswudi/alluxio java
|
| 1795 |
+
walmartlabs/circus-handlebars javascript
|
| 1796 |
+
bakape/r-a-d.io php
|
| 1797 |
+
kjordahl/swm python
|
| 1798 |
+
indeep-xyz/ruby-insensitive-search ruby
|
| 1799 |
+
eyolfson/eyl-shell rust
|
| 1800 |
+
jjhampton/angular2-tour-of-heroes typescript
|
| 1801 |
+
AperEntertainment/AperCommon c
|
| 1802 |
+
anacrolix/missinggo go
|
| 1803 |
+
folio-org/okapi java
|
| 1804 |
+
sbsmith86/neue javascript
|
| 1805 |
+
FlorentMetz/flotz php
|
| 1806 |
+
tomv564/LSP python
|
| 1807 |
+
icyflame/cutouts ruby
|
| 1808 |
+
graememcc/netStack rust
|
| 1809 |
+
scania/corporate-ui typescript
|
| 1810 |
+
embox/embox c
|
| 1811 |
+
giancosta86/caravel go
|
| 1812 |
+
Otanikotani/jacoco-parser java
|
| 1813 |
+
rakuten-frontend/rff-gulp javascript
|
| 1814 |
+
castlegateit/cgit-wp-breadcrumb-nav-menu php
|
| 1815 |
+
thomasballinger/tmuxp python
|
| 1816 |
+
cenit-io/cenit ruby
|
| 1817 |
+
opp11/calcr rust
|
| 1818 |
+
abraham/nutmeg-cli typescript
|
| 1819 |
+
ijacquez/libyaul c
|
| 1820 |
+
airbrake/gobrake go
|
| 1821 |
+
mikera/magic java
|
| 1822 |
+
matrix-org/matrix-react-sdk javascript
|
| 1823 |
+
shopixco/magento-clixgalore php
|
| 1824 |
+
philipdexter/vx python
|
| 1825 |
+
Eric-Guo/refinerycms ruby
|
| 1826 |
+
aepsil0n/rust rust
|
| 1827 |
+
azkurban/ng2 typescript
|
| 1828 |
+
chubbymaggie/asap c
|
| 1829 |
+
trasa/watchmud go
|
| 1830 |
+
Team08DatabaseProject/Healthy-Food-Ltd. java
|
| 1831 |
+
AbhilashSrivastava/haraka_sniffer javascript
|
| 1832 |
+
zburke/omnipay-bluepay php
|
| 1833 |
+
OnroerendErfgoed/crabpy python
|
| 1834 |
+
upinetree/nicorepo ruby
|
| 1835 |
+
matthiasbeyer/imag rust
|
| 1836 |
+
hslayers/hslayers-ng typescript
|
| 1837 |
+
yenWu/DDNS c
|
| 1838 |
+
kayex/chalmers-chop go
|
| 1839 |
+
testpress/android java
|
| 1840 |
+
unexpectedjs/unexpected javascript
|
| 1841 |
+
memborsky/irexinc.org php
|
| 1842 |
+
gviot/nadis python
|
| 1843 |
+
scotdalton/dayglo ruby
|
| 1844 |
+
antifuchs/chars rust
|
| 1845 |
+
xaverh/vscode-clang-format-provider typescript
|
| 1846 |
+
natsys/mariadb_10.2 c
|
| 1847 |
+
vanng822/aguin go
|
| 1848 |
+
davidmaignan/JDrive java
|
| 1849 |
+
lakrme/atom-levels javascript
|
| 1850 |
+
Osiruss/ForumTest php
|
| 1851 |
+
moreati/b-prefix-all-the-doctests python
|
| 1852 |
+
yonahforst/react-native-permissions ruby
|
| 1853 |
+
rust-lang/reference rust
|
| 1854 |
+
steveukx/git-js typescript
|
| 1855 |
+
achingupta/arm-trusted-firmware c
|
| 1856 |
+
tv42/becky go
|
| 1857 |
+
juve/corral java
|
| 1858 |
+
watilde/npm-report javascript
|
| 1859 |
+
fluxbb/commonmark php
|
| 1860 |
+
rudeb0t/DjangoAllowDeny python
|
| 1861 |
+
aliyun-beta/aliyun-openapi-ruby-sdk ruby
|
| 1862 |
+
hch12907/wiz rust
|
| 1863 |
+
sauli6692/ibc-server typescript
|
| 1864 |
+
rgde/lz4mt c
|
| 1865 |
+
divtxt/raft-consensus go
|
| 1866 |
+
yichen0831/SpaceMission java
|
| 1867 |
+
PonteIneptique/arethusa javascript
|
| 1868 |
+
Metrique/laravel-building php
|
| 1869 |
+
bodbdigr/restea python
|
| 1870 |
+
landrito/google-cloud-ruby ruby
|
| 1871 |
+
lise-henry/crowbook rust
|
| 1872 |
+
nodeswork/sbase typescript
|
| 1873 |
+
tdenniston/Halide c
|
| 1874 |
+
go-task/task go
|
| 1875 |
+
jakriz/derrick java
|
| 1876 |
+
TheBeastOfCaerbannog/kinospartak-bot javascript
|
| 1877 |
+
opdavies/sculpin php
|
| 1878 |
+
7ws/django-emailer python
|
| 1879 |
+
wsmoak/chargify-examples ruby
|
| 1880 |
+
Fraser999/sodiumoxide rust
|
| 1881 |
+
akorchev/odata2openapi typescript
|
| 1882 |
+
nerdishbynature/octokit.swift c
|
| 1883 |
+
Chasego/cod go
|
| 1884 |
+
stefan-ka/dddsample-core java
|
| 1885 |
+
sharaal/dnode javascript
|
| 1886 |
+
remxcode/laravel-base php
|
| 1887 |
+
mandiant/ioc_writer python
|
| 1888 |
+
tumblr/ostrichpoll ruby
|
| 1889 |
+
squid-lang/squid rust
|
| 1890 |
+
JakeSidSmith/sensible-canvas-interface typescript
|
| 1891 |
+
jordemort/e17 c
|
| 1892 |
+
yumaikas/PISC-mirror go
|
| 1893 |
+
spark/photon-tinker-android java
|
| 1894 |
+
torbenbrodt/smarthome javascript
|
| 1895 |
+
BNETDocs/bnetdocs-web php
|
| 1896 |
+
cloudify-cosmo/tosca-vcloud-plugin python
|
| 1897 |
+
opsb/patchstream ruby
|
| 1898 |
+
jroesch/rust rust
|
| 1899 |
+
landonepps/vscode typescript
|
| 1900 |
+
dtzWill/ipcopter c
|
| 1901 |
+
CloudyKit/jet go
|
| 1902 |
+
gr8pefish/OpenGlider java
|
| 1903 |
+
controversial/controversial.io javascript
|
| 1904 |
+
guillaumebriday/laravel-blog php
|
| 1905 |
+
alisaifee/flask-limiter python
|
| 1906 |
+
tim-group/stackbuilder ruby
|
| 1907 |
+
rustoscript/french-press rust
|
| 1908 |
+
tbragaf/ng2-seed typescript
|
| 1909 |
+
rvandegrift/e c
|
| 1910 |
+
jonlawlor/matrixexp go
|
| 1911 |
+
liachmodded/Railcraft-API java
|
| 1912 |
+
sakmas/RetainerReport javascript
|
| 1913 |
+
nekodex/osu-web php
|
| 1914 |
+
xmunoz/sodapy python
|
| 1915 |
+
joshmcarthur/disclosure ruby
|
| 1916 |
+
1tgr/rust-os rust
|
| 1917 |
+
aranja/tux typescript
|
| 1918 |
+
google/perfetto c
|
| 1919 |
+
Thomasdezeeuw/tools go
|
| 1920 |
+
project-ncl/dependency-analysis java
|
| 1921 |
+
adamsea/recipes-api javascript
|
| 1922 |
+
svpernova09/SvperCRM php
|
| 1923 |
+
mass-project/mass_api_client python
|
| 1924 |
+
kif-ev/oskiosk-server ruby
|
| 1925 |
+
KokaKiwi/rust rust
|
| 1926 |
+
scottohara/loot typescript
|
| 1927 |
+
klaaspieter/APIClient c
|
| 1928 |
+
kubernetes/apiextensions-apiserver go
|
| 1929 |
+
googleinterns/step57-2020 java
|
| 1930 |
+
InTeXration/InTeXration-Server javascript
|
| 1931 |
+
digitalkaoz/ivory-http-adapter php
|
| 1932 |
+
gsarma/ChannelWorm python
|
| 1933 |
+
dijonkitchen/shopping-api ruby
|
| 1934 |
+
japaric/rustc-builtins rust
|
| 1935 |
+
artsy/metaphysics typescript
|
| 1936 |
+
xistoso/CppSharp c
|
| 1937 |
+
dgageot/getme go
|
| 1938 |
+
ivargrimstad/mvc-samples java
|
| 1939 |
+
richarddewit/random-quotes javascript
|
| 1940 |
+
davidtsadler/ebay-sdk-trading php
|
| 1941 |
+
markbrough/exchangerates python
|
| 1942 |
+
degica/barcelona ruby
|
| 1943 |
+
rust-lang/libc rust
|
| 1944 |
+
Dia6lo/Mechanism typescript
|
| 1945 |
+
Geek-1001/Clue c
|
| 1946 |
+
royvandewater/go-to-hell go
|
| 1947 |
+
dimagi/commcare java
|
| 1948 |
+
theredcat/forge javascript
|
| 1949 |
+
kayladnls/doctrine-additions php
|
| 1950 |
+
TangledWeb/tangled.sqlalchemy python
|
| 1951 |
+
slawosz/rubinius ruby
|
| 1952 |
+
mneumann/lindenmayer-system rust
|
| 1953 |
+
Cinergix/rxdata typescript
|
| 1954 |
+
Aufree/phphub-ios c
|
| 1955 |
+
runner-mei/goal go
|
| 1956 |
+
jaxbot/android-preconditioning-leaf java
|
| 1957 |
+
airycanon/Ghost-Admin javascript
|
| 1958 |
+
lokothodida/php-simplequery php
|
| 1959 |
+
FlipperPA/wagtailpress python
|
| 1960 |
+
talk-to/NSData-TDTImageMIMEDetection ruby
|
| 1961 |
+
anastasia-tarasova/indy-sdk rust
|
| 1962 |
+
AyaMorisawa/node-powerful typescript
|
| 1963 |
+
ssp/Pester c
|
| 1964 |
+
maruel/dlibox go
|
| 1965 |
+
kuujo/copycat java
|
| 1966 |
+
ASzc/selfish-youtube javascript
|
| 1967 |
+
Hexanet/LogBundle php
|
| 1968 |
+
TangledWeb/tangled.website python
|
| 1969 |
+
SergXIIIth/vxod ruby
|
| 1970 |
+
Danite/NainEngine rust
|
| 1971 |
+
surveyjs/surveyjs typescript
|
| 1972 |
+
podio/podio-objc c
|
| 1973 |
+
simonjjones/atc go
|
| 1974 |
+
sveinnfannar/finagle java
|
| 1975 |
+
matrix-org/matrix-appservice-irc javascript
|
| 1976 |
+
Hng-X/linxer php
|
| 1977 |
+
sedders123/phial python
|
| 1978 |
+
5xRuby/rubyconftw-cfp ruby
|
| 1979 |
+
daschl/grok rust
|
| 1980 |
+
RickCarlino/farmbot-web-app typescript
|
| 1981 |
+
qnu/qfs c
|
| 1982 |
+
anacrolix/dht go
|
| 1983 |
+
bearing/dosenet-apps java
|
| 1984 |
+
MaxWhere/electron javascript
|
| 1985 |
+
neonbug/meexo php
|
| 1986 |
+
JrGoodle/clowder python
|
| 1987 |
+
handcrafted/foundation ruby
|
| 1988 |
+
chriskrycho/lightning-rs rust
|
| 1989 |
+
marvinhagemeister/mobx-form-reactions typescript
|
| 1990 |
+
GaloisInc/halvm-ghc c
|
| 1991 |
+
localhots/satan go
|
| 1992 |
+
tcat-tamu/auth java
|
| 1993 |
+
jonkemp/wizard-mvc javascript
|
| 1994 |
+
libgraviton/graviton php
|
| 1995 |
+
kevgathuku/top40 python
|
| 1996 |
+
nyc-mud-turtles-2015/nghborly ruby
|
| 1997 |
+
dtolnay/quote rust
|
| 1998 |
+
briandk/transcriptase typescript
|
| 1999 |
+
adammurdoch/native-platform c
|
| 2000 |
+
thoas/picfit go
|
| 2001 |
+
joshsh/twitlogic java
|
| 2002 |
+
DTL-FAIRData/FAIRifier javascript
|
| 2003 |
+
Adldap2/Adldap2-laravel php
|
| 2004 |
+
erikrose/blessings python
|
| 2005 |
+
CrewLabs/tinplate ruby
|
| 2006 |
+
jmacdonald/luthor rust
|
| 2007 |
+
MadaraUchiha/se-chat-dark-theme-plus typescript
|
| 2008 |
+
8l/scc c
|
| 2009 |
+
mmcdole/gofeed go
|
| 2010 |
+
adamski8/MyWeather java
|
| 2011 |
+
jerelmiller/redux-simple-auth javascript
|
| 2012 |
+
pfaocle/codeception-module-drupal-user-registry php
|
| 2013 |
+
yola/auth_tkt python
|
| 2014 |
+
mubi/user_preferences ruby
|
| 2015 |
+
j16r/rust rust
|
| 2016 |
+
AyaMorisawa/Disskey typescript
|
| 2017 |
+
waysome/libreset c
|
| 2018 |
+
pivotal-cf/cf-rabbitmq-release go
|
| 2019 |
+
SpineEventEngine/core-java java
|
| 2020 |
+
hanamura/gulp-minisite javascript
|
| 2021 |
+
nooku/nooku-platform php
|
| 2022 |
+
consbio/parserutils python
|
| 2023 |
+
akshaykarle/veewee ruby
|
| 2024 |
+
tov/libffi-rs rust
|
| 2025 |
+
frt/happyscheduler typescript
|
| 2026 |
+
jackromo/CNoodle c
|
| 2027 |
+
moovweb/tritium go
|
| 2028 |
+
facebook/litho java
|
| 2029 |
+
adube/ngeo javascript
|
| 2030 |
+
makeandship/acf-elasticsearch php
|
| 2031 |
+
archsh/tg2ext.express python
|
| 2032 |
+
brainopia/flow ruby
|
| 2033 |
+
gentoo90/winreg-rs rust
|
| 2034 |
+
virtuoushub/game-off-2016 typescript
|
| 2035 |
+
PaystackHQ/paystack-ios c
|
| 2036 |
+
jimmidyson/minishift go
|
| 2037 |
+
JRebirth/JRebirth java
|
| 2038 |
+
madrobby/scripty2 javascript
|
| 2039 |
+
njam/denkmal.org php
|
| 2040 |
+
MichaelYusko/Bot-Chucky python
|
| 2041 |
+
jakerenzella/doubtfire-api ruby
|
| 2042 |
+
sakeven/rust-rosetta rust
|
| 2043 |
+
arusakov/DefinitelyTyped typescript
|
| 2044 |
+
mtulio/kb c
|
| 2045 |
+
cybozu-go/log go
|
| 2046 |
+
rebasar/lunchy java
|
| 2047 |
+
cedaro/cedaro-wp-theme-config javascript
|
| 2048 |
+
mattsah/bustle php
|
| 2049 |
+
ryanmcdermott/birdseed python
|
| 2050 |
+
arkency/rails_event_store ruby
|
| 2051 |
+
jedisct1/sodiumoxide rust
|
| 2052 |
+
gluons/vue-thailand-address typescript
|
| 2053 |
+
APCVSRepo/sdl_ios c
|
| 2054 |
+
xqin/miniflux go
|
| 2055 |
+
Brokkonaut/CubeQuest java
|
| 2056 |
+
Turistforeningen/Hytteadmin javascript
|
| 2057 |
+
activecollab/databasestructure php
|
| 2058 |
+
mociepka/saleor python
|
| 2059 |
+
turboladen/playful ruby
|
| 2060 |
+
maghoff/bart rust
|
| 2061 |
+
reactivestack/cookies typescript
|
| 2062 |
+
e-mission/cordova-server-sync c
|
| 2063 |
+
pivotal-cf-experimental/bosh-bootloader go
|
| 2064 |
+
CapOM/ChromiumGStreamerBackend java
|
| 2065 |
+
DoctorMcKay/node-steam-tradeoffer-manager javascript
|
| 2066 |
+
ampproject/amp-toolbox-php php
|
| 2067 |
+
GallopLabs/facebook-ads-api python
|
| 2068 |
+
et/clamshell ruby
|
| 2069 |
+
szeged/servo rust
|
| 2070 |
+
Romakita/ts-express-decorators typescript
|
| 2071 |
+
guilherme-pg/lyra2 c
|
| 2072 |
+
exercism/cli go
|
| 2073 |
+
CDRussell/CasterRxJava java
|
| 2074 |
+
ffont/freesound-explorer javascript
|
| 2075 |
+
yapici/Inventory-Management-System php
|
| 2076 |
+
rail/releasetasks python
|
| 2077 |
+
dhemery/latex-markdown ruby
|
| 2078 |
+
aldanor/typeinfo rust
|
| 2079 |
+
rootulp/exercism typescript
|
| 2080 |
+
cmr/seL4 c
|
| 2081 |
+
tardisx/discord-auto-upload go
|
| 2082 |
+
MacroData/skyprint java
|
| 2083 |
+
AyaNakazawa/business_card_bank javascript
|
| 2084 |
+
kielabokkie/dotenv-diff php
|
| 2085 |
+
sebdah/yayson python
|
| 2086 |
+
WikiEducationFoundation/WikiEduDashboard ruby
|
| 2087 |
+
nbigaouette/gitlab-api-rs rust
|
| 2088 |
+
jupl/astraea typescript
|
| 2089 |
+
mfrey/RIOT c
|
| 2090 |
+
google/wuffs go
|
| 2091 |
+
jenkinsci/codedx-plugin java
|
| 2092 |
+
ScottMaclure/scott-cv javascript
|
| 2093 |
+
omise/omise-magento php
|
| 2094 |
+
serge-sans-paille/gast python
|
| 2095 |
+
mnipper/rails_survey ruby
|
| 2096 |
+
tohou/diesel rust
|
| 2097 |
+
joelgeorgev/file-hash-verifier typescript
|
| 2098 |
+
chaitanyav/cprograms c
|
| 2099 |
+
pivotal-cf/cred-alert go
|
| 2100 |
+
Zaggy1024/MinecraftForge java
|
| 2101 |
+
nickmccurdy/purespec javascript
|
| 2102 |
+
bryanlatten/docker-php php
|
| 2103 |
+
adlibre/django-bcp python
|
| 2104 |
+
beni55/falcor-1 ruby
|
| 2105 |
+
kjgorman/basiccms.rs rust
|
| 2106 |
+
jiahaog/Nativefier typescript
|
| 2107 |
+
joeljk13/Timer c
|
| 2108 |
+
drewsetski/koding go
|
| 2109 |
+
TeamWertarbyte/craften-launcher java
|
| 2110 |
+
pluggerjs/plugger javascript
|
| 2111 |
+
GeniusTS/preferences php
|
| 2112 |
+
ayushgoel/mstranslator python
|
| 2113 |
+
chef/em-winrm ruby
|
| 2114 |
+
samdoshi/portmidi-rs rust
|
| 2115 |
+
kiswa/TaskBoard typescript
|
| 2116 |
+
fujunwei/chromium-crosswalk c
|
| 2117 |
+
UserStack/ustackweb go
|
| 2118 |
+
jitsi/jitsi java
|
| 2119 |
+
HermanFassett/project-osiris-website javascript
|
| 2120 |
+
symfony/security-core php
|
| 2121 |
+
gilesbrown/python-icapservice python
|
| 2122 |
+
rubyforgood/diaper ruby
|
| 2123 |
+
kwantam/rust rust
|
| 2124 |
+
pd4d10/intelli-octo typescript
|
| 2125 |
+
KristFoundation/Programs c
|
| 2126 |
+
jrupac/goliath go
|
| 2127 |
+
quarkusio/quarkus java
|
| 2128 |
+
gaearon/redux javascript
|
| 2129 |
+
DarvinStudio/DarvinAdminBundle php
|
| 2130 |
+
nigma/dj-cmd python
|
| 2131 |
+
gds-attic/contact-o-tron ruby
|
| 2132 |
+
rsaarelm/magog rust
|
| 2133 |
+
ipatalas/vscode-postfix-ts typescript
|
| 2134 |
+
jmurzy/nodegit c
|
| 2135 |
+
pkg/browser go
|
| 2136 |
+
filestack/filestack-java java
|
| 2137 |
+
spherelot/teamboard-api javascript
|
| 2138 |
+
souldigital/silverstripe-userforms php
|
| 2139 |
+
srittau/rouver python
|
| 2140 |
+
theodi/panopticon ruby
|
| 2141 |
+
Wallacoloo/serde_osc rust
|
| 2142 |
+
Goyatuzo/LurkerBot typescript
|
| 2143 |
+
tbporter/http-server c
|
| 2144 |
+
datawire/telepresence go
|
| 2145 |
+
IchorPowered/Latch java
|
| 2146 |
+
itsananderson/burden javascript
|
| 2147 |
+
occitech/Occitech_ShopyMind php
|
| 2148 |
+
VirgilSecurity/virgil-sdk-python python
|
| 2149 |
+
Arie/serveme ruby
|
| 2150 |
+
aepsil0n/graphics rust
|
| 2151 |
+
MikeBull94/aurelia-hacker-news typescript
|
| 2152 |
+
haxpor/playbasis-ios c
|
| 2153 |
+
vrischmann/rdbtools go
|
| 2154 |
+
scenarioo/scenarioo-selenium-demo java
|
| 2155 |
+
mafintosh/protocol-buffers-schema javascript
|
| 2156 |
+
BKWLD/upchuck php
|
| 2157 |
+
verilylifesciences/analysis-py-utils python
|
| 2158 |
+
fakefs/fakefs ruby
|
| 2159 |
+
CensoredUsername/dynasm-rs rust
|
| 2160 |
+
WorldBrain/WebMemex typescript
|
| 2161 |
+
altMITgcm/MITgcm66h c
|
| 2162 |
+
Logiraptor/oak go
|
| 2163 |
+
pholser/junit-quickcheck java
|
| 2164 |
+
UKHomeOffice/passports-prototype javascript
|
| 2165 |
+
Simovative/zeus php
|
| 2166 |
+
compunova/kozinaki python
|
| 2167 |
+
t-morgan/sequel ruby
|
| 2168 |
+
ghotiphud/rust-rosetta rust
|
| 2169 |
+
eskatos/gradle-command-action typescript
|
| 2170 |
+
yitian134/chromium c
|
| 2171 |
+
materials-commons/materials go
|
| 2172 |
+
theworldbright/SoundLocker java
|
| 2173 |
+
otacke/h5p-agamotto javascript
|
| 2174 |
+
frqnck/apix php
|
| 2175 |
+
wangjohn/zinc_cli python
|
| 2176 |
+
thekompanee/fuubar ruby
|
| 2177 |
+
steveklabnik/rust_example rust
|
| 2178 |
+
PioneerCode/pioneer-tree typescript
|
| 2179 |
+
Jtalk/kopete-fork-xep0136 c
|
| 2180 |
+
keybase/client go
|
| 2181 |
+
jimmyli97/mathosphere java
|
| 2182 |
+
ohmanger/userscripts javascript
|
| 2183 |
+
MTon/api php
|
| 2184 |
+
SCUEvals/scuevals-api python
|
| 2185 |
+
alphagov/manuals-publisher ruby
|
| 2186 |
+
yasuyuky/ghteam-auth rust
|
| 2187 |
+
ngako/angular2-poc typescript
|
| 2188 |
+
daukantas/octokit.objc c
|
| 2189 |
+
rafaeljusto/gddoexp go
|
| 2190 |
+
jpaoletti/java-presentation-manager java
|
| 2191 |
+
yangmillstheory/chunkify javascript
|
| 2192 |
+
digitoimistodude/air php
|
| 2193 |
+
ifduyue/urlfetch python
|
| 2194 |
+
danielwestendorf/blow_pipe ruby
|
| 2195 |
+
sgrif/diesel rust
|
| 2196 |
+
algorithm-ninja/task-wizard typescript
|
| 2197 |
+
Vector35/binaryninja-api c
|
| 2198 |
+
mscoutermarsh/exercism_coveralls go
|
| 2199 |
+
aislab-hevs/magpie java
|
| 2200 |
+
PrasannaVenkadesh/portia javascript
|
| 2201 |
+
hfcorriez/pagon php
|
| 2202 |
+
cychiang/mafan python
|
| 2203 |
+
Promoboxx/cookbooks_public ruby
|
| 2204 |
+
nodakai/rust-static_assert_macro rust
|
| 2205 |
+
Clever/node-process-metrics typescript
|
| 2206 |
+
rbld/rebuild c
|
| 2207 |
+
matt-royal/cf-acceptance-tests go
|
| 2208 |
+
jerome79/OG-Platform java
|
| 2209 |
+
codarchlab/idai-field-client javascript
|
| 2210 |
+
at15/MissAtomicBomb php
|
| 2211 |
+
mcmtroffaes/pathlib2 python
|
| 2212 |
+
jawj/passenger ruby
|
| 2213 |
+
olson-sean-k/plexus rust
|
| 2214 |
+
ospatil/generator-node-typescript typescript
|
| 2215 |
+
nickelsberry/AXStretchableHeaderTabViewController c
|
| 2216 |
+
lxc/lxd go
|
| 2217 |
+
nallar/TickThreading java
|
| 2218 |
+
hjtoday/CBoard javascript
|
| 2219 |
+
DanTheDJ/multitenant php
|
| 2220 |
+
tilezen/scoville python
|
| 2221 |
+
BBC-News/alephant-renderer ruby
|
| 2222 |
+
stallmanifold/rust-multiboot2 rust
|
| 2223 |
+
WeAreWizards/crumpets typescript
|
| 2224 |
+
Raizlabs/BonMot c
|
| 2225 |
+
facesea/banshee go
|
| 2226 |
+
jpodeszwik/mifos java
|
| 2227 |
+
firebug/tracing-console javascript
|
| 2228 |
+
highway-accident/tracker php
|
| 2229 |
+
pczerkas/captainhook python
|
| 2230 |
+
mirego/bourgeois ruby
|
| 2231 |
+
rprichard/rust rust
|
| 2232 |
+
artfuldev/RIoT typescript
|
| 2233 |
+
laarmen/lua_debug c
|
| 2234 |
+
ranjithamca/gru go
|
| 2235 |
+
ProxyPrint/proxyprint-kitchen java
|
| 2236 |
+
yajinni/WoWAnalyzer javascript
|
| 2237 |
+
nimbusoftltd/parrot php
|
| 2238 |
+
benedictpaten/cactus python
|
| 2239 |
+
kolorahl/warden-token ruby
|
| 2240 |
+
ttokutake/kic rust
|
| 2241 |
+
uwdata/vega-lite typescript
|
| 2242 |
+
hgl888/chromium-crosswalk-efl c
|
| 2243 |
+
pierreozoux/guides go
|
| 2244 |
+
vespa-engine/vespa java
|
| 2245 |
+
umasudhan/weather javascript
|
| 2246 |
+
navarr/advent-of-code php
|
| 2247 |
+
caktus/django-pagelets python
|
| 2248 |
+
jnunemaker/httparty ruby
|
| 2249 |
+
gifnksm/rust rust
|
| 2250 |
+
joelgeorgev/react-checkbox-tree typescript
|
| 2251 |
+
NiVZ78/concentricity c
|
| 2252 |
+
HeiaHeia/trello-bot go
|
| 2253 |
+
epimorphics/dclib java
|
| 2254 |
+
metidia/waterline javascript
|
| 2255 |
+
denkmal/denkmal.org php
|
| 2256 |
+
suminb/urwid-stackedwidget python
|
| 2257 |
+
jamesotron/MrDarcy ruby
|
| 2258 |
+
tilpner/ilc rust
|
| 2259 |
+
jbrowneuk/jblog typescript
|
| 2260 |
+
ring-lang/ring c
|
| 2261 |
+
go-interpreter/wagon go
|
| 2262 |
+
conveyal/gtfs-data-manager java
|
| 2263 |
+
rawrsome/firebase-simple-login javascript
|
| 2264 |
+
mitchfizz05/Sphinx php
|
| 2265 |
+
alphagov/stagecraft python
|
| 2266 |
+
renewablefunding/huddle ruby
|
| 2267 |
+
gustavla/numeric rust
|
| 2268 |
+
inad9300/Soil typescript
|
| 2269 |
+
jvns/kernel-module-fun c
|
| 2270 |
+
cjcjameson/fly go
|
| 2271 |
+
KILFaT/BudgetKeeper java
|
| 2272 |
+
MyEtherWallet/MyEtherWallet javascript
|
| 2273 |
+
rocketeers/rocketeer php
|
| 2274 |
+
Connexions/cnx-authoring python
|
| 2275 |
+
clhynfield/vagrant-ansible-osx ruby
|
| 2276 |
+
way-cooler/way-cooler rust
|
| 2277 |
+
disjukr/jews typescript
|
| 2278 |
+
Zlacki/slackboat c
|
| 2279 |
+
Cepave/open-falcon-backend go
|
| 2280 |
+
athy/fape java
|
| 2281 |
+
maxdome/maxdome-node javascript
|
| 2282 |
+
dimitriacosta/html php
|
| 2283 |
+
agoragames/py-eventsocket python
|
| 2284 |
+
ilackarms/manageiq ruby
|
| 2285 |
+
olson-sean-k/bismuth rust
|
| 2286 |
+
Alberthaff/ngx-papaparse typescript
|
| 2287 |
+
TolikH/ofp c
|
| 2288 |
+
mistifyio/mistify-operator-admin go
|
| 2289 |
+
ksoichiro/spring-boot-practice java
|
| 2290 |
+
unkhz/almost-static-site javascript
|
| 2291 |
+
moazam1/telegram-bot-sdk php
|
| 2292 |
+
evoja/docker-Github-Gitlab-Auto-Deploy python
|
| 2293 |
+
joeosburn/cannon ruby
|
| 2294 |
+
DimaKudosh/difflib rust
|
| 2295 |
+
Hersir88/Babylon.js typescript
|
| 2296 |
+
GNOME/json-glib c
|
| 2297 |
+
oakmound/oak go
|
| 2298 |
+
damianham/react-native-audio-kit java
|
| 2299 |
+
jonkemp/inline-css javascript
|
| 2300 |
+
r3oath/hive php
|
| 2301 |
+
incuna/feincms-extensions python
|
| 2302 |
+
k1w1/rendered-multi-select ruby
|
| 2303 |
+
bluss/quickcheck rust
|
| 2304 |
+
oster/mute typescript
|
| 2305 |
+
JuudeDemos/fb-adb c
|
| 2306 |
+
pivotal-cf-experimental/destiny go
|
| 2307 |
+
electrum/presto-hive-apache java
|
| 2308 |
+
derektliu/Picky-Notes javascript
|
| 2309 |
+
FriendsOfCake/CakePdf php
|
| 2310 |
+
zmbq/djqgrid python
|
| 2311 |
+
djsegal/julia_observer ruby
|
| 2312 |
+
Techern/Netherrack rust
|
| 2313 |
+
SevereOverfl0w/Unicorn-UI-Kit typescript
|
| 2314 |
+
libfirm/libfirm c
|
| 2315 |
+
danstis/Plex-Sync go
|
| 2316 |
+
DevOpsDistilled/OpERP java
|
| 2317 |
+
getninjas/gaiden javascript
|
| 2318 |
+
cs278/bank-modulus php
|
| 2319 |
+
kevinconway/rpmvenv python
|
| 2320 |
+
cyber-dojo/web ruby
|
| 2321 |
+
gadomski/sdc-rs rust
|
| 2322 |
+
ABAPlan/abaplan-core typescript
|
| 2323 |
+
learnclang/1-helloworld c
|
| 2324 |
+
Roadagain/Chess go
|
| 2325 |
+
Axway/ats-framework java
|
| 2326 |
+
wooken/mptlog javascript
|
| 2327 |
+
hannesvdvreken/guzzle-debugbar php
|
| 2328 |
+
maxzheng/workspace-tools python
|
| 2329 |
+
dplarson/gitlabhq ruby
|
| 2330 |
+
emk/rust-cld2 rust
|
| 2331 |
+
crossroads-education/eta-cli typescript
|
| 2332 |
+
Phyllostachys/junkcode c
|
| 2333 |
+
kl4w/terraform go
|
| 2334 |
+
cs3250-team6/msubanner java
|
| 2335 |
+
darthjee/frog javascript
|
| 2336 |
+
mkusher/padawan.php php
|
| 2337 |
+
thsnr/gygax python
|
| 2338 |
+
gavinlaking/troo ruby
|
| 2339 |
+
klutzy/suruga rust
|
| 2340 |
+
FarmBot/farmbot-web-app typescript
|
| 2341 |
+
ZoranPandovski/al-go-rithms c
|
| 2342 |
+
pivotal-cf-experimental/vizzini go
|
| 2343 |
+
bcgit/bc-java java
|
| 2344 |
+
vikpe/react-webpack-typescript-starter javascript
|
| 2345 |
+
Hackathonners/swap php
|
| 2346 |
+
theislab/dca python
|
| 2347 |
+
hopshadoop/chef-glassfish ruby
|
| 2348 |
+
nicokoch/gl-rs rust
|
| 2349 |
+
artsy/reaction typescript
|
| 2350 |
+
en90/pkg c
|
| 2351 |
+
kingsamchen/Eureka go
|
| 2352 |
+
pagarme/pagarme-java java
|
| 2353 |
+
razh/osc-dev javascript
|
| 2354 |
+
nicklaw5/twitch-api-php php
|
| 2355 |
+
iamwucheng/xml_models2 python
|
| 2356 |
+
bobbytables/gemfiler ruby
|
| 2357 |
+
klingtnet/rosc rust
|
| 2358 |
+
jvilk/doppio-demo typescript
|
| 2359 |
+
apple/swift-llvm c
|
| 2360 |
+
weaveworks/flux go
|
| 2361 |
+
gradle/gradle java
|
| 2362 |
+
gaearon/normalizr javascript
|
| 2363 |
+
fniephaus/SimpleDropboxUploader php
|
| 2364 |
+
divio/django-cas python
|
| 2365 |
+
isadaqah/irc-hipchat-integration ruby
|
| 2366 |
+
mvdnes/rboy rust
|
| 2367 |
+
yinxin630/fiora typescript
|
| 2368 |
+
tiennou/objective-git c
|
| 2369 |
+
li-ang/influxdb go
|
| 2370 |
+
gogradle/gogradle java
|
| 2371 |
+
Sleavely/OTWorlds javascript
|
| 2372 |
+
hugomelo/ralsp php
|
| 2373 |
+
johnpaulett/txHL7 python
|
| 2374 |
+
amateurhuman/active_esp ruby
|
| 2375 |
+
jcolag/CommonCalendar rust
|
| 2376 |
+
shamblesides/rpnow typescript
|
| 2377 |
+
happyponyland/smallrl c
|
| 2378 |
+
krasun/ProjectEulerSolutions go
|
| 2379 |
+
janosgyerik/java-tools java
|
| 2380 |
+
jeremija/peer-calls javascript
|
| 2381 |
+
srayner/zend-db php
|
| 2382 |
+
twig/django-taggit python
|
| 2383 |
+
cegeka/puppet-rabbitmq ruby
|
| 2384 |
+
tdaede/mpv-rice rust
|
| 2385 |
+
mauve/vscode-terraform typescript
|
| 2386 |
+
AltSysrq/tgl c
|
| 2387 |
+
rafaeljribeiro/geocoder go
|
| 2388 |
+
pushtechnology/diffusion-transform java
|
| 2389 |
+
simplyianm/classtime javascript
|
| 2390 |
+
NZRS/dnscheck php
|
| 2391 |
+
gasman/Willow python
|
| 2392 |
+
SpringMT/worker_scoreboard ruby
|
| 2393 |
+
iKevinY/ghoti.rs rust
|
| 2394 |
+
imribarr-compit/ng2-bootstrap typescript
|
| 2395 |
+
blinkboxbooks/blinkbox-network.objc c
|
| 2396 |
+
antontsv/twilio go
|
| 2397 |
+
Bananeweizen/cgeo java
|
| 2398 |
+
zillding/hangouts javascript
|
| 2399 |
+
ashfordl/blog php
|
| 2400 |
+
smarkets/statprof python
|
| 2401 |
+
ArchimedesPi/printit ruby
|
| 2402 |
+
solson/rin rust
|
| 2403 |
+
Dynalon/redux-pattern-with-rx typescript
|
| 2404 |
+
spewspew/TAOCP c
|
| 2405 |
+
messagebird/go-rest-api go
|
| 2406 |
+
kiorpesc/CS1622-Project3 java
|
| 2407 |
+
ExchangeCore/Concrete5-CKEditor javascript
|
| 2408 |
+
persand/sfdaycgn2011 php
|
| 2409 |
+
360youlun/cmsplugin-bootstrap-carousel python
|
| 2410 |
+
NUBIC/dagnabit ruby
|
| 2411 |
+
andars/rust-calculator rust
|
| 2412 |
+
to2mbn/skinview3d typescript
|
| 2413 |
+
anton-simakov/ASFeedly c
|
| 2414 |
+
holygeek/translator go
|
| 2415 |
+
itszootime/geojson-java java
|
| 2416 |
+
google/site-kit-wp javascript
|
| 2417 |
+
osuripple/ripple php
|
| 2418 |
+
ceball/param python
|
| 2419 |
+
biow0lf/evemonk ruby
|
| 2420 |
+
erik/sketches rust
|
| 2421 |
+
concord-consortium/building-models typescript
|
| 2422 |
+
blueseaguo/ios-library c
|
| 2423 |
+
arapov/pile go
|
| 2424 |
+
ratan12/Atarashii java
|
| 2425 |
+
martindale/melody javascript
|
| 2426 |
+
ffsantos92/bens-penhorados php
|
| 2427 |
+
associazionepoltronieri/blender-ap python
|
| 2428 |
+
paulmolin42/mjmr ruby
|
| 2429 |
+
mario-kr/imag rust
|
| 2430 |
+
Rebilly/ReDoc typescript
|
| 2431 |
+
cinnamoncoin/Feathercoin c
|
| 2432 |
+
sosedoff/howdy go
|
| 2433 |
+
SteveWinfield/IDK-Server-Java java
|
| 2434 |
+
ardeshirj/atom javascript
|
| 2435 |
+
palmtreephp/canonical-url-bundle php
|
| 2436 |
+
wikilinks/sift python
|
| 2437 |
+
rwehresmann/stack_helper ruby
|
| 2438 |
+
aochagavia/Serve rust
|
| 2439 |
+
atomiks/tippyjs typescript
|
| 2440 |
+
candy7393/VTK c
|
| 2441 |
+
scipipe/scipipe go
|
| 2442 |
+
Lydwen/CentralTrafficLightManagement-SmartCity java
|
| 2443 |
+
tejasbubane/xecmascript javascript
|
| 2444 |
+
richardhinkamp/giveandgo-website php
|
| 2445 |
+
DesertBot/DesertBot python
|
| 2446 |
+
benjaminhyw/rails-online-shop ruby
|
| 2447 |
+
sfackler/rust-postgres rust
|
| 2448 |
+
jonaskello/tslint-immutable typescript
|
| 2449 |
+
appsembler/edx-app-ios c
|
| 2450 |
+
jmalonzo/project-euler-solutions go
|
| 2451 |
+
rhuss/sundrio java
|
| 2452 |
+
lucy-marko/centrepoint javascript
|
| 2453 |
+
Lab2Comp4711/comp4711-lab02 php
|
| 2454 |
+
4degrees/segue python
|
| 2455 |
+
AnimaGUS-minerva/www ruby
|
| 2456 |
+
Shraddha512/servo rust
|
| 2457 |
+
sobstel/golazon typescript
|
| 2458 |
+
Furkanzmc/StateManager c
|
| 2459 |
+
ava-labs/avalanchego go
|
| 2460 |
+
RBMHTechnology/apidoc-server java
|
| 2461 |
+
pshendry/DevQuest javascript
|
| 2462 |
+
aaaaadrien/marjo21 php
|
| 2463 |
+
holdenweb/nbtools python
|
| 2464 |
+
nhocki/version_gemfile ruby
|
| 2465 |
+
leonardinius/rust-guide rust
|
| 2466 |
+
wishtack/ng-steroids typescript
|
| 2467 |
+
charsyam/hiredis c
|
| 2468 |
+
benjojo/aprs.go go
|
| 2469 |
+
JEEventStore/JEECQRS java
|
| 2470 |
+
Fluidbyte/ColtJS javascript
|
| 2471 |
+
donatj/CorpusPHP php
|
| 2472 |
+
openhealthcare/opal-referral python
|
| 2473 |
+
listia/con_air ruby
|
| 2474 |
+
Drakulix/zwreec rust
|
| 2475 |
+
aaldaber/owid-grapher typescript
|
| 2476 |
+
malensek/3RVX c
|
| 2477 |
+
hashicorp/terraform go
|
| 2478 |
+
tbrooks8/Precipice java
|
| 2479 |
+
digabi/math-editor javascript
|
| 2480 |
+
meanbee/articles-to-podcast php
|
| 2481 |
+
BansheeMediaPlayer/bockbuild python
|
| 2482 |
+
zhoutong/interapp ruby
|
| 2483 |
+
mcpherrinm/baudot rust
|
| 2484 |
+
kesarion/angular2-air-datepicker typescript
|
| 2485 |
+
fsavje/scclust c
|
| 2486 |
+
bahlo/godisc go
|
| 2487 |
+
vivo-project/VIVO java
|
| 2488 |
+
visionmedia/node-progress javascript
|
| 2489 |
+
alberanid/bookmarks php
|
| 2490 |
+
elacuesta/scrapy python
|
| 2491 |
+
davidleach/onebody ruby
|
| 2492 |
+
bvinc83/lz4-rs rust
|
| 2493 |
+
CAAL/CAAL typescript
|
| 2494 |
+
lees0414/EUproject c
|
| 2495 |
+
jpfuentes2/go-env go
|
| 2496 |
+
pmcs/nassau java
|
| 2497 |
+
jsonmvc/jsonmvc javascript
|
| 2498 |
+
pH7Software/pH7-Social-Dating-CMS php
|
| 2499 |
+
mbr/flask-appconfig python
|
| 2500 |
+
tomekw/yaml_converters ruby
|
| 2501 |
+
0xd4d/iced rust
|
| 2502 |
+
fyoudine/three.js typescript
|
| 2503 |
+
whoshuu/cpr c
|
| 2504 |
+
opentable/sous go
|
| 2505 |
+
johanbrook/watchme java
|
| 2506 |
+
msanatan/GitHubProjects javascript
|
| 2507 |
+
sakara/PazWork php
|
| 2508 |
+
ninjawil/weather-station python
|
| 2509 |
+
taskrabbit/makara ruby
|
| 2510 |
+
Hoverbear/rust-rosetta rust
|
| 2511 |
+
Jameskmonger/isaac-crypto typescript
|
| 2512 |
+
metora/MesaGLSLCompiler c
|
| 2513 |
+
carlosbrando/lunchy go
|
| 2514 |
+
jedrz/slisp java
|
| 2515 |
+
mthmulders/lin2go javascript
|
| 2516 |
+
futurable/backend php
|
| 2517 |
+
sunlightlabs/thezombies python
|
| 2518 |
+
kaosf/apns-s3 ruby
|
| 2519 |
+
mehcode/config-rs rust
|
| 2520 |
+
DorianGrey/ng2-webpack-template typescript
|
| 2521 |
+
google/skia c
|
| 2522 |
+
cpmech/gosl go
|
| 2523 |
+
monkey2000/Wikidata-Toolkit java
|
| 2524 |
+
mozilla/openbadges-discovery javascript
|
| 2525 |
+
Palethorn/Yeah php
|
| 2526 |
+
PanDAWMS/panda-bigmon-atlas python
|
| 2527 |
+
nguyenquangminh0711/ruby-sensor ruby
|
| 2528 |
+
petertseng/exercism-rust rust
|
| 2529 |
+
UITools/saleor typescript
|
| 2530 |
+
danluu/setjmp-longjmp-ucontext-snippets c
|
| 2531 |
+
jroimartin/tgbot go
|
| 2532 |
+
GoogleCloudPlatform/appengine-gcs-client java
|
| 2533 |
+
taylorzane/noflo-ui javascript
|
| 2534 |
+
FreshRSS/update.freshrss.org php
|
| 2535 |
+
varunarya10/oslo.i18n python
|
| 2536 |
+
luwei2012/BlurryModalSegue ruby
|
| 2537 |
+
theemathas/binary_turk rust
|
| 2538 |
+
syuilo/Misskey typescript
|
| 2539 |
+
delwink/libpatts c
|
| 2540 |
+
cixtor/slackapi go
|
| 2541 |
+
njmube/OpERP java
|
| 2542 |
+
antoinechalifour/Reddix javascript
|
| 2543 |
+
jonnybarnes/jonnybarnes.uk php
|
| 2544 |
+
jefrailey/basic-scraper python
|
| 2545 |
+
ywzw2013/CKRefreshControl ruby
|
| 2546 |
+
Razaekel/noise-rs rust
|
| 2547 |
+
artfuldev/tictactoe-ai typescript
|
| 2548 |
+
cinode/cpptestapp c
|
| 2549 |
+
shurcooL/go go
|
| 2550 |
+
SEARCH-NCJIS/nibrs java
|
| 2551 |
+
disquisition/serve javascript
|
| 2552 |
+
laravel-zero/framework php
|
| 2553 |
+
udibr/fuel python
|
| 2554 |
+
hightower/cash_flow_analysis ruby
|
| 2555 |
+
kinghajj/minimax-rs rust
|
| 2556 |
+
ryohey/signal typescript
|
| 2557 |
+
vortexntnu/rov-control c
|
| 2558 |
+
concourse/concourse go
|
| 2559 |
+
martijn-heil/KingdomEssentials java
|
| 2560 |
+
ryym/babel-rewire-wrapper javascript
|
| 2561 |
+
EugenZi/oro-platform-app php
|
| 2562 |
+
haridsv/fabric python
|
| 2563 |
+
guerrero/homebrew-cask ruby
|
| 2564 |
+
alexwlchan/safari.rs rust
|
| 2565 |
+
online-poker/poker-html-client typescript
|
| 2566 |
+
giuliopaci/acopost c
|
| 2567 |
+
abustany/go go
|
| 2568 |
+
yuvraaz/android-push-notification java
|
| 2569 |
+
BAJ-/robot-breakout javascript
|
| 2570 |
+
sebastiaanluca/laravel-modules php
|
| 2571 |
+
gadventures/gapipy python
|
| 2572 |
+
bimmlerd/homebrew-versions ruby
|
| 2573 |
+
imazen/imageflow rust
|
| 2574 |
+
nmarsden/make-em-green typescript
|
| 2575 |
+
hlnd/nrf51-simple-radio c
|
| 2576 |
+
npe9/noahevans-go9 go
|
| 2577 |
+
sebhoss/annotated-contracts java
|
| 2578 |
+
bustlelabs/content-kit-editor javascript
|
| 2579 |
+
jeroendelau/slim-basic-auth php
|
| 2580 |
+
sk-/python2.7-type-annotator python
|
| 2581 |
+
unboxed/hrcomply-demo ruby
|
| 2582 |
+
rhysd/git-brws rust
|
| 2583 |
+
emc-mongoose/console typescript
|
| 2584 |
+
prajnashi/ffmpeg c
|
| 2585 |
+
callpraths/gorobdd go
|
| 2586 |
+
detectiveframework/detective java
|
| 2587 |
+
znetstar/broadway javascript
|
| 2588 |
+
plattinum09/CMS_SENTRY php
|
| 2589 |
+
mythmon/kitsune python
|
| 2590 |
+
zwaldowski/BlocksKit ruby
|
| 2591 |
+
sevagh/pqrs rust
|
| 2592 |
+
wikiwi/react-jss-theme typescript
|
| 2593 |
+
fgouget/spice c
|
| 2594 |
+
ggoblin/goblin go
|
| 2595 |
+
PDXFinder/pdxfinder java
|
| 2596 |
+
freezy-sk/bootlint javascript
|
| 2597 |
+
google/site-kit-wp php
|
| 2598 |
+
j4mie/django-activelink python
|
| 2599 |
+
bryckbost/memdash ruby
|
| 2600 |
+
willsalz/actors rust
|
| 2601 |
+
chipster/chipster-web typescript
|
| 2602 |
+
kopasiak/gt c
|
| 2603 |
+
cloudfoundry-incubator/cf-test-helpers go
|
| 2604 |
+
bf8086/alluxio java
|
| 2605 |
+
zarazi/movies-listie javascript
|
| 2606 |
+
bauhausphp/package-container php
|
| 2607 |
+
jwg4/flask-autodoc python
|
| 2608 |
+
mygulamali/compare-sunrise-gems ruby
|
| 2609 |
+
rootulp/exercism rust
|
| 2610 |
+
CodeForCharlotte/cmpd-holiday-gift-backend typescript
|
| 2611 |
+
cs2103aug2014-w10-1c/main c
|
| 2612 |
+
RobinUS2/xyzfs go
|
| 2613 |
+
MovingBlocks/Terasology java
|
| 2614 |
+
rhysd/node-client javascript
|
| 2615 |
+
leocavalcante/siler php
|
| 2616 |
+
EmadMokhtar/halaqat python
|
| 2617 |
+
Erol/specter ruby
|
| 2618 |
+
muktakosh/unicorn rust
|
| 2619 |
+
FoalTS/foal typescript
|
| 2620 |
+
zhangzhehust/htcondor c
|
| 2621 |
+
robdimsdale/wl go
|
| 2622 |
+
stickfigure/gstrap-gae java
|
| 2623 |
+
camayak/contentapi-medium-node javascript
|
| 2624 |
+
timegridio/timegrid php
|
| 2625 |
+
EDUlib/edx-platform python
|
| 2626 |
+
bengler/tootsie ruby
|
| 2627 |
+
phaazon/ion rust
|
| 2628 |
+
MyMICDS/MyMICDS-v2-Angular typescript
|
| 2629 |
+
JohnReid/myrrh c
|
| 2630 |
+
DanShu93/trainspotter go
|
| 2631 |
+
HubSpot/jackson-datatype-protobuf java
|
| 2632 |
+
pedro-lucas/node-pdfbox javascript
|
| 2633 |
+
dannyvankooten/vat.php php
|
| 2634 |
+
Graylog2/graylog-ansible-role python
|
| 2635 |
+
peter-murach/tty ruby
|
| 2636 |
+
erickt/rust rust
|
| 2637 |
+
pratheekhegde/a2-redux typescript
|
| 2638 |
+
CodethinkLabs/ofc c
|
| 2639 |
+
peteretelej/saf go
|
| 2640 |
+
GerritCodeReview/gerrit java
|
| 2641 |
+
ise-ethereum/on-chain-chess javascript
|
| 2642 |
+
wpsvse/wpackagist php
|
| 2643 |
+
armab/st2contrib python
|
| 2644 |
+
ReadyResponder/ReadyResponder ruby
|
| 2645 |
+
mayah/rust-puyoai rust
|
| 2646 |
+
Urigo/angular-meteor typescript
|
| 2647 |
+
mnaza/themis c
|
| 2648 |
+
cloudfoundry-incubator/guardian-release go
|
| 2649 |
+
weisJ/darklaf java
|
| 2650 |
+
pirelenito/unbubble javascript
|
| 2651 |
+
nailsapp/module-email php
|
| 2652 |
+
KrzysztofSendor/dactyl python
|
| 2653 |
+
MortadaAK/ProMotion ruby
|
| 2654 |
+
gluon-lang/try_gluon rust
|
| 2655 |
+
srackham/rimu typescript
|
| 2656 |
+
hujiajie/pa-chromium c
|
| 2657 |
+
tedsuo/ifrit go
|
| 2658 |
+
scijava/scijava-jupyter-kernel java
|
| 2659 |
+
gish/friskis-slack-booking javascript
|
| 2660 |
+
bound1ess/adviser php
|
| 2661 |
+
nurav/balrog python
|
| 2662 |
+
nibua-r/testext ruby
|
| 2663 |
+
PhilipDaniels/qork rust
|
| 2664 |
+
Jigsaw-Code/outline-server typescript
|
| 2665 |
+
pavelkryukov/putty-aes-ni c
|
| 2666 |
+
pekim/gotk3 go
|
| 2667 |
+
ferreusveritas/Growing-Trees java
|
| 2668 |
+
folio-org/stripes-core javascript
|
| 2669 |
+
xiidea/EasyAuditBundle php
|
| 2670 |
+
Pierre-Sassoulas/django-survey python
|
| 2671 |
+
thii/homebrew-cask ruby
|
| 2672 |
+
Acizza/anitrack rust
|
| 2673 |
+
bluebirrrrd/nau-timetable typescript
|
| 2674 |
+
ecalvovi/AliRoot c
|
| 2675 |
+
mortdeus/goblin go
|
| 2676 |
+
liujed/polyglot-eclipse java
|
| 2677 |
+
facebook/draft-js javascript
|
| 2678 |
+
Luceos/core php
|
| 2679 |
+
microsoft/dpu-utils python
|
| 2680 |
+
eonum/drg-search ruby
|
| 2681 |
+
nvzqz/static-assertions-rs rust
|
| 2682 |
+
Ecafracs/flatthirteen typescript
|
| 2683 |
+
ppy/osu-framework c
|
| 2684 |
+
Urethramancer/lbapi go
|
| 2685 |
+
davidsusu/tree-printer java
|
| 2686 |
+
nissoh/core javascript
|
| 2687 |
+
billmn/gorilla php
|
| 2688 |
+
PersonalGenomesOrg/open-humans python
|
| 2689 |
+
ledermann/docker-rails ruby
|
| 2690 |
+
xiph/rav1e rust
|
| 2691 |
+
gamliela/starter-react-mobx-css-modules typescript
|
| 2692 |
+
skarnet/s6-linux-init c
|
| 2693 |
+
qasim/what-class-is-this go
|
| 2694 |
+
aNNiMON/JECP java
|
| 2695 |
+
ONSdigital/florence javascript
|
| 2696 |
+
alfaproject/omnipay-skrill php
|
| 2697 |
+
vayan/external-video python
|
| 2698 |
+
rehanone/puppet-git ruby
|
| 2699 |
+
tempbottle/rust-peg rust
|
| 2700 |
+
nekodex/osu-web typescript
|
| 2701 |
+
crontab/libobjc2 c
|
| 2702 |
+
zombiezen/go-log go
|
| 2703 |
+
Suseika/collections-utils java
|
| 2704 |
+
MichaelKohler/mozilla-watcher javascript
|
| 2705 |
+
dafik/CodeGen php
|
| 2706 |
+
simonjbeaumont/xcp-rrdd python
|
| 2707 |
+
braintree/braintree-web-drop-in ruby
|
| 2708 |
+
GuzTech/tray_rust rust
|
| 2709 |
+
kawamon/hue typescript
|
| 2710 |
+
jpoirier/picoc c
|
| 2711 |
+
cloudfoundry-incubator/nsync go
|
| 2712 |
+
robertoschwald/cas java
|
| 2713 |
+
formidable-coffee/masterfully javascript
|
| 2714 |
+
dweidner/laravel-goutte php
|
| 2715 |
+
lozadaOmr/ansible-admin python
|
| 2716 |
+
pinzolo/redmine_persist_wfmt ruby
|
| 2717 |
+
adeschamps/lcm rust
|
| 2718 |
+
sheldarr/Votenger typescript
|
| 2719 |
+
ryepdx/keyphrase c
|
| 2720 |
+
monzo/typhon go
|
| 2721 |
+
aleph-zero/presto java
|
| 2722 |
+
npmcomponent/ramitos-midway javascript
|
| 2723 |
+
nordsoftware/lumen-core php
|
| 2724 |
+
ulikoehler/UliEngineering python
|
| 2725 |
+
dtan4/organicat ruby
|
| 2726 |
+
Zamicol/Challenge rust
|
| 2727 |
+
Flatline4/Flatline4 typescript
|
| 2728 |
+
echonest/libechonest c
|
| 2729 |
+
PufferPanel/PufferPanel go
|
| 2730 |
+
microprofile/microprofile-conference java
|
| 2731 |
+
jamen/craze javascript
|
| 2732 |
+
facile-it/paraunit php
|
| 2733 |
+
kxxoling/fabric python
|
| 2734 |
+
zurb/inky-rb ruby
|
| 2735 |
+
musoke/inspirer rust
|
| 2736 |
+
dragma/styled-bootstrap-grid typescript
|
| 2737 |
+
AAChartModel/AAChartKit c
|
| 2738 |
+
rancher/rancher go
|
| 2739 |
+
InnovateUKGitHub/innovation-funding-service java
|
| 2740 |
+
etopian/codebox-package-menubar javascript
|
| 2741 |
+
Radvance/Radvance php
|
| 2742 |
+
EmilStenstrom/nephele python
|
| 2743 |
+
sandro/ephemeral_response ruby
|
| 2744 |
+
spacejam/sled rust
|
| 2745 |
+
molstar/molstar typescript
|
| 2746 |
+
qtmediahub/sasquatch c
|
| 2747 |
+
firestudios/qor-example go
|
| 2748 |
+
ryanbrainard/richsobjects java
|
| 2749 |
+
SentinelsOfMagic/SentinelsOfMagic javascript
|
| 2750 |
+
unl/UNL_UCBCN_System php
|
| 2751 |
+
chingc/DJRivals python
|
| 2752 |
+
joeyates/ruby-sun-times ruby
|
| 2753 |
+
terminalcloud/libnetfilter_queue rust
|
| 2754 |
+
larsvanbraam/vue-transition-component typescript
|
| 2755 |
+
isbadawi/badavi c
|
| 2756 |
+
ianopolous/go-ipfs go
|
| 2757 |
+
scottfrederick/spring-boot java
|
| 2758 |
+
burningtomatoes/Bitsmashers javascript
|
| 2759 |
+
dkgndec/DrupalConsole php
|
| 2760 |
+
docsbox/docsbox python
|
| 2761 |
+
Teino1978-Corp/Teino1978-Corp-kaminari ruby
|
| 2762 |
+
fanderzon/rocket-api rust
|
| 2763 |
+
rtsjs/rts typescript
|
| 2764 |
+
darkbuck/Halide c
|
| 2765 |
+
go-gl/gl go
|
| 2766 |
+
gabrielavara/music-player java
|
| 2767 |
+
weepower/wee-core javascript
|
| 2768 |
+
dxw/php-missing php
|
| 2769 |
+
uva-financial-engineering/cifer-tournament python
|
| 2770 |
+
moneyadviceservice/mas-feedback ruby
|
| 2771 |
+
crumblingstatue/rust-libnotify-sys rust
|
| 2772 |
+
nrlquaker/nfov typescript
|
| 2773 |
+
qsctr/vex-4194b-2016 c
|
| 2774 |
+
spacedock-io/registry go
|
| 2775 |
+
Steveice10/MCProtocolLib java
|
| 2776 |
+
CVBDL/EagleEye-App javascript
|
| 2777 |
+
tmingos/sassy-roots php
|
| 2778 |
+
OSGConnect/freesurfer_workflow python
|
| 2779 |
+
mirego/hanzo ruby
|
| 2780 |
+
Logicalshift/tame-tree rust
|
| 2781 |
+
bradyholt/aspnet-core-react-template typescript
|
| 2782 |
+
willpatterson/HOPSTACK c
|
| 2783 |
+
bernardolins/clustereasy go
|
| 2784 |
+
fhoeben/hsac-fitnesse-fixtures java
|
| 2785 |
+
manifoldco/torus-cli javascript
|
| 2786 |
+
DNepovim/kraj-praha php
|
| 2787 |
+
aaronkurtz/bricky python
|
| 2788 |
+
ifosch/skyed ruby
|
| 2789 |
+
aptos-labs/aptos-core rust
|
| 2790 |
+
shiftkey/desktop typescript
|
| 2791 |
+
IFTTT/JazzHands c
|
| 2792 |
+
resourced/resourced-master go
|
| 2793 |
+
mrdon/AMPS java
|
| 2794 |
+
dkrathi457/app javascript
|
| 2795 |
+
hernantas/MangaReader php
|
| 2796 |
+
worldforge/libwfut python
|
| 2797 |
+
k0nserv/Humus ruby
|
| 2798 |
+
jzhu98/telescope rust
|
| 2799 |
+
paypac/node-concierge typescript
|
| 2800 |
+
adobe-rnd/cordova-osx c
|
| 2801 |
+
ephemeralsnow/packer go
|
| 2802 |
+
mkarneim/luamod java
|
| 2803 |
+
sigurdga/barteby javascript
|
| 2804 |
+
kjhoerr/august-offensive php
|
| 2805 |
+
churchlab/millstone python
|
| 2806 |
+
matiaskorhonen/libpixel-ruby ruby
|
| 2807 |
+
jonas-schievink/sneeze rust
|
| 2808 |
+
tjoskar/ng2-lazyload-image typescript
|
| 2809 |
+
netzimme/mbed-os c
|
| 2810 |
+
myodc/go-micro go
|
| 2811 |
+
pzn/clipapp java
|
| 2812 |
+
mozilla/webmaker-app-cordova javascript
|
| 2813 |
+
GrottoPress/jentil php
|
| 2814 |
+
asteroide/immo_spider python
|
| 2815 |
+
crepe/creperie ruby
|
| 2816 |
+
snewt/bnf rust
|
| 2817 |
+
Dkendal/battle_snake typescript
|
| 2818 |
+
leovegetium/Trabalho-P c
|
| 2819 |
+
rancher/k3s go
|
| 2820 |
+
holandajunior/workaday java
|
| 2821 |
+
squarewave/addons-frontend javascript
|
| 2822 |
+
anqh/anqh php
|
| 2823 |
+
odoo-chile/l10n_cl_account_vat_ledger python
|
| 2824 |
+
ValiMail/griddler ruby
|
| 2825 |
+
gchp/termbox-sys rust
|
| 2826 |
+
polyaxon/polyaxon typescript
|
| 2827 |
+
k0gaMSX/kcc c
|
| 2828 |
+
lstolyarov/terraform go
|
| 2829 |
+
Syncleus/aparapi java
|
| 2830 |
+
rowanoulton/prefix-matches javascript
|
| 2831 |
+
LaurentEsc/Laravel-Subdomain-Localization php
|
| 2832 |
+
jeenalee/sklearn_pmml python
|
| 2833 |
+
mahimahi42/microblogger ruby
|
| 2834 |
+
minijackson/INF-4301A rust
|
| 2835 |
+
robak86/neography typescript
|
| 2836 |
+
cxd4/trig c
|
| 2837 |
+
ccirello/gochatbot go
|
| 2838 |
+
Arabidopsis-Information-Portal/intermine java
|
| 2839 |
+
escaip/smart_bike javascript
|
| 2840 |
+
symfony-cmf/Resource php
|
| 2841 |
+
attenzione/SublimeLinter-scss-lint python
|
| 2842 |
+
syncrou/manageiq ruby
|
| 2843 |
+
dwrensha/capnproto-rust rust
|
| 2844 |
+
arthot/calque typescript
|
| 2845 |
+
filom/ASN1Decoder c
|
| 2846 |
+
otoolep/raft go
|
| 2847 |
+
apache/jmeter java
|
| 2848 |
+
kiboit/phast javascript
|
| 2849 |
+
vanderlee/PHPSwaggerGen php
|
| 2850 |
+
pudo/spendb python
|
| 2851 |
+
dtan4/c2y ruby
|
| 2852 |
+
qdot/systray-rs rust
|
| 2853 |
+
tsvetie/nativescript-cli typescript
|
| 2854 |
+
kazmasaurus/CRToast c
|
| 2855 |
+
wrapp/wrapplog go
|
| 2856 |
+
malucs-developer/Android-Simulator java
|
| 2857 |
+
bassettmb/slack-bot-dev javascript
|
| 2858 |
+
imabug/raddb php
|
| 2859 |
+
hackebrot/cibopath python
|
| 2860 |
+
ruby/spec ruby
|
| 2861 |
+
dinfuehr/rust rust
|
| 2862 |
+
SaschaNaz/TypeScript typescript
|
| 2863 |
+
greenplum-db/gpdb c
|
| 2864 |
+
v4lproik/no-name go
|
| 2865 |
+
rwinch/spring-security java
|
| 2866 |
+
mzrimsek/resume_site javascript
|
| 2867 |
+
alexweissman/UserFrosting php
|
| 2868 |
+
mokieyue/mopidy python
|
| 2869 |
+
chronogolf/lightspeed_restaurant ruby
|
| 2870 |
+
ajroetker/rustc-serialize rust
|
| 2871 |
+
gund/ng-http-interceptor typescript
|
| 2872 |
+
BGWoodward/FishDetector c
|
| 2873 |
+
melange-app/melange go
|
| 2874 |
+
Team694/joebot java
|
| 2875 |
+
CartoDB/Windshaft-cartodb javascript
|
| 2876 |
+
biplobice/concrete5 php
|
| 2877 |
+
textbook/flask-forecaster python
|
| 2878 |
+
heavenstudio/spree_pag_seguro ruby
|
| 2879 |
+
keeperofdakeys/asn1-rs rust
|
| 2880 |
+
BitGo/BitGoJS typescript
|
| 2881 |
+
bespider/STTweetLabel c
|
| 2882 |
+
asobti/kube-monkey go
|
| 2883 |
+
VinnyQ/blueflood java
|
| 2884 |
+
benefitcloud/ember-uploader javascript
|
| 2885 |
+
wesley1001/Kurogo-Mobile-Web php
|
| 2886 |
+
ncareol/spatialdb python
|
| 2887 |
+
giedomak/table_cloth ruby
|
| 2888 |
+
dati91/servo rust
|
| 2889 |
+
t123yh/simple-sandbox typescript
|
| 2890 |
+
cxa/MenuItemKit c
|
| 2891 |
+
liam-middlebrook/csh-plug go
|
| 2892 |
+
TehSAUCE/imagej java
|
| 2893 |
+
MacPaw/eslint-config-webservices javascript
|
| 2894 |
+
ponkrit/developer-test php
|
| 2895 |
+
fna/owning-a-home-api python
|
| 2896 |
+
lukeredpath/xcodesnippets ruby
|
| 2897 |
+
stepancheg/rust-ide-rust rust
|
| 2898 |
+
trustpilot/skift typescript
|
| 2899 |
+
UrbanCompass/RMGallery c
|
| 2900 |
+
scode/saltybox go
|
| 2901 |
+
sake/bouncycastle-java java
|
| 2902 |
+
intervention-engine/frontend javascript
|
| 2903 |
+
siad007/json-schema php
|
| 2904 |
+
gitpython-developers/GitPython python
|
| 2905 |
+
solidusio-contrib/solidus_easypost ruby
|
| 2906 |
+
bolinfest/serde-jsonrc rust
|
| 2907 |
+
influxdb/influxdb typescript
|
| 2908 |
+
anagromataf/Fountain c
|
| 2909 |
+
Dirbaio/btcd go
|
| 2910 |
+
outofcoffee/testcontainers-java java
|
| 2911 |
+
TripleSpeeder/StandingOrderDapp javascript
|
| 2912 |
+
jimmythongtran/recipe_tracker php
|
| 2913 |
+
spyder-ide/qtawesome python
|
| 2914 |
+
samvera/hyrax ruby
|
| 2915 |
+
habitat-sh/habitat rust
|
| 2916 |
+
j-f1/forked-desktop typescript
|
| 2917 |
+
CollegeBart/bart-sdl-engine-e16 c
|
| 2918 |
+
StroblIndustries/codeutilsShared go
|
| 2919 |
+
inbloom/secure-data-service java
|
| 2920 |
+
tidepool-org/blip javascript
|
| 2921 |
+
burnflare/CrowdBuy php
|
| 2922 |
+
ravel-net/ravel python
|
| 2923 |
+
postmodern/kramdown-man ruby
|
| 2924 |
+
oxcable/oxcable rust
|
| 2925 |
+
zentol/flink typescript
|
| 2926 |
+
Gluttton/PslRK c
|
| 2927 |
+
elwinar/adeptus go
|
| 2928 |
+
kaltsimon/Chasing-Pictures-front-end java
|
| 2929 |
+
bitclaw/apptmnt javascript
|
| 2930 |
+
jeffersonmartin/code-examples php
|
| 2931 |
+
humangeo/preflyt python
|
| 2932 |
+
julik/mal ruby
|
| 2933 |
+
mneumann/expression-rs rust
|
| 2934 |
+
thehyve/glowing-bear typescript
|
| 2935 |
+
robertmaynard/Sandbox c
|
| 2936 |
+
mrekucci/euler go
|
| 2937 |
+
HubSpot/jinjava java
|
| 2938 |
+
pd4d10/tiza javascript
|
| 2939 |
+
listabierta/census-ahoraencomun php
|
| 2940 |
+
ucb-sts/sts python
|
| 2941 |
+
backus/guard-rubocop ruby
|
| 2942 |
+
ggez/ggez rust
|
| 2943 |
+
dl988/quedro typescript
|
| 2944 |
+
mk12/morse c
|
| 2945 |
+
didip/tollbooth go
|
| 2946 |
+
smalecki/motech java
|
| 2947 |
+
dtekcth/dfotose javascript
|
| 2948 |
+
mdlayher/wavepipe php
|
| 2949 |
+
jlaunonen/kirppu python
|
| 2950 |
+
dhensby/silverstripe-cms ruby
|
| 2951 |
+
exe-dealer/rust-md5 rust
|
| 2952 |
+
goloveychuk/tsruntime typescript
|
| 2953 |
+
rubenk/burp c
|
| 2954 |
+
opencontainers/runc go
|
| 2955 |
+
kits-ab/gakusei java
|
| 2956 |
+
virtool/virtool javascript
|
| 2957 |
+
phalcon/zephir php
|
| 2958 |
+
matthiask/towel python
|
| 2959 |
+
slate-studio/openapi-rails ruby
|
| 2960 |
+
lowRISC/opentitan rust
|
| 2961 |
+
dsebastien/DefinitelyTyped typescript
|
| 2962 |
+
HalCanary/skia-hc c
|
| 2963 |
+
mongrelion/gapp go
|
| 2964 |
+
openmhealth/sample-data-generator java
|
| 2965 |
+
amos-ws16/amos-ws16-arrowjs-server javascript
|
| 2966 |
+
edvinaskrucas/counter-laravel php
|
| 2967 |
+
jmiserez/sts python
|
| 2968 |
+
amatsuda/nested_scaffold ruby
|
| 2969 |
+
tsion/miri rust
|
| 2970 |
+
sgtoj/cw-manage-slack-bot typescript
|
| 2971 |
+
mlaz/mynewt-core c
|
| 2972 |
+
buchgr/bazel-remote go
|
| 2973 |
+
pilot51/voicenotify java
|
| 2974 |
+
eJRF/ejrf javascript
|
| 2975 |
+
stof/symfony php
|
| 2976 |
+
teonlamont/mne-python python
|
| 2977 |
+
twitter/twurl ruby
|
| 2978 |
+
dylanmckay/protocol rust
|
| 2979 |
+
amalshehu/angular-tour-of-heroes typescript
|
| 2980 |
+
thomaskeck/root c
|
| 2981 |
+
flynn-examples/go-flynn-example go
|
| 2982 |
+
Microsoft/ApplicationInsights-Android java
|
| 2983 |
+
mrkmarron/ChakraCore javascript
|
| 2984 |
+
engram-design/FieldManager php
|
| 2985 |
+
EinsamHauer/graphite-web-iow python
|
| 2986 |
+
gina-alaska/ttnmanager ruby
|
| 2987 |
+
Boddlnagg/rustup.rs rust
|
| 2988 |
+
cannoneyed/fiddle typescript
|
| 2989 |
+
dslab-epfl/asap c
|
| 2990 |
+
go-playground/generate go
|
| 2991 |
+
proxer/ProxerLibJava java
|
| 2992 |
+
sgmap/mes-aides-ui javascript
|
| 2993 |
+
jolantis/artlantis php
|
| 2994 |
+
OCA/contract python
|
| 2995 |
+
rasnom/sorryyoufeelthatway ruby
|
| 2996 |
+
dtolnay/cxx rust
|
| 2997 |
+
formigio/angular-frontend typescript
|
| 2998 |
+
mundue/MMTrackingController c
|
| 2999 |
+
guildencrantz/ask_nest go
|
| 3000 |
+
hpautonomy/find java
|
| 3001 |
+
shioyang/EmotionalReader javascript
|
| 3002 |
+
atehnix/laravel-stubs php
|
| 3003 |
+
spreadflow/spreadflow-core python
|
| 3004 |
+
costolo/chain ruby
|
| 3005 |
+
pacman82/odbc-sys rust
|
| 3006 |
+
github/webauthn-json typescript
|
| 3007 |
+
coreboot/chrome-ec c
|
| 3008 |
+
projectatomic/buildah go
|
| 3009 |
+
helun/Ektorp java
|
| 3010 |
+
cysjonathan/coursemology2 javascript
|
| 3011 |
+
webfactory/content-mapping-sourceadapter-propel php
|
| 3012 |
+
djangogirlstaipei/eshop python
|
| 3013 |
+
benwbrum/fromthepage ruby
|
| 3014 |
+
adRichter/plantex rust
|
| 3015 |
+
artivilla/desktop typescript
|
| 3016 |
+
deniscostadsc/playground c
|
| 3017 |
+
willfaught/gockle go
|
| 3018 |
+
danshannon/javastrava-test java
|
| 3019 |
+
coryhouse/react-slingshot javascript
|
| 3020 |
+
sparkframework/spark php
|
| 3021 |
+
99designs/colorific python
|
| 3022 |
+
r7kamura/altria-simple_cov ruby
|
| 3023 |
+
nathanrosspowell/rust_guessing_game rust
|
| 3024 |
+
murmur76/beyond.ts typescript
|
| 3025 |
+
abusalimov/SublimeCImproved c
|
| 3026 |
+
Versent/saml2aws go
|
| 3027 |
+
QuickBlox/quickblox-android-sdk java
|
| 3028 |
+
Jameskmonger/dependument javascript
|
| 3029 |
+
LogicAndTrick/twhl php
|
| 3030 |
+
revng/llvmcpy python
|
| 3031 |
+
eric/metriks_log_webhook ruby
|
| 3032 |
+
mulkieran/stratisd rust
|
| 3033 |
+
BillWagner/WorkingWithTypeScript typescript
|
| 3034 |
+
ferrous26/cs452-flaming-meme c
|
| 3035 |
+
rootulp/exercism go
|
| 3036 |
+
smalldatalab/omh-dsu java
|
| 3037 |
+
dimkarakostas/unimeet javascript
|
| 3038 |
+
symfony/security-bundle php
|
| 3039 |
+
Antrikshy/reddit2Kindle python
|
| 3040 |
+
moneyadviceservice/middleman-i18n-markdown ruby
|
| 3041 |
+
tzkhan/roman-rust rust
|
| 3042 |
+
xtina-starr/reaction typescript
|
| 3043 |
+
thoughtbot/BotKit c
|
| 3044 |
+
ziutek/thread go
|
| 3045 |
+
rajdavies/fabric8 java
|
| 3046 |
+
vigetlabs/microcosm javascript
|
| 3047 |
+
whathejoe/lms-m4g4 php
|
| 3048 |
+
foliant-docs/foliant python
|
| 3049 |
+
mongodb/mongoid ruby
|
| 3050 |
+
burtonageo/rebind rust
|
| 3051 |
+
wishtack/wishtack-steroids typescript
|
| 3052 |
+
aaronriekenberg/openbsd_cproxy c
|
| 3053 |
+
ftcjeff/AirlineCode-go go
|
| 3054 |
+
RoboZonky/robozonky java
|
| 3055 |
+
dmitriiabramov/esfmt javascript
|
| 3056 |
+
artesaos/laravel-linkedin php
|
| 3057 |
+
estebistec/django-twitter-bootstrap python
|
| 3058 |
+
aruprakshit/sync ruby
|
| 3059 |
+
zslayton/cron rust
|
| 3060 |
+
dkocich/osm-pt-ngx-leaflet typescript
|
| 3061 |
+
pressel/mpi4py c
|
| 3062 |
+
anthonyrego/gosmf go
|
| 3063 |
+
Charling-Huang/birt java
|
| 3064 |
+
hellsgate1001/waypoints javascript
|
| 3065 |
+
renyuneyun/core php
|
| 3066 |
+
Antojitos/chalupas python
|
| 3067 |
+
Validic/validic ruby
|
| 3068 |
+
mijnadres/serde_elm rust
|
| 3069 |
+
artsy/force-public typescript
|
| 3070 |
+
reupen/mmh c
|
| 3071 |
+
btobolaski/terraform-provider-linode go
|
| 3072 |
+
bogdansolga/nokia-spring-boot-training java
|
| 3073 |
+
testlnord/wurfelspiel javascript
|
| 3074 |
+
fullybaked/pslackr php
|
| 3075 |
+
MasonM/hssonline-conference python
|
| 3076 |
+
pch/lastfm-client ruby
|
| 3077 |
+
oakes/neovim-rs rust
|
| 3078 |
+
cookingfox/stibble-api-client-angular typescript
|
| 3079 |
+
hikoLab/pebcessing c
|
| 3080 |
+
soudy/eparser go
|
| 3081 |
+
yingyun001/ovirt-engine java
|
| 3082 |
+
mg4tv/mg4tv-web javascript
|
| 3083 |
+
tux-rampage/zend-di php
|
| 3084 |
+
2baOrNot2ba/dreamBeam python
|
| 3085 |
+
chrisvanheuveln/cisco-network-node-utils ruby
|
| 3086 |
+
DaGenix/rust-crypto rust
|
| 3087 |
+
jordwest/news-feed-eradicator typescript
|
| 3088 |
+
ytaben/WakeOnLanRelay c
|
| 3089 |
+
mattn/go-mastodon go
|
| 3090 |
+
steria/skuldsku java
|
| 3091 |
+
cristiana214/cristianachavez214-cristianachavez javascript
|
| 3092 |
+
ob-ivan/sd-currency php
|
| 3093 |
+
k4nar/inbox python
|
| 3094 |
+
chrishunt/github-auth ruby
|
| 3095 |
+
tum-rt/emoji-feedback rust
|
| 3096 |
+
thecjharries/slim-ace typescript
|
| 3097 |
+
bbockelm/condor-network-accounting c
|
| 3098 |
+
qskycolor/gofrontend go
|
| 3099 |
+
Monospark/ActionControl java
|
| 3100 |
+
slightly-askew/portfolio-2017 javascript
|
| 3101 |
+
digitickets/omnipay-verifone-web-service php
|
| 3102 |
+
ctsit/nacculator python
|
| 3103 |
+
emodeqidao/Kiwi ruby
|
| 3104 |
+
aopicier/cryptopals-rust rust
|
| 3105 |
+
sdeleuze/mixit typescript
|
| 3106 |
+
fergul/Cache c
|
| 3107 |
+
declanshanaghy/bbqberry go
|
| 3108 |
+
Hypersonic/Starlorn java
|
| 3109 |
+
var-bin/reactjs-training javascript
|
| 3110 |
+
joshmassey/sga-itracker php
|
| 3111 |
+
kytos/python-openflow python
|
| 3112 |
+
spatchcock/calc-json-ruby ruby
|
| 3113 |
+
bitwalker/rustcalc rust
|
| 3114 |
+
what3words/w3w-node-wrapper typescript
|
| 3115 |
+
GNOME/telepathy-account-widgets c
|
| 3116 |
+
resumic/schema go
|
| 3117 |
+
kryptnostic/rhizome java
|
| 3118 |
+
topherauyeung/portfolio javascript
|
| 3119 |
+
EOL/eol_php_code php
|
| 3120 |
+
victorpoluceno/xwing python
|
| 3121 |
+
jiajiawang/load_more ruby
|
| 3122 |
+
hoodie/rust-email rust
|
| 3123 |
+
jchakra/discord-raider typescript
|
| 3124 |
+
k4rtik/btp-gvn c
|
| 3125 |
+
torinos-io/api go
|
| 3126 |
+
veyndan/paper-for-reddit java
|
| 3127 |
+
alphagov/notifications-admin javascript
|
| 3128 |
+
ProjetPP/PPP-Wikidata php
|
| 3129 |
+
Stratoscale/skipper python
|
| 3130 |
+
uhoh-itsmaciek/pg-quilter ruby
|
| 3131 |
+
cobalt-org/cobalt.rs rust
|
| 3132 |
+
Ragg-/Delir typescript
|
| 3133 |
+
ROCm-Developer-Tools/HIP c
|
| 3134 |
+
hashicorp/go-getter go
|
| 3135 |
+
philipphager/disclosure-android-app java
|
| 3136 |
+
jlord/git-it-electron javascript
|
| 3137 |
+
armadito/armadito-glpi php
|
| 3138 |
+
SUSE/azurectl python
|
| 3139 |
+
kolorahl/acls ruby
|
| 3140 |
+
LesPepitos/gist rust
|
| 3141 |
+
neild3r/vscode-php-docblocker typescript
|
| 3142 |
+
matayoshi/tools c
|
| 3143 |
+
emicklei/melrose go
|
| 3144 |
+
CA-APM/ca-apm-fieldpack-asm java
|
| 3145 |
+
dev-brutus/427 javascript
|
| 3146 |
+
sabre-io/vobject php
|
| 3147 |
+
pinax/django-waitinglist python
|
| 3148 |
+
logentries/le_ruby ruby
|
| 3149 |
+
jhelwig/homers rust
|
| 3150 |
+
chunye/azure-functions-ux typescript
|
data/qna/aligned6_qna.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/qna/repo_scoped_qa.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/repo_list.txt
ADDED
|
@@ -0,0 +1,800 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
imankulov/sentry
|
| 2 |
+
rnyberg/pyfibot
|
| 3 |
+
artefactual/archivematica-history
|
| 4 |
+
caleb531/automata
|
| 5 |
+
Antiun/account-invoicing
|
| 6 |
+
ElementalAlchemist/txircd
|
| 7 |
+
kmee/stock-logistics-warehouse
|
| 8 |
+
BT-rmartin/partner-contact
|
| 9 |
+
yuzie007/upho
|
| 10 |
+
bfaludi/daprot
|
| 11 |
+
angr/cle
|
| 12 |
+
jmenglund/CollectionBatchTool
|
| 13 |
+
coleifer/scout
|
| 14 |
+
hsercanatli/adaptivetuning
|
| 15 |
+
krmaxwell/TRX
|
| 16 |
+
svieira/Flask-HipPocket
|
| 17 |
+
capybaralet/fuel
|
| 18 |
+
openstack/akanda-rug
|
| 19 |
+
glyph/txsni
|
| 20 |
+
tiddlyweb/tiddlywebplugins.atom
|
| 21 |
+
grimwm/py-dictobj
|
| 22 |
+
amorison/qjobs
|
| 23 |
+
blancltd/blanc-basic-pages
|
| 24 |
+
zchee/python-client
|
| 25 |
+
CBitLabs/django-globals
|
| 26 |
+
rgardner/ouimeaux
|
| 27 |
+
hsolbrig/SNOMEDToOWL
|
| 28 |
+
kevinschaul/open-in-github
|
| 29 |
+
TangledWeb/tangled.auth
|
| 30 |
+
bbangert/retools
|
| 31 |
+
czpython/aldryn-faq
|
| 32 |
+
alama/PSO2Proxy
|
| 33 |
+
10gen-labs/mongo-connector
|
| 34 |
+
makinacorpus/reportlab-ecomobile
|
| 35 |
+
devinmcgloin/advent
|
| 36 |
+
problemshift/kf5py
|
| 37 |
+
PyO3/setuptools-rust
|
| 38 |
+
apoorvemohan/haas
|
| 39 |
+
crsmithdev/arrow
|
| 40 |
+
c4fcm/CLIFF-API-Client
|
| 41 |
+
martinrusev/imbox
|
| 42 |
+
favien/favien
|
| 43 |
+
thomwiggers/django-mongodbforms
|
| 44 |
+
anthonysandrin/kafka-utils
|
| 45 |
+
dplucenio/heat_diffusion_experiment
|
| 46 |
+
bgyori/bioagents
|
| 47 |
+
plainas/tq
|
| 48 |
+
vesln/robber.py
|
| 49 |
+
dirn/Simon
|
| 50 |
+
plone/plone.server
|
| 51 |
+
lauft/timew-report
|
| 52 |
+
AmiiThinks/amii-tf-nn
|
| 53 |
+
ludwiktrammer/django-tagging-autocomplete
|
| 54 |
+
pyinvoke/invocations
|
| 55 |
+
jaylett/django_exceptional_middleware
|
| 56 |
+
nosamanuel/dj-queryset-manager
|
| 57 |
+
ap--/python-oceanoptics
|
| 58 |
+
millerdev/django-nose
|
| 59 |
+
ssanderson/interface
|
| 60 |
+
ryanraaum/oldowan.mtdna
|
| 61 |
+
oemof/feedinlib
|
| 62 |
+
madmaze/pytesseract
|
| 63 |
+
timraasveld/ansible-string-split-filter
|
| 64 |
+
otknoy/michishiki_api_server
|
| 65 |
+
alexmilesyounger/ds_basics
|
| 66 |
+
adampiskorski/lpr_poc
|
| 67 |
+
ranisalt/enigma
|
| 68 |
+
infOpen/ansible-role-vsftpd
|
| 69 |
+
chubbymaggie/asap
|
| 70 |
+
girder/girder_worker
|
| 71 |
+
atiberghien/makerscience-server
|
| 72 |
+
KuChanTung/Python
|
| 73 |
+
globocom/database-as-a-service
|
| 74 |
+
Stark-Mountain/meetup-facebook-bot
|
| 75 |
+
claudiopastorini/claudiopastorini.github.io
|
| 76 |
+
b123400/purescript-ide-sublime
|
| 77 |
+
bshaffer/appengine-python-vm-hello
|
| 78 |
+
chop-dbhi/django-webhooks
|
| 79 |
+
jwarshaw/RaspberryDrive
|
| 80 |
+
aikramer2/spaCy
|
| 81 |
+
alexgarciac/scrapi
|
| 82 |
+
karel-brinda/prophyle
|
| 83 |
+
etataurov/pytest
|
| 84 |
+
khchine5/opal
|
| 85 |
+
hatbot-team/hatbot_resources
|
| 86 |
+
ellmetha/machina-singlepageapp
|
| 87 |
+
seibert/numba
|
| 88 |
+
earlwlkr/POICrawler
|
| 89 |
+
ideascube/ideascube
|
| 90 |
+
group-policy/rally
|
| 91 |
+
funkybob/paws
|
| 92 |
+
analyst-collective/dbt
|
| 93 |
+
scanner-research/scanner
|
| 94 |
+
ScanOC/trunk-player
|
| 95 |
+
saltstack/salt
|
| 96 |
+
cherba/apitools
|
| 97 |
+
RainCity471/lyCompiler
|
| 98 |
+
chiphogg/vim-vtd
|
| 99 |
+
patrickspencer/mathdeck
|
| 100 |
+
brainwane/zulip
|
| 101 |
+
handroll/handroll
|
| 102 |
+
sl2017/campos
|
| 103 |
+
wiliamsouza/hystrix-py
|
| 104 |
+
dimagi/commcare-hq
|
| 105 |
+
thiderman/network-kitten
|
| 106 |
+
kefir500/ghstats
|
| 107 |
+
JungeAlexander/cocoscore
|
| 108 |
+
ohsu-qin/qipipe
|
| 109 |
+
sergey-dryabzhinsky/dedupsqlfs
|
| 110 |
+
t-miyamae/teuthology
|
| 111 |
+
0xPoly/ooni-probe
|
| 112 |
+
sorgerlab/indra
|
| 113 |
+
nvbn/thefuck
|
| 114 |
+
aosp-mirror/platform_external_skia
|
| 115 |
+
masasin/spirit
|
| 116 |
+
benedicteb/outcast
|
| 117 |
+
SEL-Columbia/commcare-hq
|
| 118 |
+
OCA/stock-logistics-warehouse
|
| 119 |
+
lemming52/white_knight
|
| 120 |
+
egafford/sahara
|
| 121 |
+
jdevera/subdue
|
| 122 |
+
VirusTotal/misp-modules
|
| 123 |
+
benedfit/SublimeLinter-contrib-pug-lint
|
| 124 |
+
thebinarypenguin/SublimeLinter-contrib-raml-cop
|
| 125 |
+
csrocha/account_journal_payment_subtype
|
| 126 |
+
pombreda/seascope
|
| 127 |
+
tanayseven/personal_website
|
| 128 |
+
pinry/pinry
|
| 129 |
+
geelweb/laposte-python-sdk
|
| 130 |
+
phil-lopreiato/the-blue-alliance
|
| 131 |
+
EnvGen/toolbox
|
| 132 |
+
openaustralia/publicwhip-matthew
|
| 133 |
+
thorgate/django-project-template
|
| 134 |
+
monostable/haskell-kicad-data
|
| 135 |
+
OpenSpace/OpenSpace
|
| 136 |
+
planetlabs/datalake-ingester
|
| 137 |
+
yamatt/bonfiremanager
|
| 138 |
+
wkentaro/chainer
|
| 139 |
+
Dybov/real_estate_agency
|
| 140 |
+
Astroua/aws_controller
|
| 141 |
+
nagilum/script.rndmov
|
| 142 |
+
lsgunth/rapidsms
|
| 143 |
+
yeasy/robot_tool
|
| 144 |
+
ShivamSarodia/ShivyC
|
| 145 |
+
stefanklug/plata
|
| 146 |
+
willdavidc/piel
|
| 147 |
+
henriquebastos/virtualenv-bootstrap
|
| 148 |
+
ianfieldhouse/number_to_words
|
| 149 |
+
sindrig/spoppy
|
| 150 |
+
rlee287/pyautoupdate
|
| 151 |
+
bharling/django-pint
|
| 152 |
+
jackromo/RandTerrainPy
|
| 153 |
+
ayushgoel/LongShot
|
| 154 |
+
reedstrm/Pyrseas
|
| 155 |
+
andylytical/brewpi-scripts
|
| 156 |
+
HHS-IntroProgramming/Multiplication-table
|
| 157 |
+
wyager/IHaskell
|
| 158 |
+
opnfv/functest
|
| 159 |
+
amolenaar/gaphor
|
| 160 |
+
potatolondon/contentious
|
| 161 |
+
pavel-paulau/perfrunner
|
| 162 |
+
AlexHill/mezzanine
|
| 163 |
+
sassoftware/mint
|
| 164 |
+
hackerspace-ntnu/website
|
| 165 |
+
paylogic/py2deb
|
| 166 |
+
oliverlee/antlia
|
| 167 |
+
voer-platform/vp.repo
|
| 168 |
+
exekias/django-achilles
|
| 169 |
+
ikaruswill/vector-space-model
|
| 170 |
+
goldmann/docker-scripts
|
| 171 |
+
tzengyuxio/python-five91
|
| 172 |
+
Doist/todoist-python
|
| 173 |
+
datasciencebr/serenata-toolbox
|
| 174 |
+
jeanmask/opps-admin
|
| 175 |
+
fprimex/zdesk
|
| 176 |
+
praekelt/go-contacts-api
|
| 177 |
+
MisanthropicBit/bibpy
|
| 178 |
+
thismachinechills/save_skype
|
| 179 |
+
lucianovdveekens/jiradoc
|
| 180 |
+
ckan/ckanext-qa
|
| 181 |
+
hyunchel/redis-dump-load
|
| 182 |
+
ondergetekende/python-panavatar
|
| 183 |
+
tarpas/pytest-testmon
|
| 184 |
+
yola/proxyprefix
|
| 185 |
+
ScatterHQ/eliot
|
| 186 |
+
NewKnowledge/punk
|
| 187 |
+
rdo-management/ironic-discoverd
|
| 188 |
+
igstan/redis-grep
|
| 189 |
+
opencord/voltha
|
| 190 |
+
xandr2/blynkapi
|
| 191 |
+
exoanalytic/python-skyfield
|
| 192 |
+
hobarrera/django-afip
|
| 193 |
+
Connexions/cnx-publishing
|
| 194 |
+
Charcoal-SE/SmokeDetector
|
| 195 |
+
pfmoore/invoke
|
| 196 |
+
Calysto/metakernel
|
| 197 |
+
CCI-MOC/GUI-Backend
|
| 198 |
+
harvard-lil/h2o
|
| 199 |
+
binoculars/osf.io
|
| 200 |
+
kjordahl/swm
|
| 201 |
+
tomv564/LSP
|
| 202 |
+
thomasballinger/tmuxp
|
| 203 |
+
philipdexter/vx
|
| 204 |
+
OnroerendErfgoed/crabpy
|
| 205 |
+
gviot/nadis
|
| 206 |
+
moreati/b-prefix-all-the-doctests
|
| 207 |
+
rudeb0t/DjangoAllowDeny
|
| 208 |
+
bodbdigr/restea
|
| 209 |
+
7ws/django-emailer
|
| 210 |
+
mandiant/ioc_writer
|
| 211 |
+
cloudify-cosmo/tosca-vcloud-plugin
|
| 212 |
+
alisaifee/flask-limiter
|
| 213 |
+
xmunoz/sodapy
|
| 214 |
+
mass-project/mass_api_client
|
| 215 |
+
gsarma/ChannelWorm
|
| 216 |
+
markbrough/exchangerates
|
| 217 |
+
TangledWeb/tangled.sqlalchemy
|
| 218 |
+
FlipperPA/wagtailpress
|
| 219 |
+
TangledWeb/tangled.website
|
| 220 |
+
sedders123/phial
|
| 221 |
+
JrGoodle/clowder
|
| 222 |
+
kevgathuku/top40
|
| 223 |
+
erikrose/blessings
|
| 224 |
+
yola/auth_tkt
|
| 225 |
+
consbio/parserutils
|
| 226 |
+
archsh/tg2ext.express
|
| 227 |
+
MichaelYusko/Bot-Chucky
|
| 228 |
+
ryanmcdermott/birdseed
|
| 229 |
+
mociepka/saleor
|
| 230 |
+
GallopLabs/facebook-ads-api
|
| 231 |
+
rail/releasetasks
|
| 232 |
+
sebdah/yayson
|
| 233 |
+
serge-sans-paille/gast
|
| 234 |
+
adlibre/django-bcp
|
| 235 |
+
ayushgoel/mstranslator
|
| 236 |
+
gilesbrown/python-icapservice
|
| 237 |
+
nigma/dj-cmd
|
| 238 |
+
srittau/rouver
|
| 239 |
+
VirgilSecurity/virgil-sdk-python
|
| 240 |
+
verilylifesciences/analysis-py-utils
|
| 241 |
+
compunova/kozinaki
|
| 242 |
+
wangjohn/zinc_cli
|
| 243 |
+
SCUEvals/scuevals-api
|
| 244 |
+
ifduyue/urlfetch
|
| 245 |
+
cychiang/mafan
|
| 246 |
+
mcmtroffaes/pathlib2
|
| 247 |
+
tilezen/scoville
|
| 248 |
+
pczerkas/captainhook
|
| 249 |
+
benedictpaten/cactus
|
| 250 |
+
caktus/django-pagelets
|
| 251 |
+
suminb/urwid-stackedwidget
|
| 252 |
+
alphagov/stagecraft
|
| 253 |
+
Connexions/cnx-authoring
|
| 254 |
+
agoragames/py-eventsocket
|
| 255 |
+
evoja/docker-Github-Gitlab-Auto-Deploy
|
| 256 |
+
incuna/feincms-extensions
|
| 257 |
+
zmbq/djqgrid
|
| 258 |
+
kevinconway/rpmvenv
|
| 259 |
+
maxzheng/workspace-tools
|
| 260 |
+
thsnr/gygax
|
| 261 |
+
theislab/dca
|
| 262 |
+
iamwucheng/xml_models2
|
| 263 |
+
divio/django-cas
|
| 264 |
+
johnpaulett/txHL7
|
| 265 |
+
twig/django-taggit
|
| 266 |
+
gasman/Willow
|
| 267 |
+
smarkets/statprof
|
| 268 |
+
360youlun/cmsplugin-bootstrap-carousel
|
| 269 |
+
ceball/param
|
| 270 |
+
associazionepoltronieri/blender-ap
|
| 271 |
+
wikilinks/sift
|
| 272 |
+
DesertBot/DesertBot
|
| 273 |
+
4degrees/segue
|
| 274 |
+
holdenweb/nbtools
|
| 275 |
+
openhealthcare/opal-referral
|
| 276 |
+
BansheeMediaPlayer/bockbuild
|
| 277 |
+
elacuesta/scrapy
|
| 278 |
+
mbr/flask-appconfig
|
| 279 |
+
ninjawil/weather-station
|
| 280 |
+
sunlightlabs/thezombies
|
| 281 |
+
PanDAWMS/panda-bigmon-atlas
|
| 282 |
+
varunarya10/oslo.i18n
|
| 283 |
+
jefrailey/basic-scraper
|
| 284 |
+
udibr/fuel
|
| 285 |
+
haridsv/fabric
|
| 286 |
+
gadventures/gapipy
|
| 287 |
+
sk-/python2.7-type-annotator
|
| 288 |
+
mythmon/kitsune
|
| 289 |
+
j4mie/django-activelink
|
| 290 |
+
jwg4/flask-autodoc
|
| 291 |
+
EmadMokhtar/halaqat
|
| 292 |
+
EDUlib/edx-platform
|
| 293 |
+
Graylog2/graylog-ansible-role
|
| 294 |
+
armab/st2contrib
|
| 295 |
+
KrzysztofSendor/dactyl
|
| 296 |
+
nurav/balrog
|
| 297 |
+
Pierre-Sassoulas/django-survey
|
| 298 |
+
microsoft/dpu-utils
|
| 299 |
+
PersonalGenomesOrg/open-humans
|
| 300 |
+
vayan/external-video
|
| 301 |
+
simonjbeaumont/xcp-rrdd
|
| 302 |
+
lozadaOmr/ansible-admin
|
| 303 |
+
ulikoehler/UliEngineering
|
| 304 |
+
kxxoling/fabric
|
| 305 |
+
EmilStenstrom/nephele
|
| 306 |
+
chingc/DJRivals
|
| 307 |
+
docsbox/docsbox
|
| 308 |
+
uva-financial-engineering/cifer-tournament
|
| 309 |
+
OSGConnect/freesurfer_workflow
|
| 310 |
+
aaronkurtz/bricky
|
| 311 |
+
worldforge/libwfut
|
| 312 |
+
churchlab/millstone
|
| 313 |
+
asteroide/immo_spider
|
| 314 |
+
odoo-chile/l10n_cl_account_vat_ledger
|
| 315 |
+
jeenalee/sklearn_pmml
|
| 316 |
+
attenzione/SublimeLinter-scss-lint
|
| 317 |
+
pudo/spendb
|
| 318 |
+
hackebrot/cibopath
|
| 319 |
+
mokieyue/mopidy
|
| 320 |
+
textbook/flask-forecaster
|
| 321 |
+
ncareol/spatialdb
|
| 322 |
+
fna/owning-a-home-api
|
| 323 |
+
gitpython-developers/GitPython
|
| 324 |
+
spyder-ide/qtawesome
|
| 325 |
+
ravel-net/ravel
|
| 326 |
+
humangeo/preflyt
|
| 327 |
+
ucb-sts/sts
|
| 328 |
+
jlaunonen/kirppu
|
| 329 |
+
matthiask/towel
|
| 330 |
+
jmiserez/sts
|
| 331 |
+
teonlamont/mne-python
|
| 332 |
+
EinsamHauer/graphite-web-iow
|
| 333 |
+
OCA/contract
|
| 334 |
+
spreadflow/spreadflow-core
|
| 335 |
+
djangogirlstaipei/eshop
|
| 336 |
+
99designs/colorific
|
| 337 |
+
revng/llvmcpy
|
| 338 |
+
Antrikshy/reddit2Kindle
|
| 339 |
+
foliant-docs/foliant
|
| 340 |
+
estebistec/django-twitter-bootstrap
|
| 341 |
+
Antojitos/chalupas
|
| 342 |
+
MasonM/hssonline-conference
|
| 343 |
+
2baOrNot2ba/dreamBeam
|
| 344 |
+
k4nar/inbox
|
| 345 |
+
ctsit/nacculator
|
| 346 |
+
kytos/python-openflow
|
| 347 |
+
victorpoluceno/xwing
|
| 348 |
+
Stratoscale/skipper
|
| 349 |
+
SUSE/azurectl
|
| 350 |
+
pinax/django-waitinglist
|
| 351 |
+
paulfanelli/planet_alignment
|
| 352 |
+
jmcclell/django-bootstrap-pagination
|
| 353 |
+
SUNET/eduid-webapp
|
| 354 |
+
jiaaro/pydub
|
| 355 |
+
srittau/python-htmlgen
|
| 356 |
+
marcoslhc/xyvio
|
| 357 |
+
zestyping/q
|
| 358 |
+
epsy/clize
|
| 359 |
+
lawlesst/vivo-rdflib-sparqlstore
|
| 360 |
+
storecast/barrel
|
| 361 |
+
mwilliamson/whack
|
| 362 |
+
toastdriven/restless
|
| 363 |
+
Empiria/matador
|
| 364 |
+
daltonserey/tst
|
| 365 |
+
whilp/python-script
|
| 366 |
+
smly/ume
|
| 367 |
+
richo/groundstation
|
| 368 |
+
MetaMemoryT/aiozmq
|
| 369 |
+
Z2PackDev/TBmodels
|
| 370 |
+
igordejanovic/textX
|
| 371 |
+
pbs/cmsplugin-filer
|
| 372 |
+
google/python-lakeside
|
| 373 |
+
jbergant/endpoints-proto-datastore
|
| 374 |
+
cqse/teamscale-client-python
|
| 375 |
+
f00f-nyc/cityhall-python
|
| 376 |
+
ProjetPP/ExamplePPPModule-Python
|
| 377 |
+
cjhutto/bsd
|
| 378 |
+
svanoort/pyresttest
|
| 379 |
+
pmclanahan/urlwait
|
| 380 |
+
durden/nikeplus
|
| 381 |
+
veo-labs/nose-progressive
|
| 382 |
+
isghe/chainpoint
|
| 383 |
+
AndBicScadMedia/blueprint
|
| 384 |
+
garydonovan/google-maps-services-python
|
| 385 |
+
infoxchange/ixwsauth
|
| 386 |
+
andrasmaroy/pconf
|
| 387 |
+
aditweb/django-socialregistration
|
| 388 |
+
bugra/l1
|
| 389 |
+
eugeniy/pytest-tornado
|
| 390 |
+
juanriaza/django-rest-framework-msgpack
|
| 391 |
+
justin8/portinus
|
| 392 |
+
mayfield/ecmcli
|
| 393 |
+
saulshanabrook/django-simpleimages
|
| 394 |
+
williamboman/matrix-angular-sdk
|
| 395 |
+
FutureSharks/invokust
|
| 396 |
+
nitishr/PyHamcrest
|
| 397 |
+
nvdv/vprof
|
| 398 |
+
luci/recipes-py
|
| 399 |
+
freevoid/yawf
|
| 400 |
+
christopher18/Celsearch
|
| 401 |
+
lpancescu/atlas-lint
|
| 402 |
+
alexm92/sentry
|
| 403 |
+
petrjasek/superdesk-ntb
|
| 404 |
+
mpkato/interleaving
|
| 405 |
+
kapadia/rasterio
|
| 406 |
+
gbouvignies/chemex
|
| 407 |
+
google/nogotofail
|
| 408 |
+
sapcc/monasca-agent
|
| 409 |
+
bert9bert/statsmodels
|
| 410 |
+
mopidy/mopidy-soundcloud
|
| 411 |
+
scrapinghub/shub
|
| 412 |
+
alexef/pygobject
|
| 413 |
+
talons/talons
|
| 414 |
+
easy-as-python/django-webmention
|
| 415 |
+
ryankask/django-discoverage
|
| 416 |
+
davidfischer/warehouse
|
| 417 |
+
idjaw/netman
|
| 418 |
+
rahulbohra/Python-Basic
|
| 419 |
+
eriol/circuits
|
| 420 |
+
sarutobi/ritmserdtsa
|
| 421 |
+
eunchong/build
|
| 422 |
+
DistributedSystemsGroup/zoe
|
| 423 |
+
citrix-openstack-build/oslo.versionedobjects
|
| 424 |
+
lamby/debian-devel-changes-bot
|
| 425 |
+
suclearnub/discordgrapher
|
| 426 |
+
samcheck/PyMedia
|
| 427 |
+
stepan-perlov/pgup
|
| 428 |
+
rootulp/exercism
|
| 429 |
+
larrybradley/photutils
|
| 430 |
+
osahp/forecastonishing
|
| 431 |
+
alphagov/notifications-api
|
| 432 |
+
onitake/Uranium
|
| 433 |
+
keybar/keybar
|
| 434 |
+
richard-willdooit/odoo-product-configurator
|
| 435 |
+
taeram/idiocy
|
| 436 |
+
leaffan/pynhldb
|
| 437 |
+
liumengjun/django-static-precompiler
|
| 438 |
+
derricw/asciisciit
|
| 439 |
+
AliGhahraei/nao-classroom
|
| 440 |
+
ChromeDevTools/devtools-frontend
|
| 441 |
+
allenai/deep_qa
|
| 442 |
+
brightchen/Impala
|
| 443 |
+
pyhmsa/pyhmsa-gui
|
| 444 |
+
jpbottaro/anna
|
| 445 |
+
scolby33/OCSPdash
|
| 446 |
+
guillaume-philippon/aquilon
|
| 447 |
+
stefan-caraiman/cloudbase-init-ci
|
| 448 |
+
fwalch/python-client
|
| 449 |
+
google/skia-buildbot
|
| 450 |
+
MarquisLP/gamehappy
|
| 451 |
+
paolodedios/tensorflow
|
| 452 |
+
abanaiyan/sniper
|
| 453 |
+
watchdogpolska/bliski_publikator
|
| 454 |
+
openego/oeplatform
|
| 455 |
+
jaapverloop/massa
|
| 456 |
+
mvexel/maproulette
|
| 457 |
+
atindale/business-glossary
|
| 458 |
+
ionitadaniel19/testframeworksevolution
|
| 459 |
+
rth/PyAbel
|
| 460 |
+
sunng87/jip
|
| 461 |
+
delinhabit/django-rest-framework
|
| 462 |
+
sampadsaha5/sympy
|
| 463 |
+
josephbisch/the-blue-alliance
|
| 464 |
+
globus/globus-cli
|
| 465 |
+
muun/bitforge
|
| 466 |
+
josuemontano/api-starter
|
| 467 |
+
ged/mongrel2
|
| 468 |
+
L1ghtn1ng/usaf
|
| 469 |
+
torchbox/wagtail
|
| 470 |
+
adrienbrunet/fanfare_cuc
|
| 471 |
+
homeworkprod/byceps
|
| 472 |
+
SalesforceFoundation/Cumulus
|
| 473 |
+
seler/djoauth2
|
| 474 |
+
ryan-roemer/django-cloud-browser
|
| 475 |
+
atheiste/django-bit-category
|
| 476 |
+
SUNET/SATOSA
|
| 477 |
+
jonathanslenders/python-prompt-toolkit
|
| 478 |
+
CompassionCH/compassion-switzerland
|
| 479 |
+
srct/whats-open
|
| 480 |
+
StackStorm/st2
|
| 481 |
+
HIIT/hybra-core
|
| 482 |
+
GuillaumeDerval/INGInious
|
| 483 |
+
kwagyeman/openmv
|
| 484 |
+
pradyunsg/pip
|
| 485 |
+
benschmaus/catapult
|
| 486 |
+
shubhamdhama/zulip
|
| 487 |
+
ministryofjustice/cla_backend
|
| 488 |
+
puttarajubr/commcare-hq
|
| 489 |
+
oldani/nanodegree-blog
|
| 490 |
+
hmoco/osf.io
|
| 491 |
+
gamezdaniel/mswl-dt-2013
|
| 492 |
+
LINKIWI/linkr
|
| 493 |
+
rtrembecky/roots
|
| 494 |
+
appliedx/edx-platform
|
| 495 |
+
zimolzak/Raspberry-Pi-newbie
|
| 496 |
+
OpenTreeOfLife/phylesystem-api
|
| 497 |
+
AlexandreProenca/backend-morandofloripa
|
| 498 |
+
msultan/mdtraj
|
| 499 |
+
kwadraterry/GPGPU-LUT
|
| 500 |
+
conjure-up/conjure-up
|
| 501 |
+
mattstibbs/blockbuster-server
|
| 502 |
+
mvpgomes/shopit-app
|
| 503 |
+
svetlyak40wt/django-dzenlog
|
| 504 |
+
mariocesar/django-rocket
|
| 505 |
+
madebymany/isthetoiletfree
|
| 506 |
+
DeBortoliWines/Bika-LIMS
|
| 507 |
+
xcgd/account_streamline
|
| 508 |
+
1flow/1flow
|
| 509 |
+
redhat-developer-tooling/vagrant-installers
|
| 510 |
+
SanaMobile/sana.protocol_builder
|
| 511 |
+
Foxboron/Frank
|
| 512 |
+
AustinRochford/s3img-ipython-magic
|
| 513 |
+
victorhahncastell/atlassian_permissions
|
| 514 |
+
maxamillion/autocloud
|
| 515 |
+
MrHarcombe/python-gpiozero
|
| 516 |
+
UMD-DRASTIC/drastic
|
| 517 |
+
OpenTreeOfLife/opentree
|
| 518 |
+
pegasus-isi/pegasus
|
| 519 |
+
gdit-cnd/RAPID
|
| 520 |
+
Floobits/plugin-common-python
|
| 521 |
+
cpcloud/dynd-python
|
| 522 |
+
Authentise/git-release
|
| 523 |
+
israelg99/eva
|
| 524 |
+
openxc/openxc-python
|
| 525 |
+
solidrails/mongrel2
|
| 526 |
+
jwg4/qual
|
| 527 |
+
sonofatailor/django-oscar
|
| 528 |
+
stoeps13/ibmcnx2
|
| 529 |
+
Vnet-as/falcon-hateoas
|
| 530 |
+
azaroth42/iiif-harvester
|
| 531 |
+
montefra/dodocs
|
| 532 |
+
MarkusH/django-nap
|
| 533 |
+
uccser/cs4teachers
|
| 534 |
+
veatch/elasticsearch-py
|
| 535 |
+
sdg-mit/gitless
|
| 536 |
+
cjcardinale/climlab
|
| 537 |
+
sorgerlab/belpy
|
| 538 |
+
OCA/reporting-engine
|
| 539 |
+
tylerdave/devpi-builder
|
| 540 |
+
onepercentclub/onepercentclub-site
|
| 541 |
+
AtteqCom/zsl
|
| 542 |
+
mitar/django-mongo-auth
|
| 543 |
+
LinuxTeam-teilar/cronos.teilar.gr
|
| 544 |
+
boklm/tbb-testsuite
|
| 545 |
+
jr-garcia/AssimpCy
|
| 546 |
+
sussexstudent/falmer
|
| 547 |
+
meebo/greins
|
| 548 |
+
GuidoBR/python-skyfield
|
| 549 |
+
cfobel/si-prefix
|
| 550 |
+
jaraco/irc
|
| 551 |
+
misttechnologies/selenium
|
| 552 |
+
wicksy/laptop-build
|
| 553 |
+
maxsocl/oldmailer
|
| 554 |
+
mchelem/cref2
|
| 555 |
+
anttipalola/alexa
|
| 556 |
+
bopo/django-socialregistration
|
| 557 |
+
percyfal/snakemake-rules
|
| 558 |
+
GaretJax/sphinx-autobuild
|
| 559 |
+
IL2HorusTeam/il2fb-ds-airbridge
|
| 560 |
+
caktus/rapidsms-decisiontree-app
|
| 561 |
+
timhberry/openam-flask-decorator
|
| 562 |
+
nryant/twokenize_py
|
| 563 |
+
lazygunner/xunleipy
|
| 564 |
+
novafloss/populous
|
| 565 |
+
mdmintz/SeleniumBase
|
| 566 |
+
Linaro/lava-server
|
| 567 |
+
PSU-OIT-ARC/django-arcutils
|
| 568 |
+
openstack/nova
|
| 569 |
+
willy-claes/django-react
|
| 570 |
+
Jitsusama/lets-do-dns
|
| 571 |
+
nerevu/riko
|
| 572 |
+
alphagov/performanceplatform-collector
|
| 573 |
+
aymara/verbenet-editor
|
| 574 |
+
rcmachado/pysuru
|
| 575 |
+
achabotl/pambox
|
| 576 |
+
BakeCode/performance-testing
|
| 577 |
+
frx0119/django-orderable-inlines
|
| 578 |
+
thaim/ansible
|
| 579 |
+
minoue/miExecutor
|
| 580 |
+
zolech/zabbix-mesos-template
|
| 581 |
+
mperignon/bmi-delta
|
| 582 |
+
praekelt/molo-gem
|
| 583 |
+
YeoLab/anchor
|
| 584 |
+
slashk/goldstone-server
|
| 585 |
+
DataDog/dogapi
|
| 586 |
+
ioO/billjobs
|
| 587 |
+
globocom/dbaas-zabbix
|
| 588 |
+
Khilo84/Py-StackExchange
|
| 589 |
+
philgyford/django-ditto
|
| 590 |
+
metachris/py2app
|
| 591 |
+
hhursev/recipe-scraper
|
| 592 |
+
myles/me-api
|
| 593 |
+
eXma/meet-and-eat-registration-system
|
| 594 |
+
ryansturmer/gitmake
|
| 595 |
+
kmike/django-widget-tweaks
|
| 596 |
+
CO600GOL/Game_of_life
|
| 597 |
+
grigorisg9gr/pyutils
|
| 598 |
+
jambonrose/DjangoUnleashed-1.8
|
| 599 |
+
aflc/editdistance
|
| 600 |
+
kwhanalytics/rdtools
|
| 601 |
+
ekumenlabs/terminus
|
| 602 |
+
fanglinfang/myuw
|
| 603 |
+
sixty-north/python-transducers
|
| 604 |
+
mozilla/normandy
|
| 605 |
+
andialbrecht/sentry-comments
|
| 606 |
+
Alem/django-jfu
|
| 607 |
+
sloede/pyglab
|
| 608 |
+
agarone-mm/scholastic-demo
|
| 609 |
+
vintasoftware/cdrf.co
|
| 610 |
+
FreeMusicNinja/api.freemusic.ninja
|
| 611 |
+
rmoorman/qotr
|
| 612 |
+
timvandermeij/sentiment-analysis
|
| 613 |
+
chipx86/reviewboard
|
| 614 |
+
hotpxl/canonicalization-server
|
| 615 |
+
caktus/rapidsms-tropo
|
| 616 |
+
samuel/kokki
|
| 617 |
+
DemocracyClub/electionleaflets
|
| 618 |
+
renalreg/radar
|
| 619 |
+
germn/python-for-android
|
| 620 |
+
zsiciarz/django-pgallery
|
| 621 |
+
jokimies/django-pj-budget
|
| 622 |
+
lises/sheldon
|
| 623 |
+
caseyjlaw/flaskigm
|
| 624 |
+
mininet/mininet
|
| 625 |
+
registerguard/django-newswall
|
| 626 |
+
ibackus/custom_python_packages
|
| 627 |
+
madr/utsokt
|
| 628 |
+
building4theweb/soundem-api
|
| 629 |
+
shichao-an/soundmeter
|
| 630 |
+
phss/notes-cli
|
| 631 |
+
euanlau/django-betainvite
|
| 632 |
+
bow/pytest-pipeline
|
| 633 |
+
alejandrodob/mamba
|
| 634 |
+
dudepare/bedrock
|
| 635 |
+
MidwestFurryFandom/mff-rams-plugin
|
| 636 |
+
Teknologforeningen/teknologr.io
|
| 637 |
+
christophmeissner/lagesonum
|
| 638 |
+
nickodell/morse-code
|
| 639 |
+
0101/djangoembed
|
| 640 |
+
caktus/django-opendebates
|
| 641 |
+
TUD-OS/gem5-dtu
|
| 642 |
+
Commonists/CommonsDownloader
|
| 643 |
+
kalaboster/stringer
|
| 644 |
+
alphagov/digitalmarketplace-api
|
| 645 |
+
nerdzeu/NERDZCrush
|
| 646 |
+
hgl888/chromium-crosswalk-efl
|
| 647 |
+
opencivicdata/scrapers-ca
|
| 648 |
+
rapidpro/casepro
|
| 649 |
+
alphagov/digitalmarketplace-admin-frontend
|
| 650 |
+
eliteraspberries/minipkg
|
| 651 |
+
gogoair/foremast
|
| 652 |
+
spgill/bitnigma
|
| 653 |
+
jberkenbilt/qpdf
|
| 654 |
+
stephenmcd/hg-github
|
| 655 |
+
maximkulkin/marshmallow
|
| 656 |
+
tdphillips/campaigns
|
| 657 |
+
jinty/van.contactology
|
| 658 |
+
matslindh/kimochi-consumer
|
| 659 |
+
honnibal/spaCy
|
| 660 |
+
botify-labs/python-simple-workflow
|
| 661 |
+
damonkelley/django-name
|
| 662 |
+
kfdm/promgen
|
| 663 |
+
us-ignite/us_ignite
|
| 664 |
+
sassoftware/rbm
|
| 665 |
+
rutube/djonet
|
| 666 |
+
HKuz/Test_Code
|
| 667 |
+
Yelp/paasta
|
| 668 |
+
bogdal/freepacktbook
|
| 669 |
+
OpenMined/PySyft
|
| 670 |
+
daniell/django-import-export
|
| 671 |
+
opennode/nodeconductor
|
| 672 |
+
DataViva/dataviva-site
|
| 673 |
+
WalkingMachine/sara_behaviors
|
| 674 |
+
astronaut1712/taiga-back
|
| 675 |
+
laurentbristiel/robotframework-needle
|
| 676 |
+
mpirnat/django-tutorial-v2
|
| 677 |
+
brosner/django-notification
|
| 678 |
+
rsalmaso/django-allauth
|
| 679 |
+
zzz0072/Python_Exercises
|
| 680 |
+
Alweezy/alvin-mutisya-dojo-project
|
| 681 |
+
CAPU-ENG/CAPUHome-API
|
| 682 |
+
MoyTW/RL_Arena_Experiment
|
| 683 |
+
bowen0701/algorithms_data_structures
|
| 684 |
+
murphyke/avocado
|
| 685 |
+
praba230890/junction
|
| 686 |
+
yanqd0/csft
|
| 687 |
+
zimolzak/poker-experiments
|
| 688 |
+
eliran-stratoscale/rackattack-api
|
| 689 |
+
mrlolethan/MinecraftUsernameToUUID
|
| 690 |
+
OPWEN/opwen-webapp
|
| 691 |
+
uvNikita/appstats
|
| 692 |
+
cropleyb/pentai
|
| 693 |
+
gunthercox/ChatterBot
|
| 694 |
+
andburn/python-unitypack
|
| 695 |
+
PnEcrins/GeoNature
|
| 696 |
+
onepercentclub/bluebottle
|
| 697 |
+
summernote/django-summernote
|
| 698 |
+
zsiciarz/variablestars.net
|
| 699 |
+
manhhomienbienthuy/pythondotorg
|
| 700 |
+
Squareys/PyDDL
|
| 701 |
+
PatrikValkovic/grammpy
|
| 702 |
+
mitsuhiko/sentry
|
| 703 |
+
Clyde-fare/cclib_bak
|
| 704 |
+
andrewlin16/duckbot
|
| 705 |
+
weijia/djangoautoconf
|
| 706 |
+
BertrandBordage/django-terms
|
| 707 |
+
schwa-lab/dr-apps-python
|
| 708 |
+
ppb/ppb-vector
|
| 709 |
+
svetlyak40wt/python-cl-conditions
|
| 710 |
+
aman-iitj/scipy
|
| 711 |
+
MaxLikelihood/CODE
|
| 712 |
+
zhenzhai/edx-platform
|
| 713 |
+
lihui7115/ChromiumGStreamerBackend
|
| 714 |
+
cloudtools/troposphere
|
| 715 |
+
carsonmcdonald/glacier-cmd
|
| 716 |
+
gsnbng/erpnext
|
| 717 |
+
tm-kn/farmers-api
|
| 718 |
+
edx/ecommerce-api-client
|
| 719 |
+
DesertBus/txircd
|
| 720 |
+
e-mission/e-mission-server
|
| 721 |
+
wahuneke/django-stripe-payments
|
| 722 |
+
briansuhr/slowburn
|
| 723 |
+
GETLIMS/LIMS-Backend
|
| 724 |
+
robintw/scikit-image
|
| 725 |
+
it-projects-llc/website-addons
|
| 726 |
+
acgetchell/causal-sets-explorer
|
| 727 |
+
MarauderXtreme/sipa
|
| 728 |
+
CameronLonsdale/lantern
|
| 729 |
+
stan-dev/pystan
|
| 730 |
+
DigitalGlobe/gbdxtools
|
| 731 |
+
treyhunner/django-email-log
|
| 732 |
+
OCA/connector
|
| 733 |
+
open2c/cooltools
|
| 734 |
+
Schevo/kiwi
|
| 735 |
+
silas/rock
|
| 736 |
+
JohnVinyard/featureflow
|
| 737 |
+
umbc-hackafe/htcpcp
|
| 738 |
+
boluny/cray
|
| 739 |
+
DavidNorman/tensorflow
|
| 740 |
+
drougge/wwwwellpapp
|
| 741 |
+
Clinical-Genomics/scout
|
| 742 |
+
RNAcentral/rnacentral-webcode
|
| 743 |
+
ByteCommander/ChatExchange6
|
| 744 |
+
windmill/windmill
|
| 745 |
+
mcmontero/tinyAPI
|
| 746 |
+
jraede/dd-agent
|
| 747 |
+
WyohKnott/image-comparison-sources
|
| 748 |
+
jaraco/jaraco.logging
|
| 749 |
+
pgollakota/django-chartit
|
| 750 |
+
Frojd/wagtail-geo-widget
|
| 751 |
+
sunlightlabs/hanuman
|
| 752 |
+
jcarbaugh/django-wellknown
|
| 753 |
+
igordejanovic/parglare
|
| 754 |
+
iraquitan/udacity-fsnd-p4-conference-app
|
| 755 |
+
vintasoftware/django-role-permissions
|
| 756 |
+
j00bar/django-widgy
|
| 757 |
+
mayfield/cellulario
|
| 758 |
+
ghostwords/chameleon-crawler
|
| 759 |
+
YabinHu/miniflow
|
| 760 |
+
moyogo/fontbakery
|
| 761 |
+
chocopoche/mangopay2-python-sdk
|
| 762 |
+
jaraco/jaraco.classes
|
| 763 |
+
jitseniesen/spyder-memory-profiler
|
| 764 |
+
karan/TPB
|
| 765 |
+
shakib609/gitcloner
|
| 766 |
+
Daksh/sugar-toolkit-gtk3
|
| 767 |
+
weecology/mete-spatial
|
| 768 |
+
Secheron/compassion-switzerland
|
| 769 |
+
redice/graphite-web
|
| 770 |
+
DasIch/logbook
|
| 771 |
+
recklessromeo/otm-core
|
| 772 |
+
pabletos/Hubot-Warframe
|
| 773 |
+
nagareproject/core
|
| 774 |
+
fujita-shintaro/mkdocs
|
| 775 |
+
zsiciarz/pyaavso
|
| 776 |
+
openfisca/openfisca-tunisia
|
| 777 |
+
ISISComputingGroup/EPICS-inst_servers
|
| 778 |
+
emory-libraries/django-eultheme
|
| 779 |
+
hyperion-rt/hyperion
|
| 780 |
+
cardstack/cardstack
|
| 781 |
+
bltravis/django-alphabetfilter
|
| 782 |
+
zhangguiyu/django-hierarchical-auth
|
| 783 |
+
fmfi-svt-deadlock/hw-testing
|
| 784 |
+
spennihana/h2o-3
|
| 785 |
+
pastas/pasta
|
| 786 |
+
dkdndes/django-flatpages-example
|
| 787 |
+
p2pu/learning-circles
|
| 788 |
+
nikdoof/test-auth
|
| 789 |
+
vmalavolta/fabix
|
| 790 |
+
dtrip/.ubuntu
|
| 791 |
+
egenerat/flight-manager
|
| 792 |
+
robotenique/RandomAccessMemory
|
| 793 |
+
RDFLib/rdflib
|
| 794 |
+
pudo/storyweb
|
| 795 |
+
benjamindean/furi-kura
|
| 796 |
+
alphagov/ghtools
|
| 797 |
+
shad7/trakt.py
|
| 798 |
+
jaraco/hgtools
|
| 799 |
+
gbowerman/azurerm
|
| 800 |
+
sussman/zvm
|
memory_lora/codegraph.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""AST-based codebase graph representation.
|
| 3 |
+
|
| 4 |
+
New data representation beyond what the Code2LoRA paper used (raw file
|
| 5 |
+
chunks, mean+max pooled). This module extracts a STRUCTURAL summary of a
|
| 6 |
+
Python codebase -- imports (dependency edges between files), class
|
| 7 |
+
hierarchies, function/method signatures, and a best-effort call graph --
|
| 8 |
+
and serializes it into compact text sections. Those sections are fed
|
| 9 |
+
through the SAME frozen embedding pipeline as raw code
|
| 10 |
+
(``memory_lora.encoder.embed_document`` already accepts a list of
|
| 11 |
+
``(section_name, section_text)`` tuples), so a repository can be embedded
|
| 12 |
+
from BOTH its raw source text and its structural graph, without any
|
| 13 |
+
change to the encoder or hypernetwork.
|
| 14 |
+
|
| 15 |
+
Why this matters for "recall codebases": raw-text chunking captures
|
| 16 |
+
surface content (docstrings, comments, literal code) but dilutes the
|
| 17 |
+
signal that actually matters for API-level questions -- "what does
|
| 18 |
+
function X take", "what inherits from Y", "who imports Z". A compact
|
| 19 |
+
graph serialization puts that signal in a small number of dense tokens
|
| 20 |
+
instead of burying it across thousands of raw-code tokens.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
from __future__ import annotations
|
| 24 |
+
|
| 25 |
+
import ast
|
| 26 |
+
from dataclasses import dataclass, field
|
| 27 |
+
from pathlib import Path
|
| 28 |
+
from typing import Dict, List, Optional, Tuple
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@dataclass
|
| 32 |
+
class FunctionSig:
|
| 33 |
+
name: str
|
| 34 |
+
args: List[str]
|
| 35 |
+
returns: Optional[str]
|
| 36 |
+
is_method: bool = False
|
| 37 |
+
decorators: List[str] = field(default_factory=list)
|
| 38 |
+
calls: List[str] = field(default_factory=list) # best-effort, unresolved names
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
@dataclass
|
| 42 |
+
class ClassSig:
|
| 43 |
+
name: str
|
| 44 |
+
bases: List[str]
|
| 45 |
+
methods: List[FunctionSig] = field(default_factory=list)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
@dataclass
|
| 49 |
+
class FileGraph:
|
| 50 |
+
path: str
|
| 51 |
+
imports: List[str]
|
| 52 |
+
import_froms: List[Tuple[str, List[str]]] # (module, [names])
|
| 53 |
+
classes: List[ClassSig]
|
| 54 |
+
functions: List[FunctionSig] # module-level only
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def _annotation_to_str(node: Optional[ast.AST]) -> Optional[str]:
|
| 58 |
+
if node is None:
|
| 59 |
+
return None
|
| 60 |
+
try:
|
| 61 |
+
return ast.unparse(node)
|
| 62 |
+
except Exception: # noqa: BLE001
|
| 63 |
+
return None
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def _arg_to_str(a: ast.arg) -> str:
|
| 67 |
+
ann = _annotation_to_str(a.annotation)
|
| 68 |
+
return f"{a.arg}: {ann}" if ann else a.arg
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def _extract_calls(node: ast.AST) -> List[str]:
|
| 72 |
+
calls = []
|
| 73 |
+
for n in ast.walk(node):
|
| 74 |
+
if isinstance(n, ast.Call):
|
| 75 |
+
f = n.func
|
| 76 |
+
if isinstance(f, ast.Name):
|
| 77 |
+
calls.append(f.id)
|
| 78 |
+
elif isinstance(f, ast.Attribute):
|
| 79 |
+
calls.append(f.attr)
|
| 80 |
+
# dedupe, keep order
|
| 81 |
+
seen = set()
|
| 82 |
+
out = []
|
| 83 |
+
for c in calls:
|
| 84 |
+
if c not in seen:
|
| 85 |
+
seen.add(c)
|
| 86 |
+
out.append(c)
|
| 87 |
+
return out[:20] # cap -- this is a signal, not a full trace
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def _function_sig(node, is_method: bool = False) -> FunctionSig:
|
| 91 |
+
args = [_arg_to_str(a) for a in node.args.args]
|
| 92 |
+
returns = _annotation_to_str(node.returns)
|
| 93 |
+
decorators = [_annotation_to_str(d) or "" for d in node.decorator_list]
|
| 94 |
+
return FunctionSig(
|
| 95 |
+
name=node.name, args=args, returns=returns, is_method=is_method,
|
| 96 |
+
decorators=[d for d in decorators if d], calls=_extract_calls(node),
|
| 97 |
+
)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def extract_file_graph(source: str, path: str) -> Optional[FileGraph]:
|
| 101 |
+
"""Parse one Python file's source into a :class:`FileGraph`.
|
| 102 |
+
Returns None on a syntax error (skip the file, don't crash the repo)."""
|
| 103 |
+
try:
|
| 104 |
+
tree = ast.parse(source)
|
| 105 |
+
except (SyntaxError, ValueError):
|
| 106 |
+
return None
|
| 107 |
+
|
| 108 |
+
imports: List[str] = []
|
| 109 |
+
import_froms: List[Tuple[str, List[str]]] = []
|
| 110 |
+
classes: List[ClassSig] = []
|
| 111 |
+
functions: List[FunctionSig] = []
|
| 112 |
+
|
| 113 |
+
for node in ast.iter_child_nodes(tree):
|
| 114 |
+
if isinstance(node, ast.Import):
|
| 115 |
+
imports.extend(a.name for a in node.names)
|
| 116 |
+
elif isinstance(node, ast.ImportFrom):
|
| 117 |
+
mod = node.module or ("." * node.level)
|
| 118 |
+
import_froms.append((mod, [a.name for a in node.names]))
|
| 119 |
+
elif isinstance(node, ast.ClassDef):
|
| 120 |
+
bases = [_annotation_to_str(b) or "?" for b in node.bases]
|
| 121 |
+
methods = [
|
| 122 |
+
_function_sig(n, is_method=True)
|
| 123 |
+
for n in node.body
|
| 124 |
+
if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))
|
| 125 |
+
]
|
| 126 |
+
classes.append(ClassSig(name=node.name, bases=bases, methods=methods))
|
| 127 |
+
elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
| 128 |
+
functions.append(_function_sig(node, is_method=False))
|
| 129 |
+
|
| 130 |
+
return FileGraph(path=path, imports=imports, import_froms=import_froms,
|
| 131 |
+
classes=classes, functions=functions)
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def serialize_file_graph(g: FileGraph) -> str:
|
| 135 |
+
"""Compact text serialization -- dense signature summary, not prose."""
|
| 136 |
+
lines = [f"# {g.path}"]
|
| 137 |
+
if g.imports:
|
| 138 |
+
lines.append("imports: " + ", ".join(g.imports))
|
| 139 |
+
for mod, names in g.import_froms:
|
| 140 |
+
lines.append(f"from {mod} import " + ", ".join(names))
|
| 141 |
+
for c in g.classes:
|
| 142 |
+
base_str = f"({', '.join(c.bases)})" if c.bases else ""
|
| 143 |
+
lines.append(f"class {c.name}{base_str}:")
|
| 144 |
+
for m in c.methods:
|
| 145 |
+
dec = "".join(f"@{d} " for d in m.decorators)
|
| 146 |
+
args = ", ".join(m.args)
|
| 147 |
+
ret = f" -> {m.returns}" if m.returns else ""
|
| 148 |
+
calls = f" # calls: {', '.join(m.calls[:6])}" if m.calls else ""
|
| 149 |
+
lines.append(f" {dec}def {m.name}({args}){ret}{calls}")
|
| 150 |
+
for fn in g.functions:
|
| 151 |
+
dec = "".join(f"@{d} " for d in fn.decorators)
|
| 152 |
+
args = ", ".join(fn.args)
|
| 153 |
+
ret = f" -> {fn.returns}" if fn.returns else ""
|
| 154 |
+
calls = f" # calls: {', '.join(fn.calls[:6])}" if fn.calls else ""
|
| 155 |
+
lines.append(f"{dec}def {fn.name}({args}){ret}{calls}")
|
| 156 |
+
return "\n".join(lines)
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
def extract_repo_graph_sections(
|
| 160 |
+
repo_dir: Path, max_files: int = 200, skip_dirs: Optional[set] = None,
|
| 161 |
+
) -> List[Tuple[str, str]]:
|
| 162 |
+
"""Walk a repo, extract + serialize each .py file's structural graph.
|
| 163 |
+
Returns ``[(section_name, section_text), ...]`` -- directly usable as
|
| 164 |
+
the ``sections`` argument to ``memory_lora.encoder.embed_document``,
|
| 165 |
+
alongside (or instead of) raw-text sections.
|
| 166 |
+
"""
|
| 167 |
+
skip_dirs = skip_dirs or {".git", "__pycache__", ".venv", "venv", "node_modules",
|
| 168 |
+
"build", "dist", ".tox", ".mypy_cache"}
|
| 169 |
+
sections: List[Tuple[str, str]] = []
|
| 170 |
+
n = 0
|
| 171 |
+
for path in sorted(repo_dir.rglob("*.py")):
|
| 172 |
+
if any(part in skip_dirs for part in path.parts):
|
| 173 |
+
continue
|
| 174 |
+
try:
|
| 175 |
+
source = path.read_text(encoding="utf-8", errors="ignore")
|
| 176 |
+
except OSError:
|
| 177 |
+
continue
|
| 178 |
+
rel = str(path.relative_to(repo_dir))
|
| 179 |
+
g = extract_file_graph(source, rel)
|
| 180 |
+
if g is None:
|
| 181 |
+
continue
|
| 182 |
+
if not (g.imports or g.import_froms or g.classes or g.functions):
|
| 183 |
+
continue # empty file, no structural signal
|
| 184 |
+
sections.append((f"graph:{rel}", serialize_file_graph(g)))
|
| 185 |
+
n += 1
|
| 186 |
+
if n >= max_files:
|
| 187 |
+
break
|
| 188 |
+
return sections
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
def extract_repo_dependency_summary(repo_dir: Path, skip_dirs: Optional[set] = None) -> str:
|
| 192 |
+
"""One dense paragraph: which files import which other in-repo modules.
|
| 193 |
+
A cheap approximation of a dependency graph edge list, useful as a
|
| 194 |
+
single extra section capturing repo-wide (not per-file) structure."""
|
| 195 |
+
skip_dirs = skip_dirs or {".git", "__pycache__", ".venv", "venv", "node_modules"}
|
| 196 |
+
edges: List[str] = []
|
| 197 |
+
module_names = set()
|
| 198 |
+
files = [p for p in repo_dir.rglob("*.py") if not any(part in skip_dirs for part in p.parts)]
|
| 199 |
+
for p in files:
|
| 200 |
+
mod = str(p.relative_to(repo_dir)).replace("/", ".").removesuffix(".py")
|
| 201 |
+
module_names.add(mod)
|
| 202 |
+
|
| 203 |
+
for p in files:
|
| 204 |
+
try:
|
| 205 |
+
source = p.read_text(encoding="utf-8", errors="ignore")
|
| 206 |
+
tree = ast.parse(source)
|
| 207 |
+
except (SyntaxError, ValueError, OSError):
|
| 208 |
+
continue
|
| 209 |
+
rel = str(p.relative_to(repo_dir))
|
| 210 |
+
for node in ast.walk(tree):
|
| 211 |
+
if isinstance(node, ast.ImportFrom) and node.module:
|
| 212 |
+
if node.module in module_names or any(m.startswith(node.module + ".") for m in module_names):
|
| 213 |
+
edges.append(f"{rel} -> {node.module}")
|
| 214 |
+
return "dependency edges:\n" + "\n".join(edges[:300]) if edges else ""
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
__all__ = [
|
| 218 |
+
"FunctionSig", "ClassSig", "FileGraph",
|
| 219 |
+
"extract_file_graph", "serialize_file_graph",
|
| 220 |
+
"extract_repo_graph_sections", "extract_repo_dependency_summary",
|
| 221 |
+
]
|
memory_lora/core.py
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Shared building blocks for the Memory-LoRA hypernetwork.
|
| 3 |
+
|
| 4 |
+
Forked from Code2LoRA's ``hypernetwork/code2lora_core.py`` (Hotsko et al.,
|
| 5 |
+
"Code2LoRA: Hypernetwork-Generated Adapters for Code Language Models under
|
| 6 |
+
Software Evolution", MIT-licensed code release). Same core trick, different
|
| 7 |
+
target model and conditioning input:
|
| 8 |
+
|
| 9 |
+
* Code2LoRA: repository embedding -> LoRA adapter for Qwen2.5-Coder-1.5B
|
| 10 |
+
* Memory-LoRA: document embedding -> LoRA adapter for google/gemma-4-E2B
|
| 11 |
+
|
| 12 |
+
The ``MemoryLoRAHead`` (renamed from ``Code2LoRAHead``, architecture
|
| 13 |
+
unchanged) outputs ONE (A, B) pair per LoRA module *type* (q_proj, k_proj,
|
| 14 |
+
v_proj, o_proj, gate_proj, up_proj, down_proj), shared across every target
|
| 15 |
+
transformer layer -- not per-layer. This keeps the head's parameter count
|
| 16 |
+
tractable for local (MPS) training.
|
| 17 |
+
|
| 18 |
+
Gemma-4-E2B specifics (verified against the model's actual safetensors
|
| 19 |
+
header, not guessed):
|
| 20 |
+
|
| 21 |
+
* Decoder is nested at ``model.language_model.layers.{i}.*`` -- NOT
|
| 22 |
+
``model.layers.{i}.*`` like Qwen2.5-Coder. ``get_module_specs`` below
|
| 23 |
+
matches on ``language_model\\.layers\\.(\\d+)\\.``, not ``model\\.layers``.
|
| 24 |
+
* Module type names are identical to Code2LoRA's defaults:
|
| 25 |
+
q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj.
|
| 26 |
+
* Only ``model.language_model.*`` is ever touched. ``vision_tower`` and
|
| 27 |
+
``audio_tower`` are left completely alone -- irrelevant to text recall and
|
| 28 |
+
risky to perturb.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
from __future__ import annotations
|
| 32 |
+
|
| 33 |
+
import math
|
| 34 |
+
import re
|
| 35 |
+
from dataclasses import dataclass
|
| 36 |
+
from pathlib import Path
|
| 37 |
+
from typing import Any, Dict, List, Optional, Tuple
|
| 38 |
+
|
| 39 |
+
import numpy as np
|
| 40 |
+
import pyarrow as pa
|
| 41 |
+
import pyarrow.compute as pc
|
| 42 |
+
import pyarrow.dataset as pads
|
| 43 |
+
import torch
|
| 44 |
+
import torch.nn as nn
|
| 45 |
+
import torch.nn.functional as F
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
# ---------------------------------------------------------------------------
|
| 49 |
+
# LoRA module + injection (unchanged from Code2LoRA -- architecture-agnostic)
|
| 50 |
+
# ---------------------------------------------------------------------------
|
| 51 |
+
|
| 52 |
+
class LoRA(nn.Module):
|
| 53 |
+
"""Wraps an ``nn.Linear`` with an additive low-rank update.
|
| 54 |
+
|
| 55 |
+
Forward: ``y = base(x) + scaling * (x @ A^T) @ B^T``, where per-batch
|
| 56 |
+
A: ``[rank, in_features]`` and B: ``[out_features, rank]`` come from an
|
| 57 |
+
external hypernet via :meth:`set_lora_weights`.
|
| 58 |
+
|
| 59 |
+
IMPORTANT autograd contract: A and B are kept as **plain attributes**,
|
| 60 |
+
not buffers, and stored **without detaching**, so the LM loss's backward
|
| 61 |
+
graph flows through them straight into the hypernet parameters that
|
| 62 |
+
produced them. The base ``nn.Linear`` is frozen and its forward sees a
|
| 63 |
+
detached copy of the input to avoid building an autograd graph through
|
| 64 |
+
the (much larger) frozen LLM weights.
|
| 65 |
+
"""
|
| 66 |
+
|
| 67 |
+
def __init__(self, base: nn.Linear, in_features: int, out_features: int,
|
| 68 |
+
rank: int, alpha: float):
|
| 69 |
+
super().__init__()
|
| 70 |
+
self.base = base
|
| 71 |
+
for p in self.base.parameters():
|
| 72 |
+
p.requires_grad = False
|
| 73 |
+
self.in_features = in_features
|
| 74 |
+
self.out_features = out_features
|
| 75 |
+
self.rank = rank
|
| 76 |
+
self.scaling = float(alpha) / float(max(1, rank))
|
| 77 |
+
self.A: Optional[torch.Tensor] = None # [rank, in_features]
|
| 78 |
+
self.B: Optional[torch.Tensor] = None # [out_features, rank]
|
| 79 |
+
|
| 80 |
+
def set_lora_weights(self, A: torch.Tensor, B: torch.Tensor) -> None:
|
| 81 |
+
self.A = A
|
| 82 |
+
self.B = B
|
| 83 |
+
|
| 84 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 85 |
+
y = self.base(x)
|
| 86 |
+
if self.A is None or self.B is None:
|
| 87 |
+
return y
|
| 88 |
+
x_f32 = x.detach().to(torch.float32)
|
| 89 |
+
A = self.A.to(torch.float32)
|
| 90 |
+
B = self.B.to(torch.float32)
|
| 91 |
+
delta = F.linear(F.linear(x_f32, A), B) * self.scaling
|
| 92 |
+
return y + delta.to(dtype=y.dtype)
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
@dataclass
|
| 96 |
+
class ModuleSpec:
|
| 97 |
+
full_name: str # e.g. 'model.language_model.layers.5.self_attn.q_proj'
|
| 98 |
+
layer_idx: int
|
| 99 |
+
type: str # e.g. 'q_proj'
|
| 100 |
+
in_features: int
|
| 101 |
+
out_features: int
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
# Gemma-4-E2B nests its text decoder here (verified via safetensors header).
|
| 105 |
+
DEFAULT_ROOT_PREFIX = "model.language_model."
|
| 106 |
+
_LAYER_IDX_RE = re.compile(r"\blanguage_model\.layers\.(\d+)\.")
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def get_module_specs(model: nn.Module, target_module_types: List[str],
|
| 110 |
+
root_prefix: str = DEFAULT_ROOT_PREFIX
|
| 111 |
+
) -> List[ModuleSpec]:
|
| 112 |
+
"""Discover every nn.Linear under ``root_prefix`` whose name contains one
|
| 113 |
+
of ``target_module_types`` and return one :class:`ModuleSpec` per match,
|
| 114 |
+
sorted by (layer_idx, full_name).
|
| 115 |
+
|
| 116 |
+
Restricting to ``root_prefix`` is what keeps ``vision_tower`` /
|
| 117 |
+
``audio_tower`` untouched even though they also contain q_proj/k_proj/
|
| 118 |
+
v_proj/o_proj-named linears.
|
| 119 |
+
|
| 120 |
+
Gemma-4-E2B is architecturally heterogeneous across layers (unlike
|
| 121 |
+
Qwen2.5-Coder, which Code2LoRA was built for): every 5th layer is a
|
| 122 |
+
wider "full_attention" layer (q_proj/o_proj 2x the width of the
|
| 123 |
+
"sliding_attention" layers), and 20 of the 35 layers have NO k_proj/
|
| 124 |
+
v_proj at all -- they reuse an earlier layer's KV cache
|
| 125 |
+
(``num_kv_shared_layers=20`` in the model config). A LoRA (A, B) pair
|
| 126 |
+
can only be shared across modules of IDENTICAL shape, so ``.type`` here
|
| 127 |
+
is ``"{module_name}_{in}x{out}"`` (shape-qualified), not just the raw
|
| 128 |
+
module name -- e.g. ``"q_proj_1536x2048"`` vs ``"q_proj_1536x4096"``
|
| 129 |
+
end up as distinct hypernetwork output heads. Layers with no matching
|
| 130 |
+
module (e.g. k_proj on a KV-shared layer) simply produce no spec for
|
| 131 |
+
that layer, which is architecturally correct: there is nothing to
|
| 132 |
+
adapt there since that layer never computes its own K/V.
|
| 133 |
+
"""
|
| 134 |
+
specs: List[ModuleSpec] = []
|
| 135 |
+
for name, m in model.named_modules():
|
| 136 |
+
if root_prefix and not name.startswith(root_prefix):
|
| 137 |
+
continue
|
| 138 |
+
match_type = next(
|
| 139 |
+
(t for t in target_module_types if t in name), None
|
| 140 |
+
)
|
| 141 |
+
if match_type is None:
|
| 142 |
+
continue
|
| 143 |
+
if not isinstance(m, nn.Linear):
|
| 144 |
+
continue
|
| 145 |
+
m_layer = _LAYER_IDX_RE.search(name)
|
| 146 |
+
layer_idx = int(m_layer.group(1)) if m_layer else -1
|
| 147 |
+
shape_qualified_type = f"{match_type}_{m.in_features}x{m.out_features}"
|
| 148 |
+
specs.append(ModuleSpec(
|
| 149 |
+
full_name=name,
|
| 150 |
+
layer_idx=layer_idx,
|
| 151 |
+
type=shape_qualified_type,
|
| 152 |
+
in_features=int(m.in_features),
|
| 153 |
+
out_features=int(m.out_features),
|
| 154 |
+
))
|
| 155 |
+
specs.sort(key=lambda s: (s.layer_idx, s.full_name))
|
| 156 |
+
return specs
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
def replace_with_lora(model: nn.Module, specs: List[ModuleSpec],
|
| 160 |
+
rank: int, alpha: float) -> None:
|
| 161 |
+
"""Replace each target ``nn.Linear`` in ``model`` with a :class:`LoRA`
|
| 162 |
+
wrapper. Idempotent."""
|
| 163 |
+
named = dict(model.named_modules())
|
| 164 |
+
device = next(model.parameters()).device
|
| 165 |
+
dtype = next(model.parameters()).dtype
|
| 166 |
+
for sp in specs:
|
| 167 |
+
parent_name, attr = sp.full_name.rsplit(".", 1)
|
| 168 |
+
orig = getattr(named[parent_name], attr)
|
| 169 |
+
if isinstance(orig, LoRA):
|
| 170 |
+
continue
|
| 171 |
+
assert isinstance(orig, nn.Linear), \
|
| 172 |
+
f"{sp.full_name} is not nn.Linear (got {type(orig)})"
|
| 173 |
+
wrapped = LoRA(orig, sp.in_features, sp.out_features,
|
| 174 |
+
rank, alpha).to(device=device, dtype=dtype)
|
| 175 |
+
setattr(named[parent_name], attr, wrapped)
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def inject_lora_weights(model: nn.Module, specs: List[ModuleSpec],
|
| 179 |
+
head_out: Dict[str, Dict[str, torch.Tensor]],
|
| 180 |
+
batch_index: int = 0) -> None:
|
| 181 |
+
"""Push ``head_out["A"][type]`` and ``head_out["B"][type]`` into the
|
| 182 |
+
wrapper :class:`LoRA` modules for every spec sharing that type."""
|
| 183 |
+
A_by_type = head_out["A"]
|
| 184 |
+
B_by_type = head_out["B"]
|
| 185 |
+
named = dict(model.named_modules())
|
| 186 |
+
for sp in specs:
|
| 187 |
+
named[sp.full_name].set_lora_weights(
|
| 188 |
+
A_by_type[sp.type][batch_index],
|
| 189 |
+
B_by_type[sp.type][batch_index],
|
| 190 |
+
)
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
def discover_module_types_and_dims(specs: List[ModuleSpec]
|
| 194 |
+
) -> Dict[str, Tuple[int, int]]:
|
| 195 |
+
"""Return {type_name: (in_features, out_features)} -- one entry per
|
| 196 |
+
target module type. Assumes all instances of the same type share dims."""
|
| 197 |
+
type_dims: Dict[str, Tuple[int, int]] = {}
|
| 198 |
+
for sp in specs:
|
| 199 |
+
if sp.type in type_dims:
|
| 200 |
+
assert type_dims[sp.type] == (sp.in_features, sp.out_features), \
|
| 201 |
+
f"type {sp.type} appears with inconsistent dims"
|
| 202 |
+
continue
|
| 203 |
+
type_dims[sp.type] = (sp.in_features, sp.out_features)
|
| 204 |
+
return type_dims
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
# ---------------------------------------------------------------------------
|
| 208 |
+
# Shared LoRA generation head (= Code2LoRAHead, renamed; architecture unchanged)
|
| 209 |
+
# ---------------------------------------------------------------------------
|
| 210 |
+
|
| 211 |
+
class MemoryLoRAHead(nn.Module):
|
| 212 |
+
"""Maps a document-context embedding to a LoRA adapter in one forward
|
| 213 |
+
pass.
|
| 214 |
+
|
| 215 |
+
Input : ctx ``[B, input_dim]`` -- a single document embedding.
|
| 216 |
+
Output : ``{"A": {type: [B, rank, in_f]}, "B": {type: [B, out_f, rank]}}``,
|
| 217 |
+
one (A, B) pair per LoRA module *type*, shared across all
|
| 218 |
+
target transformer layers.
|
| 219 |
+
|
| 220 |
+
Args:
|
| 221 |
+
input_dim : Context-vector dim (2048, matches the Qwen3-Embedding
|
| 222 |
+
weighted-mean + max-pool concat from ``encoder.py``).
|
| 223 |
+
type_dims : ``{type: (in_features, out_features)}`` for each LoRA
|
| 224 |
+
module type (q_proj, v_proj, gate_proj, ...).
|
| 225 |
+
hidden_dim : Trunk hidden dimension. Default 128 -- deliberately
|
| 226 |
+
small: with only ~165 training documents (~3K QA
|
| 227 |
+
pairs), a 745M-param head (hidden_dim=512, the
|
| 228 |
+
original default) overfits within ~2 epochs (train
|
| 229 |
+
loss -> 0.4 while held-out cr_val/cr_test loss rises
|
| 230 |
+
from ~1.9 to ~2.7). hidden_dim=128 cuts head size
|
| 231 |
+
roughly 4x; combine with --head-dropout and higher
|
| 232 |
+
weight decay for further regularization.
|
| 233 |
+
rank : LoRA rank ``r``.
|
| 234 |
+
init_log_scale : Initial log-scale for tanh squashing. -3.5 gives
|
| 235 |
+
output magnitudes ~0.03 at init -> tiny LoRA delta.
|
| 236 |
+
dropout : Dropout applied after each trunk GELU. 0.0 (paper's
|
| 237 |
+
original setting) had no regularization at all;
|
| 238 |
+
nonzero here specifically to counter the overfitting
|
| 239 |
+
observed on this project's much smaller corpus.
|
| 240 |
+
"""
|
| 241 |
+
|
| 242 |
+
def __init__(
|
| 243 |
+
self,
|
| 244 |
+
input_dim: int,
|
| 245 |
+
type_dims: Dict[str, Tuple[int, int]],
|
| 246 |
+
hidden_dim: int = 128,
|
| 247 |
+
rank: int = 16,
|
| 248 |
+
init_log_scale: float = -3.5,
|
| 249 |
+
dropout: float = 0.1,
|
| 250 |
+
):
|
| 251 |
+
super().__init__()
|
| 252 |
+
self.input_dim = input_dim
|
| 253 |
+
self.hidden_dim = hidden_dim
|
| 254 |
+
self.rank = rank
|
| 255 |
+
self.dropout = dropout
|
| 256 |
+
self.type_dims = dict(type_dims)
|
| 257 |
+
self.types = sorted(type_dims.keys())
|
| 258 |
+
|
| 259 |
+
self.trunk = nn.Sequential(
|
| 260 |
+
nn.Linear(input_dim, hidden_dim),
|
| 261 |
+
nn.GELU(),
|
| 262 |
+
nn.Dropout(dropout),
|
| 263 |
+
nn.Linear(hidden_dim, hidden_dim),
|
| 264 |
+
nn.GELU(),
|
| 265 |
+
nn.Dropout(dropout),
|
| 266 |
+
)
|
| 267 |
+
|
| 268 |
+
self.heads_A = nn.ModuleDict({
|
| 269 |
+
t: nn.Linear(hidden_dim, rank * type_dims[t][0])
|
| 270 |
+
for t in self.types
|
| 271 |
+
})
|
| 272 |
+
self.heads_B = nn.ModuleDict({
|
| 273 |
+
t: nn.Linear(hidden_dim, type_dims[t][1] * rank)
|
| 274 |
+
for t in self.types
|
| 275 |
+
})
|
| 276 |
+
self.log_scale_A = nn.ParameterDict({
|
| 277 |
+
t: nn.Parameter(torch.tensor(init_log_scale)) for t in self.types
|
| 278 |
+
})
|
| 279 |
+
self.log_scale_B = nn.ParameterDict({
|
| 280 |
+
t: nn.Parameter(torch.tensor(init_log_scale)) for t in self.types
|
| 281 |
+
})
|
| 282 |
+
|
| 283 |
+
def forward(self, ctx: torch.Tensor) -> Dict[str, Dict[str, torch.Tensor]]:
|
| 284 |
+
if ctx.dim() == 3:
|
| 285 |
+
ctx = torch.max(ctx, dim=1).values
|
| 286 |
+
h = self.trunk(ctx.float())
|
| 287 |
+
h = F.normalize(h, p=2, dim=-1) * math.sqrt(self.hidden_dim)
|
| 288 |
+
|
| 289 |
+
A_out: Dict[str, torch.Tensor] = {}
|
| 290 |
+
B_out: Dict[str, torch.Tensor] = {}
|
| 291 |
+
for t in self.types:
|
| 292 |
+
in_f, out_f = self.type_dims[t]
|
| 293 |
+
A_raw = self.heads_A[t](h).view(-1, self.rank, in_f)
|
| 294 |
+
B_raw = self.heads_B[t](h).view(-1, out_f, self.rank)
|
| 295 |
+
scale_A = torch.exp(self.log_scale_A[t]).clamp(1e-5, 0.3)
|
| 296 |
+
scale_B = torch.exp(self.log_scale_B[t]).clamp(1e-5, 0.3)
|
| 297 |
+
A_out[t] = torch.tanh(A_raw) * scale_A
|
| 298 |
+
B_out[t] = torch.tanh(B_raw) * scale_B
|
| 299 |
+
return {"A": A_out, "B": B_out}
|
| 300 |
+
|
| 301 |
+
def config_dict(self) -> Dict[str, Any]:
|
| 302 |
+
return {
|
| 303 |
+
"input_dim": self.input_dim,
|
| 304 |
+
"hidden_dim": self.hidden_dim,
|
| 305 |
+
"rank": self.rank,
|
| 306 |
+
"dropout": self.dropout,
|
| 307 |
+
"types": self.types,
|
| 308 |
+
"type_dims": {t: list(v) for t, v in self.type_dims.items()},
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
# ---------------------------------------------------------------------------
|
| 313 |
+
# Parquet loaders -- documents + recall QA pairs
|
| 314 |
+
# ---------------------------------------------------------------------------
|
| 315 |
+
|
| 316 |
+
def _list_to_f32_array(col, dim: int) -> np.ndarray:
|
| 317 |
+
"""Vectorized fixed-width-list -> ndarray. The naive per-row Python
|
| 318 |
+
loop (``for i, v in enumerate(col.to_pylist()): out[i] = v``) does
|
| 319 |
+
dim * n_rows individual scalar assignments in pure Python -- fine at
|
| 320 |
+
~200 rows, but at real-corpus scale (74K rows x 2048 dims = 151M
|
| 321 |
+
scalar ops) it single-handedly took 5+ minutes just to load
|
| 322 |
+
embeddings before training could even start. pyarrow's own flatten()
|
| 323 |
+
+ numpy reshape does the same conversion in C.
|
| 324 |
+
"""
|
| 325 |
+
if len(col) == 0:
|
| 326 |
+
return np.zeros((0, dim), dtype=np.float32)
|
| 327 |
+
flat = col.combine_chunks().flatten() if hasattr(col, "combine_chunks") else col.flatten()
|
| 328 |
+
arr = flat.to_numpy(zero_copy_only=False).astype(np.float32, copy=False)
|
| 329 |
+
return arr.reshape(len(col), dim)
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
@dataclass
|
| 333 |
+
class DocRow:
|
| 334 |
+
doc_id: str
|
| 335 |
+
doc_version: str # constant "v1" for static (non-evolving) docs
|
| 336 |
+
split: str # "train" | "cr_val" | "cr_test" (cross-corpus)
|
| 337 |
+
doc_embedding: np.ndarray # fp32 [2048]
|
| 338 |
+
|
| 339 |
+
|
| 340 |
+
@dataclass
|
| 341 |
+
class QnaRow:
|
| 342 |
+
doc_id: str
|
| 343 |
+
doc_version: str
|
| 344 |
+
split: str # cross-corpus split, inherited from DocRow
|
| 345 |
+
qna_split: str # "train" | "held_out" (in-corpus split)
|
| 346 |
+
question: str
|
| 347 |
+
prefix: str
|
| 348 |
+
target: str
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
def load_doc_rows(parquet_path: Path,
|
| 352 |
+
splits: Optional[List[str]] = None,
|
| 353 |
+
embedding_col: str = "doc_embedding",
|
| 354 |
+
) -> List[DocRow]:
|
| 355 |
+
needed = ["doc_id", "doc_version", "split", embedding_col]
|
| 356 |
+
ds = pads.dataset(str(parquet_path), format="parquet")
|
| 357 |
+
flt = None
|
| 358 |
+
if splits:
|
| 359 |
+
flt = pc.is_in(pads.field("split"),
|
| 360 |
+
value_set=pa.array(splits, type=pa.string()))
|
| 361 |
+
table = ds.to_table(columns=needed, filter=flt)
|
| 362 |
+
n = table.num_rows
|
| 363 |
+
if n == 0:
|
| 364 |
+
return []
|
| 365 |
+
dim = len(table.column(embedding_col)[0].as_py())
|
| 366 |
+
embs = _list_to_f32_array(table.column(embedding_col), dim)
|
| 367 |
+
doc_col = table.column("doc_id").to_pylist()
|
| 368 |
+
ver_col = table.column("doc_version").to_pylist()
|
| 369 |
+
split_col = table.column("split").to_pylist()
|
| 370 |
+
rows: List[DocRow] = []
|
| 371 |
+
for i in range(n):
|
| 372 |
+
rows.append(DocRow(
|
| 373 |
+
doc_id=doc_col[i], doc_version=ver_col[i],
|
| 374 |
+
split=split_col[i] or "",
|
| 375 |
+
doc_embedding=embs[i],
|
| 376 |
+
))
|
| 377 |
+
return rows
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
def load_qna_rows(jsonl_path: Path,
|
| 381 |
+
splits: Optional[List[str]] = None,
|
| 382 |
+
qna_splits: Optional[List[str]] = None,
|
| 383 |
+
doc_ids: Optional[List[str]] = None,
|
| 384 |
+
) -> List[QnaRow]:
|
| 385 |
+
"""QnA pairs are written as JSONL by ``generate_synthetic_dataset.py``
|
| 386 |
+
(one row per line, cheap to append incrementally during generation) --
|
| 387 |
+
unlike doc embeddings, which are batch-written parquet. Filters are
|
| 388 |
+
applied in Python; at the scale of this project (low thousands of rows)
|
| 389 |
+
that's simpler and fast enough."""
|
| 390 |
+
import json as _json
|
| 391 |
+
|
| 392 |
+
splits_set = set(splits) if splits else None
|
| 393 |
+
qna_splits_set = set(qna_splits) if qna_splits else None
|
| 394 |
+
doc_ids_set = set(doc_ids) if doc_ids else None
|
| 395 |
+
|
| 396 |
+
rows: List[QnaRow] = []
|
| 397 |
+
with open(jsonl_path) as f:
|
| 398 |
+
for line in f:
|
| 399 |
+
line = line.strip()
|
| 400 |
+
if not line:
|
| 401 |
+
continue
|
| 402 |
+
d = _json.loads(line)
|
| 403 |
+
if splits_set and d.get("split") not in splits_set:
|
| 404 |
+
continue
|
| 405 |
+
if qna_splits_set and d.get("qna_split") not in qna_splits_set:
|
| 406 |
+
continue
|
| 407 |
+
if doc_ids_set and d.get("doc_id") not in doc_ids_set:
|
| 408 |
+
continue
|
| 409 |
+
rows.append(QnaRow(
|
| 410 |
+
doc_id=d.get("doc_id", ""),
|
| 411 |
+
doc_version=d.get("doc_version", "v1"),
|
| 412 |
+
split=d.get("split", ""),
|
| 413 |
+
qna_split=d.get("qna_split", ""),
|
| 414 |
+
question=d.get("question", ""),
|
| 415 |
+
prefix=d.get("prefix", ""),
|
| 416 |
+
target=d.get("target", ""),
|
| 417 |
+
))
|
| 418 |
+
return rows
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
__all__ = [
|
| 422 |
+
"LoRA",
|
| 423 |
+
"ModuleSpec",
|
| 424 |
+
"DEFAULT_ROOT_PREFIX",
|
| 425 |
+
"get_module_specs",
|
| 426 |
+
"replace_with_lora",
|
| 427 |
+
"inject_lora_weights",
|
| 428 |
+
"discover_module_types_and_dims",
|
| 429 |
+
"MemoryLoRAHead",
|
| 430 |
+
"DocRow",
|
| 431 |
+
"QnaRow",
|
| 432 |
+
"load_doc_rows",
|
| 433 |
+
"load_qna_rows",
|
| 434 |
+
]
|
memory_lora/data_paths.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Local data path resolution for Memory-LoRA.
|
| 3 |
+
|
| 4 |
+
Unlike Code2LoRA's ``data_paths.py`` (which lazily ``snapshot_download``s from
|
| 5 |
+
the ``code2lora/`` HF org), everything here is generated locally via
|
| 6 |
+
OpenRouter and never leaves the machine unless the user chooses to publish
|
| 7 |
+
it -- so this just resolves to ``<repo_root>/data/``.
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
from __future__ import annotations
|
| 11 |
+
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
| 15 |
+
DATA_ROOT = REPO_ROOT / "data"
|
| 16 |
+
|
| 17 |
+
DOCS_DIR = DATA_ROOT / "docs" # raw generated documents (jsonl)
|
| 18 |
+
EMBEDDINGS_DIR = DATA_ROOT / "embeddings" # doc embeddings parquet
|
| 19 |
+
QNA_DIR = DATA_ROOT / "qna" # recall QA pairs parquet
|
| 20 |
+
CACHE_DIR = DATA_ROOT / "openrouter_cache" # raw OpenRouter responses, keyed by prompt hash
|
| 21 |
+
RUNS_DIR = REPO_ROOT / "runs" # training checkpoints + metrics
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def ensure_dirs() -> None:
|
| 25 |
+
for d in (DOCS_DIR, EMBEDDINGS_DIR, QNA_DIR, CACHE_DIR, RUNS_DIR):
|
| 26 |
+
d.mkdir(parents=True, exist_ok=True)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
__all__ = [
|
| 30 |
+
"REPO_ROOT", "DATA_ROOT", "DOCS_DIR", "EMBEDDINGS_DIR", "QNA_DIR",
|
| 31 |
+
"CACHE_DIR", "RUNS_DIR", "ensure_dirs",
|
| 32 |
+
]
|
memory_lora/encoder.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Frozen document encoder for the Memory-LoRA hypernetwork.
|
| 3 |
+
|
| 4 |
+
Forked from Code2LoRA's ``create_dataset/embed_repos.py`` chunk/pool
|
| 5 |
+
pipeline (mean-pool chunks -> file vector -> weighted-mean+max repo vector),
|
| 6 |
+
retargeted from "repo files" to "document sections":
|
| 7 |
+
|
| 8 |
+
* Code2LoRA: file_i -> chunks -> mean-pool -> file vector
|
| 9 |
+
repo -> weighted-mean+max over file vectors
|
| 10 |
+
* Memory-LoRA: doc_section_i -> chunks -> mean-pool -> section vector
|
| 11 |
+
doc -> weighted-mean+max over section vectors
|
| 12 |
+
|
| 13 |
+
Same frozen encoder as the paper (Qwen3-Embedding-0.6B), same reasoning for
|
| 14 |
+
the weighting (content-distinctiveness via cosine-distance-from-mean +
|
| 15 |
+
log-size normalization) -- multi-section documents (e.g. the Code2LoRA paper
|
| 16 |
+
chunked into abstract/method/results/limitations) benefit from it exactly
|
| 17 |
+
the way multi-file repos did. Single-section synthetic fact-sheets degenerate
|
| 18 |
+
gracefully to a near-uniform weighting over their own chunks.
|
| 19 |
+
|
| 20 |
+
No gradient ever flows through this encoder; embeddings are precomputed once
|
| 21 |
+
and cached to parquet by ``scripts/build_doc_embeddings.py``.
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
from __future__ import annotations
|
| 25 |
+
|
| 26 |
+
import re
|
| 27 |
+
from typing import List, Optional, Tuple
|
| 28 |
+
|
| 29 |
+
import torch
|
| 30 |
+
import torch.nn.functional as F
|
| 31 |
+
from transformers import AutoModel, AutoTokenizer
|
| 32 |
+
|
| 33 |
+
DEFAULT_EMBED_MODEL = "Qwen/Qwen3-Embedding-0.6B"
|
| 34 |
+
|
| 35 |
+
# Section-name heuristics (loose analogue of Code2LoRA's path up/down-weight
|
| 36 |
+
# lists). Neutral by default for synthetic single-section documents; the
|
| 37 |
+
# upweighted names matter for the multi-section Code2LoRA-paper document.
|
| 38 |
+
SECTION_UPWEIGHT = [
|
| 39 |
+
r"abstract", r"result", r"conclusion", r"contribution",
|
| 40 |
+
]
|
| 41 |
+
SECTION_DOWNWEIGHT = [
|
| 42 |
+
r"acknowledg", r"reference", r"appendix",
|
| 43 |
+
]
|
| 44 |
+
|
| 45 |
+
MIN_CHARS_FOR_FULL_WEIGHT = 200 # sections shorter than this are downweighted
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
# ---------------------------------------------------------------------------
|
| 49 |
+
# Chunking
|
| 50 |
+
# ---------------------------------------------------------------------------
|
| 51 |
+
|
| 52 |
+
def chunk_token_ids(token_ids: List[int], chunk_tokens: int, overlap: int) -> List[List[int]]:
|
| 53 |
+
"""Produce overlapping token windows (identical to Code2LoRA's version)."""
|
| 54 |
+
if chunk_tokens <= 0:
|
| 55 |
+
raise ValueError("chunk_tokens must be > 0")
|
| 56 |
+
if overlap >= chunk_tokens:
|
| 57 |
+
raise ValueError("chunk_overlap must be < chunk_tokens")
|
| 58 |
+
chunks: List[List[int]] = []
|
| 59 |
+
step = chunk_tokens - overlap
|
| 60 |
+
n = len(token_ids)
|
| 61 |
+
if n == 0:
|
| 62 |
+
return chunks
|
| 63 |
+
for start in range(0, n, step):
|
| 64 |
+
end = min(start + chunk_tokens, n)
|
| 65 |
+
window = token_ids[start:end]
|
| 66 |
+
if len(window) < 16:
|
| 67 |
+
continue
|
| 68 |
+
chunks.append(window)
|
| 69 |
+
if end >= n:
|
| 70 |
+
break
|
| 71 |
+
return chunks
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
# ---------------------------------------------------------------------------
|
| 75 |
+
# Embedding model wrapper
|
| 76 |
+
# ---------------------------------------------------------------------------
|
| 77 |
+
|
| 78 |
+
@torch.inference_mode()
|
| 79 |
+
def embed_texts(
|
| 80 |
+
model: AutoModel,
|
| 81 |
+
tokenizer: AutoTokenizer,
|
| 82 |
+
texts: List[str],
|
| 83 |
+
device: str,
|
| 84 |
+
batch_size: int,
|
| 85 |
+
max_length: int,
|
| 86 |
+
) -> torch.Tensor:
|
| 87 |
+
"""Return embeddings [N, D] using mean pooling over last_hidden_state."""
|
| 88 |
+
all_vecs = []
|
| 89 |
+
for i in range(0, len(texts), batch_size):
|
| 90 |
+
batch = texts[i:i + batch_size]
|
| 91 |
+
enc = tokenizer(
|
| 92 |
+
batch, padding=True, truncation=True,
|
| 93 |
+
max_length=max_length, return_tensors="pt",
|
| 94 |
+
)
|
| 95 |
+
enc = {k: v.to(device) for k, v in enc.items()}
|
| 96 |
+
out = model(**enc)
|
| 97 |
+
last = out.last_hidden_state # [B, T, H]
|
| 98 |
+
mask = enc["attention_mask"].unsqueeze(-1) # [B, T, 1]
|
| 99 |
+
mean = (last * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1)
|
| 100 |
+
all_vecs.append(mean.detach().cpu())
|
| 101 |
+
if not all_vecs:
|
| 102 |
+
return torch.empty((0, model.config.hidden_size))
|
| 103 |
+
return torch.cat(all_vecs, dim=0)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
# ---------------------------------------------------------------------------
|
| 107 |
+
# Pooling: chunks -> section -> document
|
| 108 |
+
# ---------------------------------------------------------------------------
|
| 109 |
+
|
| 110 |
+
def pool_section_embeddings(chunk_embs: torch.Tensor) -> Optional[torch.Tensor]:
|
| 111 |
+
"""chunk_embs [K, D] -> section_emb [D]"""
|
| 112 |
+
if chunk_embs.numel() == 0:
|
| 113 |
+
return None
|
| 114 |
+
return chunk_embs.mean(dim=0)
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def _section_name_bonus(section_name: str) -> float:
|
| 118 |
+
s = section_name.lower()
|
| 119 |
+
bonus = 0.0
|
| 120 |
+
for pat in SECTION_DOWNWEIGHT:
|
| 121 |
+
if re.search(pat, s):
|
| 122 |
+
bonus -= 0.25
|
| 123 |
+
break
|
| 124 |
+
for pat in SECTION_UPWEIGHT:
|
| 125 |
+
if re.search(pat, s):
|
| 126 |
+
bonus += 0.15
|
| 127 |
+
break
|
| 128 |
+
return bonus
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def compute_section_weights(
|
| 132 |
+
section_embs: torch.Tensor, # [S, D]
|
| 133 |
+
section_char_counts: torch.Tensor, # [S]
|
| 134 |
+
section_names: List[str],
|
| 135 |
+
a_distinct: float,
|
| 136 |
+
b_size: float,
|
| 137 |
+
tau: float,
|
| 138 |
+
) -> torch.Tensor:
|
| 139 |
+
"""
|
| 140 |
+
Whole-doc, all-sections weighting:
|
| 141 |
+
distinct_i = 1 - cos(s_i, mean_s)
|
| 142 |
+
size_i = normalized log(1+chars)
|
| 143 |
+
score_i = a_distinct * distinct_i + b_size * size_i + name_bonus_i + tiny_section_penalty
|
| 144 |
+
w = softmax(score / tau)
|
| 145 |
+
Returns: w [S] sum=1
|
| 146 |
+
"""
|
| 147 |
+
f_norm = F.normalize(section_embs, p=2, dim=-1)
|
| 148 |
+
mean_f = F.normalize(f_norm.mean(dim=0, keepdim=True), p=2, dim=-1)
|
| 149 |
+
cos = (f_norm * mean_f).sum(dim=-1).clamp(-1, 1)
|
| 150 |
+
distinct = 1.0 - cos
|
| 151 |
+
|
| 152 |
+
chars = section_char_counts.float().clamp(min=1)
|
| 153 |
+
log_chars = torch.log1p(chars)
|
| 154 |
+
if log_chars.numel() > 1:
|
| 155 |
+
lo, hi = log_chars.min(), log_chars.max()
|
| 156 |
+
size01 = (log_chars - lo) / (hi - lo + 1e-8)
|
| 157 |
+
else:
|
| 158 |
+
size01 = torch.ones_like(log_chars)
|
| 159 |
+
|
| 160 |
+
name_bonus = torch.tensor([_section_name_bonus(n) for n in section_names],
|
| 161 |
+
dtype=torch.float32)
|
| 162 |
+
tiny_scale = (chars / float(MIN_CHARS_FOR_FULL_WEIGHT)).clamp(max=1.0)
|
| 163 |
+
tiny_bonus = torch.log(tiny_scale + 1e-6)
|
| 164 |
+
|
| 165 |
+
score = (a_distinct * distinct.cpu() + b_size * size01.cpu()
|
| 166 |
+
+ name_bonus + 0.15 * tiny_bonus.cpu())
|
| 167 |
+
return torch.softmax(score / max(tau, 1e-6), dim=0)
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def pool_doc_embedding_weighted(
|
| 171 |
+
section_embs: torch.Tensor, # [S, D]
|
| 172 |
+
section_char_counts: torch.Tensor, # [S]
|
| 173 |
+
section_names: List[str],
|
| 174 |
+
a_distinct: float = 1.0,
|
| 175 |
+
b_size: float = 0.5,
|
| 176 |
+
tau: float = 0.5,
|
| 177 |
+
alpha_mean: float = 1.0,
|
| 178 |
+
beta_max: float = 1.0,
|
| 179 |
+
) -> Optional[torch.Tensor]:
|
| 180 |
+
"""Aggregate section embeddings into one document vector:
|
| 181 |
+
concat(alpha_mean * weighted_mean, beta_max * max) -> [2D]. No final
|
| 182 |
+
L2 normalization (matches Code2LoRA's repo-vector convention)."""
|
| 183 |
+
if section_embs.numel() == 0:
|
| 184 |
+
return None
|
| 185 |
+
w = compute_section_weights(
|
| 186 |
+
section_embs, section_char_counts, section_names,
|
| 187 |
+
a_distinct, b_size, tau,
|
| 188 |
+
).to(section_embs.dtype)
|
| 189 |
+
wmean = (section_embs * w.unsqueeze(-1)).sum(dim=0)
|
| 190 |
+
vmax = section_embs.max(dim=0).values
|
| 191 |
+
return torch.cat([alpha_mean * wmean, beta_max * vmax], dim=0)
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
# ---------------------------------------------------------------------------
|
| 195 |
+
# Main pipeline per document
|
| 196 |
+
# ---------------------------------------------------------------------------
|
| 197 |
+
|
| 198 |
+
def embed_document(
|
| 199 |
+
sections: List[Tuple[str, str]], # [(section_name, section_text), ...]
|
| 200 |
+
model: AutoModel,
|
| 201 |
+
tokenizer: AutoTokenizer,
|
| 202 |
+
device: str,
|
| 203 |
+
chunk_tokens: int = 4096,
|
| 204 |
+
chunk_overlap: int = 512,
|
| 205 |
+
batch_size: int = 4,
|
| 206 |
+
a_distinct: float = 1.0,
|
| 207 |
+
b_size: float = 0.5,
|
| 208 |
+
tau: float = 0.5,
|
| 209 |
+
alpha_mean: float = 1.0,
|
| 210 |
+
beta_max: float = 1.0,
|
| 211 |
+
) -> Optional[torch.Tensor]:
|
| 212 |
+
"""One document = list of (name, text) sections (single-element for a
|
| 213 |
+
plain synthetic fact-sheet; multi-element for the chunked paper).
|
| 214 |
+
Returns a [2D] embedding, or None if the document had no usable text."""
|
| 215 |
+
section_vectors: List[torch.Tensor] = []
|
| 216 |
+
section_names: List[str] = []
|
| 217 |
+
section_char_counts: List[int] = []
|
| 218 |
+
|
| 219 |
+
for name, text in sections:
|
| 220 |
+
text = (text or "").strip()
|
| 221 |
+
if not text:
|
| 222 |
+
continue
|
| 223 |
+
ids = tokenizer.encode(text, add_special_tokens=False)
|
| 224 |
+
windows = chunk_token_ids(ids, chunk_tokens=chunk_tokens, overlap=chunk_overlap)
|
| 225 |
+
if not windows:
|
| 226 |
+
continue
|
| 227 |
+
chunks = [tokenizer.decode(w, skip_special_tokens=True) for w in windows]
|
| 228 |
+
chunk_embs = embed_texts(
|
| 229 |
+
model=model, tokenizer=tokenizer, texts=chunks,
|
| 230 |
+
device=device, batch_size=batch_size, max_length=chunk_tokens,
|
| 231 |
+
)
|
| 232 |
+
svec = pool_section_embeddings(chunk_embs)
|
| 233 |
+
if svec is None:
|
| 234 |
+
continue
|
| 235 |
+
section_vectors.append(svec)
|
| 236 |
+
section_names.append(name)
|
| 237 |
+
section_char_counts.append(len(text))
|
| 238 |
+
|
| 239 |
+
if not section_vectors:
|
| 240 |
+
return None
|
| 241 |
+
|
| 242 |
+
section_embs = torch.stack(section_vectors, dim=0)
|
| 243 |
+
char_t = torch.tensor(section_char_counts, dtype=torch.int64)
|
| 244 |
+
return pool_doc_embedding_weighted(
|
| 245 |
+
section_embs, char_t, section_names,
|
| 246 |
+
a_distinct=a_distinct, b_size=b_size, tau=tau,
|
| 247 |
+
alpha_mean=alpha_mean, beta_max=beta_max,
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
def load_encoder(model_name: str = DEFAULT_EMBED_MODEL, device: str = "mps"):
|
| 252 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 253 |
+
model = AutoModel.from_pretrained(model_name, torch_dtype=torch.float32)
|
| 254 |
+
model.to(device)
|
| 255 |
+
model.eval()
|
| 256 |
+
return model, tokenizer
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
__all__ = [
|
| 260 |
+
"DEFAULT_EMBED_MODEL",
|
| 261 |
+
"chunk_token_ids",
|
| 262 |
+
"embed_texts",
|
| 263 |
+
"pool_section_embeddings",
|
| 264 |
+
"compute_section_weights",
|
| 265 |
+
"pool_doc_embedding_weighted",
|
| 266 |
+
"embed_document",
|
| 267 |
+
"load_encoder",
|
| 268 |
+
]
|
requirements.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Memory-LoRA for google/gemma-4-E2B -- local (MPS) requirements.
|
| 2 |
+
#
|
| 3 |
+
# transformers must be installed from the main/dev branch: as of writing,
|
| 4 |
+
# Gemma4ForConditionalGeneration (model_type "gemma4") is not yet in a
|
| 5 |
+
# pinned PyPI release (the model's own config.json requires
|
| 6 |
+
# transformers_version >= 5.5.0.dev0).
|
| 7 |
+
#
|
| 8 |
+
# pip install "git+https://github.com/huggingface/transformers.git"
|
| 9 |
+
#
|
| 10 |
+
# torch installs the MPS-enabled build automatically on macOS (no separate
|
| 11 |
+
# index-url needed for Apple Silicon).
|
| 12 |
+
|
| 13 |
+
torch==2.13.0
|
| 14 |
+
transformers @ git+https://github.com/huggingface/transformers.git
|
| 15 |
+
accelerate==1.14.0
|
| 16 |
+
numpy==2.5.1
|
| 17 |
+
pyarrow==25.0.0
|
| 18 |
+
tqdm==4.69.0
|
| 19 |
+
sentencepiece==0.2.2
|
| 20 |
+
protobuf==7.35.1
|
| 21 |
+
tensorboard==2.21.0
|
| 22 |
+
openai==2.48.0
|
runs/sixview_v1/head.best.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:42b3ca944c28284e7c391bb15347765cc183edad70f9fc01eca7d52b47d81fc9
|
| 3 |
+
size 754581207
|
runs/sixview_v1/head.latest.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:de50128411b62dbe548aa778de92946a5cb27d9c7ed6dd00fb0e04dbe3fddc9e
|
| 3 |
+
size 754581395
|
runs/sixview_v1/metrics.jsonl
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"step": 200, "epoch": 0, "end_of_epoch": false, "eval_loss": 3.073296190737905, "suites": {"cr_val": {"eval_loss": 3.073296190737905, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 3.0465956268583674, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 3.2239975754518686, "n_docs": 25, "n_tokens": 805}}}
|
| 2 |
+
{"step": 400, "epoch": 0, "end_of_epoch": false, "eval_loss": 2.938264944642251, "suites": {"cr_val": {"eval_loss": 2.938264944642251, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 2.890953134488421, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.889070537964009, "n_docs": 25, "n_tokens": 805}}}
|
| 3 |
+
{"step": 415, "epoch": 0, "end_of_epoch": true, "eval_loss": 2.925391464855528, "suites": {"cr_val": {"eval_loss": 2.925391464855528, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 2.8815196507705547, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.8640587694156245, "n_docs": 25, "n_tokens": 805}}}
|
| 4 |
+
{"step": 600, "epoch": 1, "end_of_epoch": false, "eval_loss": 2.9148157247074997, "suites": {"cr_val": {"eval_loss": 2.9148157247074997, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 2.8689732771771497, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.7616432108494067, "n_docs": 25, "n_tokens": 805}}}
|
| 5 |
+
{"step": 800, "epoch": 1, "end_of_epoch": false, "eval_loss": 2.8480377581749394, "suites": {"cr_val": {"eval_loss": 2.8480377581749394, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 2.8288494332162752, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.6785004036026714, "n_docs": 25, "n_tokens": 805}}}
|
| 6 |
+
{"step": 830, "epoch": 1, "end_of_epoch": true, "eval_loss": 2.885955327256572, "suites": {"cr_val": {"eval_loss": 2.885955327256572, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 2.8312791101489303, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.668821378228087, "n_docs": 25, "n_tokens": 805}}}
|
| 7 |
+
{"step": 1000, "epoch": 2, "end_of_epoch": false, "eval_loss": 3.0374551723996475, "suites": {"cr_val": {"eval_loss": 3.0374551723996475, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 2.9976756136774148, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.6696533814720484, "n_docs": 25, "n_tokens": 805}}}
|
| 8 |
+
{"step": 1200, "epoch": 2, "end_of_epoch": false, "eval_loss": 3.0449040086767853, "suites": {"cr_val": {"eval_loss": 3.0449040086767853, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 3.0007799045652925, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.596094616525662, "n_docs": 25, "n_tokens": 805}}}
|
| 9 |
+
{"step": 1245, "epoch": 2, "end_of_epoch": true, "eval_loss": 3.019029198608677, "suites": {"cr_val": {"eval_loss": 3.019029198608677, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 2.9622069910368136, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.534812292623224, "n_docs": 25, "n_tokens": 805}}}
|
| 10 |
+
{"step": 1400, "epoch": 3, "end_of_epoch": false, "eval_loss": 3.3129004250276033, "suites": {"cr_val": {"eval_loss": 3.3129004250276033, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 3.2453028188683466, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.5926491863238885, "n_docs": 25, "n_tokens": 805}}}
|
| 11 |
+
{"step": 1600, "epoch": 3, "end_of_epoch": false, "eval_loss": 3.4394415961478866, "suites": {"cr_val": {"eval_loss": 3.4394415961478866, "n_docs": 40, "n_tokens": 6170}, "cr_test": {"eval_loss": 3.3522856792662634, "n_docs": 40, "n_tokens": 5901}, "ir_test": {"eval_loss": 2.655274886281594, "n_docs": 25, "n_tokens": 805}}}
|
runs/sixview_v1/tb/events.out.tfevents.1784911625.MAC-722851.16547.0
ADDED
|
Binary file (18.1 kB). View file
|
|
|
runs/sixview_v2/head.snapshot.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:38bf91d46b037d1df7f8827e6ab2a05b0e5d76f69b3bfd880b67d46fde06a8a6
|
| 3 |
+
size 754581395
|
runs/sixview_v2/head.t0030m.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:74cdb1549d14d59c18110ff7b9a50334158e7332e9dd118ae139bdd5e664086f
|
| 3 |
+
size 754581395
|
runs/sixview_v2/tb/events.out.tfevents.1784929857.MAC-722851.35539.0
ADDED
|
Binary file (2.08 kB). View file
|
|
|
scripts/assemble_6view_dataset.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Assemble the final ALIGNED 6-view training dataset by joining the
|
| 3 |
+
multi-view embeddings (inputs, doc_id = 'owner/repo') to ALL tech-lead QA
|
| 4 |
+
(targets) matched by repo name (commitpack/swe QA carry 'owner/repo@commit'
|
| 5 |
+
-> stripped to 'owner/repo'). This turns 132 repo-scoped-only aligned repos
|
| 6 |
+
into 515 aligned repos (~4000 QA) -- the best use of what we built.
|
| 7 |
+
|
| 8 |
+
Splits (per repo, deterministic): 80% train / 10% cr_val / 10% cr_test, so
|
| 9 |
+
the hypernetwork is evaluated on held-out repos it never trained on. Within
|
| 10 |
+
train repos, ~15% of QA -> qna_split=held_out (feeds ir_test).
|
| 11 |
+
|
| 12 |
+
Per-repo QA cap keeps any single repo (e.g. django) from dominating.
|
| 13 |
+
|
| 14 |
+
Output: data/embeddings/aligned6_embeddings.parquet
|
| 15 |
+
data/qna/aligned6_qna.jsonl
|
| 16 |
+
"""
|
| 17 |
+
from __future__ import annotations
|
| 18 |
+
import json, hashlib, random, sys
|
| 19 |
+
from collections import defaultdict
|
| 20 |
+
from pathlib import Path
|
| 21 |
+
import pyarrow as pa, pyarrow.parquet as pq
|
| 22 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 23 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 24 |
+
from memory_lora.data_paths import EMBEDDINGS_DIR, QNA_DIR
|
| 25 |
+
|
| 26 |
+
PER_REPO_CAP = 20
|
| 27 |
+
|
| 28 |
+
def split_of(repo: str) -> str:
|
| 29 |
+
h = int(hashlib.md5(repo.encode()).hexdigest(), 16) % 100
|
| 30 |
+
if h < 10: return "cr_test"
|
| 31 |
+
if h < 20: return "cr_val"
|
| 32 |
+
return "train"
|
| 33 |
+
|
| 34 |
+
def main():
|
| 35 |
+
rng = random.Random(3407)
|
| 36 |
+
mv = pq.read_table(EMBEDDINGS_DIR / "multiview_embeddings.parquet").to_pylist()
|
| 37 |
+
mv_by_repo = {}
|
| 38 |
+
for r in mv: # dedupe by repo (keep first)
|
| 39 |
+
mv_by_repo.setdefault(r["doc_id"], r)
|
| 40 |
+
mv_repos = set(mv_by_repo)
|
| 41 |
+
|
| 42 |
+
qa_by_repo = defaultdict(list)
|
| 43 |
+
for f in ["repo_scoped_qa.jsonl", "techlead_qa_commitpack.jsonl", "techlead_qa.jsonl"]:
|
| 44 |
+
p = QNA_DIR / f
|
| 45 |
+
if not p.exists(): continue
|
| 46 |
+
for l in open(p):
|
| 47 |
+
d = json.loads(l); repo = d["doc_id"].split("@")[0]
|
| 48 |
+
if repo in mv_repos:
|
| 49 |
+
qa_by_repo[repo].append(d)
|
| 50 |
+
|
| 51 |
+
# embeddings with splits (only repos that have >=1 QA are trainable/evaluable)
|
| 52 |
+
emb_rows = []
|
| 53 |
+
for repo, r in mv_by_repo.items():
|
| 54 |
+
if repo not in qa_by_repo: continue
|
| 55 |
+
emb_rows.append({"doc_id": repo, "doc_version": "head", "split": split_of(repo),
|
| 56 |
+
"category": "aligned6", "doc_embedding": r["doc_embedding"]})
|
| 57 |
+
t = pa.table({k: [e[k] for e in emb_rows] for k in
|
| 58 |
+
["doc_id", "doc_version", "split", "category", "doc_embedding"]})
|
| 59 |
+
pq.write_table(t, EMBEDDINGS_DIR / "aligned6_embeddings.parquet")
|
| 60 |
+
|
| 61 |
+
# qna with qna_split
|
| 62 |
+
n_qa = 0
|
| 63 |
+
from collections import Counter
|
| 64 |
+
split_ct = Counter()
|
| 65 |
+
with (QNA_DIR / "aligned6_qna.jsonl").open("w") as out:
|
| 66 |
+
for repo, rows in qa_by_repo.items():
|
| 67 |
+
sp = split_of(repo)
|
| 68 |
+
if len(rows) > PER_REPO_CAP:
|
| 69 |
+
rows = rng.sample(rows, PER_REPO_CAP)
|
| 70 |
+
for i, d in enumerate(rows):
|
| 71 |
+
if sp == "train":
|
| 72 |
+
qsplit = "held_out" if rng.random() < 0.15 else "train"
|
| 73 |
+
else:
|
| 74 |
+
qsplit = "held_out" # cr_val/cr_test: all held out
|
| 75 |
+
out.write(json.dumps({"doc_id": repo, "doc_version": "head",
|
| 76 |
+
"split": sp, "qna_split": qsplit, "aspect": d.get("aspect", "?"),
|
| 77 |
+
"question": d.get("question", ""), "prefix": d["prefix"],
|
| 78 |
+
"target": d["target"], "lang": d.get("lang", "unknown")}) + "\n")
|
| 79 |
+
n_qa += 1
|
| 80 |
+
split_ct[sp] += 1
|
| 81 |
+
|
| 82 |
+
print(f"aligned6 dataset: {len(emb_rows)} repos (embeddings) | {n_qa} QA")
|
| 83 |
+
print(f" repo splits: {Counter(split_of(r) for r in qa_by_repo)}")
|
| 84 |
+
print(f" QA by split: {dict(split_ct)}")
|
| 85 |
+
print(f" -> aligned6_embeddings.parquet + aligned6_qna.jsonl")
|
| 86 |
+
|
| 87 |
+
if __name__ == "__main__":
|
| 88 |
+
main()
|
scripts/augment_paraphrases.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Augment a document's QA pairs with paraphrased variants of the SAME facts.
|
| 3 |
+
|
| 4 |
+
Why: the direct-LoRA experiment on the Code2LoRA paper doc (runs/direct_paper)
|
| 5 |
+
converged to train_loss=0.0 but only hit 33% exact-match on its OWN training
|
| 6 |
+
questions at free-generation time, with several wrong answers collapsing to
|
| 7 |
+
the same recycled string (e.g. "47.4%" answering four different percentage
|
| 8 |
+
questions). With ~1 phrasing per fact and ~18 facts total, the model found a
|
| 9 |
+
shortcut (a few frequently-reinforced answers) instead of learning to
|
| 10 |
+
discriminate between questions. Multiple paraphrases of the SAME fact force
|
| 11 |
+
the model to actually condition on question content rather than pattern-
|
| 12 |
+
match a training-set shortcut.
|
| 13 |
+
|
| 14 |
+
This does NOT introduce new facts -- it takes the existing (question,
|
| 15 |
+
answer) pairs for a document and asks the model to rephrase the QUESTION
|
| 16 |
+
several different ways while keeping the answer identical.
|
| 17 |
+
|
| 18 |
+
Usage:
|
| 19 |
+
python scripts/augment_paraphrases.py --doc-id code2lora_paper --n-paraphrases 5
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
from __future__ import annotations
|
| 23 |
+
|
| 24 |
+
import argparse
|
| 25 |
+
import json
|
| 26 |
+
import os
|
| 27 |
+
import re
|
| 28 |
+
import sys
|
| 29 |
+
from pathlib import Path
|
| 30 |
+
from typing import List
|
| 31 |
+
|
| 32 |
+
from openai import OpenAI
|
| 33 |
+
|
| 34 |
+
HERE = Path(__file__).resolve().parent
|
| 35 |
+
REPO_ROOT = HERE.parent
|
| 36 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 37 |
+
from memory_lora.data_paths import QNA_DIR, CACHE_DIR, ensure_dirs # noqa: E402
|
| 38 |
+
from generate_synthetic_dataset import ( # noqa: E402
|
| 39 |
+
CachedClient, _load_dotenv, DEFAULT_GEN_MODEL, OPENROUTER_BASE_URL,
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
_load_dotenv(REPO_ROOT / ".env")
|
| 43 |
+
|
| 44 |
+
PARAPHRASE_SYSTEM = (
|
| 45 |
+
"You rewrite a factual question in N different ways while keeping its "
|
| 46 |
+
"meaning and the correct short answer completely unchanged. Output a "
|
| 47 |
+
"JSON array of N strings, each a differently-phrased question that "
|
| 48 |
+
"still has the exact same answer as the original. Vary sentence "
|
| 49 |
+
"structure, word choice, and question format (e.g. direct question, "
|
| 50 |
+
"'what value/number', fill-in-the-blank style) -- but never change what "
|
| 51 |
+
"is being asked. Output ONLY the JSON array, no prose."
|
| 52 |
+
)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def gen_paraphrases(client: CachedClient, model: str, question: str, answer: str, n: int) -> List[str]:
|
| 56 |
+
prompt = f"Original question: {question}\nCorrect answer: {answer.strip()}\nGenerate {n} paraphrases."
|
| 57 |
+
raw = client.chat(
|
| 58 |
+
model=model,
|
| 59 |
+
messages=[
|
| 60 |
+
{"role": "system", "content": PARAPHRASE_SYSTEM},
|
| 61 |
+
{"role": "user", "content": prompt},
|
| 62 |
+
],
|
| 63 |
+
temperature=0.8,
|
| 64 |
+
max_tokens=800,
|
| 65 |
+
)
|
| 66 |
+
match = re.search(r"\[.*\]", raw, re.DOTALL)
|
| 67 |
+
if not match:
|
| 68 |
+
return []
|
| 69 |
+
try:
|
| 70 |
+
items = json.loads(match.group(0))
|
| 71 |
+
except json.JSONDecodeError:
|
| 72 |
+
return []
|
| 73 |
+
return [q.strip() for q in items if isinstance(q, str) and q.strip()]
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def main() -> None:
|
| 77 |
+
ap = argparse.ArgumentParser()
|
| 78 |
+
ap.add_argument("--doc-id", required=True)
|
| 79 |
+
ap.add_argument("--n-paraphrases", type=int, default=5)
|
| 80 |
+
ap.add_argument("--gen-model", default=DEFAULT_GEN_MODEL)
|
| 81 |
+
ap.add_argument("--held-out-fraction", type=float, default=0.15,
|
| 82 |
+
help="Fraction of NEW paraphrases assigned to "
|
| 83 |
+
"qna_split=held_out (rest go to train, since the "
|
| 84 |
+
"goal here is more train-time exposure per fact).")
|
| 85 |
+
args = ap.parse_args()
|
| 86 |
+
|
| 87 |
+
ensure_dirs()
|
| 88 |
+
api_key = os.environ.get("OPENROUTER_API_KEY")
|
| 89 |
+
if not api_key:
|
| 90 |
+
raise SystemExit("OPENROUTER_API_KEY not set (expected in .env)")
|
| 91 |
+
client = CachedClient(OpenAI(base_url=OPENROUTER_BASE_URL, api_key=api_key), cache_dir=CACHE_DIR)
|
| 92 |
+
|
| 93 |
+
qna_path = QNA_DIR / "qna.jsonl"
|
| 94 |
+
rows = [json.loads(l) for l in qna_path.open()]
|
| 95 |
+
doc_rows = [r for r in rows if r["doc_id"] == args.doc_id and r["qna_split"] == "train"]
|
| 96 |
+
print(f"Found {len(doc_rows)} existing train QA pairs for {args.doc_id}", flush=True)
|
| 97 |
+
|
| 98 |
+
import random
|
| 99 |
+
rng = random.Random(3407)
|
| 100 |
+
new_rows = []
|
| 101 |
+
for r in doc_rows:
|
| 102 |
+
question = r["question"] if r.get("question") else r["prefix"].removeprefix("Q: ").removesuffix("\nA:")
|
| 103 |
+
paraphrases = gen_paraphrases(client, args.gen_model, question, r["target"], args.n_paraphrases)
|
| 104 |
+
for pq in paraphrases:
|
| 105 |
+
qna_split = "held_out" if rng.random() < args.held_out_fraction else "train"
|
| 106 |
+
new_rows.append({
|
| 107 |
+
"doc_id": r["doc_id"], "doc_version": r["doc_version"], "split": r["split"],
|
| 108 |
+
"qna_split": qna_split, "question": pq,
|
| 109 |
+
"prefix": f"Q: {pq}\nA:", "target": r["target"],
|
| 110 |
+
})
|
| 111 |
+
print(f" {question[:60]!r} -> {len(paraphrases)} paraphrases", flush=True)
|
| 112 |
+
|
| 113 |
+
with qna_path.open("a") as f:
|
| 114 |
+
for row in new_rows:
|
| 115 |
+
f.write(json.dumps(row) + "\n")
|
| 116 |
+
print(f"\nAppended {len(new_rows)} paraphrased QA pairs to {qna_path}", flush=True)
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
if __name__ == "__main__":
|
| 120 |
+
main()
|
scripts/build_doc_embeddings.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Embed every document in data/docs/documents.jsonl with the frozen
|
| 3 |
+
Qwen3-Embedding-0.6B encoder (memory_lora/encoder.py) and write
|
| 4 |
+
data/embeddings/doc_embeddings.parquet.
|
| 5 |
+
|
| 6 |
+
Mirrors Code2LoRA's ``create_dataset/build_repo_state_embeddings_shard.py``.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
from __future__ import annotations
|
| 10 |
+
|
| 11 |
+
import argparse
|
| 12 |
+
import json
|
| 13 |
+
import sys
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
|
| 16 |
+
import pyarrow as pa
|
| 17 |
+
import pyarrow.parquet as pq
|
| 18 |
+
import torch
|
| 19 |
+
from tqdm import tqdm
|
| 20 |
+
|
| 21 |
+
HERE = Path(__file__).resolve().parent
|
| 22 |
+
REPO_ROOT = HERE.parent
|
| 23 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 24 |
+
from memory_lora.data_paths import DOCS_DIR, EMBEDDINGS_DIR, ensure_dirs # noqa: E402
|
| 25 |
+
from memory_lora.encoder import DEFAULT_EMBED_MODEL, embed_document, load_encoder # noqa: E402
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def main() -> None:
|
| 29 |
+
ap = argparse.ArgumentParser()
|
| 30 |
+
ap.add_argument("--embed-model", default=DEFAULT_EMBED_MODEL)
|
| 31 |
+
ap.add_argument("--device", default="mps")
|
| 32 |
+
ap.add_argument("--chunk-tokens", type=int, default=4096)
|
| 33 |
+
ap.add_argument("--chunk-overlap", type=int, default=512)
|
| 34 |
+
args = ap.parse_args()
|
| 35 |
+
|
| 36 |
+
ensure_dirs()
|
| 37 |
+
docs_path = DOCS_DIR / "documents.jsonl"
|
| 38 |
+
out_path = EMBEDDINGS_DIR / "doc_embeddings.parquet"
|
| 39 |
+
|
| 40 |
+
device = args.device if (args.device != "mps" or torch.backends.mps.is_available()) else "cpu"
|
| 41 |
+
print(f"Loading encoder {args.embed_model} on {device} ...", flush=True)
|
| 42 |
+
model, tokenizer = load_encoder(args.embed_model, device=device)
|
| 43 |
+
|
| 44 |
+
docs = [json.loads(l) for l in docs_path.open()]
|
| 45 |
+
print(f"{len(docs)} documents to embed", flush=True)
|
| 46 |
+
|
| 47 |
+
rows = []
|
| 48 |
+
for d in tqdm(docs):
|
| 49 |
+
sections = [(s["name"], s["text"]) for s in d["sections"]]
|
| 50 |
+
vec = embed_document(
|
| 51 |
+
sections, model, tokenizer, device,
|
| 52 |
+
chunk_tokens=args.chunk_tokens, chunk_overlap=args.chunk_overlap,
|
| 53 |
+
)
|
| 54 |
+
if vec is None:
|
| 55 |
+
print(f" [warn] no embedding for {d['doc_id']}, skipping", flush=True)
|
| 56 |
+
continue
|
| 57 |
+
rows.append({
|
| 58 |
+
"doc_id": d["doc_id"],
|
| 59 |
+
"doc_version": d["doc_version"],
|
| 60 |
+
"split": d["split"],
|
| 61 |
+
"category": d["category"],
|
| 62 |
+
"doc_embedding": vec.numpy().astype("float32").tolist(),
|
| 63 |
+
})
|
| 64 |
+
|
| 65 |
+
table = pa.table({
|
| 66 |
+
"doc_id": [r["doc_id"] for r in rows],
|
| 67 |
+
"doc_version": [r["doc_version"] for r in rows],
|
| 68 |
+
"split": [r["split"] for r in rows],
|
| 69 |
+
"category": [r["category"] for r in rows],
|
| 70 |
+
"doc_embedding": [r["doc_embedding"] for r in rows],
|
| 71 |
+
})
|
| 72 |
+
pq.write_table(table, out_path)
|
| 73 |
+
dim = len(rows[0]["doc_embedding"]) if rows else 0
|
| 74 |
+
print(f"Wrote {len(rows)} embeddings (dim={dim}) -> {out_path}", flush=True)
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
if __name__ == "__main__":
|
| 78 |
+
main()
|
scripts/build_repo_multiview.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Build REAL 6-view repo inputs locally: clone repos, extract the 6
|
| 3 |
+
tech-lead views from each full tree, embed each view with the frozen Qwen
|
| 4 |
+
encoder, concat -> one multi-view repo vector. Also emit a compact per-view
|
| 5 |
+
TEXT summary per repo (so generate_repo_scoped_qa.py can produce
|
| 6 |
+
scope-aligned targets from the SAME views the embedding sees).
|
| 7 |
+
|
| 8 |
+
Views (each -> Qwen mean+max = 2048-d; 6 views -> 12288-d input vector;
|
| 9 |
+
head input_dim is set to match, "~8k" was always approximate):
|
| 10 |
+
v_graph : AST call/import graph (codegraph.py) + dependency edges
|
| 11 |
+
v_arch : READMEs, top-level docstrings, folder tree
|
| 12 |
+
v_history : git log --oneline + sampled commit diffs ("the why")
|
| 13 |
+
v_contracts : test files + type-annotated signatures
|
| 14 |
+
v_conventions: sampled source files (naming/idioms)
|
| 15 |
+
v_ops : Dockerfile / CI yaml / pyproject / setup / .env.example
|
| 16 |
+
|
| 17 |
+
Streaming design: load encoder ONCE, then per repo {clone shallow -> extract
|
| 18 |
+
-> embed -> save -> delete clone} so disk and memory stay bounded. Clone
|
| 19 |
+
failures / oversized / non-Python repos are skipped gracefully.
|
| 20 |
+
|
| 21 |
+
Usage:
|
| 22 |
+
python scripts/build_repo_multiview.py --repos-file data/repo_list.txt --limit 3
|
| 23 |
+
python scripts/build_repo_multiview.py --repos-file data/repo_list.txt --max-repos 250
|
| 24 |
+
"""
|
| 25 |
+
from __future__ import annotations
|
| 26 |
+
import argparse, json, os, re, shutil, subprocess, sys, tempfile, time
|
| 27 |
+
from pathlib import Path
|
| 28 |
+
from typing import Dict, List, Optional, Tuple
|
| 29 |
+
import numpy as np, torch
|
| 30 |
+
|
| 31 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 32 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 33 |
+
from memory_lora.data_paths import EMBEDDINGS_DIR, DOCS_DIR, ensure_dirs # noqa: E402
|
| 34 |
+
from memory_lora.encoder import load_encoder, embed_document # noqa: E402
|
| 35 |
+
from memory_lora.codegraph import extract_repo_graph_sections, extract_repo_dependency_summary # noqa: E402
|
| 36 |
+
|
| 37 |
+
SKIP = {".git", "__pycache__", ".venv", "venv", "node_modules", "build", "dist",
|
| 38 |
+
".tox", ".mypy_cache", "vendor", "third_party", "target", ".next"}
|
| 39 |
+
VIEWS = ["v_graph", "v_arch", "v_history", "v_contracts", "v_conventions", "v_ops"]
|
| 40 |
+
|
| 41 |
+
# language-agnostic file classification
|
| 42 |
+
CODE_EXTS = {".py", ".js", ".jsx", ".ts", ".tsx", ".java", ".go", ".rs", ".c",
|
| 43 |
+
".h", ".cc", ".cpp", ".hpp", ".php", ".rb", ".kt", ".swift", ".scala", ".cs"}
|
| 44 |
+
TEST_HINTS = ("test", "spec", "_test.", ".test.", "tests/")
|
| 45 |
+
# import-statement patterns per common language (for the non-Python graph fallback)
|
| 46 |
+
IMPORT_RE = re.compile(
|
| 47 |
+
r"^\s*(?:import\s+[^\n;]+|from\s+[^\n]+import[^\n]+|#include\s*[<\"][^>\"]+[>\"]|"
|
| 48 |
+
r"use\s+[^\n;]+|require\s*\(?[^\n)]+\)?|package\s+[^\n;]+)", re.MULTILINE)
|
| 49 |
+
DEF_RE = re.compile(
|
| 50 |
+
r"^\s*(?:def\s+\w+|class\s+\w+|func\s+\w+|function\s+\w+|fn\s+\w+|"
|
| 51 |
+
r"(?:public|private|protected|static|\s)+\w[\w<>\[\]]*\s+\w+\s*\(|"
|
| 52 |
+
r"type\s+\w+|struct\s+\w+|interface\s+\w+|export\s+(?:default\s+)?(?:function|class|const)\s+\w+)",
|
| 53 |
+
re.MULTILINE)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def run(cmd: List[str], cwd=None, timeout=120) -> Tuple[int, str]:
|
| 57 |
+
try:
|
| 58 |
+
r = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True,
|
| 59 |
+
errors="ignore", timeout=timeout)
|
| 60 |
+
return r.returncode, r.stdout
|
| 61 |
+
except Exception: # noqa: BLE001
|
| 62 |
+
return 1, ""
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def clone(name: str, dest: Path, depth=80) -> bool:
|
| 66 |
+
url = f"https://github.com/{name}.git"
|
| 67 |
+
code, _ = run(["git", "clone", "--depth", str(depth), "--quiet", url, str(dest)], timeout=180)
|
| 68 |
+
return code == 0 and dest.exists()
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def _read(p: Path, n=8000) -> str:
|
| 72 |
+
try: return p.read_text(errors="ignore")[:n]
|
| 73 |
+
except OSError: return ""
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def _folder_tree(root: Path, max_lines=120) -> str:
|
| 77 |
+
lines = []
|
| 78 |
+
for p in sorted(root.rglob("*")):
|
| 79 |
+
if any(s in p.parts for s in SKIP): continue
|
| 80 |
+
rel = p.relative_to(root)
|
| 81 |
+
if len(rel.parts) > 3: continue
|
| 82 |
+
lines.append(str(rel) + ("/" if p.is_dir() else ""))
|
| 83 |
+
if len(lines) >= max_lines: break
|
| 84 |
+
return "\n".join(lines)
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def extract_views(repo: Path) -> Dict[str, List[Tuple[str, str]]]:
|
| 88 |
+
"""Return {view_name: [(section_name, text), ...]} for the 6 views."""
|
| 89 |
+
v: Dict[str, List[Tuple[str, str]]] = {k: [] for k in VIEWS}
|
| 90 |
+
|
| 91 |
+
# v_graph: Python AST call/import graph (when present) + language-agnostic
|
| 92 |
+
# regex import/definition summary so non-Python repos still get structure.
|
| 93 |
+
v["v_graph"] = extract_repo_graph_sections(repo, max_files=50, skip_dirs=SKIP)
|
| 94 |
+
dep = extract_repo_dependency_summary(repo, skip_dirs=SKIP)
|
| 95 |
+
if dep: v["v_graph"].append(("dependency_edges", dep))
|
| 96 |
+
if len(v["v_graph"]) < 3: # non-Python (or thin): regex-extract imports/defs
|
| 97 |
+
code = [p for p in repo.rglob("*")
|
| 98 |
+
if p.suffix.lower() in CODE_EXTS and not any(s in p.parts for s in SKIP)][:60]
|
| 99 |
+
imports, defs = [], []
|
| 100 |
+
for p in code:
|
| 101 |
+
t = _read(p, 6000)
|
| 102 |
+
imports += IMPORT_RE.findall(t)[:8]
|
| 103 |
+
defs += [f"{p.name}: {m.strip()[:80]}" for m in DEF_RE.findall(t)[:6]]
|
| 104 |
+
if imports: v["v_graph"].append(("imports", "\n".join(imports[:120])))
|
| 105 |
+
if defs: v["v_graph"].append(("definitions", "\n".join(defs[:120])))
|
| 106 |
+
|
| 107 |
+
# v_arch: READMEs, folder tree, package docstrings
|
| 108 |
+
for pat in ["README*", "ARCHITECTURE*", "docs/*.md", "*/__init__.py"]:
|
| 109 |
+
for p in list(repo.glob(pat))[:4]:
|
| 110 |
+
if p.is_file(): v["v_arch"].append((f"arch:{p.name}", _read(p, 6000)))
|
| 111 |
+
v["v_arch"].append(("folder_tree", _folder_tree(repo)))
|
| 112 |
+
|
| 113 |
+
# v_history: git log + a few diffs
|
| 114 |
+
_, log = run(["git", "-C", str(repo), "log", "--oneline", "-80"])
|
| 115 |
+
if log: v["v_history"].append(("git_log", log[:6000]))
|
| 116 |
+
_, shas = run(["git", "-C", str(repo), "log", "--format=%H", "-6"])
|
| 117 |
+
for sha in [s for s in shas.split() if s][:5]:
|
| 118 |
+
_, diff = run(["git", "-C", str(repo), "show", "--stat", "-p", sha])
|
| 119 |
+
if diff: v["v_history"].append((f"diff:{sha[:8]}", diff[:3000]))
|
| 120 |
+
|
| 121 |
+
# v_contracts: test files (any language) + typed signatures
|
| 122 |
+
tests = [p for p in repo.rglob("*")
|
| 123 |
+
if p.suffix.lower() in CODE_EXTS and not any(s in p.parts for s in SKIP)
|
| 124 |
+
and any(h in str(p).lower() for h in TEST_HINTS)][:10]
|
| 125 |
+
for p in tests:
|
| 126 |
+
v["v_contracts"].append((f"test:{p.name}", _read(p, 4000)))
|
| 127 |
+
|
| 128 |
+
# v_conventions: sampled source files (any language, non-test)
|
| 129 |
+
srcs = [p for p in repo.rglob("*")
|
| 130 |
+
if p.suffix.lower() in CODE_EXTS and not any(s in p.parts for s in SKIP)
|
| 131 |
+
and not any(h in str(p).lower() for h in TEST_HINTS)][:12]
|
| 132 |
+
for p in srcs:
|
| 133 |
+
v["v_conventions"].append((f"src:{p.name}", _read(p, 3500)))
|
| 134 |
+
|
| 135 |
+
# v_ops: build/CI/config
|
| 136 |
+
for pat in ["Dockerfile*", ".github/workflows/*.y*ml", "pyproject.toml",
|
| 137 |
+
"setup.py", "setup.cfg", "requirements*.txt", "Makefile", ".env.example",
|
| 138 |
+
"docker-compose*.y*ml", "tox.ini"]:
|
| 139 |
+
for p in list(repo.glob(pat))[:3]:
|
| 140 |
+
if p.is_file(): v["v_ops"].append((f"ops:{p.name}", _read(p, 4000)))
|
| 141 |
+
return v
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def summarize_views_text(views: Dict[str, List[Tuple[str, str]]], per_view=1400) -> Dict[str, str]:
|
| 145 |
+
"""Compact text per view for QA generation (scope-aligned to embedding)."""
|
| 146 |
+
out = {}
|
| 147 |
+
for k, secs in views.items():
|
| 148 |
+
joined = "\n".join(f"# {n}\n{t}" for n, t in secs)
|
| 149 |
+
out[k] = joined[:per_view]
|
| 150 |
+
return out
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def main():
|
| 154 |
+
ap = argparse.ArgumentParser()
|
| 155 |
+
ap.add_argument("--repos-file", required=True)
|
| 156 |
+
ap.add_argument("--max-repos", type=int, default=250)
|
| 157 |
+
ap.add_argument("--limit", type=int, default=0)
|
| 158 |
+
ap.add_argument("--device", default="mps")
|
| 159 |
+
ap.add_argument("--out-emb", default=str(EMBEDDINGS_DIR / "multiview_embeddings.parquet"))
|
| 160 |
+
ap.add_argument("--out-src", default=str(DOCS_DIR / "multiview_sources.jsonl"))
|
| 161 |
+
args = ap.parse_args()
|
| 162 |
+
ensure_dirs()
|
| 163 |
+
|
| 164 |
+
target = args.limit if args.limit else args.max_repos
|
| 165 |
+
# accept "repo" or "repo<TAB>lang" lines; keep the lang tag if present
|
| 166 |
+
name_lang = []
|
| 167 |
+
for l in open(args.repos_file):
|
| 168 |
+
l = l.strip()
|
| 169 |
+
if not l: continue
|
| 170 |
+
parts = l.split("\t")
|
| 171 |
+
name_lang.append((parts[0], parts[1] if len(parts) > 1 else "unknown"))
|
| 172 |
+
name_lang = name_lang[: target * 3] # oversample for clone failures
|
| 173 |
+
names = [n for n, _ in name_lang]
|
| 174 |
+
lang_of = dict(name_lang)
|
| 175 |
+
|
| 176 |
+
device = args.device if (args.device != "mps" or torch.backends.mps.is_available()) else "cpu"
|
| 177 |
+
print(f"Loading Qwen encoder on {device} ...", flush=True)
|
| 178 |
+
enc_model, enc_tok = load_encoder(device=device)
|
| 179 |
+
|
| 180 |
+
# resume-safe: skip repos already done
|
| 181 |
+
done = set()
|
| 182 |
+
if Path(args.out_src).exists():
|
| 183 |
+
done = {json.loads(l)["repo"] for l in open(args.out_src)}
|
| 184 |
+
src_f = open(args.out_src, "a")
|
| 185 |
+
|
| 186 |
+
import pyarrow as pa, pyarrow.parquet as pq
|
| 187 |
+
emb_rows = []
|
| 188 |
+
# load existing embeddings if resuming
|
| 189 |
+
if Path(args.out_emb).exists():
|
| 190 |
+
t = pq.read_table(args.out_emb).to_pylist()
|
| 191 |
+
emb_rows = t
|
| 192 |
+
|
| 193 |
+
n_done = 0; t0 = time.time()
|
| 194 |
+
for name in names:
|
| 195 |
+
if n_done >= target: break
|
| 196 |
+
if name in done: continue
|
| 197 |
+
tmp = Path(tempfile.mkdtemp(prefix="rmv_"))
|
| 198 |
+
try:
|
| 199 |
+
if not clone(name, tmp / "r"):
|
| 200 |
+
continue
|
| 201 |
+
repo = tmp / "r"
|
| 202 |
+
# skip repos with too little code (any language)
|
| 203 |
+
codefiles = [p for p in repo.rglob("*")
|
| 204 |
+
if p.suffix.lower() in CODE_EXTS and not any(s in p.parts for s in SKIP)]
|
| 205 |
+
if len(codefiles) < 3:
|
| 206 |
+
continue
|
| 207 |
+
views = extract_views(repo)
|
| 208 |
+
# embed each view -> mean+max 2048; concat 6 -> 12288
|
| 209 |
+
vecs = []
|
| 210 |
+
for vk in VIEWS:
|
| 211 |
+
secs = views[vk] or [("empty", "none")]
|
| 212 |
+
vv = embed_document(secs, enc_model, enc_tok, device,
|
| 213 |
+
chunk_tokens=2048, chunk_overlap=128, batch_size=2)
|
| 214 |
+
vecs.append(vv.numpy().astype("float32") if vv is not None else np.zeros(2048, "float32"))
|
| 215 |
+
full = np.concatenate(vecs) # 12288
|
| 216 |
+
doc_id = name # repo-scoped
|
| 217 |
+
emb_rows.append({"doc_id": doc_id, "doc_version": "head", "split": "train",
|
| 218 |
+
"category": "real_repo_multiview", "doc_embedding": full.tolist()})
|
| 219 |
+
src_f.write(json.dumps({"repo": name, "doc_id": doc_id,
|
| 220 |
+
"lang": lang_of.get(name, "unknown"),
|
| 221 |
+
"view_text": summarize_views_text(views)}) + "\n")
|
| 222 |
+
src_f.flush()
|
| 223 |
+
n_done += 1
|
| 224 |
+
if n_done % 10 == 0:
|
| 225 |
+
rate = n_done / max(1e-9, (time.time() - t0) / 60)
|
| 226 |
+
# periodic parquet flush
|
| 227 |
+
_flush(emb_rows, args.out_emb, pa, pq)
|
| 228 |
+
print(f" {n_done} repos done ({rate:.1f}/min) dim={full.shape[0]} latest={name}", flush=True)
|
| 229 |
+
finally:
|
| 230 |
+
shutil.rmtree(tmp, ignore_errors=True)
|
| 231 |
+
|
| 232 |
+
_flush(emb_rows, args.out_emb, pa, pq)
|
| 233 |
+
src_f.close()
|
| 234 |
+
print(f"\nDone. {n_done} repos -> {args.out_emb} (dim={len(emb_rows[0]['doc_embedding']) if emb_rows else 0})", flush=True)
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
def _flush(rows, path, pa, pq):
|
| 238 |
+
if not rows: return
|
| 239 |
+
t = pa.table({k: [r[k] for r in rows] for k in
|
| 240 |
+
["doc_id", "doc_version", "split", "category", "doc_embedding"]})
|
| 241 |
+
pq.write_table(t, path)
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
if __name__ == "__main__":
|
| 245 |
+
main()
|
scripts/consolidate_qa.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Consolidate all tech-lead QA sources into one balanced training file with
|
| 3 |
+
a PER-REPO CAP, so no single repo/domain dominates. This is what fixes the
|
| 4 |
+
Django problem: SWE-bench inherently has ~5 Python repos (django-dominated)
|
| 5 |
+
with thousands of QA already generated; capping per repo collapses django
|
| 6 |
+
from ~2200 to <=CAP while keeping the 700+ distinct repos' diversity.
|
| 7 |
+
|
| 8 |
+
Reads: data/qna/techlead_qa.jsonl, techlead_qa_commitpack.jsonl,
|
| 9 |
+
repo_scoped_qa.jsonl (+ optional multilang tags)
|
| 10 |
+
Writes: data/qna/techlead_consolidated.jsonl
|
| 11 |
+
"""
|
| 12 |
+
from __future__ import annotations
|
| 13 |
+
import argparse, json, glob, random, sys
|
| 14 |
+
from collections import Counter, defaultdict
|
| 15 |
+
from pathlib import Path
|
| 16 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 17 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 18 |
+
from memory_lora.data_paths import QNA_DIR
|
| 19 |
+
|
| 20 |
+
def repo_of(doc_id): return doc_id.split("@")[0]
|
| 21 |
+
|
| 22 |
+
def main():
|
| 23 |
+
ap = argparse.ArgumentParser()
|
| 24 |
+
ap.add_argument("--per-repo-cap", type=int, default=15)
|
| 25 |
+
ap.add_argument("--out", default=str(QNA_DIR / "techlead_consolidated.jsonl"))
|
| 26 |
+
args = ap.parse_args()
|
| 27 |
+
rng = random.Random(3407)
|
| 28 |
+
|
| 29 |
+
files = [QNA_DIR / "techlead_qa.jsonl", QNA_DIR / "techlead_qa_commitpack.jsonl",
|
| 30 |
+
QNA_DIR / "repo_scoped_qa.jsonl"]
|
| 31 |
+
by_repo = defaultdict(list)
|
| 32 |
+
for f in files:
|
| 33 |
+
if not f.exists(): continue
|
| 34 |
+
for l in open(f):
|
| 35 |
+
try: d = json.loads(l)
|
| 36 |
+
except json.JSONDecodeError: continue
|
| 37 |
+
by_repo[repo_of(d["doc_id"])].append(d)
|
| 38 |
+
|
| 39 |
+
kept = []
|
| 40 |
+
for repo, rows in by_repo.items():
|
| 41 |
+
if len(rows) > args.per_repo_cap:
|
| 42 |
+
rows = rng.sample(rows, args.per_repo_cap)
|
| 43 |
+
kept.extend(rows)
|
| 44 |
+
rng.shuffle(kept)
|
| 45 |
+
|
| 46 |
+
with open(args.out, "w") as fo:
|
| 47 |
+
for d in kept: fo.write(json.dumps(d) + "\n")
|
| 48 |
+
|
| 49 |
+
langs = Counter(d.get("lang", "python?") for d in kept)
|
| 50 |
+
repos = Counter(repo_of(d["doc_id"]) for d in kept)
|
| 51 |
+
django = sum(v for k, v in repos.items() if "django" in k.lower())
|
| 52 |
+
print(f"consolidated: {len(kept)} QA | {len(repos)} distinct repos | cap={args.per_repo_cap}/repo")
|
| 53 |
+
print(f" django share: {django} ({100*django/max(1,len(kept)):.1f}%) <- was 46%")
|
| 54 |
+
print(f" langs: {dict(langs)}")
|
| 55 |
+
print(f" top repos: {repos.most_common(5)}")
|
| 56 |
+
print(f" -> {args.out}")
|
| 57 |
+
|
| 58 |
+
if __name__ == "__main__":
|
| 59 |
+
main()
|
scripts/convert_real_code2lora.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Convert the REAL Code2LoRA/RepoPeftBench datasets into our local schema.
|
| 3 |
+
|
| 4 |
+
Sources (downloaded from HF under data/real_code2lora/):
|
| 5 |
+
* code2lora-evo -- PRIMARY. Full per-commit history for all
|
| 6 |
+
400 train + 49 cr_val + 51 cr_test repos (58,617 commit rows for train
|
| 7 |
+
alone), each with repo_state_embedding (2048-d), diff_embedding
|
| 8 |
+
(2048-d, embeds production_code_diff), and the literal
|
| 9 |
+
production_code_diff text. QnA files (train/ir_val/ir_test/cr_val/
|
| 10 |
+
cr_test) carry assertion_event_type + old_target -- i.e. this is real
|
| 11 |
+
diff/change data, not just static snapshots.
|
| 12 |
+
* code2lora-static-anchor -- supplementary: qna/train.parquet has the
|
| 13 |
+
static-track anchor-based QnAs (different extraction protocol than
|
| 14 |
+
evo's train QnAs -- both are valid, kept as separate rows).
|
| 15 |
+
* repopeftbench-ood -- 92-repo temporal holdout, used only for
|
| 16 |
+
held-out evaluation, never trained on.
|
| 17 |
+
|
| 18 |
+
Output (appended, not overwritten, so re-running is additive-safe against
|
| 19 |
+
accidental double-runs is NOT guaranteed -- this script always rewrites
|
| 20 |
+
its own output files from scratch):
|
| 21 |
+
data/embeddings/real_code2lora_embeddings.parquet
|
| 22 |
+
doc_id = f"{repo_id}@{commit_sha[:10]}", doc_embedding = repo_state_embedding
|
| 23 |
+
data/qna/real_code2lora_qna.jsonl
|
| 24 |
+
one row per assertion-completion task, joined against the embeddings
|
| 25 |
+
above via the real (repo_id, commit_sha) pair (never guessed).
|
| 26 |
+
data/embeddings/real_code2lora_diffs.parquet
|
| 27 |
+
doc_id = f"{repo_id}@{commit_sha[:10]}", diff_embedding, and the raw
|
| 28 |
+
production_code_diff text -- kept SEPARATE from repo_state so a
|
| 29 |
+
future "what changed at this commit" task can condition on the diff
|
| 30 |
+
specifically rather than the whole-repo snapshot.
|
| 31 |
+
|
| 32 |
+
Usage:
|
| 33 |
+
python scripts/convert_real_code2lora.py
|
| 34 |
+
"""
|
| 35 |
+
|
| 36 |
+
from __future__ import annotations
|
| 37 |
+
|
| 38 |
+
import json
|
| 39 |
+
import sys
|
| 40 |
+
from pathlib import Path
|
| 41 |
+
from typing import Dict, Set, Tuple
|
| 42 |
+
|
| 43 |
+
import pyarrow as pa
|
| 44 |
+
import pyarrow.parquet as pq
|
| 45 |
+
|
| 46 |
+
HERE = Path(__file__).resolve().parent
|
| 47 |
+
REPO_ROOT = HERE.parent
|
| 48 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 49 |
+
from memory_lora.data_paths import DATA_ROOT, EMBEDDINGS_DIR, QNA_DIR, ensure_dirs # noqa: E402
|
| 50 |
+
|
| 51 |
+
REAL_ROOT = DATA_ROOT / "real_code2lora"
|
| 52 |
+
EVO_ROOT = REAL_ROOT / "code2lora-evo"
|
| 53 |
+
ANCHOR_ROOT = REAL_ROOT / "code2lora-static-anchor"
|
| 54 |
+
OOD_ROOT = REAL_ROOT / "repopeftbench-ood"
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def _doc_id(repo_id: str, commit_sha: str) -> str:
|
| 58 |
+
return f"{repo_id}@{str(commit_sha)[:10]}"
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def convert_embeddings_and_diffs() -> Set[Tuple[str, str]]:
|
| 62 |
+
"""evo/commits/{split}.parquet -> repo-state embeddings AND diff
|
| 63 |
+
embeddings (kept in separate output files). Returns the set of
|
| 64 |
+
(repo_id, commit_sha) pairs with a real embedding, for the QnA join."""
|
| 65 |
+
emb_rows, diff_rows = [], []
|
| 66 |
+
valid_keys: Set[Tuple[str, str]] = set()
|
| 67 |
+
seen_ids: Set[str] = set()
|
| 68 |
+
|
| 69 |
+
for split_file, split_label in [
|
| 70 |
+
("train.parquet", "train"), ("cr_val.parquet", "cr_val"), ("cr_test.parquet", "cr_test"),
|
| 71 |
+
]:
|
| 72 |
+
path = EVO_ROOT / "commits" / split_file
|
| 73 |
+
if not path.exists():
|
| 74 |
+
print(f" [skip] {path} not found", flush=True)
|
| 75 |
+
continue
|
| 76 |
+
table = pq.read_table(path, columns=[
|
| 77 |
+
"repo_id", "commit_sha", "repo_state_embedding", "diff_embedding", "production_code_diff",
|
| 78 |
+
])
|
| 79 |
+
n = table.num_rows
|
| 80 |
+
repo_col = table.column("repo_id").to_pylist()
|
| 81 |
+
sha_col = table.column("commit_sha").to_pylist()
|
| 82 |
+
emb_col = table.column("repo_state_embedding").to_pylist()
|
| 83 |
+
diff_emb_col = table.column("diff_embedding").to_pylist()
|
| 84 |
+
diff_text_col = table.column("production_code_diff").to_pylist()
|
| 85 |
+
for i in range(n):
|
| 86 |
+
key = (repo_col[i], sha_col[i])
|
| 87 |
+
valid_keys.add(key)
|
| 88 |
+
doc_id = _doc_id(*key)
|
| 89 |
+
if doc_id not in seen_ids:
|
| 90 |
+
seen_ids.add(doc_id)
|
| 91 |
+
emb_rows.append({
|
| 92 |
+
"doc_id": doc_id, "doc_version": sha_col[i],
|
| 93 |
+
"split": split_label, "category": "real_code_repo",
|
| 94 |
+
"doc_embedding": emb_col[i],
|
| 95 |
+
})
|
| 96 |
+
if diff_emb_col[i] is not None:
|
| 97 |
+
diff_rows.append({
|
| 98 |
+
"doc_id": doc_id, "doc_version": sha_col[i], "split": split_label,
|
| 99 |
+
"diff_embedding": diff_emb_col[i],
|
| 100 |
+
"diff_text": (diff_text_col[i] or "")[:4000],
|
| 101 |
+
})
|
| 102 |
+
print(f" evo {split_label}: {n} (repo, commit) rows, {len(set(repo_col))} unique repos", flush=True)
|
| 103 |
+
|
| 104 |
+
# supplementary: OOD holdout (from static-anchor, evo has no OOD split)
|
| 105 |
+
ood_file = OOD_ROOT / "ood_test.parquet"
|
| 106 |
+
if ood_file.exists():
|
| 107 |
+
table = pq.read_table(ood_file)
|
| 108 |
+
if "repo_state_embedding" in table.column_names:
|
| 109 |
+
n = table.num_rows
|
| 110 |
+
repo_col = table.column("repo_id").to_pylist()
|
| 111 |
+
sha_col = table.column("commit_sha").to_pylist()
|
| 112 |
+
emb_col = table.column("repo_state_embedding").to_pylist()
|
| 113 |
+
for i in range(n):
|
| 114 |
+
key = (repo_col[i], sha_col[i])
|
| 115 |
+
valid_keys.add(key)
|
| 116 |
+
doc_id = _doc_id(*key)
|
| 117 |
+
if doc_id not in seen_ids:
|
| 118 |
+
seen_ids.add(doc_id)
|
| 119 |
+
emb_rows.append({
|
| 120 |
+
"doc_id": doc_id, "doc_version": sha_col[i],
|
| 121 |
+
"split": "cr_test", "category": "real_code_repo_ood",
|
| 122 |
+
"doc_embedding": emb_col[i],
|
| 123 |
+
})
|
| 124 |
+
print(f" ood: {n} (repo, commit) rows, {len(set(repo_col))} unique repos", flush=True)
|
| 125 |
+
|
| 126 |
+
emb_table = pa.table({
|
| 127 |
+
"doc_id": [r["doc_id"] for r in emb_rows],
|
| 128 |
+
"doc_version": [r["doc_version"] for r in emb_rows],
|
| 129 |
+
"split": [r["split"] for r in emb_rows],
|
| 130 |
+
"category": [r["category"] for r in emb_rows],
|
| 131 |
+
"doc_embedding": [r["doc_embedding"] for r in emb_rows],
|
| 132 |
+
})
|
| 133 |
+
emb_path = EMBEDDINGS_DIR / "real_code2lora_embeddings.parquet"
|
| 134 |
+
pq.write_table(emb_table, emb_path)
|
| 135 |
+
print(f"Wrote {len(emb_rows)} real repo embeddings -> {emb_path}", flush=True)
|
| 136 |
+
|
| 137 |
+
diff_table = pa.table({
|
| 138 |
+
"doc_id": [r["doc_id"] for r in diff_rows],
|
| 139 |
+
"doc_version": [r["doc_version"] for r in diff_rows],
|
| 140 |
+
"split": [r["split"] for r in diff_rows],
|
| 141 |
+
"diff_embedding": [r["diff_embedding"] for r in diff_rows],
|
| 142 |
+
"diff_text": [r["diff_text"] for r in diff_rows],
|
| 143 |
+
})
|
| 144 |
+
diff_path = EMBEDDINGS_DIR / "real_code2lora_diffs.parquet"
|
| 145 |
+
pq.write_table(diff_table, diff_path)
|
| 146 |
+
print(f"Wrote {len(diff_rows)} real diff embeddings -> {diff_path}", flush=True)
|
| 147 |
+
|
| 148 |
+
return valid_keys
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def convert_qna(valid_keys: Set[Tuple[str, str]]) -> int:
|
| 152 |
+
"""evo/qna/{split}.parquet (primary) + static-anchor/qna/train.parquet
|
| 153 |
+
(supplementary static-track anchors) -> our jsonl rows, joined against
|
| 154 |
+
valid_keys (only keep QnAs whose (repo_id, commit_sha) has a real
|
| 155 |
+
embedding)."""
|
| 156 |
+
out_path = QNA_DIR / "real_code2lora_qna.jsonl"
|
| 157 |
+
n_written, n_dropped = 0, 0
|
| 158 |
+
|
| 159 |
+
sources = [
|
| 160 |
+
(EVO_ROOT / "qna" / "train.parquet", "train", "train"),
|
| 161 |
+
(EVO_ROOT / "qna" / "ir_val.parquet", "train", "held_out"),
|
| 162 |
+
(EVO_ROOT / "qna" / "ir_test.parquet", "train", "held_out"),
|
| 163 |
+
(EVO_ROOT / "qna" / "cr_val.parquet", "cr_val", "held_out"),
|
| 164 |
+
(EVO_ROOT / "qna" / "cr_test.parquet", "cr_test", "held_out"),
|
| 165 |
+
(ANCHOR_ROOT / "qna" / "train.parquet", "train", "train"),
|
| 166 |
+
]
|
| 167 |
+
with out_path.open("w") as f:
|
| 168 |
+
for path, doc_split, qna_split in sources:
|
| 169 |
+
if not path.exists():
|
| 170 |
+
print(f" [skip] {path} not found", flush=True)
|
| 171 |
+
continue
|
| 172 |
+
table = pq.read_table(path, columns=["repo_id", "commit_sha", "prefix", "target"])
|
| 173 |
+
n = table.num_rows
|
| 174 |
+
repo_col = table.column("repo_id").to_pylist()
|
| 175 |
+
sha_col = table.column("commit_sha").to_pylist()
|
| 176 |
+
prefix_col = table.column("prefix").to_pylist()
|
| 177 |
+
target_col = table.column("target").to_pylist()
|
| 178 |
+
kept = 0
|
| 179 |
+
for i in range(n):
|
| 180 |
+
key = (repo_col[i], sha_col[i])
|
| 181 |
+
if key not in valid_keys:
|
| 182 |
+
n_dropped += 1
|
| 183 |
+
continue
|
| 184 |
+
f.write(json.dumps({
|
| 185 |
+
"doc_id": _doc_id(repo_col[i], sha_col[i]), "doc_version": sha_col[i],
|
| 186 |
+
"split": doc_split, "qna_split": qna_split,
|
| 187 |
+
"question": "", "prefix": prefix_col[i], "target": target_col[i],
|
| 188 |
+
}) + "\n")
|
| 189 |
+
n_written += 1
|
| 190 |
+
kept += 1
|
| 191 |
+
print(f" {path.parent.parent.name}/{path.name}: {kept}/{n} QnAs matched "
|
| 192 |
+
f"-> split={doc_split} qna_split={qna_split}", flush=True)
|
| 193 |
+
print(f"Wrote {n_written} real QnA pairs ({n_dropped} dropped, no matching "
|
| 194 |
+
f"embedding) -> {out_path}", flush=True)
|
| 195 |
+
return n_written
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def main() -> None:
|
| 199 |
+
ensure_dirs()
|
| 200 |
+
print("Converting real repo + diff embeddings (from code2lora-evo)...", flush=True)
|
| 201 |
+
valid_keys = convert_embeddings_and_diffs()
|
| 202 |
+
print(f"\n{len(valid_keys)} valid (repo, commit) embedding keys found.\n", flush=True)
|
| 203 |
+
print("Converting real QnA pairs (joined against real embeddings)...", flush=True)
|
| 204 |
+
n_qna = convert_qna(valid_keys)
|
| 205 |
+
print(f"\nDone: {len(valid_keys)} real repo-commit docs, {n_qna} real QnA pairs.", flush=True)
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
if __name__ == "__main__":
|
| 209 |
+
main()
|
scripts/diag_mps_leak.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Isolated MPS memory-leak diagnostic.
|
| 3 |
+
|
| 4 |
+
Runs a minimal train-step loop on REAL code prefixes and prints
|
| 5 |
+
system-available memory after every single operation, aborting the moment
|
| 6 |
+
it crosses a hard floor. Tests one variable at a time (gradient
|
| 7 |
+
checkpointing on/off, empty_cache on/off) so we can pinpoint what actually
|
| 8 |
+
leaks, without the full training harness in the way.
|
| 9 |
+
"""
|
| 10 |
+
from __future__ import annotations
|
| 11 |
+
import argparse, json, sys, time
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
import psutil, torch, torch.nn.functional as F
|
| 14 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 15 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 16 |
+
from memory_lora.core import (MemoryLoRAHead, get_module_specs, discover_module_types_and_dims,
|
| 17 |
+
inject_lora_weights, replace_with_lora, DEFAULT_ROOT_PREFIX)
|
| 18 |
+
from transformers import AutoModelForImageTextToText, AutoTokenizer
|
| 19 |
+
|
| 20 |
+
TARGET_MODULES = ["q_proj","k_proj","v_proj","o_proj","up_proj","gate_proj","down_proj"]
|
| 21 |
+
|
| 22 |
+
def avail_gb(): return psutil.virtual_memory().available / 1e9
|
| 23 |
+
|
| 24 |
+
def main():
|
| 25 |
+
ap = argparse.ArgumentParser()
|
| 26 |
+
ap.add_argument("--grad-checkpoint", action="store_true")
|
| 27 |
+
ap.add_argument("--empty-cache-every", type=int, default=0, help="0=never")
|
| 28 |
+
ap.add_argument("--steps", type=int, default=10)
|
| 29 |
+
ap.add_argument("--seq-len", type=int, default=512)
|
| 30 |
+
ap.add_argument("--micro-batch", type=int, default=2)
|
| 31 |
+
ap.add_argument("--floor-gb", type=float, default=22.0)
|
| 32 |
+
ap.add_argument("--train", action="store_true", help="do backward (else forward-only)")
|
| 33 |
+
args = ap.parse_args()
|
| 34 |
+
device = torch.device("mps")
|
| 35 |
+
|
| 36 |
+
print(f"[cfg] grad_ckpt={args.grad_checkpoint} empty_cache_every={args.empty_cache_every} "
|
| 37 |
+
f"train={args.train} seq={args.seq_len} mb={args.micro_batch}", flush=True)
|
| 38 |
+
print(f"[mem] start avail={avail_gb():.1f}GB", flush=True)
|
| 39 |
+
|
| 40 |
+
tok = AutoTokenizer.from_pretrained("google/gemma-4-E2B")
|
| 41 |
+
if tok.pad_token is None: tok.pad_token = tok.eos_token
|
| 42 |
+
model = AutoModelForImageTextToText.from_pretrained(
|
| 43 |
+
"google/gemma-4-E2B", torch_dtype=torch.bfloat16, attn_implementation="sdpa").to(device)
|
| 44 |
+
model.eval()
|
| 45 |
+
for p in model.parameters(): p.requires_grad = False
|
| 46 |
+
print(f"[mem] after model load avail={avail_gb():.1f}GB", flush=True)
|
| 47 |
+
if args.grad_checkpoint:
|
| 48 |
+
model.config.use_cache = False
|
| 49 |
+
model.gradient_checkpointing_enable(gradient_checkpointing_kwargs={"use_reentrant": False})
|
| 50 |
+
print(" gradient checkpointing ON", flush=True)
|
| 51 |
+
|
| 52 |
+
specs = get_module_specs(model, TARGET_MODULES, root_prefix=DEFAULT_ROOT_PREFIX)
|
| 53 |
+
type_dims = discover_module_types_and_dims(specs)
|
| 54 |
+
replace_with_lora(model, specs, rank=16, alpha=32.0)
|
| 55 |
+
head = MemoryLoRAHead(input_dim=2048, type_dims=type_dims, hidden_dim=512, rank=16).to(device)
|
| 56 |
+
print(f"[mem] after head+lora avail={avail_gb():.1f}GB", flush=True)
|
| 57 |
+
|
| 58 |
+
# real prefixes
|
| 59 |
+
prefixes, targets = [], []
|
| 60 |
+
with open(REPO_ROOT / "data/qna/real_code2lora_qna.jsonl") as f:
|
| 61 |
+
for line in f:
|
| 62 |
+
d = json.loads(line); prefixes.append(d["prefix"]); targets.append(d["target"])
|
| 63 |
+
if len(prefixes) >= args.steps * args.micro_batch: break
|
| 64 |
+
ctx = torch.randn(1, 2048, device=device)
|
| 65 |
+
|
| 66 |
+
for step in range(args.steps):
|
| 67 |
+
if avail_gb() < args.floor_gb:
|
| 68 |
+
print(f"[ABORT] avail={avail_gb():.1f}GB < floor {args.floor_gb} at step {step}", flush=True)
|
| 69 |
+
break
|
| 70 |
+
i0 = step * args.micro_batch
|
| 71 |
+
ps = prefixes[i0:i0+args.micro_batch]; ts = targets[i0:i0+args.micro_batch]
|
| 72 |
+
ids_list, lab_list = [], []
|
| 73 |
+
for p, t in zip(ps, ts):
|
| 74 |
+
tids = tok(t + (tok.eos_token or ""), add_special_tokens=False)["input_ids"]
|
| 75 |
+
pids = tok(p, add_special_tokens=False)["input_ids"]
|
| 76 |
+
budget = max(8, args.seq_len - len(tids)); pids = pids[-budget:]
|
| 77 |
+
ids = pids + tids; lab = [-100]*len(pids) + list(tids)
|
| 78 |
+
ids_list.append(torch.tensor(ids)); lab_list.append(torch.tensor(lab))
|
| 79 |
+
L = args.seq_len
|
| 80 |
+
pad = tok.pad_token_id or 0
|
| 81 |
+
def lp(x, v): return F.pad(x, (L-x.size(0),0), value=v) if x.size(0)<=L else x[-L:]
|
| 82 |
+
input_ids = torch.stack([lp(t,pad) for t in ids_list]).to(device)
|
| 83 |
+
labels = torch.stack([lp(t,-100) for t in lab_list]).to(device)
|
| 84 |
+
attn = (input_ids != pad).long().to(device)
|
| 85 |
+
head_out = head(ctx); inject_lora_weights(model, specs, head_out, batch_index=0)
|
| 86 |
+
if args.train:
|
| 87 |
+
out = model(input_ids=input_ids, attention_mask=attn, labels=labels)
|
| 88 |
+
(out.loss).backward()
|
| 89 |
+
head.zero_grad(set_to_none=True)
|
| 90 |
+
else:
|
| 91 |
+
with torch.no_grad():
|
| 92 |
+
out = model(input_ids=input_ids, attention_mask=attn, labels=labels)
|
| 93 |
+
loss_val = out.loss.item()
|
| 94 |
+
del head_out, out
|
| 95 |
+
if args.empty_cache_every and step % args.empty_cache_every == 0:
|
| 96 |
+
torch.mps.empty_cache()
|
| 97 |
+
print(f"[step {step}] loss={loss_val:.3f} avail={avail_gb():.1f}GB", flush=True)
|
| 98 |
+
print(f"[done] final avail={avail_gb():.1f}GB", flush=True)
|
| 99 |
+
|
| 100 |
+
if __name__ == "__main__":
|
| 101 |
+
main()
|
scripts/eval_memory_lora.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Evaluate a trained Memory-LoRA head: recall EM/EditSim on held-out QA,
|
| 3 |
+
split into in-corpus (ir_test) and cross-corpus (cr_val/cr_test), plus a
|
| 4 |
+
manual spot-check comparing the LoRA-adapted model against the bare base
|
| 5 |
+
model on hand-picked Code2LoRA-paper questions (proof the adapter, not
|
| 6 |
+
general pretraining, is doing the recall).
|
| 7 |
+
|
| 8 |
+
Forked from Code2LoRA's evaluation metrics (EM after whitespace collapsing
|
| 9 |
+
+ trailing-punctuation removal with relaxed prefix matching; EditSim via
|
| 10 |
+
difflib.SequenceMatcher).
|
| 11 |
+
|
| 12 |
+
Usage:
|
| 13 |
+
python scripts/eval_memory_lora.py --checkpoint runs/full1/head.best.pt
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
from __future__ import annotations
|
| 17 |
+
|
| 18 |
+
import argparse
|
| 19 |
+
import difflib
|
| 20 |
+
import json
|
| 21 |
+
import re
|
| 22 |
+
import sys
|
| 23 |
+
from pathlib import Path
|
| 24 |
+
from typing import Any, Dict, List
|
| 25 |
+
|
| 26 |
+
import torch
|
| 27 |
+
from transformers import AutoModelForImageTextToText, AutoTokenizer
|
| 28 |
+
|
| 29 |
+
HERE = Path(__file__).resolve().parent
|
| 30 |
+
REPO_ROOT = HERE.parent
|
| 31 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 32 |
+
from memory_lora.data_paths import EMBEDDINGS_DIR, QNA_DIR # noqa: E402
|
| 33 |
+
from memory_lora.core import ( # noqa: E402
|
| 34 |
+
MemoryLoRAHead,
|
| 35 |
+
DEFAULT_ROOT_PREFIX,
|
| 36 |
+
get_module_specs,
|
| 37 |
+
inject_lora_weights,
|
| 38 |
+
load_doc_rows,
|
| 39 |
+
load_qna_rows,
|
| 40 |
+
replace_with_lora,
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
DEFAULT_MODEL = "google/gemma-4-E2B"
|
| 44 |
+
DEFAULT_TARGET_MODULES = [
|
| 45 |
+
"q_proj", "k_proj", "v_proj", "o_proj",
|
| 46 |
+
"up_proj", "gate_proj", "down_proj",
|
| 47 |
+
]
|
| 48 |
+
|
| 49 |
+
SPOT_CHECK_QUESTIONS = [
|
| 50 |
+
("What LoRA rank does Code2LoRA's static hypernetwork use?", "16"),
|
| 51 |
+
("How many trainable parameters does Code2LoRA-Static have?", "720 million"),
|
| 52 |
+
("What is the cross-repo exact match of Code2LoRA-Static on the static track?", "63.8%"),
|
| 53 |
+
("How many Python repositories are in RepoPeftBench?", "604"),
|
| 54 |
+
("What is the base LLM used in Code2LoRA's experiments?", "Qwen2.5-Coder-1.5B"),
|
| 55 |
+
]
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def normalize(s: str) -> str:
|
| 59 |
+
s = s.strip().rstrip(".,;:!?")
|
| 60 |
+
s = re.sub(r"\s+", " ", s)
|
| 61 |
+
return s.lower()
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def exact_match(pred: str, target: str) -> bool:
|
| 65 |
+
p, t = normalize(pred), normalize(target)
|
| 66 |
+
return p == t or p.startswith(t) or t.startswith(p)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def edit_sim(pred: str, target: str) -> float:
|
| 70 |
+
return difflib.SequenceMatcher(None, normalize(pred), normalize(target)).ratio()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
@torch.no_grad()
|
| 74 |
+
def generate(base_model, tokenizer, prefix: str, device, max_new_tokens: int = 12) -> str:
|
| 75 |
+
"""Greedy-decode the answer, then truncate at the first newline.
|
| 76 |
+
|
| 77 |
+
Without this the model frequently keeps going past the answer into a
|
| 78 |
+
hallucinated ``\\nQ: <next question>`` continuation (base models without
|
| 79 |
+
an EOS-triggering chat template rarely stop cleanly on a bare
|
| 80 |
+
completion prompt); comparing the *untruncated* string against the gold
|
| 81 |
+
answer would mark an otherwise-correct short answer wrong just because
|
| 82 |
+
of what it rambled into afterward.
|
| 83 |
+
"""
|
| 84 |
+
enc = tokenizer(prefix, return_tensors="pt").to(device)
|
| 85 |
+
out = base_model.generate(
|
| 86 |
+
**enc, max_new_tokens=max_new_tokens, do_sample=False,
|
| 87 |
+
pad_token_id=tokenizer.pad_token_id or tokenizer.eos_token_id,
|
| 88 |
+
)
|
| 89 |
+
gen_ids = out[0][enc["input_ids"].shape[1]:]
|
| 90 |
+
text = tokenizer.decode(gen_ids, skip_special_tokens=True)
|
| 91 |
+
return text.split("\n")[0]
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def load_head_and_model(checkpoint: Path, model_name: str, target_modules: List[str],
|
| 95 |
+
root_prefix: str, device: torch.device, dtype: torch.dtype,
|
| 96 |
+
attn_implementation: str):
|
| 97 |
+
ckpt = torch.load(checkpoint, map_location="cpu")
|
| 98 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 99 |
+
if tokenizer.pad_token is None:
|
| 100 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 101 |
+
base_model = AutoModelForImageTextToText.from_pretrained(
|
| 102 |
+
model_name, torch_dtype=dtype, attn_implementation=attn_implementation,
|
| 103 |
+
).to(device)
|
| 104 |
+
base_model.eval()
|
| 105 |
+
for p in base_model.parameters():
|
| 106 |
+
p.requires_grad = False
|
| 107 |
+
|
| 108 |
+
specs = get_module_specs(base_model, target_modules, root_prefix=root_prefix)
|
| 109 |
+
rank = ckpt["config"]["rank"]
|
| 110 |
+
alpha = ckpt["args"].get("alpha", 32.0)
|
| 111 |
+
replace_with_lora(base_model, specs, rank=rank, alpha=alpha)
|
| 112 |
+
|
| 113 |
+
head = MemoryLoRAHead(
|
| 114 |
+
input_dim=ckpt["config"]["input_dim"],
|
| 115 |
+
type_dims={k: tuple(v) for k, v in ckpt["config"]["type_dims"].items()},
|
| 116 |
+
hidden_dim=ckpt["config"]["hidden_dim"],
|
| 117 |
+
rank=rank,
|
| 118 |
+
).to(device)
|
| 119 |
+
head.load_state_dict(ckpt["state_dict"])
|
| 120 |
+
head.eval()
|
| 121 |
+
return base_model, head, specs, tokenizer
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def eval_suite(base_model, head, specs, tokenizer, doc_rows, qnas_by_doc, device,
|
| 125 |
+
max_qna_per_doc: int = 20) -> Dict[str, float]:
|
| 126 |
+
n_em, n_total, sum_editsim = 0, 0, 0.0
|
| 127 |
+
for dr in doc_rows:
|
| 128 |
+
pairs = qnas_by_doc.get(dr.doc_id, [])[:max_qna_per_doc]
|
| 129 |
+
if not pairs:
|
| 130 |
+
continue
|
| 131 |
+
ctx = torch.from_numpy(dr.doc_embedding).to(device).unsqueeze(0)
|
| 132 |
+
head_out = head(ctx)
|
| 133 |
+
inject_lora_weights(base_model, specs, head_out, batch_index=0)
|
| 134 |
+
for p in pairs:
|
| 135 |
+
pred = generate(base_model, tokenizer, p["prefix"], device)
|
| 136 |
+
target = p["target"]
|
| 137 |
+
if exact_match(pred, target):
|
| 138 |
+
n_em += 1
|
| 139 |
+
sum_editsim += edit_sim(pred, target)
|
| 140 |
+
n_total += 1
|
| 141 |
+
return {
|
| 142 |
+
"em": n_em / max(n_total, 1),
|
| 143 |
+
"editsim": sum_editsim / max(n_total, 1),
|
| 144 |
+
"n": n_total,
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
def main() -> None:
|
| 149 |
+
ap = argparse.ArgumentParser()
|
| 150 |
+
ap.add_argument("--checkpoint", required=True)
|
| 151 |
+
ap.add_argument("--embeddings-path", default=str(EMBEDDINGS_DIR / "doc_embeddings.parquet"))
|
| 152 |
+
ap.add_argument("--qna-path", default=str(QNA_DIR / "qna.jsonl"))
|
| 153 |
+
ap.add_argument("--model-name", default=DEFAULT_MODEL)
|
| 154 |
+
ap.add_argument("--target-modules", nargs="+", default=DEFAULT_TARGET_MODULES)
|
| 155 |
+
ap.add_argument("--root-prefix", default=DEFAULT_ROOT_PREFIX)
|
| 156 |
+
ap.add_argument("--device", default="mps")
|
| 157 |
+
ap.add_argument("--dtype", default="bfloat16", choices=["bfloat16", "float16", "float32"])
|
| 158 |
+
ap.add_argument("--attn-implementation", default="sdpa", choices=["sdpa", "eager"])
|
| 159 |
+
ap.add_argument("--suites", nargs="+", default=["cr_val", "cr_test", "ir_test"])
|
| 160 |
+
ap.add_argument("--max-qna-per-doc", type=int, default=20)
|
| 161 |
+
ap.add_argument("--limit-docs", type=int, default=0,
|
| 162 |
+
help="Random-sample at most N docs per suite (fixed seed) "
|
| 163 |
+
"for a fast estimate -- cr_test has thousands of real "
|
| 164 |
+
"repos, far too many to greedy-generate on CPU.")
|
| 165 |
+
ap.add_argument("--skip-spot-check", action="store_true")
|
| 166 |
+
args = ap.parse_args()
|
| 167 |
+
|
| 168 |
+
device = torch.device(args.device if (args.device != "mps" or torch.backends.mps.is_available()) else "cpu")
|
| 169 |
+
dtype = {"bfloat16": torch.bfloat16, "float16": torch.float16, "float32": torch.float32}[args.dtype]
|
| 170 |
+
|
| 171 |
+
base_model, head, specs, tokenizer = load_head_and_model(
|
| 172 |
+
Path(args.checkpoint), args.model_name, args.target_modules,
|
| 173 |
+
args.root_prefix, device, dtype, args.attn_implementation,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
all_docs = load_doc_rows(Path(args.embeddings_path))
|
| 177 |
+
all_qnas = load_qna_rows(Path(args.qna_path))
|
| 178 |
+
qnas_by_doc_all = {}
|
| 179 |
+
qnas_held_out_by_doc = {}
|
| 180 |
+
for q in all_qnas:
|
| 181 |
+
qnas_by_doc_all.setdefault(q.doc_id, []).append({"prefix": q.prefix, "target": q.target})
|
| 182 |
+
if q.qna_split == "held_out":
|
| 183 |
+
qnas_held_out_by_doc.setdefault(q.doc_id, []).append({"prefix": q.prefix, "target": q.target})
|
| 184 |
+
train_docs = [d for d in all_docs if d.split == "train"]
|
| 185 |
+
|
| 186 |
+
results: Dict[str, Any] = {}
|
| 187 |
+
for suite in args.suites:
|
| 188 |
+
if suite in ("cr_val", "cr_test"):
|
| 189 |
+
rows, q_by_doc = [d for d in all_docs if d.split == suite], qnas_by_doc_all
|
| 190 |
+
elif suite == "ir_test":
|
| 191 |
+
rows, q_by_doc = train_docs, qnas_held_out_by_doc
|
| 192 |
+
else:
|
| 193 |
+
continue
|
| 194 |
+
if args.limit_docs and len(rows) > args.limit_docs:
|
| 195 |
+
import random as _r
|
| 196 |
+
rows = _r.Random(3407).sample(rows, args.limit_docs)
|
| 197 |
+
print(f"Evaluating {suite} ({len(rows)} docs) ...", flush=True)
|
| 198 |
+
m = eval_suite(base_model, head, specs, tokenizer, rows, q_by_doc, device,
|
| 199 |
+
max_qna_per_doc=args.max_qna_per_doc)
|
| 200 |
+
results[suite] = m
|
| 201 |
+
print(f" {suite}: EM={m['em']:.3f} EditSim={m['editsim']:.3f} n={m['n']}", flush=True)
|
| 202 |
+
|
| 203 |
+
print(json.dumps(results, indent=2))
|
| 204 |
+
|
| 205 |
+
if not args.skip_spot_check:
|
| 206 |
+
print("\n=== Spot check: base model vs. LoRA-adapted, Code2LoRA paper facts ===", flush=True)
|
| 207 |
+
paper_doc = next((d for d in all_docs if d.doc_id == "code2lora_paper"), None)
|
| 208 |
+
if paper_doc is None:
|
| 209 |
+
print(" [skip] code2lora_paper doc not found in embeddings", flush=True)
|
| 210 |
+
else:
|
| 211 |
+
ctx = torch.from_numpy(paper_doc.doc_embedding).to(device).unsqueeze(0)
|
| 212 |
+
head_out = head(ctx)
|
| 213 |
+
for q, gold in SPOT_CHECK_QUESTIONS:
|
| 214 |
+
prefix = f"Q: {q}\nA:"
|
| 215 |
+
# base: zero out LoRA (A=B=None) by re-wrapping without injection
|
| 216 |
+
for sp in specs:
|
| 217 |
+
named = dict(base_model.named_modules())
|
| 218 |
+
named[sp.full_name].A = None
|
| 219 |
+
named[sp.full_name].B = None
|
| 220 |
+
base_pred = generate(base_model, tokenizer, prefix, device)
|
| 221 |
+
inject_lora_weights(base_model, specs, head_out, batch_index=0)
|
| 222 |
+
adapted_pred = generate(base_model, tokenizer, prefix, device)
|
| 223 |
+
print(f"Q: {q}")
|
| 224 |
+
print(f" gold: {gold}")
|
| 225 |
+
print(f" base: {base_pred!r}")
|
| 226 |
+
print(f" adapted: {adapted_pred!r}")
|
| 227 |
+
print()
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
if __name__ == "__main__":
|
| 231 |
+
main()
|
scripts/generate_commitpack_qa.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Breadth generator: judgment QA from CommitPackFT commits across THOUSANDS
|
| 3 |
+
of DISTINCT repos (25k distinct repos in the python shard alone).
|
| 4 |
+
|
| 5 |
+
Complements generate_techlead_qa.py (SWE-bench), which is deep but spans only
|
| 6 |
+
~12 repos. For a HYPERNETWORK, distinct-repo count is the currency of
|
| 7 |
+
generalization -- so this takes ~1 commit per NEW repo to maximize breadth,
|
| 8 |
+
not many commits of the same repo.
|
| 9 |
+
|
| 10 |
+
Commit-scope judgment aspects (a single small commit rarely shows whole-system
|
| 11 |
+
architecture, so we skip that): why / conventions / contracts / impact.
|
| 12 |
+
Same Tier-A/B discipline: short judgment answers, no exact file/line lists.
|
| 13 |
+
gemini-3.6-flash reasoning is mandatory -> generous max_tokens.
|
| 14 |
+
|
| 15 |
+
Usage:
|
| 16 |
+
python scripts/generate_commitpack_qa.py --limit 3
|
| 17 |
+
python scripts/generate_commitpack_qa.py --max-repos 2500 --per-repo 1
|
| 18 |
+
"""
|
| 19 |
+
from __future__ import annotations
|
| 20 |
+
import argparse, hashlib, json, os, re, sys, time
|
| 21 |
+
from pathlib import Path
|
| 22 |
+
from typing import Dict, List
|
| 23 |
+
from openai import OpenAI
|
| 24 |
+
|
| 25 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 26 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 27 |
+
from memory_lora.data_paths import QNA_DIR, DOCS_DIR, CACHE_DIR, ensure_dirs # noqa: E402
|
| 28 |
+
|
| 29 |
+
def _load_dotenv(p: Path):
|
| 30 |
+
if p.exists():
|
| 31 |
+
for line in p.read_text().splitlines():
|
| 32 |
+
if "=" in line and not line.strip().startswith("#"):
|
| 33 |
+
k, v = line.split("=", 1); os.environ.setdefault(k.strip(), v.strip())
|
| 34 |
+
_load_dotenv(REPO_ROOT / ".env")
|
| 35 |
+
|
| 36 |
+
MODEL = "google/gemini-3.6-flash"
|
| 37 |
+
BASE_URL = "https://openrouter.ai/api/v1"
|
| 38 |
+
SHARD = REPO_ROOT / "data" / "commitpack" / "multilang_commits.jsonl"
|
| 39 |
+
|
| 40 |
+
SYSTEM = (
|
| 41 |
+
"You are a staff engineer writing onboarding Q&A about a single real commit. "
|
| 42 |
+
"Given the commit message and the before/after file contents, produce a JSON "
|
| 43 |
+
"array of 3-4 objects with keys 'aspect','question','answer'. aspect in: "
|
| 44 |
+
"why, conventions, contracts, impact. Rules: (1) test JUDGMENT/understanding, "
|
| 45 |
+
"not trivia. (2) answers SHORT -- one phrase/sentence, no file paths or line "
|
| 46 |
+
"numbers. (3) 'why' = rationale/trade-off; 'impact' = the KIND of behavior/"
|
| 47 |
+
"contract affected, not a file list; 'conventions' = the idiom/style this "
|
| 48 |
+
"change follows. (4) ground answers in the actual change; invent nothing. "
|
| 49 |
+
"Output ONLY the JSON array."
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
def cache_key(*p): return hashlib.sha256("||".join(p).encode()).hexdigest()[:24]
|
| 53 |
+
|
| 54 |
+
def gen_qa(client, ctx, cache_dir, retries=4) -> List[Dict]:
|
| 55 |
+
cf = cache_dir / f"cpqa_{cache_key(MODEL, ctx)}.json"
|
| 56 |
+
if cf.exists():
|
| 57 |
+
raw = cf.read_text()
|
| 58 |
+
else:
|
| 59 |
+
last = None
|
| 60 |
+
for a in range(retries):
|
| 61 |
+
try:
|
| 62 |
+
r = client.chat.completions.create(model=MODEL,
|
| 63 |
+
messages=[{"role": "system", "content": SYSTEM},
|
| 64 |
+
{"role": "user", "content": ctx}],
|
| 65 |
+
max_tokens=3000, temperature=0.6)
|
| 66 |
+
raw = r.choices[0].message.content or ""; cf.write_text(raw); break
|
| 67 |
+
except Exception as e: # noqa: BLE001
|
| 68 |
+
last = e; time.sleep(2 ** a)
|
| 69 |
+
else:
|
| 70 |
+
return []
|
| 71 |
+
m = re.search(r"\[.*\]", raw, re.DOTALL)
|
| 72 |
+
if not m: return []
|
| 73 |
+
try: items = json.loads(m.group(0))
|
| 74 |
+
except json.JSONDecodeError: return []
|
| 75 |
+
out = []
|
| 76 |
+
for it in items:
|
| 77 |
+
q = (it.get("question") or "").strip(); a = (it.get("answer") or "").strip()
|
| 78 |
+
asp = (it.get("aspect") or "general").strip()
|
| 79 |
+
if q and a and len(a) < 240: out.append({"aspect": asp, "question": q, "answer": a})
|
| 80 |
+
return out
|
| 81 |
+
|
| 82 |
+
def build_ctx(d) -> str:
|
| 83 |
+
def clip(s, n): return (s or "")[:n]
|
| 84 |
+
return (f"REPO: {d['repos'].split(',')[0]} FILE: {d.get('new_file','')}\n"
|
| 85 |
+
f"COMMIT: {clip(d.get('subject'),120)}\n{clip(d.get('message'),500)}\n\n"
|
| 86 |
+
f"BEFORE:\n{clip(d.get('old_contents'),1800)}\n\n"
|
| 87 |
+
f"AFTER:\n{clip(d.get('new_contents'),1800)}")
|
| 88 |
+
|
| 89 |
+
def main():
|
| 90 |
+
import threading
|
| 91 |
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 92 |
+
ap = argparse.ArgumentParser()
|
| 93 |
+
ap.add_argument("--max-repos", type=int, default=2500)
|
| 94 |
+
ap.add_argument("--per-repo", type=int, default=1)
|
| 95 |
+
ap.add_argument("--limit", type=int, default=0)
|
| 96 |
+
ap.add_argument("--model", default=MODEL)
|
| 97 |
+
ap.add_argument("--workers", type=int, default=10,
|
| 98 |
+
help="Concurrent OpenRouter requests. Sequential gen was "
|
| 99 |
+
"~10x too slow for 3k+ repos; the API handles "
|
| 100 |
+
"concurrency fine and the per-prompt cache keeps it "
|
| 101 |
+
"idempotent.")
|
| 102 |
+
args = ap.parse_args()
|
| 103 |
+
globals()["MODEL"] = args.model
|
| 104 |
+
ensure_dirs()
|
| 105 |
+
key = os.environ.get("OPENROUTER_API_KEY")
|
| 106 |
+
if not key: raise SystemExit("OPENROUTER_API_KEY not set")
|
| 107 |
+
client = OpenAI(base_url=BASE_URL, api_key=key)
|
| 108 |
+
|
| 109 |
+
target = args.limit if args.limit else args.max_repos
|
| 110 |
+
# select one commit per distinct repo (breadth), up to target
|
| 111 |
+
seen: Dict[str, int] = {}
|
| 112 |
+
tasks = []
|
| 113 |
+
for line in open(SHARD):
|
| 114 |
+
if len(tasks) >= target: break
|
| 115 |
+
try: d = json.loads(line)
|
| 116 |
+
except json.JSONDecodeError: continue
|
| 117 |
+
repo = d["repos"].split(",")[0]
|
| 118 |
+
if seen.get(repo, 0) >= args.per_repo: continue
|
| 119 |
+
seen[repo] = seen.get(repo, 0) + 1
|
| 120 |
+
tasks.append(d)
|
| 121 |
+
|
| 122 |
+
qna_f = (QNA_DIR / "techlead_qa_commitpack.jsonl").open("a")
|
| 123 |
+
src_f = (DOCS_DIR / "techlead_sources_commitpack.jsonl").open("a")
|
| 124 |
+
lock = threading.Lock()
|
| 125 |
+
n_docs = [0]; n_qa = [0]; t0 = time.time()
|
| 126 |
+
|
| 127 |
+
def work(d):
|
| 128 |
+
repo = d["repos"].split(",")[0]
|
| 129 |
+
qas = gen_qa(client, build_ctx(d), CACHE_DIR)
|
| 130 |
+
if not qas: return
|
| 131 |
+
doc_id = f"{repo}@{d['commit'][:10]}"
|
| 132 |
+
with lock:
|
| 133 |
+
src_f.write(json.dumps({"doc_id": doc_id, "repo": repo, "base_commit": d["commit"],
|
| 134 |
+
"context": build_ctx(d), "source": "commitpackft", "lang": d.get("lang","python")}) + "\n")
|
| 135 |
+
for qa in qas:
|
| 136 |
+
qna_f.write(json.dumps({"doc_id": doc_id, "doc_version": d["commit"],
|
| 137 |
+
"split": "train", "qna_split": "train", "aspect": qa["aspect"],
|
| 138 |
+
"question": qa["question"], "prefix": f"Q: {qa['question']}\nA:",
|
| 139 |
+
"target": " " + qa["answer"], "lang": d.get("lang","python")}) + "\n")
|
| 140 |
+
n_qa[0] += 1
|
| 141 |
+
n_docs[0] += 1
|
| 142 |
+
if n_docs[0] % 50 == 0:
|
| 143 |
+
rate = n_docs[0] / max(1e-9, (time.time() - t0) / 60)
|
| 144 |
+
print(f" {n_docs[0]} repos, {n_qa[0]} QA ({rate:.1f} repo/min)", flush=True)
|
| 145 |
+
|
| 146 |
+
with ThreadPoolExecutor(max_workers=args.workers) as ex:
|
| 147 |
+
for _ in as_completed([ex.submit(work, d) for d in tasks]):
|
| 148 |
+
pass
|
| 149 |
+
qna_f.close(); src_f.close()
|
| 150 |
+
print(f"\nDone. {n_docs[0]} DISTINCT repos -> {n_qa[0]} judgment-QA pairs.", flush=True)
|
| 151 |
+
|
| 152 |
+
if __name__ == "__main__":
|
| 153 |
+
main()
|
scripts/generate_repo_scoped_qa.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Generate REPO-SCOPED judgment QA from the SAME 6 views that
|
| 3 |
+
build_repo_multiview.py embedded -- so target scope matches input scope
|
| 4 |
+
(a repo-level embedding must be paired with repo-level questions, not
|
| 5 |
+
commit-scoped ones). Reads data/docs/multiview_sources.jsonl (per-repo
|
| 6 |
+
view_text) and writes data/qna/repo_scoped_qa.jsonl keyed by the same
|
| 7 |
+
doc_id (= repo name).
|
| 8 |
+
|
| 9 |
+
gemini-3.6-flash: reasoning mandatory -> generous max_tokens.
|
| 10 |
+
Tier-A/B discipline: judgment answers, short, no exact file/line lists.
|
| 11 |
+
|
| 12 |
+
Usage:
|
| 13 |
+
python scripts/generate_repo_scoped_qa.py --limit 3
|
| 14 |
+
python scripts/generate_repo_scoped_qa.py
|
| 15 |
+
"""
|
| 16 |
+
from __future__ import annotations
|
| 17 |
+
import argparse, hashlib, json, os, re, sys, time
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
from typing import Dict, List
|
| 20 |
+
from openai import OpenAI
|
| 21 |
+
|
| 22 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 23 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 24 |
+
from memory_lora.data_paths import QNA_DIR, DOCS_DIR, CACHE_DIR, ensure_dirs # noqa: E402
|
| 25 |
+
|
| 26 |
+
def _load_dotenv(p: Path):
|
| 27 |
+
if p.exists():
|
| 28 |
+
for line in p.read_text().splitlines():
|
| 29 |
+
if "=" in line and not line.strip().startswith("#"):
|
| 30 |
+
k, v = line.split("=", 1); os.environ.setdefault(k.strip(), v.strip())
|
| 31 |
+
_load_dotenv(REPO_ROOT / ".env")
|
| 32 |
+
MODEL = "google/gemini-3.6-flash"; BASE_URL = "https://openrouter.ai/api/v1"
|
| 33 |
+
|
| 34 |
+
SYSTEM = (
|
| 35 |
+
"You are a 20-year tech lead writing onboarding Q&A for a NEW engineer joining "
|
| 36 |
+
"a repository. You are given 6 views of the repo: its call/import graph, "
|
| 37 |
+
"architecture (readme/tree), git history, test contracts, code conventions, "
|
| 38 |
+
"and ops/build config. Produce a JSON array of 8-12 objects with keys "
|
| 39 |
+
"'aspect','question','answer'. aspect in: architecture, data_flow, why, "
|
| 40 |
+
"contracts, conventions, impact, ops. Rules: (1) questions are REPO-LEVEL and "
|
| 41 |
+
"test JUDGMENT a senior would have ('what layer owns X', 'what convention does "
|
| 42 |
+
"this repo use for Y', 'how does data flow through Z', 'why is this structured "
|
| 43 |
+
"this way'), NOT trivia about one commit. (2) answers SHORT -- one phrase or "
|
| 44 |
+
"sentence, copyable, NO file-path or line-number lists. (3) 'impact' = the KIND "
|
| 45 |
+
"of thing that breaks/changes, not an exact file enumeration. (4) ground every "
|
| 46 |
+
"answer in the provided views; invent nothing. Output ONLY the JSON array."
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
def ckey(*p): return hashlib.sha256("||".join(p).encode()).hexdigest()[:24]
|
| 50 |
+
|
| 51 |
+
def gen(client, ctx, cache_dir, retries=4) -> List[Dict]:
|
| 52 |
+
cf = cache_dir / f"rsqa_{ckey(MODEL, ctx)}.json"
|
| 53 |
+
if cf.exists():
|
| 54 |
+
raw = cf.read_text()
|
| 55 |
+
else:
|
| 56 |
+
last = None
|
| 57 |
+
for a in range(retries):
|
| 58 |
+
try:
|
| 59 |
+
r = client.chat.completions.create(model=MODEL,
|
| 60 |
+
messages=[{"role": "system", "content": SYSTEM}, {"role": "user", "content": ctx}],
|
| 61 |
+
max_tokens=4000, temperature=0.6)
|
| 62 |
+
raw = r.choices[0].message.content or ""; cf.write_text(raw); break
|
| 63 |
+
except Exception as e: # noqa: BLE001
|
| 64 |
+
last = e; time.sleep(2 ** a)
|
| 65 |
+
else:
|
| 66 |
+
return []
|
| 67 |
+
m = re.search(r"\[.*\]", raw, re.DOTALL)
|
| 68 |
+
if not m: return []
|
| 69 |
+
try: items = json.loads(m.group(0))
|
| 70 |
+
except json.JSONDecodeError: return []
|
| 71 |
+
out = []
|
| 72 |
+
for it in items:
|
| 73 |
+
q = (it.get("question") or "").strip(); a = (it.get("answer") or "").strip()
|
| 74 |
+
asp = (it.get("aspect") or "general").strip()
|
| 75 |
+
if q and a and len(a) < 240: out.append({"aspect": asp, "question": q, "answer": a})
|
| 76 |
+
return out
|
| 77 |
+
|
| 78 |
+
def build_ctx(repo: str, vt: Dict[str, str]) -> str:
|
| 79 |
+
parts = [f"REPOSITORY: {repo}\n"]
|
| 80 |
+
for k in ["v_arch", "v_graph", "v_history", "v_contracts", "v_conventions", "v_ops"]:
|
| 81 |
+
parts.append(f"=== {k} ===\n{vt.get(k,'')}\n")
|
| 82 |
+
return "\n".join(parts)
|
| 83 |
+
|
| 84 |
+
def main():
|
| 85 |
+
import threading
|
| 86 |
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 87 |
+
ap = argparse.ArgumentParser()
|
| 88 |
+
ap.add_argument("--sources", default=str(DOCS_DIR / "multiview_sources.jsonl"))
|
| 89 |
+
ap.add_argument("--limit", type=int, default=0)
|
| 90 |
+
ap.add_argument("--model", default=MODEL)
|
| 91 |
+
ap.add_argument("--workers", type=int, default=10)
|
| 92 |
+
args = ap.parse_args()
|
| 93 |
+
globals()["MODEL"] = args.model
|
| 94 |
+
ensure_dirs()
|
| 95 |
+
key = os.environ.get("OPENROUTER_API_KEY")
|
| 96 |
+
if not key: raise SystemExit("OPENROUTER_API_KEY not set")
|
| 97 |
+
client = OpenAI(base_url=BASE_URL, api_key=key)
|
| 98 |
+
|
| 99 |
+
src = [json.loads(l) for l in open(args.sources)]
|
| 100 |
+
if args.limit: src = src[: args.limit]
|
| 101 |
+
outp = QNA_DIR / "repo_scoped_qa.jsonl"
|
| 102 |
+
done = set()
|
| 103 |
+
if outp.exists():
|
| 104 |
+
done = {json.loads(l)["doc_id"] for l in open(outp)}
|
| 105 |
+
todo = [r for r in src if r["doc_id"] not in done]
|
| 106 |
+
out_f = outp.open("a")
|
| 107 |
+
lock = threading.Lock()
|
| 108 |
+
n_docs = [0]; n_qa = [0]; t0 = time.time()
|
| 109 |
+
|
| 110 |
+
def work(row):
|
| 111 |
+
doc_id = row["doc_id"]
|
| 112 |
+
qas = gen(client, build_ctx(row["repo"], row["view_text"]), CACHE_DIR)
|
| 113 |
+
if not qas: return
|
| 114 |
+
with lock:
|
| 115 |
+
for qa in qas:
|
| 116 |
+
out_f.write(json.dumps({"doc_id": doc_id, "doc_version": "head",
|
| 117 |
+
"split": "train", "qna_split": "train", "aspect": qa["aspect"],
|
| 118 |
+
"question": qa["question"], "prefix": f"Q: {qa['question']}\nA:",
|
| 119 |
+
"target": " " + qa["answer"], "lang": row.get("lang", "unknown")}) + "\n")
|
| 120 |
+
n_qa[0] += 1
|
| 121 |
+
n_docs[0] += 1
|
| 122 |
+
if n_docs[0] % 25 == 0:
|
| 123 |
+
print(f" {n_docs[0]}/{len(todo)} repos, {n_qa[0]} QA "
|
| 124 |
+
f"({n_docs[0]/max(1e-9,(time.time()-t0)/60):.1f}/min)", flush=True)
|
| 125 |
+
|
| 126 |
+
with ThreadPoolExecutor(max_workers=args.workers) as ex:
|
| 127 |
+
for _ in as_completed([ex.submit(work, r) for r in todo]):
|
| 128 |
+
pass
|
| 129 |
+
out_f.close()
|
| 130 |
+
print(f"\nDone. {n_docs[0]} repos -> {n_qa[0]} repo-scoped judgment QA.", flush=True)
|
| 131 |
+
|
| 132 |
+
if __name__ == "__main__":
|
| 133 |
+
main()
|
scripts/generate_synthetic_dataset.py
ADDED
|
@@ -0,0 +1,545 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Generate the Memory-LoRA training corpus via OpenRouter.
|
| 3 |
+
|
| 4 |
+
Produces two local parquet-backed artifacts under ``data/``:
|
| 5 |
+
|
| 6 |
+
data/docs/documents.jsonl -- one row per document (id, category, topic,
|
| 7 |
+
cross-corpus split, list of (section, text))
|
| 8 |
+
data/qna/qna.jsonl -- one row per recall QA pair (doc_id, split,
|
| 9 |
+
qna_split, question, prefix, target)
|
| 10 |
+
|
| 11 |
+
Four document categories, all seeded to contain specific, checkable facts
|
| 12 |
+
(numbers, names, claims) so recall is gradeable by exact-match, mirroring
|
| 13 |
+
Code2LoRA's assertion-completion targets:
|
| 14 |
+
|
| 15 |
+
paper -- the REAL Code2LoRA paper, chunked into sections
|
| 16 |
+
(not synthetic -- hand-authored below from the
|
| 17 |
+
paper we already read in full).
|
| 18 |
+
coding_agent_harness -- synthetic docs about capabilities that help coding
|
| 19 |
+
agents / CLI tools (Claude Code, Codex, etc.) handle
|
| 20 |
+
large codebases: context injection, repo indexing,
|
| 21 |
+
diffing, static analysis, self-improvement loops.
|
| 22 |
+
agile_pm -- synthetic docs about agile project tracking: Jira
|
| 23 |
+
ticket lifecycles, sprints, story points, velocity,
|
| 24 |
+
epics, standups, retrospectives, burndown.
|
| 25 |
+
general -- broad diverse synthetic fact-sheets, needed so the
|
| 26 |
+
hypernetwork's document->LoRA mapping generalizes
|
| 27 |
+
(breadth requirement, same reason Code2LoRA needed
|
| 28 |
+
400+ repos rather than 1).
|
| 29 |
+
|
| 30 |
+
OpenRouter is OpenAI-API compatible -- plain ``openai`` client,
|
| 31 |
+
base_url=https://openrouter.ai/api/v1. Key read from OPENROUTER_API_KEY
|
| 32 |
+
(loaded from a local .env, never hardcoded/committed).
|
| 33 |
+
|
| 34 |
+
Usage:
|
| 35 |
+
python scripts/generate_synthetic_dataset.py --limit 3 # smoke test
|
| 36 |
+
python scripts/generate_synthetic_dataset.py --n-per-category 60
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
from __future__ import annotations
|
| 40 |
+
|
| 41 |
+
import argparse
|
| 42 |
+
import hashlib
|
| 43 |
+
import json
|
| 44 |
+
import os
|
| 45 |
+
import random
|
| 46 |
+
import re
|
| 47 |
+
import sys
|
| 48 |
+
import time
|
| 49 |
+
from pathlib import Path
|
| 50 |
+
from typing import Any, Dict, List, Optional
|
| 51 |
+
|
| 52 |
+
from openai import OpenAI
|
| 53 |
+
|
| 54 |
+
HERE = Path(__file__).resolve().parent
|
| 55 |
+
REPO_ROOT = HERE.parent
|
| 56 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 57 |
+
from memory_lora.data_paths import DOCS_DIR, QNA_DIR, CACHE_DIR, ensure_dirs # noqa: E402
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def _load_dotenv(path: Path) -> None:
|
| 61 |
+
if not path.exists():
|
| 62 |
+
return
|
| 63 |
+
for line in path.read_text().splitlines():
|
| 64 |
+
line = line.strip()
|
| 65 |
+
if not line or line.startswith("#") or "=" not in line:
|
| 66 |
+
continue
|
| 67 |
+
k, v = line.split("=", 1)
|
| 68 |
+
os.environ.setdefault(k.strip(), v.strip())
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
_load_dotenv(REPO_ROOT / ".env")
|
| 72 |
+
|
| 73 |
+
DEFAULT_GEN_MODEL = "qwen/qwen-2.5-7b-instruct"
|
| 74 |
+
OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
# ---------------------------------------------------------------------------
|
| 78 |
+
# Cache-wrapped OpenRouter call
|
| 79 |
+
# ---------------------------------------------------------------------------
|
| 80 |
+
|
| 81 |
+
def _cache_key(model: str, messages: List[Dict[str, str]], **kwargs) -> str:
|
| 82 |
+
payload = json.dumps({"model": model, "messages": messages, **kwargs},
|
| 83 |
+
sort_keys=True)
|
| 84 |
+
return hashlib.sha256(payload.encode()).hexdigest()[:24]
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class CachedClient:
|
| 88 |
+
def __init__(self, client: OpenAI, cache_dir: Path):
|
| 89 |
+
self.client = client
|
| 90 |
+
self.cache_dir = cache_dir
|
| 91 |
+
|
| 92 |
+
def chat(self, model: str, messages: List[Dict[str, str]],
|
| 93 |
+
temperature: float = 0.9, max_tokens: int = 2000,
|
| 94 |
+
retries: int = 4) -> str:
|
| 95 |
+
key = _cache_key(model, messages, temperature=temperature,
|
| 96 |
+
max_tokens=max_tokens)
|
| 97 |
+
cache_file = self.cache_dir / f"{key}.txt"
|
| 98 |
+
if cache_file.exists():
|
| 99 |
+
return cache_file.read_text()
|
| 100 |
+
last_err: Optional[Exception] = None
|
| 101 |
+
for attempt in range(retries):
|
| 102 |
+
try:
|
| 103 |
+
resp = self.client.chat.completions.create(
|
| 104 |
+
model=model, messages=messages,
|
| 105 |
+
temperature=temperature, max_tokens=max_tokens,
|
| 106 |
+
)
|
| 107 |
+
text = resp.choices[0].message.content or ""
|
| 108 |
+
cache_file.write_text(text)
|
| 109 |
+
return text
|
| 110 |
+
except Exception as e: # noqa: BLE001
|
| 111 |
+
last_err = e
|
| 112 |
+
wait = 2 ** attempt
|
| 113 |
+
print(f" [warn] OpenRouter call failed ({e}); retry in {wait}s",
|
| 114 |
+
flush=True)
|
| 115 |
+
time.sleep(wait)
|
| 116 |
+
raise RuntimeError(f"OpenRouter call failed after {retries} retries: {last_err}")
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
# ---------------------------------------------------------------------------
|
| 120 |
+
# Topic seeds per category (kept diverse -> the hypernetwork sees breadth)
|
| 121 |
+
# ---------------------------------------------------------------------------
|
| 122 |
+
|
| 123 |
+
CODING_AGENT_TOPICS = [
|
| 124 |
+
"repository-level context injection strategies for LLM coding agents",
|
| 125 |
+
"incremental static analysis caching for large monorepos",
|
| 126 |
+
"test-impact analysis to select which tests to rerun after a diff",
|
| 127 |
+
"dependency graph indexing for cross-file code navigation",
|
| 128 |
+
"safe automated refactoring patterns for renaming across a codebase",
|
| 129 |
+
"context window budget management when an agent reads many files",
|
| 130 |
+
"self-improvement loops where a coding agent revises its own tool use",
|
| 131 |
+
"diffing and patch-application strategies for multi-file edits",
|
| 132 |
+
"detecting and avoiding regressions when an agent edits shared utilities",
|
| 133 |
+
"code search ranking heuristics for retrieval-augmented coding agents",
|
| 134 |
+
"sandboxing and permission models for autonomous coding agents",
|
| 135 |
+
"long-horizon planning for agents building complex multi-module programs",
|
| 136 |
+
"memory architectures that let an agent recall project conventions",
|
| 137 |
+
"strategies for agents to keep a mental model of a large codebase in sync",
|
| 138 |
+
"CLI tool design patterns for developer-facing coding agents",
|
| 139 |
+
"evaluating coding agent reliability on multi-step programming tasks",
|
| 140 |
+
"handling build system and dependency resolution errors autonomously",
|
| 141 |
+
"techniques for agents to summarize large pull requests for review",
|
| 142 |
+
"version-control-aware agent workflows (branches, rebases, conflicts)",
|
| 143 |
+
"strategies for agents to write and maintain their own regression tests",
|
| 144 |
+
]
|
| 145 |
+
|
| 146 |
+
AGILE_PM_TOPICS = [
|
| 147 |
+
"Jira ticket lifecycle states and transition rules",
|
| 148 |
+
"sprint planning and story point estimation techniques",
|
| 149 |
+
"velocity tracking and forecasting sprint capacity",
|
| 150 |
+
"epic and subtask hierarchy conventions in agile tracking tools",
|
| 151 |
+
"daily standup meeting structure and anti-patterns",
|
| 152 |
+
"sprint retrospective formats and action item follow-through",
|
| 153 |
+
"burndown and burnup chart interpretation",
|
| 154 |
+
"backlog grooming and prioritization frameworks (MoSCoW, WSJF)",
|
| 155 |
+
"definition of done and acceptance criteria best practices",
|
| 156 |
+
"kanban WIP limits and flow efficiency metrics",
|
| 157 |
+
"cross-team dependency tracking in scaled agile (SAFe, LeSS)",
|
| 158 |
+
"bug triage severity/priority labeling conventions",
|
| 159 |
+
"release planning and versioning cadences",
|
| 160 |
+
"stakeholder reporting cadences and status update formats",
|
| 161 |
+
"agile ceremonies for distributed/remote teams",
|
| 162 |
+
]
|
| 163 |
+
|
| 164 |
+
PROJECT_STATUS_TOPICS = [
|
| 165 |
+
"a web app team's sprint status: open tickets, in-progress work, recent commits",
|
| 166 |
+
"a data pipeline team's current sprint: blocked tickets, recent diffs, on-call rotation",
|
| 167 |
+
"a mobile app team's release cycle: feature tickets, QA status, code review queue",
|
| 168 |
+
"an API service team's incident + sprint status: hotfix tickets, recent deploys",
|
| 169 |
+
"an ML training infra team's sprint: experiment tickets, recent config diffs",
|
| 170 |
+
"a platform team's migration project: tracked subtasks, rollout percentage, blockers",
|
| 171 |
+
"a devtools team's backlog grooming outcome: prioritized tickets, recent PRs merged",
|
| 172 |
+
"a security team's remediation sprint: CVE tickets, patch status, recent commits",
|
| 173 |
+
"a frontend team's design-system rollout: component tickets, adoption tracking",
|
| 174 |
+
"a backend team's database migration sprint: schema tickets, rollback plan, diffs",
|
| 175 |
+
]
|
| 176 |
+
|
| 177 |
+
PROJECT_STATUS_SYSTEM = (
|
| 178 |
+
"You write a realistic internal project-status snapshot for a software "
|
| 179 |
+
"team, combining a Jira-style ticket board with recent code activity. "
|
| 180 |
+
"Invent a plausible project/repo name, then include: (1) 6-10 tickets, "
|
| 181 |
+
"each with a ticket key (e.g. PROJ-1234), status (To Do/In Progress/In "
|
| 182 |
+
"Review/Done/Blocked), assignee name, story points, and a one-line "
|
| 183 |
+
"description; (2) a sprint summary (sprint number, dates, velocity, "
|
| 184 |
+
"burndown status); (3) a 'recent changes' section describing 2-4 "
|
| 185 |
+
"specific code changes (file names, what changed, why) as if summarizing "
|
| 186 |
+
"recent commits/diffs; (4) any current blockers or risks. Every fact "
|
| 187 |
+
"(ticket key, status, assignee, points, sprint number, file name) must "
|
| 188 |
+
"be specific and consistent so it can be tested for recall. 400-700 "
|
| 189 |
+
"words. No markdown headers, structured prose with clear labels."
|
| 190 |
+
)
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
def gen_project_status_document(client: CachedClient, model: str, topic: str) -> str:
|
| 194 |
+
prompt = f"Write a project-status snapshot for: {topic}."
|
| 195 |
+
return client.chat(
|
| 196 |
+
model=model,
|
| 197 |
+
messages=[
|
| 198 |
+
{"role": "system", "content": PROJECT_STATUS_SYSTEM},
|
| 199 |
+
{"role": "user", "content": prompt},
|
| 200 |
+
],
|
| 201 |
+
temperature=0.9,
|
| 202 |
+
max_tokens=1400,
|
| 203 |
+
)
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
GENERAL_TOPICS = [
|
| 207 |
+
"the history and mechanics of a fictional national park's geology",
|
| 208 |
+
"the biology of a deep-sea bioluminescent organism",
|
| 209 |
+
"the engineering of a suspension bridge's cable system",
|
| 210 |
+
"the brewing process and quality control of specialty coffee",
|
| 211 |
+
"the orbital mechanics of a hypothetical exoplanet system",
|
| 212 |
+
"the supply chain logistics of a regional produce cooperative",
|
| 213 |
+
"the architecture of a public transit signaling system",
|
| 214 |
+
"the culinary traditions of a fictional coastal fishing village",
|
| 215 |
+
"the manufacturing process of a specific alloy used in aerospace",
|
| 216 |
+
"the ecology of a wetland restoration project",
|
| 217 |
+
"the governance structure of a municipal water utility",
|
| 218 |
+
"the training regimen of competitive long-distance cyclists",
|
| 219 |
+
"the archival practices of a rare-book conservation lab",
|
| 220 |
+
"the acoustics engineering of a concert hall renovation",
|
| 221 |
+
"the logistics of a regional disaster-relief supply network",
|
| 222 |
+
"the taxonomy and care requirements of a rare orchid genus",
|
| 223 |
+
"the operations of a small-batch letterpress printing studio",
|
| 224 |
+
"the hydrology of an urban stormwater management system",
|
| 225 |
+
"the production pipeline of a stop-motion animation studio",
|
| 226 |
+
"the maintenance schedule of a commercial wind turbine farm",
|
| 227 |
+
]
|
| 228 |
+
|
| 229 |
+
DOC_GEN_SYSTEM = (
|
| 230 |
+
"You write dense, factual reference documents. Every document must contain "
|
| 231 |
+
"15-30 SPECIFIC, VERIFIABLE facts: exact numbers, named entities, precise "
|
| 232 |
+
"claims, thresholds, or procedures. Avoid vague generalities. Write "
|
| 233 |
+
"300-800 words. Do not use markdown headers; write flowing prose "
|
| 234 |
+
"paragraphs. Invent plausible specifics (names, numbers, dates) when the "
|
| 235 |
+
"topic is fictional/hypothetical -- consistency within the document "
|
| 236 |
+
"matters more than real-world accuracy."
|
| 237 |
+
)
|
| 238 |
+
|
| 239 |
+
QA_GEN_SYSTEM = (
|
| 240 |
+
"You extract recall test questions from a reference document. Given the "
|
| 241 |
+
"document, produce a JSON array of 15-25 objects, each with keys "
|
| 242 |
+
"'question' and 'answer'. Each question must test recall of ONE specific "
|
| 243 |
+
"fact stated in the document (a number, name, threshold, or precise "
|
| 244 |
+
"claim). The answer must be SHORT (1-8 words, ideally a number, name, or "
|
| 245 |
+
"short phrase) and must be copyable verbatim or near-verbatim from the "
|
| 246 |
+
"document. Do not ask yes/no questions. Do not ask questions requiring "
|
| 247 |
+
"reasoning beyond direct recall. Output ONLY the JSON array, no prose."
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
def gen_document(client: CachedClient, model: str, category: str, topic: str) -> str:
|
| 252 |
+
prompt = (
|
| 253 |
+
f"Write a reference document about: {topic}.\n"
|
| 254 |
+
f"Category: {category}."
|
| 255 |
+
)
|
| 256 |
+
return client.chat(
|
| 257 |
+
model=model,
|
| 258 |
+
messages=[
|
| 259 |
+
{"role": "system", "content": DOC_GEN_SYSTEM},
|
| 260 |
+
{"role": "user", "content": prompt},
|
| 261 |
+
],
|
| 262 |
+
temperature=0.9,
|
| 263 |
+
max_tokens=1200,
|
| 264 |
+
)
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
def gen_qna(client: CachedClient, model: str, doc_text: str) -> List[Dict[str, str]]:
|
| 268 |
+
raw = client.chat(
|
| 269 |
+
model=model,
|
| 270 |
+
messages=[
|
| 271 |
+
{"role": "system", "content": QA_GEN_SYSTEM},
|
| 272 |
+
{"role": "user", "content": doc_text},
|
| 273 |
+
],
|
| 274 |
+
temperature=0.3,
|
| 275 |
+
max_tokens=2000,
|
| 276 |
+
)
|
| 277 |
+
match = re.search(r"\[.*\]", raw, re.DOTALL)
|
| 278 |
+
if not match:
|
| 279 |
+
return []
|
| 280 |
+
try:
|
| 281 |
+
items = json.loads(match.group(0))
|
| 282 |
+
except json.JSONDecodeError:
|
| 283 |
+
return []
|
| 284 |
+
out = []
|
| 285 |
+
for it in items:
|
| 286 |
+
q = (it.get("question") or "").strip()
|
| 287 |
+
a = (it.get("answer") or "").strip()
|
| 288 |
+
if q and a and len(a) < 200:
|
| 289 |
+
out.append({"question": q, "answer": a})
|
| 290 |
+
return out
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
# ---------------------------------------------------------------------------
|
| 294 |
+
# The Code2LoRA paper -- real document, hand-chunked into sections (from the
|
| 295 |
+
# paper we already read in full; not regenerated by an LLM).
|
| 296 |
+
# ---------------------------------------------------------------------------
|
| 297 |
+
|
| 298 |
+
def code2lora_paper_sections() -> List[Dict[str, str]]:
|
| 299 |
+
return [
|
| 300 |
+
{"name": "abstract", "text": (
|
| 301 |
+
"Code2LoRA is a hypernetwork framework that generates repository-"
|
| 302 |
+
"specific LoRA adapters, effectively injecting repository "
|
| 303 |
+
"knowledge with zero inference-time token overhead. Code2LoRA "
|
| 304 |
+
"supports two usage scenarios: Code2LoRA-Static converts a "
|
| 305 |
+
"single repository snapshot into an adapter; Code2LoRA-Evo "
|
| 306 |
+
"maintains an adapter backed by a GRU hidden state updated per "
|
| 307 |
+
"code diff. The authors build RepoPeftBench, a benchmark of 604 "
|
| 308 |
+
"Python repositories with two tracks: a static track with 40K "
|
| 309 |
+
"training and 12K test assertion-completion tasks, and an "
|
| 310 |
+
"evolution track with 215K commit-derived training and 87K "
|
| 311 |
+
"commit-derived test tasks. On the static track, Code2LoRA-"
|
| 312 |
+
"Static achieves 63.8% cross-repo and 66.2% in-repo exact match, "
|
| 313 |
+
"matching the per-repository LoRA upper bound; on the evolution "
|
| 314 |
+
"track, Code2LoRA-Evo achieves 60.3% cross-repo exact match, "
|
| 315 |
+
"+5.2 percentage points over a single shared LoRA."
|
| 316 |
+
)},
|
| 317 |
+
{"name": "method_architecture", "text": (
|
| 318 |
+
"Code2LoRA has three components: a shared repository encoder "
|
| 319 |
+
"that maps repository-level context to dense embeddings, a "
|
| 320 |
+
"hypernetwork that maps those embeddings to LoRA weights, and a "
|
| 321 |
+
"base LLM that receives the generated adapter. Only the "
|
| 322 |
+
"hypernetwork is trained. The repository encoder uses a frozen "
|
| 323 |
+
"Qwen3-Embedding-0.6B model: each file is divided into 4096-"
|
| 324 |
+
"token chunks with 512-token overlap, embedded, and mean-pooled "
|
| 325 |
+
"to produce a file vector of dimension 1024. The repository "
|
| 326 |
+
"embedding is the concatenation of a weighted mean and a max "
|
| 327 |
+
"pool of file vectors, giving a 2048-dimensional vector. "
|
| 328 |
+
"Code2LoRA-Static's hypernetwork has a 2-layer MLP trunk with "
|
| 329 |
+
"GELU activation, hidden dimension 1024, followed by dedicated "
|
| 330 |
+
"output heads per module type. LoRA matrices use rank r=16 and "
|
| 331 |
+
"alpha=32, targeting seven module types (q_proj, k_proj, "
|
| 332 |
+
"v_proj, o_proj, gate_proj, up_proj, down_proj) shared across "
|
| 333 |
+
"all 28 transformer layers of the base model. Code2LoRA-Static "
|
| 334 |
+
"has approximately 720 million trainable parameters. Code2LoRA-"
|
| 335 |
+
"Evo adds a 1-layer GRU with hidden size 2048 that aggregates "
|
| 336 |
+
"sequential diff embeddings into a hidden state, which "
|
| 337 |
+
"substitutes for the static embedding in the same shared head; "
|
| 338 |
+
"Code2LoRA-Evo has approximately 745 million trainable "
|
| 339 |
+
"parameters, using truncated backpropagation through time with "
|
| 340 |
+
"a window of K=16 steps."
|
| 341 |
+
)},
|
| 342 |
+
{"name": "benchmark_repopeftbench", "text": (
|
| 343 |
+
"RepoPeftBench comprises 604 Python repositories drawn from "
|
| 344 |
+
"GitHub: 512 in-distribution repositories (requiring at least "
|
| 345 |
+
"300 stars) and a 92-repository temporal out-of-distribution "
|
| 346 |
+
"holdout created strictly after the 2025-04-01 scrape cutoff. "
|
| 347 |
+
"The in-distribution set is partitioned into cross-repo (103 "
|
| 348 |
+
"held-out repositories: 51 validation, 52 test) and in-repo "
|
| 349 |
+
"(409 training repositories) splits. The task is assertion "
|
| 350 |
+
"completion: given a structured prefix from a test file "
|
| 351 |
+
"(imports, enclosing class, helper methods, test body up to the "
|
| 352 |
+
"assertion), the model predicts the expected value of the "
|
| 353 |
+
"assertion. The static track draws 39,612 training and 11,636 "
|
| 354 |
+
"test tasks from repository snapshots. The evolution track "
|
| 355 |
+
"replays commit history, yielding 215,129 training and 86,793 "
|
| 356 |
+
"test tasks derived from commits. Evaluation metrics are Exact "
|
| 357 |
+
"Match (EM), Edit Similarity, and CodeBLEU. The base LLM used "
|
| 358 |
+
"in all experiments is Qwen2.5-Coder-1.5B, loaded in bfloat16, "
|
| 359 |
+
"trained on a single H100 80GB GPU using the TRL library."
|
| 360 |
+
)},
|
| 361 |
+
{"name": "results_static_track", "text": (
|
| 362 |
+
"On RepoPeftBench's static track, Code2LoRA-Static achieves "
|
| 363 |
+
"63.8% cross-repo exact match, 9.9 percentage points above the "
|
| 364 |
+
"strongest baseline (full fine-tuning plus RAG, at 53.9%). "
|
| 365 |
+
"Other baselines score lower: RAG with k=3 reaches 39.7% EM, "
|
| 366 |
+
"Dependency-Resolved Context reaches 48.2% EM, full fine-tuning "
|
| 367 |
+
"alone reaches 51.4% EM, and a single shared LoRA reaches 47.4% "
|
| 368 |
+
"EM. On in-repo evaluation, Code2LoRA-Static reaches 66.2% EM, "
|
| 369 |
+
"matching the per-repository LoRA upper bound of 64.0% EM "
|
| 370 |
+
"without any per-repository training. A strengthened Text2LoRA "
|
| 371 |
+
"baseline, matched on input modality and target-module "
|
| 372 |
+
"coverage, reaches only 45.8% EM on cross-repo, isolating the "
|
| 373 |
+
"Text2LoRA hypernetwork head itself as the bottleneck."
|
| 374 |
+
)},
|
| 375 |
+
{"name": "results_evolution_track", "text": (
|
| 376 |
+
"On the evolution track, which evaluates on commit-derived "
|
| 377 |
+
"prefixes, Code2LoRA-Evo is the strongest method on both "
|
| 378 |
+
"splits: 60.3% cross-repo EM and 64.5% in-repo EM, a gain of "
|
| 379 |
+
"5.2 percentage points over a single shared LoRA on cross-repo. "
|
| 380 |
+
"Code2LoRA-Evo's in-repo EM of 64.5% exceeds the per-repository "
|
| 381 |
+
"LoRA upper bound of 64.2% without any per-repository training. "
|
| 382 |
+
"Code2LoRA-Static, evaluated on the same commit-derived inputs "
|
| 383 |
+
"as a within-framework reference, drops to 55.7% cross-repo EM "
|
| 384 |
+
"and 60.6% in-repo EM, markedly below its static-track "
|
| 385 |
+
"performance, showing that snapshot-based adaptation goes "
|
| 386 |
+
"stale as a repository accumulates commits. On the 92-"
|
| 387 |
+
"repository temporal out-of-distribution holdout, Code2LoRA-"
|
| 388 |
+
"Evo achieves the highest exact match at 74.1%, ahead of "
|
| 389 |
+
"Code2LoRA-Static at 72.2% and a single shared LoRA at 72.3%."
|
| 390 |
+
)},
|
| 391 |
+
{"name": "efficiency", "text": (
|
| 392 |
+
"Code2LoRA-Static and Code2LoRA-Evo generate a repository-"
|
| 393 |
+
"specific adapter in under 10 milliseconds per repository with "
|
| 394 |
+
"zero extra inference tokens, versus approximately 1,500 extra "
|
| 395 |
+
"tokens per query for RAG with k=3, and approximately 500 to "
|
| 396 |
+
"2,000 extra tokens per query for Dependency-Resolved Context. "
|
| 397 |
+
"Full fine-tuning requires about 4 hours of training and adds "
|
| 398 |
+
"3.1 gigabytes of storage per repository; per-repository LoRA "
|
| 399 |
+
"requires about 5 minutes of training and 32 megabytes of "
|
| 400 |
+
"storage per repository. In contrast, Code2LoRA-Static's "
|
| 401 |
+
"hypernetwork adds a fixed 679 megabytes of storage shared "
|
| 402 |
+
"across all repositories, and Code2LoRA-Evo adds 65 megabytes, "
|
| 403 |
+
"independent of how many repositories are served."
|
| 404 |
+
)},
|
| 405 |
+
{"name": "limitations", "text": (
|
| 406 |
+
"The Code2LoRA paper's limitations section notes the evaluation "
|
| 407 |
+
"is restricted to Python repositories, a single frozen backbone "
|
| 408 |
+
"(Qwen2.5-Coder-1.5B), and one downstream task (assertion "
|
| 409 |
+
"completion). The reported 74.1% out-of-distribution exact "
|
| 410 |
+
"match may be partially inflated because assertion targets in "
|
| 411 |
+
"the post-cutoff OOD repositories are systematically shorter "
|
| 412 |
+
"(median 7 characters) than in the cross-repo and in-repo test "
|
| 413 |
+
"sets (median 12-13 characters). The LoRA-generation "
|
| 414 |
+
"hypernetwork dominates the trainable parameter count -- "
|
| 415 |
+
"approximately 720 million for Code2LoRA-Static and 745 "
|
| 416 |
+
"million for Code2LoRA-Evo -- so the evolution-track finding "
|
| 417 |
+
"is most directly supported at the 1.5-billion-parameter "
|
| 418 |
+
"backbone scale."
|
| 419 |
+
)},
|
| 420 |
+
]
|
| 421 |
+
|
| 422 |
+
|
| 423 |
+
# ---------------------------------------------------------------------------
|
| 424 |
+
# Splits + orchestration
|
| 425 |
+
# ---------------------------------------------------------------------------
|
| 426 |
+
|
| 427 |
+
def assign_cross_corpus_split(rng: random.Random) -> str:
|
| 428 |
+
r = rng.random()
|
| 429 |
+
if r < 0.8:
|
| 430 |
+
return "train"
|
| 431 |
+
if r < 0.9:
|
| 432 |
+
return "cr_val"
|
| 433 |
+
return "cr_test"
|
| 434 |
+
|
| 435 |
+
|
| 436 |
+
def main() -> None:
|
| 437 |
+
ap = argparse.ArgumentParser()
|
| 438 |
+
ap.add_argument("--gen-model", default=DEFAULT_GEN_MODEL)
|
| 439 |
+
ap.add_argument("--n-per-category", type=int, default=60,
|
| 440 |
+
help="Docs to generate per synthetic category "
|
| 441 |
+
"(coding_agent_harness, agile_pm, general).")
|
| 442 |
+
ap.add_argument("--limit", type=int, default=0,
|
| 443 |
+
help="If set, overrides --n-per-category to a small "
|
| 444 |
+
"number for a cheap smoke test.")
|
| 445 |
+
ap.add_argument("--only-categories", nargs="+", default=[],
|
| 446 |
+
help="Restrict generation to these categories (e.g. "
|
| 447 |
+
"--only-categories project_status), instead of "
|
| 448 |
+
"regenerating the whole corpus. Also skips the "
|
| 449 |
+
"paper doc when set.")
|
| 450 |
+
ap.add_argument("--skip-paper", action="store_true")
|
| 451 |
+
ap.add_argument("--seed", type=int, default=3407)
|
| 452 |
+
args = ap.parse_args()
|
| 453 |
+
|
| 454 |
+
ensure_dirs()
|
| 455 |
+
|
| 456 |
+
api_key = os.environ.get("OPENROUTER_API_KEY")
|
| 457 |
+
if not api_key:
|
| 458 |
+
raise SystemExit("OPENROUTER_API_KEY not set (expected in .env)")
|
| 459 |
+
|
| 460 |
+
client = CachedClient(
|
| 461 |
+
OpenAI(base_url=OPENROUTER_BASE_URL, api_key=api_key),
|
| 462 |
+
cache_dir=CACHE_DIR,
|
| 463 |
+
)
|
| 464 |
+
rng = random.Random(args.seed)
|
| 465 |
+
|
| 466 |
+
n_per_cat = args.limit if args.limit else args.n_per_category
|
| 467 |
+
|
| 468 |
+
docs_path = DOCS_DIR / "documents.jsonl"
|
| 469 |
+
qna_path = QNA_DIR / "qna.jsonl"
|
| 470 |
+
docs_f = docs_path.open("a")
|
| 471 |
+
qna_f = qna_path.open("a")
|
| 472 |
+
|
| 473 |
+
doc_counter = 0
|
| 474 |
+
qna_counter = 0
|
| 475 |
+
|
| 476 |
+
def emit_doc(doc_id: str, category: str, topic: str,
|
| 477 |
+
sections: List[Dict[str, str]], split: str) -> None:
|
| 478 |
+
nonlocal doc_counter, qna_counter
|
| 479 |
+
docs_f.write(json.dumps({
|
| 480 |
+
"doc_id": doc_id, "doc_version": "v1", "category": category,
|
| 481 |
+
"topic": topic, "split": split, "sections": sections,
|
| 482 |
+
}) + "\n")
|
| 483 |
+
doc_counter += 1
|
| 484 |
+
|
| 485 |
+
full_text = "\n\n".join(s["text"] for s in sections)
|
| 486 |
+
qnas = gen_qna(client, args.gen_model, full_text)
|
| 487 |
+
n_qna = len(qnas)
|
| 488 |
+
for i, qa in enumerate(qnas):
|
| 489 |
+
qna_split = "train" if rng.random() < 0.8 else "held_out"
|
| 490 |
+
qna_f.write(json.dumps({
|
| 491 |
+
"doc_id": doc_id, "doc_version": "v1", "split": split,
|
| 492 |
+
"qna_split": qna_split,
|
| 493 |
+
"question": qa["question"],
|
| 494 |
+
"prefix": f"Q: {qa['question']}\nA:",
|
| 495 |
+
"target": " " + qa["answer"],
|
| 496 |
+
}) + "\n")
|
| 497 |
+
qna_counter += 1
|
| 498 |
+
print(f" [{category}] {doc_id} ({topic[:50]}...) -> {n_qna} QAs, split={split}",
|
| 499 |
+
flush=True)
|
| 500 |
+
|
| 501 |
+
# 1. The real Code2LoRA paper -- always included, always in train split
|
| 502 |
+
# (we WANT it memorized, not held out for cross-corpus generalization
|
| 503 |
+
# testing -- that's the whole point of this build).
|
| 504 |
+
if not args.skip_paper and not args.only_categories:
|
| 505 |
+
print("=== paper (real, hand-authored sections) ===", flush=True)
|
| 506 |
+
emit_doc("code2lora_paper", "paper", "Code2LoRA paper",
|
| 507 |
+
code2lora_paper_sections(), split="train")
|
| 508 |
+
|
| 509 |
+
# 2. Synthetic categories
|
| 510 |
+
topic_lists = {
|
| 511 |
+
"coding_agent_harness": CODING_AGENT_TOPICS,
|
| 512 |
+
"agile_pm": AGILE_PM_TOPICS,
|
| 513 |
+
"project_status": PROJECT_STATUS_TOPICS,
|
| 514 |
+
"general": GENERAL_TOPICS,
|
| 515 |
+
}
|
| 516 |
+
if args.only_categories:
|
| 517 |
+
topic_lists = {k: v for k, v in topic_lists.items() if k in args.only_categories}
|
| 518 |
+
for category, topics in topic_lists.items():
|
| 519 |
+
print(f"=== {category} ({n_per_cat} docs) ===", flush=True)
|
| 520 |
+
for i in range(n_per_cat):
|
| 521 |
+
topic = topics[i % len(topics)]
|
| 522 |
+
if i >= len(topics):
|
| 523 |
+
topic = f"{topic} (variant {i // len(topics) + 1}, different specifics)"
|
| 524 |
+
doc_id = f"{category}_{i:04d}"
|
| 525 |
+
split = assign_cross_corpus_split(rng)
|
| 526 |
+
try:
|
| 527 |
+
if category == "project_status":
|
| 528 |
+
text = gen_project_status_document(client, args.gen_model, topic)
|
| 529 |
+
else:
|
| 530 |
+
text = gen_document(client, args.gen_model, category, topic)
|
| 531 |
+
except RuntimeError as e:
|
| 532 |
+
print(f" [error] skipping {doc_id}: {e}", flush=True)
|
| 533 |
+
continue
|
| 534 |
+
sections = [{"name": "body", "text": text}]
|
| 535 |
+
emit_doc(doc_id, category, topic, sections, split)
|
| 536 |
+
|
| 537 |
+
docs_f.close()
|
| 538 |
+
qna_f.close()
|
| 539 |
+
print(f"\nDone. {doc_counter} documents, {qna_counter} QA pairs written to:")
|
| 540 |
+
print(f" {docs_path}")
|
| 541 |
+
print(f" {qna_path}")
|
| 542 |
+
|
| 543 |
+
|
| 544 |
+
if __name__ == "__main__":
|
| 545 |
+
main()
|
scripts/generate_techlead_qa.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Generate high-quality, judgment-shaped "Tech Lead" QA from REAL GitHub
|
| 3 |
+
data (SWE-bench: real issues + fix patches + test patches + PR discussion),
|
| 4 |
+
via OpenRouter google/gemini-3.6-flash.
|
| 5 |
+
|
| 6 |
+
Design decisions baked in from this session's analysis:
|
| 7 |
+
- Targets are TIER-A/B *judgment* QA only (why / architecture / data-flow /
|
| 8 |
+
contracts / conventions / impact-NARRATIVE), never Tier-C exact-recall
|
| 9 |
+
("list the precise files+lines") which a LoRA can only hallucinate.
|
| 10 |
+
- Answers are SHORT (a phrase/sentence) so they're compressible into a
|
| 11 |
+
weight-delta and gradeable.
|
| 12 |
+
- Each example is keyed to doc_id = "{repo}@{base_commit[:10]}" so it can
|
| 13 |
+
later be tied to a repo-state embedding for hypernetwork training.
|
| 14 |
+
- gemini-3.6-flash is a REASONING model: reasoning is mandatory and cannot
|
| 15 |
+
be disabled, and it consumes completion tokens BEFORE content -- so
|
| 16 |
+
max_tokens must be generous (default 3500) or content comes back empty.
|
| 17 |
+
|
| 18 |
+
Usage:
|
| 19 |
+
python scripts/generate_techlead_qa.py --limit 3 # smoke test
|
| 20 |
+
python scripts/generate_techlead_qa.py --max-instances 1200
|
| 21 |
+
"""
|
| 22 |
+
from __future__ import annotations
|
| 23 |
+
import argparse, hashlib, json, os, re, sys, time
|
| 24 |
+
from pathlib import Path
|
| 25 |
+
from typing import Dict, List
|
| 26 |
+
from openai import OpenAI
|
| 27 |
+
|
| 28 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 29 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 30 |
+
from memory_lora.data_paths import QNA_DIR, DOCS_DIR, CACHE_DIR, ensure_dirs # noqa: E402
|
| 31 |
+
|
| 32 |
+
def _load_dotenv(p: Path):
|
| 33 |
+
if p.exists():
|
| 34 |
+
for line in p.read_text().splitlines():
|
| 35 |
+
if "=" in line and not line.strip().startswith("#"):
|
| 36 |
+
k, v = line.split("=", 1); os.environ.setdefault(k.strip(), v.strip())
|
| 37 |
+
_load_dotenv(REPO_ROOT / ".env")
|
| 38 |
+
|
| 39 |
+
MODEL = "google/gemini-3.6-flash"
|
| 40 |
+
BASE_URL = "https://openrouter.ai/api/v1"
|
| 41 |
+
|
| 42 |
+
SYSTEM = (
|
| 43 |
+
"You are a staff engineer writing onboarding Q&A about a real code change. "
|
| 44 |
+
"Given an issue, its fix patch, the test patch, and any discussion, produce "
|
| 45 |
+
"a JSON array of 5-8 objects with keys 'aspect', 'question', 'answer'. "
|
| 46 |
+
"aspect must be one of: architecture, data_flow, why, contracts, conventions, "
|
| 47 |
+
"impact. Rules: (1) Questions test JUDGMENT and UNDERSTANDING, not memorized "
|
| 48 |
+
"trivia. (2) Answers are SHORT -- one phrase or one sentence, copyable, no "
|
| 49 |
+
"lists of file paths or line numbers. (3) 'why' questions explain the "
|
| 50 |
+
"rationale/trade-off. 'impact' questions describe the KIND of thing affected "
|
| 51 |
+
"(a behavior, a contract), NOT an exact file enumeration. (4) Ground every "
|
| 52 |
+
"answer in the provided change; do not invent APIs. Output ONLY the JSON array."
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
def cache_key(*parts) -> str:
|
| 56 |
+
return hashlib.sha256("||".join(parts).encode()).hexdigest()[:24]
|
| 57 |
+
|
| 58 |
+
def gen_qa(client, ctx: str, cache_dir: Path, retries=4) -> List[Dict]:
|
| 59 |
+
key = cache_key(MODEL, ctx)
|
| 60 |
+
cf = cache_dir / f"tlqa_{key}.json"
|
| 61 |
+
if cf.exists():
|
| 62 |
+
raw = cf.read_text()
|
| 63 |
+
else:
|
| 64 |
+
last = None
|
| 65 |
+
for a in range(retries):
|
| 66 |
+
try:
|
| 67 |
+
r = client.chat.completions.create(
|
| 68 |
+
model=MODEL,
|
| 69 |
+
messages=[{"role": "system", "content": SYSTEM},
|
| 70 |
+
{"role": "user", "content": ctx}],
|
| 71 |
+
max_tokens=3500, temperature=0.6)
|
| 72 |
+
raw = r.choices[0].message.content or ""
|
| 73 |
+
cf.write_text(raw); break
|
| 74 |
+
except Exception as e: # noqa: BLE001
|
| 75 |
+
last = e; time.sleep(2 ** a)
|
| 76 |
+
else:
|
| 77 |
+
print(f" [warn] failed: {last}", flush=True); return []
|
| 78 |
+
m = re.search(r"\[.*\]", raw, re.DOTALL)
|
| 79 |
+
if not m: return []
|
| 80 |
+
try:
|
| 81 |
+
items = json.loads(m.group(0))
|
| 82 |
+
except json.JSONDecodeError:
|
| 83 |
+
return []
|
| 84 |
+
out = []
|
| 85 |
+
for it in items:
|
| 86 |
+
q = (it.get("question") or "").strip()
|
| 87 |
+
a = (it.get("answer") or "").strip()
|
| 88 |
+
asp = (it.get("aspect") or "general").strip()
|
| 89 |
+
if q and a and len(a) < 240:
|
| 90 |
+
out.append({"aspect": asp, "question": q, "answer": a})
|
| 91 |
+
return out
|
| 92 |
+
|
| 93 |
+
def build_ctx(row) -> str:
|
| 94 |
+
def clip(s, n): return (s or "")[:n]
|
| 95 |
+
return (f"REPO: {row['repo']}\n"
|
| 96 |
+
f"ISSUE:\n{clip(row.get('problem_statement'),1500)}\n\n"
|
| 97 |
+
f"DISCUSSION:\n{clip(row.get('hints_text'),800)}\n\n"
|
| 98 |
+
f"FIX PATCH:\n{clip(row.get('patch'),2500)}\n\n"
|
| 99 |
+
f"TEST PATCH:\n{clip(row.get('test_patch'),1200)}")
|
| 100 |
+
|
| 101 |
+
def main():
|
| 102 |
+
ap = argparse.ArgumentParser()
|
| 103 |
+
ap.add_argument("--max-instances", type=int, default=1200)
|
| 104 |
+
ap.add_argument("--limit", type=int, default=0, help="smoke-test cap")
|
| 105 |
+
ap.add_argument("--split", default="test")
|
| 106 |
+
args = ap.parse_args()
|
| 107 |
+
ensure_dirs()
|
| 108 |
+
api_key = os.environ.get("OPENROUTER_API_KEY")
|
| 109 |
+
if not api_key: raise SystemExit("OPENROUTER_API_KEY not set")
|
| 110 |
+
client = OpenAI(base_url=BASE_URL, api_key=api_key)
|
| 111 |
+
|
| 112 |
+
from datasets import load_dataset
|
| 113 |
+
ds = load_dataset("princeton-nlp/SWE-bench", split=args.split, streaming=True)
|
| 114 |
+
|
| 115 |
+
n_max = args.limit if args.limit else args.max_instances
|
| 116 |
+
qna_f = (QNA_DIR / "techlead_qa.jsonl").open("a")
|
| 117 |
+
src_f = (DOCS_DIR / "techlead_sources.jsonl").open("a")
|
| 118 |
+
n_docs = n_qa = 0
|
| 119 |
+
t0 = time.time()
|
| 120 |
+
for row in ds:
|
| 121 |
+
if n_docs >= n_max: break
|
| 122 |
+
doc_id = f"{row['repo']}@{row['base_commit'][:10]}"
|
| 123 |
+
ctx = build_ctx(row)
|
| 124 |
+
qas = gen_qa(client, ctx, CACHE_DIR)
|
| 125 |
+
if not qas: continue
|
| 126 |
+
# store the source context so a repo-state embedding can be built later
|
| 127 |
+
src_f.write(json.dumps({"doc_id": doc_id, "repo": row["repo"],
|
| 128 |
+
"base_commit": row["base_commit"], "context": ctx}) + "\n")
|
| 129 |
+
for qa in qas:
|
| 130 |
+
qna_f.write(json.dumps({
|
| 131 |
+
"doc_id": doc_id, "doc_version": row["base_commit"],
|
| 132 |
+
"split": "train", "qna_split": "train",
|
| 133 |
+
"aspect": qa["aspect"], "question": qa["question"],
|
| 134 |
+
"prefix": f"Q: {qa['question']}\nA:", "target": " " + qa["answer"],
|
| 135 |
+
}) + "\n")
|
| 136 |
+
n_qa += 1
|
| 137 |
+
n_docs += 1
|
| 138 |
+
if n_docs % 10 == 0:
|
| 139 |
+
rate = n_docs / max(1e-9, (time.time() - t0) / 60)
|
| 140 |
+
print(f" {n_docs} instances, {n_qa} QA ({rate:.1f} inst/min) latest={doc_id}", flush=True)
|
| 141 |
+
qna_f.close(); src_f.close()
|
| 142 |
+
print(f"\nDone. {n_docs} real instances -> {n_qa} judgment-QA pairs.", flush=True)
|
| 143 |
+
print(f" {QNA_DIR/'techlead_qa.jsonl'}\n {DOCS_DIR/'techlead_sources.jsonl'}", flush=True)
|
| 144 |
+
|
| 145 |
+
if __name__ == "__main__":
|
| 146 |
+
main()
|
scripts/merge_corpora.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Merge the real Code2LoRA/RepoPeftBench corpus (73,849 real repo-commit
|
| 3 |
+
docs, 443,798 real assertion-completion QnAs) with our synthetic corpus
|
| 4 |
+
(211 docs: the Code2LoRA paper + coding-agent-harness + agile/Jira +
|
| 5 |
+
general fact-sheets) into one combined training set for the hypernetwork.
|
| 6 |
+
|
| 7 |
+
Output:
|
| 8 |
+
data/embeddings/combined_embeddings.parquet
|
| 9 |
+
data/qna/combined_qna.jsonl
|
| 10 |
+
|
| 11 |
+
Usage:
|
| 12 |
+
python scripts/merge_corpora.py
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
from __future__ import annotations
|
| 16 |
+
|
| 17 |
+
import json
|
| 18 |
+
import sys
|
| 19 |
+
from pathlib import Path
|
| 20 |
+
|
| 21 |
+
import pyarrow as pa
|
| 22 |
+
import pyarrow.parquet as pq
|
| 23 |
+
|
| 24 |
+
HERE = Path(__file__).resolve().parent
|
| 25 |
+
REPO_ROOT = HERE.parent
|
| 26 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 27 |
+
from memory_lora.data_paths import EMBEDDINGS_DIR, QNA_DIR, ensure_dirs # noqa: E402
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def merge_embeddings() -> int:
|
| 31 |
+
synthetic_path = EMBEDDINGS_DIR / "doc_embeddings.parquet"
|
| 32 |
+
real_path = EMBEDDINGS_DIR / "real_code2lora_embeddings.parquet"
|
| 33 |
+
out_path = EMBEDDINGS_DIR / "combined_embeddings.parquet"
|
| 34 |
+
|
| 35 |
+
tables = []
|
| 36 |
+
for p, label in [(synthetic_path, "synthetic"), (real_path, "real")]:
|
| 37 |
+
if not p.exists():
|
| 38 |
+
print(f" [skip] {p} not found", flush=True)
|
| 39 |
+
continue
|
| 40 |
+
t = pq.read_table(p)
|
| 41 |
+
print(f" {label}: {t.num_rows} rows, columns={t.column_names}", flush=True)
|
| 42 |
+
tables.append(t.select(["doc_id", "doc_version", "split", "category", "doc_embedding"]))
|
| 43 |
+
|
| 44 |
+
combined = pa.concat_tables(tables)
|
| 45 |
+
pq.write_table(combined, out_path)
|
| 46 |
+
print(f"Wrote {combined.num_rows} combined embeddings -> {out_path}", flush=True)
|
| 47 |
+
return combined.num_rows
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def merge_qna() -> int:
|
| 51 |
+
synthetic_path = QNA_DIR / "qna.jsonl"
|
| 52 |
+
real_path = QNA_DIR / "real_code2lora_qna.jsonl"
|
| 53 |
+
out_path = QNA_DIR / "combined_qna.jsonl"
|
| 54 |
+
|
| 55 |
+
n = 0
|
| 56 |
+
with out_path.open("w") as out:
|
| 57 |
+
for p, label in [(synthetic_path, "synthetic"), (real_path, "real")]:
|
| 58 |
+
if not p.exists():
|
| 59 |
+
print(f" [skip] {p} not found", flush=True)
|
| 60 |
+
continue
|
| 61 |
+
count = 0
|
| 62 |
+
with p.open() as f:
|
| 63 |
+
for line in f:
|
| 64 |
+
line = line.strip()
|
| 65 |
+
if not line:
|
| 66 |
+
continue
|
| 67 |
+
out.write(line + "\n")
|
| 68 |
+
count += 1
|
| 69 |
+
n += 1
|
| 70 |
+
print(f" {label}: {count} QnA rows", flush=True)
|
| 71 |
+
print(f"Wrote {n} combined QnA pairs -> {out_path}", flush=True)
|
| 72 |
+
return n
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def main() -> None:
|
| 76 |
+
ensure_dirs()
|
| 77 |
+
print("Merging embeddings...", flush=True)
|
| 78 |
+
n_docs = merge_embeddings()
|
| 79 |
+
print("\nMerging QnA...", flush=True)
|
| 80 |
+
n_qna = merge_qna()
|
| 81 |
+
print(f"\nCombined corpus: {n_docs} documents, {n_qna} QnA pairs.", flush=True)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
if __name__ == "__main__":
|
| 85 |
+
main()
|
scripts/show_eval_examples.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Show concrete held-out examples: for a few cr_test docs (both REAL repos
|
| 3 |
+
and synthetic), inject the hypernetwork-generated adapter and print
|
| 4 |
+
question -> gold vs base-model vs adapted-model prediction, so we can SEE
|
| 5 |
+
what the eval actually measured. CPU-only."""
|
| 6 |
+
from __future__ import annotations
|
| 7 |
+
import json, random, sys
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
import numpy as np, torch
|
| 10 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 11 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 12 |
+
from memory_lora.core import (MemoryLoRAHead, get_module_specs, replace_with_lora,
|
| 13 |
+
inject_lora_weights, load_doc_rows, load_qna_rows, DEFAULT_ROOT_PREFIX)
|
| 14 |
+
from transformers import AutoModelForImageTextToText, AutoTokenizer
|
| 15 |
+
TM = ["q_proj","k_proj","v_proj","o_proj","up_proj","gate_proj","down_proj"]
|
| 16 |
+
|
| 17 |
+
@torch.no_grad()
|
| 18 |
+
def gen(model, tok, prefix, n=12):
|
| 19 |
+
enc = tok(prefix, return_tensors="pt")
|
| 20 |
+
out = model.generate(**enc, max_new_tokens=n, do_sample=False,
|
| 21 |
+
pad_token_id=tok.pad_token_id or tok.eos_token_id)
|
| 22 |
+
return tok.decode(out[0][enc["input_ids"].shape[1]:], skip_special_tokens=True).split("\n")[0]
|
| 23 |
+
|
| 24 |
+
def main():
|
| 25 |
+
ckpt = torch.load("runs/full_real_v4/head.best.pt", map_location="cpu")
|
| 26 |
+
tok = AutoTokenizer.from_pretrained("google/gemma-4-E2B")
|
| 27 |
+
if tok.pad_token is None: tok.pad_token = tok.eos_token
|
| 28 |
+
print("loading base model on CPU...", flush=True)
|
| 29 |
+
model = AutoModelForImageTextToText.from_pretrained("google/gemma-4-E2B",
|
| 30 |
+
torch_dtype=torch.float32, attn_implementation="eager", low_cpu_mem_usage=True)
|
| 31 |
+
model.eval()
|
| 32 |
+
for p in model.parameters(): p.requires_grad = False
|
| 33 |
+
specs = get_module_specs(model, TM, root_prefix=DEFAULT_ROOT_PREFIX)
|
| 34 |
+
replace_with_lora(model, specs, rank=ckpt["config"]["rank"], alpha=ckpt["args"].get("alpha",32.0))
|
| 35 |
+
head = MemoryLoRAHead(input_dim=ckpt["config"]["input_dim"],
|
| 36 |
+
type_dims={k:tuple(v) for k,v in ckpt["config"]["type_dims"].items()},
|
| 37 |
+
hidden_dim=ckpt["config"]["hidden_dim"], rank=ckpt["config"]["rank"])
|
| 38 |
+
head.load_state_dict(ckpt["state_dict"]); head.eval()
|
| 39 |
+
|
| 40 |
+
docs = load_doc_rows("data/embeddings/combined_embeddings.parquet")
|
| 41 |
+
qnas = load_qna_rows("data/qna/combined_qna.jsonl")
|
| 42 |
+
by_doc = {}
|
| 43 |
+
for q in qnas:
|
| 44 |
+
if q.split == "cr_test": by_doc.setdefault(q.doc_id, []).append(q)
|
| 45 |
+
doc_by_id = {d.doc_id: d for d in docs}
|
| 46 |
+
|
| 47 |
+
real = [d for d in by_doc if "@" in d and d in doc_by_id] # real repos
|
| 48 |
+
synth = [d for d in by_doc if "@" not in d and d in doc_by_id] # synthetic
|
| 49 |
+
rng = random.Random(1)
|
| 50 |
+
picks = rng.sample(real, min(4,len(real))) + rng.sample(synth, min(2,len(synth)))
|
| 51 |
+
named = dict(model.named_modules())
|
| 52 |
+
|
| 53 |
+
for doc_id in picks:
|
| 54 |
+
d = doc_by_id[doc_id]
|
| 55 |
+
kind = "REAL REPO" if "@" in doc_id else "SYNTHETIC"
|
| 56 |
+
ctx = torch.from_numpy(d.doc_embedding).unsqueeze(0)
|
| 57 |
+
head_out = head(ctx)
|
| 58 |
+
pairs = by_doc[doc_id][:2]
|
| 59 |
+
print(f"\n========== [{kind}] {doc_id} ==========", flush=True)
|
| 60 |
+
for q in pairs:
|
| 61 |
+
for sp in specs: named[sp.full_name].A=None; named[sp.full_name].B=None
|
| 62 |
+
base = gen(model, tok, q.prefix)
|
| 63 |
+
inject_lora_weights(model, specs, head_out, batch_index=0)
|
| 64 |
+
adapt = gen(model, tok, q.prefix)
|
| 65 |
+
ok = adapt.strip().rstrip('.').lower().startswith(q.target.strip().rstrip('.').lower()) or \
|
| 66 |
+
q.target.strip().lower().startswith(adapt.strip().lower())
|
| 67 |
+
print(f" Q: {q.prefix.strip()[:90].replace(chr(10),' ')}", flush=True)
|
| 68 |
+
print(f" gold={q.target.strip()!r} base={base.strip()!r} adapted={adapt.strip()!r} {'OK' if ok else 'X'}", flush=True)
|
| 69 |
+
|
| 70 |
+
if __name__ == "__main__":
|
| 71 |
+
main()
|
scripts/test_embed_this_repo.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Step A of the side recall-test: embed THIS repo (gemma4-hack) with the
|
| 3 |
+
frozen encoder in a short-lived, low-memory process, save the 2048-d vector
|
| 4 |
+
to disk, and exit -- so the big base-model process (Step B) never has the
|
| 5 |
+
encoder resident at the same time. CPU-only to avoid competing with the
|
| 6 |
+
live MPS training run."""
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
import sys, gc
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
import numpy as np
|
| 11 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 12 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 13 |
+
from memory_lora.encoder import load_encoder, embed_document
|
| 14 |
+
from memory_lora.codegraph import extract_repo_graph_sections, extract_repo_dependency_summary
|
| 15 |
+
|
| 16 |
+
def main():
|
| 17 |
+
skip = {".git","venv","__pycache__","data","runs",".mypy_cache","scratchpad"}
|
| 18 |
+
print("Extracting codegraph sections from this repo...", flush=True)
|
| 19 |
+
graph_sections = extract_repo_graph_sections(REPO_ROOT, max_files=60, skip_dirs=skip)
|
| 20 |
+
dep = extract_repo_dependency_summary(REPO_ROOT, skip_dirs=skip)
|
| 21 |
+
sections = list(graph_sections)
|
| 22 |
+
if dep:
|
| 23 |
+
sections.append(("dependency_graph", dep))
|
| 24 |
+
# also add a few raw key files for content signal
|
| 25 |
+
for rel in ["memory_lora/core.py", "memory_lora/encoder.py", "scripts/train_memory_lora.py",
|
| 26 |
+
"memory_lora/codegraph.py", "requirements.txt"]:
|
| 27 |
+
p = REPO_ROOT / rel
|
| 28 |
+
if p.exists():
|
| 29 |
+
sections.append((f"raw:{rel}", p.read_text(errors="ignore")))
|
| 30 |
+
print(f" {len(sections)} sections", flush=True)
|
| 31 |
+
|
| 32 |
+
print("Loading encoder on CPU...", flush=True)
|
| 33 |
+
model, tok = load_encoder(device="cpu")
|
| 34 |
+
vec = embed_document(sections, model, tok, "cpu", chunk_tokens=2048, chunk_overlap=256, batch_size=2)
|
| 35 |
+
del model, tok; gc.collect()
|
| 36 |
+
if vec is None:
|
| 37 |
+
print("FAILED: no embedding", flush=True); return
|
| 38 |
+
out = REPO_ROOT / "runs" / "this_repo_emb.npy"
|
| 39 |
+
np.save(out, vec.numpy().astype("float32"))
|
| 40 |
+
print(f"Saved repo embedding {tuple(vec.shape)} -> {out}", flush=True)
|
| 41 |
+
|
| 42 |
+
if __name__ == "__main__":
|
| 43 |
+
main()
|
scripts/test_recall_this_repo.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Step B of the side recall-test. Loads base Gemma-4-E2B on CPU, generates
|
| 3 |
+
a LoRA for THIS repo from its precomputed embedding (Step A) via the
|
| 4 |
+
currently-training hypernetwork's latest checkpoint, and compares base vs
|
| 5 |
+
adapted completions on prompts drawn from this repo's own code.
|
| 6 |
+
|
| 7 |
+
CPU-only (never touches the live MPS training). Peak memory ~= just the
|
| 8 |
+
base model (~10GB) since the encoder already ran and exited in Step A.
|
| 9 |
+
|
| 10 |
+
Note on interpretation: the hypernetwork was trained on pytest
|
| 11 |
+
ASSERTION-COMPLETION over real repos, and THIS repo is unseen (true
|
| 12 |
+
cross-repo test). Prompts are shaped to probe whether the generated
|
| 13 |
+
adapter biases the frozen model toward this repo's specific identifiers/
|
| 14 |
+
values vs the base model's generic guess.
|
| 15 |
+
"""
|
| 16 |
+
from __future__ import annotations
|
| 17 |
+
import sys
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
import numpy as np, torch
|
| 20 |
+
HERE = Path(__file__).resolve().parent; REPO_ROOT = HERE.parent
|
| 21 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 22 |
+
from memory_lora.core import (MemoryLoRAHead, get_module_specs, replace_with_lora,
|
| 23 |
+
inject_lora_weights, DEFAULT_ROOT_PREFIX)
|
| 24 |
+
from transformers import AutoModelForImageTextToText, AutoTokenizer
|
| 25 |
+
|
| 26 |
+
TARGET_MODULES = ["q_proj","k_proj","v_proj","o_proj","up_proj","gate_proj","down_proj"]
|
| 27 |
+
|
| 28 |
+
# Prompts drawn from THIS repo's actual code / conventions. Each is cut right
|
| 29 |
+
# before a repo-specific value the adapter should help recall.
|
| 30 |
+
PROMPTS = [
|
| 31 |
+
("from memory_lora.core import MemoryLoRAHead\n"
|
| 32 |
+
"def test_default_rank():\n"
|
| 33 |
+
" head = MemoryLoRAHead(input_dim=2048, type_dims={})\n"
|
| 34 |
+
" assert head.rank ==", "16"),
|
| 35 |
+
("# memory_lora/core.py sets the LoRA injection root for Gemma-4-E2B\n"
|
| 36 |
+
"DEFAULT_ROOT_PREFIX =", '"model.language_model."'),
|
| 37 |
+
("# memory_lora/encoder.py default frozen embedding model\n"
|
| 38 |
+
"DEFAULT_EMBED_MODEL =", '"Qwen/Qwen3-Embedding-0.6B"'),
|
| 39 |
+
("# scripts/train_memory_lora.py base model being adapted\n"
|
| 40 |
+
"DEFAULT_MODEL =", '"google/gemma-4-E2B"'),
|
| 41 |
+
("from memory_lora.core import MemoryLoRAHead\n"
|
| 42 |
+
"def test_hidden_dim():\n"
|
| 43 |
+
" h = MemoryLoRAHead(input_dim=2048, type_dims={})\n"
|
| 44 |
+
" assert h.hidden_dim ==", "128"),
|
| 45 |
+
("# the seven attention/MLP projection types Memory-LoRA targets\n"
|
| 46 |
+
"DEFAULT_TARGET_MODULES = [\"q_proj\", \"k_proj\", \"v_proj\", \"o_proj\",", '"up_proj"'),
|
| 47 |
+
]
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
@torch.no_grad()
|
| 51 |
+
def gen(model, tok, prefix, max_new=14):
|
| 52 |
+
enc = tok(prefix, return_tensors="pt")
|
| 53 |
+
out = model.generate(**enc, max_new_tokens=max_new, do_sample=False,
|
| 54 |
+
pad_token_id=tok.pad_token_id or tok.eos_token_id)
|
| 55 |
+
return tok.decode(out[0][enc["input_ids"].shape[1]:], skip_special_tokens=True).split("\n")[0]
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def main():
|
| 59 |
+
print("Loading base google/gemma-4-E2B on CPU (bounded ~10GB)...", flush=True)
|
| 60 |
+
tok = AutoTokenizer.from_pretrained("google/gemma-4-E2B")
|
| 61 |
+
if tok.pad_token is None: tok.pad_token = tok.eos_token
|
| 62 |
+
model = AutoModelForImageTextToText.from_pretrained(
|
| 63 |
+
"google/gemma-4-E2B", torch_dtype=torch.float32, low_cpu_mem_usage=True)
|
| 64 |
+
model.eval()
|
| 65 |
+
for p in model.parameters(): p.requires_grad = False
|
| 66 |
+
print(" loaded.", flush=True)
|
| 67 |
+
|
| 68 |
+
ckpt = torch.load(REPO_ROOT / "runs" / "test_ckpt.pt", map_location="cpu")
|
| 69 |
+
specs = get_module_specs(model, TARGET_MODULES, root_prefix=DEFAULT_ROOT_PREFIX)
|
| 70 |
+
replace_with_lora(model, specs, rank=ckpt["config"]["rank"], alpha=ckpt["args"].get("alpha", 32.0))
|
| 71 |
+
head = MemoryLoRAHead(input_dim=ckpt["config"]["input_dim"],
|
| 72 |
+
type_dims={k: tuple(v) for k, v in ckpt["config"]["type_dims"].items()},
|
| 73 |
+
hidden_dim=ckpt["config"]["hidden_dim"], rank=ckpt["config"]["rank"])
|
| 74 |
+
head.load_state_dict(ckpt["state_dict"]); head.eval()
|
| 75 |
+
|
| 76 |
+
repo_emb = torch.from_numpy(np.load(REPO_ROOT / "runs" / "this_repo_emb.npy")).unsqueeze(0)
|
| 77 |
+
head_out = head(repo_emb)
|
| 78 |
+
print(f" generated adapter for THIS repo (unseen). "
|
| 79 |
+
f"training step in checkpoint: {ckpt['args'].get('epochs','?')} epochs cfg\n", flush=True)
|
| 80 |
+
|
| 81 |
+
named = dict(model.named_modules())
|
| 82 |
+
for prefix, gold in PROMPTS:
|
| 83 |
+
# base: no adapter
|
| 84 |
+
for sp in specs:
|
| 85 |
+
named[sp.full_name].A = None; named[sp.full_name].B = None
|
| 86 |
+
base = gen(model, tok, prefix)
|
| 87 |
+
# adapted: inject this repo's generated LoRA
|
| 88 |
+
inject_lora_weights(model, specs, head_out, batch_index=0)
|
| 89 |
+
adapted = gen(model, tok, prefix)
|
| 90 |
+
tag = prefix.strip().split("\n")[-1][:55]
|
| 91 |
+
print(f"PROMPT: ...{tag}", flush=True)
|
| 92 |
+
print(f" gold: {gold}", flush=True)
|
| 93 |
+
print(f" base: {base!r}", flush=True)
|
| 94 |
+
print(f" adapted: {adapted!r}", flush=True)
|
| 95 |
+
print(flush=True)
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
if __name__ == "__main__":
|
| 99 |
+
main()
|
scripts/train_direct_lora.py
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Train a standalone, directly-parameterized LoRA adapter on priority
|
| 3 |
+
document(s) -- NOT hypernetwork-generated.
|
| 4 |
+
|
| 5 |
+
Why this exists (see runs/full1, runs/full2, runs/full3_priority logs):
|
| 6 |
+
a single hypernetwork trunk shared across 165+ documents cannot
|
| 7 |
+
simultaneously (a) generalize broadly across the corpus and (b) reliably
|
| 8 |
+
memorize any one document's specific facts -- three separate interventions
|
| 9 |
+
(bigger head, oversampling) each improved (b) only by making (a) collapse
|
| 10 |
+
faster, because they all perturb the SAME shared trunk weights.
|
| 11 |
+
|
| 12 |
+
This script sidesteps the tension entirely for content we don't need
|
| 13 |
+
zero-shot generalization on (documents we already have and specifically
|
| 14 |
+
want memorized, e.g. the Code2LoRA paper): instead of a hypernetwork
|
| 15 |
+
mapping embedding->weights, the LoRA A/B matrices are ordinary
|
| 16 |
+
``nn.Parameter`` tensors trained directly via backprop on exactly the
|
| 17 |
+
QA pairs for the selected doc_id(s) -- standard PEFT-style fine-tuning,
|
| 18 |
+
with the same LoRA wrapper class (``memory_lora.core.LoRA``) and the same
|
| 19 |
+
frozen Gemma-4-E2B target modules as the hypernetwork path, so results are
|
| 20 |
+
directly comparable and the diagnostic single-doc runs (which proved this
|
| 21 |
+
converges to correct multi-fact recall) apply unchanged.
|
| 22 |
+
|
| 23 |
+
Usage:
|
| 24 |
+
python scripts/train_direct_lora.py --output-dir direct_paper \\
|
| 25 |
+
--doc-ids code2lora_paper --epochs 300
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
from __future__ import annotations
|
| 29 |
+
|
| 30 |
+
import argparse
|
| 31 |
+
import json
|
| 32 |
+
import random
|
| 33 |
+
import sys
|
| 34 |
+
import time
|
| 35 |
+
from pathlib import Path
|
| 36 |
+
from typing import Any, Dict, List
|
| 37 |
+
|
| 38 |
+
import numpy as np
|
| 39 |
+
import torch
|
| 40 |
+
import torch.nn as nn
|
| 41 |
+
import torch.nn.functional as F
|
| 42 |
+
from transformers import AutoModelForImageTextToText, AutoTokenizer, get_cosine_schedule_with_warmup
|
| 43 |
+
|
| 44 |
+
HERE = Path(__file__).resolve().parent
|
| 45 |
+
REPO_ROOT = HERE.parent
|
| 46 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 47 |
+
from memory_lora.data_paths import QNA_DIR, RUNS_DIR, ensure_dirs # noqa: E402
|
| 48 |
+
from memory_lora.core import ( # noqa: E402
|
| 49 |
+
DEFAULT_ROOT_PREFIX,
|
| 50 |
+
discover_module_types_and_dims,
|
| 51 |
+
get_module_specs,
|
| 52 |
+
load_qna_rows,
|
| 53 |
+
replace_with_lora,
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
DEFAULT_MODEL = "google/gemma-4-E2B"
|
| 57 |
+
DEFAULT_TARGET_MODULES = [
|
| 58 |
+
"q_proj", "k_proj", "v_proj", "o_proj",
|
| 59 |
+
"up_proj", "gate_proj", "down_proj",
|
| 60 |
+
]
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def _tokenize_lm_batch(tokenizer, prefixes: List[str], targets: List[str],
|
| 64 |
+
max_seq_len: int = 384) -> Dict[str, torch.Tensor]:
|
| 65 |
+
eos = tokenizer.eos_token or ""
|
| 66 |
+
input_ids_list, labels_list = [], []
|
| 67 |
+
for p, t in zip(prefixes, targets):
|
| 68 |
+
t_ids = tokenizer(t + eos, add_special_tokens=False)["input_ids"]
|
| 69 |
+
if not t_ids:
|
| 70 |
+
continue
|
| 71 |
+
prefix_budget = max(8, max_seq_len - len(t_ids))
|
| 72 |
+
p_ids_full = tokenizer(p, add_special_tokens=False)["input_ids"]
|
| 73 |
+
p_ids = p_ids_full[-prefix_budget:] if len(p_ids_full) > prefix_budget else p_ids_full
|
| 74 |
+
ids = p_ids + t_ids
|
| 75 |
+
labels = ([-100] * len(p_ids)) + list(t_ids)
|
| 76 |
+
input_ids_list.append(torch.tensor(ids, dtype=torch.long))
|
| 77 |
+
labels_list.append(torch.tensor(labels, dtype=torch.long))
|
| 78 |
+
if not input_ids_list:
|
| 79 |
+
return {}
|
| 80 |
+
L = max(t.size(0) for t in input_ids_list)
|
| 81 |
+
pad_id = tokenizer.pad_token_id or 0
|
| 82 |
+
|
| 83 |
+
def _lpad(x, val):
|
| 84 |
+
return F.pad(x, (L - x.size(0), 0), value=val)
|
| 85 |
+
|
| 86 |
+
input_ids = torch.stack([_lpad(t, pad_id) for t in input_ids_list], 0)
|
| 87 |
+
labels = torch.stack([_lpad(t, -100) for t in labels_list], 0)
|
| 88 |
+
attn_list = [torch.ones(t.size(0), dtype=torch.long) for t in input_ids_list]
|
| 89 |
+
attn = torch.stack([_lpad(t, 0) for t in attn_list], 0)
|
| 90 |
+
return {"input_ids": input_ids, "labels": labels, "attention_mask": attn}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def init_direct_lora_params(model: nn.Module, specs, rank: int, device, dtype) -> Dict[str, Dict[str, nn.Parameter]]:
|
| 94 |
+
"""Give each LoRA wrapper its OWN trainable (A, B), instead of an
|
| 95 |
+
externally-injected tensor from a hypernetwork. B initialized to zero
|
| 96 |
+
(standard LoRA init) so the adapter starts as a no-op."""
|
| 97 |
+
named = dict(model.named_modules())
|
| 98 |
+
params: Dict[str, Dict[str, nn.Parameter]] = {}
|
| 99 |
+
for sp in specs:
|
| 100 |
+
lora_mod = named[sp.full_name]
|
| 101 |
+
A = nn.Parameter(torch.randn(rank, sp.in_features, device=device, dtype=torch.float32) * 0.01)
|
| 102 |
+
B = nn.Parameter(torch.zeros(sp.out_features, rank, device=device, dtype=torch.float32))
|
| 103 |
+
lora_mod.set_lora_weights(A, B)
|
| 104 |
+
params[sp.full_name] = {"A": A, "B": B}
|
| 105 |
+
return params
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def main() -> None:
|
| 109 |
+
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 110 |
+
ap.add_argument("--qna-path", default=str(QNA_DIR / "qna.jsonl"))
|
| 111 |
+
ap.add_argument("--output-dir", required=True)
|
| 112 |
+
ap.add_argument("--model-name", default=DEFAULT_MODEL)
|
| 113 |
+
ap.add_argument("--target-modules", nargs="+", default=DEFAULT_TARGET_MODULES)
|
| 114 |
+
ap.add_argument("--root-prefix", default=DEFAULT_ROOT_PREFIX)
|
| 115 |
+
ap.add_argument("--doc-ids", nargs="+", default=[],
|
| 116 |
+
help="Train a single direct LoRA jointly on the union "
|
| 117 |
+
"of these documents' QnAs (use one doc_id for a "
|
| 118 |
+
"dedicated per-document adapter).")
|
| 119 |
+
ap.add_argument("--doc-ids-file", default="",
|
| 120 |
+
help="Alternative to --doc-ids: path to a file with "
|
| 121 |
+
"whitespace-separated doc_ids. Avoids shell "
|
| 122 |
+
"word-splitting pitfalls (e.g. zsh does not "
|
| 123 |
+
"word-split unquoted $VAR by default) for large "
|
| 124 |
+
"doc-id lists.")
|
| 125 |
+
ap.add_argument("--rank", type=int, default=32)
|
| 126 |
+
ap.add_argument("--alpha", type=float, default=64.0)
|
| 127 |
+
ap.add_argument("--epochs", type=int, default=300)
|
| 128 |
+
ap.add_argument("--lr", type=float, default=3e-4)
|
| 129 |
+
ap.add_argument("--weight-decay", type=float, default=0.0)
|
| 130 |
+
ap.add_argument("--warmup-ratio", type=float, default=0.05)
|
| 131 |
+
ap.add_argument("--max-grad-norm", type=float, default=1.0)
|
| 132 |
+
ap.add_argument("--max-seq-len", type=int, default=384)
|
| 133 |
+
ap.add_argument("--lm-micro-batch", type=int, default=4)
|
| 134 |
+
ap.add_argument("--eval-every-epochs", type=int, default=10)
|
| 135 |
+
ap.add_argument("--epoch-ckpt-every", type=int, default=25)
|
| 136 |
+
ap.add_argument("--seed", type=int, default=3407)
|
| 137 |
+
ap.add_argument("--device", default="mps")
|
| 138 |
+
ap.add_argument("--dtype", default="bfloat16", choices=["bfloat16", "float16", "float32"])
|
| 139 |
+
ap.add_argument("--attn-implementation", default="sdpa", choices=["sdpa", "eager"])
|
| 140 |
+
ap.add_argument("--gradient-checkpointing", action="store_true", default=True)
|
| 141 |
+
ap.add_argument("--no-gradient-checkpointing", dest="gradient_checkpointing", action="store_false")
|
| 142 |
+
args = ap.parse_args()
|
| 143 |
+
|
| 144 |
+
out_dir = Path(args.output_dir)
|
| 145 |
+
if not out_dir.is_absolute():
|
| 146 |
+
out_dir = RUNS_DIR / out_dir
|
| 147 |
+
out_dir.mkdir(parents=True, exist_ok=True)
|
| 148 |
+
ensure_dirs()
|
| 149 |
+
|
| 150 |
+
device = torch.device(args.device if (args.device != "mps" or torch.backends.mps.is_available()) else "cpu")
|
| 151 |
+
dtype = {"bfloat16": torch.bfloat16, "float16": torch.float16, "float32": torch.float32}[args.dtype]
|
| 152 |
+
random.seed(args.seed)
|
| 153 |
+
np.random.seed(args.seed)
|
| 154 |
+
torch.manual_seed(args.seed)
|
| 155 |
+
|
| 156 |
+
if args.doc_ids_file:
|
| 157 |
+
file_ids = Path(args.doc_ids_file).read_text().split()
|
| 158 |
+
doc_ids = set(args.doc_ids) | set(file_ids)
|
| 159 |
+
else:
|
| 160 |
+
doc_ids = set(args.doc_ids)
|
| 161 |
+
if not doc_ids:
|
| 162 |
+
raise SystemExit("No --doc-ids or --doc-ids-file provided.")
|
| 163 |
+
print(f"Training a direct (non-hypernetwork) LoRA jointly on: {sorted(doc_ids)}", flush=True)
|
| 164 |
+
all_qnas = load_qna_rows(Path(args.qna_path))
|
| 165 |
+
train_qnas = [q for q in all_qnas if q.doc_id in doc_ids and q.qna_split == "train"]
|
| 166 |
+
held_out_qnas = [q for q in all_qnas if q.doc_id in doc_ids and q.qna_split == "held_out"]
|
| 167 |
+
print(f" {len(train_qnas)} train QAs, {len(held_out_qnas)} held-out QAs", flush=True)
|
| 168 |
+
if not train_qnas:
|
| 169 |
+
raise SystemExit("No train QnAs found for the given --doc-ids.")
|
| 170 |
+
|
| 171 |
+
print(f"Loading {args.model_name} ...", flush=True)
|
| 172 |
+
tokenizer = AutoTokenizer.from_pretrained(args.model_name)
|
| 173 |
+
if tokenizer.pad_token is None:
|
| 174 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 175 |
+
base_model = AutoModelForImageTextToText.from_pretrained(
|
| 176 |
+
args.model_name, torch_dtype=dtype, attn_implementation=args.attn_implementation,
|
| 177 |
+
).to(device)
|
| 178 |
+
base_model.eval()
|
| 179 |
+
for p in base_model.parameters():
|
| 180 |
+
p.requires_grad = False
|
| 181 |
+
if args.gradient_checkpointing:
|
| 182 |
+
base_model.config.use_cache = False
|
| 183 |
+
base_model.gradient_checkpointing_enable(gradient_checkpointing_kwargs={"use_reentrant": False})
|
| 184 |
+
print(" gradient checkpointing: ON", flush=True)
|
| 185 |
+
|
| 186 |
+
specs = get_module_specs(base_model, args.target_modules, root_prefix=args.root_prefix)
|
| 187 |
+
type_dims = discover_module_types_and_dims(specs)
|
| 188 |
+
print(f" discovered {len(specs)} target modules, {len(type_dims)} shape-types", flush=True)
|
| 189 |
+
replace_with_lora(base_model, specs, rank=args.rank, alpha=args.alpha)
|
| 190 |
+
lora_params = init_direct_lora_params(base_model, specs, args.rank, device, dtype)
|
| 191 |
+
all_params = [p for pair in lora_params.values() for p in pair.values()]
|
| 192 |
+
n_params = sum(p.numel() for p in all_params)
|
| 193 |
+
print(f" direct LoRA trainable params: {n_params / 1e6:.2f}M "
|
| 194 |
+
f"(rank={args.rank}, {len(specs)} modules)", flush=True)
|
| 195 |
+
|
| 196 |
+
optim = torch.optim.AdamW(all_params, lr=args.lr, weight_decay=args.weight_decay)
|
| 197 |
+
total_steps = args.epochs
|
| 198 |
+
warmup_steps = max(1, int(total_steps * args.warmup_ratio))
|
| 199 |
+
sched = get_cosine_schedule_with_warmup(optim, warmup_steps, total_steps)
|
| 200 |
+
|
| 201 |
+
def _save(name: str) -> Path:
|
| 202 |
+
out = out_dir / f"lora.{name}.pt"
|
| 203 |
+
state = {full_name: {"A": pair["A"].detach().cpu(), "B": pair["B"].detach().cpu()}
|
| 204 |
+
for full_name, pair in lora_params.items()}
|
| 205 |
+
torch.save({"lora": state, "rank": args.rank, "alpha": args.alpha,
|
| 206 |
+
"doc_ids": sorted(doc_ids), "target_modules": args.target_modules,
|
| 207 |
+
"root_prefix": args.root_prefix}, out)
|
| 208 |
+
return out
|
| 209 |
+
|
| 210 |
+
@torch.no_grad()
|
| 211 |
+
def _eval_held_out() -> float:
|
| 212 |
+
if not held_out_qnas:
|
| 213 |
+
return float("nan")
|
| 214 |
+
base_model.eval()
|
| 215 |
+
total_loss, total_tok = 0.0, 0
|
| 216 |
+
prefixes = [q.prefix for q in held_out_qnas]
|
| 217 |
+
targets = [q.target for q in held_out_qnas]
|
| 218 |
+
for i in range(0, len(prefixes), args.lm_micro_batch):
|
| 219 |
+
j = min(i + args.lm_micro_batch, len(prefixes))
|
| 220 |
+
batch = _tokenize_lm_batch(tokenizer, prefixes[i:j], targets[i:j], max_seq_len=args.max_seq_len)
|
| 221 |
+
if not batch:
|
| 222 |
+
continue
|
| 223 |
+
batch = {k: v.to(device) for k, v in batch.items()}
|
| 224 |
+
out = base_model(**batch)
|
| 225 |
+
ntok = (batch["labels"] != -100).sum().item()
|
| 226 |
+
total_loss += out.loss.item() * ntok
|
| 227 |
+
total_tok += ntok
|
| 228 |
+
return total_loss / max(total_tok, 1)
|
| 229 |
+
|
| 230 |
+
prefixes_all = [q.prefix for q in train_qnas]
|
| 231 |
+
targets_all = [q.target for q in train_qnas]
|
| 232 |
+
metrics_log: List[Dict[str, Any]] = []
|
| 233 |
+
t0 = time.time()
|
| 234 |
+
for epoch in range(args.epochs):
|
| 235 |
+
order = list(range(len(prefixes_all)))
|
| 236 |
+
random.shuffle(order)
|
| 237 |
+
prefixes = [prefixes_all[i] for i in order]
|
| 238 |
+
targets = [targets_all[i] for i in order]
|
| 239 |
+
loss_acc, n_tok_seen = 0.0, 0
|
| 240 |
+
for i in range(0, len(prefixes), args.lm_micro_batch):
|
| 241 |
+
j = min(i + args.lm_micro_batch, len(prefixes))
|
| 242 |
+
batch = _tokenize_lm_batch(tokenizer, prefixes[i:j], targets[i:j], max_seq_len=args.max_seq_len)
|
| 243 |
+
if not batch:
|
| 244 |
+
continue
|
| 245 |
+
batch = {k: v.to(device) for k, v in batch.items()}
|
| 246 |
+
out = base_model(**batch)
|
| 247 |
+
ntok = (batch["labels"] != -100).sum().item()
|
| 248 |
+
loss = out.loss * ntok
|
| 249 |
+
loss.backward()
|
| 250 |
+
loss_acc += loss.detach().item()
|
| 251 |
+
n_tok_seen += ntok
|
| 252 |
+
torch.nn.utils.clip_grad_norm_(all_params, args.max_grad_norm)
|
| 253 |
+
optim.step()
|
| 254 |
+
sched.step()
|
| 255 |
+
optim.zero_grad(set_to_none=True)
|
| 256 |
+
|
| 257 |
+
avg = loss_acc / max(n_tok_seen, 1)
|
| 258 |
+
elapsed = (time.time() - t0) / 60
|
| 259 |
+
if epoch % 10 == 0 or epoch == args.epochs - 1:
|
| 260 |
+
print(f"[ep{epoch}] train_loss={avg:.4f} lr={sched.get_last_lr()[0]:.2e} elapsed={elapsed:.1f}m", flush=True)
|
| 261 |
+
|
| 262 |
+
if epoch % max(1, args.eval_every_epochs) == 0 or epoch == args.epochs - 1:
|
| 263 |
+
held_out_loss = _eval_held_out()
|
| 264 |
+
print(f" [eval] ep{epoch} held_out_loss={held_out_loss:.4f}", flush=True)
|
| 265 |
+
metrics_log.append({"epoch": epoch, "train_loss": avg, "held_out_loss": held_out_loss})
|
| 266 |
+
(out_dir / "metrics.jsonl").open("a").write(json.dumps(metrics_log[-1]) + "\n")
|
| 267 |
+
|
| 268 |
+
if epoch % max(1, args.epoch_ckpt_every) == 0 or epoch == args.epochs - 1:
|
| 269 |
+
p = _save(f"ep{epoch}")
|
| 270 |
+
print(f" [ckpt] -> {p}", flush=True)
|
| 271 |
+
_save("latest")
|
| 272 |
+
|
| 273 |
+
print(f"\nDirect LoRA training done. Final train_loss={avg:.4f}", flush=True)
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
if __name__ == "__main__":
|
| 277 |
+
main()
|
scripts/train_memory_lora.py
ADDED
|
@@ -0,0 +1,668 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Train the Memory-LoRA hypernetwork on google/gemma-4-E2B.
|
| 3 |
+
|
| 4 |
+
Forked from Code2LoRA's ``hypernetwork/train_code2lora_static_v2.py``
|
| 5 |
+
(direct-projection trainer), retargeted:
|
| 6 |
+
|
| 7 |
+
* repo embedding -> doc embedding (memory_lora/encoder.py output)
|
| 8 |
+
* Qwen2.5-Coder -> google/gemma-4-E2B (memory_lora/core.py target modules)
|
| 9 |
+
* cuda + flash_attn2 -> mps + sdpa (falls back to eager)
|
| 10 |
+
* no wandb/TRL -> plain PyTorch loop + TensorBoard (SummaryWriter)
|
| 11 |
+
|
| 12 |
+
Same core trick as the paper: only the hypernetwork head is trained; the
|
| 13 |
+
base LLM is frozen (gradient-checkpointed for memory headroom); LoRA A/B
|
| 14 |
+
tensors are non-detached so the causal-LM loss's backward graph flows
|
| 15 |
+
straight into the head's parameters.
|
| 16 |
+
|
| 17 |
+
Usage:
|
| 18 |
+
python scripts/train_memory_lora.py --output-dir runs/pilot1 \\
|
| 19 |
+
--limit-train-docs 5 --epochs 1 # smoke test
|
| 20 |
+
|
| 21 |
+
python scripts/train_memory_lora.py --output-dir runs/full1
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
from __future__ import annotations
|
| 25 |
+
|
| 26 |
+
import argparse
|
| 27 |
+
import json
|
| 28 |
+
import random
|
| 29 |
+
import sys
|
| 30 |
+
import time
|
| 31 |
+
from pathlib import Path
|
| 32 |
+
from typing import Any, Dict, List, Optional, Tuple
|
| 33 |
+
|
| 34 |
+
import numpy as np
|
| 35 |
+
import psutil
|
| 36 |
+
import torch
|
| 37 |
+
import torch.nn as nn
|
| 38 |
+
import torch.nn.functional as F
|
| 39 |
+
from torch.utils.tensorboard import SummaryWriter
|
| 40 |
+
from transformers import (
|
| 41 |
+
AutoModelForImageTextToText,
|
| 42 |
+
AutoTokenizer,
|
| 43 |
+
get_cosine_schedule_with_warmup,
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
HERE = Path(__file__).resolve().parent
|
| 47 |
+
REPO_ROOT = HERE.parent
|
| 48 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 49 |
+
from memory_lora.data_paths import EMBEDDINGS_DIR, QNA_DIR, RUNS_DIR, ensure_dirs # noqa: E402
|
| 50 |
+
from memory_lora.core import ( # noqa: E402
|
| 51 |
+
MemoryLoRAHead,
|
| 52 |
+
DEFAULT_ROOT_PREFIX,
|
| 53 |
+
discover_module_types_and_dims,
|
| 54 |
+
get_module_specs,
|
| 55 |
+
inject_lora_weights,
|
| 56 |
+
load_doc_rows,
|
| 57 |
+
load_qna_rows,
|
| 58 |
+
replace_with_lora,
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
DEFAULT_MODEL = "google/gemma-4-E2B"
|
| 62 |
+
DEFAULT_TARGET_MODULES = [
|
| 63 |
+
"q_proj", "k_proj", "v_proj", "o_proj",
|
| 64 |
+
"up_proj", "gate_proj", "down_proj",
|
| 65 |
+
]
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
# ---------------------------------------------------------------------------
|
| 69 |
+
# Dataset & batching
|
| 70 |
+
# ---------------------------------------------------------------------------
|
| 71 |
+
|
| 72 |
+
class DocDataset:
|
| 73 |
+
"""One example = one document with its train-split QnAs."""
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
docs_by_id: Dict[str, Dict[str, Any]],
|
| 78 |
+
qnas_by_doc: Dict[str, List[Dict[str, str]]],
|
| 79 |
+
doc_ids: List[str],
|
| 80 |
+
max_qna_per_doc: int = 32,
|
| 81 |
+
seed: int = 3407,
|
| 82 |
+
):
|
| 83 |
+
self.doc_ids = list(doc_ids)
|
| 84 |
+
self.docs = docs_by_id
|
| 85 |
+
self.qnas = qnas_by_doc
|
| 86 |
+
self.max_qna = max_qna_per_doc
|
| 87 |
+
self.rng = random.Random(seed)
|
| 88 |
+
|
| 89 |
+
def __len__(self) -> int:
|
| 90 |
+
return len(self.doc_ids)
|
| 91 |
+
|
| 92 |
+
def __getitem__(self, idx: int) -> Optional[Dict[str, Any]]:
|
| 93 |
+
d = self.doc_ids[idx]
|
| 94 |
+
pairs = list(self.qnas.get(d, []))
|
| 95 |
+
if not pairs:
|
| 96 |
+
return None
|
| 97 |
+
if len(pairs) > self.max_qna:
|
| 98 |
+
pairs = self.rng.sample(pairs, self.max_qna)
|
| 99 |
+
return {"doc_id": d, "embedding": self.docs[d]["emb"], "qnas": pairs}
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def _tokenize_lm_batch(tokenizer, prefixes: List[str], targets: List[str],
|
| 103 |
+
max_seq_len: int = 2048,
|
| 104 |
+
fixed_len: bool = False) -> Dict[str, torch.Tensor]:
|
| 105 |
+
"""Causal-LM batch with the loss masked on prefix tokens. Keeps the
|
| 106 |
+
rightmost prefix tokens on overflow; targets are never truncated.
|
| 107 |
+
|
| 108 |
+
fixed_len: pad every batch to EXACTLY max_seq_len instead of the
|
| 109 |
+
batch's own local max length. Real code prefixes vary widely (100-1024+
|
| 110 |
+
tokens across different repos), so per-batch padding produces a new
|
| 111 |
+
tensor shape almost every document. On MPS this repeatedly triggered
|
| 112 |
+
unbounded memory growth (observed: a run that stayed under 13GB on
|
| 113 |
+
homogeneous-length synthetic docs hit 70+GB and got OS-killed within
|
| 114 |
+
~10 documents of real, variable-length code) -- MPS's caching allocator
|
| 115 |
+
does not appear to reliably reclaim/reuse blocks across many distinct
|
| 116 |
+
shapes the way CUDA's does. Fixing every batch to one shape avoids the
|
| 117 |
+
allocator ever seeing a new size after the first batch. Slightly wastes
|
| 118 |
+
compute on padding for short sequences; that trade is worth it for
|
| 119 |
+
system stability.
|
| 120 |
+
"""
|
| 121 |
+
eos = tokenizer.eos_token or ""
|
| 122 |
+
input_ids_list: List[torch.Tensor] = []
|
| 123 |
+
labels_list: List[torch.Tensor] = []
|
| 124 |
+
for p, t in zip(prefixes, targets):
|
| 125 |
+
t_ids = tokenizer(t + eos, add_special_tokens=False)["input_ids"]
|
| 126 |
+
if not t_ids:
|
| 127 |
+
continue
|
| 128 |
+
prefix_budget = max(8, max_seq_len - len(t_ids))
|
| 129 |
+
p_ids_full = tokenizer(p, add_special_tokens=False)["input_ids"]
|
| 130 |
+
p_ids = p_ids_full[-prefix_budget:] if len(p_ids_full) > prefix_budget else p_ids_full
|
| 131 |
+
ids = p_ids + t_ids
|
| 132 |
+
labels = ([-100] * len(p_ids)) + list(t_ids)
|
| 133 |
+
input_ids_list.append(torch.tensor(ids, dtype=torch.long))
|
| 134 |
+
labels_list.append(torch.tensor(labels, dtype=torch.long))
|
| 135 |
+
if not input_ids_list:
|
| 136 |
+
return {}
|
| 137 |
+
local_max = max(t.size(0) for t in input_ids_list)
|
| 138 |
+
L = max(max_seq_len, local_max) if fixed_len else local_max
|
| 139 |
+
pad_id = tokenizer.pad_token_id or 0
|
| 140 |
+
|
| 141 |
+
def _lpad(x, val):
|
| 142 |
+
return F.pad(x, (L - x.size(0), 0), value=val)
|
| 143 |
+
|
| 144 |
+
input_ids = torch.stack([_lpad(t, pad_id) for t in input_ids_list], 0)
|
| 145 |
+
labels = torch.stack([_lpad(t, -100) for t in labels_list], 0)
|
| 146 |
+
attn_list = [torch.ones(t.size(0), dtype=torch.long) for t in input_ids_list]
|
| 147 |
+
attn = torch.stack([_lpad(t, 0) for t in attn_list], 0)
|
| 148 |
+
return {"input_ids": input_ids, "labels": labels, "attention_mask": attn}
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
# ---------------------------------------------------------------------------
|
| 152 |
+
# Eval
|
| 153 |
+
# ---------------------------------------------------------------------------
|
| 154 |
+
|
| 155 |
+
@torch.no_grad()
|
| 156 |
+
def evaluate_suite(
|
| 157 |
+
base_model: nn.Module, head: MemoryLoRAHead, specs, tokenizer,
|
| 158 |
+
doc_rows: List[Any], qnas_by_doc: Dict[str, List[Dict[str, str]]],
|
| 159 |
+
*, device: torch.device, max_seq_len: int = 512,
|
| 160 |
+
lm_micro_batch: int = 4, max_qna_per_doc: int = 32,
|
| 161 |
+
fixed_len: bool = False,
|
| 162 |
+
) -> Dict[str, float]:
|
| 163 |
+
base_model.eval()
|
| 164 |
+
head.eval()
|
| 165 |
+
total_loss = 0.0
|
| 166 |
+
total_tokens = 0
|
| 167 |
+
n_docs = 0
|
| 168 |
+
for dr in doc_rows:
|
| 169 |
+
pairs = qnas_by_doc.get(dr.doc_id)
|
| 170 |
+
if not pairs:
|
| 171 |
+
continue
|
| 172 |
+
if len(pairs) > max_qna_per_doc:
|
| 173 |
+
pairs = pairs[:max_qna_per_doc]
|
| 174 |
+
ctx = torch.from_numpy(dr.doc_embedding).to(device).unsqueeze(0)
|
| 175 |
+
head_out = head(ctx)
|
| 176 |
+
inject_lora_weights(base_model, specs, head_out, batch_index=0)
|
| 177 |
+
prefixes = [p["prefix"] for p in pairs]
|
| 178 |
+
targets = [p["target"] for p in pairs]
|
| 179 |
+
for i in range(0, len(prefixes), lm_micro_batch):
|
| 180 |
+
j = min(i + lm_micro_batch, len(prefixes))
|
| 181 |
+
batch = _tokenize_lm_batch(tokenizer, prefixes[i:j], targets[i:j],
|
| 182 |
+
max_seq_len=max_seq_len, fixed_len=fixed_len)
|
| 183 |
+
if not batch:
|
| 184 |
+
continue
|
| 185 |
+
batch = {k: v.to(device) for k, v in batch.items()}
|
| 186 |
+
out = base_model(**batch)
|
| 187 |
+
loss = out.loss
|
| 188 |
+
ntok = (batch["labels"] != -100).sum().item()
|
| 189 |
+
total_loss += loss.item() * ntok
|
| 190 |
+
total_tokens += ntok
|
| 191 |
+
n_docs += 1
|
| 192 |
+
avg = total_loss / max(total_tokens, 1)
|
| 193 |
+
return {"eval_loss": avg, "n_docs": n_docs, "n_tokens": total_tokens}
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
# ---------------------------------------------------------------------------
|
| 197 |
+
# Main
|
| 198 |
+
# ---------------------------------------------------------------------------
|
| 199 |
+
|
| 200 |
+
def _docs_by_id(doc_rows) -> Dict[str, Dict[str, Any]]:
|
| 201 |
+
return {dr.doc_id: {"emb": dr.doc_embedding} for dr in doc_rows}
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
def _group_qnas_by_doc(rows) -> Dict[str, List[Dict[str, str]]]:
|
| 205 |
+
out: Dict[str, List[Dict[str, str]]] = {}
|
| 206 |
+
for qr in rows:
|
| 207 |
+
out.setdefault(qr.doc_id, []).append({"prefix": qr.prefix, "target": qr.target})
|
| 208 |
+
return out
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def main() -> None:
|
| 212 |
+
ap = argparse.ArgumentParser(description=__doc__,
|
| 213 |
+
formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 214 |
+
ap.add_argument("--embeddings-path", default=str(EMBEDDINGS_DIR / "doc_embeddings.parquet"))
|
| 215 |
+
ap.add_argument("--qna-path", default=str(QNA_DIR / "qna.jsonl"))
|
| 216 |
+
ap.add_argument("--output-dir", required=True)
|
| 217 |
+
ap.add_argument("--model-name", default=DEFAULT_MODEL)
|
| 218 |
+
ap.add_argument("--target-modules", nargs="+", default=DEFAULT_TARGET_MODULES)
|
| 219 |
+
ap.add_argument("--root-prefix", default=DEFAULT_ROOT_PREFIX)
|
| 220 |
+
|
| 221 |
+
ap.add_argument("--rank", type=int, default=16)
|
| 222 |
+
ap.add_argument("--alpha", type=float, default=32.0)
|
| 223 |
+
ap.add_argument("--head-hidden-dim", type=int, default=128,
|
| 224 |
+
help="Kept small deliberately -- with ~165 training "
|
| 225 |
+
"docs, the paper's 512-1024 hidden dim overfits "
|
| 226 |
+
"within ~2 epochs (see memory_lora/core.py docstring).")
|
| 227 |
+
ap.add_argument("--head-dropout", type=float, default=0.1)
|
| 228 |
+
|
| 229 |
+
ap.add_argument("--epochs", type=int, default=3)
|
| 230 |
+
ap.add_argument("--lr", type=float, default=1e-4)
|
| 231 |
+
ap.add_argument("--weight-decay", type=float, default=0.05)
|
| 232 |
+
ap.add_argument("--warmup-ratio", type=float, default=0.03)
|
| 233 |
+
ap.add_argument("--lr-total-steps", type=int, default=0,
|
| 234 |
+
help="Override the cosine LR schedule's total-step "
|
| 235 |
+
"target with a realistic estimate of what "
|
| 236 |
+
"--max-hours will actually cover, instead of "
|
| 237 |
+
"steps_per_epoch * epochs (which assumes the run "
|
| 238 |
+
"finishes a full epoch -- unrealistic at "
|
| 239 |
+
"tens-of-thousands-of-docs scale). 0 = use the "
|
| 240 |
+
"epoch-based calculation.")
|
| 241 |
+
ap.add_argument("--max-grad-norm", type=float, default=1.0)
|
| 242 |
+
ap.add_argument("--early-stop-patience", type=int, default=8,
|
| 243 |
+
help="Stop after this many consecutive evals with no "
|
| 244 |
+
"improvement on --primary-eval-suite. 0 = disabled.")
|
| 245 |
+
|
| 246 |
+
ap.add_argument("--max-qna-per-doc", type=int, default=32)
|
| 247 |
+
ap.add_argument("--lm-micro-batch", type=int, default=4)
|
| 248 |
+
ap.add_argument("--max-seq-len", type=int, default=512)
|
| 249 |
+
ap.add_argument("--fixed-seq-len", action="store_true", default=True,
|
| 250 |
+
help="Pad every batch to exactly --max-seq-len instead "
|
| 251 |
+
"of each batch's own local max length. See "
|
| 252 |
+
"_tokenize_lm_batch docstring: on MPS, varying "
|
| 253 |
+
"tensor shapes across many real-code documents "
|
| 254 |
+
"of wildly different lengths caused unbounded "
|
| 255 |
+
"memory growth (a run went from healthy to "
|
| 256 |
+
"OS-killed within ~10 documents). Costs some "
|
| 257 |
+
"wasted padding compute; worth it for stability.")
|
| 258 |
+
ap.add_argument("--no-fixed-seq-len", dest="fixed_seq_len", action="store_false")
|
| 259 |
+
|
| 260 |
+
ap.add_argument("--eval-every-steps", type=int, default=50)
|
| 261 |
+
ap.add_argument("--eval-suites", nargs="+", default=["cr_val", "cr_test", "ir_test"])
|
| 262 |
+
ap.add_argument("--limit-eval-docs", type=int, default=200,
|
| 263 |
+
help="Cap docs per eval suite (random sample, fixed "
|
| 264 |
+
"seed) for speed at real-corpus scale -- e.g. "
|
| 265 |
+
"cr_val alone can be 8,600+ real repo-commit "
|
| 266 |
+
"docs; evaluating all of them every eval cycle "
|
| 267 |
+
"would dominate wall-clock time. 0 = no cap "
|
| 268 |
+
"(matches the paper's own --limit-eval-snapshots).")
|
| 269 |
+
ap.add_argument("--primary-eval-suite", default="cr_val")
|
| 270 |
+
ap.add_argument("--log-every-iters", type=int, default=10)
|
| 271 |
+
|
| 272 |
+
ap.add_argument("--seed", type=int, default=3407)
|
| 273 |
+
ap.add_argument("--device", default="mps")
|
| 274 |
+
ap.add_argument("--dtype", default="bfloat16", choices=["bfloat16", "float16", "float32"])
|
| 275 |
+
ap.add_argument("--attn-implementation", default="sdpa", choices=["sdpa", "eager"])
|
| 276 |
+
ap.add_argument("--limit-train-docs", type=int, default=0)
|
| 277 |
+
ap.add_argument("--priority-doc-ids", nargs="+", default=[],
|
| 278 |
+
help="doc_ids to oversample within the shared "
|
| 279 |
+
"multi-document head (--priority-oversample "
|
| 280 |
+
"extra passes per epoch), instead of raising "
|
| 281 |
+
"global head capacity -- raising rank/hidden_dim "
|
| 282 |
+
"fixes within-document fact interference but "
|
| 283 |
+
"makes the whole corpus overfit faster (see "
|
| 284 |
+
"runs/full2 diagnosis); oversampling gives "
|
| 285 |
+
"specific documents more gradient signal without "
|
| 286 |
+
"changing capacity or hurting the rest.")
|
| 287 |
+
ap.add_argument("--priority-oversample", type=int, default=5,
|
| 288 |
+
help="How many times to repeat each --priority-doc-ids "
|
| 289 |
+
"entry per epoch's shuffled training order.")
|
| 290 |
+
ap.add_argument("--only-doc-ids", nargs="+", default=[],
|
| 291 |
+
help="Restrict training (and, if present in this set, "
|
| 292 |
+
"ir_test eval) to exactly these doc_ids. Used for "
|
| 293 |
+
"single-document capacity diagnostics -- e.g. can "
|
| 294 |
+
"the architecture memorize ONE document's facts "
|
| 295 |
+
"when not sharing hypernetwork capacity across "
|
| 296 |
+
"165 others?")
|
| 297 |
+
ap.add_argument("--gradient-checkpointing", action="store_true", default=True)
|
| 298 |
+
ap.add_argument("--no-gradient-checkpointing", dest="gradient_checkpointing", action="store_false")
|
| 299 |
+
ap.add_argument("--max-hours", type=float, default=0.0,
|
| 300 |
+
help="Wall-clock training budget in hours. 0 = unlimited "
|
| 301 |
+
"(stop only after --epochs). Checked once per doc "
|
| 302 |
+
"iteration; when exceeded, saves a final checkpoint "
|
| 303 |
+
"and stops cleanly (does not just get killed mid-write).")
|
| 304 |
+
ap.add_argument("--min-available-gb", type=float, default=15.0,
|
| 305 |
+
help="Hard safety floor: stop (with a final "
|
| 306 |
+
"checkpoint) if SYSTEM-WIDE available memory "
|
| 307 |
+
"(psutil.virtual_memory().available -- NOT this "
|
| 308 |
+
"process's own RSS, which undercounts MPS "
|
| 309 |
+
"memory on Apple Silicon) drops below this many "
|
| 310 |
+
"GB. Checked every 2 iterations. 0 = disabled.")
|
| 311 |
+
ap.add_argument("--checkpoint-every-steps", type=int, default=50,
|
| 312 |
+
help="Overwrite head.latest.pt every N optimizer steps "
|
| 313 |
+
"so a crash/kill never loses more than N steps of "
|
| 314 |
+
"progress. Overwrites (doesn't accumulate files), "
|
| 315 |
+
"so it's disk-safe even for a 3GB head. 0=disabled.")
|
| 316 |
+
ap.add_argument("--checkpoint-every-minutes", type=float, default=30.0,
|
| 317 |
+
help="Save a timestamped checkpoint every N minutes of "
|
| 318 |
+
"wall-clock time, independent of eval/epoch "
|
| 319 |
+
"boundaries. 0 = disabled (epoch-end saves only).")
|
| 320 |
+
ap.add_argument("--epoch-ckpt-every", type=int, default=10,
|
| 321 |
+
help="Only write a NEW numbered head.epN.pt every N "
|
| 322 |
+
"epochs (head.latest.pt still updates every "
|
| 323 |
+
"epoch). Each checkpoint is a full head save "
|
| 324 |
+
"(hundreds of MB) -- with many small/fast epochs "
|
| 325 |
+
"(e.g. a tiny single-document run), saving one "
|
| 326 |
+
"per epoch can fill the disk in minutes.")
|
| 327 |
+
ap.add_argument("--resume-from", default="",
|
| 328 |
+
help="Path to a head.*.pt checkpoint to load weights "
|
| 329 |
+
"from before training starts (optimizer/scheduler "
|
| 330 |
+
"restart fresh; only head weights are resumed).")
|
| 331 |
+
args = ap.parse_args()
|
| 332 |
+
|
| 333 |
+
out_dir = Path(args.output_dir)
|
| 334 |
+
if not out_dir.is_absolute():
|
| 335 |
+
out_dir = RUNS_DIR / out_dir
|
| 336 |
+
out_dir.mkdir(parents=True, exist_ok=True)
|
| 337 |
+
ensure_dirs()
|
| 338 |
+
|
| 339 |
+
device = torch.device(args.device if (args.device != "mps" or torch.backends.mps.is_available()) else "cpu")
|
| 340 |
+
dtype = {"bfloat16": torch.bfloat16, "float16": torch.float16, "float32": torch.float32}[args.dtype]
|
| 341 |
+
random.seed(args.seed)
|
| 342 |
+
np.random.seed(args.seed)
|
| 343 |
+
torch.manual_seed(args.seed)
|
| 344 |
+
|
| 345 |
+
tb = SummaryWriter(log_dir=str(out_dir / "tb"))
|
| 346 |
+
|
| 347 |
+
# ---- Load embeddings + QnAs ----
|
| 348 |
+
print("Loading document embeddings ...", flush=True)
|
| 349 |
+
all_docs = load_doc_rows(Path(args.embeddings_path))
|
| 350 |
+
only_ids = set(args.only_doc_ids) if args.only_doc_ids else None
|
| 351 |
+
train_docs = [d for d in all_docs if d.split == "train"]
|
| 352 |
+
if only_ids:
|
| 353 |
+
train_docs = [d for d in train_docs if d.doc_id in only_ids]
|
| 354 |
+
if args.limit_train_docs:
|
| 355 |
+
train_docs = train_docs[: args.limit_train_docs]
|
| 356 |
+
print(f" {len(train_docs)} train docs (of {len(all_docs)} total)", flush=True)
|
| 357 |
+
|
| 358 |
+
print("Loading QnAs ...", flush=True)
|
| 359 |
+
all_qnas = load_qna_rows(Path(args.qna_path))
|
| 360 |
+
if only_ids:
|
| 361 |
+
all_qnas = [q for q in all_qnas if q.doc_id in only_ids]
|
| 362 |
+
train_qnas = [q for q in all_qnas if q.qna_split == "train"]
|
| 363 |
+
qnas_train = _group_qnas_by_doc(train_qnas)
|
| 364 |
+
docs_by_id = _docs_by_id(train_docs)
|
| 365 |
+
doc_ids = [d for d in docs_by_id if d in qnas_train]
|
| 366 |
+
print(f" {sum(len(v) for v in qnas_train.values())} train QA pairs across {len(doc_ids)} docs", flush=True)
|
| 367 |
+
|
| 368 |
+
if args.priority_doc_ids and args.priority_oversample > 1:
|
| 369 |
+
extra = []
|
| 370 |
+
for pid in args.priority_doc_ids:
|
| 371 |
+
if pid in doc_ids:
|
| 372 |
+
extra.extend([pid] * (args.priority_oversample - 1))
|
| 373 |
+
else:
|
| 374 |
+
print(f" [warn] --priority-doc-ids {pid!r} not in training set, skipping", flush=True)
|
| 375 |
+
doc_ids = doc_ids + extra
|
| 376 |
+
print(f" oversampled {args.priority_doc_ids} x{args.priority_oversample} "
|
| 377 |
+
f"-> {len(doc_ids)} entries/epoch", flush=True)
|
| 378 |
+
|
| 379 |
+
ds = DocDataset(docs_by_id, qnas_train, doc_ids,
|
| 380 |
+
max_qna_per_doc=args.max_qna_per_doc, seed=args.seed)
|
| 381 |
+
|
| 382 |
+
# ---- Build LLM, discover modules, wrap them ----
|
| 383 |
+
print(f"Loading {args.model_name} ...", flush=True)
|
| 384 |
+
tokenizer = AutoTokenizer.from_pretrained(args.model_name)
|
| 385 |
+
if tokenizer.pad_token is None:
|
| 386 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 387 |
+
base_model = AutoModelForImageTextToText.from_pretrained(
|
| 388 |
+
args.model_name, torch_dtype=dtype,
|
| 389 |
+
attn_implementation=args.attn_implementation,
|
| 390 |
+
).to(device)
|
| 391 |
+
base_model.eval()
|
| 392 |
+
for p in base_model.parameters():
|
| 393 |
+
p.requires_grad = False
|
| 394 |
+
if args.gradient_checkpointing:
|
| 395 |
+
base_model.config.use_cache = False
|
| 396 |
+
try:
|
| 397 |
+
base_model.gradient_checkpointing_enable(
|
| 398 |
+
gradient_checkpointing_kwargs={"use_reentrant": False})
|
| 399 |
+
print(" gradient checkpointing: ON", flush=True)
|
| 400 |
+
except Exception as e: # noqa: BLE001
|
| 401 |
+
print(f" [warn] gradient checkpointing unavailable: {e}", flush=True)
|
| 402 |
+
|
| 403 |
+
specs = get_module_specs(base_model, args.target_modules, root_prefix=args.root_prefix)
|
| 404 |
+
type_dims = discover_module_types_and_dims(specs)
|
| 405 |
+
print(f" discovered {len(specs)} target modules, {len(type_dims)} types: {sorted(type_dims)}", flush=True)
|
| 406 |
+
if not specs:
|
| 407 |
+
raise SystemExit(
|
| 408 |
+
f"No modules matched root_prefix={args.root_prefix!r} + "
|
| 409 |
+
f"{args.target_modules}. Inspect base_model.named_modules() and "
|
| 410 |
+
f"pass --root-prefix explicitly."
|
| 411 |
+
)
|
| 412 |
+
replace_with_lora(base_model, specs, rank=args.rank, alpha=args.alpha)
|
| 413 |
+
|
| 414 |
+
head = MemoryLoRAHead(
|
| 415 |
+
input_dim=train_docs[0].doc_embedding.shape[0],
|
| 416 |
+
type_dims=type_dims,
|
| 417 |
+
hidden_dim=args.head_hidden_dim,
|
| 418 |
+
rank=args.rank,
|
| 419 |
+
dropout=args.head_dropout,
|
| 420 |
+
).to(device)
|
| 421 |
+
if args.resume_from:
|
| 422 |
+
ckpt = torch.load(args.resume_from, map_location=device)
|
| 423 |
+
head.load_state_dict(ckpt["state_dict"])
|
| 424 |
+
print(f" resumed head weights from {args.resume_from}", flush=True)
|
| 425 |
+
n_head_params = sum(p.numel() for p in head.parameters())
|
| 426 |
+
print(f" head params: {n_head_params / 1e6:.1f}M", flush=True)
|
| 427 |
+
|
| 428 |
+
optim = torch.optim.AdamW(head.parameters(), lr=args.lr, weight_decay=args.weight_decay)
|
| 429 |
+
steps_per_epoch = max(1, len(ds))
|
| 430 |
+
if args.lr_total_steps:
|
| 431 |
+
# At real-corpus scale (tens of thousands of docs), --max-hours will
|
| 432 |
+
# cut training off long before steps_per_epoch * epochs is reached,
|
| 433 |
+
# so a schedule calibrated to full-epoch coverage would barely start
|
| 434 |
+
# annealing from its LR peak. Calibrate to the realistically
|
| 435 |
+
# achievable step count instead.
|
| 436 |
+
total_steps = args.lr_total_steps
|
| 437 |
+
else:
|
| 438 |
+
total_steps = steps_per_epoch * args.epochs
|
| 439 |
+
warmup_steps = max(1, int(total_steps * args.warmup_ratio))
|
| 440 |
+
sched = get_cosine_schedule_with_warmup(optim, warmup_steps, total_steps)
|
| 441 |
+
|
| 442 |
+
# ---- Eval suites ----
|
| 443 |
+
eval_suites: Dict[str, Dict[str, Any]] = {}
|
| 444 |
+
print("Loading eval suites ...", flush=True)
|
| 445 |
+
qnas_by_doc_all = _group_qnas_by_doc(all_qnas)
|
| 446 |
+
qnas_held_out_by_doc = _group_qnas_by_doc([q for q in all_qnas if q.qna_split == "held_out"])
|
| 447 |
+
eval_rng = random.Random(args.seed)
|
| 448 |
+
for suite in args.eval_suites:
|
| 449 |
+
if suite in ("cr_val", "cr_test"):
|
| 450 |
+
rows = [d for d in all_docs if d.split == suite]
|
| 451 |
+
q_by_doc = qnas_by_doc_all
|
| 452 |
+
elif suite == "ir_test":
|
| 453 |
+
rows = train_docs
|
| 454 |
+
q_by_doc = qnas_held_out_by_doc
|
| 455 |
+
else:
|
| 456 |
+
continue
|
| 457 |
+
if args.limit_eval_docs and len(rows) > args.limit_eval_docs:
|
| 458 |
+
rows = eval_rng.sample(rows, args.limit_eval_docs)
|
| 459 |
+
eval_suites[suite] = {"doc_rows": rows, "qnas_by_doc": q_by_doc}
|
| 460 |
+
n_q = sum(len(q_by_doc.get(d.doc_id, [])) for d in rows)
|
| 461 |
+
print(f" {suite}: {len(rows)} docs, {n_q} qnas", flush=True)
|
| 462 |
+
|
| 463 |
+
# ---- Train ----
|
| 464 |
+
metrics_log: List[Dict[str, Any]] = []
|
| 465 |
+
best_eval = float("inf")
|
| 466 |
+
global_step = 0
|
| 467 |
+
t0 = time.time()
|
| 468 |
+
last_ckpt_wall = t0
|
| 469 |
+
budget_seconds = args.max_hours * 3600.0 if args.max_hours > 0 else float("inf")
|
| 470 |
+
ckpt_interval_seconds = args.checkpoint_every_minutes * 60.0 if args.checkpoint_every_minutes > 0 else float("inf")
|
| 471 |
+
stop_training = False
|
| 472 |
+
patience_counter = 0
|
| 473 |
+
for epoch in range(args.epochs):
|
| 474 |
+
if stop_training:
|
| 475 |
+
break
|
| 476 |
+
order = list(range(len(ds)))
|
| 477 |
+
random.shuffle(order)
|
| 478 |
+
head.train()
|
| 479 |
+
running_loss, running_n = 0.0, 0
|
| 480 |
+
for it, di in enumerate(order):
|
| 481 |
+
now = time.time()
|
| 482 |
+
if now - t0 >= budget_seconds:
|
| 483 |
+
print(f" [budget] {args.max_hours:.2f}h training budget reached "
|
| 484 |
+
f"(epoch {epoch}, it {it}/{len(order)}) -- stopping.", flush=True)
|
| 485 |
+
stop_training = True
|
| 486 |
+
break
|
| 487 |
+
if now - last_ckpt_wall >= ckpt_interval_seconds:
|
| 488 |
+
mins = int((now - t0) / 60)
|
| 489 |
+
p = _save_ckpt(out_dir, head, type_dims, args, name=f"t{mins:04d}m")
|
| 490 |
+
_save_ckpt(out_dir, head, type_dims, args, name="latest")
|
| 491 |
+
print(f" [ckpt] periodic ({args.checkpoint_every_minutes:.0f}min interval) -> {p}", flush=True)
|
| 492 |
+
last_ckpt_wall = now
|
| 493 |
+
if args.min_available_gb > 0 and it % 2 == 0:
|
| 494 |
+
# IMPORTANT: this checks SYSTEM-WIDE available memory
|
| 495 |
+
# (psutil.virtual_memory), not this process's own RSS.
|
| 496 |
+
# psutil.Process().memory_info().rss -- like `ps -o rss` --
|
| 497 |
+
# does NOT reliably capture MPS/GPU-resident allocations
|
| 498 |
+
# on Apple Silicon: a run was observed at 55-83GB actual
|
| 499 |
+
# usage (per `top`'s MEM column, corroborated by system
|
| 500 |
+
# vm_stat showing genuine memory exhaustion) while RSS
|
| 501 |
+
# reported under 1GB the whole time. System-wide available
|
| 502 |
+
# memory is the metric that's actually reliable here.
|
| 503 |
+
available_gb = psutil.virtual_memory().available / 1e9
|
| 504 |
+
if available_gb < args.min_available_gb:
|
| 505 |
+
print(f" [safety] system available memory {available_gb:.1f}GB "
|
| 506 |
+
f"below --min-available-gb {args.min_available_gb:.1f}GB "
|
| 507 |
+
f"(epoch {epoch}, it {it}) -- saving and stopping to "
|
| 508 |
+
f"protect system stability.", flush=True)
|
| 509 |
+
_save_ckpt(out_dir, head, type_dims, args, name="latest")
|
| 510 |
+
stop_training = True
|
| 511 |
+
break
|
| 512 |
+
sample = ds[di]
|
| 513 |
+
if sample is None:
|
| 514 |
+
continue
|
| 515 |
+
ctx = torch.from_numpy(sample["embedding"]).to(device).unsqueeze(0)
|
| 516 |
+
qnas = sample["qnas"]
|
| 517 |
+
prefixes = [q["prefix"] for q in qnas]
|
| 518 |
+
targets = [q["target"] for q in qnas]
|
| 519 |
+
micro_batches = []
|
| 520 |
+
for i in range(0, len(prefixes), args.lm_micro_batch):
|
| 521 |
+
j = min(i + args.lm_micro_batch, len(prefixes))
|
| 522 |
+
b = _tokenize_lm_batch(tokenizer, prefixes[i:j], targets[i:j],
|
| 523 |
+
max_seq_len=args.max_seq_len, fixed_len=args.fixed_seq_len)
|
| 524 |
+
if b:
|
| 525 |
+
micro_batches.append({k: v.to(device) for k, v in b.items()})
|
| 526 |
+
if not micro_batches:
|
| 527 |
+
continue
|
| 528 |
+
n_tok_seen, loss_acc = 0, 0.0
|
| 529 |
+
for mb_idx, batch in enumerate(micro_batches):
|
| 530 |
+
if args.min_available_gb > 0 and mb_idx % 3 == 0:
|
| 531 |
+
# Same system-wide check as the per-document one below,
|
| 532 |
+
# but INSIDE the micro-batch loop too: observed runaway
|
| 533 |
+
# growth can blow past a safe threshold within a
|
| 534 |
+
# single document's micro-batches, before the
|
| 535 |
+
# per-document check would ever fire.
|
| 536 |
+
available_gb = psutil.virtual_memory().available / 1e9
|
| 537 |
+
if available_gb < args.min_available_gb:
|
| 538 |
+
print(f" [safety] system available memory {available_gb:.1f}GB "
|
| 539 |
+
f"below --min-available-gb {args.min_available_gb:.1f}GB "
|
| 540 |
+
f"mid-document (epoch {epoch}, it {it}, micro-batch "
|
| 541 |
+
f"{mb_idx}) -- saving and stopping immediately.", flush=True)
|
| 542 |
+
_save_ckpt(out_dir, head, type_dims, args, name="latest")
|
| 543 |
+
stop_training = True
|
| 544 |
+
break
|
| 545 |
+
head_out = head(ctx)
|
| 546 |
+
inject_lora_weights(base_model, specs, head_out, batch_index=0)
|
| 547 |
+
out = base_model(**batch)
|
| 548 |
+
ntok = (batch["labels"] != -100).sum().item()
|
| 549 |
+
loss = out.loss * ntok
|
| 550 |
+
loss.backward()
|
| 551 |
+
loss_acc += loss.detach().item()
|
| 552 |
+
n_tok_seen += ntok
|
| 553 |
+
del head_out, out, loss
|
| 554 |
+
if stop_training:
|
| 555 |
+
break
|
| 556 |
+
if n_tok_seen == 0:
|
| 557 |
+
continue
|
| 558 |
+
if device.type == "mps" and it % 5 == 0:
|
| 559 |
+
# MPS's caching allocator is markedly less aggressive about
|
| 560 |
+
# returning freed blocks to the OS than CUDA's -- on a
|
| 561 |
+
# unified-memory Mac (CPU and GPU share physical RAM,
|
| 562 |
+
# unlike a discrete-GPU box with isolated VRAM) that cache
|
| 563 |
+
# growth directly threatens the whole system, not just this
|
| 564 |
+
# process. Without this, a real-corpus run OOM'd the OS
|
| 565 |
+
# itself (83GB RSS, process state "stuck", heavy swapping)
|
| 566 |
+
# within the first ~10 minutes.
|
| 567 |
+
torch.mps.empty_cache()
|
| 568 |
+
|
| 569 |
+
torch.nn.utils.clip_grad_norm_(head.parameters(), args.max_grad_norm)
|
| 570 |
+
optim.step()
|
| 571 |
+
sched.step()
|
| 572 |
+
optim.zero_grad(set_to_none=True)
|
| 573 |
+
global_step += 1
|
| 574 |
+
|
| 575 |
+
if args.checkpoint_every_steps > 0 and global_step % args.checkpoint_every_steps == 0:
|
| 576 |
+
_save_ckpt(out_dir, head, type_dims, args, name="latest")
|
| 577 |
+
|
| 578 |
+
running_loss += loss_acc
|
| 579 |
+
running_n += n_tok_seen
|
| 580 |
+
if it % max(1, args.log_every_iters) == 0:
|
| 581 |
+
avg = running_loss / max(running_n, 1)
|
| 582 |
+
elapsed = (time.time() - t0) / 60
|
| 583 |
+
print(f"[ep{epoch} it{it}/{len(order)} step{global_step}] "
|
| 584 |
+
f"loss={avg:.4f} lr={sched.get_last_lr()[0]:.2e} elapsed={elapsed:.1f}m", flush=True)
|
| 585 |
+
tb.add_scalar("train/loss", avg, global_step)
|
| 586 |
+
tb.add_scalar("train/lr", sched.get_last_lr()[0], global_step)
|
| 587 |
+
running_loss, running_n = 0.0, 0
|
| 588 |
+
|
| 589 |
+
if (args.eval_every_steps > 0 and global_step > 0
|
| 590 |
+
and global_step % args.eval_every_steps == 0
|
| 591 |
+
and it + 1 != len(order)):
|
| 592 |
+
# The `it + 1 != len(order)` guard skips a redundant eval when
|
| 593 |
+
# eval_every_steps happens to equal (a multiple of) steps-per-
|
| 594 |
+
# epoch -- the unconditional end-of-epoch eval below would
|
| 595 |
+
# otherwise double-count this exact step in the early-stop
|
| 596 |
+
# patience counter every epoch.
|
| 597 |
+
prev_best = best_eval
|
| 598 |
+
best_eval = _do_eval(args, base_model, head, specs, tokenizer, eval_suites,
|
| 599 |
+
device, out_dir, metrics_log, best_eval, global_step, epoch, tb)
|
| 600 |
+
patience_counter = 0 if best_eval < prev_best else patience_counter + 1
|
| 601 |
+
if args.early_stop_patience > 0 and patience_counter >= args.early_stop_patience:
|
| 602 |
+
print(f" [early-stop] no improvement on {args.primary_eval_suite} for "
|
| 603 |
+
f"{patience_counter} evals -- stopping.", flush=True)
|
| 604 |
+
stop_training = True
|
| 605 |
+
break
|
| 606 |
+
|
| 607 |
+
_save_ckpt(out_dir, head, type_dims, args, name="latest")
|
| 608 |
+
if epoch % max(1, args.epoch_ckpt_every) == 0:
|
| 609 |
+
ep_path = _save_ckpt(out_dir, head, type_dims, args, name=f"ep{epoch}")
|
| 610 |
+
print(f" [ckpt] end-of-epoch ep{epoch} -> {ep_path}", flush=True)
|
| 611 |
+
else:
|
| 612 |
+
print(f" [ckpt] end-of-epoch ep{epoch} -> (latest.pt only)", flush=True)
|
| 613 |
+
prev_best = best_eval
|
| 614 |
+
best_eval = _do_eval(args, base_model, head, specs, tokenizer, eval_suites,
|
| 615 |
+
device, out_dir, metrics_log, best_eval, global_step, epoch, tb,
|
| 616 |
+
end_of_epoch=True)
|
| 617 |
+
patience_counter = 0 if best_eval < prev_best else patience_counter + 1
|
| 618 |
+
if args.early_stop_patience > 0 and patience_counter >= args.early_stop_patience:
|
| 619 |
+
print(f" [early-stop] no improvement on {args.primary_eval_suite} for "
|
| 620 |
+
f"{patience_counter} evals -- stopping.", flush=True)
|
| 621 |
+
stop_training = True
|
| 622 |
+
|
| 623 |
+
tb.close()
|
| 624 |
+
print(f"\nTraining done. Best primary eval = {best_eval:.4f}", flush=True)
|
| 625 |
+
|
| 626 |
+
|
| 627 |
+
def _save_ckpt(out_dir: Path, head: MemoryLoRAHead, type_dims, args, name: str = "latest") -> Path:
|
| 628 |
+
out = out_dir / f"head.{name}.pt"
|
| 629 |
+
torch.save({
|
| 630 |
+
"state_dict": head.state_dict(),
|
| 631 |
+
"config": head.config_dict(),
|
| 632 |
+
"type_dims": type_dims,
|
| 633 |
+
"args": vars(args),
|
| 634 |
+
}, out)
|
| 635 |
+
return out
|
| 636 |
+
|
| 637 |
+
|
| 638 |
+
def _do_eval(args, base_model, head, specs, tokenizer, eval_suites, device, out_dir,
|
| 639 |
+
metrics_log, best_eval, global_step, epoch, tb, end_of_epoch: bool = False) -> float:
|
| 640 |
+
suite_metrics: Dict[str, Dict[str, float]] = {}
|
| 641 |
+
for name, suite in eval_suites.items():
|
| 642 |
+
m = evaluate_suite(base_model, head, specs, tokenizer,
|
| 643 |
+
suite["doc_rows"], suite["qnas_by_doc"],
|
| 644 |
+
device=device, max_seq_len=args.max_seq_len,
|
| 645 |
+
lm_micro_batch=args.lm_micro_batch,
|
| 646 |
+
max_qna_per_doc=args.max_qna_per_doc,
|
| 647 |
+
fixed_len=args.fixed_seq_len)
|
| 648 |
+
suite_metrics[name] = m
|
| 649 |
+
print(f" [eval {name}] step={global_step} loss={m['eval_loss']:.4f} "
|
| 650 |
+
f"docs={m['n_docs']} tok={m['n_tokens']}", flush=True)
|
| 651 |
+
tb.add_scalar(f"eval/{name}_loss", m["eval_loss"], global_step)
|
| 652 |
+
primary = suite_metrics.get(args.primary_eval_suite)
|
| 653 |
+
primary_loss = primary["eval_loss"] if primary else float("inf")
|
| 654 |
+
row = {"step": global_step, "epoch": epoch, "end_of_epoch": end_of_epoch,
|
| 655 |
+
"eval_loss": primary_loss, "suites": suite_metrics}
|
| 656 |
+
metrics_log.append(row)
|
| 657 |
+
(out_dir / "metrics.jsonl").open("a").write(json.dumps(row) + "\n")
|
| 658 |
+
if primary_loss < best_eval:
|
| 659 |
+
best_eval = primary_loss
|
| 660 |
+
p = _save_ckpt(out_dir, head, head.type_dims, args, name="best")
|
| 661 |
+
print(f" [ckpt] best updated -> {p} (loss={primary_loss:.4f})", flush=True)
|
| 662 |
+
_save_ckpt(out_dir, head, head.type_dims, args, name="latest")
|
| 663 |
+
head.train()
|
| 664 |
+
return best_eval
|
| 665 |
+
|
| 666 |
+
|
| 667 |
+
if __name__ == "__main__":
|
| 668 |
+
main()
|