rb512 commited on
Commit
9a51602
·
verified ·
1 Parent(s): ce1b528

Add Dhvani v7 model card

Browse files
Files changed (1) hide show
  1. README.md +197 -0
README.md ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language: en
3
+ license: apache-2.0
4
+ tags:
5
+ - sentence-embeddings
6
+ - contrastive-learning
7
+ - multi-head
8
+ - decorrelated
9
+ - style-aware
10
+ - compression-invariant
11
+ datasets:
12
+ - stanfordnlp/snli
13
+ - nyu-mll/multi_nli
14
+ base_model: Qwen/Qwen3-1.7B
15
+ pipeline_tag: sentence-similarity
16
+ ---
17
+
18
+ # Dhvani v7: Decorrelated Multi-Head Embeddings
19
+
20
+ **Dhvani v7** fixes the critical surface↔abhida head collapse in v6 (ρ=0.985 → -0.009) using hinge-based cross-covariance decorrelation. The three heads now produce genuinely independent embedding subspaces.
21
+
22
+ ## Key Results
23
+
24
+ | Metric | v6 | v7 | Delta |
25
+ |--------|----|----|-------|
26
+ | Surface↔Abhida correlation | 0.985 | **-0.009** | Fixed ✅ |
27
+ | STS17 (surface) | 0.868 | **0.883** | +1.5 |
28
+ | STS17 (abhida) | 0.858 | **0.854** | -0.4 |
29
+ | STS17 (vyanjana) | 0.804 | **0.817** | +1.3 |
30
+ | Abhida meaning separation | — | **0.692** | New metric |
31
+ | Vyanjana register gap | 1.6 | **1.656** | Maintained |
32
+ | Register probe accuracy | 1.0 | **1.0** | Maintained |
33
+
34
+ ## Architecture
35
+
36
+ ```
37
+ Input → Qwen3-1.7B (LoRA r=16, α=32) → Mean Pool (2048)
38
+ → Shared Trunk (Linear 2048→1024 + LN + GELU)
39
+ → Surface Head (Linear 1024→512 + LN) — lexical/syntactic similarity
40
+ → Abhida Head (Linear 1024→512 + LN) — deep meaning (decorrelated from surface)
41
+ → Vyanjana Head (Linear 1024→512 + LN) — register/tone
42
+ All heads → L2 normalized
43
+ ```
44
+
45
+ ## The Decorrelation Fix
46
+
47
+ v6 trained with a weak orthogonality penalty (weight=0.1, dot-product only) → heads collapsed.
48
+
49
+ v7 uses **hinge-based cross-covariance decorrelation**:
50
+ - Full cross-covariance matrix penalty between surface↔abhida
51
+ - Hinge threshold (0.05): no gradient when already decorrelated → stable convergence
52
+ - Only applied to the collapsed pair; vyanjana was already independent
53
+ - VICReg-style variance regularization prevents dimensional collapse
54
+
55
+ ## Training
56
+
57
+ - **Backbone**: Qwen/Qwen3-1.7B with LoRA (r=16, α=32, targets: q/k/v/o_proj)
58
+ - **Data**: NLI (SNLI + MultiNLI) for surface/abhida + balanced style pairs for vyanjana
59
+ - **Losses**: InfoNCE (surface), hard-negative InfoNCE (abhida), register-contrastive (vyanjana), hinge cross-covariance
60
+ - **Hardware**: AWS g5.xlarge (A10G 24GB), 2500 steps, ~3.5h
61
+ - **Optimizer**: AdamW (lr=1e-4, cosine schedule, 500-step warmup)
62
+
63
+ ## Checkpoint Format
64
+
65
+ ```python
66
+ {
67
+ 'step': 2500,
68
+ 'config': {...},
69
+ 'metrics': {'cos_surf_abhi': -0.009, 'sts17_surface': 0.883, ...},
70
+ 'lora': model.base.state_dict(),
71
+ 'trunk': model.trunk.state_dict(),
72
+ 'surface_head': model.surface_head.state_dict(),
73
+ 'abhida_head': model.abhida_head.state_dict(),
74
+ 'vyanjana_head': model.vyanjana_head.state_dict(),
75
+ 'optimizer': ...,
76
+ 'scheduler': ...,
77
+ }
78
+ ```
79
+
80
+ ## Usage
81
+
82
+ ```python
83
+ import torch
84
+ import torch.nn as nn
85
+ import torch.nn.functional as F
86
+ from transformers import AutoModel, AutoTokenizer
87
+ from peft import get_peft_model, LoraConfig, TaskType
88
+ from huggingface_hub import hf_hub_download
89
+
90
+ class DhvaniV7(nn.Module):
91
+ def __init__(self, cfg):
92
+ super().__init__()
93
+ base = AutoModel.from_pretrained(
94
+ cfg['base_model'], torch_dtype=torch.bfloat16,
95
+ attn_implementation='eager', trust_remote_code=True
96
+ )
97
+ lora_config = LoraConfig(
98
+ r=cfg['lora_r'], lora_alpha=cfg['lora_alpha'],
99
+ lora_dropout=cfg['lora_dropout'],
100
+ target_modules=cfg['lora_targets'],
101
+ bias='none', task_type=TaskType.FEATURE_EXTRACTION
102
+ )
103
+ self.base = get_peft_model(base, lora_config)
104
+ self.trunk = nn.Sequential(
105
+ nn.Linear(cfg['hidden_dim'], cfg['trunk_dim']),
106
+ nn.LayerNorm(cfg['trunk_dim']), nn.GELU(),
107
+ )
108
+ self.surface_head = nn.Sequential(
109
+ nn.Linear(cfg['trunk_dim'], cfg['subspace_dim']),
110
+ nn.LayerNorm(cfg['subspace_dim']),
111
+ )
112
+ self.abhida_head = nn.Sequential(
113
+ nn.Linear(cfg['trunk_dim'], cfg['subspace_dim']),
114
+ nn.LayerNorm(cfg['subspace_dim']),
115
+ )
116
+ self.vyanjana_head = nn.Sequential(
117
+ nn.Linear(cfg['trunk_dim'], cfg['subspace_dim']),
118
+ nn.LayerNorm(cfg['subspace_dim']),
119
+ )
120
+
121
+ @staticmethod
122
+ def mean_pool(hidden, mask):
123
+ m = mask.unsqueeze(-1).float()
124
+ return (hidden * m).sum(1) / m.sum(1).clamp(min=1e-9)
125
+
126
+ def encode_tokens(self, input_ids, attention_mask):
127
+ out = self.base(input_ids=input_ids, attention_mask=attention_mask)
128
+ pooled = self.mean_pool(out.last_hidden_state.float(), attention_mask)
129
+ trunk = self.trunk(pooled)
130
+ return {
131
+ 'surface': F.normalize(self.surface_head(trunk), p=2, dim=-1),
132
+ 'abhida': F.normalize(self.abhida_head(trunk), p=2, dim=-1),
133
+ 'vyanjana': F.normalize(self.vyanjana_head(trunk), p=2, dim=-1),
134
+ 'full': F.normalize(torch.cat([
135
+ self.surface_head(trunk),
136
+ self.abhida_head(trunk),
137
+ self.vyanjana_head(trunk),
138
+ ], dim=-1), p=2, dim=-1),
139
+ }
140
+
141
+ # Load
142
+ ckpt_path = hf_hub_download(repo_id="rb512/dhvani-v7", filename="v7_best.pt")
143
+ ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False)
144
+ cfg = ckpt["config"]
145
+
146
+ tokenizer = AutoTokenizer.from_pretrained(cfg['base_model'], trust_remote_code=True)
147
+ if tokenizer.pad_token is None:
148
+ tokenizer.pad_token = tokenizer.eos_token
149
+
150
+ model = DhvaniV7(cfg)
151
+ model.base.load_state_dict(ckpt["lora"])
152
+ model.trunk.load_state_dict(ckpt["trunk"])
153
+ model.surface_head.load_state_dict(ckpt["surface_head"])
154
+ model.abhida_head.load_state_dict(ckpt["abhida_head"])
155
+ model.vyanjana_head.load_state_dict(ckpt["vyanjana_head"])
156
+ model.eval()
157
+
158
+ # Encode
159
+ texts = ["The cat sat on the mat.", "A feline rested upon the rug."]
160
+ enc = tokenizer(texts, max_length=128, truncation=True, padding='max_length', return_tensors='pt')
161
+ with torch.no_grad():
162
+ embs = model.encode_tokens(enc['input_ids'], enc['attention_mask'])
163
+
164
+ # Surface: high similarity (paraphrases)
165
+ # Abhida: high similarity (same meaning, decorrelated from surface)
166
+ # Vyanjana: similar (same register)
167
+ print(f"Surface sim: {(embs['surface'][0] @ embs['surface'][1]).item():.3f}")
168
+ print(f"Abhida sim: {(embs['abhida'][0] @ embs['abhida'][1]).item():.3f}")
169
+ print(f"Vyanjana sim: {(embs['vyanjana'][0] @ embs['vyanjana'][1]).item():.3f}")
170
+ ```
171
+
172
+ ## Philosophical Inspiration
173
+
174
+ Named after Ānandavardhana's 9th-century theory of *dhvani* (resonance) in Sanskrit poetics:
175
+ - **Abhidā** (अभिधा, denotation): literal propositional content — what was said
176
+ - **Vyañjanā** (व्यञ्जना, suggestion): expressive register and style — how it was said
177
+ - **Surface**: overall graded semantic similarity
178
+
179
+ ## Related
180
+
181
+ - [Karaka Attention](https://huggingface.co/rb512/karaka-attention): Uses abhida head as conditioning signal for semantically typed attention
182
+ - [AGT: Action-Gating Test](https://doi.org/10.1007/s43681-025-00700-8) (Springer AI & Ethics)
183
+
184
+ ## Citation
185
+
186
+ ```bibtex
187
+ @article{dhvani2026,
188
+ title={Dhvani: Structured Multi-Head Embeddings that Separate What Was Said from How It Was Said},
189
+ author={Baxi, Rahul},
190
+ year={2026},
191
+ note={VyasaLabs Technical Report}
192
+ }
193
+ ```
194
+
195
+ ## License
196
+
197
+ Apache 2.0