Instructions to use FronyAI/frony-embed-medium-arctic-ko-v2.5 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- sentence-transformers
How to use FronyAI/frony-embed-medium-arctic-ko-v2.5 with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("FronyAI/frony-embed-medium-arctic-ko-v2.5") sentences = [ "The weather is lovely today.", "It's so sunny outside!", "He drove to the stadium." ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [3, 3] - Notebooks
- Google Colab
- Kaggle
Frony Embed Arctic V2.5 (medium)
A Korean-first text embedding model for retrieval, built on Snowflake/snowflake-arctic-embed-l-v2.0.
What it's for. Single-stage retrieval where the top-1 hit matters — RAG pipelines that feed one or two passages directly to an LLM, FAQ matching, semantic search over Korean documents. It handles Korean↔English cross-lingual retrieval and was explicitly tuned for Markdown-formatted passages, which is how most modern RAG chunks actually look.
At a glance
| Base model | Snowflake/snowflake-arctic-embed-l-v2.0 |
| Architecture | Bi-encoder, single-vector dense retrieval (mean pooling) |
| Dimensions | 1024, or 512 via Matryoshka truncation (both directly trained) |
| Max sequence length | 8192 tokens (512 recommended — see note below) |
| Similarity | Cosine (outputs are L2-normalized) |
| Languages | Korean, English (ko→ko, ko→en, en→ko) |
| Training data | about 500K query–passage pairs |
| Training | 3 stages — multi-vector → self-distillation → hard negatives |
| Training hardware | Single GPU, 46GB VRAM |
| License | Apache-2.0 (see License and attribution) |
Note on sequence length. The base model accepts up to 8192 tokens, but training and evaluation were done at shorter lengths. Quality is only guaranteed up to 512 tokens. Chunk accordingly.
Usage
pip install -U sentence-transformers
The model distinguishes queries from passages using the special tokens <Q> and
<P>. These are required — retrieval quality degrades noticeably without
them. They are registered as prompts in the published model, so prompt_name
adds them for you.
import torch.nn.functional as F
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("FronyAI/frony-embed-medium-arctic-ko-v2.5")
queries = ["대한민국의 수도는 어디입니까?"]
passages = ["서울은 대한민국의 수도이다.", "부산은 대한민국 제2의 도시이다."]
q = model.encode(queries, prompt_name="query", convert_to_tensor=True)
p = model.encode(passages, prompt_name="passage", convert_to_tensor=True)
# Outputs are L2-normalized already, so cosine similarity is a plain dot product.
scores = q @ p.T # [1, 2]
# 512 dimensions (Matryoshka): slice the first 512, then re-normalize.
# Truncating a unit vector leaves it shorter than unit length, and skipping the
# second normalization distorts every score that follows. Truncate queries and
# passages to the same width — mixing widths produces meaningless scores.
q512 = F.normalize(q[:, :512], p=2, dim=-1)
p512 = F.normalize(p[:, :512], p=2, dim=-1)
scores_512 = q512 @ p512.T # [1, 2]
# Outside sentence-transformers, write the tokens inline instead:
# "<Q>대한민국의 수도는 어디입니까?"
# "<P>서울은 대한민국의 수도이다."
512 is the only supported truncation. Stage 3 trains the full 1024-dimension output and the 512-dimension prefix jointly, with equal weight. Narrower widths such as 256 or 128 were never part of the training objective and are not expected to hold up.
Training
Training runs in three sequential stages, each initialized from the previous stage's checkpoint:
The reasoning behind the order: preliminary experiments showed multi-vector (late-interaction) retrieval consistently outperforming dense retrieval on our data. Rather than ship a multi-vector model — which costs far more at index and query time — we train that objective first, then transfer what it learned into a single-vector representation, and finally sharpen the result against hard negatives.
Shared setup
Common across all three stages:
| Pooling | Mean pooling over tokens, attention-mask weighted |
| Max sequence length | 512 |
| Temperature | 0.02 |
| Loss | InfoNCE (cross-entropy over similarity scores) |
| Optimizer | 8-bit AdamW (bitsandbytes) |
| Schedule | Polynomial decay, power=1.0 |
| Weight decay | 1e-3, excluding biases and LayerNorm |
| Precision | fp16 |
| Gradient accumulation | 4 |
| Gradient clipping | 1.0 |
| Framework | PyTorch Lightning |
| Model selection | Early stopping on validation loss |
The validation set is held fixed across all three stages, so loss curves are directly comparable from one stage to the next.
Query and passage tokens. <Q> and <P> are added to the vocabulary as genuine special tokens in Stage 1, with the embedding matrix resized accordingly, and their embeddings are trained through all three stages. They are not string prefixes in the manner of "query: " — they are single learned tokens, which is why they cost one token rather than several and why omitting them degrades retrieval noticeably.
Stage1: Align — Multi-vector training
What it's for. Learn token-level interaction before anything is compressed into a single vector.
Preliminary experiments on our data showed multi-vector (late-interaction) retrieval consistently beating dense retrieval. Shipping a multi-vector model would multiply index and query cost, so we train that objective first and transfer it into a single vector later. This stage exists to produce something worth transferring.
Scoring. ColBERT-style MaxSim over the full token sequence, no pooling applied: each query token takes its best-matching passage token, and those maxima are averaged across the query. Training is InfoNCE over these scores with in-batch negatives.
Vocabulary change. <Q> and <P> are added here as genuine special
tokens, with the embedding matrix resized accordingly, and their embeddings
train through all three stages.
Cumulative batching. Multi-vector scoring materializes a token-by-token similarity matrix for every pair, which makes large batches expensive — and batch size is exactly what determines how many in-batch negatives the contrastive loss sees. Rather than paying for a larger batch, each step maintains a FIFO queue of the four most recent passage batches and scores the current query batch against all of them, giving a negative pool of 32 passages from a batch of 8. The queued passages are re-encoded at every step rather than cached, so gradients flow through all 32 — a memory-for-compute trade, not a memory bank in the MoCo sense (He et al., 2020, arXiv:1911.05722), since the negatives stay current with respect to the model's parameters.
Note that two numbers here collide by coincidence: batch size 8 with gradient accumulation 4 gives an effective batch of 32, and the negative pool is also 32. Gradient accumulation is the ordinary kind and only affects how often the optimizer steps, while cumulative batching only affects how many passages each query is scored against. This scheme was also arrived at independently while working around memory limits — gradient caching (Gao et al., 2021, arXiv:2101.06983) solves the same problem more efficiently by caching gradients with respect to the embeddings and replaying the encoder in sub-batches, which decouples pool size from activation memory and is the most direct way to widen the pool in a future version.
Configuration
| Initialized from | snowflake-arctic-embed-l-v2.0 |
| Batch size | 8 |
| Negative pool | 32 passages (8 × 4 queued batches) |
| Learning rate | 1e-5 → 1e-6 |
| Warmup | 5% of total steps |
| Early stopping patience | 5 |
| Validation interval | every 10% of an epoch |
Stage2: Distill — Dense transfer via self-distillation
What it's for. Move what Stage 1 learned into the pooled single-vector representation — the one the released model actually uses at inference.
What changed. Batching, learning rate, and negative pool all carry over unchanged from Stage 1. What changes is the objective: the pooled vector becomes the thing being trained, and the token-level scoring shifts from being the training target to being the teacher.
Start with what went wrong. The first version of this stage optimized dense objectives alone. The token loss held for a while, then began climbing partway through training — the multi-vector ability acquired in Stage 1 was decaying under dense-only optimization. That matters more than it first appears, because the distillation targets are produced by that same token-level scoring: degrading it degrades the signal being distilled. The fix was a small hard-label loss on the token vectors, weighted 0.10, whose only job is to anchor the representation the distillation depends on.
This is also why the pipeline has three stages rather than two. Stage 1's contribution has to be actively maintained during Stage 2, not merely inherited from it.
How the two representations work. No separate teacher model is involved. A single forward pass produces one set of hidden states, and two representations are read off it — the dense vector, produced by mean pooling and scored by dot product, and the token vectors, left unpooled and scored by the same MaxSim as Stage 1. Both come from the same encoder in the same step, so the model teaches itself.
Three terms combine as a weighted sum, with effective weights dense 0.81, distillation 0.09, token 0.10. The distillation term supplies the dense vector with soft targets drawn from the token vectors' score distribution, so the dense representation is pulled toward the ranking that multi-vector scoring produces rather than only toward the correct answer. Both representations receive gradient from that term, which makes it a consistency constraint between the two rather than one-way transfer from a frozen teacher.
Configuration
| Initialized from | Stage 1 checkpoint |
| Batch size | 8 |
| Negative pool | 32 passages (8 × 4 queued batches) |
| Learning rate | 1e-5 → 1e-6 |
| Warmup | 5% of total steps |
| Early stopping patience | 5 |
| Validation interval | every 10% of an epoch |
Stage3: Refine — Hard-negative fine-tuning
What it's for. Sharpen discrimination at the top of the ranking, and make the 512-dimension truncation a first-class output rather than an afterthought.
What changed — most of it. This is the sharpest break in the pipeline. Cumulative batching is dropped and in-batch negatives are removed entirely. The learning rate picks up where Stage 2 ends and drops an order of magnitude below it, and warmup is omitted because the model arrives already converged. Validation runs twice as often as in earlier stages, and unlike Stages 1 and 2 the released weights come from the best checkpoint rather than the last.
The training signal changes character along with it. Each query is scored against exactly its own positive and its own four mined hard negatives — a five-way softmax per query, with no easy negatives in the mix. Every gradient step is spent on distinctions the model is likely to get wrong, which is what produces this model's characteristic profile: strong Accuracy@1, at some cost to recall further down the ranking.
Matryoshka objective. The same loss is computed twice, once on the full 1024 dimensions and once on the first 512, and the two are averaged with equal weight. This covers two widths only — not the geometric ladder (768/512/256/128) used in some Matryoshka implementations. The 512-dimension output is directly optimized and evaluated; narrower truncations were never trained and should not be assumed to work.
Hard negative mining. Negatives were mined with
intfloat/multilingual-e5-large against a relative threshold rather than an
absolute one. For each query, the positive passage's own similarity score sets
the reference; candidates are admitted only if they score below 99% of it, and
the top 4 admitted candidates become that query's hard negatives. If the
positive scores 0.90, the cutoff is 0.891 and mining takes the highest scorers
sitting just below it.
Both halves of that rule do specific work. Anchoring to the positive keeps negative difficulty consistent across the dataset, since raw cosine scores vary widely from query to query — a fixed cutoff like 0.85 would be too permissive where the positive scores 0.95 and too strict where it scores 0.80. The 1% margin then removes false negatives: candidates scoring at or near the positive's level are usually relevant passages themselves, and training on them teaches the model to push apart texts it should be pulling together. What survives is the intended target — passages close enough to be genuinely confusable, but far enough to be actually wrong.
Configuration
| Initialized from | Stage 2 checkpoint |
| Batch size | 8 |
| Negatives per query | 4 mined hard negatives, no in-batch negatives |
| Learning rate | 1e-6 → 1e-7 |
| Warmup | None |
| Early stopping patience | 10 |
| Validation interval | every 5% of an epoch |
| Model selection | Best validation checkpoint |
Data and augmentation
Roughly 500,000 query–passage pairs from multiple sources, including AI Hub.
Because a growing share of retrieval corpora is LLM-generated and Markdown-formatted, part of the training data was converted into Markdown-style passages. Three augmentations were applied, each targeting a different failure mode:
| Augmentation | Targets |
|---|---|
| Pair concatenation | Multi-part queries and multi-passage contexts |
| Language transfer (ko ↔ en) | Cross-lingual retrieval |
| Style transfer (plain → Markdown) | Structured, LLM-generated passages |
Augmentation was performed with Gemma-3-12B.
Evaluation
Setup
Five dataset groups:
- 3 groups — subsets extracted from AI Hub datasets
- 1 group — synthetic queries paired with Markdown-style passages, generated by GPT-4o-mini from a sports regulation PDF
- 1 group — a concatenation of the four groups above, as a mixed-domain set
Train/eval separation. Evaluation sets were split off from their source groups before training and were never seen during any of the three stages. Although AI Hub appears in both the training corpus and the evaluation groups, the specific query–passage pairs used for evaluation were held out and excluded from training.
Each query has a single correct passage, so Accuracy@k here is equivalent to Hit Rate@k. Reported numbers are the average across all five groups.
The mixed group is a concatenation of the other four, so it is not statistically independent of them. The five-group average consequently weights the first four groups twice. Read the average as an aggregate summary rather than as five independent measurements.
Results
| Architecture | Open/Closed | Acc@1 | Acc@3 | Acc@5 | Acc@10 |
|---|---|---|---|---|---|
| FronyAI/frony-embed-medium-arctic-ko-v2.5 | Open | 0.6942 | 0.8361 | 0.8807 | 0.9197 |
| FronyAI/frony-embed-medium-arctic-ko-v2.5 (half dim) | Open | 0.6778 | 0.8277 | 0.8726 | 0.9129 |
| dragonkue/snowflake-arctic-embed-l-v2.0-ko | Open | 0.6612 | 0.8396 | 0.8931 | 0.9390 |
| nlpai-lab/KURE-v1 | Open | 0.6434 | 0.8240 | 0.8788 | 0.9285 |
| upstage-large | Closed | 0.6323 | 0.8522 | 0.9068 | 0.9459 |
| BAAI/bge-m3 | Open | 0.5849 | 0.7763 | 0.8420 | 0.8985 |
| intfloat/multilingual-e5-large | Open | 0.5764 | 0.7630 | 0.8267 | 0.8891 |
| Snowflake/snowflake-arctic-embed-l-v2.0 | Open | 0.5726 | 0.7591 | 0.8232 | 0.8917 |
| jinaai/jina-embeddings-v3 | Open | 0.5270 | 0.7242 | 0.7953 | 0.8644 |
| openai-text-embedding-3-large | Closed | 0.4903 | 0.6621 | 0.7316 | 0.8149 |
On public benchmarks
No public benchmark scores are reported here, and this is a deliberate choice rather than an omission.
The training corpus was assembled from a broad mix of Korean sources, and we cannot currently rule out overlap with the evaluation splits of common public benchmarks. Reporting numbers under those conditions would produce scores that look strong for the wrong reason. We would rather publish an internal evaluation we can vouch for than a public one we can't.
Auditing the training corpus for benchmark contamination is planned. Public results will be added once the training set can be certified clean against the specific benchmarks reported — not before.
In the meantime, treat the table above as a comparison conducted under consistent conditions across all listed models, and validate on your own data before committing to any of them.
References
The three-stage pipeline was assembled from ideas in the following work. Each entry notes what was taken from it.
Multi-stage pipeline structure
- LG AI Research (2025). EXAONE 4.0: Unified Large Language Models Integrating Non-reasoning and Reasoning Modes. arXiv:2507.11407 — the shape of a sequential pipeline where each stage initializes from the previous checkpoint with a different objective.
Token-level similarity (Stages 1 and 2)
- Khattab, O., Zaharia, M. (2020). ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT. SIGIR 2020. arXiv:2004.12832 — the MaxSim late-interaction score.
Self-distillation (Stage 2)
- Chen, J., Xiao, S., Zhang, P., Luo, K., Lian, D., Liu, Z. (2024). BGE M3-Embedding: Multi-Lingual, Multi-Functionality, Multi-Granularity Text Embeddings Through Self-Knowledge Distillation. arXiv:2402.03216 — the idea of using one retrieval functionality's relevance scores as the teacher signal for another, within a single model. Stage 2 applies this between the token and dense representations.
Hard-negative mining and training parameters (Stage 3)
- Yu, P., Merrick, L., Nuti, G., Campos, D. (2024). Arctic-Embed 2.0: Multilingual Retrieval Without Compromise. arXiv:2412.04506 — hard-negative mining with a tuned false-positive cutoff, and much of the training configuration. This is also the base model for this work.
Matryoshka objective (Stage 3)
- Kusupati, A., et al. (2022). Matryoshka Representation Learning. NeurIPS 2022. arXiv:2205.13147 — the nested-dimension training objective.
Contrastive objective (all stages)
- van den Oord, A., Li, Y., Vinyals, O. (2018). Representation Learning with Contrastive Predictive Coding. arXiv:1807.03748 — the InfoNCE loss.
Models and tools used
Snowflake/snowflake-arctic-embed-l-v2.0— base model (cited above).intfloat/multilingual-e5-large— teacher model for hard-negative mining in Stage 3. Wang, L., Yang, N., Huang, X., Yang, L., Majumder, R., Wei, F. (2024). Multilingual E5 Text Embeddings: A Technical Report. arXiv:2402.05672google/gemma-3-12b-it— data augmentation (pair concatenation, ko↔en language transfer, plain→Markdown style transfer). Subject to the Gemma Terms of Use.gpt-4o-mini— synthetic evaluation queries for one of the five evaluation groups. Not used to generate training data.bitsandbytes— 8-bit Adam. Dettmers, T., Lewis, M., Shleifer, S., Zettlemoyer, L. (2022). 8-bit Optimizers via Block-wise Quantization. ICLR 2022. arXiv:2110.02861sentence-transformers— packaging and inference. Reimers, N., Gurevych, I. (2019). Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. EMNLP 2019. arXiv:1908.10084PyTorch Lightning— training framework.
License and attribution
Model weights are released under Apache-2.0.
Training data. The training corpus includes datasets from AI Hub, operated by the National Information Society Agency (한국지능정보사회진흥원, NIA) under the Ministry of Science and ICT. Per AI Hub's usage policy, this work is acknowledged as follows:
본 모델의 학습에는 과학기술정보통신부와 한국지능정보사회진흥원의 「지능정보산업 인프라 조성」 사업의 일환으로 구축된 AI 허브 데이터가 활용되었습니다.
This model was trained in part on AI Hub datasets constructed under the Intelligent Information Industry Infrastructure Development project of the Ministry of Science and ICT and the National Information Society Agency (NIA), Republic of Korea.
Note the following, which concern the underlying data rather than these weights:
- AI Hub data may be used for research and development, commercial and non-commercial alike. However, selling the datasets or other direct commercial use of the data requires separate agreement with the constructing institution.
- No AI Hub data is redistributed in this repository. Only trained model weights are published.
- Rights to AI Hub data remain with the constructing and participating institutions and NIA. The Apache-2.0 license on these weights does not grant any rights to that data.
- Organizations and individuals located outside Korea require separate agreement with the constructing institution and NIA to use AI Hub data, and transferring the data abroad requires separate agreement as well. These conditions apply to the data itself; if your use case involves obtaining or handling AI Hub data, review them directly.
This summary is provided for convenience and is not legal advice. Verify current terms at the AI Hub usage policy, and consult your own counsel for deployments where the answer matters.
Contact
Open an issue or pull request with questions or suggestions, or email flash659@gmail.com.
- Downloads last month
- 212
Model tree for FronyAI/frony-embed-medium-arctic-ko-v2.5
Base model
Snowflake/snowflake-arctic-embed-l-v2.0