--- tags: - sentence-transformers - feature-extraction - code-search - code-embedding - retrieval - modernbert - dense base_model: Shuu12121/NightOwl-35M 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 --- # NightOwl-CodeEmbedding-35M 🦉 `NightOwl-CodeEmbedding-35M` は、コード検索・コード編集検索・技術QA向けに構築された **384次元・34Mパラメータ**の超小型 dense 埋め込みモデルです。 [`Shuu12121/NightOwl-35M`](https://huggingface.co/Shuu12121/NightOwl-35M)(ModernBERT ベースのコードエンコーダ)からファインチューニングしています。CLS プーリング + コサイン類似度を使用し、`query:` / `passage:` のようなプレフィックスは**不要**です。 [`NightOwl-CodeEmbedding`](https://huggingface.co/Shuu12121/NightOwl-CodeEmbedding)(150.8M)と**同じ学習手法・同じデータ**で構築した軽量版です。CPU 推論、オンデバイス検索、数百万チャンク規模のインデックス構築など、150M 版では重すぎる環境を想定しています。 ## Highlights * **34.1M パラメータ / 384次元** — 150.8M 版の 4.4分の1 のサイズ、インデックスサイズは半分 * MTEB(Code, v1) の 12タスク macro average で **65.56**、150.8M 版(70.91)の **約92%** の性能を保持 * 出力次元が 384 なので、1M チャンクのインデックスが FP32 で約 1.5 GiB(768次元なら約 2.9 GiB) * 標準的な single-vector 検索:1文書1ベクトル + 内積/コサイン検索なので、既存のベクトル DB にそのまま載る * **8言語対応**:CodeSearchNet の6言語に Rust と TypeScript を追加 * NL→コード検索、コード→コード検索、**コード編集検索**、技術QA をカバー * ハードネガティブは `Qwen/Qwen3-Embedding-0.6B` でマイニング(anchor あたり15件) * CodeSearchNet test split と CodeEditSearchRetrieval ベンチマークに対して除染済み([Data Decontamination](#data-decontamination) 参照) ## 対応言語 * Go, Java, JavaScript, PHP, Python, Ruby(CodeSearchNet 言語) * **Rust, TypeScript**(追加) これ以外の言語での性能は未検証です。 ## Usage ```python from sentence_transformers import SentenceTransformer model = SentenceTransformer("Shuu12121/NightOwl-CodeEmbedding-35M") 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) scores = model.similarity(query_embeddings, document_embeddings) print(scores) ``` ## Model Details | 項目 | 値 | | --- | --- | | ベースモデル | `Shuu12121/NightOwl-35M` | | アーキテクチャ | ModernBERT | | パラメータ数 | 34,094,976 | | 埋め込み次元 | 384 | | プーリング | CLS pooling | | 最大系列長 | 1,024 tokens | | 類似度 | コサイン類似度 | | クエリ/文書プレフィックス | 不要 | | 重み dtype | FP32 | | 重みメモリ | 130 MiB | | ライセンス | Apache-2.0 | ### 150.8M 版との構成比較 | | **35M(本モデル)** | NightOwl-CodeEmbedding | | --- | ---: | ---: | | パラメータ数 | 34,094,976 | 150,779,136 | | `hidden_size` / layers / heads | 384 / 10 / 6 | 768 / 19 / 12 | | 埋め込み次元 | 384 | 768 | | 語彙 | 50,368(共通 code BPE) | 50,368(共通 code BPE) | | 重みメモリ (FP32) | 130 MiB | 575 MiB | | 1M ベクトルのインデックス (FP32) | ≈1.46 GiB | ≈2.93 GiB | パラメータの内訳では、トークン埋め込み(50,368 × 384 ≈ 19.3M)が全体の **約57%** を占めます。語彙をファミリー内で共有しているため、この規模では埋め込み行列が支配的です。非埋め込みパラメータは約 14.8M。 ## MTEB Results コード関連の検索・技術QAタスクを MTEB で評価しました。 複数サブセットを持つタスクは macro average で報告しています。 | Task | Split | NDCG@10 | | --- | ---: | ---: | | AppsRetrieval | test | 0.27650 | | COIRCodeSearchNetRetrieval | test | 0.78940 | | CodeEditSearchRetrieval | train¹ | 0.68028 | | CodeFeedbackMT | test | 0.68310 | | CodeFeedbackST | test | 0.77990 | | CodeSearchNetCCRetrieval | test | 0.87225 | | CodeSearchNetRetrieval | test | 0.86228 | | CodeTransOceanContest | test | 0.72880 | | CodeTransOceanDL | test | 0.35020 | | CosQA | test | 0.39480 | | StackOverflowQA | test | 0.81140 | | SyntheticText2SQL | test | 0.63750 | | **Macro average, all 12 tasks** | | **0.65555** | | **CoIR macro average, 10 tasks** | | **0.63239** | ¹ `CodeEditSearchRetrieval` には MTEB 上に標準の `test` split がないため、公式の `train` split で評価しています。これらの事例はファインチューニングに**使用していません**。[Data Decontamination](#data-decontamination) を参照。 ### 言語別スコア **CodeSearchNetRetrieval** | Go | Java | JS | PHP | Python | Ruby | Avg | | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 0.9500 | 0.8802 | 0.7718 | 0.8676 | 0.8926 | 0.8120 | 0.8624 | **CodeSearchNetCCRetrieval** | Go | Java | JS | PHP | Python | Ruby | Avg | | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 0.8922 | 0.8846 | 0.9010 | 0.8337 | 0.8557 | 0.8663 | 0.8723 | **COIRCodeSearchNetRetrieval** | Go | Java | JS | PHP | Python | Ruby | Avg | | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 0.8590 | 0.7654 | 0.6780 | 0.7878 | 0.9657 | 0.6805 | 0.7894 | **CodeEditSearchRetrieval**(13言語) | C | C++ | Go | Java | JS | PHP | Python | Ruby | Rust | Scala | Shell | Swift | TS | Avg | | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 0.6000 | 0.6515 | 0.7125 | 0.6865 | 0.6910 | 0.6670 | 0.7169 | 0.7201 | 0.6348 | 0.6971 | 0.6502 | 0.6852 | 0.7309 | 0.6803 | このタスクには学習対象外の C, C++, Scala, Shell, Swift が含まれます。これらのスコア(0.60–0.70)は、対応8言語(0.63–0.73)より低いものの大きくは崩れておらず、コード編集検索という形式自体はある程度言語横断で転移していることを示唆します。とはいえ最低スコアは C(0.6000)で、対応言語外での性能低下は実在します。 ### 150.8M 版との比較 同一手法・同一データで学習した 150.8M 版との差分です。 | Task | **35M** | 150.8M | Δ | | --- | ---: | ---: | ---: | | AppsRetrieval | 0.2765 | 0.3918 | −0.1153 | | COIRCodeSearchNetRetrieval | 0.7894 | 0.8426 | −0.0532 | | CodeEditSearchRetrieval | 0.6803 | 0.7481 | −0.0678 | | CodeFeedbackMT | 0.6831 | 0.7669 | −0.0838 | | CodeFeedbackST | 0.7799 | 0.8521 | −0.0722 | | CodeSearchNetCCRetrieval | 0.8723 | 0.9181 | −0.0458 | | CodeSearchNetRetrieval | 0.8624 | 0.8924 | −0.0300 | | CodeTransOceanContest | 0.7288 | 0.7595 | −0.0307 | | CodeTransOceanDL | 0.3502 | 0.3606 | −0.0104 | | CosQA | 0.3948 | 0.4281 | −0.0333 | | StackOverflowQA | 0.8114 | 0.8661 | −0.0547 | | SyntheticText2SQL | 0.6375 | 0.6827 | −0.0452 | | **Macro average** | **0.6556** | **0.7091** | **−0.0535** | 読み取れること: * パラメータを **4.4分の1** に削減して、macro average の低下は **5.4ポイント**(相対で約7.5%)。 * **劣化が小さいタスク**は CodeSearchNet 系(−0.03〜−0.05)と CodeTransOcean 系(−0.01〜−0.03)。関数レベルのコード検索・コード間検索は 34M でもかなり保持されます。 * **劣化が大きいタスク**は AppsRetrieval(−0.115)と CodeFeedbackMT(−0.084)。長く複雑な自然言語の問題記述や、マルチターン文脈の理解は容量の影響を受けやすいと見られます。**長い NL クエリが主用途なら 150.8M 版を推奨します。** * CodeTransOceanDL は両モデルとも 0.35–0.36 と低く、モデルサイズによらず苦手なタスクです。 > ⚠️ **注意:** 150.8M 版の数値は公開済みモデルカードのもので、本モデルとは**別の評価ランで測定されています**。厳密な比較のためには両モデルを同一の MTEB バージョン・同一ハードウェアで再評価してください。 ### 他の小型モデルとの比較 MTEB(Code, v1) の task mean(macro average ×100)での比較です。*Zero-shot* 列は、そのモデルが学習に使っていないタスクの割合です。 | Model | Params | Emb. dim | Max tokens | Zero-shot | MTEB(Code, v1) ↑ | | --- | ---: | --- | ---: | ---: | ---: | | **`NightOwl-CodeEmbedding-35M`**(本モデル) | **34.1M** | 384 | 1,024 | 8% | **65.56** | | `NightOwl-CodeEmbedding` | 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 | ## ベースモデル: NightOwl-35M バックボーン `NightOwl-CodeEmbedding-35M` は [`Shuu12121/NightOwl-35M`](https://huggingface.co/Shuu12121/NightOwl-35M) からファインチューニングしています。これは汎用チェックポイントからの転用ではなく、**トークナイザを含めて一から事前学習した** ModernBERT 系コードエンコーダです。 **コードを意識したトークナイザ.** NightOwl ファミリーは 50,368語彙のカスタム BPE を共有し、空白を隣接する単語と**独立に**トークン化します。これによりインデント自体が固有のトークンを持ち、「先頭空白 + 単語」の結合片にはなりません。コードでは同じ識別子が様々なインデント深度で繰り返し出現するため、空白を結合すると語彙の大部分が「インデント + トークン」のほぼ重複した変種に浪費されます。空白を分離しておくことで、固定の語彙枠でより多くの実質的に異なるサブワードをカバーでき、同時にインデントも忠実に表現できます — Python のような空白が意味を持つ言語で効いてきます。 **行単位マスキングによる2フェーズ事前学習.** `mlm_probability = 0.3` のマスク言語モデリングを2フェーズで実施します。 * *Phase 1 — 混合事前学習:* コード・自然言語・技術ドキュメントに対する通常のランダムトークン MLM(`NightOwl-35M-Pre` を生成) * *Phase 2 — コード限定の継続学習:* **行単位 MLM**。ランダムトークンではなくソースコードの行全体をマスクします。コード検索において意味の単位が孤立したトークンより行や文に近いことを踏まえ、事前学習の目的関数を下流タスクに揃えます。推奨チェックポイント `NightOwl-35M` はこの Phase 2 の結果です。 バックボーンのアーキテクチャ: | 項目 | 値 | | --- | --- | | アーキテクチャ | ModernBERT(local/global 交互アテンション、RoPE) | | パラメータ数 | ≈34M | | `hidden_size` / layers / heads | 384 / 10 / 6 | | `intermediate_size` | 768 | | `global_attn_every_n_layers` | 3(10層中4層が global) | | `local_attention_window` | 128 | | 語彙 | 50,368(カスタム code BPE、ファミリー共通) | | 事前学習時の最大系列長 | 1,024 (Phase 1) → 2,048 (Phase 2) | 事前学習データは `bigcode/starcoder2data-extras`(Kaggle ノートブック、StackOverflow スレッド、GitHub issue、技術ドキュメント等)と、対応8言語のファイル単位ソースコード `Shuu12121/github-file-programs-dataset` の混合です。長い事例はチャンク分割し、打ち切らずに全トークンを使用します。 ## Training `CachedMultipleNegativesRankingLoss` により、query→document / document→query の双方向目的関数で学習しました。 | 項目 | 値 | | --- | --- | | anchor あたりの positive | 1 | | anchor あたりの negative | 15 | | Loss | `CachedMultipleNegativesRankingLoss` | | 目的関数 | 双方向検索学習 | | ハードネガティブのマイニングモデル | `Qwen/Qwen3-Embedding-0.6B` | | Epochs | 1 | | Learning rate | 6e-5 | | Batch size | 256 | ### Training Data 150.8M 版と同一のデータを使用しています。 1. **公開コード検索データセット**(CoIR タスクファミリー): AppsRetrieval, COIRCodeSearchNetRetrieval, CodeFeedbackMT, CodeFeedbackST, CodeSearchNetCCRetrieval, CodeSearchNetRetrieval, CodeTransOceanContest, CodeTransOceanDL, CosQA, StackOverflowQA, SyntheticText2SQL 2. **独自のコード–コメントペアデータ**: 対応8言語における、コードスニペットと自然言語の説明コメントのペア 3. **コード編集データ**: `commitpackft` 由来。編集意図とコード変更を対応付けたもの すべてハードネガティブ検索データセットとして構築されており、各 anchor に対して positive 1件・ハードネガティブ15件を持ちます。ハードネガティブは [`Qwen/Qwen3-Embedding-0.6B`](https://huggingface.co/Qwen/Qwen3-Embedding-0.6B) でマイニングしました。意味的には近いが一致しない候補を取ってくるため、ランダムネガティブよりはるかに難しくなります。マイニングモデルはデータセット構築時にのみ使用し、推論時には不要です。 ### Data Decontamination ベンチマーク汚染を減らすため、学習**前**に以下の重複を除去しています。 * 独自コード–コメントペアデータと **CodeSearchNet test split** の重複 * `commitpackft` 由来のコード編集データと **CodeEditSearchRetrieval** ベンチマーク評価データの重複 `CodeEditSearchRetrieval` について、MTEB は評価 split を `train` とラベル付けしていますが、これは単に公式の split 名であり、評価対象の事例は本モデルのファインチューニングデータに含まれていません。したがって報告スコアは **held-out なベンチマーク事例に対する in-domain 汎化性能**として読むべきです(学習セット上の性能ではないが、学習分布が in-domain である以上、厳密な zero-shot 性能でもありません)。 ## Intended Use * 自然言語からのコード検索 * コード→コード検索、類似関数検索 * コード編集検索(編集意図とコード変更のマッチング) * プログラミング Q&A・技術的質問に対する検索 * ローカルのセマンティックコード検索システム * コードベース・開発者向けドキュメントに対する RAG **特に 35M 版が向く場面:** * CPU のみの環境、またはエッジ/オンデバイス検索 * 数百万〜数千万チャンク規模のインデックス構築(埋め込み計算とインデックスサイズの両方が半分以下) * 本モデルで一次検索し、150.8M 版やクロスエンコーダで再ランクする二段構成 ## Limitations * コード関連検索に特化しており、無関係な自然言語タスクでは汎用テキスト埋め込みモデルに劣る可能性があります。 * **モデルサイズに起因する性能低下**: 150.8M 版に対して macro average で 5.4ポイント低く、特に長い自然言語クエリ(AppsRetrieval で −0.115)とマルチターン文脈(CodeFeedbackMT で −0.084)で差が大きくなります。精度が最優先なら 150.8M 版を使ってください。 * 1,024トークンを超える入力は切り捨てられます。競合(8K以上の `F2LLM` や `granite` 系)より短い文脈長なので、長いファイルは分割が必要です。 * MTEB(Code, v1) は本モデルにとって大部分が in-domain です(8% zero-shot)。学習分布から遠いコード領域・クエリ形式・言語では、リーダーボードの数値より低い性能を想定してください。 * 性能はプログラミング言語、クエリ形式、インデックスするコードチャンクの粒度によって変動します。対応8言語以外は未検証です。 * dense single-vector 埋め込みを出力します。極めて細粒度のトークンレベルマッチングが必要な用途では、late-interaction(マルチベクトル)モデルやクロスエンコーダによる再ランクなど、インデックスサイズと検索インフラのトレードオフが異なる手法の検討を推奨します。 ## Citation ```bibtex @misc{nightowl_codeembedding_35m, title = {NightOwl-CodeEmbedding-35M}, author = {Shuu12121}, year = {2026}, publisher = {Hugging Face}, url = {https://huggingface.co/Shuu12121/NightOwl-CodeEmbedding-35M} } ```