CoRover/Hybrid-Finsler-Assymetric-Embeddings
Hybrid Finsler Flow Embedding
A fine-tuned embedding model that adds directional asymmetry to standard sentence embeddings using Finsler geometry (Randers metric). Built on top of all-MiniLM-L6-v2, it learns which direction text flows — enabling retrieval systems that answer "what comes next?" instead of just "what is similar?"
The Core Idea
Standard RAG uses cosine similarity: sim(A, B) == sim(B, A). This is symmetric — it finds relevant chunks but has no notion of order or progression.
Finsler geometry introduces asymmetric distance:
d(A → B) ≠ d(B → A)If A naturally leads to B (e.g., "boil the water" → "add pasta"), then d(A→B) < d(B→A). This directional signal is encoded in a learned drift vector (omega) per text, using the Randers metric:
d(x → y) = ||y - x|| + ⟨omega_x, y - x⟩Architecture
Input text
│
▼
MiniLM Encoder (trainable, 384-dim)
│
├──► Drift Head → omega (384-dim, ||omega|| < 0.95)
├──► Base output → h (384-dim, for FAISS retrieval)
└──► Semantic Head → s (128-dim, L2-normalized, for contrastive loss)What each output is for
Training Loss (3 components)
L = L_asymmetry + λ_sem * L_semantic + λ_sep * L_separationThe key insight over a pure Finsler model: L_semantic prevents the drift head from distorting the base embedding space, keeping h suitable for standard cosine retrieval.
Checkpoints
Quick Start
Install dependencies
pip install torch transformers faiss-cpu numpy huggingface_hubDownload model files
from huggingface_hub import snapshot_download
snapshot_download(
repo_id="CoRover/Hybrid-Finsler-Assymetric-Embeddings",
local_dir="./finsler_model"
)Then cd finsler_model or adjust paths below accordingly.
FinslerRAG pipeline (recommended)
import sys
sys.path.append(".")
from run_finsler import FinslerRAG
rag = FinslerRAG("hybrid_finsler_final.pt")
docs = [
{"text": "Bring water to a rolling boil.", "metadata": {"step": 1}},
{"text": "Add salt to the boiling water.", "metadata": {"step": 2}},
{"text": "Add pasta to the boiling water.", "metadata": {"step": 3}},
{"text": "Cook pasta for 8-10 minutes.", "metadata": {"step": 4}},
{"text": "Drain the pasta and add sauce.", "metadata": {"step": 5}},
]
rag.index_documents(docs)
# What comes next after boiling water?
results = rag.query_progressive("I have boiled the water, now what?", top_k=3)
for r in results:
print(f"Step {r['metadata']['step']}: {r['text']}")
# Step 2: Add salt to the boiling water.
# Step 3: Add pasta to the boiling water.
# Step 4: Cook pasta for 8-10 minutes.Load model directly (embeddings only)
import sys, torch
from transformers import AutoTokenizer
sys.path.append(".")
from run_finsler import HybridFinslerModel
model = HybridFinslerModel(device="cpu")
model.load_state_dict(torch.load("hybrid_finsler_final.pt", map_location="cpu"))
model.eval()
tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
def encode(text):
tok = tokenizer(text, return_tensors="pt", truncation=True, max_length=128)
with torch.no_grad():
h, omega, s = model(tok.input_ids, tok.attention_mask)
return h.squeeze().numpy(), omega.squeeze().numpy()
h_a, omega_a = encode("Boil the water")
h_b, omega_b = encode("Add pasta to the water")
import numpy as np
def randers(h_src, omega_src, h_tgt):
diff = h_tgt - h_src
return np.linalg.norm(diff) + np.dot(omega_src, diff)
d_forward = randers(h_a, omega_a, h_b) # small (natural direction)
d_backward = randers(h_b, omega_b, h_a) # large (unnatural direction)
print(f"d(A→B) = {d_forward:.4f}")
print(f"d(B→A) = {d_backward:.4f}")
print(f"Asymmetric: {abs(d_forward - d_backward) > 1e-4}")Query Modes
FinslerRAG.query() supports 4 retrieval modes:
# Hybrid with custom alpha (default alpha=0.5)
results = rag.query("my query", mode="hybrid", alpha=0.7, top_k=5)
# Progressive: returns relevant chunks in chronological order
results = rag.query_progressive("my query", top_k=5, forward_only=True)query_progressive result fields
{
"text": "Add pasta to the boiling water.",
"metadata": {"step": 3},
"score": float, # randers_forward (lower = further ahead)
"cosine_score": float, # FAISS cosine similarity
"randers_forward": float, # d(query → chunk)
"randers_backward": float, # d(chunk → query)
"is_forward": bool, # randers_forward < randers_backward
"direction_ratio": float, # randers_backward / randers_forward
"progression_rank": int, # 1 = earliest next step
}Save and Load Index
# Save
rag.save("my_index/")
# Load in a new session (no need to re-encode documents)
rag2 = FinslerRAG("hybrid_finsler_final.pt")
rag2.load("my_index/")
results = rag2.query("my query")Benchmarks
Evaluated on WikiHow procedural pairs (held-out articles not seen during training).
Temporal Direction Classification (TDC)
Task: Given a pair (A, B), classify forward vs. reversed procedural step. Decision rule: "forward" if d(A→B) < d(B→A). 300 forward + 300 backward pairs.
Next Step Retrieval (NSR)
Task: Retrieve the correct next step from 20 candidates (1 true + 19 distractors). 200 evaluation queries.
Hybrid (Randers) trades R@1 for directional ordering — best used with cosine pre-filtering (see query_progressive).Asymmetry Ratio
500 in-distribution forward pairs (sᵢ, sᵢ₊₁). Ratio = d(sᵢ₊₁→sᵢ) / d(sᵢ→sᵢ₊₁).
Step Ordering Accuracy (SOA)
Task: Kendall's τ between model-induced ordering and ground-truth step order. 5 held-out articles.
Semantic Clustering Quality
K-Means (k=10) on embeddings for 200 steps from 10 held-out articles.
Semantic clustering is limited — a known trade-off between flow geometry and topical clustering in a shared embedding space.
Recommended Model by Use Case
When to use this model
Good fit:
- Procedural documents (tutorials, recipes, workflows, SOPs)
- Sequential knowledge bases where order matters
- RAG systems that need to answer "what should I do next?"
- Any domain where A → B has a different meaning than B → A
Not the best fit:
- Pure semantic similarity tasks (use standard MiniLM instead)
- Non-sequential corpora (FAQs, encyclopedias, product descriptions)
Technical Details
Citation
If you use this model, please cite:
@misc{hybrid-finsler-flow,
title = {Hybrid Finsler Flow Embedding},
author = {Abhilash Dable},
year = {2025},
note = {Fine-tuned MiniLM with Randers metric for directional RAG}
}