saksornr commited on
Commit
068ccc7
·
verified ·
1 Parent(s): 60924ab

Publish Draftmark browser v3 ONNX release and GPU handoff

Browse files
Files changed (9) hide show
  1. LICENSE +21 -0
  2. README.md +44 -0
  3. config.json +34 -0
  4. finetune-v3.json +823 -0
  5. handoff.md +101 -0
  6. onnx/model.int8.onnx +3 -0
  7. release-manifest.json +29 -0
  8. tokenizer.json +0 -0
  9. tokenizer_config.json +62 -0
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Draftmark contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ language:
4
+ - en
5
+ pipeline_tag: text-classification
6
+ base_model: Oxidane/tmr-ai-text-detector
7
+ base_model_relation: finetune
8
+ tags:
9
+ - onnx
10
+ - roberta
11
+ - ai-text-detection
12
+ - onnxruntime
13
+ - wasm
14
+ - browser
15
+ ---
16
+
17
+ # Draftmark RoBERTa FT INT8
18
+
19
+ Draftmark is a free, on-device writing-pattern detector for English prose. This is the exact weight-only INT8 ONNX export used by the live browser release. Its model and tokenizer assets total **131.1 MB**. [Live Draftmark](https://draftmark-virid.vercel.app/) · [Release manifest](release-manifest.json)
20
+
21
+ ## Inference and intended use
22
+
23
+ The ONNX graph at `onnx/model.int8.onnx` accepts `input_ids` and `attention_mask` as rank-two INT64 tensors. Its two logits are ordered `human`, then `ai`. Apply a softmax per window. The shipped worker scores sentence-aligned windows of up to 512 tokens including special tokens and averages the AI-class scores weighted by content-token count. Oversized sentences are split across windows. The shipped flag threshold is **0.999146566314596** and the limited-signal cutoff is **0.25**.
24
+
25
+ The evaluated app accepts English prose of 150–2,000 words and up to 20,000 characters. Scores can support manual review. Authorship decisions require independent evidence. Results depend on the generator, rewriting method, domain, and writing population.
26
+
27
+ ## Fresh holdout results
28
+
29
+ | Measure | Previous Ettin | Draftmark FT INT8 |
30
+ | --- | ---: | ---: |
31
+ | Unedited AI recall | 215/300 | 277/300 |
32
+ | Decoder rewrite recall | 18/150 | 89/150 |
33
+ | Sequence-to-sequence rewrite recall | 132/150 | 110/150 |
34
+ | Mean paraphrase recall | 50.0% | 66.3% |
35
+ | General-human false flags | 10/300 | 1/300 |
36
+ | Learner-essay false flags | 80/220 | 0/220 |
37
+
38
+ The paired 95% confidence interval for the mean paraphrase gain was **+10.7 to +22.0 percentage points**. Sequence-to-sequence recall declined. The learner false-flag count applies to the 220 ASAP 2.0 essays evaluated. The results are a comparison against Draftmark’s previous detector on these samples. [Aggregate benchmark](finetune-v3.json)
39
+
40
+ ## Training and attribution
41
+
42
+ Draftmark fine-tuned the last four encoder layers and the classification head of Oxidane’s MIT-licensed TMR RoBERTa at revision `0ceddea903015ef99cbaa040a4d8a216aed9c683`. Training used source-grouped DetectRL-X pairs, original AI and human prose from DetectionAI, and learner essays from the ASAP 2.0 corpus and the Shijaku–Canhasi TOEFL collection. The report records the source pins, split sizes, and overlap screening. The ASAP 2.0 corpus is CC BY 4.0 and is credited to Scott Crossley and contributors, Vanderbilt University, and The Learning Agency Lab. [TMR](https://huggingface.co/Oxidane/tmr-ai-text-detector) · [DetectRL-X](https://aclanthology.org/2026.acl-long.1773/) · [DetectionAI](https://github.com/brianjabarian/DetectionAI) · [ASAP 2.0](https://github.com/scrosseye/ASAP_2.0) · [Shijaku–Canhasi corpus](https://github.com/rexshijaku/chatgpt-generated-text-detection-corpus)
43
+
44
+ The [GPU handoff](handoff.md) documents how to reconstruct a Transformers checkpoint from the pinned base and the [replacement tensors on the training branch](https://huggingface.co/saksornr/draftmark-roberta-int8/blob/training/training/trainable.safetensors). The main branch is the browser distribution.
config.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "RobertaForSequenceClassification"
4
+ ],
5
+ "attention_probs_dropout_prob": 0.1,
6
+ "bos_token_id": 0,
7
+ "classifier_dropout": null,
8
+ "dtype": "float32",
9
+ "eos_token_id": 2,
10
+ "hidden_act": "gelu",
11
+ "hidden_dropout_prob": 0.1,
12
+ "hidden_size": 768,
13
+ "id2label": {
14
+ "0": "human",
15
+ "1": "ai"
16
+ },
17
+ "initializer_range": 0.02,
18
+ "intermediate_size": 3072,
19
+ "label2id": {
20
+ "ai": 1,
21
+ "human": 0
22
+ },
23
+ "layer_norm_eps": 1e-05,
24
+ "max_position_embeddings": 514,
25
+ "model_type": "roberta",
26
+ "num_attention_heads": 12,
27
+ "num_hidden_layers": 12,
28
+ "pad_token_id": 1,
29
+ "position_embedding_type": "absolute",
30
+ "transformers_version": "4.57.3",
31
+ "type_vocab_size": 1,
32
+ "use_cache": true,
33
+ "vocab_size": 50265
34
+ }
finetune-v3.json ADDED
@@ -0,0 +1,823 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "baseline": {
3
+ "model": "ettin",
4
+ "version": "browser-v1",
5
+ "upper": 0.9998051638246666,
6
+ "lower": 0.25,
7
+ "experimental": false
8
+ },
9
+ "selected": "finetuned/full",
10
+ "policy": {
11
+ "model": "finetuned",
12
+ "scoring": "full",
13
+ "version": "browser-v3",
14
+ "experimental": false,
15
+ "upper": 0.999146566314596,
16
+ "lower": 0.25
17
+ },
18
+ "limits": {
19
+ "general_fpr": 0.02,
20
+ "learner_fpr": 0.05,
21
+ "minimum_paraphrase_gain": 0.1,
22
+ "maximum_clean_recall_loss": 0.05,
23
+ "maximum_model_bytes": 160000000,
24
+ "maximum_warm_p95_ms": 5000
25
+ },
26
+ "manifest": {
27
+ "heldout_sha256": "c305977e14a03b9ae6c07ac35ac95ac4afc09f9fd1f8df2f9348f9d69afb7f0e",
28
+ "development_sha256": "a81c7b90b5d1dd5a1ebc3cb4711ada93858f22f31604db3e3f408e5a46ee8878",
29
+ "data_sha256": "cd200cc87a23ba552e6182d9479a0bdfaa9826e80022ab4d09cd4e4b571485ee",
30
+ "model_manifest_sha256": "330d445dd29b9f81995cdb20bf935d28b518cca4a850a1a807f42c6601b0c527",
31
+ "model_sha256": "9104295a0903256724f44b86523ad32da0b800efc1ff6a3fc3d2f8e2d2339418",
32
+ "worker_sha256": "e6eba6365b39e878221f4d8e6b274b5ffa4092c6002a253c235a3240a21a434e",
33
+ "wasm_sha256": "4b884c203b0fa48d057be3332c65513ff85aa3c5bddd6946acc0fab7ecda001d",
34
+ "decision_sha256": "1416ece45b413cb5dc8616e634baa0bef7ae0d790186d5df6a155454b064a3a5",
35
+ "performance_sha256": "24de2e1f9cbffcde48612ad248e1f5716e94abc39f493b8ca6c4f999e544a4a7"
36
+ },
37
+ "calibration": {
38
+ "live": {
39
+ "cohorts": {
40
+ "asap_learner": {
41
+ "flags": {
42
+ "hits": 41,
43
+ "n": 101,
44
+ "rate": 0.40594059405940597,
45
+ "ci95": [
46
+ 0.31532231224182006,
47
+ 0.5034519147825671
48
+ ]
49
+ },
50
+ "abstention": {
51
+ "hits": 39,
52
+ "n": 101,
53
+ "rate": 0.38613861386138615,
54
+ "ci95": [
55
+ 0.2970216442209859,
56
+ 0.48359978849274593
57
+ ]
58
+ },
59
+ "outside_input_limits": 0
60
+ },
61
+ "clean_ai": {
62
+ "flags": {
63
+ "hits": 152,
64
+ "n": 220,
65
+ "rate": 0.6909090909090909,
66
+ "ci95": [
67
+ 0.6270045309504402,
68
+ 0.7482608352728177
69
+ ]
70
+ },
71
+ "abstention": {
72
+ "hits": 51,
73
+ "n": 220,
74
+ "rate": 0.2318181818181818,
75
+ "ci95": [
76
+ 0.18094651434879364,
77
+ 0.29189499500424887
78
+ ]
79
+ },
80
+ "outside_input_limits": 0
81
+ },
82
+ "decoder": {
83
+ "flags": {
84
+ "hits": 6,
85
+ "n": 110,
86
+ "rate": 0.05454545454545454,
87
+ "ci95": [
88
+ 0.025235483062071407,
89
+ 0.11391927231733298
90
+ ]
91
+ },
92
+ "abstention": {
93
+ "hits": 58,
94
+ "n": 110,
95
+ "rate": 0.5272727272727272,
96
+ "ci95": [
97
+ 0.4346352821640567,
98
+ 0.6180695287310817
99
+ ]
100
+ },
101
+ "outside_input_limits": 1
102
+ },
103
+ "general_human": {
104
+ "flags": {
105
+ "hits": 4,
106
+ "n": 220,
107
+ "rate": 0.01818181818181818,
108
+ "ci95": [
109
+ 0.007092586915565129,
110
+ 0.04580910785430784
111
+ ]
112
+ },
113
+ "abstention": {
114
+ "hits": 107,
115
+ "n": 220,
116
+ "rate": 0.4863636363636364,
117
+ "ci95": [
118
+ 0.42111944404533,
119
+ 0.552075886938723
120
+ ]
121
+ },
122
+ "outside_input_limits": 1
123
+ },
124
+ "seq2seq": {
125
+ "flags": {
126
+ "hits": 102,
127
+ "n": 110,
128
+ "rate": 0.9272727272727272,
129
+ "ci95": [
130
+ 0.8630186778224797,
131
+ 0.962690026201357
132
+ ]
133
+ },
134
+ "abstention": {
135
+ "hits": 8,
136
+ "n": 110,
137
+ "rate": 0.07272727272727272,
138
+ "ci95": [
139
+ 0.03730997379864303,
140
+ 0.13698132217752032
141
+ ]
142
+ },
143
+ "outside_input_limits": 0
144
+ }
145
+ },
146
+ "paraphrase_discrimination": {
147
+ "decoder": {
148
+ "auroc": 0.541996564869507,
149
+ "recall_at_1pct_fpr": 0.01834862385321101,
150
+ "recall_at_5pct_fpr": 0.12844036697247707
151
+ },
152
+ "seq2seq": {
153
+ "auroc": 0.986384391863844,
154
+ "recall_at_1pct_fpr": 0.9,
155
+ "recall_at_5pct_fpr": 0.9454545454545454
156
+ }
157
+ }
158
+ },
159
+ "finetuned/full": {
160
+ "cohorts": {
161
+ "asap_learner": {
162
+ "flags": {
163
+ "hits": 0,
164
+ "n": 101,
165
+ "rate": 0.0,
166
+ "ci95": [
167
+ 0,
168
+ 0.03664194365595336
169
+ ]
170
+ },
171
+ "abstention": {
172
+ "hits": 1,
173
+ "n": 101,
174
+ "rate": 0.009900990099009901,
175
+ "ci95": [
176
+ 0.001749866201761846,
177
+ 0.05396847460951917
178
+ ]
179
+ },
180
+ "outside_input_limits": 0
181
+ },
182
+ "clean_ai": {
183
+ "flags": {
184
+ "hits": 204,
185
+ "n": 220,
186
+ "rate": 0.9272727272727272,
187
+ "ci95": [
188
+ 0.8851382050617915,
189
+ 0.9547414241045473
190
+ ]
191
+ },
192
+ "abstention": {
193
+ "hits": 16,
194
+ "n": 220,
195
+ "rate": 0.07272727272727272,
196
+ "ci95": [
197
+ 0.04525857589545253,
198
+ 0.1148617949382084
199
+ ]
200
+ },
201
+ "outside_input_limits": 0
202
+ },
203
+ "decoder": {
204
+ "flags": {
205
+ "hits": 57,
206
+ "n": 110,
207
+ "rate": 0.5181818181818182,
208
+ "ci95": [
209
+ 0.4257777238231319,
210
+ 0.6093588167736271
211
+ ]
212
+ },
213
+ "abstention": {
214
+ "hits": 49,
215
+ "n": 110,
216
+ "rate": 0.44545454545454544,
217
+ "ci95": [
218
+ 0.3559755711590631,
219
+ 0.53861480705066
220
+ ]
221
+ },
222
+ "outside_input_limits": 1
223
+ },
224
+ "general_human": {
225
+ "flags": {
226
+ "hits": 2,
227
+ "n": 220,
228
+ "rate": 0.00909090909090909,
229
+ "ci95": [
230
+ 0.00249655343526377,
231
+ 0.03253536199064455
232
+ ]
233
+ },
234
+ "abstention": {
235
+ "hits": 23,
236
+ "n": 220,
237
+ "rate": 0.10454545454545454,
238
+ "ci95": [
239
+ 0.0706788038882292,
240
+ 0.15198579464930803
241
+ ]
242
+ },
243
+ "outside_input_limits": 1
244
+ },
245
+ "seq2seq": {
246
+ "flags": {
247
+ "hits": 78,
248
+ "n": 110,
249
+ "rate": 0.7090909090909091,
250
+ "ci95": [
251
+ 0.6183048036071215,
252
+ 0.7857654132556071
253
+ ]
254
+ },
255
+ "abstention": {
256
+ "hits": 32,
257
+ "n": 110,
258
+ "rate": 0.2909090909090909,
259
+ "ci95": [
260
+ 0.214234586744393,
261
+ 0.3816951963928785
262
+ ]
263
+ },
264
+ "outside_input_limits": 0
265
+ }
266
+ },
267
+ "paraphrase_discrimination": {
268
+ "decoder": {
269
+ "auroc": 0.9780486783125969,
270
+ "recall_at_1pct_fpr": 0.5229357798165137,
271
+ "recall_at_5pct_fpr": 0.8990825688073395
272
+ },
273
+ "seq2seq": {
274
+ "auroc": 0.9839352428393525,
275
+ "recall_at_1pct_fpr": 0.7090909090909091,
276
+ "recall_at_5pct_fpr": 0.8272727272727273
277
+ }
278
+ }
279
+ }
280
+ },
281
+ "release": true,
282
+ "gates": {
283
+ "general_fpr": true,
284
+ "learner_fpr": true,
285
+ "paraphrase_gain": true,
286
+ "clean_ai_recall": true,
287
+ "native_cpu_parity": true,
288
+ "model_size": true,
289
+ "warm_latency": true,
290
+ "general_human_support": true,
291
+ "asap_learner_support": true,
292
+ "decoder_support": true,
293
+ "seq2seq_support": true,
294
+ "clean_ai_support": true
295
+ },
296
+ "model": {
297
+ "repo": "Oxidane/tmr-ai-text-detector",
298
+ "revision": "draftmark-ft-9104295a09032567",
299
+ "baseRevision": "0ceddea903015ef99cbaa040a4d8a216aed9c683",
300
+ "name": "Draftmark RoBERTa FT INT8",
301
+ "license": "MIT",
302
+ "licenseUrl": "https://huggingface.co/Oxidane/tmr-ai-text-detector#license",
303
+ "limit": 512,
304
+ "tokenizerType": "roberta",
305
+ "source": "static",
306
+ "quantization": "weights",
307
+ "files": {
308
+ "model": [
309
+ "model.int8.onnx",
310
+ 127550037,
311
+ "9104295a0903256724f44b86523ad32da0b800efc1ff6a3fc3d2f8e2d2339418"
312
+ ],
313
+ "tokenizer": [
314
+ "tokenizer.json",
315
+ 3558741,
316
+ "1f33749d010b4d63908e5c174c341622cb45039dd73a139dcd95bd74cc7e304b"
317
+ ],
318
+ "config": [
319
+ "tokenizer_config.json",
320
+ 1354,
321
+ "288b4077af1ffb3beead6d96fccfc93beb2df9b689cbb038c4eb329165efc43a"
322
+ ]
323
+ }
324
+ },
325
+ "model_bytes": 131110132,
326
+ "training": {
327
+ "base": "Oxidane/tmr-ai-text-detector@0ceddea903015ef99cbaa040a4d8a216aed9c683",
328
+ "device": "mps",
329
+ "torch": "2.8.0",
330
+ "seed": 36513,
331
+ "max_training_tokens": 384,
332
+ "trainable_parameters": 28943618,
333
+ "top_encoder_layers": 4,
334
+ "batch_size": 16,
335
+ "learning_rate": 2e-05,
336
+ "cohort_weights": {
337
+ "learner": 1.45,
338
+ "decoder": 1.3,
339
+ "seq2seq": 0.9,
340
+ "encoder": 1.0
341
+ },
342
+ "epochs": [
343
+ {
344
+ "upper": 0.975287437438965,
345
+ "rates": {
346
+ "asap_learner": 0.009900990099009901,
347
+ "seq2seq": 0.8636363636363636,
348
+ "clean_ai": 0.9590909090909091,
349
+ "general_human": 0.00909090909090909,
350
+ "decoder": 0.4090909090909091
351
+ },
352
+ "selection": 0.9720454545454545,
353
+ "epoch": 1,
354
+ "train_loss": 0.33598193104093854
355
+ },
356
+ {
357
+ "upper": 0.9825209975242616,
358
+ "rates": {
359
+ "asap_learner": 0.009900990099009901,
360
+ "seq2seq": 0.8818181818181818,
361
+ "clean_ai": 0.9363636363636364,
362
+ "general_human": 0.00909090909090909,
363
+ "decoder": 0.6818181818181818
364
+ },
365
+ "selection": 1.1095454545454544,
366
+ "epoch": 2,
367
+ "train_loss": 0.1008723359008851
368
+ },
369
+ {
370
+ "upper": 0.9987732768058778,
371
+ "rates": {
372
+ "asap_learner": 0.009900990099009901,
373
+ "seq2seq": 0.9727272727272728,
374
+ "clean_ai": 0.9772727272727273,
375
+ "general_human": 0.00909090909090909,
376
+ "decoder": 0.6272727272727273
377
+ },
378
+ "selection": 1.1420454545454546,
379
+ "epoch": 3,
380
+ "train_loss": 0.061243358406307756
381
+ }
382
+ ],
383
+ "selected_epoch": 3,
384
+ "checkpoint_sha256": "4c10be4f8da2d2f75ee14c2b1d8fb143f549edec478e0d9121877a0977fa1ea4"
385
+ },
386
+ "data": {
387
+ "sources": {
388
+ "DetectRL-X": "https://huggingface.co/datasets/WUJUNCHAO/DetectRL-X/tree/ccc9a0a74793dd3448e0da1650b430f5df1b0402",
389
+ "ASAP 2.0": "https://github.com/scrosseye/ASAP_2.0/tree/060ab225ca0984c0bf43ff222bf6bb2bc6195b6f",
390
+ "DetectionAI": "https://github.com/brianjabarian/DetectionAI/tree/5610637e3df52e107e642ed151e7f842b15f79d2",
391
+ "MAGE": "https://huggingface.co/datasets/yaful/MAGE/tree/342663f0a2b775455c023f5d36a1341ff0ec5402",
392
+ "APT-Eval": "https://github.com/ShoumikSaha/ai-polished-text/tree/53b1d2619a633e025998d6c7d0a12b0228b589da",
393
+ "Heterogeneous AI Spans": "https://huggingface.co/datasets/open-text-detector/heterogeneous-ai-spans/tree/c8a59b129c34cfd9c67f739ae049abfff26fc2d3",
394
+ "Ettin public training subset": "https://huggingface.co/datasets/nakas/gpttrace-text-train/tree/3f31325869bfc5414c1e8c713a6a4fd75b3eebb7",
395
+ "Shijaku\u2013Canhasi TOEFL": "https://github.com/rexshijaku/chatgpt-generated-text-detection-corpus/tree/c0eb34cfd5c96cc02f7109a561eb753128cae9e6",
396
+ "RAID train_none.csv": "sha256:c5467bca6fc7f5c728c676450c7f84ce401df6c6ccc6d82c47e3b5f3c6d6fce4"
397
+ },
398
+ "asap_train_sha256": "aec01e98eb16cc3bc3828010ca053a09daecc2821dd2105f8a7333089271beb4",
399
+ "counts": {
400
+ "train": {
401
+ "decoder": 680,
402
+ "clean_ai": 1755,
403
+ "general_human": 1754,
404
+ "seq2seq": 430,
405
+ "encoder": 420,
406
+ "learner": 1300
407
+ },
408
+ "calibration": {
409
+ "decoder": 110,
410
+ "clean_ai": 220,
411
+ "general_human": 220,
412
+ "seq2seq": 110,
413
+ "asap_learner": 101
414
+ },
415
+ "holdout": {
416
+ "decoder": 150,
417
+ "clean_ai": 300,
418
+ "general_human": 300,
419
+ "seq2seq": 150,
420
+ "asap_learner": 220
421
+ }
422
+ },
423
+ "sha256": {
424
+ "train": "bb4793d1a71c8c9470196eaf19810605e01433e7854fc20d678ee6ad3a035707",
425
+ "calibration": "a81c7b90b5d1dd5a1ebc3cb4711ada93858f22f31604db3e3f408e5a46ee8878",
426
+ "holdout": "c305977e14a03b9ae6c07ac35ac95ac4afc09f9fd1f8df2f9348f9d69afb7f0e"
427
+ },
428
+ "groups_excluded_for_overlap": 272,
429
+ "groups_excluded_for_pretrained_overlap": 265,
430
+ "training_overlap_limit": "Screened against the previous benchmark, the new training/calibration data, RAID train without attacks, MAGE train, and the public GPTTrace training subset. Unpublished training rows are unverifiable."
431
+ },
432
+ "performance": {
433
+ "browser": "Chromium 131.0.6778.205",
434
+ "device": "darwin 25.6.0 Apple M4 Pro",
435
+ "engine": "ONNX Runtime Web WASM CPU, one thread per worker",
436
+ "worker_sha256": "e6eba6365b39e878221f4d8e6b274b5ffa4092c6002a253c235a3240a21a434e",
437
+ "parity": true,
438
+ "label_order": [
439
+ "human",
440
+ "ai"
441
+ ],
442
+ "cases": [
443
+ {
444
+ "fixture": "example",
445
+ "expected": 0.9987629118304412,
446
+ "score": 0.9987629265593501,
447
+ "delta": 1.4728908870331736e-08,
448
+ "token_ids_match": true,
449
+ "pass_token_counts": [
450
+ 204
451
+ ],
452
+ "chunks": 1,
453
+ "tokens": 204,
454
+ "expected_chunks": 1,
455
+ "expected_tokens": 204
456
+ },
457
+ {
458
+ "fixture": "300-word",
459
+ "expected": 0.9992861080622527,
460
+ "score": 0.9992861089126702,
461
+ "delta": 8.504175141865744e-10,
462
+ "token_ids_match": true,
463
+ "pass_token_counts": [
464
+ 336
465
+ ],
466
+ "chunks": 1,
467
+ "tokens": 336,
468
+ "expected_chunks": 1,
469
+ "expected_tokens": 336
470
+ },
471
+ {
472
+ "fixture": "multi-window",
473
+ "expected": 0.9687787378573235,
474
+ "score": 0.9687795552453534,
475
+ "delta": 8.173880299278125e-07,
476
+ "token_ids_match": true,
477
+ "pass_token_counts": [
478
+ 643
479
+ ],
480
+ "chunks": 2,
481
+ "tokens": 643,
482
+ "expected_chunks": 2,
483
+ "expected_tokens": 643
484
+ },
485
+ {
486
+ "fixture": "oversized-sentence",
487
+ "expected": 0.006943256878519529,
488
+ "score": 0.0069432706767937865,
489
+ "delta": 1.3798274257556531e-08,
490
+ "token_ids_match": true,
491
+ "pass_token_counts": [
492
+ 1281
493
+ ],
494
+ "chunks": 3,
495
+ "tokens": 1281,
496
+ "expected_chunks": 3,
497
+ "expected_tokens": 1281
498
+ },
499
+ {
500
+ "fixture": "unicode",
501
+ "expected": 0.04916038580631243,
502
+ "score": 0.04916000132066757,
503
+ "delta": 3.8448564485676906e-07,
504
+ "token_ids_match": true,
505
+ "pass_token_counts": [
506
+ 246
507
+ ],
508
+ "chunks": 1,
509
+ "tokens": 246,
510
+ "expected_chunks": 1,
511
+ "expected_tokens": 246
512
+ }
513
+ ],
514
+ "warm_p50_ms": 1247,
515
+ "warm_p95_ms": 1262,
516
+ "warm_samples": 20,
517
+ "reference_words": 300,
518
+ "first_scan_ms": 1364,
519
+ "first_scan_download_observed": true
520
+ },
521
+ "holdout_runtime": {
522
+ "browser": "Chromium 131.0.6778.205",
523
+ "device": "darwin 25.6.0 Apple M4 Pro",
524
+ "engine": "ONNX Runtime Web WASM CPU, one thread per worker",
525
+ "worker_sha256": "e6eba6365b39e878221f4d8e6b274b5ffa4092c6002a253c235a3240a21a434e",
526
+ "signature": "80da49b4ca2df09f57c5d3efc50407d6e8ce7f1ef5a91250ee5130035dc4056a",
527
+ "specs": {
528
+ "live": {
529
+ "model": "ettin",
530
+ "version": "browser-v1",
531
+ "upper": 0.9998051638246666,
532
+ "lower": 0.25,
533
+ "experimental": false
534
+ },
535
+ "finetuned/full": {
536
+ "model": "finetuned",
537
+ "scoring": "full",
538
+ "version": "browser-v3",
539
+ "experimental": false,
540
+ "upper": 0.999146566314596,
541
+ "lower": 0.25
542
+ }
543
+ }
544
+ },
545
+ "holdout": {
546
+ "live": {
547
+ "cohorts": {
548
+ "asap_learner": {
549
+ "flags": {
550
+ "hits": 80,
551
+ "n": 220,
552
+ "rate": 0.36363636363636365,
553
+ "ci95": [
554
+ 0.3029141434403334,
555
+ 0.42903916640019657
556
+ ]
557
+ },
558
+ "abstention": {
559
+ "hits": 98,
560
+ "n": 220,
561
+ "rate": 0.44545454545454544,
562
+ "ci95": [
563
+ 0.3812726964449632,
564
+ 0.5115086274912487
565
+ ]
566
+ },
567
+ "outside_input_limits": 0
568
+ },
569
+ "clean_ai": {
570
+ "flags": {
571
+ "hits": 215,
572
+ "n": 300,
573
+ "rate": 0.7166666666666667,
574
+ "ci95": [
575
+ 0.6631845423956875,
576
+ 0.7646699712719605
577
+ ]
578
+ },
579
+ "abstention": {
580
+ "hits": 63,
581
+ "n": 300,
582
+ "rate": 0.21,
583
+ "ci95": [
584
+ 0.16772109488365303,
585
+ 0.25961209451503364
586
+ ]
587
+ },
588
+ "outside_input_limits": 0
589
+ },
590
+ "decoder": {
591
+ "flags": {
592
+ "hits": 18,
593
+ "n": 150,
594
+ "rate": 0.12,
595
+ "ci95": [
596
+ 0.0772684043967938,
597
+ 0.18170966135395242
598
+ ]
599
+ },
600
+ "abstention": {
601
+ "hits": 71,
602
+ "n": 150,
603
+ "rate": 0.47333333333333333,
604
+ "ci95": [
605
+ 0.39509757671394596,
606
+ 0.5529008840404923
607
+ ]
608
+ },
609
+ "outside_input_limits": 1
610
+ },
611
+ "general_human": {
612
+ "flags": {
613
+ "hits": 10,
614
+ "n": 300,
615
+ "rate": 0.03333333333333333,
616
+ "ci95": [
617
+ 0.018204749873650852,
618
+ 0.0602624514575691
619
+ ]
620
+ },
621
+ "abstention": {
622
+ "hits": 150,
623
+ "n": 300,
624
+ "rate": 0.5,
625
+ "ci95": [
626
+ 0.44377849611195097,
627
+ 0.556221503888049
628
+ ]
629
+ },
630
+ "outside_input_limits": 1
631
+ },
632
+ "seq2seq": {
633
+ "flags": {
634
+ "hits": 132,
635
+ "n": 150,
636
+ "rate": 0.88,
637
+ "ci95": [
638
+ 0.8182903386460476,
639
+ 0.9227315956032063
640
+ ]
641
+ },
642
+ "abstention": {
643
+ "hits": 18,
644
+ "n": 150,
645
+ "rate": 0.12,
646
+ "ci95": [
647
+ 0.0772684043967938,
648
+ 0.18170966135395242
649
+ ]
650
+ },
651
+ "outside_input_limits": 1
652
+ }
653
+ },
654
+ "paraphrase_discrimination": {
655
+ "decoder": {
656
+ "auroc": 0.553657605889879,
657
+ "recall_at_1pct_fpr": 0.03355704697986577,
658
+ "recall_at_5pct_fpr": 0.12751677852348994
659
+ },
660
+ "seq2seq": {
661
+ "auroc": 0.9725258692285246,
662
+ "recall_at_1pct_fpr": 0.825503355704698,
663
+ "recall_at_5pct_fpr": 0.8859060402684564
664
+ }
665
+ }
666
+ },
667
+ "finetuned/full": {
668
+ "cohorts": {
669
+ "asap_learner": {
670
+ "flags": {
671
+ "hits": 0,
672
+ "n": 220,
673
+ "rate": 0.0,
674
+ "ci95": [
675
+ 0,
676
+ 0.017162136081943655
677
+ ]
678
+ },
679
+ "abstention": {
680
+ "hits": 3,
681
+ "n": 220,
682
+ "rate": 0.013636363636363636,
683
+ "ci95": [
684
+ 0.004648152891035449,
685
+ 0.039318652206855195
686
+ ]
687
+ },
688
+ "outside_input_limits": 0
689
+ },
690
+ "clean_ai": {
691
+ "flags": {
692
+ "hits": 277,
693
+ "n": 300,
694
+ "rate": 0.9233333333333333,
695
+ "ci95": [
696
+ 0.8875891334382622,
697
+ 0.9483727624969882
698
+ ]
699
+ },
700
+ "abstention": {
701
+ "hits": 23,
702
+ "n": 300,
703
+ "rate": 0.07666666666666666,
704
+ "ci95": [
705
+ 0.05162723750301175,
706
+ 0.11241086656173778
707
+ ]
708
+ },
709
+ "outside_input_limits": 0
710
+ },
711
+ "decoder": {
712
+ "flags": {
713
+ "hits": 89,
714
+ "n": 150,
715
+ "rate": 0.5933333333333334,
716
+ "ci95": [
717
+ 0.51334517440468,
718
+ 0.6686602129547861
719
+ ]
720
+ },
721
+ "abstention": {
722
+ "hits": 59,
723
+ "n": 150,
724
+ "rate": 0.3933333333333333,
725
+ "ci95": [
726
+ 0.3187585669410804,
727
+ 0.47323527607667293
728
+ ]
729
+ },
730
+ "outside_input_limits": 1
731
+ },
732
+ "general_human": {
733
+ "flags": {
734
+ "hits": 1,
735
+ "n": 300,
736
+ "rate": 0.0033333333333333335,
737
+ "ci95": [
738
+ 0.0005886425761407379,
739
+ 0.018637164554943353
740
+ ]
741
+ },
742
+ "abstention": {
743
+ "hits": 39,
744
+ "n": 300,
745
+ "rate": 0.13,
746
+ "ci95": [
747
+ 0.09657483743516235,
748
+ 0.17278130076316203
749
+ ]
750
+ },
751
+ "outside_input_limits": 1
752
+ },
753
+ "seq2seq": {
754
+ "flags": {
755
+ "hits": 110,
756
+ "n": 150,
757
+ "rate": 0.7333333333333333,
758
+ "ci95": [
759
+ 0.6573840257093969,
760
+ 0.7976294426892675
761
+ ]
762
+ },
763
+ "abstention": {
764
+ "hits": 39,
765
+ "n": 150,
766
+ "rate": 0.26,
767
+ "ci95": [
768
+ 0.19642034813317322,
769
+ 0.33556579865677183
770
+ ]
771
+ },
772
+ "outside_input_limits": 1
773
+ }
774
+ },
775
+ "paraphrase_discrimination": {
776
+ "decoder": {
777
+ "auroc": 0.9850957329801799,
778
+ "recall_at_1pct_fpr": 0.7449664429530202,
779
+ "recall_at_5pct_fpr": 0.9261744966442953
780
+ },
781
+ "seq2seq": {
782
+ "auroc": 0.9826715449709322,
783
+ "recall_at_1pct_fpr": 0.7651006711409396,
784
+ "recall_at_5pct_fpr": 0.8523489932885906
785
+ }
786
+ }
787
+ }
788
+ },
789
+ "paraphrase_gain": {
790
+ "delta": 0.16333333333333333,
791
+ "by_method": {
792
+ "decoder": 0.47333333333333333,
793
+ "seq2seq": -0.14666666666666667
794
+ },
795
+ "ci95": [
796
+ 0.10662015139065152,
797
+ 0.22040486624644678
798
+ ],
799
+ "bootstrap_source_groups": 300,
800
+ "bootstrap_samples": 10000
801
+ },
802
+ "clean_ai": {
803
+ "live": {
804
+ "hits": 215,
805
+ "n": 300,
806
+ "rate": 0.7166666666666667,
807
+ "ci95": [
808
+ 0.6631845423956875,
809
+ 0.7646699712719605
810
+ ]
811
+ },
812
+ "candidate": {
813
+ "hits": 277,
814
+ "n": 300,
815
+ "rate": 0.9233333333333333,
816
+ "ci95": [
817
+ 0.8875891334382622,
818
+ 0.9483727624969882
819
+ ]
820
+ },
821
+ "delta": 0.20666666666666667
822
+ }
823
+ }
handoff.md ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Draftmark GPU training handoff
2
+
3
+ Draftmark v3 is a binary English writing-pattern detector fine-tuned from TMR RoBERTa. Production runs the weight-only INT8 ONNX artifact in a browser WASM worker. The next training run should target decoder rewrites without giving back sequence-to-sequence recall or increasing false flags on human prose and learner essays.
4
+
5
+ Paths to scripts below refer to the Draftmark source workspace. Transfer the source checkout or a source-only archive to the cluster, then rebuild the benchmark cache from the pinned sources. Keep cluster credentials in the scheduler's secret store.
6
+
7
+ ## Artifacts and starting point
8
+
9
+ | Artifact | Location |
10
+ | --- | --- |
11
+ | Public model release | [saksornr/draftmark-roberta-int8](https://huggingface.co/saksornr/draftmark-roberta-int8) |
12
+ | Trainable weight delta | [training/trainable.safetensors](https://huggingface.co/saksornr/draftmark-roberta-int8/blob/training/training/trainable.safetensors) |
13
+ | Pinned TMR base | [Oxidane/tmr-ai-text-detector at 0ceddea](https://huggingface.co/Oxidane/tmr-ai-text-detector/tree/0ceddea903015ef99cbaa040a4d8a216aed9c683) |
14
+ | Browser export | [onnx/model.int8.onnx](https://huggingface.co/saksornr/draftmark-roberta-int8/blob/main/onnx/model.int8.onnx) |
15
+ | Frozen evaluation | [finetune-v3.json](https://draftmark-virid.vercel.app/detector-finetune-benchmark.json) |
16
+ | Original workspace recipe | `README.md`, section “Train and evaluate the local RoBERTa candidate” |
17
+
18
+ The training branch stores the **replacement tensors** for the last four encoder layers and classification head. Load them over the pinned base, with no addition to the base weights. The checkpoint contains 28,943,618 trained parameters. Start a new optimizer and scheduler for continued training.
19
+
20
+ Use Python 3.12 with the cluster's CUDA-enabled PyTorch build and the compatible dependencies in `detector/requirements-finetune.txt`. The following commands create a standard Transformers checkpoint in scratch storage.
21
+
22
+ ~~~sh
23
+ export DRAFTMARK_SCRATCH="$PWD/draftmark-scratch"
24
+ mkdir -p "$DRAFTMARK_SCRATCH"
25
+ hf download saksornr/draftmark-roberta-int8 training/trainable.safetensors \
26
+ --revision training --local-dir "$DRAFTMARK_SCRATCH"
27
+
28
+ python - <<'PY'
29
+ import hashlib
30
+ import os
31
+ from pathlib import Path
32
+
33
+ from safetensors.torch import load_file
34
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer
35
+
36
+ scratch = Path(os.environ["DRAFTMARK_SCRATCH"])
37
+ delta = scratch / "training/trainable.safetensors"
38
+ expected_hash = "4c10be4f8da2d2f75ee14c2b1d8fb143f549edec478e0d9121877a0977fa1ea4"
39
+ with delta.open("rb") as stream:
40
+ assert hashlib.file_digest(stream, "sha256").hexdigest() == expected_hash
41
+
42
+ base = "Oxidane/tmr-ai-text-detector"
43
+ revision = "0ceddea903015ef99cbaa040a4d8a216aed9c683"
44
+ model = AutoModelForSequenceClassification.from_pretrained(base, revision=revision)
45
+ tokenizer = AutoTokenizer.from_pretrained(base, revision=revision)
46
+ tensors = load_file(delta)
47
+ prefixes = tuple(f"roberta.encoder.layer.{index}." for index in range(8, 12)) + ("classifier.",)
48
+ expected = {name for name, _ in model.named_parameters() if name.startswith(prefixes)}
49
+ assert set(tensors) == expected
50
+ assert sum(value.numel() for value in tensors.values()) == 28_943_618
51
+ missing, unexpected = model.load_state_dict(tensors, strict=False)
52
+ assert not unexpected and set(missing) == set(model.state_dict()) - expected
53
+ assert model.config.id2label == {0: "human", 1: "ai"}
54
+
55
+ destination = scratch / "warm-start"
56
+ model.save_pretrained(destination, safe_serialization=True)
57
+ tokenizer.save_pretrained(destination)
58
+ print(destination)
59
+ PY
60
+ ~~~
61
+
62
+ The resulting directory is the GPU training input. The browser graph and tokenizer total 131,110,132 bytes. The exact ONNX SHA-256 is `9104295a0903256724f44b86523ad32da0b800efc1ff6a3fc3d2f8e2d2339418`.
63
+
64
+ ## Data and experiment plan
65
+
66
+ 1. Reproduce the v3 control with `detector/finetune_data.py` and `detector/finetune_model.py`. The run used 6,339 training drafts, 761 calibration drafts, and 1,120 held-out drafts. The aggregate report contains source pins, cohort counts, split hashes, and overlap exclusions.
67
+ 2. Prepare fresh source-grouped splits before looking at predictions. Keep human originals, paired AI outputs, rewrites, and near duplicates in the same split. Screen across splits and against the previous Draftmark evaluation manifests and available pretrained manifests. Treat the v3 holdout as a regression suite and reserve an untouched final test for the next release.
68
+ 3. Add decoder rewrites from new generators and methods, along with their matched clean AI drafts and human originals. Retain sequence-to-sequence examples in each training run. Add learner essays from a separately licensed source as a fairness check, ideally from a corpus distinct from ASAP 2.0. Retain learner negatives from multiple prompts and proficiency levels. Track method, generator, domain, prompt, original source, and corpus revision.
69
+ 4. In DetectRL-X, join the attack file's changed `llm_generated_text` to its clean counterpart in the general file. Preserve the separate category for human-authored drafts that AI polished. Use the author's original label for human controls and exclude ambiguous pairs. [DetectRL-X paper](https://aclanthology.org/2026.acl-long.1773/) · [ASAP 2.0 corpus](https://github.com/scrosseye/ASAP_2.0)
70
+
71
+ Keep source essays and per-document predictions in access-controlled storage. Share aggregate metrics, source manifests or hashes, the release policy, and the model artifacts.
72
+
73
+ ## CUDA cluster implementation
74
+
75
+ The checked-in trainer supports CPU and Apple MPS. Add a CUDA/DDP entry point before launching a multi-GPU job. Reuse the existing model, tokenization, cohort weights, and checkpoint selection logic so the first cluster run has a comparable control.
76
+
77
+ - **Control settings** Keep encoder layers 0–7 and embeddings frozen, train layers 8–11 and the classifier, and use a 384-token training cap, global batch 16, AdamW at 2e-5, weight decay 0.01, gradient clip 1.0, and three epochs. Warm up over the first twelfth of optimizer steps and decay to 25% of the peak learning rate. The original seed was 36513. Learner, decoder, seq2seq, and encoder example weights were 1.45, 1.30, 0.90, and 1.0.
78
+ - **Distributed execution** Bind each process to `LOCAL_RANK`, initialize NCCL, and wrap the classifier with `DistributedDataParallel`. Use one process per GPU, BF16 autocast on supported hardware, and length-bucketed rank shards with the same number of updates. Derive gradient accumulation from the global batch target. Normalize weighted loss across ranks and accumulation steps so the effective cohort weights match the control.
79
+ - **Validation and resume** Gather raw scores with stable IDs and deduplicate padding rows from distributed sampling. The v3 selection criterion was mean paraphrase recall plus 0.35 times unedited AI recall on calibration, with false-flag targets of 1% on general prose and 3% on learner essays. Save model, optimizer, scheduler, scaler if applicable, epoch, step, RNG state, dataset hashes, and hyperparameters on rank zero. Verify that a resumed smoke run matches the expected progress before requesting a longer allocation.
80
+ - **Launch** After implementing the CUDA entry point, start with `torchrun --standalone --nproc-per-node=4 <entrypoint> <arguments>` on one node. For multiple nodes, use one `torchrun` launcher per node with the same rendezvous endpoint and job-specific rendezvous ID. Record world size, effective batch, CUDA/PyTorch versions, GPU type, and job configuration. [PyTorch torchrun documentation](https://docs.pytorch.org/docs/stable/elastic/run.html)
81
+
82
+ Run a matched warm-start experiment before changing model size or training all layers. Useful ablations are the prior cohort mix versus added decoder and learner hard negatives, then a 384- versus 512-token training window. Compare runs at frozen false-positive budgets. Watch decoder and seq2seq recall separately so their mean cannot hide a large regression.
83
+
84
+ ## Export and release gates
85
+
86
+ 1. Save the chosen Transformers checkpoint and export dynamic batch and sequence axes with ONNX opset 17. Reuse the weight-only INT8 export in `detector/finetune_model.py`. Float activations avoided the native/Chrome score drift observed with the dynamic INT8 trial. Verify the model plus tokenizer are **under 160 MB**.
87
+ 2. Preserve production semantics from `src/detector/detector.worker.ts` and `src/detector/decision.ts`. Inputs use English prose of 150–2,000 words and at most 20,000 characters. Score sentence-aligned chunks up to 512 tokens including special tokens, split oversized sentences without truncating the draft, and weight the score by content-token count. Class order is human, then AI. The current upper and lower cutoffs are 0.999146566314596 and 0.25. Fit new cutoffs on the exported WASM calibration scores.
88
+ 3. Freeze the candidate, threshold, holdout, and worker checksums before evaluating the final set. Reuse `scripts/paraphrase-browser.mjs` and `detector/finetune_eval.py`, updating their baseline loader from the archived Ettin policy to the published v3 artifact and policy. Report both paraphrase families, clean AI recall, general and learner false flags, abstentions, counts, confidence intervals, and browser latency. Count every visible AI flag as a positive and every AI abstention as a miss.
89
+ 4. Require **<2%** false flags on general human prose and **<5%** on human-written learner essays. Use the shipped v3 as the new comparison baseline. The last release required at least a **10-point** mean paraphrase recall gain with a positive lower bound on the paired 95% interval, at most a **5-point** clean-AI recall loss, native/WASM score parity, and **≤5 seconds p95** for a warm 300-word browser scan. Evaluate on both desktop and mobile before promoting a new static build.
90
+
91
+ | v3 result on the 1,120-draft holdout | Measured result |
92
+ | --- | --- |
93
+ | Mean paraphrase recall | 66.3% vs 50.0% for Ettin |
94
+ | Decoder rewrite recall | 89/150 vs 18/150 |
95
+ | Sequence-to-sequence rewrite recall | 110/150 vs 132/150 |
96
+ | Unedited AI recall | 277/300 vs 215/300 |
97
+ | General-human false flags | 1/300 |
98
+ | Learner false flags | 0/220 |
99
+ | Warm 300-word scan | 1.26 s p95 on Apple M4 Pro in Chromium |
100
+
101
+ These results establish performance on the listed cohorts. A state-of-the-art comparison requires evaluating the exact new artifact against other detectors on the same independent benchmark at matched false-positive rates. [RAID](https://github.com/liamdugan/raid)
onnx/model.int8.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9104295a0903256724f44b86523ad32da0b800efc1ff6a3fc3d2f8e2d2339418
3
+ size 127550037
release-manifest.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "browser-v3",
3
+ "base_model": "Oxidane/tmr-ai-text-detector",
4
+ "base_revision": "0ceddea903015ef99cbaa040a4d8a216aed9c683",
5
+ "policy": {
6
+ "model": "finetuned",
7
+ "scoring": "full",
8
+ "version": "browser-v3",
9
+ "experimental": false,
10
+ "upper": 0.999146566314596,
11
+ "lower": 0.25
12
+ },
13
+ "weight_only_int8": true,
14
+ "browser_bytes": 131110132,
15
+ "files": {
16
+ "onnx/model.int8.onnx": {
17
+ "size": 127550037,
18
+ "sha256": "9104295a0903256724f44b86523ad32da0b800efc1ff6a3fc3d2f8e2d2339418"
19
+ },
20
+ "tokenizer.json": {
21
+ "size": 3558741,
22
+ "sha256": "1f33749d010b4d63908e5c174c341622cb45039dd73a139dcd95bd74cc7e304b"
23
+ },
24
+ "tokenizer_config.json": {
25
+ "size": 1354,
26
+ "sha256": "288b4077af1ffb3beead6d96fccfc93beb2df9b689cbb038c4eb329165efc43a"
27
+ }
28
+ }
29
+ }
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
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "0": {
5
+ "content": "<s>",
6
+ "lstrip": false,
7
+ "normalized": true,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "1": {
13
+ "content": "<pad>",
14
+ "lstrip": false,
15
+ "normalized": true,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "2": {
21
+ "content": "</s>",
22
+ "lstrip": false,
23
+ "normalized": true,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ },
28
+ "3": {
29
+ "content": "<unk>",
30
+ "lstrip": false,
31
+ "normalized": true,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "50264": {
37
+ "content": "<mask>",
38
+ "lstrip": true,
39
+ "normalized": false,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ }
44
+ },
45
+ "bos_token": "<s>",
46
+ "clean_up_tokenization_spaces": false,
47
+ "cls_token": "<s>",
48
+ "eos_token": "</s>",
49
+ "errors": "replace",
50
+ "extra_special_tokens": {},
51
+ "mask_token": "<mask>",
52
+ "max_length": 512,
53
+ "model_max_length": 512,
54
+ "pad_token": "<pad>",
55
+ "sep_token": "</s>",
56
+ "stride": 0,
57
+ "tokenizer_class": "RobertaTokenizer",
58
+ "trim_offsets": true,
59
+ "truncation_side": "right",
60
+ "truncation_strategy": "longest_first",
61
+ "unk_token": "<unk>"
62
+ }