minsik-oh commited on
Commit
dd9391b
·
verified ·
1 Parent(s): aa9aaac

Release reproduced country-specific SCPO DeBERTa checkpoint

Browse files
LICENSE ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Attribution-NonCommercial 4.0 International
2
+
3
+ =======================================================================
4
+
5
+ Creative Commons Corporation ("Creative Commons") is not a law firm and
6
+ does not provide legal services or legal advice. Distribution of
7
+ Creative Commons public licenses does not create a lawyer-client or
8
+ other relationship. Creative Commons makes its licenses and related
9
+ information available on an "as-is" basis. Creative Commons gives no
10
+ warranties regarding its licenses, any material licensed under their
11
+ terms and conditions, or any related information. Creative Commons
12
+ disclaims all liability for damages resulting from their use to the
13
+ fullest extent possible.
14
+
15
+ Using Creative Commons Public Licenses
16
+
17
+ Creative Commons public licenses provide a standard set of terms and
18
+ conditions that creators and other rights holders may use to share
19
+ original works of authorship and other material subject to copyright
20
+ and certain other rights specified in the public license below. The
21
+ following considerations are for informational purposes only, are not
22
+ exhaustive, and do not form part of our licenses.
23
+
24
+ Considerations for licensors: Our public licenses are
25
+ intended for use by those authorized to give the public
26
+ permission to use material in ways otherwise restricted by
27
+ copyright and certain other rights. Our licenses are
28
+ irrevocable. Licensors should read and understand the terms
29
+ and conditions of the license they choose before applying it.
30
+ Licensors should also secure all rights necessary before
31
+ applying our licenses so that the public can reuse the
32
+ material as expected. Licensors should clearly mark any
33
+ material not subject to the license. This includes other CC-
34
+ licensed material, or material used under an exception or
35
+ limitation to copyright. More considerations for licensors:
36
+ wiki.creativecommons.org/Considerations_for_licensors
37
+
38
+ Considerations for the public: By using one of our public
39
+ licenses, a licensor grants the public permission to use the
40
+ licensed material under specified terms and conditions. If
41
+ the licensor's permission is not necessary for any reason--for
42
+ example, because of any applicable exception or limitation to
43
+ copyright--then that use is not regulated by the license. Our
44
+ licenses grant only permissions under copyright and certain
45
+ other rights that a licensor has authority to grant. Use of
46
+ the licensed material may still be restricted for other
47
+ reasons, including because others have copyright or other
48
+ rights in the material. A licensor may make special requests,
49
+ such as asking that all changes be marked or described.
50
+ Although not required by our licenses, you are encouraged to
51
+ respect those requests where reasonable. More considerations
52
+ for the public:
53
+ wiki.creativecommons.org/Considerations_for_licensees
54
+
55
+ =======================================================================
56
+
57
+ Creative Commons Attribution-NonCommercial 4.0 International Public
58
+ License
59
+
60
+ By exercising the Licensed Rights (defined below), You accept and agree
61
+ to be bound by the terms and conditions of this Creative Commons
62
+ Attribution-NonCommercial 4.0 International Public License ("Public
63
+ License"). To the extent this Public License may be interpreted as a
64
+ contract, You are granted the Licensed Rights in consideration of Your
65
+ acceptance of these terms and conditions, and the Licensor grants You
66
+ such rights in consideration of benefits the Licensor receives from
67
+ making the Licensed Material available under these terms and
68
+ conditions.
69
+
70
+
71
+ Section 1 -- Definitions.
72
+
73
+ a. Adapted Material means material subject to Copyright and Similar
74
+ Rights that is derived from or based upon the Licensed Material
75
+ and in which the Licensed Material is translated, altered,
76
+ arranged, transformed, or otherwise modified in a manner requiring
77
+ permission under the Copyright and Similar Rights held by the
78
+ Licensor. For purposes of this Public License, where the Licensed
79
+ Material is a musical work, performance, or sound recording,
80
+ Adapted Material is always produced where the Licensed Material is
81
+ synched in timed relation with a moving image.
82
+
83
+ b. Adapter's License means the license You apply to Your Copyright
84
+ and Similar Rights in Your contributions to Adapted Material in
85
+ accordance with the terms and conditions of this Public License.
86
+
87
+ c. Copyright and Similar Rights means copyright and/or similar rights
88
+ closely related to copyright including, without limitation,
89
+ performance, broadcast, sound recording, and Sui Generis Database
90
+ Rights, without regard to how the rights are labeled or
91
+ categorized. For purposes of this Public License, the rights
92
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
93
+ Rights.
94
+ d. Effective Technological Measures means those measures that, in the
95
+ absence of proper authority, may not be circumvented under laws
96
+ fulfilling obligations under Article 11 of the WIPO Copyright
97
+ Treaty adopted on December 20, 1996, and/or similar international
98
+ agreements.
99
+
100
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
101
+ any other exception or limitation to Copyright and Similar Rights
102
+ that applies to Your use of the Licensed Material.
103
+
104
+ f. Licensed Material means the artistic or literary work, database,
105
+ or other material to which the Licensor applied this Public
106
+ License.
107
+
108
+ g. Licensed Rights means the rights granted to You subject to the
109
+ terms and conditions of this Public License, which are limited to
110
+ all Copyright and Similar Rights that apply to Your use of the
111
+ Licensed Material and that the Licensor has authority to license.
112
+
113
+ h. Licensor means the individual(s) or entity(ies) granting rights
114
+ under this Public License.
115
+
116
+ i. NonCommercial means not primarily intended for or directed towards
117
+ commercial advantage or monetary compensation. For purposes of
118
+ this Public License, the exchange of the Licensed Material for
119
+ other material subject to Copyright and Similar Rights by digital
120
+ file-sharing or similar means is NonCommercial provided there is
121
+ no payment of monetary compensation in connection with the
122
+ exchange.
123
+
124
+ j. Share means to provide material to the public by any means or
125
+ process that requires permission under the Licensed Rights, such
126
+ as reproduction, public display, public performance, distribution,
127
+ dissemination, communication, or importation, and to make material
128
+ available to the public including in ways that members of the
129
+ public may access the material from a place and at a time
130
+ individually chosen by them.
131
+
132
+ k. Sui Generis Database Rights means rights other than copyright
133
+ resulting from Directive 96/9/EC of the European Parliament and of
134
+ the Council of 11 March 1996 on the legal protection of databases,
135
+ as amended and/or succeeded, as well as other essentially
136
+ equivalent rights anywhere in the world.
137
+
138
+ l. You means the individual or entity exercising the Licensed Rights
139
+ under this Public License. Your has a corresponding meaning.
140
+
141
+
142
+ Section 2 -- Scope.
143
+
144
+ a. License grant.
145
+
146
+ 1. Subject to the terms and conditions of this Public License,
147
+ the Licensor hereby grants You a worldwide, royalty-free,
148
+ non-sublicensable, non-exclusive, irrevocable license to
149
+ exercise the Licensed Rights in the Licensed Material to:
150
+
151
+ a. reproduce and Share the Licensed Material, in whole or
152
+ in part, for NonCommercial purposes only; and
153
+
154
+ b. produce, reproduce, and Share Adapted Material for
155
+ NonCommercial purposes only.
156
+
157
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
158
+ Exceptions and Limitations apply to Your use, this Public
159
+ License does not apply, and You do not need to comply with
160
+ its terms and conditions.
161
+
162
+ 3. Term. The term of this Public License is specified in Section
163
+ 6(a).
164
+
165
+ 4. Media and formats; technical modifications allowed. The
166
+ Licensor authorizes You to exercise the Licensed Rights in
167
+ all media and formats whether now known or hereafter created,
168
+ and to make technical modifications necessary to do so. The
169
+ Licensor waives and/or agrees not to assert any right or
170
+ authority to forbid You from making technical modifications
171
+ necessary to exercise the Licensed Rights, including
172
+ technical modifications necessary to circumvent Effective
173
+ Technological Measures. For purposes of this Public License,
174
+ simply making modifications authorized by this Section 2(a)
175
+ (4) never produces Adapted Material.
176
+
177
+ 5. Downstream recipients.
178
+
179
+ a. Offer from the Licensor -- Licensed Material. Every
180
+ recipient of the Licensed Material automatically
181
+ receives an offer from the Licensor to exercise the
182
+ Licensed Rights under the terms and conditions of this
183
+ Public License.
184
+
185
+ b. No downstream restrictions. You may not offer or impose
186
+ any additional or different terms or conditions on, or
187
+ apply any Effective Technological Measures to, the
188
+ Licensed Material if doing so restricts exercise of the
189
+ Licensed Rights by any recipient of the Licensed
190
+ Material.
191
+
192
+ 6. No endorsement. Nothing in this Public License constitutes or
193
+ may be construed as permission to assert or imply that You
194
+ are, or that Your use of the Licensed Material is, connected
195
+ with, or sponsored, endorsed, or granted official status by,
196
+ the Licensor or others designated to receive attribution as
197
+ provided in Section 3(a)(1)(A)(i).
198
+
199
+ b. Other rights.
200
+
201
+ 1. Moral rights, such as the right of integrity, are not
202
+ licensed under this Public License, nor are publicity,
203
+ privacy, and/or other similar personality rights; however, to
204
+ the extent possible, the Licensor waives and/or agrees not to
205
+ assert any such rights held by the Licensor to the limited
206
+ extent necessary to allow You to exercise the Licensed
207
+ Rights, but not otherwise.
208
+
209
+ 2. Patent and trademark rights are not licensed under this
210
+ Public License.
211
+
212
+ 3. To the extent possible, the Licensor waives any right to
213
+ collect royalties from You for the exercise of the Licensed
214
+ Rights, whether directly or through a collecting society
215
+ under any voluntary or waivable statutory or compulsory
216
+ licensing scheme. In all other cases the Licensor expressly
217
+ reserves any right to collect such royalties, including when
218
+ the Licensed Material is used other than for NonCommercial
219
+ purposes.
220
+
221
+
222
+ Section 3 -- License Conditions.
223
+
224
+ Your exercise of the Licensed Rights is expressly made subject to the
225
+ following conditions.
226
+
227
+ a. Attribution.
228
+
229
+ 1. If You Share the Licensed Material (including in modified
230
+ form), You must:
231
+
232
+ a. retain the following if it is supplied by the Licensor
233
+ with the Licensed Material:
234
+
235
+ i. identification of the creator(s) of the Licensed
236
+ Material and any others designated to receive
237
+ attribution, in any reasonable manner requested by
238
+ the Licensor (including by pseudonym if
239
+ designated);
240
+
241
+ ii. a copyright notice;
242
+
243
+ iii. a notice that refers to this Public License;
244
+
245
+ iv. a notice that refers to the disclaimer of
246
+ warranties;
247
+
248
+ v. a URI or hyperlink to the Licensed Material to the
249
+ extent reasonably practicable;
250
+
251
+ b. indicate if You modified the Licensed Material and
252
+ retain an indication of any previous modifications; and
253
+
254
+ c. indicate the Licensed Material is licensed under this
255
+ Public License, and include the text of, or the URI or
256
+ hyperlink to, this Public License.
257
+
258
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
259
+ reasonable manner based on the medium, means, and context in
260
+ which You Share the Licensed Material. For example, it may be
261
+ reasonable to satisfy the conditions by providing a URI or
262
+ hyperlink to a resource that includes the required
263
+ information.
264
+
265
+ 3. If requested by the Licensor, You must remove any of the
266
+ information required by Section 3(a)(1)(A) to the extent
267
+ reasonably practicable.
268
+
269
+ 4. If You Share Adapted Material You produce, the Adapter's
270
+ License You apply must not prevent recipients of the Adapted
271
+ Material from complying with this Public License.
272
+
273
+
274
+ Section 4 -- Sui Generis Database Rights.
275
+
276
+ Where the Licensed Rights include Sui Generis Database Rights that
277
+ apply to Your use of the Licensed Material:
278
+
279
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
280
+ to extract, reuse, reproduce, and Share all or a substantial
281
+ portion of the contents of the database for NonCommercial purposes
282
+ only;
283
+
284
+ b. if You include all or a substantial portion of the database
285
+ contents in a database in which You have Sui Generis Database
286
+ Rights, then the database in which You have Sui Generis Database
287
+ Rights (but not its individual contents) is Adapted Material; and
288
+
289
+ c. You must comply with the conditions in Section 3(a) if You Share
290
+ all or a substantial portion of the contents of the database.
291
+
292
+ For the avoidance of doubt, this Section 4 supplements and does not
293
+ replace Your obligations under this Public License where the Licensed
294
+ Rights include other Copyright and Similar Rights.
295
+
296
+
297
+ Section 5 -- Disclaimer of Warranties and Limitation of Liability.
298
+
299
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
300
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
301
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
302
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
303
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
304
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
305
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
306
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
307
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
308
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
309
+
310
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
311
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
312
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
313
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
314
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
315
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
316
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
317
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
318
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
319
+
320
+ c. The disclaimer of warranties and limitation of liability provided
321
+ above shall be interpreted in a manner that, to the extent
322
+ possible, most closely approximates an absolute disclaimer and
323
+ waiver of all liability.
324
+
325
+
326
+ Section 6 -- Term and Termination.
327
+
328
+ a. This Public License applies for the term of the Copyright and
329
+ Similar Rights licensed here. However, if You fail to comply with
330
+ this Public License, then Your rights under this Public License
331
+ terminate automatically.
332
+
333
+ b. Where Your right to use the Licensed Material has terminated under
334
+ Section 6(a), it reinstates:
335
+
336
+ 1. automatically as of the date the violation is cured, provided
337
+ it is cured within 30 days of Your discovery of the
338
+ violation; or
339
+
340
+ 2. upon express reinstatement by the Licensor.
341
+
342
+ For the avoidance of doubt, this Section 6(b) does not affect any
343
+ right the Licensor may have to seek remedies for Your violations
344
+ of this Public License.
345
+
346
+ c. For the avoidance of doubt, the Licensor may also offer the
347
+ Licensed Material under separate terms or conditions or stop
348
+ distributing the Licensed Material at any time; however, doing so
349
+ will not terminate this Public License.
350
+
351
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
352
+ License.
353
+
354
+
355
+ Section 7 -- Other Terms and Conditions.
356
+
357
+ a. The Licensor shall not be bound by any additional or different
358
+ terms or conditions communicated by You unless expressly agreed.
359
+
360
+ b. Any arrangements, understandings, or agreements regarding the
361
+ Licensed Material not stated herein are separate from and
362
+ independent of the terms and conditions of this Public License.
363
+
364
+
365
+ Section 8 -- Interpretation.
366
+
367
+ a. For the avoidance of doubt, this Public License does not, and
368
+ shall not be interpreted to, reduce, limit, restrict, or impose
369
+ conditions on any use of the Licensed Material that could lawfully
370
+ be made without permission under this Public License.
371
+
372
+ b. To the extent possible, if any provision of this Public License is
373
+ deemed unenforceable, it shall be automatically reformed to the
374
+ minimum extent necessary to make it enforceable. If the provision
375
+ cannot be reformed, it shall be severed from this Public License
376
+ without affecting the enforceability of the remaining terms and
377
+ conditions.
378
+
379
+ c. No term or condition of this Public License will be waived and no
380
+ failure to comply consented to unless expressly agreed to by the
381
+ Licensor.
382
+
383
+ d. Nothing in this Public License constitutes or may be interpreted
384
+ as a limitation upon, or waiver of, any privileges and immunities
385
+ that apply to the Licensor or You, including from the legal
386
+ processes of any jurisdiction or authority.
387
+
388
+ =======================================================================
389
+
390
+ Creative Commons is not a party to its public
391
+ licenses. Notwithstanding, Creative Commons may elect to apply one of
392
+ its public licenses to material it publishes and in those instances
393
+ will be considered the “Licensor.” The text of the Creative Commons
394
+ public licenses is dedicated to the public domain under the CC0 Public
395
+ Domain Dedication. Except for the limited purpose of indicating that
396
+ material is shared under a Creative Commons public license or as
397
+ otherwise permitted by the Creative Commons policies published at
398
+ creativecommons.org/policies, Creative Commons does not authorize the
399
+ use of the trademark "Creative Commons" or any other trademark or logo
400
+ of Creative Commons without its prior written consent including,
401
+ without limitation, in connection with any unauthorized modifications
402
+ to any of its public licenses or any other arrangements,
403
+ understandings, or agreements concerning use of licensed material. For
404
+ the avoidance of doubt, this paragraph does not form part of the
405
+ public licenses.
406
+
407
+ Creative Commons may be contacted at creativecommons.org.
408
+
README.md ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: cc-by-nc-4.0
3
+ library_name: transformers
4
+ pipeline_tag: text-classification
5
+ base_model: OpenAssistant/reward-model-deberta-v3-base
6
+ base_model_relation: finetune
7
+ datasets:
8
+ - HannahRoseKirk/prism-alignment
9
+ language:
10
+ - en
11
+ tags:
12
+ - reward-model
13
+ - scpo
14
+ - cultural-alignment
15
+ - canada
16
+ - arxiv:2606.18606
17
+ ---
18
+ # SCPO DeBERTa-v3-base — Canada
19
+
20
+ A scalar reward model fine-tuned on PRISM preference pairs from participants
21
+ residing in Canada. Higher scores indicate a preferred response for the
22
+ same prompt. Scores are not probabilities and are not calibrated across models.
23
+
24
+ [Paper](https://arxiv.org/abs/2606.18606) ·
25
+ [Code](https://github.com/minsik-ai/Steerable-Cultural-Preference)
26
+
27
+ ## Recorded experiment results
28
+
29
+ | Measurement | Accuracy |
30
+ |---|---:|
31
+ | Starting global model, overall | 60.4046% |
32
+ | Selected checkpoint, overall | 66.1850% |
33
+ | Selected checkpoint, reference-misranked subset | 27.7372% |
34
+
35
+ These are original in-memory post-training experiment scores, with no model-mode
36
+ or random-state reset before scoring. A fresh `eval()` inference session disables
37
+ dropout and may produce different accuracy. `validation.json` checks loading and
38
+ finite, repeatable inference on generic probes; it is not a benchmark result.
39
+
40
+ The country configuration was selected through exploratory trials on a fixed
41
+ test split. It is not an unbiased held-out estimate or the paper's three-run mean.
42
+ The independent execution rerun reproduced the selected recorded accuracy.
43
+ The reference-misranked subset consists of pairs strictly misranked by this base
44
+ model, excluding tied reference scores. Different backbones have different subsets.
45
+
46
+ ## Training and reproduction
47
+
48
+ - Full-model fine-tuning from `OpenAssistant/reward-model-deberta-v3-base`.
49
+ - Base revision: `7dab4156e63944834c3aae169c3fe83955672cff`.
50
+ - PRISM revision: `18ab5cfb37456f4ec8cbc00212ce54cf7b1239f6`.
51
+ - Learning rate: `1e-06`; batch size: 8; optimizer steps: 1024.
52
+ - Filtering tau: 0.7; weighting beta: 1.1.
53
+ - Data shuffle seed: 0; survey split/model seed: 0;
54
+ Trainer seed: 42; Trainer data seed: unset.
55
+ - Survey users split 85/15; human-rating ties excluded from preference pairs.
56
+ - Original training inputs use literal `prompt + " [SEP] " + response`, capped
57
+ and padded to 512 tokens. Original scoring uses tokenizer prompt/response pairs
58
+ in interaction batches of at most eight with no explicit truncation.
59
+
60
+ See `release-settings.json`, `provenance.json`, and `requirements-pw-lock.txt`.
61
+ The exact country script and unchanged trainer/collator are included under
62
+ `reproduction/`. With the recorded environment installed, run:
63
+
64
+ ```bash
65
+ python reproduction/preferences.py ./reproduction-output
66
+ ```
67
+
68
+ Original loaders use upstream `main`; verify the recorded model/data revisions
69
+ before rerunning. No private dataset records are bundled.
70
+
71
+ ## Inference
72
+
73
+ The following uses standard evaluation-mode inference.
74
+
75
+ ```python
76
+ import torch
77
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer
78
+
79
+ model_id = "MulticulturalAlignment/scpo-deberta-v3-base-canada"
80
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
81
+ model = AutoModelForSequenceClassification.from_pretrained(model_id).eval()
82
+ inputs = tokenizer("How can I disagree respectfully?",
83
+ "Listen carefully and explain your reasons calmly.",
84
+ return_tensors="pt")
85
+ with torch.inference_mode():
86
+ reward = model(**inputs).logits.item()
87
+ print(reward)
88
+ ```
89
+
90
+ ## Intended use and limitations
91
+
92
+ Research on preference modeling and pluralistic alignment. Country labels reflect
93
+ participants' residence, not a representative account of a country's culture or
94
+ every resident's preferences. The English-dominant sample and small country test
95
+ sets limit generalization. This reward model does not generate text and is not
96
+ validated for consequential decisions about people.
97
+
98
+ ## Attribution and release license
99
+
100
+ These fine-tuned weights are released under [CC-BY-NC-4.0](https://creativecommons.org/licenses/by-nc/4.0/).
101
+ The [OpenAssistant base model](https://huggingface.co/OpenAssistant/reward-model-deberta-v3-base) is
102
+ marked MIT. The [PRISM dataset card](https://huggingface.co/datasets/HannahRoseKirk/prism-alignment)
103
+ lists human text as CC-BY-4.0 and model responses as CC-BY-NC-4.0, subject to
104
+ original provider terms. This package contains no PRISM records.
added_tokens.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "[MASK]": 128000
3
+ }
checksums.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "LICENSE": "41003d4a74749c0220e33dd415042164b5a1093ed401f36277234f772d22d3d0",
3
+ "README.md": "b05ba3cf9bb2cd44f29a166926cc98ff88d550e779109e1ca78ea2da847c566f",
4
+ "added_tokens.json": "dc046d04c9b0ada7ae6f1dc89c465801799acdf0c9a6aab8c15a1b2d5ca4e91f",
5
+ "config.json": "d88248219ef56b7227b25161fe83bfc1f949d77032367525b372270ef80bef17",
6
+ "model.safetensors": "aa23ee2ae72319bcc6351cd800c413a320856483208fc09f7e447351ba868583",
7
+ "provenance.json": "fd6291ee5bc555a8abbe283f6e81a7fcfe153cb5fbc18ccbc1a0d8b4e7c2a2c8",
8
+ "release-settings.json": "df34196ae4709cef88574e10e06b2bd6e940a7881d4ee2428219ac75c75ed4f6",
9
+ "requirements-pw-lock.txt": "abe2e55884496b23fc4206efbf563edc7cfc615ef37189851f6f442454e3e8bc",
10
+ "special_tokens_map.json": "63cd5b53789b3b5ae2c3d7aa377bcba1557ff0b41dc69ce07b94350ea32291c2",
11
+ "spm.model": "c679fbf93643d19aab7ee10c0b99e460bdbc02fedf34b92b05af343b4af586fd",
12
+ "tokenizer.json": "b8d055f68ab07e04ecdeacf0bf506d578d826d2682b4709c94899a2f3556f583",
13
+ "tokenizer_config.json": "2c9737294d56f67d6122507ce309dfb8dd98221a73ed8315db8f9b07cf1988fa",
14
+ "validation.json": "f8ec56e8a9fa315675301294d15e14f753aa22480629349f4c31d2cff427edde",
15
+ "reproduction/our_data_collator.py": "67c1b081e7886ed8a5747abe7612ff255f0043d8c3d59ef64bb774db12518c79",
16
+ "reproduction/our_inverse_reward_trainer.py": "b41fc006ae62dfdd5553217cdb231c35d45c80dd5437f3f7c70ce006f59835a1",
17
+ "reproduction/our_reward_trainer.py": "35aea8a2f4b30f51e5427b61418698d69528b868fd7b35abad7132508d092ab3",
18
+ "reproduction/preferences.py": "16642fdfa0c817ca2b0ce33600d6478535f2994bef5c4f00d0d7b7227026b72e"
19
+ }
config.json ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "OpenAssistant/reward-model-deberta-v3-base",
3
+ "architectures": [
4
+ "DebertaV2ForSequenceClassification"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "hidden_act": "gelu",
8
+ "hidden_dropout_prob": 0.1,
9
+ "hidden_size": 768,
10
+ "id2label": {
11
+ "0": "REWARD"
12
+ },
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 3072,
15
+ "label2id": {
16
+ "REWARD": 0
17
+ },
18
+ "layer_norm_eps": 1e-07,
19
+ "max_position_embeddings": 512,
20
+ "max_relative_positions": -1,
21
+ "model_type": "deberta-v2",
22
+ "norm_rel_ebd": "layer_norm",
23
+ "num_attention_heads": 12,
24
+ "num_hidden_layers": 12,
25
+ "pad_token_id": 0,
26
+ "pooler_dropout": 0,
27
+ "pooler_hidden_act": "gelu",
28
+ "pooler_hidden_size": 768,
29
+ "pos_att_type": [
30
+ "p2c",
31
+ "c2p"
32
+ ],
33
+ "position_biased_input": false,
34
+ "position_buckets": 256,
35
+ "problem_type": "regression",
36
+ "relative_attention": true,
37
+ "share_att_key": true,
38
+ "torch_dtype": "float32",
39
+ "transformers_version": "4.45.2",
40
+ "type_vocab_size": 0,
41
+ "vocab_size": 128100
42
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aa23ee2ae72319bcc6351cd800c413a320856483208fc09f7e447351ba868583
3
+ size 737716196
provenance.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "country": "Canada",
3
+ "protocol": "original-source-v1",
4
+ "source_revision": "94f8430054835aa919b226b4344b8f0e8424f29b",
5
+ "original_sha256": {
6
+ "preferences.py": "df4c9e3991b8238c5a50a3d672d67ca3d6350f06a28a99bc6959e8edd817cd8e",
7
+ "our_reward_trainer.py": "35aea8a2f4b30f51e5427b61418698d69528b868fd7b35abad7132508d092ab3",
8
+ "our_inverse_reward_trainer.py": "b41fc006ae62dfdd5553217cdb231c35d45c80dd5437f3f7c70ce006f59835a1",
9
+ "our_data_collator.py": "67c1b081e7886ed8a5747abe7612ff255f0043d8c3d59ef64bb774db12518c79"
10
+ },
11
+ "generated_sha256": "16642fdfa0c817ca2b0ce33600d6478535f2994bef5c4f00d0d7b7227026b72e",
12
+ "base_model_revision": "7dab4156e63944834c3aae169c3fe83955672cff",
13
+ "dataset_revision": "18ab5cfb37456f4ec8cbc00212ce54cf7b1239f6",
14
+ "experiment_metrics": {
15
+ "overall": 66.1849710982659,
16
+ "global_overall": 60.40462427745664,
17
+ "misranked": 27.73722627737226,
18
+ "global_misranked": 0.0
19
+ },
20
+ "weight_sha256": "aa23ee2ae72319bcc6351cd800c413a320856483208fc09f7e447351ba868583",
21
+ "selection": "Per-country exploratory fixed-test selections; Israel accepted by user below prior matching threshold"
22
+ }
release-settings.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "country": "Canada",
3
+ "shuffle_seed": 0,
4
+ "learning_rate": 1e-06,
5
+ "tau": 0.7,
6
+ "beta": 1.1,
7
+ "batch_size": 8,
8
+ "max_steps": 1024,
9
+ "method": "filtered_weighted",
10
+ "model_name": "OpenAssistant/reward-model-deberta-v3-base",
11
+ "split_seed": 0,
12
+ "model_seed": 0,
13
+ "trainer_seed": 42,
14
+ "trainer_data_seed": null
15
+ }
reproduction/our_data_collator.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+ from typing import Union, Optional, List, Dict, Any
3
+
4
+ import torch
5
+ from transformers import PreTrainedTokenizerBase
6
+
7
+
8
+ @dataclass
9
+ class OurRewardDataCollatorWithPadding:
10
+ r"""
11
+ Reward DataCollator class that pads the inputs to the maximum length of the batch.
12
+
13
+ Args:
14
+ tokenizer (`PreTrainedTokenizerBase`):
15
+ The tokenizer used for encoding the data.
16
+ padding (`Union[bool, str, `PaddingStrategy`]`, `optional`, defaults to `True`):
17
+ padding_strategy to pass to the tokenizer.
18
+ pad_to_multiple_of (`Optional[int]`, `optional`, defaults to `None`):
19
+ If set will pad the sequence to a multiple of the provided value.
20
+ return_tensors (`str`, `optional`, defaults to `"pt"`):
21
+ The tensor type to use.
22
+ """
23
+
24
+ tokenizer: PreTrainedTokenizerBase
25
+ padding: Union[bool, str] = True
26
+ max_length: Optional[int] = None
27
+ pad_to_multiple_of: Optional[int] = None
28
+ return_tensors: str = "pt"
29
+
30
+ def __call__(self, features: List[Dict[str, Any]]) -> Dict[str, Any]:
31
+ features_chosen = []
32
+ features_rejected = []
33
+ margin = []
34
+ # check if we have a margin. If we do, we need to batch it as well
35
+ has_margin = "margin" in features[0]
36
+ for feature in features:
37
+ # check if the keys are named as expected
38
+ if (
39
+ "input_ids_chosen" not in feature
40
+ or "input_ids_rejected" not in feature
41
+ or "attention_mask_chosen" not in feature
42
+ or "attention_mask_rejected" not in feature
43
+ ):
44
+ raise ValueError(
45
+ "The features should include `input_ids_chosen`, `attention_mask_chosen`, `input_ids_rejected` and `attention_mask_rejected`"
46
+ )
47
+
48
+ features_chosen.append(
49
+ {
50
+ "input_ids": feature["input_ids_chosen"],
51
+ "attention_mask": feature["attention_mask_chosen"],
52
+ "ref_rewards": feature["ref_rewards_chosen"]
53
+ }
54
+ )
55
+ features_rejected.append(
56
+ {
57
+ "input_ids": feature["input_ids_rejected"],
58
+ "attention_mask": feature["attention_mask_rejected"],
59
+ "ref_rewards": feature["ref_rewards_rejected"]
60
+ }
61
+ )
62
+ if has_margin:
63
+ margin.append(feature["margin"])
64
+ batch_chosen = self.tokenizer.pad(
65
+ features_chosen,
66
+ padding=self.padding,
67
+ max_length=self.max_length,
68
+ pad_to_multiple_of=self.pad_to_multiple_of,
69
+ return_tensors=self.return_tensors,
70
+ )
71
+ batch_rejected = self.tokenizer.pad(
72
+ features_rejected,
73
+ padding=self.padding,
74
+ max_length=self.max_length,
75
+ pad_to_multiple_of=self.pad_to_multiple_of,
76
+ return_tensors=self.return_tensors,
77
+ )
78
+ batch = {
79
+ "input_ids_chosen": batch_chosen["input_ids"],
80
+ "attention_mask_chosen": batch_chosen["attention_mask"],
81
+ "ref_rewards_chosen": batch_chosen["ref_rewards"],
82
+ "input_ids_rejected": batch_rejected["input_ids"],
83
+ "attention_mask_rejected": batch_rejected["attention_mask"],
84
+ "ref_rewards_rejected": batch_rejected["ref_rewards"],
85
+ "return_loss": True,
86
+ }
87
+ if has_margin:
88
+ margin = torch.tensor(margin, dtype=torch.float)
89
+ batch["margin"] = margin
90
+ return batch
reproduction/our_inverse_reward_trainer.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+ from typing import Union, Dict, Any, Tuple, List, Mapping, Optional
3
+
4
+ import torch
5
+ from torch import nn
6
+ from transformers import PreTrainedModel
7
+ from trl import RewardTrainer
8
+
9
+
10
+ class OurInverseRewardTrainer(RewardTrainer):
11
+ _tag_names = ["trl", "reward-trainer"]
12
+
13
+
14
+ def compute_loss(
15
+ self,
16
+ model: Union[PreTrainedModel, nn.Module],
17
+ inputs: Dict[str, Union[torch.Tensor, Any]],
18
+ return_outputs=False,
19
+ num_items_in_batch=None,
20
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, Dict[str, torch.Tensor]]]:
21
+ if not self.use_reward_data_collator:
22
+ warnings.warn(
23
+ "The current compute_loss is implemented for RewardDataCollatorWithPadding,"
24
+ " if you are using a custom data collator make sure you know what you are doing or"
25
+ " implement your own compute_loss method."
26
+ )
27
+ rewards_chosen = model(
28
+ input_ids=inputs["input_ids_chosen"],
29
+ attention_mask=inputs["attention_mask_chosen"],
30
+ return_dict=True,
31
+ )["logits"]
32
+ ref_rewards_chosen = inputs["ref_rewards_chosen"]
33
+ rewards_rejected = model(
34
+ input_ids=inputs["input_ids_rejected"],
35
+ attention_mask=inputs["attention_mask_rejected"],
36
+ return_dict=True,
37
+ )["logits"]
38
+ ref_rewards_rejected = inputs["ref_rewards_rejected"]
39
+ # calculate loss, optionally modulate with margin
40
+ # ratio = 1. + torch.exp(ref_rewards_chosen) / torch.exp(ref_rewards_rejected)
41
+ ratio = torch.maximum(torch.exp(ref_rewards_rejected) / torch.exp(ref_rewards_chosen), torch.ones_like(ref_rewards_chosen))
42
+ # ratio = torch.exp(ref_rewards_chosen) / torch.exp(ref_rewards_rejected)
43
+ # print(ratio)
44
+ if "margin" in inputs:
45
+ loss = -(ratio * nn.functional.logsigmoid(rewards_chosen - rewards_rejected - inputs["margin"])).mean()
46
+ else:
47
+ loss = -(ratio * nn.functional.logsigmoid(rewards_chosen - rewards_rejected)).mean()
48
+
49
+ if self.args.center_rewards_coefficient is not None:
50
+ loss += self.args.center_rewards_coefficient * torch.mean((rewards_chosen + rewards_rejected) ** 2)
51
+
52
+ if return_outputs:
53
+ return loss, {
54
+ "rewards_chosen": rewards_chosen,
55
+ "rewards_rejected": rewards_rejected,
56
+ }
57
+ return loss
reproduction/our_reward_trainer.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+ from typing import Union, Dict, Any, Tuple, List, Mapping, Optional
3
+
4
+ import torch
5
+ from torch import nn
6
+ from transformers import PreTrainedModel
7
+ from trl import RewardTrainer
8
+
9
+
10
+ class OurRewardTrainer(RewardTrainer):
11
+ _tag_names = ["trl", "reward-trainer"]
12
+
13
+ def __init__(self, *args, beta: float = 1.0, **kwargs):
14
+ super().__init__(*args, **kwargs)
15
+ self.beta = beta
16
+
17
+ def compute_loss(
18
+ self,
19
+ model: Union[PreTrainedModel, nn.Module],
20
+ inputs: Dict[str, Union[torch.Tensor, Any]],
21
+ return_outputs=False,
22
+ num_items_in_batch=None,
23
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, Dict[str, torch.Tensor]]]:
24
+ if not self.use_reward_data_collator:
25
+ warnings.warn(
26
+ "The current compute_loss is implemented for RewardDataCollatorWithPadding,"
27
+ " if you are using a custom data collator make sure you know what you are doing or"
28
+ " implement your own compute_loss method."
29
+ )
30
+ rewards_chosen = model(
31
+ input_ids=inputs["input_ids_chosen"],
32
+ attention_mask=inputs["attention_mask_chosen"],
33
+ return_dict=True,
34
+ )["logits"]
35
+ ref_rewards_chosen = inputs["ref_rewards_chosen"]
36
+ rewards_rejected = model(
37
+ input_ids=inputs["input_ids_rejected"],
38
+ attention_mask=inputs["attention_mask_rejected"],
39
+ return_dict=True,
40
+ )["logits"]
41
+ ref_rewards_rejected = inputs["ref_rewards_rejected"]
42
+ # calculate loss, optionally modulate with margin
43
+ # ratio = 1. + torch.exp(ref_rewards_chosen) / torch.exp(ref_rewards_rejected)
44
+ ratio = torch.minimum(torch.exp((ref_rewards_chosen - ref_rewards_rejected) / self.beta), torch.ones_like(ref_rewards_chosen))
45
+ # ratio = torch.exp(ref_rewards_chosen) / torch.exp(ref_rewards_rejected)
46
+ # print(ratio)
47
+ if "margin" in inputs:
48
+ loss = -(ratio * nn.functional.logsigmoid(rewards_chosen - rewards_rejected - inputs["margin"])).mean()
49
+ else:
50
+ loss = -(ratio * nn.functional.logsigmoid(rewards_chosen - rewards_rejected)).mean()
51
+
52
+ if self.args.center_rewards_coefficient is not None:
53
+ loss += self.args.center_rewards_coefficient * torch.mean((rewards_chosen + rewards_rejected) ** 2)
54
+
55
+ if return_outputs:
56
+ return loss, {
57
+ "rewards_chosen": rewards_chosen,
58
+ "rewards_rejected": rewards_rejected,
59
+ }
60
+ return loss
reproduction/preferences.py ADDED
@@ -0,0 +1,626 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # from transformers.utils import logging
2
+ # logging.set_verbosity_error()
3
+ import csv
4
+ import warnings
5
+
6
+ from peft import LoraConfig, TaskType
7
+
8
+ warnings.filterwarnings('ignore')
9
+
10
+ import torch
11
+ from datasets import Dataset
12
+ from trl import RewardConfig, RewardTrainer
13
+ import collections
14
+ from tqdm import tqdm
15
+ import argparse
16
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
17
+ import os
18
+ import numpy as np
19
+
20
+ from our_data_collator import OurRewardDataCollatorWithPadding
21
+ from our_reward_trainer import OurRewardTrainer
22
+ # from our_inverse_reward_trainer import OurInverseRewardTrainer
23
+
24
+ BATCH_SIZE = 8
25
+ # EPOCHS = 2
26
+ EPOCHS = 1
27
+ LR = 1e-6
28
+ LR_OVERRIDE = {
29
+ }
30
+ # LR = 1e-5
31
+ EDITED_EPOCHS = 3
32
+ EDITED_LR = 1e-06
33
+ EDITED_LR_OVERRIDE = {
34
+ }
35
+
36
+ SKIP_ORIG_PARTIAL = ["South Africa", "Mexico", "Australia", "New Zealand", "Chile", "Canada", "Israel"]
37
+
38
+ REWARD_THRES = 0.7
39
+ REWARD_THRES_OVERRIDE = {
40
+ }
41
+ WEIGHTING_BETA = 1.1
42
+
43
+ MAX_STEPS = {
44
+ # "United States": 1200,
45
+ "New Zealand": 1024,
46
+ "Mexico": 1024,
47
+ "Chile": 1024,
48
+ "South Africa": 1024,
49
+ "Israel": 1024,
50
+ "Canada": 1024,
51
+ "Australia": 1024
52
+ }
53
+
54
+ REPORT = 1000000
55
+
56
+ RANDOM_DATA_SPLIT_SEED = 0
57
+ RANDOM_DATA_SHUFFLE_SEED = 0
58
+ RANDOM_MODEL_SEED = 0
59
+
60
+ from transformers import set_seed
61
+ set_seed(RANDOM_MODEL_SEED)
62
+ MODEL_NAME = "OpenAssistant/reward-model-deberta-v3-base"
63
+ # MODEL_NAME = "allenai/Llama-3.1-Tulu-3-8B-RM"
64
+
65
+
66
+ def main(out_path):
67
+ print("script starting")
68
+ # Use reside_country
69
+
70
+ # GPO list
71
+ countries = ["United States", "Canada",
72
+ "Germany", "France", "Spain",
73
+ "Nigeria", "Egypt",
74
+ "India", "China", "Japan",
75
+ "Brazil", "Argentina",
76
+ "Australia", "New Zealand"]
77
+ # Our list
78
+ # Max 3 countries per continent, more than 10 users.
79
+ # Must be also in GlobalOpinionsQA - South Africa, Korea not in the Global Opinions QA
80
+ # North America : United States, Canada, Mexico
81
+ # South America : Chile
82
+ # Europe: United Kingdom, Spain, Belgium
83
+ # Asia: Israel, Japan
84
+ # Australia: Australia
85
+ # countries = ["United States", "Mexico", "Canada",
86
+ # "Chile",
87
+ # "United Kingdom", "Spain", "Belgium",
88
+ # "Israel", "Japan",
89
+ # "Australia"]
90
+ # Counter({'United States': 386, 'United Kingdom': 340, 'South Africa': 86, 'New Zealand': 77, 'Australia': 72,
91
+ # 'Mexico': 67, 'Chile': 65, 'Israel': 61, 'Canada': 54, 'Spain': 18, 'Belgium': 17, 'Hungary': 16, 'Denmark': 15,
92
+ # 'Norway': 15, 'Ireland': 15, 'Poland': 14, 'Czechia': 14, 'Switzerland': 14, 'Latvia': 14, 'Germany': 13,
93
+ # 'Greece': 13, 'Finland': 13, 'Italy': 13, 'France': 12, 'Japan': 11, 'Slovenia': 10, 'Austria': 10, 'Estonia': 10,
94
+ # 'Netherlands': 8, 'Portugal': 7, 'Korea, Republic of': 7, 'Sweden': 6, 'Luxembourg': 2,
95
+ # 'Tanzania, United Republic of': 1, 'Uruguay': 1, 'Lesotho': 1, 'Iceland': 1, 'Prefer not to say': 1})
96
+
97
+ # Or, just top-10 responding countries with more than 20 users
98
+ # countries = ["United States", "United Kingdom", "South Africa", "New Zealand", "Australia", "Mexico", "Chile",
99
+ # "Israel", "Canada"]
100
+ # countries = ["United States"]
101
+
102
+ # countries = ["New Zealand", "Mexico", "South Africa"]
103
+ # countries = ["South Africa"]
104
+ # countries = ["Australia"]
105
+
106
+ # countries = ["Japan"]
107
+ countries = ['Canada']
108
+
109
+ print("dataset starting")
110
+ from datasets import load_dataset
111
+ # Load datasets
112
+ utts = load_dataset("HannahRoseKirk/prism-alignment", "utterances", split="train")
113
+ infos = load_dataset("HannahRoseKirk/prism-alignment", "survey", split="train")
114
+
115
+ info_split = infos.train_test_split(test_size=0.15, seed=RANDOM_DATA_SPLIT_SEED)
116
+ info_split.save_to_disk(f"{out_path}/dataset/PRISM/seed/{RANDOM_DATA_SPLIT_SEED}/")
117
+
118
+ info_train = info_split["train"]
119
+ info_test = info_split["test"]
120
+
121
+ reside_countries = collections.Counter()
122
+ birth_countries = collections.Counter()
123
+
124
+ info_train_ids = collections.defaultdict(set)
125
+
126
+ # map users to countries for the training set
127
+ # count number of users that reside/were born in each country
128
+ for info in info_train:
129
+ country = info["location"]["reside_country"]
130
+ b_country = info["location"]["birth_country"]
131
+ reside_countries[country] += 1
132
+ birth_countries[b_country] += 1
133
+ if country in countries:
134
+ info_train_ids[country].add(info["user_id"])
135
+
136
+ # map users to countries for the test set
137
+ # count number of users that reside or were born in each country
138
+ info_test_ids = collections.defaultdict(set)
139
+ for info in info_test:
140
+ country = info["location"]["reside_country"]
141
+ b_country = info["location"]["birth_country"]
142
+ reside_countries[country] += 1
143
+ birth_countries[b_country] += 1
144
+ if country in countries:
145
+ info_test_ids[country].add(info["user_id"])
146
+
147
+ print("**** RESIDE COUNTRIES ****")
148
+ print(reside_countries)
149
+ # print(birth_countries)
150
+
151
+ full_perfs = {count: dict() for count in countries}
152
+ # Different from average
153
+ full_perfs["avg"] = dict()
154
+
155
+ partial_perfs = {count: dict() for count in countries}
156
+ # Different from average
157
+ partial_perfs["avg"] = dict()
158
+
159
+ print("**** USERS ****")
160
+ for country in countries:
161
+ print(f"{country}: train {len(info_train_ids[country])} test {len(info_test_ids[country])}")
162
+
163
+ # Keyed per user & turn
164
+ utt_train = {country: collections.defaultdict(list) for country in countries}
165
+ utt_test = {country: collections.defaultdict(list) for country in countries}
166
+ for utt in utts:
167
+ user_id = utt["user_id"]
168
+ turn = utt["interaction_id"]
169
+ for country in countries:
170
+ key = f"{user_id}_{turn}"
171
+ if user_id in info_train_ids[country]:
172
+ utt_train[country][key].append(utt)
173
+ elif user_id in info_test_ids[country]:
174
+ utt_test[country][key].append(utt)
175
+ else:
176
+ continue
177
+ print("**** Raw Utterances ****")
178
+ print("**** Train ****")
179
+ print({count: len(items) for count, items in utt_train.items()})
180
+ print("**** Test ****")
181
+ print({count: len(items) for count, items in utt_test.items()})
182
+
183
+ utt_score_train = collections.defaultdict(list)
184
+ utt_score_test = collections.defaultdict(list)
185
+
186
+ def format_text(chosen, rejected):
187
+ assert chosen["interaction_id"] == rejected["interaction_id"]
188
+ return {
189
+ "chosen": [{"content": chosen["user_prompt"], "role": "user"},
190
+ {"content": chosen["model_response"], "role": "assistant"}],
191
+ "rejected": [{"content": rejected["user_prompt"], "role": "user"},
192
+ {"content": rejected["model_response"], "role": "assistant"}],
193
+ "chosen_id": chosen["utterance_id"],
194
+ "rejected_id": rejected["utterance_id"],
195
+ "interaction_id": chosen["interaction_id"]
196
+ }
197
+
198
+ # import model and tokenizer
199
+ # move to GPU
200
+ device = "cuda:0" if torch.cuda.is_available() else "cpu"
201
+
202
+ # model predicts which generated answer is better judged by a human
203
+ # returns a score of how good a response is given a question (?)
204
+ model, tokenizer = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME), \
205
+ AutoTokenizer.from_pretrained(MODEL_NAME)
206
+
207
+ model = model.to(device)
208
+
209
+ ### BASELINE ###
210
+
211
+ # Batched utterance score processing
212
+ # get scores/rewards for each utterance in the train set
213
+ # utterance consists of both a user's prompt and the model's response
214
+ utt_train_rewards = {}
215
+ for country, keyed_per_turn in utt_train.items():
216
+ print(f"Processing {country} - train")
217
+ for raw_utts in tqdm(keyed_per_turn.values()):
218
+ for i in range(0, len(raw_utts), BATCH_SIZE):
219
+ utt_batch = raw_utts[i:min(len(raw_utts), i + BATCH_SIZE)]
220
+
221
+ # questions are prompts from the users
222
+ q_s = []
223
+ # answers are how the model responds
224
+ a_s = []
225
+
226
+ # create list of all user prompts
227
+ # create list of all model responses
228
+ for utt in utt_batch:
229
+ q = utt["user_prompt"]
230
+ a = utt["model_response"]
231
+ q_s.append(q)
232
+ a_s.append(a)
233
+
234
+ # tokenize the inputs
235
+ inputs = tokenizer(q_s, a_s, padding=True, return_tensors='pt').to(device)
236
+ # given question, answer
237
+ # get a score for how good the answer is
238
+ # save the score for the given utterance
239
+ scores = model(**inputs).logits.cpu().detach()
240
+ for j in range(len(utt_batch)):
241
+ utt_id = utt_batch[j]["utterance_id"]
242
+ score = scores[j]
243
+ utt_train_rewards[utt_id] = score
244
+
245
+ # get scores/rewards for each utterance in the test set
246
+ # this scoring loop could probably be decomposed with the one starting on line 161
247
+
248
+ utt_test_rewards = {}
249
+ for country, keyed_per_turn in utt_test.items():
250
+ print(f"Processing {country} - test")
251
+ for raw_utts in tqdm(keyed_per_turn.values()):
252
+ for i in range(0, len(raw_utts), BATCH_SIZE):
253
+ utt_batch = raw_utts[i:min(len(raw_utts), i + BATCH_SIZE)]
254
+ q_s = []
255
+ a_s = []
256
+ for utt in utt_batch:
257
+ q = utt["user_prompt"]
258
+ a = utt["model_response"]
259
+ q_s.append(q)
260
+ a_s.append(a)
261
+ inputs = tokenizer(q_s, a_s, padding=True, return_tensors='pt').to(device)
262
+
263
+ scores = model(**inputs).logits.cpu().detach()
264
+ for j in range(len(utt_batch)):
265
+ utt = utt_batch[j]
266
+ utt_id = utt["utterance_id"]
267
+ score = scores[j]
268
+ utt_test_rewards[utt_id] = score
269
+
270
+
271
+ utt_pref_train = collections.defaultdict(list)
272
+ utt_pref_test = collections.defaultdict(list)
273
+
274
+ utt_pref_edited_train = collections.defaultdict(list)
275
+ utt_pref_edited_test = collections.defaultdict(list)
276
+
277
+ print("Processing edits")
278
+ score_same_cnt = 0
279
+
280
+ # utt_train is keyed per user and turn
281
+ # {country: {key: [utterances]}}
282
+ # key = f"{user_id}_{turn}"
283
+ # turn is not "turn" in the dataset, but rather interaction_id
284
+ # see line 117: turn = utt["interaction_id"]
285
+ # what is interaction_id?
286
+
287
+ def score_thres(bigger, smaller, country):
288
+ return (torch.exp(bigger) / (torch.exp(bigger) + torch.exp(smaller))) < (REWARD_THRES if country not in REWARD_THRES_OVERRIDE else REWARD_THRES_OVERRIDE[country])
289
+
290
+ # utt_pref_train = {country: [(pref_utt_id, dispref_utt_id)...]}
291
+ for country, keyed_per_turn in utt_train.items():
292
+
293
+ # prefs is a reference to utt_pref_train
294
+ # when we modify prefs in the loop below, this also populates utt_pref_train
295
+ prefs = utt_pref_train[country]
296
+ edited_prefs = utt_pref_edited_train[country]
297
+ scores = utt_score_train[country]
298
+ # Ignoring key which is user / turn info.
299
+ for raw_utts in keyed_per_turn.values():
300
+ for i, utt1 in enumerate(raw_utts):
301
+ utt1r = utt_train_rewards[utt1["utterance_id"]]
302
+ utt1s = utt1["score"]
303
+ scores.append([utt1, utt1s])
304
+ for j in range(i + 1, len(raw_utts)):
305
+ utt2 = raw_utts[j]
306
+ utt2r = utt_train_rewards[utt2["utterance_id"]]
307
+ utt2s = utt2["score"]
308
+ if utt1s > utt2s:
309
+ prefs.append(format_text(utt1, utt2))
310
+ if score_thres(utt1r, utt2r, country):
311
+ edited_prefs.append(format_text(utt1, utt2))
312
+ elif utt2s > utt1s:
313
+ prefs.append(format_text(utt2, utt1))
314
+ if score_thres(utt2r, utt1r, country):
315
+ edited_prefs.append(format_text(utt2, utt1))
316
+ else:
317
+ score_same_cnt += 1
318
+
319
+ print("Evaluating test results")
320
+ for country, keyed_per_turn in utt_test.items():
321
+ prefs = utt_pref_test[country]
322
+ edited_prefs = utt_pref_edited_test[country]
323
+ scores = utt_score_test[country]
324
+ # Ignoring key which is user / turn info.
325
+
326
+ # for each pair of utterances
327
+ for raw_utts in keyed_per_turn.values():
328
+ for i, utt1 in enumerate(raw_utts):
329
+ # utt1s stands for utt1_score
330
+ utt1r = utt_test_rewards[utt1["utterance_id"]]
331
+ utt1s = utt1["score"]
332
+
333
+ # scores = [[utt, utt_score], ...]
334
+ scores.append([utt1, utt1s])
335
+
336
+ for j in range(i + 1, len(raw_utts)):
337
+ utt2 = raw_utts[j]
338
+ utt2r = utt_test_rewards[utt2["utterance_id"]]
339
+ utt2s = utt2["score"]
340
+
341
+ # prefs stores all pairs of utterances
342
+ # with the higher scored one at idx 0
343
+ if utt1s > utt2s:
344
+ prefs.append(format_text(utt1, utt2))
345
+ if utt1r < utt2r:
346
+ edited_prefs.append(format_text(utt1, utt2))
347
+ elif utt2s > utt1s:
348
+ prefs.append(format_text(utt2, utt1))
349
+ if utt2r < utt1r:
350
+ edited_prefs.append(format_text(utt2, utt1))
351
+ else:
352
+ # if scored the same, count it, but leave out of prefs
353
+ # the count of how many have been "removed"
354
+ score_same_cnt += 1
355
+
356
+ print("**** PAIRS ****")
357
+ print("**** TRAIN ****")
358
+ print({count: len(pairs) for count, pairs in utt_pref_train.items()})
359
+ print("**** TEST ****")
360
+ print({count: len(pairs) for count, pairs in utt_pref_test.items()})
361
+ print("**** EDITED TRAIN ****")
362
+ print({count: len(pairs) for count, pairs in utt_pref_edited_train.items()})
363
+ print("**** EDITED TEST ****")
364
+ print({count: len(pairs) for count, pairs in utt_pref_edited_test.items()})
365
+ print(f"Scored same : {score_same_cnt}")
366
+
367
+ # Compute edited pairs ratio (edited / total) for train and test
368
+ edited_ratios = {"train": {}, "test": {}}
369
+ total_train_pairs = 0
370
+ total_train_edited = 0
371
+ total_test_pairs = 0
372
+ total_test_edited = 0
373
+ for count in countries:
374
+ train_total = len(utt_pref_train[count])
375
+ train_edited = len(utt_pref_edited_train[count])
376
+ test_total = len(utt_pref_test[count])
377
+ test_edited = len(utt_pref_edited_test[count])
378
+ edited_ratios["train"][count] = train_edited / train_total if train_total > 0 else 0.0
379
+ edited_ratios["test"][count] = test_edited / test_total if test_total > 0 else 0.0
380
+ total_train_pairs += train_total
381
+ total_train_edited += train_edited
382
+ total_test_pairs += test_total
383
+ total_test_edited += test_edited
384
+ # Compute average ratios based on total counts
385
+ edited_ratios["train"]["avg"] = total_train_edited / total_train_pairs if total_train_pairs > 0 else 0.0
386
+ edited_ratios["test"]["avg"] = total_test_edited / total_test_pairs if total_test_pairs > 0 else 0.0
387
+
388
+ print("**** EDITED PAIRS RATIO ****")
389
+ print("**** TRAIN ****")
390
+ for count in countries:
391
+ print(f"{count}: {edited_ratios['train'][count]:.4f}")
392
+ print(f"Average: {edited_ratios['train']['avg']:.4f}")
393
+ print("**** TEST ****")
394
+ for count in countries:
395
+ print(f"{count}: {edited_ratios['test'][count]:.4f}")
396
+ print(f"Average: {edited_ratios['test']['avg']:.4f}")
397
+
398
+ print("**** Starting reward model Evals ****")
399
+ print("**** Percentage of pairs correctly evaluated ****")
400
+ avg_perf = 0.
401
+ for count, pairs in utt_pref_test.items():
402
+ correct = 0
403
+ wrong = 0
404
+ for pair in pairs:
405
+ chosen_score = utt_test_rewards[pair["chosen_id"]]
406
+ rejected_score = utt_test_rewards[pair["rejected_id"]]
407
+
408
+ # model (deberta) gave higher score to preferred response
409
+ if chosen_score > rejected_score:
410
+ correct += 1
411
+ # model (deberta) gave higher score to rejected response
412
+ else:
413
+ wrong += 1
414
+ perf = correct * 1.0 / (correct + wrong) * 100
415
+ print(f"{count}: {perf:.2f}%")
416
+ full_perfs[count]["start"] = perf
417
+ avg_perf += perf
418
+ avg_perf /= len(countries)
419
+ full_perfs["avg"]["start"] = avg_perf
420
+ print(f"Starting Performance: {avg_perf:.2f}%")
421
+
422
+ avg_perf = 0.
423
+ for count, pairs in utt_pref_edited_test.items():
424
+ correct = 0
425
+ wrong = 0
426
+ for pair in pairs:
427
+ chosen_score = utt_test_rewards[pair["chosen_id"]]
428
+ rejected_score = utt_test_rewards[pair["rejected_id"]]
429
+
430
+ # model (deberta) gave higher score to preferred response
431
+ if chosen_score > rejected_score:
432
+ correct += 1
433
+ # model (deberta) gave higher score to rejected response
434
+ else:
435
+ wrong += 1
436
+ perf = correct * 1.0 / (correct + wrong) * 100
437
+ print(f"{count}: {perf:.2f}%")
438
+ partial_perfs[count]["start"] = perf
439
+ avg_perf += perf
440
+ avg_perf /= len(countries)
441
+ partial_perfs["avg"]["start"] = avg_perf
442
+ print(f"Starting Partial Performance: {avg_perf:.2f}%")
443
+
444
+ print("**** Training Country-Specific Models ****")
445
+
446
+ ### TRAIN THE REWARD MODEL (DEBERTA) WITH EDITED PREFS ###
447
+ # this training loop can probably be decomposed with the one starting on line 328
448
+ print("**** Ablation reward model training ****")
449
+
450
+ avg_perf = 0.
451
+ avg_partial_perf = 0.
452
+ test_baseline_rewards = collections.defaultdict(dict)
453
+ # Train reward model
454
+ for count in countries:
455
+ model = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME)
456
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
457
+
458
+ def format_func_train(examples):
459
+ kwargs = {"padding": "max_length", "truncation": True, "max_length": 512, "return_tensors": "pt"}
460
+ chosen_chat = examples["chosen"][0]["content"] + " [SEP] " + examples["chosen"][1]["content"]
461
+ rejected_chat = examples["rejected"][0]["content"] + " [SEP] " + examples["rejected"][1]["content"]
462
+ chosen_tokens = tokenizer.encode_plus(chosen_chat, **kwargs)
463
+ rejected_tokens = tokenizer.encode_plus(rejected_chat, **kwargs)
464
+ ref_rewards_chosen = utt_train_rewards[examples["chosen_id"]]
465
+ ref_rewards_rejected = utt_train_rewards[examples["rejected_id"]]
466
+ return {
467
+ "input_ids_chosen": chosen_tokens["input_ids"][0],
468
+ "attention_mask_chosen": chosen_tokens["attention_mask"][0],
469
+ "input_ids_rejected": rejected_tokens["input_ids"][0],
470
+ "attention_mask_rejected": rejected_tokens["attention_mask"][0],
471
+ "ref_rewards_chosen": ref_rewards_chosen,
472
+ "ref_rewards_rejected": ref_rewards_rejected,
473
+ }
474
+
475
+ def format_func_test(examples):
476
+ kwargs = {"padding": "max_length", "truncation": True, "max_length": 512, "return_tensors": "pt"}
477
+ chosen_chat = examples["chosen"][0]["content"] + " [SEP] " + examples["chosen"][1]["content"]
478
+ rejected_chat = examples["rejected"][0]["content"] + " [SEP] " + examples["rejected"][1]["content"]
479
+ chosen_tokens = tokenizer.encode_plus(chosen_chat, **kwargs)
480
+ rejected_tokens = tokenizer.encode_plus(rejected_chat, **kwargs)
481
+ ref_rewards_chosen = utt_test_rewards[examples["chosen_id"]]
482
+ ref_rewards_rejected = utt_test_rewards[examples["rejected_id"]]
483
+ return {
484
+ "input_ids_chosen": chosen_tokens["input_ids"][0],
485
+ "attention_mask_chosen": chosen_tokens["attention_mask"][0],
486
+ "input_ids_rejected": rejected_tokens["input_ids"][0],
487
+ "attention_mask_rejected": rejected_tokens["attention_mask"][0],
488
+ "ref_rewards_chosen": ref_rewards_chosen,
489
+ "ref_rewards_rejected": ref_rewards_rejected,
490
+ }
491
+
492
+ train_reward_dataset = Dataset.from_list(utt_pref_edited_train[count]).map(format_func_train)
493
+ train_reward_dataset = train_reward_dataset.shuffle(seed=RANDOM_DATA_SHUFFLE_SEED)
494
+ test_reward_dataset = Dataset.from_list(utt_pref_test[count]).map(format_func_test)
495
+ test_reward_dataset = test_reward_dataset.shuffle(seed=RANDOM_DATA_SHUFFLE_SEED)
496
+
497
+ training_args = RewardConfig(
498
+ output_dir=f"{out_path}/trunc/{count}/ours_{EDITED_EPOCHS}epoch/",
499
+ per_device_train_batch_size=BATCH_SIZE,
500
+ num_train_epochs=EDITED_EPOCHS,
501
+ max_steps=MAX_STEPS[count],
502
+ learning_rate=EDITED_LR,
503
+ logging_steps=25,
504
+ eval_strategy="steps",
505
+ eval_steps=REPORT,
506
+ save_strategy="no",
507
+ max_length=2048,
508
+ report_to="none",
509
+ remove_unused_columns=False
510
+ )
511
+ data_collator = OurRewardDataCollatorWithPadding(
512
+ tokenizer=tokenizer, max_length=training_args.max_length
513
+ )
514
+ trainer = OurRewardTrainer(
515
+ model=model,
516
+ args=training_args,
517
+ beta=WEIGHTING_BETA,
518
+ data_collator=data_collator,
519
+ train_dataset=train_reward_dataset,
520
+ eval_dataset=test_reward_dataset
521
+ )
522
+
523
+ trainer.train()
524
+
525
+ trainer.save_model(training_args.output_dir)
526
+
527
+ rewards = test_baseline_rewards[count]
528
+ print("Scoring the test set!")
529
+ keyed_per_turn = utt_test[count]
530
+ for raw_utts in tqdm(keyed_per_turn.values()):
531
+ for i in range(0, len(raw_utts), BATCH_SIZE):
532
+ utt_batch = raw_utts[i:min(len(raw_utts), i + BATCH_SIZE)]
533
+ q_s = []
534
+ a_s = []
535
+ for utt in utt_batch:
536
+ q = utt["user_prompt"]
537
+ a = utt["model_response"]
538
+ q_s.append(q)
539
+ a_s.append(a)
540
+ inputs = tokenizer(q_s, a_s, padding=True, return_tensors='pt').to(device)
541
+ scores = model(**inputs).logits.cpu().detach()
542
+ for j in range(len(utt_batch)):
543
+ utt_id = utt_batch[j]["utterance_id"]
544
+ score = scores[j]
545
+ rewards[utt_id] = score
546
+
547
+ print("Evaluating the test set!")
548
+
549
+ # this evaluation loop can probably be decomposed with the one starting on line 300
550
+ # currently train on the edited set, test on the full set
551
+ pairs = utt_pref_test[count]
552
+
553
+ correct = 0
554
+ wrong = 0
555
+ for pair in pairs:
556
+ chosen_score = rewards[pair["chosen_id"]]
557
+ rejected_score = rewards[pair["rejected_id"]]
558
+ if chosen_score > rejected_score:
559
+ correct += 1
560
+ else:
561
+ wrong += 1
562
+ perf = correct * 1.0 / (correct + wrong) * 100
563
+ print(f"{count}: {perf:.2f}%")
564
+ full_perfs[count]["ours_partial"] = perf
565
+ avg_perf += perf
566
+
567
+ pairs = utt_pref_edited_test[count]
568
+
569
+ correct = 0
570
+ wrong = 0
571
+ for pair in pairs:
572
+ chosen_score = rewards[pair["chosen_id"]]
573
+ rejected_score = rewards[pair["rejected_id"]]
574
+
575
+ # model (deberta) gave higher score to preferred response
576
+ if chosen_score > rejected_score:
577
+ correct += 1
578
+ # model (deberta) gave higher score to rejected response
579
+ else:
580
+ wrong += 1
581
+ perf = correct * 1.0 / (correct + wrong) * 100
582
+ print(f"{count}: {perf:.2f}%")
583
+ partial_perfs[count]["ours_partial"] = perf
584
+ avg_partial_perf += perf
585
+
586
+ print("**** Ablation reward model Evals ****")
587
+ print("**** Percentage of pairs correctly evaluated ****")
588
+ avg_perf /= len(countries)
589
+ full_perfs["avg"]["ours_partial"] = avg_perf
590
+ print(f"Ablation Model Performance: {avg_perf:.2f}%")
591
+
592
+ avg_partial_perf /= len(countries)
593
+ partial_perfs["avg"]["ours_partial"] = avg_partial_perf
594
+ print(f"Ablation Model Partial Performance: {avg_partial_perf:.2f}%")
595
+
596
+ import json
597
+ path = f"{out_path}/experiment/seed/{RANDOM_MODEL_SEED}/"
598
+ if not os.path.exists(path):
599
+ os.makedirs(path)
600
+
601
+ print("************* OVERALL PERFORMANCE *****************")
602
+ print(json.dumps(full_perfs, indent=4))
603
+ with open(f"{out_path}/experiment/seed/{RANDOM_MODEL_SEED}/full_report.json", 'w') as f:
604
+ json.dump(full_perfs, f, ensure_ascii=False, indent=4)
605
+
606
+ print("************* OVERALL Partial PERFORMANCE *****************")
607
+ print(json.dumps(partial_perfs, indent=4))
608
+ with open(f"{out_path}/experiment/seed/{RANDOM_MODEL_SEED}/partial_report.json", 'w') as f:
609
+ json.dump(partial_perfs, f, ensure_ascii=False, indent=4)
610
+
611
+ print("************* EDITED PAIRS RATIO *****************")
612
+ print(json.dumps(edited_ratios, indent=4))
613
+ with open(f"{out_path}/experiment/seed/{RANDOM_MODEL_SEED}/edited_ratios.json", 'w') as f:
614
+ json.dump(edited_ratios, f, ensure_ascii=False, indent=4)
615
+
616
+
617
+ parser = argparse.ArgumentParser()
618
+ parser.add_argument("out_path")
619
+ args = parser.parse_args()
620
+
621
+ os.environ["TOKENIZERS_PARALLELISM"] = "true"
622
+ # Press the green button in the gutter to run the script.
623
+ if __name__ == '__main__':
624
+ main(args.out_path)
625
+
626
+ # See PyCharm help at https://www.jetbrains.com/help/pycharm/
requirements-pw-lock.txt ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Exact observed PW environment: Linux x86_64, Python 3.11.16, CUDA 12.1 wheels.
2
+ Jinja2==3.1.6
3
+ MarkupSafe==3.0.4
4
+ PyYAML==6.0.3
5
+ Pygments==2.21.0
6
+ accelerate==1.0.1
7
+ aiohappyeyeballs==2.7.1
8
+ aiohttp==3.14.4
9
+ aiosignal==1.4.0
10
+ attrs==26.1.0
11
+ certifi==2026.7.22
12
+ charset-normalizer==3.5.2
13
+ datasets==3.0.1
14
+ dill==0.3.8
15
+ docstring_parser==0.18.0
16
+ filelock==4.0.12
17
+ frozenlist==1.8.0
18
+ fsspec==2024.6.1
19
+ huggingface-hub==0.25.2
20
+ idna==3.20
21
+ markdown-it-py==4.2.0
22
+ mdurl==0.1.2
23
+ mpmath==1.3.0
24
+ multidict==6.9.1
25
+ multiprocess==0.70.16
26
+ networkx==3.6.1
27
+ numpy==1.24.4
28
+ nvidia-cublas-cu12==12.1.3.1
29
+ nvidia-cuda-cupti-cu12==12.1.105
30
+ nvidia-cuda-nvrtc-cu12==12.1.105
31
+ nvidia-cuda-runtime-cu12==12.1.105
32
+ nvidia-cudnn-cu12==9.1.0.70
33
+ nvidia-cufft-cu12==11.0.2.54
34
+ nvidia-curand-cu12==10.3.2.106
35
+ nvidia-cusolver-cu12==11.4.5.107
36
+ nvidia-cusparse-cu12==12.1.0.106
37
+ nvidia-nccl-cu12==2.20.5
38
+ nvidia-nvjitlink-cu12==12.9.86
39
+ nvidia-nvtx-cu12==12.1.105
40
+ packaging==26.3
41
+ pandas==2.0.3
42
+ peft==0.13.2
43
+ propcache==0.5.4
44
+ protobuf==3.20.3
45
+ psutil==7.2.2
46
+ pyarrow==17.0.0
47
+ python-dateutil==2.9.0.post0
48
+ python-dotenv==1.0.1
49
+ pytz==2026.5
50
+ regex==2026.9.29
51
+ requests==2.34.2
52
+ rich==13.9.2
53
+ safetensors==0.4.5
54
+ sentencepiece==0.2.0
55
+ shtab==1.12.1
56
+ six==1.17.0
57
+ sympy==1.14.0
58
+ tokenizers==0.20.1
59
+ torch==2.4.1
60
+ tqdm==4.66.5
61
+ transformers==4.45.2
62
+ triton==3.0.0
63
+ trl==0.11.4
64
+ typeguard==4.6.0
65
+ typing_extensions==4.16.0
66
+ tyro==0.8.13
67
+ tzdata==2026.5
68
+ urllib3==2.8.0
69
+ xxhash==4.0.1
70
+ yarl==1.25.1
special_tokens_map.json ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": {
3
+ "content": "[CLS]",
4
+ "lstrip": false,
5
+ "normalized": false,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "cls_token": {
10
+ "content": "[CLS]",
11
+ "lstrip": false,
12
+ "normalized": false,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "eos_token": {
17
+ "content": "[SEP]",
18
+ "lstrip": false,
19
+ "normalized": false,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "mask_token": {
24
+ "content": "[MASK]",
25
+ "lstrip": false,
26
+ "normalized": false,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ },
30
+ "pad_token": {
31
+ "content": "[PAD]",
32
+ "lstrip": false,
33
+ "normalized": false,
34
+ "rstrip": false,
35
+ "single_word": false
36
+ },
37
+ "sep_token": {
38
+ "content": "[SEP]",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false
43
+ },
44
+ "unk_token": {
45
+ "content": "[UNK]",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false
50
+ }
51
+ }
spm.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c679fbf93643d19aab7ee10c0b99e460bdbc02fedf34b92b05af343b4af586fd
3
+ size 2464616
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "1": {
12
+ "content": "[CLS]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "2": {
20
+ "content": "[SEP]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "3": {
28
+ "content": "[UNK]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "128000": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "bos_token": "[CLS]",
45
+ "clean_up_tokenization_spaces": false,
46
+ "cls_token": "[CLS]",
47
+ "do_lower_case": false,
48
+ "eos_token": "[SEP]",
49
+ "mask_token": "[MASK]",
50
+ "max_length": 512,
51
+ "model_max_length": 1000000000000000019884624838656,
52
+ "pad_token": "[PAD]",
53
+ "sep_token": "[SEP]",
54
+ "sp_model_kwargs": {},
55
+ "split_by_punct": false,
56
+ "stride": 0,
57
+ "tokenizer_class": "DebertaV2Tokenizer",
58
+ "truncation_side": "right",
59
+ "truncation_strategy": "longest_first",
60
+ "unk_token": "[UNK]",
61
+ "vocab_type": "spm"
62
+ }
validation.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "checkpoint": "scpo-deberta-v3-base-canada",
3
+ "device": "cpu",
4
+ "scores": [
5
+ [
6
+ -2.664663314819336
7
+ ],
8
+ [
9
+ 0.41405123472213745
10
+ ]
11
+ ],
12
+ "deterministic": true,
13
+ "sample_pair_vs_concat_ids_equal": [
14
+ true,
15
+ true
16
+ ]
17
+ }