junaid008 commited on
Commit
4734758
·
verified ·
1 Parent(s): a631ed8

Hindko Embeddings v1.0.0: multilingual-e5-large fine-tuned for Hindko (model, card, benchmarks)

Browse files
.gitattributes CHANGED
@@ -33,3 +33,11 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ benchmarks/00_scorecard.png filter=lfs diff=lfs merge=lfs -text
37
+ benchmarks/01_test_overall_all_models.png filter=lfs diff=lfs merge=lfs -text
38
+ benchmarks/02_test_per_task.png filter=lfs diff=lfs merge=lfs -text
39
+ benchmarks/03_dev_candidates.png filter=lfs diff=lfs merge=lfs -text
40
+ benchmarks/04_round1_vs_round2.png filter=lfs diff=lfs merge=lfs -text
41
+ benchmarks/05_size_vs_score.png filter=lfs diff=lfs merge=lfs -text
42
+ benchmarks/06_booktitle_detail.png filter=lfs diff=lfs merge=lfs -text
43
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
1_Pooling/config.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "embedding_dimension": 1024,
3
+ "pooling_mode": "mean",
4
+ "include_prompt": true
5
+ }
2_Normalize/config.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "module_input_name": "sentence_embedding",
3
+ "module_output_name": "sentence_embedding"
4
+ }
LICENSE ADDED
@@ -0,0 +1,446 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Hindko Embeddings 1.0.0 (junaid008/hindko-embeddings)
2
+ Copyright (c) 2026 junaid008
3
+
4
+ The files in this repository (model weights, configuration, model card,
5
+ evaluation outputs and benchmark images) are licensed under the Creative
6
+ Commons Attribution 4.0 International License (CC BY 4.0), reproduced below
7
+ and at https://creativecommons.org/licenses/by/4.0/legalcode
8
+
9
+ Attribution: "Hindko Embeddings" by junaid008, https://huggingface.co/junaid008/hindko-embeddings
10
+
11
+ The model is a fine-tuned version of intfloat/multilingual-e5-large, which is
12
+ released under the MIT License. Its copyright and permission notice is
13
+ reproduced in the Third-party notice at the end of this file and applies to
14
+ the portions of the base model contained in the weights, tokenizer and
15
+ configuration files.
16
+
17
+ The licence covers the files in this repository only. The texts the model
18
+ was trained and evaluated on are not included and no rights in them are
19
+ granted.
20
+
21
+ -----------------------------------------------------------------------
22
+
23
+ Attribution 4.0 International
24
+
25
+ =======================================================================
26
+
27
+ Creative Commons Corporation ("Creative Commons") is not a law firm and
28
+ does not provide legal services or legal advice. Distribution of
29
+ Creative Commons public licenses does not create a lawyer-client or
30
+ other relationship. Creative Commons makes its licenses and related
31
+ information available on an "as-is" basis. Creative Commons gives no
32
+ warranties regarding its licenses, any material licensed under their
33
+ terms and conditions, or any related information. Creative Commons
34
+ disclaims all liability for damages resulting from their use to the
35
+ fullest extent possible.
36
+
37
+ Using Creative Commons Public Licenses
38
+
39
+ Creative Commons public licenses provide a standard set of terms and
40
+ conditions that creators and other rights holders may use to share
41
+ original works of authorship and other material subject to copyright
42
+ and certain other rights specified in the public license below. The
43
+ following considerations are for informational purposes only, are not
44
+ exhaustive, and do not form part of our licenses.
45
+
46
+ Considerations for licensors: Our public licenses are
47
+ intended for use by those authorized to give the public
48
+ permission to use material in ways otherwise restricted by
49
+ copyright and certain other rights. Our licenses are
50
+ irrevocable. Licensors should read and understand the terms
51
+ and conditions of the license they choose before applying it.
52
+ Licensors should also secure all rights necessary before
53
+ applying our licenses so that the public can reuse the
54
+ material as expected. Licensors should clearly mark any
55
+ material not subject to the license. This includes other CC-
56
+ licensed material, or material used under an exception or
57
+ limitation to copyright. More considerations for licensors:
58
+ wiki.creativecommons.org/Considerations_for_licensors
59
+
60
+ Considerations for the public: By using one of our public
61
+ licenses, a licensor grants the public permission to use the
62
+ licensed material under specified terms and conditions. If
63
+ the licensor's permission is not necessary for any reason--for
64
+ example, because of any applicable exception or limitation to
65
+ copyright--then that use is not regulated by the license. Our
66
+ licenses grant only permissions under copyright and certain
67
+ other rights that a licensor has authority to grant. Use of
68
+ the licensed material may still be restricted for other
69
+ reasons, including because others have copyright or other
70
+ rights in the material. A licensor may make special requests,
71
+ such as asking that all changes be marked or described.
72
+ Although not required by our licenses, you are encouraged to
73
+ respect those requests where reasonable. More considerations
74
+ for the public:
75
+ wiki.creativecommons.org/Considerations_for_licensees
76
+
77
+ =======================================================================
78
+
79
+ Creative Commons Attribution 4.0 International Public License
80
+
81
+ By exercising the Licensed Rights (defined below), You accept and agree
82
+ to be bound by the terms and conditions of this Creative Commons
83
+ Attribution 4.0 International Public License ("Public License"). To the
84
+ extent this Public License may be interpreted as a contract, You are
85
+ granted the Licensed Rights in consideration of Your acceptance of
86
+ these terms and conditions, and the Licensor grants You such rights in
87
+ consideration of benefits the Licensor receives from making the
88
+ Licensed Material available under these terms and conditions.
89
+
90
+
91
+ Section 1 -- Definitions.
92
+
93
+ a. Adapted Material means material subject to Copyright and Similar
94
+ Rights that is derived from or based upon the Licensed Material
95
+ and in which the Licensed Material is translated, altered,
96
+ arranged, transformed, or otherwise modified in a manner requiring
97
+ permission under the Copyright and Similar Rights held by the
98
+ Licensor. For purposes of this Public License, where the Licensed
99
+ Material is a musical work, performance, or sound recording,
100
+ Adapted Material is always produced where the Licensed Material is
101
+ synched in timed relation with a moving image.
102
+
103
+ b. Adapter's License means the license You apply to Your Copyright
104
+ and Similar Rights in Your contributions to Adapted Material in
105
+ accordance with the terms and conditions of this Public License.
106
+
107
+ c. Copyright and Similar Rights means copyright and/or similar rights
108
+ closely related to copyright including, without limitation,
109
+ performance, broadcast, sound recording, and Sui Generis Database
110
+ Rights, without regard to how the rights are labeled or
111
+ categorized. For purposes of this Public License, the rights
112
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
113
+ Rights.
114
+
115
+ d. Effective Technological Measures means those measures that, in the
116
+ absence of proper authority, may not be circumvented under laws
117
+ fulfilling obligations under Article 11 of the WIPO Copyright
118
+ Treaty adopted on December 20, 1996, and/or similar international
119
+ agreements.
120
+
121
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
122
+ any other exception or limitation to Copyright and Similar Rights
123
+ that applies to Your use of the Licensed Material.
124
+
125
+ f. Licensed Material means the artistic or literary work, database,
126
+ or other material to which the Licensor applied this Public
127
+ License.
128
+
129
+ g. Licensed Rights means the rights granted to You subject to the
130
+ terms and conditions of this Public License, which are limited to
131
+ all Copyright and Similar Rights that apply to Your use of the
132
+ Licensed Material and that the Licensor has authority to license.
133
+
134
+ h. Licensor means the individual(s) or entity(ies) granting rights
135
+ under this Public License.
136
+
137
+ i. Share means to provide material to the public by any means or
138
+ process that requires permission under the Licensed Rights, such
139
+ as reproduction, public display, public performance, distribution,
140
+ dissemination, communication, or importation, and to make material
141
+ available to the public including in ways that members of the
142
+ public may access the material from a place and at a time
143
+ individually chosen by them.
144
+
145
+ j. Sui Generis Database Rights means rights other than copyright
146
+ resulting from Directive 96/9/EC of the European Parliament and of
147
+ the Council of 11 March 1996 on the legal protection of databases,
148
+ as amended and/or succeeded, as well as other essentially
149
+ equivalent rights anywhere in the world.
150
+
151
+ k. You means the individual or entity exercising the Licensed Rights
152
+ under this Public License. Your has a corresponding meaning.
153
+
154
+
155
+ Section 2 -- Scope.
156
+
157
+ a. License grant.
158
+
159
+ 1. Subject to the terms and conditions of this Public License,
160
+ the Licensor hereby grants You a worldwide, royalty-free,
161
+ non-sublicensable, non-exclusive, irrevocable license to
162
+ exercise the Licensed Rights in the Licensed Material to:
163
+
164
+ a. reproduce and Share the Licensed Material, in whole or
165
+ in part; and
166
+
167
+ b. produce, reproduce, and Share Adapted Material.
168
+
169
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
170
+ Exceptions and Limitations apply to Your use, this Public
171
+ License does not apply, and You do not need to comply with
172
+ its terms and conditions.
173
+
174
+ 3. Term. The term of this Public License is specified in Section
175
+ 6(a).
176
+
177
+ 4. Media and formats; technical modifications allowed. The
178
+ Licensor authorizes You to exercise the Licensed Rights in
179
+ all media and formats whether now known or hereafter created,
180
+ and to make technical modifications necessary to do so. The
181
+ Licensor waives and/or agrees not to assert any right or
182
+ authority to forbid You from making technical modifications
183
+ necessary to exercise the Licensed Rights, including
184
+ technical modifications necessary to circumvent Effective
185
+ Technological Measures. For purposes of this Public License,
186
+ simply making modifications authorized by this Section 2(a)
187
+ (4) never produces Adapted Material.
188
+
189
+ 5. Downstream recipients.
190
+
191
+ a. Offer from the Licensor -- Licensed Material. Every
192
+ recipient of the Licensed Material automatically
193
+ receives an offer from the Licensor to exercise the
194
+ Licensed Rights under the terms and conditions of this
195
+ Public License.
196
+
197
+ b. No downstream restrictions. You may not offer or impose
198
+ any additional or different terms or conditions on, or
199
+ apply any Effective Technological Measures to, the
200
+ Licensed Material if doing so restricts exercise of the
201
+ Licensed Rights by any recipient of the Licensed
202
+ Material.
203
+
204
+ 6. No endorsement. Nothing in this Public License constitutes or
205
+ may be construed as permission to assert or imply that You
206
+ are, or that Your use of the Licensed Material is, connected
207
+ with, or sponsored, endorsed, or granted official status by,
208
+ the Licensor or others designated to receive attribution as
209
+ provided in Section 3(a)(1)(A)(i).
210
+
211
+ b. Other rights.
212
+
213
+ 1. Moral rights, such as the right of integrity, are not
214
+ licensed under this Public License, nor are publicity,
215
+ privacy, and/or other similar personality rights; however, to
216
+ the extent possible, the Licensor waives and/or agrees not to
217
+ assert any such rights held by the Licensor to the limited
218
+ extent necessary to allow You to exercise the Licensed
219
+ Rights, but not otherwise.
220
+
221
+ 2. Patent and trademark rights are not licensed under this
222
+ Public License.
223
+
224
+ 3. To the extent possible, the Licensor waives any right to
225
+ collect royalties from You for the exercise of the Licensed
226
+ Rights, whether directly or through a collecting society
227
+ under any voluntary or waivable statutory or compulsory
228
+ licensing scheme. In all other cases the Licensor expressly
229
+ reserves any right to collect such royalties.
230
+
231
+
232
+ Section 3 -- License Conditions.
233
+
234
+ Your exercise of the Licensed Rights is expressly made subject to the
235
+ following conditions.
236
+
237
+ a. Attribution.
238
+
239
+ 1. If You Share the Licensed Material (including in modified
240
+ form), You must:
241
+
242
+ a. retain the following if it is supplied by the Licensor
243
+ with the Licensed Material:
244
+
245
+ i. identification of the creator(s) of the Licensed
246
+ Material and any others designated to receive
247
+ attribution, in any reasonable manner requested by
248
+ the Licensor (including by pseudonym if
249
+ designated);
250
+
251
+ ii. a copyright notice;
252
+
253
+ iii. a notice that refers to this Public License;
254
+
255
+ iv. a notice that refers to the disclaimer of
256
+ warranties;
257
+
258
+ v. a URI or hyperlink to the Licensed Material to the
259
+ extent reasonably practicable;
260
+
261
+ b. indicate if You modified the Licensed Material and
262
+ retain an indication of any previous modifications; and
263
+
264
+ c. indicate the Licensed Material is licensed under this
265
+ Public License, and include the text of, or the URI or
266
+ hyperlink to, this Public License.
267
+
268
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
269
+ reasonable manner based on the medium, means, and context in
270
+ which You Share the Licensed Material. For example, it may be
271
+ reasonable to satisfy the conditions by providing a URI or
272
+ hyperlink to a resource that includes the required
273
+ information.
274
+
275
+ 3. If requested by the Licensor, You must remove any of the
276
+ information required by Section 3(a)(1)(A) to the extent
277
+ reasonably practicable.
278
+
279
+ 4. If You Share Adapted Material You produce, the Adapter's
280
+ License You apply must not prevent recipients of the Adapted
281
+ Material from complying with this Public License.
282
+
283
+
284
+ Section 4 -- Sui Generis Database Rights.
285
+
286
+ Where the Licensed Rights include Sui Generis Database Rights that
287
+ apply to Your use of the Licensed Material:
288
+
289
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
290
+ to extract, reuse, reproduce, and Share all or a substantial
291
+ portion of the contents of the database;
292
+
293
+ b. if You include all or a substantial portion of the database
294
+ contents in a database in which You have Sui Generis Database
295
+ Rights, then the database in which You have Sui Generis Database
296
+ Rights (but not its individual contents) is Adapted Material; and
297
+
298
+ c. You must comply with the conditions in Section 3(a) if You Share
299
+ all or a substantial portion of the contents of the database.
300
+
301
+ For the avoidance of doubt, this Section 4 supplements and does not
302
+ replace Your obligations under this Public License where the Licensed
303
+ Rights include other Copyright and Similar Rights.
304
+
305
+
306
+ Section 5 -- Disclaimer of Warranties and Limitation of Liability.
307
+
308
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
309
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
310
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
311
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
312
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
313
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
314
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
315
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
316
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
317
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
318
+
319
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
320
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
321
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
322
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
323
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
324
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
325
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
326
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
327
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
328
+
329
+ c. The disclaimer of warranties and limitation of liability provided
330
+ above shall be interpreted in a manner that, to the extent
331
+ possible, most closely approximates an absolute disclaimer and
332
+ waiver of all liability.
333
+
334
+
335
+ Section 6 -- Term and Termination.
336
+
337
+ a. This Public License applies for the term of the Copyright and
338
+ Similar Rights licensed here. However, if You fail to comply with
339
+ this Public License, then Your rights under this Public License
340
+ terminate automatically.
341
+
342
+ b. Where Your right to use the Licensed Material has terminated under
343
+ Section 6(a), it reinstates:
344
+
345
+ 1. automatically as of the date the violation is cured, provided
346
+ it is cured within 30 days of Your discovery of the
347
+ violation; or
348
+
349
+ 2. upon express reinstatement by the Licensor.
350
+
351
+ For the avoidance of doubt, this Section 6(b) does not affect any
352
+ right the Licensor may have to seek remedies for Your violations
353
+ of this Public License.
354
+
355
+ c. For the avoidance of doubt, the Licensor may also offer the
356
+ Licensed Material under separate terms or conditions or stop
357
+ distributing the Licensed Material at any time; however, doing so
358
+ will not terminate this Public License.
359
+
360
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
361
+ License.
362
+
363
+
364
+ Section 7 -- Other Terms and Conditions.
365
+
366
+ a. The Licensor shall not be bound by any additional or different
367
+ terms or conditions communicated by You unless expressly agreed.
368
+
369
+ b. Any arrangements, understandings, or agreements regarding the
370
+ Licensed Material not stated herein are separate from and
371
+ independent of the terms and conditions of this Public License.
372
+
373
+
374
+ Section 8 -- Interpretation.
375
+
376
+ a. For the avoidance of doubt, this Public License does not, and
377
+ shall not be interpreted to, reduce, limit, restrict, or impose
378
+ conditions on any use of the Licensed Material that could lawfully
379
+ be made without permission under this Public License.
380
+
381
+ b. To the extent possible, if any provision of this Public License is
382
+ deemed unenforceable, it shall be automatically reformed to the
383
+ minimum extent necessary to make it enforceable. If the provision
384
+ cannot be reformed, it shall be severed from this Public License
385
+ without affecting the enforceability of the remaining terms and
386
+ conditions.
387
+
388
+ c. No term or condition of this Public License will be waived and no
389
+ failure to comply consented to unless expressly agreed to by the
390
+ Licensor.
391
+
392
+ d. Nothing in this Public License constitutes or may be interpreted
393
+ as a limitation upon, or waiver of, any privileges and immunities
394
+ that apply to the Licensor or You, including from the legal
395
+ processes of any jurisdiction or authority.
396
+
397
+
398
+ =======================================================================
399
+
400
+ Creative Commons is not a party to its public
401
+ licenses. Notwithstanding, Creative Commons may elect to apply one of
402
+ its public licenses to material it publishes and in those instances
403
+ will be considered the “Licensor.” The text of the Creative Commons
404
+ public licenses is dedicated to the public domain under the CC0 Public
405
+ Domain Dedication. Except for the limited purpose of indicating that
406
+ material is shared under a Creative Commons public license or as
407
+ otherwise permitted by the Creative Commons policies published at
408
+ creativecommons.org/policies, Creative Commons does not authorize the
409
+ use of the trademark "Creative Commons" or any other trademark or logo
410
+ of Creative Commons without its prior written consent including,
411
+ without limitation, in connection with any unauthorized modifications
412
+ to any of its public licenses or any other arrangements,
413
+ understandings, or agreements concerning use of licensed material. For
414
+ the avoidance of doubt, this paragraph does not form part of the
415
+ public licenses.
416
+
417
+ Creative Commons may be contacted at creativecommons.org.
418
+
419
+ -----------------------------------------------------------------------
420
+
421
+ Third-party notice: intfloat/multilingual-e5-large
422
+
423
+ Base model: https://huggingface.co/intfloat/multilingual-e5-large
424
+ License: MIT
425
+
426
+ MIT License
427
+
428
+ Copyright (c) Microsoft Corporation.
429
+
430
+ Permission is hereby granted, free of charge, to any person obtaining a copy
431
+ of this software and associated documentation files (the "Software"), to deal
432
+ in the Software without restriction, including without limitation the rights
433
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
434
+ copies of the Software, and to permit persons to whom the Software is
435
+ furnished to do so, subject to the following conditions:
436
+
437
+ The above copyright notice and this permission notice shall be included in all
438
+ copies or substantial portions of the Software.
439
+
440
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
441
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
442
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
443
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
444
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
445
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
446
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,425 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - hno
4
+ - hnd
5
+ license: cc-by-4.0
6
+ library_name: sentence-transformers
7
+ pipeline_tag: sentence-similarity
8
+ base_model: intfloat/multilingual-e5-large
9
+ tags:
10
+ - sentence-transformers
11
+ - feature-extraction
12
+ - sentence-similarity
13
+ - hindko
14
+ - embeddings
15
+ - low-resource
16
+ - urdu-script
17
+ - perso-arabic
18
+ model-index:
19
+ - name: hindko-embeddings
20
+ results:
21
+ - task:
22
+ type: Retrieval
23
+ dataset:
24
+ name: HindkoEmbedBench v1.0 HeadlineRetrieval
25
+ type: HindkoEmbedBench-HeadlineRetrieval
26
+ split: test
27
+ metrics:
28
+ - type: ndcg_at_10
29
+ name: nDCG@10
30
+ value: 0.6372
31
+ - type: recall_at_1
32
+ name: Recall@1
33
+ value: 0.5625
34
+ - type: recall_at_10
35
+ name: Recall@10
36
+ value: 0.7125
37
+ - task:
38
+ type: Retrieval
39
+ dataset:
40
+ name: HindkoEmbedBench v1.0 BookTitleRetrieval
41
+ type: HindkoEmbedBench-BookTitleRetrieval
42
+ split: test
43
+ metrics:
44
+ - type: ndcg_at_10
45
+ name: nDCG@10
46
+ value: 0.3460
47
+ - type: recall_at_1
48
+ name: Recall@1
49
+ value: 0.1548
50
+ - type: recall_at_10
51
+ name: Recall@10
52
+ value: 0.4494
53
+ - type: mrr_at_10
54
+ name: MRR@10
55
+ value: 0.3608
56
+ - task:
57
+ type: Retrieval
58
+ dataset:
59
+ name: HindkoEmbedBench v1.0 PassageContinuation
60
+ type: HindkoEmbedBench-PassageContinuation
61
+ split: test
62
+ metrics:
63
+ - type: ndcg_at_10
64
+ name: nDCG@10
65
+ value: 0.8756
66
+ - task:
67
+ type: Classification
68
+ dataset:
69
+ name: HindkoEmbedBench v1.0 VerseProseClassification
70
+ type: HindkoEmbedBench-VerseProseClassification
71
+ split: test
72
+ metrics:
73
+ - type: f1
74
+ name: macro-F1
75
+ value: 0.9801
76
+ - task:
77
+ type: Clustering
78
+ dataset:
79
+ name: HindkoEmbedBench v1.0 BookClustering
80
+ type: HindkoEmbedBench-BookClustering
81
+ split: test
82
+ metrics:
83
+ - type: v_measure
84
+ name: V-measure
85
+ value: 0.8566
86
+ ---
87
+
88
+ # Hindko Embeddings
89
+
90
+ > **License: [CC BY 4.0](LICENSE)** for this model's weights and files. The base model, intfloat/multilingual-e5-large, is MIT-licensed; its notice is kept in [`LICENSE`](LICENSE). See [License](#license).
91
+
92
+ A sentence-embedding model for **Hindko** (Northern `hno` and Southern `hnd`), the Indo-Aryan language of Peshawar, Hazara and Kohat in Khyber Pakhtunkhwa, Pakistan, written in Urdu (Perso-Arabic) script. It turns a Hindko headline, sentence, verse or passage into a vector, so that texts about the same thing end up close together: for search, retrieval for RAG, similarity, clustering and classification. It is [intfloat/multilingual-e5-large](https://huggingface.co/intfloat/multilingual-e5-large) fine-tuned on 41,533 training pairs from a Hindko corpus (39,517 of them from Hindko-variety records), and to our knowledge it is the first embedding model trained for Hindko.
93
+
94
+ On the held-out test split of **HindkoEmbedBench v1.0**, the five-task benchmark built for this project (first used in round 1, for our earlier model), it scores **0.7391** overall. A character n-gram TF-IDF baseline scores 0.6864, and the best public embedding model tested, bge-m3, scores 0.6332 at the same 512-token length. The model is ahead of TF-IDF on four of the five tasks and **behind it on one**: finding a book passage from its table-of-contents title (see [Limitations](#limitations-and-bias)).
95
+
96
+ ## At a glance
97
+
98
+ | | |
99
+ |---|---|
100
+ | **Type** | Sentence-transformers bi-encoder: transformer encoder, mean pooling, L2-normalized output |
101
+ | **Base model** | [intfloat/multilingual-e5-large](https://huggingface.co/intfloat/multilingual-e5-large) (MIT), 560M parameters; its XLM-RoBERTa tokenizer is unchanged |
102
+ | **Output** | 1,024-dimensional vectors; compare with cosine similarity (dot product of normalized vectors) |
103
+ | **Input length** | `max_seq_length` 512 tokens; longer input is truncated |
104
+ | **Prefixes** | `query: ` for queries and for similarity, clustering and classification; `passage: ` for documents to be retrieved ([details](#prefixes)) |
105
+ | **Library** | sentence-transformers 6.0 or later with transformers 5.x (saved with sentence-transformers 6.1.0 and transformers 5.3.0); older versions may not load the saved configuration |
106
+ | **Language** | Hindko in Urdu script (`hno`, `hnd`). Not evaluated on Romanized Hindko or other languages |
107
+ | **Training data** | 41,533 pairs (87,176 distinct texts) from the train split of a Hindko corpus of newspapers, books and web pages, with 23,061 mined hard negatives |
108
+ | **Test score** | **0.7391** overall; TF-IDF 0.6864, bge-m3 0.6332, our round-1 model 0.6923 |
109
+ | **Known weak spot** | Book-title retrieval: 0.3460 nDCG@10 on test, below TF-IDF (0.3756) and bge-m3 (0.3778) |
110
+ | **Weights** | float16 safetensors, about 1,068 MB: the same weights that were benchmarked |
111
+ | **Version** | 1.0.0, 2026-10-01 |
112
+ | **Sibling project** | [Hindko Tokenizer](https://huggingface.co/junaid008/hindko-tokenizer) ([GitHub](https://github.com/junaidaslam2006/Hindko-Tokenizer)). This model does **not** use it; it keeps its base model's tokenizer |
113
+ | **Code** | The benchmark and the training code will be released |
114
+
115
+ ## Highlights
116
+
117
+ - **Highest overall test score of all models tested**: 0.7391, against 0.6864 for TF-IDF (+0.0527), 0.6332 for bge-m3 (+0.1059) and 0.5977 for its own base model without fine-tuning (+0.1414).
118
+ - **Large gains on passage tasks**: continuation retrieval 0.8756 nDCG@10 (TF-IDF 0.7899, bge-m3 0.7174) and book clustering 0.8566 V-measure (TF-IDF 0.6895, bge-m3 0.5168).
119
+ - **Better than our round-1 model** (0.6923 on test) on four of five tasks; slightly lower on verse/prose classification (0.9801 vs 0.9827).
120
+ - **Chosen on dev only**, by a rule fixed in advance; this model was scored on test once, after the choice.
121
+ - **Weak spot**: book-title retrieval, where TF-IDF and bge-m3 score higher on test (28 queries) and TF-IDF scores higher on dev (262 queries); on dev the model is also narrowly behind TF-IDF on verse/prose (0.9406 vs 0.9463).
122
+
123
+ ![Scorecard: Hindko Embeddings on the HindkoEmbedBench test split](benchmarks/00_scorecard.png)
124
+
125
+ ## Usage
126
+
127
+ ```bash
128
+ pip install -U "sentence-transformers>=6.0"
129
+ ```
130
+
131
+ ### Search (retrieval)
132
+
133
+ ```python
134
+ from sentence_transformers import SentenceTransformer
135
+
136
+ model = SentenceTransformer("junaid008/hindko-embeddings")
137
+ if model.device.type == "cpu":
138
+ model = model.float() # weights are stored in float16; use float32 on a CPU
139
+
140
+ query = "query: ڈرامے دی پیدائش"
141
+ passages = [
142
+ "passage: ایہہ بہت کہٹ لوک جانڑدین کہ ڈرامے دی پیدائش کسراں تے کتھے ہوئی آئی۔",
143
+ "passage: اج اساں اگر آپڑیں بزرگاں دی انہاں گلاں تے غور نہ کیتا تے پچھتاوے دے سوا کج ہتھ نہ آسی۔",
144
+ "passage: اسی طراں خیبر پختونخوا اچ بولی جانڑیں ولی دیگر زباناں دے ادب و ثقافت دی بی نمائندگی کیتی گئی اَئی۔",
145
+ ]
146
+
147
+ q = model.encode([query], normalize_embeddings=True)
148
+ p = model.encode(passages, normalize_embeddings=True)
149
+ scores = model.similarity(q, p) # cosine similarity, shape (1, 3); higher = more relevant
150
+ ranking = scores[0].argsort(descending=True)
151
+ ```
152
+
153
+ ### Similarity, clustering and classification
154
+
155
+ Use `query: ` on every text when the texts play the same role:
156
+
157
+ ```python
158
+ sentences = [
159
+ "query: ایہہ بہت کہٹ لوک جانڑدین کہ ڈرامے دی پیدائش کسراں تے کتھے ہوئی آئی۔",
160
+ "query: اج اساں اگر آپڑیں بزرگاں دی انہاں گلاں تے غور نہ کیتا تے پچھتاوے دے سوا کج ہتھ نہ آسی۔",
161
+ "query: اسی طراں خیبر پختونخوا اچ بولی جانڑیں ولی دیگر زباناں دے ادب و ثقافت دی بی نمائندگی کیتی گئی اَئی۔",
162
+ ]
163
+ emb = model.encode(sentences, normalize_embeddings=True)
164
+ sim = model.similarity(emb, emb) # 3 x 3 cosine-similarity matrix
165
+ ```
166
+
167
+ The embeddings can be fed to any clustering or classification method. The benchmark uses k-means and logistic regression from scikit-learn on these normalized vectors. Use the scores to rank or group texts; they are not calibrated probabilities, so set any threshold on your own data.
168
+
169
+ The example sentences are from the held-out test split of the Hindko Tokenizer, and they also occur in HindkoEmbedBench test documents; they were already published in the tokenizer card. Approximate meanings: (1) "Very few people know how and where drama was born." (2) "If we do not reflect on these words of our elders today, we will be left with nothing but regret." (3) "In the same way, the literature and culture of the other languages spoken in Khyber Pakhtunkhwa were also represented." The query means "the birth of drama".
170
+
171
+ ### Prefixes
172
+
173
+ The model was trained and evaluated with the e5 prefixes below; results without them were not measured, so keep them.
174
+
175
+ | Text | Prefix |
176
+ |---|---|
177
+ | Search query, headline, title, first line of a poem: anything used to look something up | `query: ` |
178
+ | Document, article, passage or poem to be found | `passage: ` |
179
+ | Both sides of a similarity comparison; texts to cluster or classify | `query: ` |
180
+
181
+ In training, title, verse, prose-sentence, headline and continuation pairs used `query: ` for the anchor and `passage: ` for the positive and the negatives; pairs of neighbouring chunks used `query: ` on both sides. The benchmark uses the same scheme.
182
+
183
+ Write the prefix into the text and call `model.encode`, as in the examples. `encode_query()` and `encode_document()` do **not** add these prefixes for this model.
184
+
185
+ ### Normalize input first
186
+
187
+ Training and benchmark text was put in one canonical form: Unicode NFC, invisible and control characters removed, spaces collapsed, Arabic presentation forms mapped to letters, and Arabic-keyboard YEH/KAF folded where the word is provably Urdu or Hindko spelling. The Hindko Tokenizer repository ships a self-contained `normalize()` that produces this form:
188
+
189
+ ```python
190
+ import os, sys
191
+ from huggingface_hub import hf_hub_download
192
+
193
+ qs = hf_hub_download("junaid008/hindko-tokenizer", "examples/quickstart.py")
194
+ sys.path.insert(0, os.path.dirname(qs))
195
+ from quickstart import normalize
196
+
197
+ raw_text = "ایہہ بہت کہٹ لوک جانڑدین" # any Hindko input
198
+ text = normalize(raw_text) # here: the double space is collapsed
199
+ ```
200
+
201
+ ### Practical notes
202
+
203
+ - **Length.** Input is cut at 512 tokens. For long documents, split them into passages (for example at sentence boundaries) and embed each one.
204
+ - **Precision.** The weights are float16, and all benchmark numbers were measured with them on a GPU in float16. On a CPU, convert to float32 as shown above.
205
+ - **Normalization of vectors.** Pass `normalize_embeddings=True`, as the benchmark did; cosine similarity and dot product then agree.
206
+
207
+ ## HindkoEmbedBench v1.0
208
+
209
+ To our knowledge there was no benchmark for Hindko text embeddings, so one was built for this project (first used in round 1). It has five tasks in the style of MTEB, each with a **dev** version (used for model selection) and a **test** version (scored once per model, after selection). It was built **automatically from corpus metadata**: headlines and their articles, table-of-contents titles and their passages, the verse/prose label of book passages, and the book each passage comes from. No human relevance judgments were collected.
210
+
211
+ | Task | Type | Main metric | Dev | Test |
212
+ |---|---|---|---|---|
213
+ | HeadlineRetrieval | retrieval: newspaper headline or web page title finds its article | nDCG@10 | 85 queries / 784 docs | 80 queries / 517 docs |
214
+ | BookTitleRetrieval | retrieval: table-of-contents title (often a poem's first line) finds its passage(s) | nDCG@10 | 262 queries / 784 docs | 28 queries (57 relevant) / 517 docs |
215
+ | PassageContinuation | retrieval: first half of a passage finds its second half | nDCG@10 | 416 queries / 416 docs | 360 queries / 360 docs |
216
+ | VerseProseClassification | logistic regression on frozen embeddings | macro-F1 | 1,600 train / 297 eval | 1,600 train / 157 eval |
217
+ | BookClustering | k-means, k = number of books | V-measure | 355 passages, 8 books | 176 passages, 5 books |
218
+
219
+ **Overall score** = unweighted mean of the five main metrics.
220
+
221
+ **How it was built.**
222
+ - **Group-disjoint, leak-checked splits.** Whole newspaper editions, books and web sites sit on one side of the split. The benchmark uses the same record-level splits as the Hindko Tokenizer, published as [`split_manifest.jsonl`](https://github.com/junaidaslam2006/Hindko-Tokenizer/blob/main/tokenizer/splits/split_manifest.jsonl) (sha256 `76582d3a1e0afefe…`). Only Hindko-variety records are used.
223
+ - **Shortcut filters.** A record's own title is stripped from its text; generic or repeated titles, titles that appear verbatim in the target, and near-duplicate documents are removed. Documents are cut at a sentence boundary at or below 3,000 characters. One known artifact remains: book-title relevant passages rarely start with a short genre label line (a line reading only "ghazal" or "naat", for example), while about 31 % of test book documents (5 % on dev) do, so a model could gain by ranking such documents low. Our training data strips these lines from both positives and mined negatives, so training does not reward this cue.
224
+ - **Classification and clustering** follow the MTEB protocol: 10 logistic-regression runs on 256 examples per label drawn from a train-split pool of 1,600 passages; 10 k-means runs. The train pool and the evaluation books are disjoint.
225
+ - **Frozen.** Every task file is hashed, and the harness refuses to run if a file changes.
226
+
227
+ **Release status.** The benchmark data contains newspaper and book text and is **not released yet**. This card describes it; the benchmark code will be released with the training code.
228
+
229
+ ## Results
230
+
231
+ All models were run with the same harness: sentence-transformers, `normalize_embeddings=True`, cosine scoring, each model with its own recommended prefixes. Neural models were run at `max_seq_length` 512 in float16, except the two round-1 models (256 tokens, float32). Full numbers: [`eval/results.csv`](eval/results.csv).
232
+
233
+ ### Test split (scored once per model, after selection)
234
+
235
+ | Model | Tokens | Overall | Headline nDCG@10 | BookTitle nDCG@10 | Continuation nDCG@10 | Verse/prose macro-F1 | Clustering V-measure |
236
+ |---|---:|---:|---:|---:|---:|---:|---:|
237
+ | **Hindko Embeddings (this model)** | 512 | **0.7391** | **0.6372** | 0.3460 | **0.8756** | 0.9801 | **0.8566** |
238
+ | Round-1 e5-small fine-tune (ours) | 256 | 0.7197 | 0.6091 | 0.3664 | 0.8314 | 0.9736 | 0.8177 |
239
+ | Round-1 model, e5-base fine-tune (ours) | 256 | 0.6923 | 0.6097 | 0.2740 | 0.8340 | **0.9827** | 0.7612 |
240
+ | Round-2 e5-base fine-tune (ours, runner-up on dev) | 512 | 0.6919 | 0.6027 | 0.2422 | 0.8350 | 0.9818 | 0.7979 |
241
+ | TF-IDF char 2-4-gram (lexical reference) | n/a | 0.6864 | 0.6173 | 0.3756 | 0.7899 | 0.9597 | 0.6895 |
242
+ | BAAI/bge-m3 | 512 | 0.6332 | 0.5960 | **0.3778** | 0.7174 | 0.9578 | 0.5168 |
243
+ | intfloat/multilingual-e5-large (base model) | 512 | 0.5977 | 0.5886 | 0.3122 | 0.6706 | 0.9413 | 0.4758 |
244
+ | intfloat/multilingual-e5-small | 512 | 0.5619 | 0.5381 | 0.2934 | 0.5664 | 0.9197 | 0.4918 |
245
+ | Qwen/Qwen3-Embedding-0.6B | 512 | 0.5576 | 0.5634 | 0.2784 | 0.6186 | 0.9051 | 0.4227 |
246
+ | intfloat/multilingual-e5-base | 512 | 0.5532 | 0.5626 | 0.2776 | 0.6139 | 0.8540 | 0.4580 |
247
+ | sentence-transformers/LaBSE | 512 | 0.5314 | 0.5064 | 0.1608 | 0.5383 | 0.9616 | 0.4899 |
248
+ | sentence-transformers/paraphrase-multilingual-mpnet-base-v2 | 512 | 0.4428 | 0.3399 | 0.0815 | 0.5030 | 0.9018 | 0.3879 |
249
+
250
+ Best value per column in bold. The public models are untuned. They were first run at 256 tokens (float32) in round 1 and re-run at 512 tokens (float16) for this comparison, so length and precision changed together. On test this raised six of the seven (bge-m3: 0.6185 to 0.6332; multilingual-e5-large: 0.5605 to 0.5977) and left paraphrase-multilingual-mpnet unchanged (0.4429 to 0.4428), so the 512-token numbers are the stronger comparison overall. On dev, LaBSE (0.5200 to 0.5139) and multilingual-e5-small (0.5371 to 0.5353) fell slightly.
251
+
252
+ Of our own models, only this model and the round-2 runner-up were scored on test in round 2; the two round-1 models were scored on test in round 1. The round-1 e5-small model scores second on test (0.7197) but was not chosen in round 1, because its dev score was lower.
253
+
254
+ ### Dev split (used for model selection)
255
+
256
+ | Model | Tokens | Overall | Headline | BookTitle | Continuation | Verse/prose | Clustering |
257
+ |---|---:|---:|---:|---:|---:|---:|---:|
258
+ | **Hindko Embeddings (this model, `r2-e5l`)** | 512 | **0.7117** | 0.6357 | 0.4257 | **0.8308** | 0.9406 | 0.7258 |
259
+ | Round-2 e5-base fine-tune (`r2-e5b`) | 512 | 0.7079 | 0.6006 | 0.4464 | 0.8176 | 0.9411 | **0.7339** |
260
+ | Round-2 e5-base, no mined negatives or book blocks (`r2-e5b-plain`) | 512 | 0.7066 | 0.5941 | 0.4408 | 0.8295 | 0.9453 | 0.7234 |
261
+ | Round-2 e5-small fine-tune (`r2-e5s`) | 512 | 0.7039 | 0.6191 | 0.4358 | 0.8094 | **0.9480** | 0.7070 |
262
+ | Round-2 bge-m3 fine-tune (`r2-bgem3`) | 512 | 0.7008 | **0.6459** | 0.4435 | 0.8246 | 0.9429 | 0.6470 |
263
+ | Round-1 model, e5-base fine-tune | 256 | 0.6851 | 0.6299 | 0.3288 | 0.8081 | 0.9432 | 0.7157 |
264
+ | Round-1 e5-small fine-tune | 256 | 0.6700 | 0.6193 | 0.2778 | 0.7943 | 0.9382 | 0.7204 |
265
+ | TF-IDF char 2-4-gram | n/a | 0.6667 | 0.6049 | **0.4594** | 0.7655 | 0.9463 | 0.5573 |
266
+ | BAAI/bge-m3 | 512 | 0.5923 | 0.6183 | 0.2443 | 0.6617 | 0.9363 | 0.5011 |
267
+ | intfloat/multilingual-e5-large | 512 | 0.5872 | 0.6028 | 0.2004 | 0.6524 | 0.9425 | 0.5379 |
268
+ | intfloat/multilingual-e5-base | 512 | 0.5737 | 0.5728 | 0.1827 | 0.6293 | 0.9381 | 0.5457 |
269
+ | Qwen/Qwen3-Embedding-0.6B | 512 | 0.5449 | 0.5327 | 0.1735 | 0.6297 | 0.8985 | 0.4902 |
270
+ | intfloat/multilingual-e5-small | 512 | 0.5353 | 0.5467 | 0.1186 | 0.5698 | 0.9311 | 0.5101 |
271
+ | sentence-transformers/LaBSE | 512 | 0.5139 | 0.4165 | 0.2089 | 0.5036 | 0.9455 | 0.4948 |
272
+ | sentence-transformers/paraphrase-multilingual-mpnet-base-v2 | 512 | 0.4280 | 0.2822 | 0.1138 | 0.4360 | 0.8869 | 0.4210 |
273
+
274
+ Same metrics as the test table. On dev this model is ahead of TF-IDF on three of five tasks (headline, continuation, clustering) and behind it on book titles (0.4257 vs 0.4594) and, narrowly, on verse/prose (0.9406 vs 0.9463).
275
+
276
+ ### Retrieval details (test)
277
+
278
+ | Model | Headline R@1 | Headline R@10 | Headline nDCG@10, newspaper (72 q) | Headline nDCG@10, web (8 q) | BookTitle R@1 | BookTitle R@10 | BookTitle MRR@10 |
279
+ |---|---:|---:|---:|---:|---:|---:|---:|
280
+ | **This model** | **0.5625** | **0.7125** | **0.6072** | 0.9077 | 0.1548 | 0.4494 | 0.3608 |
281
+ | TF-IDF char 2-4-gram | 0.5500 | 0.6875 | 0.5879 | 0.8827 | 0.1875 | **0.5030** | 0.3579 |
282
+ | BAAI/bge-m3 (512) | 0.5500 | 0.6500 | 0.5581 | 0.9375 | **0.2262** | 0.4286 | **0.4113** |
283
+ | Round-1 model (256) | 0.5375 | 0.6750 | 0.5715 | **0.9539** | 0.1012 | 0.4315 | 0.2731 |
284
+
285
+ R@k is recall at k; a book-title query can have several relevant passages (57 for 28 queries).
286
+
287
+ ### Charts
288
+
289
+ The images are in [`benchmarks/`](benchmarks) (3200 x 1800 PNG, free to reuse under the licence) and are drawn from [`eval/results.csv`](eval/results.csv) and [`eval/selection.json`](eval/selection.json) by [`make_charts.py`](make_charts.py).
290
+
291
+ ![Overall test score of every model](benchmarks/01_test_overall_all_models.png)
292
+
293
+ ![Per-task test scores: this model, TF-IDF and bge-m3](benchmarks/02_test_per_task.png)
294
+
295
+ ![Dev selection pool and the tie band](benchmarks/03_dev_candidates.png)
296
+
297
+ ![Round 2 vs round 1 on test](benchmarks/04_round1_vs_round2.png)
298
+
299
+ ![Dev score against model size](benchmarks/05_size_vs_score.png)
300
+
301
+ ![Book-title retrieval in detail, dev and test](benchmarks/06_booktitle_detail.png)
302
+
303
+ ## Training
304
+
305
+ ### Data
306
+
307
+ Pairs were built only from the **train split** of a Hindko corpus: issues of the *Weekly Hindkowan* (Peshawar), the *Gandhara Hindko Academy* book series (much of it poetry) and Hindko web pages. Each pair is an anchor and a positive; some rows also carry mined hard negatives.
308
+
309
+ | Dataset | Pair (anchor → positive) | Rows | Mined negatives per row |
310
+ |---|---|---:|---:|
311
+ | title | table-of-contents title → its passage (1,886); first line of a poem → the rest of the poem (2,505) | 4,391 | 3 (2 from the same book, 1 from another book) |
312
+ | verse_ict | one line of a poem → the poem with that line removed (the line is kept in about 10 % of rows) | 2,949 | 1 (same book) |
313
+ | prose_q | headline or web page title → article body (1,585: 1,447 news, 138 web); one sentence → the surrounding text (up to 900 characters) with that sentence removed, though it is kept in about 10 % of rows (5,354) | 6,939 | 1 |
314
+ | continuation | first half of a passage of up to 1,200 characters → second half | 12,904 | 0 |
315
+ | neighbour | a chunk of about 500 characters → the next chunk of the same text | 14,350 | 0 |
316
+ | **Total** | 87,176 distinct texts | **41,533** | **23,061** |
317
+
318
+ - **Sources:** 24,745 rows from books, 14,073 from newspapers and 2,715 from web pages.
319
+ - **Variety:** 39,517 rows come from Hindko-variety records. The title, verse and prose-sentence datasets also use 1,268 Urdu-variety and 748 mixed-variety rows from the same corpus.
320
+ - **Hard negatives** were mined with a character 2-4-gram TF-IDF index fit only on training documents (13,519 documents). A candidate was rejected if it was the same record, in the same near-duplicate cluster or the same chapter, contained the anchor (also in variant spellings), or re-used a large part of the positive.
321
+
322
+ **Leak prevention.**
323
+ - Only train-split records were used, and none from a split group that has dev or test records (230 such train records were excluded).
324
+ - One train book (204 records) was excluded because it is a re-edition of a dev book.
325
+ - Any text with word 8-gram containment of 0.3 or more in any dev or test text was dropped, under two text normalizations. Anchors equal to or close to a dev or test query (character 3-gram Jaccard 0.5 or more), and anchors of 12 or more characters contained in any dev or test text, were dropped as well.
326
+ - A separately implemented audit script (it shares no code with the pair builder) re-checked every row against the split manifest and the frozen benchmark files: **0 violations** in all six checks. The highest remaining 8-gram containment is 0.2973.
327
+ - The tokenizer is the base model's, unchanged; no vocabulary was added.
328
+
329
+ ### Recipe
330
+
331
+ - **Loss:** `CachedMultipleNegativesRankingLoss` with scale 20, i.e. temperature 0.05. Every other positive and negative in the batch also serves as a negative.
332
+ - **Batches:** 256 rows, each batch drawn from one dataset. Title and verse rows are drawn in **same-book blocks of 32**, so many in-batch negatives are other poems and chapters of the same book. A conflict rule keeps duplicate texts, two rows from one record or duplicate cluster, two passages of one chapter, and a row whose mined negative is another row's positive out of the same batch.
333
+ - **Hyperparameters:** learning rate 2e-5, 2 epochs, 322 optimizer steps (161 per epoch), linear warmup over 10 % of the steps and linear decay, weight decay 0.01, AdamW, bf16 mixed precision, `max_seq_length` 512, gradient-cache mini-batch 32, seed 20261001.
334
+ - **Hardware:** one NVIDIA A100-SXM4-80GB GPU; 1,620 s of training (27 minutes), 25.4 GB peak memory.
335
+ - **Output:** saved in float16. The dev and test scores of this model were measured from the float16 weights that are published here.
336
+
337
+ **What changed from round 1.** The round-1 model (multilingual-e5-base) was trained on 30,431 pairs (headline, book title, continuation and neighbour pairs) at 256 tokens, with in-batch negatives only. Round 2 added the first-line, verse-line and prose-sentence pairs (4,391 title rows against 1,390 book-title pairs in round 1), mined hard negatives, same-book blocks, 512 tokens and the larger base model.
338
+
339
+ **Ablation.** The same e5-base recipe without mined negatives and same-book blocks (`r2-e5b-plain`) scored 0.7066 on dev against 0.7079 with them: a small difference overall (+0.0013), with gains on headlines (+0.0065), book titles (+0.0056) and clustering (+0.0105), and losses on continuation (-0.0119) and verse/prose (-0.0042). It is one seed on dev, so these differences are within noise.
340
+
341
+ ## Model selection protocol
342
+
343
+ 1. **The benchmark was frozen first.** Task files are hashed, and the harness refuses to run on changed files.
344
+ 2. **Recipe gate.** After the first round-2 run (`r2-e5b`), a gate fixed in advance decided the recipe for the remaining runs: book-title nDCG@10 at least 0.36, overall at least 0.685 and clustering at least 0.68 on dev. It passed (0.4464, 0.7079, 0.7339), so the remaining runs (e5-large, e5-small and bge-m3) were trained with mined negatives and same-book blocks.
345
+ 3. **Candidates.** Five round-2 models (e5-small, e5-base, e5-large, bge-m3, and e5-base without mined negatives) were trained on the same pairs. Each was evaluated on dev from its saved float16 weights at 512 tokens. The pool also held the two round-1 models, with their round-1 dev scores (0.6851 and 0.6700).
346
+ 4. **Rule, written before any round-2 result:** take the highest dev overall score; among models within 0.003 of it, take the smallest. `r2-e5l` scored 0.7117. The next best, `r2-e5b`, scored 0.7079 (0.0038 lower) and was outside the band, so `r2-e5l` was selected and `r2-e5b` became the runner-up. The selection file was written before any round-2 test result existed.
347
+ 5. **Test, once.** The selected model and the runner-up were scored on the test split once. The untuned public models were re-run at 512 tokens after the selection and were never in the pool.
348
+
349
+ The round-2 choice used dev only, and test was scored once per model, after it. Test is not untouched across rounds, though: the round-1 test scores of the public models and of our round-1 models were known when round 2 was planned, and the plan cited them, plus a test-split document-length statistic, when it chose the candidate base models and adopted 512 tokens. No checkpoint, hyperparameter or threshold was chosen on test. The dev scores of the round-2 candidates (0.7008 to 0.7117) differ by about the dev standard error estimated in the training plan (about 0.01), so the choice of e5-large over e5-base is not statistically established on dev. On test the two models moved in different directions: 0.7391 for e5-large and 0.6919 for e5-base.
350
+
351
+ ## Intended uses
352
+
353
+ - Semantic search and retrieval over Hindko text in Urdu script, including retrieval for RAG systems.
354
+ - Similarity, clustering and classification features for Hindko documents, verses and sentences.
355
+ - A baseline for research on embeddings for low-resource, Perso-Arabic-script languages.
356
+
357
+ **Out of scope.** Romanized Hindko, speech transcripts, cross-lingual search (for example an English query over Hindko documents) and other languages were not evaluated; the base model's multilingual ability may or may not survive fine-tuning. Do not use similarity scores alone for decisions about people.
358
+
359
+ ## Limitations and bias
360
+
361
+ - **Book-title retrieval is a weak spot.** On test, this model scores 0.3460 nDCG@10 against 0.3756 for TF-IDF and 0.3778 for bge-m3; our round-1 e5-small model also scored higher (0.3664). On dev it is also behind TF-IDF (0.4257 vs 0.4594). It also has the lowest dev book-title score of the five round-2 candidates (0.4257, against 0.4358 to 0.4464); it was selected on the overall score. For title or first-line lookup, combine it with a lexical search (hybrid retrieval).
362
+ - **Residual overlap.** The leak filters drop training texts with word 8-gram containment of 0.3 or more in dev or test text. A separate line-level fuzzy check still finds one test book-title query whose relevant passage has at least half of its lines closely matched in train-split newspaper reprints, and 1 to 3 dev book-title queries per book with at least 30 %. These may slightly favour models trained on this corpus on book-title retrieval; this model still scores below TF-IDF there.
363
+ - **Small test sets.** The test split has 80 headline queries, only 28 book-title queries (from 5 books), 157 verse/prose items (the verse class is essentially one book) and 176 clustering passages from 5 books. Differences of a few points on these tasks are within noise. Dev and test are both reported for this reason.
364
+ - **Automatic benchmark.** Relevance comes from metadata (headline to article, contents title to passage, book identity), not from human judgments. A few headlines are attached to the wrong article, and book identity is only a proxy for topic and style.
365
+ - **Domain.** Training and evaluation text is newspaper prose (mostly from one Peshawar weekly), literary books (much of it poetry) and a small amount of web text. Expect weaker results on conversational, social-media, technical or legal text.
366
+ - **Dialect and spelling.** Peshawari and literary spellings dominate; Hazara and other varieties are less represented. Hindko spelling varies (retroflex nasal, harakat, Arabic-keyboard letters). The model was trained on normalized text, so [normalize input](#normalize-input-first) the same way.
367
+ - **Script.** Only Urdu (Perso-Arabic) script was evaluated; Romanized Hindko was not.
368
+ - **Truncation.** Retrieval mostly sees the start of each document: benchmark documents are cut at 3,000 characters and the model reads at most 512 tokens.
369
+ - **Selection noise.** See [Model selection protocol](#model-selection-protocol): the dev margin over the runner-up is smaller than the dev standard error.
370
+ - **Bias.** The model reflects the viewpoints and vocabulary of the published newspapers and books it was trained on, and any biases of its multilingual base model. No bias evaluation was done.
371
+
372
+ ## Ethical considerations and privacy
373
+
374
+ - **No training text is included.** The repository holds model weights, configuration and evaluation outputs only.
375
+ - **Provenance.** The training and benchmark texts belong to their publishers and authors (*Weekly Hindkowan*, the *Gandhara Hindko Academy* and web sources). They are not distributed here, and the licence below does not cover them.
376
+ - **Use with care.** Embeddings of personal text can reveal what the text is about. Treat stored embeddings with the same care as the text they come from.
377
+
378
+ ## License
379
+
380
+ **[Creative Commons Attribution 4.0 International (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/)** for this model; full text in [`LICENSE`](LICENSE).
381
+
382
+ - You may use, share and adapt the model, including commercially.
383
+ - Give credit: "Hindko Embeddings" by junaid008, with a link to this repository (the citation below is enough).
384
+ - The base model, [intfloat/multilingual-e5-large](https://huggingface.co/intfloat/multilingual-e5-large), is released under the MIT License (Copyright (c) Microsoft Corporation). Its notice is reproduced in [`LICENSE`](LICENSE) and must be kept with copies of the weights.
385
+ - The licence covers the files in this repository. It grants no rights in the texts the model was trained or evaluated on, which are not included.
386
+
387
+ ## Citation
388
+
389
+ ```bibtex
390
+ @misc{hindko_embeddings_2026,
391
+ title = {Hindko Embeddings: a sentence-embedding model for Hindko},
392
+ author = {junaid008},
393
+ year = {2026},
394
+ version = {1.0.0},
395
+ howpublished = {\url{https://huggingface.co/junaid008/hindko-embeddings}},
396
+ note = {CC BY 4.0. Fine-tuned from intfloat/multilingual-e5-large; selected on the dev split of HindkoEmbedBench v1.0 by a pre-registered rule; test overall 0.7391}
397
+ }
398
+ ```
399
+
400
+ Please also cite the base model:
401
+
402
+ ```bibtex
403
+ @article{wang2024multilingual,
404
+ title = {Multilingual E5 Text Embeddings: A Technical Report},
405
+ author = {Wang, Liang and Yang, Nan and Huang, Xiaolong and Yang, Linjun and Majumder, Rangan and Wei, Furu},
406
+ journal = {arXiv preprint arXiv:2402.05672},
407
+ year = {2024}
408
+ }
409
+ ```
410
+
411
+ ## Acknowledgements
412
+
413
+ Heartfelt thanks to the **Chief Minister's Policy Office**, the **Weekly Hindkowan** and the **Gandhara Hindko Board** for supporting this work and sharing the texts that made it possible.
414
+
415
+ This project was built together with **Muhammad Ozair**.
416
+
417
+ ## Contact
418
+
419
+ **junaid008** on Hugging Face. Please open a discussion on this repository for questions, errors or clearance matters.
420
+
421
+ ## Changelog
422
+
423
+ | Version | Date | Changes |
424
+ |---|---|---|
425
+ | 1.0.0 | 2026-10-01 | First release: multilingual-e5-large fine-tuned on 41,533 pairs from a Hindko corpus (round 2, `r2-e5l`); HindkoEmbedBench v1.0 results, selection record and benchmark images. |
benchmarks/00_scorecard.png ADDED

Git LFS Details

  • SHA256: 634a7ed55d7b25730949ba86feb6ab7ee68090e385d42dc2419887095c341fe3
  • Pointer size: 131 Bytes
  • Size of remote file: 316 kB
benchmarks/01_test_overall_all_models.png ADDED

Git LFS Details

  • SHA256: 79b5458576426c1ef0cef189af931d91e47fc390d0ed5f3ea1f6de9181daa532
  • Pointer size: 131 Bytes
  • Size of remote file: 269 kB
benchmarks/02_test_per_task.png ADDED

Git LFS Details

  • SHA256: 6cc9517ac13f1dd66bdf018cd1739e717788b68252a8e4693ca0dfaad6e6ecf7
  • Pointer size: 131 Bytes
  • Size of remote file: 200 kB
benchmarks/03_dev_candidates.png ADDED

Git LFS Details

  • SHA256: ce7db405704e001a970c95bf832c7469f42bb0eb6ba290836fbdcec6d83d528c
  • Pointer size: 131 Bytes
  • Size of remote file: 263 kB
benchmarks/04_round1_vs_round2.png ADDED

Git LFS Details

  • SHA256: c2194422c177c099ec1fb8e8979001fd8b6370a14745dfee2a8f4137ba09db67
  • Pointer size: 131 Bytes
  • Size of remote file: 207 kB
benchmarks/05_size_vs_score.png ADDED

Git LFS Details

  • SHA256: f78024764ac7cb8bb35c92b05688fca4c81eea59544e6f32c65b6c3d428ee5e8
  • Pointer size: 131 Bytes
  • Size of remote file: 242 kB
benchmarks/06_booktitle_detail.png ADDED

Git LFS Details

  • SHA256: 2745ab39cb9da4f45f2c7e3df025917a4b51d6b1081a0458fe69a92859627cb6
  • Pointer size: 131 Bytes
  • Size of remote file: 248 kB
config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_cross_attention": false,
3
+ "architectures": [
4
+ "XLMRobertaModel"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "bos_token_id": 0,
8
+ "classifier_dropout": null,
9
+ "dtype": "float16",
10
+ "eos_token_id": 2,
11
+ "hidden_act": "gelu",
12
+ "hidden_dropout_prob": 0.1,
13
+ "hidden_size": 1024,
14
+ "initializer_range": 0.02,
15
+ "intermediate_size": 4096,
16
+ "is_decoder": false,
17
+ "layer_norm_eps": 1e-05,
18
+ "max_position_embeddings": 514,
19
+ "model_type": "xlm-roberta",
20
+ "num_attention_heads": 16,
21
+ "num_hidden_layers": 24,
22
+ "output_past": true,
23
+ "pad_token_id": 1,
24
+ "position_embedding_type": "absolute",
25
+ "tie_word_embeddings": true,
26
+ "transformers_version": "5.3.0",
27
+ "type_vocab_size": 1,
28
+ "use_cache": false,
29
+ "vocab_size": 250002
30
+ }
config_sentence_transformers.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "__version__": {
3
+ "pytorch": "2.11.0+cu128",
4
+ "sentence_transformers": "6.1.0",
5
+ "transformers": "5.3.0"
6
+ },
7
+ "default_prompt_name": null,
8
+ "model_type": "SentenceTransformer",
9
+ "prompts": {
10
+ "document": "",
11
+ "query": ""
12
+ },
13
+ "similarity_fn_name": "cosine"
14
+ }
eval/results.csv ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ model,model_id,base_model,kind,role,profile,split,max_seq_length,dtype,overall,HeadlineRetrieval,BookTitleRetrieval,PassageContinuation,VerseProseClassification,BookClustering,HL_R1,HL_R10,HL_news,HL_web,HL_nq,BT_R1,BT_R10,BT_MRR
2
+ LaBSE,sentence-transformers/LaBSE,sentence-transformers/LaBSE,public,baseline,labse,dev,512,float16,0.5139,0.4165,0.2089,0.5036,0.9455,0.4948,0.3176,0.5294,0.4239,0.372,85,0.1412,0.3015,0.181
3
+ LaBSE,sentence-transformers/LaBSE,sentence-transformers/LaBSE,public,baseline,labse,test,512,float16,0.5314,0.5064,0.1608,0.5383,0.9616,0.4899,0.4,0.6375,0.4896,0.658,80,0.0714,0.2232,0.153
4
+ Qwen3-Embedding-0.6B,Qwen/Qwen3-Embedding-0.6B,Qwen/Qwen3-Embedding-0.6B,public,baseline,qwen3,dev,512,float16,0.5449,0.5327,0.1735,0.6297,0.8985,0.4902,0.4353,0.6353,0.4797,0.8552,85,0.1107,0.2519,0.1495
5
+ Qwen3-Embedding-0.6B,Qwen/Qwen3-Embedding-0.6B,Qwen/Qwen3-Embedding-0.6B,public,baseline,qwen3,test,512,float16,0.5576,0.5634,0.2784,0.6186,0.9051,0.4227,0.4875,0.6375,0.5297,0.8663,80,0.1458,0.3393,0.3135
6
+ bge-m3,BAAI/bge-m3,BAAI/bge-m3,public,baseline,bge-m3,dev,512,float16,0.5923,0.6183,0.2443,0.6617,0.9363,0.5011,0.5412,0.6824,0.5743,0.8859,85,0.1641,0.3435,0.2135
7
+ bge-m3,BAAI/bge-m3,BAAI/bge-m3,public,baseline,bge-m3,test,512,float16,0.6332,0.596,0.3778,0.7174,0.9578,0.5168,0.55,0.65,0.5581,0.9375,80,0.2262,0.4286,0.4113
8
+ multilingual-e5-base,intfloat/multilingual-e5-base,intfloat/multilingual-e5-base,public,baseline,e5,dev,512,float16,0.5737,0.5728,0.1827,0.6293,0.9381,0.5457,0.4588,0.6706,0.5452,0.7411,85,0.1031,0.2901,0.1504
9
+ multilingual-e5-base,intfloat/multilingual-e5-base,intfloat/multilingual-e5-base,public,baseline,e5,test,512,float16,0.5532,0.5626,0.2776,0.6139,0.854,0.458,0.4875,0.6375,0.5243,0.9077,80,0.1488,0.3512,0.3161
10
+ multilingual-e5-large,intfloat/multilingual-e5-large,intfloat/multilingual-e5-large,public,baseline,e5,dev,512,float16,0.5872,0.6028,0.2004,0.6524,0.9425,0.5379,0.4941,0.7294,0.5646,0.8348,85,0.126,0.2977,0.1709
11
+ multilingual-e5-large,intfloat/multilingual-e5-large,intfloat/multilingual-e5-large,public,baseline,e5,test,512,float16,0.5977,0.5886,0.3122,0.6706,0.9413,0.4758,0.525,0.6625,0.5565,0.8772,80,0.1756,0.378,0.3971
12
+ multilingual-e5-small,intfloat/multilingual-e5-small,intfloat/multilingual-e5-small,public,baseline,e5,dev,512,float16,0.5353,0.5467,0.1186,0.5698,0.9311,0.5101,0.4824,0.6235,0.5115,0.7609,85,0.084,0.1641,0.1047
13
+ multilingual-e5-small,intfloat/multilingual-e5-small,intfloat/multilingual-e5-small,public,baseline,e5,test,512,float16,0.5619,0.5381,0.2934,0.5664,0.9197,0.4918,0.4875,0.5875,0.4988,0.8914,80,0.1726,0.3661,0.2995
14
+ paraphrase-multilingual-mpnet-base-v2,sentence-transformers/paraphrase-multilingual-mpnet-base-v2,sentence-transformers/paraphrase-multilingual-mpnet-base-v2,public,baseline,mpnet,dev,512,float16,0.428,0.2822,0.1138,0.436,0.8869,0.421,0.1882,0.4,0.2702,0.3551,85,0.0573,0.187,0.0914
15
+ paraphrase-multilingual-mpnet-base-v2,sentence-transformers/paraphrase-multilingual-mpnet-base-v2,sentence-transformers/paraphrase-multilingual-mpnet-base-v2,public,baseline,mpnet,test,512,float16,0.4428,0.3399,0.0815,0.503,0.9018,0.3879,0.2375,0.4625,0.3353,0.3814,80,0,0.1637,0.0686
16
+ Round-1 model (e5-base fine-tune),r1-ft-e5-base,intfloat/multilingual-e5-base,round-1,incumbent; selected in round 1,e5,dev,256,float32,0.6851,0.6299,0.3288,0.8081,0.9432,0.7157,0.4941,0.7765,0.6024,0.7968,85,0.229,0.458,0.2894
17
+ Round-1 model (e5-base fine-tune),r1-ft-e5-base,intfloat/multilingual-e5-base,round-1,incumbent; selected in round 1,e5,test,256,float32,0.6923,0.6097,0.274,0.834,0.9827,0.7612,0.5375,0.675,0.5715,0.9539,80,0.1012,0.4315,0.2731
18
+ Round-1 e5-small fine-tune,r1-ft-e5-small,intfloat/multilingual-e5-small,round-1,incumbent,e5,dev,256,float32,0.67,0.6193,0.2778,0.7943,0.9382,0.7204,0.5294,0.7176,0.5912,0.7906,85,0.1679,0.416,0.2353
19
+ Round-1 e5-small fine-tune,r1-ft-e5-small,intfloat/multilingual-e5-small,round-1,incumbent,e5,test,256,float32,0.7197,0.6091,0.3664,0.8314,0.9736,0.8177,0.55,0.675,0.5708,0.9539,80,0.247,0.4196,0.4438
20
+ TF-IDF char 2-4-gram,tfidf-char2-4,,lexical,reference,,dev,,,0.6667,0.6049,0.4594,0.7655,0.9463,0.5573,0.5294,0.6824,0.5656,0.8442,85,0.3282,0.6069,0.4132
21
+ TF-IDF char 2-4-gram,tfidf-char2-4,,lexical,reference,,test,,,0.6864,0.6173,0.3756,0.7899,0.9597,0.6895,0.55,0.6875,0.5879,0.8827,80,0.1875,0.503,0.3579
22
+ Round-2 bge-m3 fine-tune,r2-bgem3,BAAI/bge-m3,round-2,candidate,bge-m3,dev,512,float16,0.7008,0.6459,0.4435,0.8246,0.9429,0.647,0.5529,0.7294,0.6064,0.8859,85,0.3397,0.5573,0.4077
23
+ "Round-2 e5-base fine-tune, no mined negatives",r2-e5b-plain,intfloat/multilingual-e5-base,round-2,candidate (ablation),e5,dev,512,float16,0.7066,0.5941,0.4408,0.8295,0.9453,0.7234,0.4824,0.7059,0.5722,0.7272,85,0.3359,0.5534,0.4053
24
+ Round-2 e5-base fine-tune,r2-e5b,intfloat/multilingual-e5-base,round-2,runner-up,e5,dev,512,float16,0.7079,0.6006,0.4464,0.8176,0.9411,0.7339,0.4941,0.7059,0.5744,0.7598,85,0.3473,0.5496,0.4137
25
+ Round-2 e5-base fine-tune,r2-e5b,intfloat/multilingual-e5-base,round-2,runner-up,e5,test,512,float16,0.6919,0.6027,0.2422,0.835,0.9818,0.7979,0.5375,0.65,0.5706,0.8914,80,0.1071,0.3542,0.251
26
+ Hindko Embeddings (this model),r2-e5l,intfloat/multilingual-e5-large,round-2,selected (released),e5,dev,512,float16,0.7117,0.6357,0.4257,0.8308,0.9406,0.7258,0.5294,0.7412,0.5963,0.875,85,0.2977,0.563,0.3826
27
+ Hindko Embeddings (this model),r2-e5l,intfloat/multilingual-e5-large,round-2,selected (released),e5,test,512,float16,0.7391,0.6372,0.346,0.8756,0.9801,0.8566,0.5625,0.7125,0.6072,0.9077,80,0.1548,0.4494,0.3608
28
+ Round-2 e5-small fine-tune,r2-e5s,intfloat/multilingual-e5-small,round-2,candidate,e5,dev,512,float16,0.7039,0.6191,0.4358,0.8094,0.948,0.707,0.5294,0.7176,0.5899,0.7968,85,0.3397,0.5458,0.4015
eval/selection.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "rule": "pool = round-2 dev results + incumbents ft-e5-base (size 2) and ft-e5-small (size 1) with their round-1 dev scores; best = max overall; near = overall >= best - 0.003; selected = smallest size rank in near (ties by higher score); runner-up = best-scoring other model",
3
+ "dev_scores": {
4
+ "ft-e5-base": 0.6851297501603847,
5
+ "ft-e5-small": 0.6700276166417629,
6
+ "r2-bgem3": 0.7007568407810918,
7
+ "r2-e5b": 0.7079351835925609,
8
+ "r2-e5b-plain": 0.7066095544829916,
9
+ "r2-e5l": 0.7117165057564516,
10
+ "r2-e5s": 0.7038754488016046
11
+ },
12
+ "near": [
13
+ "r2-e5l"
14
+ ],
15
+ "selected": "r2-e5l",
16
+ "runner_up": "r2-e5b",
17
+ "tie": 0.003,
18
+ "written_utc": "2026-10-01T17:48:17Z",
19
+ "gate": {
20
+ "pass": true,
21
+ "decided_utc": "2026-10-01T15:38:50Z",
22
+ "BookTitleRetrieval": 0.446437329167755,
23
+ "overall": 0.7079351835925609,
24
+ "BookClustering": 0.7339101300956627
25
+ },
26
+ "pairs_sha256": {
27
+ "rows.jsonl": "9ddde8f6ef2750166e4d895b8aba55ba394ba954961169ab0aec0f5d4a541faa",
28
+ "texts.jsonl": "f0c31d84f79e7c3cee0b45e708ec1bb1929f9e2d99d7fbdec66ecb47a1024a28"
29
+ },
30
+ "size_rank": {
31
+ "r2-e5s": 1,
32
+ "ft-e5-small": 1,
33
+ "r2-e5b": 2,
34
+ "r2-e5b-plain": 2,
35
+ "ft-e5-base": 2,
36
+ "r2-e5l": 3,
37
+ "r2-bgem3": 4
38
+ },
39
+ "notes": "dev_scores of ft-e5-base and ft-e5-small are their round-1 dev results (max_seq_length 256, float32); all other pool members were evaluated at max_seq_length 512 in float16. Test was run once, after this selection, on the selected model and the runner-up. gate = the pre-registered recipe gate evaluated on r2-e5b dev (BookTitleRetrieval >= 0.36, overall >= 0.685, BookClustering >= 0.68); pass -> the large runs used mined hard negatives and same-book blocks."
40
+ }
eval/training.json ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "runs": {
3
+ "r2-bgem3": {
4
+ "base": "BAAI/bge-m3",
5
+ "lr": 1.5e-05,
6
+ "epochs": 2,
7
+ "batch": 256,
8
+ "mini": 32,
9
+ "max_seq_length": 512,
10
+ "negatives": "on",
11
+ "block": 32,
12
+ "steps": 322,
13
+ "train_seconds": 1608.7,
14
+ "peak_gb": 25.564,
15
+ "gpu": "NVIDIA A100-SXM4-80GB"
16
+ },
17
+ "r2-e5b-plain": {
18
+ "base": "intfloat/multilingual-e5-base",
19
+ "lr": 3e-05,
20
+ "epochs": 2,
21
+ "batch": 256,
22
+ "mini": 64,
23
+ "max_seq_length": 512,
24
+ "negatives": "off",
25
+ "block": 0,
26
+ "steps": 322,
27
+ "train_seconds": 369.8,
28
+ "peak_gb": 17.084,
29
+ "gpu": "NVIDIA A100-SXM4-80GB"
30
+ },
31
+ "r2-e5b": {
32
+ "base": "intfloat/multilingual-e5-base",
33
+ "lr": 3e-05,
34
+ "epochs": 2,
35
+ "batch": 256,
36
+ "mini": 64,
37
+ "max_seq_length": 512,
38
+ "negatives": "on",
39
+ "block": 32,
40
+ "steps": 322,
41
+ "train_seconds": 548.6,
42
+ "peak_gb": 17.091,
43
+ "gpu": "NVIDIA A100-SXM4-80GB"
44
+ },
45
+ "r2-e5l": {
46
+ "base": "intfloat/multilingual-e5-large",
47
+ "lr": 2e-05,
48
+ "epochs": 2,
49
+ "batch": 256,
50
+ "mini": 32,
51
+ "max_seq_length": 512,
52
+ "negatives": "on",
53
+ "block": 32,
54
+ "steps": 322,
55
+ "train_seconds": 1620.1,
56
+ "peak_gb": 25.447,
57
+ "gpu": "NVIDIA A100-SXM4-80GB"
58
+ },
59
+ "r2-e5s": {
60
+ "base": "intfloat/multilingual-e5-small",
61
+ "lr": 5e-05,
62
+ "epochs": 2,
63
+ "batch": 256,
64
+ "mini": 128,
65
+ "max_seq_length": 512,
66
+ "negatives": "on",
67
+ "block": 32,
68
+ "steps": 322,
69
+ "train_seconds": 309.6,
70
+ "peak_gb": 14.999,
71
+ "gpu": "NVIDIA A100-SXM4-80GB"
72
+ }
73
+ },
74
+ "train_rows": {
75
+ "title": 4391,
76
+ "verse_ict": 2949,
77
+ "prose_q": 6939,
78
+ "continuation": 12904,
79
+ "neighbour": 14350,
80
+ "total": 41533
81
+ },
82
+ "common": {
83
+ "epochs": 2,
84
+ "batch_size": 256,
85
+ "warmup": "10% of steps, linear decay",
86
+ "weight_decay": 0.01,
87
+ "loss": "CachedMultipleNegativesRankingLoss(scale=20.0, mini_batch_size=mini)",
88
+ "seed": 20261001,
89
+ "prefixes_e5": {
90
+ "title, verse_ict, prose_q, continuation": [
91
+ "query: ",
92
+ "passage: "
93
+ ],
94
+ "neighbour": [
95
+ "query: ",
96
+ "query: "
97
+ ]
98
+ },
99
+ "mixed_precision": "bf16 on GPUs with compute capability >= 8 (A100)",
100
+ "saved_dtype": "float16"
101
+ },
102
+ "released": {
103
+ "name": "r2-e5l",
104
+ "weights": "1068 MB fp16"
105
+ }
106
+ }
make_charts.py ADDED
@@ -0,0 +1,402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Benchmark images for Hindko Embeddings (model card), in the style of the Hindko Tokenizer charts.
2
+
3
+ Every score is read from eval/results.csv and eval/selection.json in this folder; nothing is typed in by hand
4
+ except the task sizes (HindkoEmbedBench v1.0 description) and the parameter counts of the public models (PARAMS).
5
+ Writes benchmarks/<nn>_<name>.png (3200 x 1800): HTML pages rendered by headless Chrome at 2x, with the Google
6
+ Fonts embedded so they always load.
7
+
8
+ python make_charts.py # all charts
9
+ python make_charts.py 00,03 # only these
10
+ python make_charts.py --keep-html
11
+ """
12
+ import base64
13
+ import csv
14
+ import json
15
+ import os
16
+ import re
17
+ import shutil
18
+ import subprocess
19
+ import sys
20
+ import urllib.request
21
+
22
+ sys.dont_write_bytecode = True
23
+ HERE = os.path.dirname(os.path.abspath(__file__))
24
+ EVAL = os.path.join(HERE, 'eval')
25
+ OUT = os.path.join(HERE, 'benchmarks')
26
+ WORK = os.path.join(HERE, '.render') # HTML sources and the Chrome profile; removed afterwards
27
+ CHROME = (os.environ.get('CHROME') or shutil.which('chrome') or shutil.which('google-chrome') or shutil.which('chromium')
28
+ or os.path.join(os.environ.get('PROGRAMFILES', ''), 'Google', 'Chrome', 'Application', 'chrome.exe'))
29
+ UA = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0 Safari/537.36'}
30
+ W, H = 1600, 900
31
+
32
+ # ------------------------------------------------------------------------------------------------ data
33
+ R = {}
34
+ for r in csv.DictReader(open(os.path.join(EVAL, 'results.csv'), encoding='utf-8')):
35
+ R[(r['model_id'], r['split'])] = r
36
+ SEL = json.load(open(os.path.join(EVAL, 'selection.json'), encoding='utf-8'))
37
+
38
+ OURS = SEL['selected'] # r2-e5l
39
+ RUNNER = SEL['runner_up'] # r2-e5b
40
+ TFIDF = 'tfidf-char2-4'
41
+ R1 = 'r1-ft-e5-base' # round-1 model (selected in round 1)
42
+ R1S = 'r1-ft-e5-small'
43
+ BGE = 'BAAI/bge-m3'
44
+ E5L = 'intfloat/multilingual-e5-large'
45
+ POOL_ID = {'ft-e5-base': R1, 'ft-e5-small': R1S} # selection.json names -> results.csv model_id
46
+ TASKS = ['HeadlineRetrieval', 'BookTitleRetrieval', 'PassageContinuation', 'VerseProseClassification', 'BookClustering']
47
+ TASK_LABEL = {'overall': ('Overall', 'mean of 5'), 'HeadlineRetrieval': ('Headline', 'nDCG@10'),
48
+ 'BookTitleRetrieval': ('Book title', 'nDCG@10'), 'PassageContinuation': ('Continuation', 'nDCG@10'),
49
+ 'VerseProseClassification': ('Verse / prose', 'macro-F1'), 'BookClustering': ('Book clustering', 'V-measure')}
50
+ # HindkoEmbedBench v1.0 task sizes (benchmark description)
51
+ SIZES = {'dev': '85 headline, 262 book-title and 416 continuation queries; 297 verse/prose and 355 clustering items',
52
+ 'test': '80 headline, 28 book-title and 360 continuation queries; 157 verse/prose and 176 clustering items'}
53
+ # parameters in millions: e5-small/-base and mpnet counted from their safetensors; e5-large, bge-m3, LaBSE and
54
+ # Qwen3-Embedding-0.6B as listed on their Hugging Face model pages. Fine-tuning does not change the count.
55
+ PARAMS = {'intfloat/multilingual-e5-small': 118, 'intfloat/multilingual-e5-base': 278, 'intfloat/multilingual-e5-large': 560,
56
+ 'BAAI/bge-m3': 568, 'sentence-transformers/LaBSE': 471, 'Qwen/Qwen3-Embedding-0.6B': 596,
57
+ 'sentence-transformers/paraphrase-multilingual-mpnet-base-v2': 278}
58
+
59
+ PUBLIC = [(m, s) for (m, s), r in R.items() if r['kind'] == 'public' and s == 'test']
60
+
61
+
62
+ def v(mid, split, col='overall'):
63
+ return float(R[(mid, split)][col])
64
+
65
+
66
+ def f3(x):
67
+ return '%.3f' % x
68
+
69
+
70
+ def f4(x):
71
+ return '%.4f' % x
72
+
73
+
74
+ def short(mid):
75
+ return mid.split('/')[-1]
76
+
77
+
78
+ # ------------------------------------------------------------------------------------------------ page
79
+ CSS = """
80
+ :root{--ink:#0F172A;--muted:#5B6576;--grid:#E4E8EE;--accent:#2F6FDB;--accent-ink:#1D4FA8;--bar:#C9D0DA;--soft:#EAF1FC}
81
+ *{box-sizing:border-box}
82
+ html,body{margin:0;width:%(W)dpx;height:%(H)dpx;overflow:hidden;background:#FFFFFF;color:var(--ink);font-family:'IBM Plex Sans',sans-serif}
83
+ .page{position:absolute;inset:0;padding:56px 80px 0}
84
+ .eyebrow{font-size:17px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--accent)}
85
+ h1{font-family:'Source Serif 4',serif;font-weight:600;font-size:54px;line-height:1.08;letter-spacing:-.015em;margin:12px 0 10px}
86
+ .sub{font-size:23px;line-height:1.4;color:var(--muted);max-width:1400px;margin:0}
87
+ .foot{position:absolute;left:80px;right:80px;bottom:34px;display:flex;justify-content:space-between;gap:40px;font-size:16px;color:var(--muted);border-top:1px solid var(--grid);padding-top:14px}
88
+ .foot b{color:var(--ink);font-weight:600}
89
+ .bars{margin-top:30px}
90
+ .row{display:grid;grid-template-columns:380px 1fr 120px;align-items:center;column-gap:22px;height:%(rowh)dpx}
91
+ .lab{font-size:21px;line-height:1.15;text-align:right}
92
+ .lab small{display:block;font-size:15px;color:var(--muted)}
93
+ .trk{position:relative;height:%(barh)dpx}
94
+ .fill{position:absolute;left:0;top:0;bottom:0;background:var(--bar);border-radius:0 4px 4px 0}
95
+ .val{font-size:21px;font-variant-numeric:tabular-nums;color:var(--ink)}
96
+ .row.me .lab{font-weight:700}.row.me .fill{background:var(--accent)}.row.me .val{font-weight:700;color:var(--accent-ink)}
97
+ .row.ref .fill{background:#8E9AAB}
98
+ .gl{position:absolute;top:-8px;bottom:-8px;border-left:1px dashed var(--grid)}
99
+ table{border-collapse:collapse;width:100%%;margin-top:30px;font-variant-numeric:tabular-nums}
100
+ th{font-size:15px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);text-align:right;padding:0 18px 12px;border-bottom:2px solid var(--ink);vertical-align:bottom}
101
+ th small{display:block;font-size:13px;letter-spacing:.02em;text-transform:none;font-weight:400}
102
+ th:first-child,td:first-child{text-align:left;padding-left:0}
103
+ td{font-size:22px;text-align:right;padding:13px 18px;border-bottom:1px solid var(--grid)}
104
+ td small{font-size:15px;color:var(--muted);margin-left:8px;font-weight:400}
105
+ td .best{border-bottom:3px solid currentColor;padding-bottom:1px}
106
+ tr.me td{font-weight:700;color:var(--accent-ink);background:var(--soft)}
107
+ tr.me td:first-child{padding-left:14px;border-radius:6px 0 0 6px}
108
+ .legend{display:flex;gap:34px;font-size:19px;margin-top:26px}
109
+ .legend span{display:inline-flex;align-items:center;gap:10px}
110
+ .legend i{display:inline-block;width:22px;height:16px;border-radius:3px}
111
+ .note{font-size:19px;line-height:1.45;color:var(--muted);max-width:1440px;margin-top:18px}
112
+ """
113
+
114
+ HEAD = ('<!doctype html><html><head><meta charset="utf-8">'
115
+ '<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;600;700'
116
+ '&family=Source+Serif+4:opsz,wght@8..60,600&display=block">'
117
+ '<style>%s</style></head><body><div class="page">')
118
+
119
+
120
+ def page(title, sub, body, foot_left, rowh=52, barh=30):
121
+ return (HEAD % (CSS % dict(W=W, H=H, rowh=rowh, barh=barh)) +
122
+ '<div class="eyebrow">Hindko Embeddings &middot; Benchmarks</div><h1>%s</h1><p class="sub">%s</p>%s'
123
+ '<div class="foot"><span>%s</span><span style="white-space:nowrap">huggingface.co/junaid008/hindko-embeddings</span></div></div></body></html>'
124
+ % (title, sub, body, foot_left))
125
+
126
+
127
+ def foot(split, extra=''):
128
+ name = 'Test split, scored once after selection on dev' if split == 'test' else 'Dev (validation) split'
129
+ return '<b>HindkoEmbedBench v1.0 &middot; %s</b>%s' % (name, extra)
130
+
131
+
132
+ def bars(items, vmax, grid=()):
133
+ """items: (label, sublabel, value, value_html, cls) with cls '', 'me' or 'ref'."""
134
+ out = ['<div class="bars">']
135
+ for lab, sublab, val, vh, cls in items:
136
+ gl = ''.join('<span class="gl" style="left:%.3f%%"></span>' % (100 * g / vmax) for g in grid)
137
+ out.append('<div class="row %s"><div class="lab">%s%s</div><div class="trk">%s<div class="fill" style="width:%.3f%%"></div></div>'
138
+ '<div class="val">%s</div></div>' % (cls, lab, '<small>%s</small>' % sublab if sublab else '', gl, 100 * val / vmax, vh))
139
+ out.append('</div>')
140
+ return ''.join(out)
141
+
142
+
143
+ def legend(series):
144
+ return '<div class="legend">%s</div>' % ''.join('<span><i style="background:%s"></i>%s</span>' % (c, n) for n, c in series)
145
+
146
+
147
+ def grouped(groups, series, vmax=1.0, width=1440, height=470, ticks=(0.2, 0.4, 0.6, 0.8, 1.0), x0=60, label_fmt=f3,
148
+ bar_w=None, gap=10, lab_size=16, below=None):
149
+ """Vertical grouped columns. groups: [(title, subtitle)]; series: [(name, color, [values], bold)]."""
150
+ y0, y1 = 22, height - 70
151
+ plot_w = width - x0 - 10
152
+ gw = plot_w / len(groups)
153
+ n = len(series)
154
+ bw = bar_w or min(64, (gw - 50 - gap * (n - 1)) / n)
155
+ svg = ['<svg viewBox="0 0 %d %d" width="%d" height="%d" style="display:block;margin-top:14px;overflow:visible">' % (width, height, width, height)]
156
+ Y = lambda val: y1 - (y1 - y0) * val / vmax
157
+ for t in ticks:
158
+ svg.append('<line x1="%d" x2="%d" y1="%.1f" y2="%.1f" stroke="#E4E8EE"/><text x="%d" y="%.1f" font-size="15" fill="#5B6576" text-anchor="end">%.1f</text>'
159
+ % (x0, width - 10, Y(t), Y(t), x0 - 10, Y(t) + 5, t))
160
+ svg.append('<line x1="%d" x2="%d" y1="%d" y2="%d" stroke="#0F172A" stroke-width="1.5"/>' % (x0, width - 10, y1, y1))
161
+ for gi, (gt, gs) in enumerate(groups):
162
+ gx = x0 + gi * gw
163
+ total = n * bw + (n - 1) * gap
164
+ bx0 = gx + (gw - total) / 2
165
+ for si, (name, col, vals, bold) in enumerate(series):
166
+ val = vals[gi]
167
+ if val is None:
168
+ continue
169
+ x = bx0 + si * (bw + gap)
170
+ svg.append('<rect x="%.1f" y="%.1f" width="%.1f" height="%.1f" fill="%s" rx="3"/>' % (x, Y(val), bw, y1 - Y(val), col))
171
+ svg.append('<text x="%.1f" y="%.1f" font-size="%d" font-weight="%d" fill="%s" text-anchor="middle">%s</text>'
172
+ % (x + bw / 2, Y(val) - 8, lab_size, 700 if bold else 400, '#1D4FA8' if bold else '#0F172A', label_fmt(val)))
173
+ svg.append('<text x="%.1f" y="%d" font-size="19" font-weight="600" fill="#0F172A" text-anchor="middle">%s</text>' % (gx + gw / 2, y1 + 28, gt))
174
+ svg.append('<text x="%.1f" y="%d" font-size="15" fill="#5B6576" text-anchor="middle">%s</text>' % (gx + gw / 2, y1 + 50, gs))
175
+ if below:
176
+ svg.append(below(gi, gx, gw, y1))
177
+ svg.append('</svg>')
178
+ return ''.join(svg)
179
+
180
+
181
+ # ------------------------------------------------------------------------------------------------ 00 scorecard
182
+ def c00():
183
+ rows = [(OURS, 'Hindko Embeddings', 'this model &middot; 512 tokens'),
184
+ (TFIDF, 'TF-IDF char 2-4-gram', 'lexical reference'),
185
+ (RUNNER, 'Round-2 e5-base fine-tune', 'runner-up on dev &middot; 512 tokens'),
186
+ (R1, 'Round-1 model', 'our e5-base fine-tune &middot; 256 tokens'),
187
+ (R1S, 'Round-1 e5-small fine-tune', '256 tokens'),
188
+ (BGE, 'bge-m3', 'best public model &middot; 512 tokens'),
189
+ (E5L, 'multilingual-e5-large', 'base model, untuned &middot; 512 tokens')]
190
+ rows.sort(key=lambda r: -v(r[0], 'test')) # ranked by overall test score, like the README table
191
+ cols = ['overall'] + TASKS
192
+ best = {c: max(v(m, 'test', c) for m, _, _ in rows) for c in cols}
193
+ head = ''.join('<th>%s<small>%s</small></th>' % TASK_LABEL[c] for c in cols)
194
+ trs = []
195
+ for m, name, sub in rows:
196
+ tds = ''.join('<td>%s</td>' % (('<span class="best">%s</span>' if v(m, 'test', c) == best[c] else '%s') % f3(v(m, 'test', c))) for c in cols)
197
+ trs.append('<tr%s><td>%s<small>%s</small></td>%s</tr>' % (' class="me"' if m == OURS else '', name, sub, tds))
198
+ body = '<table><tr><th>Model</th>%s</tr>%s</table>' % (head, ''.join(trs))
199
+ d_tf = v(OURS, 'test') - v(TFIDF, 'test')
200
+ d_bge = v(OURS, 'test') - v(BGE, 'test')
201
+ body += ('<p class="note">Overall: <b style="color:#0F172A">+%.3f</b> over TF-IDF and <b style="color:#0F172A">+%.3f</b> over bge-m3. '
202
+ 'Ahead of TF-IDF on four of the five tasks; behind it, and behind bge-m3, on book-title retrieval (28 test queries).</p>' % (d_tf, d_bge))
203
+ return page('Hindko Embeddings on the held-out test set',
204
+ 'Five automatic Hindko tasks; higher is better. The best value in each column is underlined.', body,
205
+ foot('test', ' &middot; neural models at max_seq_length 512 unless noted'))
206
+
207
+
208
+ # ------------------------------------------------------------------------------------------------ 01 overall, all models
209
+ def c01():
210
+ items = [('Hindko Embeddings', 'this model &middot; e5-large fine-tune', v(OURS, 'test'), f4(v(OURS, 'test')), 'me'),
211
+ ('Round-1 e5-small fine-tune', 'ours, round 1 &middot; 256 tokens', v(R1S, 'test'), f4(v(R1S, 'test')), ''),
212
+ ('Round-1 model', 'ours, round 1 &middot; e5-base &middot; 256 tokens', v(R1, 'test'), f4(v(R1, 'test')), ''),
213
+ ('Round-2 e5-base fine-tune', 'ours, runner-up on dev', v(RUNNER, 'test'), f4(v(RUNNER, 'test')), ''),
214
+ ('TF-IDF char 2-4-gram', 'lexical reference', v(TFIDF, 'test'), f4(v(TFIDF, 'test')), 'ref')]
215
+ for m, s in PUBLIC:
216
+ items.append((short(m).replace('paraphrase-', ''), 'public, untuned', v(m, 'test'), f4(v(m, 'test')), ''))
217
+ items.sort(key=lambda x: -x[2])
218
+ return page('Overall score on the test set',
219
+ 'Mean of the five task scores for every model tested. Public models run untuned at 512 tokens; higher is better.',
220
+ bars(items, 0.8, grid=(0.2, 0.4, 0.6)) +
221
+ '<div style="display:grid;grid-template-columns:380px 1fr 120px;column-gap:22px;margin-top:2px"><span></span>'
222
+ '<div style="position:relative;height:20px;font-size:15px;color:#5B6576">%s</div><span></span></div>'
223
+ % ''.join('<span style="position:absolute;left:%.3f%%;transform:translateX(-50%%)">%.1f</span>' % (100 * t / 0.8, t) for t in (0.0, 0.2, 0.4, 0.6, 0.8)),
224
+ foot('test', ' &middot; max_seq_length 512, except the round-1 models (256) and TF-IDF'), rowh=47, barh=26)
225
+
226
+
227
+ # ------------------------------------------------------------------------------------------------ 02 per task, test
228
+ def c02():
229
+ cols = ['overall'] + TASKS
230
+ series = [('Hindko Embeddings (this model)', '#2F6FDB', [v(OURS, 'test', c) for c in cols], True),
231
+ ('TF-IDF char 2-4-gram', '#8E9AAB', [v(TFIDF, 'test', c) for c in cols], False),
232
+ ('bge-m3, best public model', '#C9D0DA', [v(BGE, 'test', c) for c in cols], False)]
233
+ body = legend([(n, c) for n, c, _, _ in series]) + grouped([TASK_LABEL[c] for c in cols], series, height=500)
234
+ return page('Per-task scores on the test set',
235
+ 'Ahead of TF-IDF on four of five tasks. On book-title retrieval (only 28 test queries) TF-IDF and bge-m3 score higher.',
236
+ body, foot('test', ' &middot; neural models at max_seq_length 512'))
237
+
238
+
239
+ # ------------------------------------------------------------------------------------------------ 03 dev candidates
240
+ def c03():
241
+ pool = sorted(SEL['dev_scores'].items(), key=lambda kv: -kv[1])
242
+ best = pool[0][1]
243
+ lo, hi = 0.660, 0.720
244
+ X = lambda val: 100 * (val - lo) / (hi - lo)
245
+ sub = {'r2-e5l': 'e5-large &middot; 560M &middot; 512 tokens', 'r2-e5b': 'e5-base &middot; 278M &middot; 512 tokens',
246
+ 'r2-e5b-plain': 'e5-base, no mined negatives or book blocks', 'r2-e5s': 'e5-small &middot; 118M &middot; 512 tokens',
247
+ 'r2-bgem3': 'bge-m3 &middot; 568M &middot; 512 tokens', 'ft-e5-base': 'round-1 model &middot; e5-base &middot; 256 tokens',
248
+ 'ft-e5-small': 'round-1 &middot; e5-small &middot; 256 tokens'}
249
+ tag = {SEL['selected']: 'selected', SEL['runner_up']: 'runner-up', 'ft-e5-base': 'incumbent', 'ft-e5-small': 'incumbent'}
250
+ rows = []
251
+ for name, val in pool:
252
+ me = name == SEL['selected']
253
+ dot = ('<div style="position:absolute;top:50%%;left:0;width:%.3f%%;height:2px;margin-top:-1px;background:%s"></div>'
254
+ '<div style="position:absolute;top:50%%;left:%.3f%%;width:18px;height:18px;margin:-9px 0 0 -9px;border-radius:50%%;background:%s"></div>'
255
+ % (X(val), '#9DB9EA' if me else '#D3D9E1', X(val), '#2F6FDB' if me else '#8E9AAB'))
256
+ rows.append('<div class="row%s" style="grid-template-columns:330px 1fr 230px;height:64px"><div class="lab">%s<small>%s</small></div>'
257
+ '<div class="trk" style="height:30px">%s</div><div class="val">%s<small style="font-size:15px;color:#5B6576;margin-left:10px;font-weight:400">%s</small></div></div>'
258
+ % (' me' if me else '', name, sub[name], dot, f4(val), tag.get(name, '')))
259
+ left = 'calc(330px + 22px + (100%% - 330px - 230px - 44px)*%.5f)'
260
+ band = ('<div style="position:absolute;top:0;bottom:0;left:%s;width:calc((100%% - 330px - 230px - 44px)*%.5f);background:#EAF1FC;border-left:1px solid #9DB9EA;border-right:1px solid #9DB9EA"></div>'
261
+ % (left % (X(best - SEL['tie']) / 100), (X(best) - X(best - SEL['tie'])) / 100))
262
+ tf = v(TFIDF, 'dev')
263
+ ref = ('<div style="position:absolute;top:0;bottom:0;left:%s;border-left:2px dashed #8E9AAB"></div>' % (left % (X(tf) / 100)))
264
+ ticks = ''.join('<span style="position:absolute;left:%s;transform:translateX(-50%%);font-size:15px;color:#5B6576">%.2f</span>' % (left % (X(t) / 100), t)
265
+ for t in (0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72))
266
+ body = ('<div style="position:relative;margin-top:26px">%s%s%s</div><div style="position:relative;height:22px;margin-top:4px">%s</div>'
267
+ '<p class="note" style="margin-top:14px">Shaded: the pre-registered tie band (within %.3f of the best). Only the best model falls in it, so it was selected; '
268
+ 'the runner-up is %.4f below. Dashed line: TF-IDF on dev, %s. Axis starts at 0.66.</p>'
269
+ % (band, ref, ''.join(rows), ticks, SEL['tie'], best - SEL['dev_scores'][SEL['runner_up']], f4(tf)))
270
+ return page('Selected on dev by a fixed rule',
271
+ 'Overall dev score of every model in the selection pool. Rule: highest dev score; within %.3f of it, the smaller model wins.' % SEL['tie'],
272
+ body, foot('dev', ' &middot; round-2 models at 512 tokens in float16; incumbents at their round-1 setting'))
273
+
274
+
275
+ # ------------------------------------------------------------------------------------------------ 04 round 1 vs round 2
276
+ def c04():
277
+ cols = ['overall'] + TASKS
278
+ a = [v(R1, 'test', c) for c in cols]
279
+ b = [v(OURS, 'test', c) for c in cols]
280
+ series = [('Round-1 model (e5-base fine-tune, 256 tokens)', '#9DB9EA', a, False),
281
+ ('Hindko Embeddings, round 2 (e5-large fine-tune, 512 tokens)', '#2F6FDB', b, True)]
282
+
283
+ def below(gi, gx, gw, y1):
284
+ d = float(f3(b[gi])) - float(f3(a[gi])) # from the rounded values printed on the bars
285
+ return ('<text x="%.1f" y="%d" font-size="17" font-weight="700" fill="%s" text-anchor="middle">%s</text>'
286
+ % (gx + gw / 2, y1 + 76, '#1D4FA8' if d >= 0 else '#B4442C', ('%+.3f' % d).replace('-', '&minus;')))
287
+ body = legend([(n, c) for n, c, _, _ in series]) + grouped([TASK_LABEL[c] for c in cols], series, height=500, below=below)
288
+ return page('Round 2 vs round 1',
289
+ 'Test scores, with the change below each group. Round 2 changed the base (e5-base to e5-large), the data (new short-query pairs, mined hard negatives, same-book batches) and the length (256 to 512 tokens).',
290
+ body, foot('test'))
291
+
292
+
293
+ # ------------------------------------------------------------------------------------------------ 05 size vs score
294
+ def c05():
295
+ width, height = 1440, 520
296
+ x0, x1, y0, y1 = 80, 1280, 20, height - 60
297
+ xmax, ylo, yhi = 650, 0.40, 0.75
298
+ X = lambda p: x0 + (x1 - x0) * p / xmax
299
+ Y = lambda s: y1 - (y1 - y0) * (s - ylo) / (yhi - ylo)
300
+ svg = ['<svg viewBox="0 0 %d %d" width="%d" height="%d" style="display:block;margin-top:26px;overflow:visible">' % (width, height, width, height)]
301
+ for t in (0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75):
302
+ svg.append('<line x1="%d" x2="%d" y1="%.1f" y2="%.1f" stroke="#E4E8EE"/><text x="%d" y="%.1f" font-size="15" fill="#5B6576" text-anchor="end">%.2f</text>' % (x0, x1, Y(t), Y(t), x0 - 10, Y(t) + 5, t))
303
+ for p in (0, 100, 200, 300, 400, 500, 600):
304
+ svg.append('<text x="%.1f" y="%d" font-size="15" fill="#5B6576" text-anchor="middle">%d</text>' % (X(p), y1 + 24, p))
305
+ svg.append('<text x="%.1f" y="%d" font-size="16" fill="#5B6576" text-anchor="middle">parameters (millions)</text>' % ((x0 + x1) / 2, y1 + 50))
306
+ svg.append('<text x="18" y="%d" font-size="16" fill="#5B6576" transform="rotate(-90 18 %d)" text-anchor="middle">dev overall score</text>' % ((y0 + y1) // 2, (y0 + y1) // 2))
307
+ tf = v(TFIDF, 'dev')
308
+ svg.append('<line x1="%d" x2="%d" y1="%.1f" y2="%.1f" stroke="#8E9AAB" stroke-width="2" stroke-dasharray="7 6"/>' % (x0, x1, Y(tf), Y(tf)))
309
+ svg.append('<text x="%d" y="%.1f" font-size="16" fill="#5B6576" text-anchor="start">TF-IDF %s</text>' % (x0 + 8, Y(tf) - 8, f4(tf)))
310
+ e5 = ['intfloat/multilingual-e5-small', 'intfloat/multilingual-e5-base', 'intfloat/multilingual-e5-large']
311
+ ft = {'intfloat/multilingual-e5-small': 'r2-e5s', 'intfloat/multilingual-e5-base': 'r2-e5b', 'intfloat/multilingual-e5-large': OURS, BGE: 'r2-bgem3'}
312
+ for ids, col, w in (([ft[m] for m in e5], '#9DB9EA', 3), (e5, '#C9D0DA', 3)):
313
+ pts = ' '.join('%.1f,%.1f' % (X(PARAMS[m if m in PARAMS else [k for k, x in ft.items() if x == m][0]]), Y(v(m, 'dev'))) for m in ids)
314
+ svg.append('<polyline points="%s" fill="none" stroke="%s" stroke-width="%d"/>' % (pts, col, w))
315
+ for base, run in ft.items(): # fine-tuning gain per base: dotted vertical
316
+ svg.append('<line x1="%.1f" x2="%.1f" y1="%.1f" y2="%.1f" stroke="#C9D0DA" stroke-width="1.5" stroke-dasharray="3 4"/>'
317
+ % (X(PARAMS[base]), X(PARAMS[base]), Y(v(base, 'dev')), Y(v(run, 'dev'))))
318
+ # (id, label, dx, dy, anchor, kind)
319
+ pts = [(OURS, 'e5-large fine-tune (this model)', -14, -14, 'end', 'me'), ('r2-bgem3', 'bge-m3 fine-tune', 14, 26, 'start', 'ft'),
320
+ ('r2-e5b', 'e5-base fine-tune', 0, -16, 'middle', 'ft'), ('r2-e5s', 'e5-small fine-tune', 0, -16, 'middle', 'ft'),
321
+ (E5L, 'e5-large', -14, -12, 'end', 'pub'), (BGE, 'bge-m3', 14, -10, 'start', 'pub'),
322
+ ('intfloat/multilingual-e5-base', 'e5-base', 14, -10, 'start', 'pub'), ('intfloat/multilingual-e5-small', 'e5-small', 0, 28, 'middle', 'pub'),
323
+ ('sentence-transformers/LaBSE', 'LaBSE', -14, 6, 'end', 'pub'), ('Qwen/Qwen3-Embedding-0.6B', 'Qwen3-Embedding-0.6B', 14, 6, 'start', 'pub'),
324
+ ('sentence-transformers/paraphrase-multilingual-mpnet-base-v2', 'mpnet-base-v2', 14, 6, 'start', 'pub')]
325
+ inv = {r: b for b, r in ft.items()}
326
+ for mid, lab, dx, dy, anc, kind in pts:
327
+ p = PARAMS[mid] if mid in PARAMS else PARAMS[inv[mid]]
328
+ s = v(mid, 'dev')
329
+ col = {'me': '#2F6FDB', 'ft': '#6F95DE', 'pub': '#8E9AAB'}[kind]
330
+ r = 11 if kind == 'me' else 8
331
+ svg.append('<circle cx="%.1f" cy="%.1f" r="%d" fill="%s" stroke="#FFFFFF" stroke-width="2"/>' % (X(p), Y(s), r, col))
332
+ svg.append('<text x="%.1f" y="%.1f" font-size="%d" font-weight="%d" fill="%s" text-anchor="%s" stroke="#FFFFFF" stroke-width="5" paint-order="stroke">%s '
333
+ '<tspan font-weight="400" fill="#5B6576">%s</tspan></text>'
334
+ % (X(p) + dx, Y(s) + dy, 18 if kind == 'me' else 16, 700 if kind == 'me' else 600, '#1D4FA8' if kind == 'me' else '#0F172A', anc, lab, f4(s)))
335
+ svg.append('</svg>')
336
+ body = (legend([('fine-tuned on Hindko (round 2)', '#6F95DE'), ('public model, untuned', '#8E9AAB'), ('TF-IDF reference', '#8E9AAB')]).replace(
337
+ '<i style="background:#8E9AAB"></i>TF-IDF', '<i style="background:none;border-top:2px dashed #8E9AAB;height:0;width:28px"></i>TF-IDF') + ''.join(svg))
338
+ return page('Fine-tuning matters more than size',
339
+ 'Dev score against model size. Every fine-tuned model scores above every untuned one; among the fine-tuned e5 models the larger ones score slightly higher.',
340
+ body, foot('dev', ' &middot; neural models at max_seq_length 512 in float16; TF-IDF is lexical'))
341
+
342
+
343
+ # ------------------------------------------------------------------------------------------------ 06 book-title detail
344
+ def c06():
345
+ mets = [('BT_R1', 'Recall@1'), ('BT_R10', 'Recall@10'), ('BT_MRR', 'MRR@10'), ('BookTitleRetrieval', 'nDCG@10')]
346
+ panels = []
347
+ for split, title in (('dev', 'Dev: 262 queries'), ('test', 'Test: 28 queries from 5 books')):
348
+ series = [('this model', '#2F6FDB', [v(OURS, split, c) for c, _ in mets], True),
349
+ ('TF-IDF', '#8E9AAB', [v(TFIDF, split, c) for c, _ in mets], False),
350
+ ('bge-m3', '#C9D0DA', [v(BGE, split, c) for c, _ in mets], False)]
351
+ svg = grouped([(lab, '') for _, lab in mets], series, vmax=0.8, width=700, height=430, ticks=(0.2, 0.4, 0.6, 0.8), x0=50,
352
+ bar_w=44, gap=6, lab_size=15)
353
+ panels.append('<div><div style="font-size:22px;font-weight:600;margin-top:6px">%s</div>%s</div>' % (title, svg))
354
+ body = (legend([('Hindko Embeddings (this model)', '#2F6FDB'), ('TF-IDF char 2-4-gram', '#8E9AAB'), ('bge-m3 (untuned, 512 tokens)', '#C9D0DA')]) +
355
+ '<div style="display:grid;grid-template-columns:1fr 1fr;gap:40px">%s</div>' % ''.join(panels) +
356
+ '<p class="note" style="margin-top:0">The test set has only 28 queries (57 relevant passages), so its numbers are noisy; the dev gap to TF-IDF points the same way.</p>')
357
+ return page('Weak spot: finding a passage from its book title',
358
+ 'BookTitleRetrieval: a table-of-contents title (often the first line of a poem) must retrieve its passage. TF-IDF beats this model on nDCG@10 on both dev and test.',
359
+ body, foot('test', '; dev panel on the dev split &middot; neural models at max_seq_length 512'))
360
+
361
+
362
+ CHARTS = [('00_scorecard', c00), ('01_test_overall_all_models', c01), ('02_test_per_task', c02), ('03_dev_candidates', c03),
363
+ ('04_round1_vs_round2', c04), ('05_size_vs_score', c05), ('06_booktitle_detail', c06)]
364
+
365
+
366
+ def embed_fonts(html):
367
+ for m in re.finditer(r'<link[^>]+href="(https://fonts.googleapis.com/css2?[^"]+)"[^>]*>', html):
368
+ url = m.group(1).replace('&amp;', '&')
369
+ css = urllib.request.urlopen(urllib.request.Request(url, headers=UA), timeout=30).read().decode()
370
+ for u in sorted(set(re.findall(r'url\((https://fonts.gstatic.com/[^)]+)\)', css))):
371
+ data = urllib.request.urlopen(urllib.request.Request(u, headers=UA), timeout=60).read()
372
+ css = css.replace(u, 'data:font/woff2;base64,' + base64.b64encode(data).decode())
373
+ html = html.replace(m.group(0), '<style>' + css + '</style>')
374
+ return html
375
+
376
+
377
+ def main():
378
+ args = [a for a in sys.argv[1:] if not a.startswith('--')]
379
+ keep = '--keep-html' in sys.argv
380
+ only = args[0].split(',') if args else None
381
+ os.makedirs(OUT, exist_ok=True)
382
+ os.makedirs(WORK, exist_ok=True)
383
+ env = dict(os.environ, TEMP=WORK, TMP=WORK)
384
+ try:
385
+ for name, fn in CHARTS:
386
+ if only and name[:2] not in only:
387
+ continue
388
+ html = os.path.join(WORK, name + '.html')
389
+ open(html, 'w', encoding='utf-8', newline='\n').write(embed_fonts(fn()))
390
+ png = os.path.join(OUT, name + '.png')
391
+ subprocess.run([CHROME, '--headless=new', '--disable-gpu', '--hide-scrollbars', '--force-device-scale-factor=2',
392
+ '--user-data-dir=' + os.path.join(WORK, 'chrome'), '--no-first-run', '--disable-crash-reporter',
393
+ '--window-size=%d,%d' % (W, H), '--virtual-time-budget=20000', '--screenshot=' + png,
394
+ 'file:///' + html.replace('\\', '/')], check=True, capture_output=True, timeout=300, env=env)
395
+ print(name)
396
+ finally:
397
+ if not keep:
398
+ shutil.rmtree(WORK, ignore_errors=True)
399
+
400
+
401
+ if __name__ == '__main__':
402
+ main()
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f14d62eff2fd75d55322ecce26b5b38818f9fd66a155370551fdaad93d86278b
3
+ size 1119825632
modules.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "idx": 0,
4
+ "name": "0",
5
+ "path": "",
6
+ "type": "sentence_transformers.base.modules.transformer.Transformer"
7
+ },
8
+ {
9
+ "idx": 1,
10
+ "name": "1",
11
+ "path": "1_Pooling",
12
+ "type": "sentence_transformers.sentence_transformer.modules.pooling.Pooling"
13
+ },
14
+ {
15
+ "idx": 2,
16
+ "name": "2",
17
+ "path": "2_Normalize",
18
+ "type": "sentence_transformers.base.modules.normalize.Normalize"
19
+ }
20
+ ]
sentence_bert_config.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "transformer_task": "feature-extraction",
3
+ "modality_config": {
4
+ "text": {
5
+ "method": "forward",
6
+ "method_output_name": "last_hidden_state"
7
+ }
8
+ },
9
+ "module_output_name": "token_embeddings"
10
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:883b037111086fd4dfebbbc9b7cee11e1517b5e0c0514879478661440f137085
3
+ size 17082987
tokenizer_config.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": true,
3
+ "backend": "tokenizers",
4
+ "bos_token": "<s>",
5
+ "clean_up_tokenization_spaces": true,
6
+ "cls_token": "<s>",
7
+ "eos_token": "</s>",
8
+ "is_local": true,
9
+ "mask_token": "<mask>",
10
+ "max_length": 512,
11
+ "model_max_length": 512,
12
+ "pad_to_multiple_of": null,
13
+ "pad_token": "<pad>",
14
+ "pad_token_type_id": 0,
15
+ "padding_side": "right",
16
+ "sep_token": "</s>",
17
+ "stride": 0,
18
+ "tokenizer_class": "XLMRobertaTokenizer",
19
+ "truncation_side": "right",
20
+ "truncation_strategy": "longest_first",
21
+ "unk_token": "<unk>"
22
+ }