@huggingface/transformers 3.0.0-alpha.9 → 3.0.1
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.
- package/README.md +82 -50
- package/dist/ort-wasm-simd-threaded.jsep.wasm +0 -0
- package/dist/transformers.cjs +2550 -2552
- package/dist/transformers.cjs.map +1 -1
- package/dist/transformers.js +3639 -3567
- package/dist/transformers.js.map +1 -1
- package/dist/transformers.min.cjs +25 -25
- package/dist/transformers.min.cjs.map +1 -1
- package/dist/transformers.min.js +41 -42
- package/dist/transformers.min.js.map +1 -1
- package/dist/transformers.min.mjs +56 -57
- package/dist/transformers.min.mjs.map +1 -1
- package/dist/transformers.mjs +2586 -2564
- package/dist/transformers.mjs.map +1 -1
- package/package.json +14 -13
- package/src/backends/onnx.js +24 -19
- package/src/configs.js +19 -4
- package/src/env.js +5 -9
- package/src/generation/logits_process.js +40 -37
- package/src/models.js +356 -539
- package/src/ops/registry.js +14 -3
- package/src/pipelines.js +5 -5
- package/src/processors.js +392 -351
- package/src/tokenizers.js +140 -175
- package/src/utils/constants.js +1 -1
- package/src/utils/core.js +12 -0
- package/src/utils/data-structures.js +13 -11
- package/src/utils/hub.js +1 -1
- package/src/utils/maths.js +14 -5
- package/src/utils/tensor.js +60 -13
- package/types/backends/onnx.d.ts +5 -2
- package/types/backends/onnx.d.ts.map +1 -1
- package/types/configs.d.ts +29 -3
- package/types/configs.d.ts.map +1 -1
- package/types/env.d.ts +4 -2
- package/types/env.d.ts.map +1 -1
- package/types/generation/logits_process.d.ts.map +1 -1
- package/types/models.d.ts +116 -289
- package/types/models.d.ts.map +1 -1
- package/types/ops/registry.d.ts +6 -6
- package/types/ops/registry.d.ts.map +1 -1
- package/types/pipelines.d.ts +1 -2
- package/types/pipelines.d.ts.map +1 -1
- package/types/processors.d.ts +58 -51
- package/types/processors.d.ts.map +1 -1
- package/types/tokenizers.d.ts +23 -32
- package/types/tokenizers.d.ts.map +1 -1
- package/types/utils/constants.d.ts +1 -1
- package/types/utils/constants.d.ts.map +1 -1
- package/types/utils/core.d.ts +7 -0
- package/types/utils/core.d.ts.map +1 -1
- package/types/utils/data-structures.d.ts +6 -6
- package/types/utils/data-structures.d.ts.map +1 -1
- package/types/utils/hub.d.ts +1 -1
- package/types/utils/hub.d.ts.map +1 -1
- package/types/utils/maths.d.ts +2 -2
- package/types/utils/maths.d.ts.map +1 -1
- package/types/utils/tensor.d.ts +27 -1
- 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
|
|
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
|
-
|
|
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
|
}
|
|
@@ -904,6 +1209,7 @@ export class DonutFeatureExtractor extends ImageFeatureExtractor {
|
|
|
904
1209
|
});
|
|
905
1210
|
}
|
|
906
1211
|
}
|
|
1212
|
+
export class DonutImageProcessor extends DonutFeatureExtractor { } // NOTE extends DonutFeatureExtractor
|
|
907
1213
|
export class NougatImageProcessor extends DonutFeatureExtractor { } // NOTE extends DonutFeatureExtractor
|
|
908
1214
|
|
|
909
1215
|
/**
|
|
@@ -931,302 +1237,32 @@ export class DetrFeatureExtractor extends ImageFeatureExtractor {
|
|
|
931
1237
|
// TODO support different mask sizes (not just 64x64)
|
|
932
1238
|
// Currently, just fill pixel mask with 1s
|
|
933
1239
|
const maskSize = [result.pixel_values.dims[0], 64, 64];
|
|
934
|
-
const pixel_mask =
|
|
935
|
-
'int64',
|
|
936
|
-
new BigInt64Array(maskSize.reduce((a, b) => a * b)).fill(1n),
|
|
937
|
-
maskSize
|
|
938
|
-
);
|
|
1240
|
+
const pixel_mask = full(maskSize, 1n);
|
|
939
1241
|
|
|
940
1242
|
return { ...result, pixel_mask };
|
|
941
1243
|
}
|
|
942
1244
|
|
|
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} */
|
|
1245
|
+
/** @type {typeof post_process_object_detection} */
|
|
952
1246
|
post_process_object_detection(...args) {
|
|
953
1247
|
return post_process_object_detection(...args);
|
|
954
1248
|
}
|
|
955
1249
|
|
|
956
|
-
/**
|
|
957
|
-
|
|
958
|
-
|
|
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]
|
|
1250
|
+
/** @type {typeof post_process_panoptic_segmentation} */
|
|
1251
|
+
post_process_panoptic_segmentation(...args) {
|
|
1252
|
+
return post_process_panoptic_segmentation(...args);
|
|
1037
1253
|
}
|
|
1038
1254
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
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];
|
|
1255
|
+
post_process_instance_segmentation() {
|
|
1256
|
+
// TODO
|
|
1257
|
+
throw Error("Not implemented yet");
|
|
1149
1258
|
}
|
|
1259
|
+
}
|
|
1150
1260
|
|
|
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
|
-
)
|
|
1261
|
+
export class MaskFormerFeatureExtractor extends ImageFeatureExtractor {
|
|
1222
1262
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
})
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
return toReturn;
|
|
1263
|
+
/** @type {typeof post_process_panoptic_segmentation} */
|
|
1264
|
+
post_process_panoptic_segmentation(...args) {
|
|
1265
|
+
return post_process_panoptic_segmentation(...args);
|
|
1230
1266
|
}
|
|
1231
1267
|
|
|
1232
1268
|
post_process_instance_segmentation() {
|
|
@@ -1235,8 +1271,9 @@ export class DetrFeatureExtractor extends ImageFeatureExtractor {
|
|
|
1235
1271
|
}
|
|
1236
1272
|
}
|
|
1237
1273
|
|
|
1274
|
+
|
|
1238
1275
|
export class YolosFeatureExtractor extends ImageFeatureExtractor {
|
|
1239
|
-
/** @type {post_process_object_detection} */
|
|
1276
|
+
/** @type {typeof post_process_object_detection} */
|
|
1240
1277
|
post_process_object_detection(...args) {
|
|
1241
1278
|
return post_process_object_detection(...args);
|
|
1242
1279
|
}
|
|
@@ -2520,16 +2557,20 @@ export class AutoProcessor {
|
|
|
2520
2557
|
ConvNextFeatureExtractor,
|
|
2521
2558
|
ConvNextImageProcessor,
|
|
2522
2559
|
SegformerFeatureExtractor,
|
|
2560
|
+
SapiensFeatureExtractor,
|
|
2523
2561
|
BitImageProcessor,
|
|
2524
2562
|
DPTImageProcessor,
|
|
2525
2563
|
DPTFeatureExtractor,
|
|
2564
|
+
PvtImageProcessor,
|
|
2526
2565
|
GLPNFeatureExtractor,
|
|
2527
2566
|
BeitFeatureExtractor,
|
|
2528
2567
|
DeiTFeatureExtractor,
|
|
2529
2568
|
DetrFeatureExtractor,
|
|
2530
2569
|
RTDetrImageProcessor,
|
|
2570
|
+
MaskFormerFeatureExtractor,
|
|
2531
2571
|
YolosFeatureExtractor,
|
|
2532
2572
|
DonutFeatureExtractor,
|
|
2573
|
+
DonutImageProcessor,
|
|
2533
2574
|
NougatImageProcessor,
|
|
2534
2575
|
EfficientNetImageProcessor,
|
|
2535
2576
|
|