FiftyOne SampleParser 完全指南:从内存数据流构建数据集的 add 与 ingest 双路径 FiftyOne SampleParser 完全指南从内存数据流构建数据集的 add 与 ingest 双路径【免费下载链接】fiftyoneRefine high-quality datasets and visual AI models项目地址: https://gitcode.com/GitHub_Trending/fi/fiftyone导读SampleParser是 FiftyOne 提供的一组可扩展的样本解析接口用于将内存中的数据流例如torch.utils.data.Dataset迭代器、tf.data.Dataset.as_numpy_iterator()的产出、内存中的 numpy 图像等批量解析并写入fo.Dataset。本文围绕官方文档 docs/source/user_guide/sample_parsers.rst 展开系统讲解add_*引用媒体与ingest_*摄取媒体两类数据集方法的完整用法、全部内置解析器、以及如何编写自定义解析器。读完本文你将能够在训练循环、数据增强流水线或自定义数据格式场景中用十余行代码将任意数据流自动化导入 FiftyOne 数据集并能基于源码原理自定义属于自己的SampleParser。使用前提SampleParser接口仅推荐用于特定场景。在绝大多数情况下官方建议优先采用手动添加样本或数据集导入器来加载数据。SampleParser 是什么接口定位与适用场景SampleParser是 FiftyOne 中负责把一条外部格式的样本翻译成 FiftyOne 能理解的字段的抽象接口。其基类定义在 fiftyone/utils/data/parsers.py核心契约非常精简with_sample(sample)载入下一条样本内部会先调用clear_sample()清空上一状态再将其存入current_samplecurrent_sample只读属性返回当前待解析的样本未调用with_sample()时访问会抛出ValueError(No current sample...)clear_sample()清除当前样本及解析器缓存的状态。子类则在此基础上按媒体类型图像/视频和是否有标签未标注/已标注暴露get_XXX()系列方法与has_XXX系列属性。整个解析循环是载入一条 → 提取字段 → 构造fo.Sample→ 写入数据集的逐条流式过程因此特别适合内存中生成、无需落盘中间文件的样本流。典型的数据源文档原文明确给出是torch.utils.data.Dataset的迭代器tf.data.Dataset.as_numpy_iterator()产生的迭代器任何内存中的 numpy 图像数组。将样本添加到数据集add 路径add_*系列方法不会读取媒体内容仅记录媒体路径fo.Sample存储的是filepath而非媒体本身因此适合源媒体已存在于磁盘的场景。基本配方无论图像还是视频、是否带标签使用模式都是统一的创建合适类型的解析器 → 连同样本可迭代对象一起传给对应的 Dataset 方法。未标注图像import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个样本可迭代对象以及用于解析它们的 UnlabeledImageSampleParser samples ... sample_parser foud.ImageSampleParser # 例如 # 将图像样本添加到数据集 dataset.add_images(samples, sample_parser)已标注图像import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个样本可迭代对象以及用于解析它们的 LabeledImageSampleParser samples ... sample_parser foud.ImageClassificationSampleParser # 例如 # 将带标注的图像样本添加到数据集 dataset.add_labeled_images(samples, sample_parser)未标注视频import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个样本可迭代对象以及用于解析它们的 UnlabeledVideoSampleParser samples ... sample_parser foud.VideoSampleParser # 例如 # 将视频样本添加到数据集 dataset.add_images(samples, sample_parser)注意上例沿用了官方文档中的写法实际上添加视频应使用dataset.add_videos(samples, sample_parser)见下文添加未标注视频小节。已标注视频import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个样本可迭代对象以及用于解析它们的 LabeledVideoSampleParser samples ... sample_parser foud.FiftyOneVideoLabelsSampleParser # 例如 # 将带标注的视频样本添加到数据集 dataset.add_labeled_videos(samples, sample_parser)从源码看fiftyone/core/dataset.pyadd_images(paths_or_samples, sample_parserNone, tagsNone, generatorFalse, progressNone)在未显式传入解析器时会默认构造foud.ImageSampleParser()此时要求传入的必须是图像路径的可迭代对象add_labeled_imagesfiftyone/core/dataset.py则额外支持label_field、expand_schema、dynamic等参数控制标签字段名与 schema 扩展行为。添加未标注图像的三种便捷方式FiftyOne 为目录/glob/任意迭代器三种来源提供了对应方法方式一目录——Dataset.add_images_dir(images_dir, tagsNone, recursiveTrue, ...)fiftyone/core/dataset.py内部调用foud.parse_images_dir()收集目录下所有图像路径非图像 MIME 类型的文件会被自动跳过再走add_imagesimport fiftyone as fo dataset fo.Dataset() # 一个图像目录 images_dir /path/to/images # 将目录中的图像添加到数据集 dataset.add_images_dir(images_dir)方式二glob 模式——Dataset.add_images_patt(images_patt, tagsNone, ...)fiftyone/core/dataset.py内部通过etau.get_glob_matches()展开匹配路径import fiftyone as fo dataset fo.Dataset() # 一个 glob 图像模式 images_patt /path/to/images/*.jpg # 将匹配的图像添加到数据集 dataset.add_images_patt(images_patt)方式三SampleParser——Dataset.add_images(samples, sample_parser)。官方内置的ImageSampleParserfiftyone/utils/data/parsers.py接受可直接np.asarray()转 numpy 的图像对象或磁盘上的图像路径两类样本对路径走foui.read()读取对数组走np.asarray()has_image_path为True说明可提取路径、has_image_metadata为False。import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个图像或图像路径的可迭代对象以及用于解析它们的 UnlabeledImageSampleParser samples ... sample_parser foud.ImageSampleParser # 将图像添加到数据集 dataset.add_images(samples, sample_parser)添加已标注图像Dataset.add_labeled_images(samples, sample_parser, label_fieldNone, ...)用于解析带标签的样本。官方内置ImageClassificationSampleParserfiftyone/utils/data/parsers.py处理(image_or_path, target)元组其中image_or_path可通过np.asarray()转 numpy 的图像或磁盘上的图像路径target类别 ID 或标签字符串也可为None表示未标注样本或直接传入Classification/Classifications实例。import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个 (image_or_path, target) 元组的可迭代对象以及用于解析它们的 LabeledImageSampleParser samples ... sample_parser foud.ImageClassificationSampleParser # 将已标注图像添加到数据集 dataset.add_labeled_images(samples, sample_parser)添加未标注视频目录Dataset.add_videos_dir(videos_dir, ...)glob 模式Dataset.add_videos_patt(videos_patt, ...)SampleParserDataset.add_videos(samples, sample_parser)。import fiftyone as fo dataset fo.Dataset() # 一个视频目录 videos_dir /path/to/videos # 将目录中的视频添加到数据集 dataset.add_videos_dir(videos_dir)import fiftyone as fo dataset fo.Dataset() # 一个 glob 视频模式 videos_patt /path/to/videos/*.mp4 # 将匹配的视频添加到数据集 dataset.add_videos_patt(videos_patt)内置的VideoSampleParserfiftyone/utils/data/parsers.py要求样本就是视频在磁盘上的路径get_video_path()直接返回self.current_sampleimport fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个视频路径的可迭代对象以及用于解析它们的 UnlabeledVideoSampleParser samples ... sample_parser foud.VideoSampleParser # 将视频添加到数据集 dataset.add_videos(samples, sample_parser)添加已标注视频Dataset.add_labeled_videos(samples, sample_parser, label_fieldNone, ...)。内置的VideoLabelsSampleParserfiftyone/utils/data/parsers.py处理(video_path, video_labels_or_path)元组其中video_path磁盘上的视频路径video_labels_or_path一个eta.core.video.VideoLabels实例、其序列化 dict 表示或其在磁盘上的路径。import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个 (video_path, video_labels_or_path) 元组的可迭代对象以及用于解析它们的 LabeledVideoSampleParser samples ... sample_parser foud.VideoLabelsSampleParser # 将已标注视频添加到数据集 dataset.add_labeled_videos(samples, sample_parser)将样本摄取进数据集ingest 路径常规add_*不复制源媒体但当数据来自二进制源如 TFRecords、或散落在临时目录中时你可能希望把每条样本的原始媒体拷贝到一个统一的存储位置此时应使用ingest_*系列方法。它们会把媒体写入dataset_dir默认取get_default_dataset_dir(dataset.name)见 fiftyone/core/dataset.py底层借助fiftyone.utils.data.ingestors中定义的UnlabeledImageDatasetIngestor、LabeledImageDatasetIngestor等实现fiftyone/utils/data/ingestors.py。基本配方与add_*一致只是把方法名换成ingest_*并额外传入dataset_dir。未标注图像import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个样本可迭代对象以及用于解析它们的 UnlabeledImageSampleParser samples ... sample_parser foud.ImageSampleParser # 例如 # 图像将被写入的目录若为 None则使用基于数据集 name 的默认目录 dataset_dir ... # 将未标注图像样本摄取进数据集源图像会被复制到 dataset_dir dataset.ingest_images(samples, sample_parser, dataset_dirdataset_dir)已标注图像import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() samples ... sample_parser foud.ImageClassificationSampleParser # 例如 dataset_dir ... dataset.add_labeled_images(samples, sample_parser, dataset_dirdataset_dir)注意官方文档原文此处为add_labeled_images如需真正摄取媒体应使用dataset.ingest_labeled_images(samples, sample_parser, dataset_dirdataset_dir)。未标注视频import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() samples ... sample_parser foud.VideoSampleParser # 例如 dataset_dir ... # 将未标注视频样本摄取进数据集源视频会被复制到 dataset_dir dataset.ingest_videos(samples, sample_parser, dataset_dirdataset_dir)已标注视频import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() samples ... sample_parser foud.VideoLabelsSampleParser # 例如 dataset_dir ... dataset.add_labeled_videos(samples, sample_parser, dataset_dirdataset_dir)同样地摄取已标注视频应使用dataset.ingest_labeled_videos(samples, sample_parser, dataset_dirdataset_dir)。摄取未标注图像路径拷贝与内存写入的分支逻辑Dataset.ingest_images()fiftyone/core/dataset.py依赖解析器的has_image_path属性决定处理方式若解析器能提供图像路径has_image_path True源图像会直接从源位置复制到数据集的后备目录否则图像会通过get_image()在内存中读取再写入后备目录可传image_format指定落盘格式默认使用fiftyone.config.default_image_ext。import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个图像或图像路径的可迭代对象以及用于解析它们的 UnlabeledImageSampleParser samples ... sample_parser foud.ImageSampleParser dataset_dir ... # 将图像摄取进数据集源图像会被复制到 dataset_dir dataset.ingest_images(samples, sample_parser, dataset_dirdataset_dir)这一机制在仓库测试中有真实用例tests/misc/torch_tests.py 中把torch.utils.data.DataLoader产出的图像 patch 批量np.transpose成 numpy 数组后直接调用dataset.ingest_images(imgs)未传解析器走默认ImageSampleParser内存数组通过get_image()落盘完整演示了内存数据流 → 摄取为数据集的闭环。摄取已标注图像Dataset.ingest_labeled_images()fiftyone/core/dataset.py同样依据LabeledImageSampleParser.has_image_path决定拷贝或内存写入并支持label_field指定标签字段import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个 (image_or_path, target) 元组的可迭代对象以及用于解析它们的 LabeledImageSampleParser samples ... sample_parser foud.ImageClassificationSampleParser # 例如 dataset_dir ... # 将已标注图像摄取进数据集源图像会被复制到 dataset_dir dataset.ingest_labeled_images(samples, sample_parser, dataset_dirdataset_dir)摄取未标注视频Dataset.ingest_videos()直接把源视频从源位置复制到数据集后备目录视频没有内存读取分支因为解析器总是返回视频路径import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个视频路径的可迭代对象以及用于解析它们的 UnlabeledVideoSampleParser samples ... sample_parser foud.VideoSampleParser dataset_dir ... # 将视频摄取进数据集源视频会被复制到 dataset_dir dataset.ingest_videos(samples, sample_parser, dataset_dirdataset_dir)摄取已标注视频Dataset.ingest_labeled_videos()处理(video_path, video_labels_or_path)元组源视频直接复制到后备目录同时写入 sample-level 与 frame-level 标签import fiftyone as fo import fiftyone.utils.data as foud dataset fo.Dataset() # 一个 (video_path, video_labels_or_path) 元组的可迭代对象以及用于解析它们的 LabeledVideoSampleParser samples ... sample_parser foud.VideoLabelsSampleParser # 例如 dataset_dir ... # 将已标注视频摄取进数据集源视频会被复制到 dataset_dir dataset.ingest_labeled_videos(samples, sample_parser, dataset_dirdataset_dir)内置 SampleParser 一览下表列出 FiftyOne 为常见数据格式提供的全部内置解析器均定义于 fiftyone/utils/data/parsers.pyTF 系列位于 fiftyone/utils/tf.py既可用于add_*也可用于ingest_*SampleParser说明ImageSampleParser解析原始图像样本图像数组或路径VideoSampleParser解析原始视频样本视频路径ImageClassificationSampleParser通用图像分类解析器标签表示为Classification实例ImageDetectionSampleParser通用图像检测解析器标签表示为Detections实例ImageLabelsSampleParser通用图像标签解析器标签存储在 ETAImageLabels格式中FiftyOneImageClassificationSampleParserFiftyOne 图像分类数据集样本解析器格式细节参见FiftyOneImageClassificationDatasetFiftyOneImageDetectionSampleParserFiftyOne 图像检测数据集样本解析器格式细节参见FiftyOneImageDetectionDatasetFiftyOneImageLabelsSampleParserFiftyOne 图像标签数据集样本解析器格式细节参见FiftyOneImageLabelsDatasetFiftyOneVideoLabelsSampleParserFiftyOne 视频标签数据集样本解析器格式细节参见FiftyOneVideoLabelsDatasetTFImageClassificationSampleParser以 TFRecords 存储的图像分类样本解析器TFObjectDetectionSampleParser以 TF Object Detection API 格式存储的图像检测样本解析器关键内置解析器的输入契约来自源码ImageClassificationSampleParser(classesNone)样本为(image_or_path, target)。target可为None未标注、标签字符串/字符串列表、类别 ID/ID 列表需提供classes按classes[target]映射、形如{label: ..., confidence: ..., attributes: {...}}的 dict 或 dict 列表或直接是Classification/Classifications实例。单个目标产出Classification列表产出Classifications。ImageDetectionSampleParser(label_fieldlabel, bounding_box_fieldbounding_box, confidence_fieldNone, attributes_fieldNone, classesNone, normalizedTrue)样本为(image_or_path, detections_or_path)detections_or_path可为None、检测 dict 列表、磁盘上此类格式文件的路径或Detections实例。normalizedTrue表示 bbox 坐标为[0,1]相对坐标normalizedFalse时解析器会读取图像将绝对像素坐标换算为相对坐标。ImageLabelsSampleParser(prefixNone, labels_dictNone, multilabelFalse, skip_non_categoricalFalse)样本为(image_or_path, image_labels_or_path)将 ETAImageLabels标签展开为 FiftyOne 标签字典。VideoLabelsSampleParser样本为(video_path, video_labels_or_path)同时产出 sample-level 标签与 frame-level 标签。编写自定义 SampleParser当样本格式不在内置列表时可实现对应的SampleParser子类接口。SampleParser本身是抽象接口具体实现哪个接口取决于你要导入的样本类型。例如LabeledImageSampleParserfiftyone/utils/data/parsers.py定义了从一条已标注图像样本中解析图像路径、图像本体、元数据以及标签分类或检测等的完整接口。未标注图像解析器实现UnlabeledImageSampleParser接口模板import fiftyone.utils.data as foud class CustomUnlabeledImageSampleParser(foud.UnlabeledImageSampleParser): Custom parser for unlabeled image samples. property def has_image_path(self): # 返回 True 或 False pass property def has_image_metadata(self): # 返回 True 或 False pass def get_image(self): 返回当前样本的图像numpy 格式 # 从 self.current_sample 中返回图像 pass def get_image_path(self): 返回当前样本的图像路径 # 从 self.current_sample 中返回图像路径若 has_image_path False 则抛错 pass def get_image_metadata(self): 返回当前样本的 ImageMetadata 实例 # 从 self.current_sample 中返回图像元数据若 has_image_metadata False 则抛错 pass当Dataset.add_images()传入该自定义解析器时导入过程等价于以下伪代码即with_sample()驱动的逐条解析循环import fiftyone as fo dataset fo.Dataset(...) samples ... sample_parser CustomUnlabeledImageSampleParser(...) for sample in samples: sample_parser.with_sample(sample) image_path sample_parser.get_image_path() if sample_parser.has_image_metadata: metadata sample_parser.get_image_metadata() else: metadata None sample fo.Sample(filepathimage_path, metadatametadata) dataset.add_sample(sample)关键约定基类SampleParser.with_sample()负责载入下一条样本并通过current_sample属性暴露UnlabeledImageSampleParser的has_image_path声明能否通过get_image_path()拿到磁盘路径has_image_metadata声明能否通过get_image_metadata()拿到ImageMetadata按约定所有UnlabeledImageSampleParser实现都必须通过get_image()提供当前样本的图像。已标注图像解析器实现LabeledImageSampleParser接口额外多出label_cls属性与get_label()方法模板import fiftyone.utils.data as foud class CustomLabeledImageSampleParser(foud.LabeledImageSampleParser): Custom parser for labeled image samples. property def has_image_path(self): # 返回 True 或 False pass property def has_image_metadata(self): # 返回 True 或 False pass property def label_cls(self): 本解析器返回的 Label 类可以是以下任一种 - 单个 Label 类保证返回该类型标签 - Label 类列表/元组可产生其中任一类型的单个标签字段 - dict键 → Label 类返回标签字典键与值类型由此 dict 指定不要求所有键都存在 - None对返回的标签不做任何保证 pass def get_image(self): # 返回 numpy 图像 pass def get_image_path(self): # 返回图像路径若 has_image_path False 则抛错 pass def get_image_metadata(self): # 返回 ImageMetadata若 has_image_metadata False 则抛错 pass def get_label(self): 返回当前样本的标签一个 Label 实例、或字段名 → Label 的字典、或 None未标注 passDataset.add_labeled_images()的等价伪代码展示了label_field的处理逻辑——标签为 dict 时可用label_field前缀重命名各字段标签为单个实例时默认存入ground_truth字段import fiftyone as fo dataset fo.Dataset(...) samples ... sample_parser CustomLabeledImageSampleParser(...) label_field ... if isinstance(label_field, dict): label_key lambda k: label_field.get(k, k) elif label_field is not None: label_key lambda k: label_field _ k else: label_field ground_truth label_key lambda k: k for sample in samples: sample_parser.with_sample(sample) image_path sample_parser.get_image_path() if sample_parser.has_image_metadata: metadata sample_parser.get_image_metadata() else: metadata None label sample_parser.get_label() sample fo.Sample(filepathimage_path, metadatametadata) if isinstance(label, dict): sample.update_fields({label_key(k): v for k, v in label.items()}) elif label is not None: sample[label_field] label dataset.add_sample(sample)约定label_cls属性声明解析器将产生的标签类型按约定所有LabeledImageSampleParser实现都必须通过get_image()提供图像、通过get_label()提供标签。未标注视频解析器实现UnlabeledVideoSampleParser接口核心是get_video_path()模板import fiftyone.utils.data as foud class CustomUnlabeledVideoSampleParser(foud.UnlabeledVideoSampleParser): Custom parser for unlabeled video samples. property def has_video_metadata(self): # 返回 True 或 False pass def get_video_path(self): 返回当前样本的视频路径 pass def get_video_metadata(self): 返回当前样本的 VideoMetadata若 has_video_metadata False 则抛错 passDataset.add_videos()的等价伪代码import fiftyone as fo dataset fo.Dataset(...) samples ... sample_parser CustomUnlabeledVideoSampleParser(...) for sample in samples: sample_parser.with_sample(sample) video_path sample_parser.get_video_path() if sample_parser.has_image_metadata: metadata sample_parser.get_image_metadata() else: metadata None sample fo.Sample(filepathvideo_path, metadatametadata) dataset.add_sample(sample)说明官方文档此段伪代码沿用了has_image_metadata/get_image_metadata()实际对视频解析器而言应使用has_video_metadata/get_video_metadata()接口定义见 fiftyone/utils/data/parsers.py。UnlabeledVideoSampleParser通过get_video_path()获取视频路径通过has_video_metadata/get_video_metadata()获取VideoMetadata。已标注视频解析器实现LabeledVideoSampleParser接口同时处理 sample-level 与 frame-level 标签模板import fiftyone.utils.data as foud class CustomLabeledVideoSampleParser(foud.LabeledVideoSampleParser): Custom parser for labeled video samples. property def has_video_metadata(self): # 返回 True 或 False pass property def label_cls(self): 本解析器产生的 sample-level 标签类型单个类 / 类列表 / 类字典 / None pass property def frame_labels_cls(self): 本解析器产生的 frame-level 标签类型单个类 / 类列表 / 类字典 / None pass def get_video_path(self): # 返回视频路径 pass def get_video_metadata(self): # 返回 VideoMetadata若 has_video_metadata False 则抛错 pass def get_label(self): 返回 sample-level 标签Label 实例、字段名 → Label 字典或 None pass def get_frame_labels(self): 返回帧标签帧号 → 字段名 → Label的字典或 None无帧标签 passDataset.add_labeled_videos()的等价伪代码——注意 frame 标签通过sample.frames.merge()写入import fiftyone as fo dataset fo.Dataset(...) samples ... sample_parser CustomLabeledVideoSampleParser(...) label_field ... if isinstance(label_field, dict): label_key lambda k: label_field.get(k, k) elif label_field is not None: label_key lambda k: label_field _ k else: label_field ground_truth label_key lambda k: k for sample in samples: sample_parser.with_sample(sample) video_path sample_parser.get_video_path() if sample_parser.has_video_metadata: metadata sample_parser.get_video_metadata() else: metadata None label sample_parser.get_label() frames sample_parser.get_frame_labels() sample fo.Sample(filepathvideo_path, metadatametadata) if isinstance(label, dict): sample.update_fields({label_key(k): v for k, v in label.items()}) elif label is not None: sample[label_field] label if frames is not None: frame_labels {} for frame_number, _label in frames.items(): if isinstance(_label, dict): frame_labels[frame_number] { label_key(k): v for k, v in _label.items() } elif _label is not None: frame_labels[frame_number] {label_field: _label} sample.frames.merge(frame_labels) dataset.add_sample(sample)约定label_cls声明 sample-level 标签类型、frame_labels_cls声明 frame-level 标签类型按约定所有LabeledVideoSampleParser实现都必须通过get_label()提供 sample-level 标签、通过get_frame_labels()提供 frame-level 标签。实践建议与注意事项优先使用内置解析器覆盖图像分类、图像检测、ETA 标签、FiftyOne 原生格式与 TF 生态格式等常见场景自定义解析器仅用于内置格式覆盖不到的情况。add_*与ingest_*的选择媒体已稳定存在磁盘上、希望数据集只存引用 → 用add_*不读媒体速度快媒体在内存/二进制源/临时文件中、需要统一落盘 → 用ingest_*配合dataset_dir、image_format控制落盘位置与格式。label_field的三种形态单标签字段名默认ground_truth、字符串前缀自动为每个标签键加前缀、dict 映射键 → 目标字段名在add_labeled_images、add_labeled_videos及其 ingest 变体中行为一致。内存数据流实践torch.utils.data.DataLoader迭代产物或tf.data.Dataset.as_numpy_iterator()的输出可直接作为samples传入仓库测试 tests/misc/torch_tests.py 给出了端到端示例。schema 控制expand_schemaTrue时导入过程中遇到的新字段会自动加入数据集 schema置为False则要求样本 schema 是数据集 schema 的子集否则报错适合对 schema 有严格管控的场景。【免费下载链接】fiftyoneRefine high-quality datasets and visual AI models项目地址: https://gitcode.com/GitHub_Trending/fi/fiftyone创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考