@huggingface/transformers 3.0.0-alpha.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +33 -22
  2. package/dist/ort-wasm-simd-threaded.jsep.wasm +0 -0
  3. package/dist/transformers.cjs +2515 -2525
  4. package/dist/transformers.cjs.map +1 -1
  5. package/dist/transformers.js +3529 -3455
  6. package/dist/transformers.js.map +1 -1
  7. package/dist/transformers.min.cjs +25 -25
  8. package/dist/transformers.min.cjs.map +1 -1
  9. package/dist/transformers.min.js +39 -40
  10. package/dist/transformers.min.js.map +1 -1
  11. package/dist/transformers.min.mjs +56 -57
  12. package/dist/transformers.min.mjs.map +1 -1
  13. package/dist/transformers.mjs +2551 -2538
  14. package/dist/transformers.mjs.map +1 -1
  15. package/package.json +14 -13
  16. package/src/backends/onnx.js +24 -19
  17. package/src/configs.js +19 -4
  18. package/src/env.js +5 -9
  19. package/src/generation/logits_process.js +40 -37
  20. package/src/models.js +326 -514
  21. package/src/ops/registry.js +14 -3
  22. package/src/pipelines.js +5 -4
  23. package/src/processors.js +390 -351
  24. package/src/tokenizers.js +140 -175
  25. package/src/utils/constants.js +1 -1
  26. package/src/utils/core.js +12 -0
  27. package/src/utils/data-structures.js +13 -11
  28. package/src/utils/hub.js +1 -1
  29. package/src/utils/maths.js +14 -5
  30. package/src/utils/tensor.js +60 -13
  31. package/types/backends/onnx.d.ts +5 -2
  32. package/types/backends/onnx.d.ts.map +1 -1
  33. package/types/configs.d.ts +29 -3
  34. package/types/configs.d.ts.map +1 -1
  35. package/types/env.d.ts +4 -2
  36. package/types/env.d.ts.map +1 -1
  37. package/types/generation/logits_process.d.ts.map +1 -1
  38. package/types/models.d.ts +116 -289
  39. package/types/models.d.ts.map +1 -1
  40. package/types/ops/registry.d.ts +6 -6
  41. package/types/ops/registry.d.ts.map +1 -1
  42. package/types/pipelines.d.ts +1 -2
  43. package/types/pipelines.d.ts.map +1 -1
  44. package/types/processors.d.ts +55 -51
  45. package/types/processors.d.ts.map +1 -1
  46. package/types/tokenizers.d.ts +23 -32
  47. package/types/tokenizers.d.ts.map +1 -1
  48. package/types/utils/constants.d.ts +1 -1
  49. package/types/utils/constants.d.ts.map +1 -1
  50. package/types/utils/core.d.ts +7 -0
  51. package/types/utils/core.d.ts.map +1 -1
  52. package/types/utils/data-structures.d.ts +6 -6
  53. package/types/utils/data-structures.d.ts.map +1 -1
  54. package/types/utils/hub.d.ts +1 -1
  55. package/types/utils/hub.d.ts.map +1 -1
  56. package/types/utils/maths.d.ts +2 -2
  57. package/types/utils/maths.d.ts.map +1 -1
  58. package/types/utils/tensor.d.ts +27 -1
  59. package/types/utils/tensor.d.ts.map +1 -1
package/src/processors.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  } from './utils/maths.js';
41
41
 
42
42
 
43
- import { Tensor, cat, interpolate, stack, interpolate_4d } from './utils/tensor.js';
43
+ import { Tensor, cat, interpolate, stack, interpolate_4d, full } from './utils/tensor.js';
44
44
 
45
45
  import { RawImage } from './utils/image.js';
46
46
  import {
@@ -73,7 +73,7 @@ function center_to_corners_format([centerX, centerY, width, height]) {
73
73
  * @param {Tensor} outputs.logits The logits
74
74
  * @param {Tensor} outputs.pred_boxes The predicted boxes.
75
75
  * @param {number} [threshold=0.5] The threshold to use for the scores.
76
- * @param {number[][]} [target_sizes=null] The sizes of the original images.
76
+ * @param {[number, number][]} [target_sizes=null] The sizes of the original images.
77
77
  * @param {boolean} [is_zero_shot=false] Whether zero-shot object detection was performed.
78
78
  * @return {Object[]} An array of objects containing the post-processed outputs.
79
79
  * @private
@@ -150,6 +150,364 @@ function post_process_object_detection(outputs, threshold = 0.5, target_sizes =
150
150
  return toReturn;
151
151
  }
152
152
 
153
+
154
+ /**
155
+ * Post-processes the outputs of the model (for semantic segmentation).
156
+ * @param {*} outputs Raw outputs of the model.
157
+ * @param {[number, number][]} [target_sizes=null] List of tuples corresponding to the requested final size
158
+ * (height, width) of each prediction. If unset, predictions will not be resized.
159
+ * @returns {{segmentation: Tensor; labels: number[]}[]} The semantic segmentation maps.
160
+ */
161
+ function post_process_semantic_segmentation(outputs, target_sizes = null) {
162
+
163
+ const logits = outputs.logits;
164
+ const batch_size = logits.dims[0];
165
+
166
+ if (target_sizes !== null && target_sizes.length !== batch_size) {
167
+ throw Error("Make sure that you pass in as many target sizes as the batch dimension of the logits")
168
+ }
169
+
170
+ const toReturn = [];
171
+ for (let i = 0; i < batch_size; ++i) {
172
+ const target_size = target_sizes !== null ? target_sizes[i] : null;
173
+
174
+ let data = logits[i];
175
+
176
+ // 1. If target_size is not null, we need to resize the masks to the target size
177
+ if (target_size !== null) {
178
+ // resize the masks to the target size
179
+ data = interpolate(data, target_size, 'bilinear', false);
180
+ }
181
+ const [height, width] = target_size ?? data.dims.slice(-2);
182
+
183
+ const segmentation = new Tensor(
184
+ 'int32',
185
+ new Int32Array(height * width),
186
+ [height, width]
187
+ );
188
+
189
+ // Buffer to store current largest value
190
+ const buffer = data[0].data;
191
+ const segmentation_data = segmentation.data;
192
+ for (let j = 1; j < data.dims[0]; ++j) {
193
+ const row = data[j].data;
194
+ for (let k = 0; k < row.length; ++k) {
195
+ if (row[k] > buffer[k]) {
196
+ buffer[k] = row[k];
197
+ segmentation_data[k] = j;
198
+ }
199
+ }
200
+ }
201
+
202
+ // Store which objects have labels
203
+ // This is much more efficient that creating a set of the final values
204
+ const hasLabel = new Array(data.dims[0]);
205
+ for (let j = 0; j < segmentation_data.length; ++j) {
206
+ const index = segmentation_data[j];
207
+ hasLabel[index] = index;
208
+ }
209
+ /** @type {number[]} The unique list of labels that were detected */
210
+ const labels = hasLabel.filter(x => x !== undefined);
211
+
212
+ toReturn.push({ segmentation, labels });
213
+ }
214
+ return toReturn;
215
+ }
216
+
217
+
218
+ /**
219
+ * Binarize the given masks using `object_mask_threshold`, it returns the associated values of `masks`, `scores` and `labels`.
220
+ * @param {Tensor} class_logits The class logits.
221
+ * @param {Tensor} mask_logits The mask logits.
222
+ * @param {number} object_mask_threshold A number between 0 and 1 used to binarize the masks.
223
+ * @param {number} num_labels The number of labels.
224
+ * @returns {[Tensor[], number[], number[]]} The binarized masks, the scores, and the labels.
225
+ * @private
226
+ */
227
+ function remove_low_and_no_objects(class_logits, mask_logits, object_mask_threshold, num_labels) {
228
+
229
+ const mask_probs_item = [];
230
+ const pred_scores_item = [];
231
+ const pred_labels_item = [];
232
+
233
+ for (let j = 0; j < class_logits.dims[0]; ++j) {
234
+ const cls = class_logits[j];
235
+ const mask = mask_logits[j];
236
+
237
+ const pred_label = max(cls.data)[1];
238
+ if (pred_label === num_labels) {
239
+ // Is the background, so we ignore it
240
+ continue;
241
+ }
242
+
243
+ const scores = softmax(cls.data);
244
+ const pred_score = scores[pred_label];
245
+ if (pred_score > object_mask_threshold) {
246
+ mask_probs_item.push(mask);
247
+ pred_scores_item.push(pred_score);
248
+ pred_labels_item.push(pred_label);
249
+ }
250
+ }
251
+
252
+ return [mask_probs_item, pred_scores_item, pred_labels_item];
253
+ }
254
+
255
+ /**
256
+ * Checks whether the segment is valid or not.
257
+ * @param {Int32Array} mask_labels Labels for each pixel in the mask.
258
+ * @param {Tensor[]} mask_probs Probabilities for each pixel in the masks.
259
+ * @param {number} k The class id of the segment.
260
+ * @param {number} mask_threshold The mask threshold.
261
+ * @param {number} overlap_mask_area_threshold The overlap mask area threshold.
262
+ * @returns {[boolean, number[]]} Whether the segment is valid or not, and the indices of the valid labels.
263
+ * @private
264
+ */
265
+ function check_segment_validity(
266
+ mask_labels,
267
+ mask_probs,
268
+ k,
269
+ mask_threshold = 0.5,
270
+ overlap_mask_area_threshold = 0.8
271
+ ) {
272
+ // mask_k is a 1D array of indices, indicating where the mask is equal to k
273
+ const mask_k = [];
274
+ let mask_k_area = 0;
275
+ let original_area = 0;
276
+
277
+ const mask_probs_k_data = mask_probs[k].data;
278
+
279
+ // Compute the area of all the stuff in query k
280
+ for (let i = 0; i < mask_labels.length; ++i) {
281
+ if (mask_labels[i] === k) {
282
+ mask_k.push(i);
283
+ ++mask_k_area;
284
+ }
285
+
286
+ if (mask_probs_k_data[i] >= mask_threshold) {
287
+ ++original_area;
288
+ }
289
+ }
290
+ let mask_exists = mask_k_area > 0 && original_area > 0;
291
+
292
+ // Eliminate disconnected tiny segments
293
+ if (mask_exists) {
294
+ // Perform additional check
295
+ let area_ratio = mask_k_area / original_area;
296
+ mask_exists = area_ratio > overlap_mask_area_threshold;
297
+ }
298
+
299
+ return [mask_exists, mask_k]
300
+ }
301
+
302
+ /**
303
+ * Computes the segments.
304
+ * @param {Tensor[]} mask_probs The mask probabilities.
305
+ * @param {number[]} pred_scores The predicted scores.
306
+ * @param {number[]} pred_labels The predicted labels.
307
+ * @param {number} mask_threshold The mask threshold.
308
+ * @param {number} overlap_mask_area_threshold The overlap mask area threshold.
309
+ * @param {Set<number>} label_ids_to_fuse The label ids to fuse.
310
+ * @param {number[]} target_size The target size of the image.
311
+ * @returns {[Tensor, Array<{id: number, label_id: number, score: number}>]} The computed segments.
312
+ * @private
313
+ */
314
+ function compute_segments(
315
+ mask_probs,
316
+ pred_scores,
317
+ pred_labels,
318
+ mask_threshold,
319
+ overlap_mask_area_threshold,
320
+ label_ids_to_fuse = null,
321
+ target_size = null,
322
+ ) {
323
+ const [height, width] = target_size ?? mask_probs[0].dims;
324
+
325
+ const segmentation = new Tensor(
326
+ 'int32',
327
+ new Int32Array(height * width),
328
+ [height, width]
329
+ );
330
+ const segments = [];
331
+
332
+ // 1. If target_size is not null, we need to resize the masks to the target size
333
+ if (target_size !== null) {
334
+ // resize the masks to the target size
335
+ for (let i = 0; i < mask_probs.length; ++i) {
336
+ mask_probs[i] = interpolate(mask_probs[i], target_size, 'bilinear', false);
337
+ }
338
+ }
339
+
340
+ // 2. Weigh each mask by its prediction score
341
+ // NOTE: `mask_probs` is updated in-place
342
+ //
343
+ // Temporary storage for the best label/scores for each pixel ([height, width]):
344
+ const mask_labels = new Int32Array(mask_probs[0].data.length);
345
+ const bestScores = new Float32Array(mask_probs[0].data.length);
346
+
347
+ for (let i = 0; i < mask_probs.length; ++i) {
348
+ let score = pred_scores[i];
349
+
350
+ const mask_probs_i_data = mask_probs[i].data;
351
+
352
+ for (let j = 0; j < mask_probs_i_data.length; ++j) {
353
+ mask_probs_i_data[j] *= score
354
+ if (mask_probs_i_data[j] > bestScores[j]) {
355
+ mask_labels[j] = i;
356
+ bestScores[j] = mask_probs_i_data[j];
357
+ }
358
+ }
359
+ }
360
+
361
+ let current_segment_id = 0;
362
+
363
+ // let stuff_memory_list = {}
364
+ const segmentation_data = segmentation.data;
365
+ for (let k = 0; k < pred_labels.length; ++k) {
366
+ const pred_class = pred_labels[k];
367
+
368
+ // TODO add `should_fuse`
369
+ // let should_fuse = pred_class in label_ids_to_fuse
370
+
371
+ // Check if mask exists and large enough to be a segment
372
+ const [mask_exists, mask_k] = check_segment_validity(
373
+ mask_labels,
374
+ mask_probs,
375
+ k,
376
+ mask_threshold,
377
+ overlap_mask_area_threshold
378
+ )
379
+
380
+ if (!mask_exists) {
381
+ // Nothing to see here
382
+ continue;
383
+ }
384
+
385
+ // TODO
386
+ // if (pred_class in stuff_memory_list) {
387
+ // current_segment_id = stuff_memory_list[pred_class]
388
+ // } else {
389
+ // current_segment_id += 1;
390
+ // }
391
+ ++current_segment_id;
392
+
393
+
394
+ // Add current object segment to final segmentation map
395
+ for (const index of mask_k) {
396
+ segmentation_data[index] = current_segment_id;
397
+ }
398
+
399
+ segments.push({
400
+ id: current_segment_id,
401
+ label_id: pred_class,
402
+ // was_fused: should_fuse, TODO
403
+ score: pred_scores[k],
404
+ })
405
+
406
+ // TODO
407
+ // if(should_fuse){
408
+ // stuff_memory_list[pred_class] = current_segment_id
409
+ // }
410
+ }
411
+
412
+ return [segmentation, segments];
413
+ }
414
+
415
+
416
+ /**
417
+ * Post-process the model output to generate the final panoptic segmentation.
418
+ * @param {*} outputs The model output to post process
419
+ * @param {number} [threshold=0.5] The probability score threshold to keep predicted instance masks.
420
+ * @param {number} [mask_threshold=0.5] Threshold to use when turning the predicted masks into binary values.
421
+ * @param {number} [overlap_mask_area_threshold=0.8] The overlap mask area threshold to merge or discard small disconnected parts within each binary instance mask.
422
+ * @param {Set<number>} [label_ids_to_fuse=null] The labels in this state will have all their instances be fused together.
423
+ * @param {[number, number][]} [target_sizes=null] The target sizes to resize the masks to.
424
+ * @returns {Array<{ segmentation: Tensor, segments_info: Array<{id: number, label_id: number, score: number}>}>}
425
+ */
426
+ function post_process_panoptic_segmentation(
427
+ outputs,
428
+ threshold = 0.5,
429
+ mask_threshold = 0.5,
430
+ overlap_mask_area_threshold = 0.8,
431
+ label_ids_to_fuse = null,
432
+ target_sizes = null,
433
+ ) {
434
+ if (label_ids_to_fuse === null) {
435
+ console.warn("`label_ids_to_fuse` unset. No instance will be fused.")
436
+ label_ids_to_fuse = new Set();
437
+ }
438
+
439
+ const class_queries_logits = outputs.class_queries_logits ?? outputs.logits; // [batch_size, num_queries, num_classes+1]
440
+ const masks_queries_logits = outputs.masks_queries_logits ?? outputs.pred_masks; // [batch_size, num_queries, height, width]
441
+
442
+ const mask_probs = masks_queries_logits.sigmoid() // [batch_size, num_queries, height, width]
443
+
444
+ let [batch_size, num_queries, num_labels] = class_queries_logits.dims;
445
+ num_labels -= 1; // Remove last class (background)
446
+
447
+ if (target_sizes !== null && target_sizes.length !== batch_size) {
448
+ throw Error("Make sure that you pass in as many target sizes as the batch dimension of the logits")
449
+ }
450
+
451
+ let toReturn = [];
452
+ for (let i = 0; i < batch_size; ++i) {
453
+ let target_size = target_sizes !== null ? target_sizes[i] : null;
454
+
455
+ let class_logits = class_queries_logits[i];
456
+ let mask_logits = mask_probs[i];
457
+
458
+ let [mask_probs_item, pred_scores_item, pred_labels_item] = remove_low_and_no_objects(class_logits, mask_logits, threshold, num_labels);
459
+
460
+ if (pred_labels_item.length === 0) {
461
+ // No mask found
462
+ let [height, width] = target_size ?? mask_logits.dims.slice(-2);
463
+
464
+ let segmentation = new Tensor(
465
+ 'int32',
466
+ new Int32Array(height * width).fill(-1),
467
+ [height, width]
468
+ )
469
+ toReturn.push({
470
+ segmentation: segmentation,
471
+ segments_info: []
472
+ });
473
+ continue;
474
+ }
475
+
476
+
477
+ // Get segmentation map and segment information of batch item
478
+ let [segmentation, segments] = compute_segments(
479
+ mask_probs_item,
480
+ pred_scores_item,
481
+ pred_labels_item,
482
+ mask_threshold,
483
+ overlap_mask_area_threshold,
484
+ label_ids_to_fuse,
485
+ target_size,
486
+ )
487
+
488
+ toReturn.push({
489
+ segmentation: segmentation,
490
+ segments_info: segments
491
+ })
492
+ }
493
+
494
+ return toReturn;
495
+ }
496
+
497
+
498
+ /**
499
+ * Post-processes the outputs of the model (for instance segmentation).
500
+ * @param {*} outputs Raw outputs of the model.
501
+ * @param {number} [threshold=0.5] The probability score threshold to keep predicted instance masks.
502
+ * @param {[number, number][]} [target_sizes=null] List of tuples corresponding to the requested final size
503
+ * (height, width) of each prediction. If unset, predictions will not be resized.
504
+ * @returns {Array<{ segmentation: Tensor, segments_info: Array<{id: number, label_id: number, score: number}>}>}
505
+ */
506
+ function post_process_instance_segmentation(outputs, threshold = 0.5, target_sizes = null) {
507
+ throw new Error('Not implemented yet');
508
+ return [];
509
+ }
510
+
153
511
  /**
154
512
  * Named tuple to indicate the order we are using is (height x width), even though
155
513
  * the Graphics’ industry standard is (width x height).
@@ -726,72 +1084,19 @@ export class ImageFeatureExtractor extends FeatureExtractor {
726
1084
 
727
1085
  }
728
1086
 
1087
+ export class SapiensFeatureExtractor extends ImageFeatureExtractor {
1088
+ /** @type {typeof post_process_semantic_segmentation} */
1089
+ post_process_semantic_segmentation(...args) {
1090
+ return post_process_semantic_segmentation(...args);
1091
+ }
1092
+ }
729
1093
  export class SegformerFeatureExtractor extends ImageFeatureExtractor {
730
-
731
- /**
732
- * Converts the output of `SegformerForSemanticSegmentation` into semantic segmentation maps.
733
- * @param {*} outputs Raw outputs of the model.
734
- * @param {number[][]} [target_sizes=null] List of tuples corresponding to the requested final size
735
- * (height, width) of each prediction. If unset, predictions will not be resized.
736
- * @returns {{segmentation: Tensor; labels: number[]}[]} The semantic segmentation maps.
737
- */
738
- post_process_semantic_segmentation(outputs, target_sizes = null) {
739
-
740
- const logits = outputs.logits;
741
- const batch_size = logits.dims[0];
742
-
743
- if (target_sizes !== null && target_sizes.length !== batch_size) {
744
- throw Error("Make sure that you pass in as many target sizes as the batch dimension of the logits")
745
- }
746
-
747
- const toReturn = [];
748
- for (let i = 0; i < batch_size; ++i) {
749
- const target_size = target_sizes !== null ? target_sizes[i] : null;
750
-
751
- let data = logits[i];
752
-
753
- // 1. If target_size is not null, we need to resize the masks to the target size
754
- if (target_size !== null) {
755
- // resize the masks to the target size
756
- data = interpolate(data, target_size, 'bilinear', false);
757
- }
758
- const [height, width] = target_size ?? data.dims.slice(-2);
759
-
760
- const segmentation = new Tensor(
761
- 'int32',
762
- new Int32Array(height * width),
763
- [height, width]
764
- );
765
-
766
- // Buffer to store current largest value
767
- const buffer = data[0].data;
768
- const segmentation_data = segmentation.data;
769
- for (let j = 1; j < data.dims[0]; ++j) {
770
- const row = data[j].data;
771
- for (let k = 0; k < row.length; ++k) {
772
- if (row[k] > buffer[k]) {
773
- buffer[k] = row[k];
774
- segmentation_data[k] = j;
775
- }
776
- }
777
- }
778
-
779
- // Store which objects have labels
780
- // This is much more efficient that creating a set of the final values
781
- const hasLabel = new Array(data.dims[0]);
782
- const out = segmentation.data;
783
- for (let j = 0; j < out.length; ++j) {
784
- const index = out[j];
785
- hasLabel[index] = index;
786
- }
787
- /** @type {number[]} The unique list of labels that were detected */
788
- const labels = hasLabel.filter(x => x !== undefined);
789
-
790
- toReturn.push({ segmentation, labels });
791
- }
792
- return toReturn;
1094
+ /** @type {typeof post_process_semantic_segmentation} */
1095
+ post_process_semantic_segmentation(...args) {
1096
+ return post_process_semantic_segmentation(...args);
793
1097
  }
794
1098
  }
1099
+ export class PvtImageProcessor extends ImageFeatureExtractor { }
795
1100
  export class DPTFeatureExtractor extends ImageFeatureExtractor { }
796
1101
  export class DPTImageProcessor extends DPTFeatureExtractor { } // NOTE: extends DPTFeatureExtractor
797
1102
  export class BitImageProcessor extends ImageFeatureExtractor { }
@@ -862,7 +1167,7 @@ export class MobileNetV4FeatureExtractor extends ImageFeatureExtractor { }
862
1167
  export class MobileViTFeatureExtractor extends ImageFeatureExtractor { }
863
1168
  export class MobileViTImageProcessor extends MobileViTFeatureExtractor { } // NOTE extends MobileViTFeatureExtractor
864
1169
  export class OwlViTFeatureExtractor extends ImageFeatureExtractor {
865
- /** @type {post_process_object_detection} */
1170
+ /** @type {typeof post_process_object_detection} */
866
1171
  post_process_object_detection(...args) {
867
1172
  return post_process_object_detection(...args);
868
1173
  }
@@ -870,7 +1175,7 @@ export class OwlViTFeatureExtractor extends ImageFeatureExtractor {
870
1175
  export class Owlv2ImageProcessor extends OwlViTFeatureExtractor { } // NOTE extends OwlViTFeatureExtractor
871
1176
 
872
1177
  export class RTDetrImageProcessor extends ImageFeatureExtractor {
873
- /** @type {post_process_object_detection} */
1178
+ /** @type {typeof post_process_object_detection} */
874
1179
  post_process_object_detection(...args) {
875
1180
  return post_process_object_detection(...args);
876
1181
  }
@@ -931,302 +1236,32 @@ export class DetrFeatureExtractor extends ImageFeatureExtractor {
931
1236
  // TODO support different mask sizes (not just 64x64)
932
1237
  // Currently, just fill pixel mask with 1s
933
1238
  const maskSize = [result.pixel_values.dims[0], 64, 64];
934
- const pixel_mask = new Tensor(
935
- 'int64',
936
- new BigInt64Array(maskSize.reduce((a, b) => a * b)).fill(1n),
937
- maskSize
938
- );
1239
+ const pixel_mask = full(maskSize, 1n);
939
1240
 
940
1241
  return { ...result, pixel_mask };
941
1242
  }
942
1243
 
943
- /**
944
- * Post-processes the outputs of the model (for object detection).
945
- * @param {Object} outputs The outputs of the model that must be post-processed
946
- * @param {Tensor} outputs.logits The logits
947
- * @param {Tensor} outputs.pred_boxes The predicted boxes.
948
- * @return {Object[]} An array of objects containing the post-processed outputs.
949
- */
950
-
951
- /** @type {post_process_object_detection} */
1244
+ /** @type {typeof post_process_object_detection} */
952
1245
  post_process_object_detection(...args) {
953
1246
  return post_process_object_detection(...args);
954
1247
  }
955
1248
 
956
- /**
957
- * Binarize the given masks using `object_mask_threshold`, it returns the associated values of `masks`, `scores` and `labels`.
958
- * @param {Tensor} class_logits The class logits.
959
- * @param {Tensor} mask_logits The mask logits.
960
- * @param {number} object_mask_threshold A number between 0 and 1 used to binarize the masks.
961
- * @param {number} num_labels The number of labels.
962
- * @returns {[Tensor[], number[], number[]]} The binarized masks, the scores, and the labels.
963
- */
964
- remove_low_and_no_objects(class_logits, mask_logits, object_mask_threshold, num_labels) {
965
-
966
- let mask_probs_item = [];
967
- let pred_scores_item = [];
968
- let pred_labels_item = [];
969
-
970
- for (let j = 0; j < class_logits.dims[0]; ++j) {
971
- let cls = class_logits[j];
972
- let mask = mask_logits[j];
973
-
974
- let pred_label = max(cls.data)[1];
975
- if (pred_label === num_labels) {
976
- // Is the background, so we ignore it
977
- continue;
978
- }
979
-
980
- let scores = softmax(cls.data);
981
- let pred_score = scores[pred_label];
982
- if (pred_score > object_mask_threshold) {
983
- mask_probs_item.push(mask);
984
- pred_scores_item.push(pred_score);
985
- pred_labels_item.push(pred_label);
986
- }
987
- }
988
-
989
- return [mask_probs_item, pred_scores_item, pred_labels_item];
990
-
991
- }
992
-
993
- /**
994
- * Checks whether the segment is valid or not.
995
- * @param {Int32Array} mask_labels Labels for each pixel in the mask.
996
- * @param {Tensor[]} mask_probs Probabilities for each pixel in the masks.
997
- * @param {number} k The class id of the segment.
998
- * @param {number} mask_threshold The mask threshold.
999
- * @param {number} overlap_mask_area_threshold The overlap mask area threshold.
1000
- * @returns {[boolean, number[]]} Whether the segment is valid or not, and the indices of the valid labels.
1001
- */
1002
- check_segment_validity(
1003
- mask_labels,
1004
- mask_probs,
1005
- k,
1006
- mask_threshold = 0.5,
1007
- overlap_mask_area_threshold = 0.8
1008
- ) {
1009
- // mask_k is a 1D array of indices, indicating where the mask is equal to k
1010
- let mask_k = [];
1011
- let mask_k_area = 0;
1012
- let original_area = 0;
1013
-
1014
- const mask_probs_k_data = mask_probs[k].data;
1015
-
1016
- // Compute the area of all the stuff in query k
1017
- for (let i = 0; i < mask_labels.length; ++i) {
1018
- if (mask_labels[i] === k) {
1019
- mask_k.push(i);
1020
- ++mask_k_area;
1021
- }
1022
-
1023
- if (mask_probs_k_data[i] >= mask_threshold) {
1024
- ++original_area;
1025
- }
1026
- }
1027
- let mask_exists = mask_k_area > 0 && original_area > 0;
1028
-
1029
- // Eliminate disconnected tiny segments
1030
- if (mask_exists) {
1031
- // Perform additional check
1032
- let area_ratio = mask_k_area / original_area;
1033
- mask_exists = area_ratio > overlap_mask_area_threshold;
1034
- }
1035
-
1036
- return [mask_exists, mask_k]
1249
+ /** @type {typeof post_process_panoptic_segmentation} */
1250
+ post_process_panoptic_segmentation(...args) {
1251
+ return post_process_panoptic_segmentation(...args);
1037
1252
  }
1038
1253
 
1039
- /**
1040
- * Computes the segments.
1041
- * @param {Tensor[]} mask_probs The mask probabilities.
1042
- * @param {number[]} pred_scores The predicted scores.
1043
- * @param {number[]} pred_labels The predicted labels.
1044
- * @param {number} mask_threshold The mask threshold.
1045
- * @param {number} overlap_mask_area_threshold The overlap mask area threshold.
1046
- * @param {Set<number>} label_ids_to_fuse The label ids to fuse.
1047
- * @param {number[]} target_size The target size of the image.
1048
- * @returns {[Tensor, Array<{id: number, label_id: number, score: number}>]} The computed segments.
1049
- */
1050
- compute_segments(
1051
- mask_probs,
1052
- pred_scores,
1053
- pred_labels,
1054
- mask_threshold,
1055
- overlap_mask_area_threshold,
1056
- label_ids_to_fuse = null,
1057
- target_size = null,
1058
- ) {
1059
- let [height, width] = target_size ?? mask_probs[0].dims;
1060
-
1061
- let segmentation = new Tensor(
1062
- 'int32',
1063
- new Int32Array(height * width),
1064
- [height, width]
1065
- );
1066
- let segments = [];
1067
-
1068
- // 1. If target_size is not null, we need to resize the masks to the target size
1069
- if (target_size !== null) {
1070
- // resize the masks to the target size
1071
- for (let i = 0; i < mask_probs.length; ++i) {
1072
- mask_probs[i] = interpolate(mask_probs[i], target_size, 'bilinear', false);
1073
- }
1074
- }
1075
-
1076
- // 2. Weigh each mask by its prediction score
1077
- // NOTE: `mask_probs` is updated in-place
1078
- //
1079
- // Temporary storage for the best label/scores for each pixel ([height, width]):
1080
- let mask_labels = new Int32Array(mask_probs[0].data.length);
1081
- let bestScores = new Float32Array(mask_probs[0].data.length);
1082
-
1083
- for (let i = 0; i < mask_probs.length; ++i) {
1084
- let score = pred_scores[i];
1085
-
1086
- const mask_probs_i_data = mask_probs[i].data;
1087
-
1088
- for (let j = 0; j < mask_probs_i_data.length; ++j) {
1089
- mask_probs_i_data[j] *= score
1090
- if (mask_probs_i_data[j] > bestScores[j]) {
1091
- mask_labels[j] = i;
1092
- bestScores[j] = mask_probs_i_data[j];
1093
- }
1094
- }
1095
- }
1096
-
1097
- let current_segment_id = 0;
1098
-
1099
- // let stuff_memory_list = {}
1100
- const segmentation_data = segmentation.data;
1101
- for (let k = 0; k < pred_labels.length; ++k) {
1102
- let pred_class = pred_labels[k];
1103
-
1104
- // TODO add `should_fuse`
1105
- // let should_fuse = pred_class in label_ids_to_fuse
1106
-
1107
- // Check if mask exists and large enough to be a segment
1108
- let [mask_exists, mask_k] = this.check_segment_validity(
1109
- mask_labels,
1110
- mask_probs,
1111
- k,
1112
- mask_threshold,
1113
- overlap_mask_area_threshold
1114
- )
1115
-
1116
- if (!mask_exists) {
1117
- // Nothing to see here
1118
- continue;
1119
- }
1120
-
1121
- // TODO
1122
- // if (pred_class in stuff_memory_list) {
1123
- // current_segment_id = stuff_memory_list[pred_class]
1124
- // } else {
1125
- // current_segment_id += 1;
1126
- // }
1127
- ++current_segment_id;
1128
-
1129
-
1130
- // Add current object segment to final segmentation map
1131
- for (let index of mask_k) {
1132
- segmentation_data[index] = current_segment_id;
1133
- }
1134
-
1135
- segments.push({
1136
- id: current_segment_id,
1137
- label_id: pred_class,
1138
- // was_fused: should_fuse, TODO
1139
- score: pred_scores[k],
1140
- })
1141
-
1142
- // TODO
1143
- // if(should_fuse){
1144
- // stuff_memory_list[pred_class] = current_segment_id
1145
- // }
1146
- }
1147
-
1148
- return [segmentation, segments];
1254
+ post_process_instance_segmentation() {
1255
+ // TODO
1256
+ throw Error("Not implemented yet");
1149
1257
  }
1258
+ }
1150
1259
 
1151
- /**
1152
- * Post-process the model output to generate the final panoptic segmentation.
1153
- * @param {*} outputs The model output to post process
1154
- * @param {number} [threshold=0.5] The probability score threshold to keep predicted instance masks.
1155
- * @param {number} [mask_threshold=0.5] Threshold to use when turning the predicted masks into binary values.
1156
- * @param {number} [overlap_mask_area_threshold=0.8] The overlap mask area threshold to merge or discard small disconnected parts within each binary instance mask.
1157
- * @param {Set<number>} [label_ids_to_fuse=null] The labels in this state will have all their instances be fused together.
1158
- * @param {number[][]} [target_sizes=null] The target sizes to resize the masks to.
1159
- * @returns {Array<{ segmentation: Tensor, segments_info: Array<{id: number, label_id: number, score: number}>}>}
1160
- */
1161
- post_process_panoptic_segmentation(
1162
- outputs,
1163
- threshold = 0.5,
1164
- mask_threshold = 0.5,
1165
- overlap_mask_area_threshold = 0.8,
1166
- label_ids_to_fuse = null,
1167
- target_sizes = null,
1168
- ) {
1169
- if (label_ids_to_fuse === null) {
1170
- console.warn("`label_ids_to_fuse` unset. No instance will be fused.")
1171
- label_ids_to_fuse = new Set();
1172
- }
1173
-
1174
- const class_queries_logits = outputs.logits; // [batch_size, num_queries, num_classes+1]
1175
- const masks_queries_logits = outputs.pred_masks; // [batch_size, num_queries, height, width]
1176
-
1177
- const mask_probs = masks_queries_logits.sigmoid() // [batch_size, num_queries, height, width]
1178
-
1179
- let [batch_size, num_queries, num_labels] = class_queries_logits.dims;
1180
- num_labels -= 1; // Remove last class (background)
1181
-
1182
- if (target_sizes !== null && target_sizes.length !== batch_size) {
1183
- throw Error("Make sure that you pass in as many target sizes as the batch dimension of the logits")
1184
- }
1185
-
1186
- let toReturn = [];
1187
- for (let i = 0; i < batch_size; ++i) {
1188
- let target_size = target_sizes !== null ? target_sizes[i] : null;
1189
-
1190
- let class_logits = class_queries_logits[i];
1191
- let mask_logits = mask_probs[i];
1192
-
1193
- let [mask_probs_item, pred_scores_item, pred_labels_item] = this.remove_low_and_no_objects(class_logits, mask_logits, threshold, num_labels);
1194
-
1195
- if (pred_labels_item.length === 0) {
1196
- // No mask found
1197
- let [height, width] = target_size ?? mask_logits.dims.slice(-2);
1198
-
1199
- let segmentation = new Tensor(
1200
- 'int32',
1201
- new Int32Array(height * width).fill(-1),
1202
- [height, width]
1203
- )
1204
- toReturn.push({
1205
- segmentation: segmentation,
1206
- segments_info: []
1207
- });
1208
- continue;
1209
- }
1210
-
1211
-
1212
- // Get segmentation map and segment information of batch item
1213
- let [segmentation, segments] = this.compute_segments(
1214
- mask_probs_item,
1215
- pred_scores_item,
1216
- pred_labels_item,
1217
- mask_threshold,
1218
- overlap_mask_area_threshold,
1219
- label_ids_to_fuse,
1220
- target_size,
1221
- )
1260
+ export class MaskFormerFeatureExtractor extends ImageFeatureExtractor {
1222
1261
 
1223
- toReturn.push({
1224
- segmentation: segmentation,
1225
- segments_info: segments
1226
- })
1227
- }
1228
-
1229
- return toReturn;
1262
+ /** @type {typeof post_process_panoptic_segmentation} */
1263
+ post_process_panoptic_segmentation(...args) {
1264
+ return post_process_panoptic_segmentation(...args);
1230
1265
  }
1231
1266
 
1232
1267
  post_process_instance_segmentation() {
@@ -1235,8 +1270,9 @@ export class DetrFeatureExtractor extends ImageFeatureExtractor {
1235
1270
  }
1236
1271
  }
1237
1272
 
1273
+
1238
1274
  export class YolosFeatureExtractor extends ImageFeatureExtractor {
1239
- /** @type {post_process_object_detection} */
1275
+ /** @type {typeof post_process_object_detection} */
1240
1276
  post_process_object_detection(...args) {
1241
1277
  return post_process_object_detection(...args);
1242
1278
  }
@@ -2520,14 +2556,17 @@ export class AutoProcessor {
2520
2556
  ConvNextFeatureExtractor,
2521
2557
  ConvNextImageProcessor,
2522
2558
  SegformerFeatureExtractor,
2559
+ SapiensFeatureExtractor,
2523
2560
  BitImageProcessor,
2524
2561
  DPTImageProcessor,
2525
2562
  DPTFeatureExtractor,
2563
+ PvtImageProcessor,
2526
2564
  GLPNFeatureExtractor,
2527
2565
  BeitFeatureExtractor,
2528
2566
  DeiTFeatureExtractor,
2529
2567
  DetrFeatureExtractor,
2530
2568
  RTDetrImageProcessor,
2569
+ MaskFormerFeatureExtractor,
2531
2570
  YolosFeatureExtractor,
2532
2571
  DonutFeatureExtractor,
2533
2572
  NougatImageProcessor,