--- tags: - sentence-transformers - feature-extraction - code-search - code-embedding - retrieval - modernbert - dense base_model: Shuu12121/NightOwl-CodeEmbedding pipeline_tag: feature-extraction library_name: sentence-transformers license: apache-2.0 datasets: - Shuu12121/coir_hard_negative_datasets_v3_kd - Shuu12121/owl_code_search_hard_negative_datasets_V2_kd - Shuu12121/codeedit_hard_negative_datasets_kd - CoIR-Retrieval/apps - deepmind/code_contests --- # NightOwl-CodeEmbedding-v2 🦉 `NightOwl-CodeEmbedding-v2` is a compact, 768-dimensional dense embedding model built for code retrieval, code-edit retrieval, and technical question answering. It is an updated version of [`Shuu12121/NightOwl-CodeEmbedding`](https://huggingface.co/Shuu12121/NightOwl-CodeEmbedding) (v1). Compared with v1, it: * supports inputs of up to **4,096 tokens** (v1: 1,024), and * is much stronger on competitive-programming retrieval (**AppsRetrieval 0.392 → 0.518**) and long multi-turn queries (**CodeFeedbackMT 0.767 → 0.886**), while staying within about 0.01 of v1 on every other task (see [MTEB Results](#mteb-results)). The model uses CLS pooling with cosine similarity and does **not** require `query:` / `passage:` style prefixes. ## What changed from v1 1. **Longer context (1,024 → 4,096 tokens).** v1 was trained with a 1,024-token limit, but simply raising the limit to 4,096 — with no further training — improves long-input tasks without hurting any task (MTEB 2.5.1, 11 tasks): | Task | v1 @ 1,024 | v1 @ 4,096 | | ---------------------- | ---------: | ---------: | | CodeFeedbackMT | 0.7669 | 0.8870 | | CodeTransOceanContest | 0.7595 | 0.7919 | | CodeTransOceanDL | 0.3606 | 0.3747 | | AppsRetrieval | 0.3918 | 0.3999 | | Other 7 tasks | | +0.000 to +0.004 | | **Mean of 11 tasks** | **0.6987** | **0.7152** | About 66% of CodeFeedbackMT queries exceed 1,024 tokens, and the question to answer is usually in the last turn, which v1 truncated away. 2. **Additional fine-tuning + weight interpolation (WiSE-FT).** v1 was fine-tuned further on competitive-programming data plus a replay of its own training data (see [Training](#training)). The released weights are the **average of v1 and the fine-tuned weights (α = 0.5)**. The fully fine-tuned model reached a higher AppsRetrieval score (0.540) but lost 0.02–0.06 on several other tasks. Interpolating at α = 0.5 keeps most of the gain while removing almost all of the regressions. ## Highlights * Compact (150.8M parameters), 768-d single-vector embeddings: plain dot-product / cosine search that drops straight into any vector-database stack * **4,096-token context** * **0.7356 mean NDCG@10 on the 12 MTEB(Code, v1) tasks** (self-evaluated with MTEB 2.5.1; v1's leaderboard score is 0.7091) * Covers **eight programming languages**: the six CodeSearchNet languages plus Rust and TypeScript * Handles NL-to-code search, code-to-code retrieval, **code-edit retrieval**, and technical QA * Decontaminated against the benchmark test sets used for evaluation (see [Data Decontamination](#data-decontamination)) * Drop-in compatible with `sentence-transformers`; Apache-2.0 licensed ## Supported Languages * Go, Java, JavaScript, PHP, Python, Ruby (CodeSearchNet languages) * **Rust, TypeScript** (additional) Performance on languages outside this set is untested and may vary. ## Usage ```python from sentence_transformers import SentenceTransformer model = SentenceTransformer("Shuu12121/NightOwl-CodeEmbedding-v2") print(model.max_seq_length) # 4096 queries = ["Python function that sorts a list in descending order"] documents = [ "def sort_desc(values): return sorted(values, reverse=True)", "def average(values): return sum(values) / len(values)", ] query_embeddings = model.encode(queries) document_embeddings = model.encode(documents) # Cosine similarity (embeddings are normalized internally by similarity()) scores = model.similarity(query_embeddings, document_embeddings) print(scores) ``` If memory or latency matters more than long-input quality, you can lower the limit, e.g. `model.max_seq_length = 1024`. ## Model Details | Property | Value | | ----------------------- | --------------------------------------- | | Base model | `Shuu12121/NightOwl-CodeEmbedding` (v1) | | Backbone | `Shuu12121/NightOwl` | | Architecture | ModernBERT | | Parameters | 150,779,136 | | Embedding dimension | 768 | | Pooling | CLS pooling | | Maximum sequence length | 4,096 tokens | | Similarity | Cosine similarity | | Query/document prefixes | Not required | | Weight dtype | FP32 | | Weight memory | 575 MiB | | License | Apache-2.0 | ## MTEB Results Evaluation setup: * MTEB version: `2.5.1` * Metric: `NDCG@10` * Hardware: NVIDIA RTX PRO 6000 Blackwell * Batch size: 64 * `max_seq_length`: 4,096 (v2), 1,024 (v1, its released setting) Multi-subset task scores are reported as macro averages. v1 was re-evaluated with the same MTEB version, so the two columns are directly comparable. | Task | Split | v2 | v1 (1,024) | Diff | | -------------------------------- | ------: | -----: | ---------: | -----: | | AppsRetrieval | test | 0.5181 | 0.3918 | +0.1263 | | COIRCodeSearchNetRetrieval | test | 0.8381 | 0.8426² | – | | CodeEditSearchRetrieval | train¹ | 0.7480 | 0.7481 | −0.0001 | | CodeFeedbackMT | test | 0.8856 | 0.7669 | +0.1187 | | CodeFeedbackST | test | 0.8535 | 0.8526 | +0.0010 | | CodeSearchNetCCRetrieval | test | 0.9093 | 0.9182 | −0.0089 | | CodeSearchNetRetrieval | test | 0.8901 | 0.8924 | −0.0022 | | CodeTransOceanContest | test | 0.8038 | 0.7595 | +0.0443 | | CodeTransOceanDL | test | 0.3765 | 0.3606 | +0.0159 | | CosQA | test | 0.4333 | 0.4281 | +0.0051 | | StackOverflowQA | test | 0.8679 | 0.8661 | +0.0019 | | SyntheticText2SQL | test | 0.7030 | 0.7015 | +0.0015 | | **Mean, 11 tasks (excl. COIRCodeSearchNet)** | | **0.7263** | **0.6987** | **+0.0276** | | **Macro average, all 12 tasks** | | **0.7356** | – | | | **CoIR macro average, 10 tasks** | | **0.7189** | – | | ¹ `CodeEditSearchRetrieval` does not provide a standard `test` split in MTEB, so the official `train` split is used for evaluation. These examples were **not** used for fine-tuning. See [Data Decontamination](#data-decontamination). ² v1 was not re-evaluated on COIRCodeSearchNetRetrieval (about 1M documents). This value is from v1's model card (MTEB 2.15.1), so it is not strictly comparable. The CoIR macro average uses the same 10 tasks as v1's card (all 12 except CodeEditSearchRetrieval and CodeSearchNetRetrieval). ### Leaderboard v1 is listed on the [MTEB(Code, v1)](https://huggingface.co/spaces/mteb/leaderboard) leaderboard with a task mean of 70.91. v2's results above are self-evaluated and have not yet been submitted to the leaderboard. As with v1, MTEB(Code, v1) is largely **in-domain** for this model (8% zero-shot): it was trained on most of these task families, so its scores reflect in-domain retrieval rather than zero-shot transfer. Comparisons with models that are 100% zero-shot (e.g. `embeddinggemma-300m`, `Qwen3-Embedding`) are not apples-to-apples. ### Comparison with similar-sized models Leaderboard task means (×100) for compact dense single-vector models. v2's value is self-evaluated (MTEB 2.5.1) and is shown for reference. | Model | Params | Emb. dim | Max tokens | Zero-shot | MTEB(Code, v1) ↑ | | ---------------------------------------------------- | ------: | -------- | ---------: | --------: | ---------------: | | **`NightOwl-CodeEmbedding-v2`** (this model) | 150.8M | 768 | 4,096 | 8% | **73.56†** | | `NightOwl-CodeEmbedding` (v1) | 150.8M | 768 | 1,024 | 8% | 70.91 | | `codefuse-ai/F2LLM-v2-160M` | 159M | 640 | 40,960 | 58% | 70.38 | | `google/embeddinggemma-300m` | 308M | 768 | 2,048 | 100% | 68.76 | | `codefuse-ai/F2LLM-v2-80M` | 80M | 320 | 40,960 | 58% | 67.97 | | `ibm-granite/granite-embedding-311m-multilingual-r2` | 312M | 768 | 8,192 | 100% | 63.84 | | _Larger single-vector reference_ | | | | | | | `codefuse-ai/F2LLM-v2-0.6B` | 596M | 1,024 | 40,960 | 58% | 77.41 | | `Qwen/Qwen3-Embedding-0.6B` | 596M | 1,024 | 32,768 | 100% | 75.42 | † Self-evaluated with MTEB 2.5.1; not an official leaderboard entry. ## Training ### v1 v1 was fine-tuned from [`Shuu12121/NightOwl`](https://huggingface.co/Shuu12121/NightOwl) with `CachedMultipleNegativesRankingLoss` (bidirectional query-to-document and document-to-query) on 2,534,400 samples, each with one positive and 15 hard negatives mined by `Qwen/Qwen3-Embedding-0.6B` (1 epoch, learning rate 6e-5, batch size 1024, max sequence length 1,024). The data covers the CoIR task families of MTEB(Code, v1), custom code–comment pairs in eight languages, and code-edit data derived from `commitpackft`. See the [v1 model card](https://huggingface.co/Shuu12121/NightOwl-CodeEmbedding) for details. ### v2 Starting from v1, the model was fine-tuned on: 1. **Competitive programming (problem statement → Python solution):** APPS train and the CodeContests train split (up to 3 Python solutions per problem). 2. **Code translation (Python → C++):** one (Python, C++) solution pair per CodeContests problem, targeting CodeTransOceanContest. 3. **Replay of v1's training data** to limit forgetting: samples from `coir_hard_negative_datasets_v3_kd` (CodeFeedbackMT 4,000, CodeFeedbackST 3,000, StackOverflowQA 3,000, CosQA 1,000, SyntheticText2SQL 2,000, CodeTransOceanContest 561) and `codeedit_hard_negative_datasets_kd` (300 per language, 13 languages). For data 1 and 2, 7 hard negatives per example were mined with `Qwen/Qwen3-Embedding-0.6B`; solutions of the same problem (or of near-identical problems) were excluded from the negatives. Data 3 reuses the hard negatives already in the datasets. | Property | Value | | -------------------- | ------------------------------------------------------------ | | Loss | `CachedMultipleNegativesRankingLoss` (scale 100, bidirectional) | | Negatives per anchor | 7 | | Batching | one data source per batch (proportional sampling), no duplicates | | Epochs | 1 | | Learning rate | 2e-5 (cosine, 10% warmup) | | Batch size | 64 | | Max sequence length | 1,024 during training (4,096 at inference) | | Weight interpolation | 0.5 × v1 + 0.5 × fine-tuned | Interpolation results (MTEB 2.5.1, 11 tasks, `max_seq_length` 1,024): | α (share of fine-tuned weights) | 0 (v1) | 0.3 | **0.5** | 0.7 | 1 (fine-tuned) | | ------------------------------- | -----: | -----: | -------: | -----: | -------------: | | AppsRetrieval | 0.3918 | 0.4692 | 0.5066 | 0.5285 | 0.5404 | | Mean of 11 tasks | 0.6987 | 0.7081 | **0.7103** | 0.7076 | 0.6949 | ## Data Decontamination Overlaps with the evaluation data were removed **before** training. v1: * Custom code–comment pair data vs. the **CodeSearchNet test split** * `commitpackft`-derived code-edit data vs. the **CodeEditSearchRetrieval** evaluation data v2 (additional data): * APPS train problems whose statement has cosine similarity ≥ 0.95 to an **APPS test** problem * CodeContests problems that are the same Codeforces problem as an **APPS test** problem, and problems whose statement has cosine similarity ≥ 0.90 to any APPS test or APPS train problem * Python → C++ pairs whose Python or C++ code has cosine similarity ≥ 0.95 to a **CodeTransOceanContest test** query or its answer Similarities were computed with v1. The replay data is a subset of v1's training data, so it adds no new overlap. For `CodeEditSearchRetrieval`, note that MTEB labels the evaluation split `train`. This is just the official split name for the task; the evaluated examples were not included in this model's fine-tuning data. The score should therefore be read as **in-domain generalization on held-out benchmark examples**. ## Base Model: the NightOwl Backbone The backbone, [`Shuu12121/NightOwl`](https://huggingface.co/Shuu12121/NightOwl), is a ModernBERT-style code encoder **pre-trained from scratch**, tokenizer included. * **Code-aware tokenizer:** a custom 50,368-token BPE tokenizer in which whitespace is tokenized independently of adjacent words, so indentation gets its own tokens and the vocabulary is not wasted on "indent + word" variants. * **Two-phase pre-training** with masked-language modeling (`mlm_probability = 0.3`): standard random-token MLM over code, natural language, and documentation (Phase 1), then **line-level MLM** on code only, masking whole source lines (Phase 2). | Property | Value | | ------------------------------ | ----------------------------------------------------- | | Architecture | ModernBERT (alternating local/global attention, RoPE) | | Parameters | ≈150M | | `hidden_size` / layers / heads | 768 / 19 / 12 | | Vocabulary | 50,368 (custom code BPE) | | Max sequence length | 1,024 (Phase 1) → 2,048 (Phase 2) | See the [v1 model card](https://huggingface.co/Shuu12121/NightOwl-CodeEmbedding) for the pre-training data and the backbone comparison. ## Intended Use * Natural language to code search * Code-to-code retrieval and similar-function search * Code-edit retrieval (matching edit intents to code changes) * Retrieval over programming Q&A, long multi-turn technical conversations, and competitive-programming problems * Local semantic code search systems * RAG systems over codebases and developer documentation ## Limitations * Specialized for code-related retrieval; may underperform general-purpose text embedding models on unrelated natural-language tasks. * Inputs longer than 4,096 tokens are truncated. The model was trained on inputs of at most 1,024 tokens and the backbone was pre-trained on at most 2,048; the 4,096 setting is supported by the evaluation results above, but quality on very long inputs is less tested than on short ones. * Slightly lower than v1 on CodeSearchNetCCRetrieval (−0.009) and CodeSearchNetRetrieval (−0.002). * MTEB(Code, v1) is largely in-domain for this model (8% zero-shot). On code domains, query styles, or languages far from the training distribution, expect lower performance than the benchmark numbers suggest. * The model produces dense single-vector embeddings. For very fine-grained token-level matching, late-interaction models or cross-encoder rerankers may be worth considering. ## Recommended Indexing Settings Encode both queries and documents with normalized embeddings: ```python embeddings = model.encode(texts, normalize_embeddings=True) ``` With normalized embeddings, dot product is equivalent to cosine similarity. For codebase search, indexing function-level or class-level chunks usually works best. ## Citation If you use this model, please cite it together with the base model and Sentence Transformers. ```bibtex @misc{nightowl_codeembedding_v2, title = {NightOwl-CodeEmbedding-v2}, author = {Shuu12121}, year = {2026}, publisher = {Hugging Face}, url = {https://huggingface.co/Shuu12121/NightOwl-CodeEmbedding-v2} } ```