pcuenq HF Staff commited on
Commit
32e5f25
·
1 Parent(s): b28e70d

Upload flexible_shapes_repro.ipynb

Browse files
Files changed (1) hide show
  1. flexible_shapes_repro.ipynb +567 -0
flexible_shapes_repro.ipynb ADDED
@@ -0,0 +1,567 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "8f5b0950",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "import coremltools as ct"
11
+ ]
12
+ },
13
+ {
14
+ "cell_type": "code",
15
+ "execution_count": 2,
16
+ "id": "009656b9",
17
+ "metadata": {},
18
+ "outputs": [],
19
+ "source": [
20
+ "from transformers import AutoTokenizer, AutoModel\n",
21
+ "import numpy as np\n",
22
+ "import torch\n",
23
+ "import torch.nn as nn"
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "markdown",
28
+ "id": "c0eb4797",
29
+ "metadata": {},
30
+ "source": [
31
+ "## Model Setup"
32
+ ]
33
+ },
34
+ {
35
+ "cell_type": "code",
36
+ "execution_count": 3,
37
+ "id": "6a3b370e",
38
+ "metadata": {},
39
+ "outputs": [],
40
+ "source": [
41
+ "model_id = \"bert-base-uncased\""
42
+ ]
43
+ },
44
+ {
45
+ "cell_type": "code",
46
+ "execution_count": 4,
47
+ "id": "1b4b35d8",
48
+ "metadata": {},
49
+ "outputs": [
50
+ {
51
+ "name": "stderr",
52
+ "output_type": "stream",
53
+ "text": [
54
+ "Some weights of the model checkpoint at bert-base-uncased were not used when initializing BertModel: ['cls.seq_relationship.bias', 'cls.predictions.transform.LayerNorm.bias', 'cls.predictions.transform.LayerNorm.weight', 'cls.seq_relationship.weight', 'cls.predictions.transform.dense.bias', 'cls.predictions.transform.dense.weight', 'cls.predictions.decoder.weight', 'cls.predictions.bias']\n",
55
+ "- This IS expected if you are initializing BertModel from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n",
56
+ "- This IS NOT expected if you are initializing BertModel from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n"
57
+ ]
58
+ }
59
+ ],
60
+ "source": [
61
+ "tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
62
+ "model = AutoModel.from_pretrained(model_id)\n",
63
+ "\n",
64
+ "model = model.eval()"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "code",
69
+ "execution_count": 5,
70
+ "id": "f3f55386",
71
+ "metadata": {},
72
+ "outputs": [],
73
+ "source": [
74
+ "compute_units = ct.ComputeUnit.CPU_ONLY"
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": 6,
80
+ "id": "ccbd0617",
81
+ "metadata": {},
82
+ "outputs": [],
83
+ "source": [
84
+ "shape = (1, 128)\n",
85
+ "inputs = {\n",
86
+ " \"input_ids\": np.random.randint(0, tokenizer.vocab_size, shape),\n",
87
+ " \"attention_mask\": np.ones(shape, dtype=np.int64),\n",
88
+ "}"
89
+ ]
90
+ },
91
+ {
92
+ "cell_type": "code",
93
+ "execution_count": 7,
94
+ "id": "20ea1402",
95
+ "metadata": {},
96
+ "outputs": [
97
+ {
98
+ "data": {
99
+ "text/plain": [
100
+ "odict_keys(['last_hidden_state', 'pooler_output'])"
101
+ ]
102
+ },
103
+ "execution_count": 7,
104
+ "metadata": {},
105
+ "output_type": "execute_result"
106
+ }
107
+ ],
108
+ "source": [
109
+ "t_inputs = {k: torch.tensor(v, dtype=torch.int32) for k, v in inputs.items()}\n",
110
+ "outputs = model(**t_inputs)\n",
111
+ "outputs.keys()"
112
+ ]
113
+ },
114
+ {
115
+ "cell_type": "markdown",
116
+ "id": "e512e19b",
117
+ "metadata": {},
118
+ "source": [
119
+ "## JIT"
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "execution_count": 8,
125
+ "id": "ad66c2eb",
126
+ "metadata": {},
127
+ "outputs": [],
128
+ "source": [
129
+ "class Wrapper(nn.Module):\n",
130
+ " def __init__(self, model):\n",
131
+ " super().__init__()\n",
132
+ " self.model = model\n",
133
+ " \n",
134
+ " def forward(self, *args, **kwargs):\n",
135
+ " return self.model(return_dict=False, *args, **kwargs)"
136
+ ]
137
+ },
138
+ {
139
+ "cell_type": "code",
140
+ "execution_count": 9,
141
+ "id": "efb91bb7",
142
+ "metadata": {},
143
+ "outputs": [],
144
+ "source": [
145
+ "to_jit = Wrapper(model)\n",
146
+ "jit_inputs = list(t_inputs.values())"
147
+ ]
148
+ },
149
+ {
150
+ "cell_type": "code",
151
+ "execution_count": 10,
152
+ "id": "068cb16c",
153
+ "metadata": {},
154
+ "outputs": [],
155
+ "source": [
156
+ "jitted_model = torch.jit.trace(to_jit, jit_inputs)\n",
157
+ "jitted_model.eval();"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": 11,
163
+ "id": "2ae7472a",
164
+ "metadata": {},
165
+ "outputs": [],
166
+ "source": [
167
+ "with torch.no_grad():\n",
168
+ " output_jit = jitted_model(*jit_inputs)"
169
+ ]
170
+ },
171
+ {
172
+ "cell_type": "code",
173
+ "execution_count": 12,
174
+ "id": "f75237f7",
175
+ "metadata": {},
176
+ "outputs": [
177
+ {
178
+ "data": {
179
+ "text/plain": [
180
+ "tensor(0., grad_fn=<MaxBackward1>)"
181
+ ]
182
+ },
183
+ "execution_count": 12,
184
+ "metadata": {},
185
+ "output_type": "execute_result"
186
+ }
187
+ ],
188
+ "source": [
189
+ "(output_jit[0] - outputs[\"last_hidden_state\"]).abs().max()"
190
+ ]
191
+ },
192
+ {
193
+ "cell_type": "code",
194
+ "execution_count": 13,
195
+ "id": "820fd659",
196
+ "metadata": {},
197
+ "outputs": [
198
+ {
199
+ "data": {
200
+ "text/plain": [
201
+ "tensor(0., grad_fn=<MaxBackward1>)"
202
+ ]
203
+ },
204
+ "execution_count": 13,
205
+ "metadata": {},
206
+ "output_type": "execute_result"
207
+ }
208
+ ],
209
+ "source": [
210
+ "(output_jit[1] - outputs[\"pooler_output\"]).abs().max()"
211
+ ]
212
+ },
213
+ {
214
+ "cell_type": "markdown",
215
+ "id": "8be44765",
216
+ "metadata": {},
217
+ "source": [
218
+ "## Core ML Conversion"
219
+ ]
220
+ },
221
+ {
222
+ "cell_type": "code",
223
+ "execution_count": 14,
224
+ "id": "5e221907",
225
+ "metadata": {},
226
+ "outputs": [],
227
+ "source": [
228
+ "input_shape = ct.Shape(shape=(1, ct.RangeDim(lower_bound=1, upper_bound=128, default=1)))"
229
+ ]
230
+ },
231
+ {
232
+ "cell_type": "code",
233
+ "execution_count": 15,
234
+ "id": "bb8e96d5",
235
+ "metadata": {},
236
+ "outputs": [],
237
+ "source": [
238
+ "def _get_coreml_inputs(sample_inputs):\n",
239
+ " return [\n",
240
+ " ct.TensorType(\n",
241
+ " name=k,\n",
242
+ "# shape=v.shape,\n",
243
+ " shape=input_shape,\n",
244
+ " dtype=v.numpy().dtype if isinstance(v, torch.Tensor) else v.dtype,\n",
245
+ " ) for k, v in sample_inputs.items()\n",
246
+ " ]"
247
+ ]
248
+ },
249
+ {
250
+ "cell_type": "code",
251
+ "execution_count": 16,
252
+ "id": "e9e83c6a",
253
+ "metadata": {},
254
+ "outputs": [
255
+ {
256
+ "name": "stderr",
257
+ "output_type": "stream",
258
+ "text": [
259
+ "Tuple detected at graph output. This will be flattened in the converted model.\n",
260
+ "Converting PyTorch Frontend ==> MIL Ops: 0%| | 0/630 [00:00<?, ? ops/s]Core ML embedding (gather) layer does not support any inputs besides the weights and indices. Those given will be ignored.\n",
261
+ "Converting PyTorch Frontend ==> MIL Ops: 100%|▉| 628/630 [00:00<00:00, 3196.37 o\n",
262
+ "Running MIL Common passes: 100%|███████████| 40/40 [00:00<00:00, 49.98 passes/s]\n",
263
+ "Running MIL FP16ComputePrecision pass: 100%|█| 1/1 [00:01<00:00, 1.01s/ passes]\n",
264
+ "Running MIL Clean up passes: 100%|█████████| 11/11 [00:01<00:00, 5.64 passes/s]\n"
265
+ ]
266
+ }
267
+ ],
268
+ "source": [
269
+ "coreml_input_types = _get_coreml_inputs(t_inputs)\n",
270
+ "coreml_output_types = [ct.TensorType(name=name) for name in outputs.keys()]\n",
271
+ "\n",
272
+ "coreml_model = ct.convert(\n",
273
+ " jitted_model,\n",
274
+ " convert_to = \"mlprogram\",\n",
275
+ " minimum_deployment_target = ct.target.macOS13,\n",
276
+ " inputs = coreml_input_types,\n",
277
+ " outputs = coreml_output_types,\n",
278
+ ")"
279
+ ]
280
+ },
281
+ {
282
+ "cell_type": "markdown",
283
+ "id": "f3263470",
284
+ "metadata": {},
285
+ "source": [
286
+ "Conversion succeeds. Let's run inference."
287
+ ]
288
+ },
289
+ {
290
+ "cell_type": "code",
291
+ "execution_count": 17,
292
+ "id": "378948b4",
293
+ "metadata": {},
294
+ "outputs": [],
295
+ "source": [
296
+ "coreml_outputs = coreml_model.predict(t_inputs)"
297
+ ]
298
+ },
299
+ {
300
+ "cell_type": "code",
301
+ "execution_count": 18,
302
+ "id": "bb3e90c9",
303
+ "metadata": {},
304
+ "outputs": [
305
+ {
306
+ "name": "stdout",
307
+ "output_type": "stream",
308
+ "text": [
309
+ "last_hidden_state\n",
310
+ "\tshape: torch.Size([1, 128, 768])\n",
311
+ "\tmax diff: 0.010896801948547363\n",
312
+ "pooler_output\n",
313
+ "\tshape: torch.Size([1, 768])\n",
314
+ "\tmax diff: 0.004700236022472382\n"
315
+ ]
316
+ }
317
+ ],
318
+ "source": [
319
+ "for name in [\"last_hidden_state\", \"pooler_output\"]:\n",
320
+ " coreml_tensor = torch.tensor(coreml_outputs[name])\n",
321
+ " diff = (coreml_tensor - outputs[name]).abs().max()\n",
322
+ " print(f\"{name}\\n\\tshape: {coreml_tensor.shape}\\n\\tmax diff: {diff}\")"
323
+ ]
324
+ },
325
+ {
326
+ "cell_type": "markdown",
327
+ "id": "6506507b",
328
+ "metadata": {},
329
+ "source": [
330
+ "### Metadata Manipulation"
331
+ ]
332
+ },
333
+ {
334
+ "cell_type": "code",
335
+ "execution_count": 19,
336
+ "id": "0c48e4ab",
337
+ "metadata": {},
338
+ "outputs": [],
339
+ "source": [
340
+ "spec = coreml_model._spec"
341
+ ]
342
+ },
343
+ {
344
+ "cell_type": "code",
345
+ "execution_count": 20,
346
+ "id": "7e24db9b",
347
+ "metadata": {},
348
+ "outputs": [],
349
+ "source": [
350
+ "def set_multiarray_shape(node, shape):\n",
351
+ " \"\"\"Change the shape of the specified input or output in the Core ML model.\"\"\"\n",
352
+ " del node.type.multiArrayType.shape[:]\n",
353
+ " for x in shape:\n",
354
+ " node.type.multiArrayType.shape.append(x)"
355
+ ]
356
+ },
357
+ {
358
+ "cell_type": "code",
359
+ "execution_count": 21,
360
+ "id": "9937f578",
361
+ "metadata": {},
362
+ "outputs": [],
363
+ "source": [
364
+ "for ml_input in coreml_model._spec.description.input:\n",
365
+ " set_multiarray_shape(ml_input, (1, 128))"
366
+ ]
367
+ },
368
+ {
369
+ "cell_type": "code",
370
+ "execution_count": 22,
371
+ "id": "d4bbcd8b",
372
+ "metadata": {},
373
+ "outputs": [],
374
+ "source": [
375
+ "from coremltools.models.neural_network import flexible_shape_utils"
376
+ ]
377
+ },
378
+ {
379
+ "cell_type": "code",
380
+ "execution_count": 23,
381
+ "id": "d44bf932",
382
+ "metadata": {},
383
+ "outputs": [],
384
+ "source": [
385
+ "flexible_shape_utils.set_multiarray_ndshape_range(\n",
386
+ " coreml_model._spec,\n",
387
+ " \"input_ids\",\n",
388
+ " [1, 1],\n",
389
+ " [1, 128],\n",
390
+ ")\n",
391
+ "\n",
392
+ "flexible_shape_utils.set_multiarray_ndshape_range(\n",
393
+ " coreml_model._spec,\n",
394
+ " \"attention_mask\",\n",
395
+ " [1, 1],\n",
396
+ " [1, 128],\n",
397
+ ")"
398
+ ]
399
+ },
400
+ {
401
+ "cell_type": "markdown",
402
+ "id": "4cb87162",
403
+ "metadata": {},
404
+ "source": [
405
+ "Output shapes"
406
+ ]
407
+ },
408
+ {
409
+ "cell_type": "code",
410
+ "execution_count": 24,
411
+ "id": "fe0c14ed",
412
+ "metadata": {},
413
+ "outputs": [],
414
+ "source": [
415
+ "shapes = ((1, 128, 768), (1, 768))\n",
416
+ "for output, shape in zip(spec.description.output, shapes):\n",
417
+ " set_multiarray_shape(output, shape)"
418
+ ]
419
+ },
420
+ {
421
+ "cell_type": "code",
422
+ "execution_count": 25,
423
+ "id": "2a9ab275",
424
+ "metadata": {},
425
+ "outputs": [],
426
+ "source": [
427
+ "set_multiarray_shape(coreml_model._spec.description.output[1], (1, 768))"
428
+ ]
429
+ },
430
+ {
431
+ "cell_type": "markdown",
432
+ "id": "63751eec",
433
+ "metadata": {},
434
+ "source": [
435
+ "Flexible shapes for `last_hidden_state`"
436
+ ]
437
+ },
438
+ {
439
+ "cell_type": "code",
440
+ "execution_count": 26,
441
+ "id": "c61921b8",
442
+ "metadata": {},
443
+ "outputs": [],
444
+ "source": [
445
+ "flexible_shape_utils.set_multiarray_ndshape_range(\n",
446
+ " coreml_model._spec,\n",
447
+ " \"last_hidden_state\",\n",
448
+ " [1, 1, 768],\n",
449
+ " [1, 128, 768],\n",
450
+ ")"
451
+ ]
452
+ },
453
+ {
454
+ "cell_type": "code",
455
+ "execution_count": 27,
456
+ "id": "7f666ca0",
457
+ "metadata": {},
458
+ "outputs": [
459
+ {
460
+ "data": {
461
+ "text/plain": [
462
+ "[name: \"last_hidden_state\"\n",
463
+ "type {\n",
464
+ " multiArrayType {\n",
465
+ " shape: 1\n",
466
+ " shape: 128\n",
467
+ " shape: 768\n",
468
+ " dataType: FLOAT32\n",
469
+ " shapeRange {\n",
470
+ " sizeRanges {\n",
471
+ " lowerBound: 1\n",
472
+ " upperBound: 1\n",
473
+ " }\n",
474
+ " sizeRanges {\n",
475
+ " lowerBound: 1\n",
476
+ " upperBound: 128\n",
477
+ " }\n",
478
+ " sizeRanges {\n",
479
+ " lowerBound: 768\n",
480
+ " upperBound: 768\n",
481
+ " }\n",
482
+ " }\n",
483
+ " }\n",
484
+ "}\n",
485
+ ", name: \"pooler_output\"\n",
486
+ "type {\n",
487
+ " multiArrayType {\n",
488
+ " shape: 1\n",
489
+ " shape: 768\n",
490
+ " dataType: FLOAT32\n",
491
+ " }\n",
492
+ "}\n",
493
+ "]"
494
+ ]
495
+ },
496
+ "execution_count": 27,
497
+ "metadata": {},
498
+ "output_type": "execute_result"
499
+ }
500
+ ],
501
+ "source": [
502
+ "coreml_model._spec.description.output"
503
+ ]
504
+ },
505
+ {
506
+ "cell_type": "code",
507
+ "execution_count": 28,
508
+ "id": "f36b4233",
509
+ "metadata": {},
510
+ "outputs": [
511
+ {
512
+ "name": "stderr",
513
+ "output_type": "stream",
514
+ "text": [
515
+ "/opt/homebrew/Caskroom/miniforge/base/envs/sdcoreml/lib/python3.9/site-packages/coremltools/models/model.py:146: RuntimeWarning: You will not be able to run predict() on this Core ML model. Underlying exception message was: Error compiling model: \"compiler error: Encountered an error while compiling a neural network model: validator error: Model output 'pooler_output' has a different shape than its corresponding return value to main.\".\n",
516
+ " _warnings.warn(\n"
517
+ ]
518
+ }
519
+ ],
520
+ "source": [
521
+ "coreml_model = ct.models.MLModel(coreml_model._spec, weights_dir=coreml_model.weights_dir)"
522
+ ]
523
+ },
524
+ {
525
+ "cell_type": "code",
526
+ "execution_count": null,
527
+ "id": "4eef9027",
528
+ "metadata": {},
529
+ "outputs": [],
530
+ "source": []
531
+ }
532
+ ],
533
+ "metadata": {
534
+ "kernelspec": {
535
+ "display_name": "Python 3 (ipykernel)",
536
+ "language": "python",
537
+ "name": "python3"
538
+ },
539
+ "language_info": {
540
+ "codemirror_mode": {
541
+ "name": "ipython",
542
+ "version": 3
543
+ },
544
+ "file_extension": ".py",
545
+ "mimetype": "text/x-python",
546
+ "name": "python",
547
+ "nbconvert_exporter": "python",
548
+ "pygments_lexer": "ipython3",
549
+ "version": "3.9.15"
550
+ },
551
+ "toc": {
552
+ "base_numbering": 1,
553
+ "nav_menu": {},
554
+ "number_sections": true,
555
+ "sideBar": true,
556
+ "skip_h1_title": false,
557
+ "title_cell": "Table of Contents",
558
+ "title_sidebar": "Contents",
559
+ "toc_cell": false,
560
+ "toc_position": {},
561
+ "toc_section_display": true,
562
+ "toc_window_display": false
563
+ }
564
+ },
565
+ "nbformat": 4,
566
+ "nbformat_minor": 5
567
+ }