大数据集可视化:FiftyOne 的使用经验分享(一)

背景

一般对于普通数据集的使用,都是直接在网站下载(比如:Kaggle),数据集的格式也相对统一,按照案例直接批量使用就行了。

但是对于大型的数据集,以及有定制化的需求,需要额外的操作时,则需要自己对数据集的进行一些适配和修正。一般会遇到些问题:

  1. 数据集包一般很大,官方很少会分类出小包,下载起来麻烦;(比如:GBIF、ImageNet、Caltech)
  2. 数据集格式一般没有详细的说明,直接上手比较麻烦。(一个大数据集可能包含不同的任务,比如 captions 和 keypoints 的数据格式就不一样,得自己区分)
  3. 如果需要筛选一下再用,那么人工手动操作比较麻烦,能可视化最好;
  4. 想要批量导出或者导入,需要写一定代码适配;
  5. ......

本人遇到了上述的问题,找到了一个比较好用的 Python库,浅浅介绍一下。

一、简介

官方的介绍是:

The open-source tool for building high-quality datasets and computer vision models

即“一个用于构建高质量数据集和计算机视觉模型的开源工具”,概括下就是:FiftyOne 是一个用于机器学习和计算机视觉任务的强大的 Python 库,它支持各种数据集操作,包括导入、分析和可视化数据。

先放个效果图片供参考:

核心功能还包括:

        1. Curating datasets - 精选数据集

里面适配了很多知名的数据集,针对他们的格式做了比较好的适配,而且可以几行代码就可以定制化的下载想要的数据集,可谓是开袋即食,比如:COCO、VOC、YOLO、CAVT ......

        2Evaluating models - 评估模型

可以在模型训练完后,将结果添加到数据集中,然后直接调用评估相关的API,评估的比较多。比如:平均精度均值(mAP)、TP、FP、FN、IoU......

        3. Visualizing embeddings - 可视化嵌入

使用FiftyOne的嵌入可视化功能揭示数据中的隐藏结构,挖掘困难样本,预标注数据,推荐新样本进行标注等。

        4. Working with geolocation - 处理地理位置

许多数据集包含位置元数据,但传统上可视化基于位置的数据集需要闭源或基于云的工具。FiftyOne提供了存储、可视化和按位置查询数据集的原生支持。

        5. Finding annotation mistakes - 发现标注错误

可以用FiftyOne自动识别数据集中可能的标签错误。

        6. Removing redundant images - 移除冗余图像

可以自动从数据集中移除重复或近似重复的图像,从原始数据中策划多样化的训练数据集。

这里放一下官方文档,大家可以参考:

FiftyOne — FiftyOne 0.23.7 documentationicon-default.png?t=N7T8https://docs.voxel51.com/index.htmlGitHub - voxel51/fiftyone: The open-source tool for building high-quality datasets and computer vision modelsThe open-source tool for building high-quality datasets and computer vision models - voxel51/fiftyoneicon-default.png?t=N7T8https://github.com/voxel51/fiftyone

二、安装

2.1 创建并激活环境

最好弄个虚拟环境,官网也是这么建议的。这里以Anaconda为例,大家根据自己习惯:

conda create -n your_env_name python=3.8

这里指定了Python 3.8,如果不指定将会安装Anaconda当前默认的Python版本,是基于你安装的Anaconda版本和创建环境时的最新可用版本。

官网要求的是:Python 3.7 - 3.12版本,但是我配的时候 3.7 踩坑了,最好别用原因下面会提。

安装好后可以确认下:

python --version

版本没问题就激活环境:

conda activate your_env_name

前面出现环境名称就算激活成功(我的叫FiftyOne),当前路径无所谓,目前只是安装阶段。

补充一下:如果后续哪里有问题,也可以删除环境重新安装,这也是虚拟环境的优势。

// 先查看当前 Anaconda 环境列表:
conda env list
// 或者
conda info --envs
// 如果想要删除哪个
conda env remove -n env_name

2.2 安装FiftyOne

pip install fiftyone

安装过程比较慢,耐心等待就行,一般是缺什么安什么,比如这里就报错:(Python 3.7 会遇到)

这里就缺 py7zr 的一个依赖 inflate64 ,要求 1.0.0 以上。

先查看当前版本,可以发现是0.3.1,不满足要求:

如果直接指定版本,也会报错:

去官网查看最新版本,的确是 1.0.0:

这里其实是 Python版本不兼容,需要至少 Python 3.8,大家注意避坑!

其他如果有缺的包,直接安装就行,没遇到其他问题。

2.3 验证安装成功

可以通过导入FiftyOne包来验证是否成功:

python
>>>
>>> import fiftyone as fo
>>>

如果没问题,当导入fiftyone时不应有任何输出,如果有其他故障,可以参考:官方的安装问题说明icon-default.png?t=N7T8https://docs.voxel51.com/getting_started/install.html#install-troubleshooting

2.4 其他安装

2.4.1 FFmpeg

如果需要操作的数据是视频相关的,需要安装这个。

windows 直接下载,解压并添加到你的目录就可以了:

Download FFmpegicon-default.png?t=N7T8https://ffmpeg.org/download.html#build-windows其他系统可以用命令:

// Linux:
sudo apt install -y ffmpeg
// macOs:
brew install ffmpeg

2.4.2 FiftyOne Desktop App

默认的时候,启动后会在浏览器打开,官方也提供了桌面端,需要的可以安装:

pip install "fiftyone[desktop]"

用的时候,启动命令 `launch_app()` 提供了 `desktop`这个 flag 来选择用什么启动。

当然,也可以直接在 FiftyOne config 中设置的 desktop_app 标志,以默认使用桌面应用。

三、使用

官方提到一个特性:

”FiftyOne uses a lightweight non-relational database to store datasets, so you can easily scale to datasets of any size without worrying about RAM constraints on your machine.“

即:FiftyOne使用轻量级非关系型数据库来存储数据集,因此您可以轻松扩展到任何大小的数据集,而无需担心您机器上的RAM限制。

3.1 加载示例数据集

数据集由多个包含字段属性的样本对象组成,这些字段属性可以动态创建、修改和删除

3.1.1 创建一个数据集

先创建一个空的数据集以作展示:

import fiftyone as fo

dataset = fo.Dataset("test-dataset")

print(dataset)

打印输出的结果:

Name:           test-dataset
Media type:     None
Num samples:    0
Persistent:     False
Tags:           []
Sample fields:
    id:         fiftyone.core.fields.ObjectIdField
    filepath:   fiftyone.core.fields.StringField
    tags:       fiftyone.core.fields.ListField(fiftyone.core.fields.StringField)
    metadata:   fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.metadata.Metadata)

3.1.2 创建一个样本

字段是样本(Sample)实例的属性,用于存储有关样本的自定义信息。将数据集想象为一张表,其中每一行是一个样本,表的每一列是一个字段。所有样本都必须填充其文件路径字段,该字段指向磁盘上样本的源数据。

import fiftyone as fo

sample = fo.Sample(filepath="/path/to/image.png")

print(sample)

默认情况下,样本还会被赋予 id、media_type(媒体类型)、metadata(元数据) 和 tags(标签字段),这些字段存储常见信息:

<Sample: {
    'id': None,
    'media_type': 'image',
    'filepath': 'path/to/image.png',
    'tags': [],
    'metadata': None,
}>

列表和字典字段的元素可以是同质的或异质的,甚至可以包含嵌套的列表和字典,字段也可以包含更复杂的数据类型(比如嵌套标签)。

字段可以动态创建、修改和删除。当一个新的字段被分配给数据集中的一个样本,或者一个带有新字段的样本被添加到数据集时,相应的字段会自动添加到数据集的模式中,因此可以在数据集中的所有其他样本上访问。

3.2 加载COCO数据集

支持的数据集有很多,因为本人尝试了这个,所以以此为例,其他的数据集可以看官网介绍:

FiftyOne Integrations — FiftyOne 0.23.7 documentationicon-default.png?t=N7T8https://docs.voxel51.com/integrations/index.htmlFiftyOne支持加载 COCO-2014 COCO-2017 数据集,该数据集也可以手动从其官方下载:
COCO - Common Objects in Contexticon-default.png?t=N7T8https://cocodataset.org/#download需要注意的是,FiftyOne支持加载检测任务的注释,包括 边界框 和 分割

但是COCO数据集还包括了其他数据类型,这里只引入检测任务而已。

比如从官网直接下载的包中,可以看到分为这几类(以 `annotations_trainval2014` 为例):

打开 `captions`,其内部 `annotations` 标签内容包含了 `Caption` ,如下:

打开 `instances`,能看到包含了 `Segmentation` 和 `Bbox` :

打开 `person`:

上面这样截图,是因为 json 文件都太大了,不好直接格式化进行展示。当然,也没办法进行一些切分 和 手动筛选

3.2.1 自定义加载COCO数据集

引入库后,可以用简短的代码就自动下载该数据集,并且可以进行额外的筛选:

import fiftyone as fo
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset(
    "coco-2014",
    split="train",
    max_samples=50,
    shuffle=True,
)

session = fo.launch_app(dataset)

session.wait()

参数说明:

split / splits

分别指定要加载的 拆分 的字符串或字符串列表;

这里支持:”train“ , "test" , "validation",即训练、测试和验证;

如果未指定,则会加载所有;

label_types

要加载的 标签类型 或标签类型列表;

这里支持:”detections“,”segmentations“;

默认的话,仅加载 "detections" ;

max_samples

要加载的每个拆分的 最大样本数

这里说的拆分是针对 "split",即指定了谁,就是每个里面取max_samples个;

shuffle是否 随机洗牌 以部分下载样本的选择顺序;

`session` 就是所启动的实例,网页或者桌面端的那个界面,后续可以在一个程序里面生成多个数据集,用 `session.dataset` 进行添加。

`session.wait()` 让程序在这里停着直到手动关闭界面,不然运行后会闪退

注意:

这里程序是分割引入的,即只下载了所指定的一部分数据集到本地,所以效率更高;

并且如果多次运行程序,也会先检查本地是否存在了所需数据,不会重复下载

但是,如果你条件变了,比如`split`改了、`max_samples`加多了,那么检查发现本地没有后,会再进行补充下载

这里展示两种`label_types`运行后的界面:

label_types=["detections"]:(框内包含各种物体和其边框,当然框的粗细和颜色在这里可以调)

点开某个具体的图片:(可以看到,一个图片内包含多个`Label`

label_types=["segmentations"](图片中就会额外包含`mask`的信息)

有趣的,如果下载数量比较多以后(比如下载全部的COCO数据集),数据量会比官方的包大!

可以看到,这里下载的100Gb 是远大于官网提供的下载包。猜测原因如下,当然大家最好还是按需下载好一点:

  1. 数据压缩格式不同:使用了不同的压缩标准,或者没有压缩;
  2. 包含额外的元数据或注释信息:FiftyOne下载的数据集可能不仅仅包含图片,还可能包含额外的元数据或注释信息,这些信息也会增加数据的总体积。
  3. 下载速度与数据显示:也可能是显示的问题;

3.2.2 筛数据集标签

因为选择数据的时候,往往需要指定 `Label`。当然可以先下载然后选择不同的DataView进行筛选,再导出即可。不过,直接下载指定`Label`的数据集更为高效:

import fiftyone as fo
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset(
    "coco-2014",
    split="train",
    label_types=["detections"],
    classes=["dog"],
    max_samples = 200,
    shuffle=True,
    only_matching=True,
)
session = fo.launch_app(dataset)

这里的 `classes` 即为需要指定的标签,也可以指定多个;

`only_matching` 表示 ”是否仅加载提供的类别或属性要求匹配的标签";(区别于上面一个图片包含多种`Label`的情况)

这里就可以仅下载上面指定的 "dog" 了。但是,如果发现所有"train"中符合标签要求的`sample`少于`max_samples`个,那么这个 dataset 的数量就会少于这个设定的最大值;

其实这里单独讲筛选,是因为有个,写出来帮大家避开一下:
因为加载数据集后,就会下载到本地。所以你第二次运行程序,如果改参数,会生成新的数据集:

在这里可以选择要展示的数据集,注意下自动的命名规则:`name + split + max_samples`;

并没有刚才上面提到的标签,即:classes=["dog"];

我刚开始修改了好几次`Label`,结果运行并没有改变,官网也没什么说明,所以我推测:

改 `classes` 并不会让程序认为是一个新的数据集,所以不会触发数据集的更新

同理,如果改了上面三个参数,那么就会被认为是新的数据集,一直生成新的

所以可能会需要 查找和删除 所生成的数据集:

import fiftyone as fo

# 列出当前所有已加载的数据集名称
dataset_list = fo.list_datasets()
print(dataset_list)

# 删除已存在的数据集
fo.delete_dataset("coco-2014-train-50")

3.3 添加样本示例

import fiftyone as fo
# 添加样本示例
# 创建一个样本
sample = fo.Sample(filepath="/path/to/image.png")
# 设置字段值
sample["quality"] = 89.7
sample["keypoints"] = [[31, 27], [63, 72]]
sample["geo_json"] = {
    "type": "Feature",
    "geometry": {"type": "Point", "coordinates": [125.6, 10.1]},
    "properties": {"name": "camera"},
}
# 向数据集中添加样本
dataset.add_sample(sample)
print(dataset)

当然最好注意下样本和数据集格式的匹配,据官网说会有一定的智能修正,还未进行测试;

3.4 导出样本示例

import os
import fiftyone as fo
# 类别列表
classes = dataset.distinct("ground_truth.detections.label")

# 存储数据集图片的目录
IMAGES_DIR = os.path.dirname(dataset.first().filepath)

# 以 COCO 格式导出一些标签
dataset.take(3).export(
    dataset_type=fo.types.COCODetectionDataset,
    label_field="ground_truth",
    labels_path="C:\\Users\\Mr_Ant\\Desktop\\coco.json",
    classes=classes,
)

这里导出的是 `JSON` 格式的信息,图片地址存在变量 `IMAGES_DIR`里,可进行额外的操作;

这里展示一下导出的JSON文件:

{
    "info": {
        "year": 2014,
        "version": "1.0",
        "contributor": "COCO Consortium",
        "url": "http://cocodataset.org",
        "date_created": "2017/09/01"
    },
    "licenses": [
        {
            "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/",
            "id": 1,
            "name": "Attribution-NonCommercial-ShareAlike License"
        }
        ......
    ],
    "categories": [
        {
            "id": 0,
            "name": "airplane",
            "supercategory": "vehicle"
        }
        ......
    ],
    "images": [
        {
            "id": 1,
            "file_name": "COCO_train2014_000000206749.jpg",
            "height": 640,
            "width": 479,
            "license": null,
            "coco_url": null
        }
        ......
    ],
    "annotations": [
        {
            "id": 1,
            "image_id": 1,
            "category_id": 13,
            "bbox": [
                288.82,
                63.38,
                42.22,
                135.72
            ],
            "area": 5730.0984,
            "iscrowd": 0,
            "supercategory": "kitchen"
        },
        {
            "id": 2,
            "image_id": 1,
            "category_id": 47,
            "bbox": [
                33.08,
                335.1,
                355.23,
                251.69
            ],
            "area": 89407.83870000001,
            "iscrowd": 0,
            "supercategory": "food"
        }
        ......
    ]
}

可以发现 `categories` 里面放的是所有的类别,即上面导出时产生的 classes;

`annotations`  里一张图片可能多个选框,即注意区分 `image_id`;

当然,这里所呈现的仅是 COCO-2014 且 分割后一部分数据集的格式,具体大家可以根据自己需求导出后再查看与适配。

结束语

本篇仅介绍了比较基本的一些用法,主要还是一些避坑指南,

具体的大家可以查看官方文档(虽然是纯英文的......)

后续根据需求也会继续学习并且写下来分享,欢迎一起讨论与学习!

  • 43
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,那么您需要先了解一下您的数据集是什么样子的,包含哪些数据,以及您想要展示的信息是什么。一般来说,数据可视化的目的是为了更直观地展示数据,让人们能够更容易地理解数据的含义和趋势。 在Python中,有很多可视化工具可以使用,比如Matplotlib、Seaborn、Plotly等。这些工具都有自己的特点和优势,您可以根据自己的需要选择其中之一进行使用。 接下来,我将给您提供一个简单的例子,展示如何使用Matplotlib将一个数据集可视化: 假设您有一个包含学生考试成绩的数据集,其中包含每个学生的姓名、年龄、性别以及数学、英语、语文三门科目的成绩。现在您想要展示这些学生的平均成绩情况。 首先,您需要使用Python读取这个数据集,并将其存储为一个DataFrame对象。可以使用pandas库来完成这个任务: ``` import pandas as pd # 读取数据集 data = pd.read_csv('students_scores.csv') # 计算平均成绩 data['mean_score'] = data[['math_score', 'english_score', 'chinese_score']].mean(axis=1) ``` 然后,您可以使用Matplotlib来绘制一个柱状图,展示每个年龄段的平均成绩情况: ``` import matplotlib.pyplot as plt # 按年龄分组,计算平均成绩 by_age = data.groupby('age')['mean_score'].mean() # 绘制柱状图 plt.bar(by_age.index, by_age.values) # 添加标签和标题 plt.xlabel('Age') plt.ylabel('Mean Score') plt.title('Mean Scores by Age') ``` 这样,您就可以得到一个展示每个年龄段平均成绩的柱状图了。当然,这只是一个简单的例子,您可以根据自己的需要进行更复杂的数据可视化
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值