如何对图像进行聚类

文章来源:https://medium.com/voxel51/how-to-cluster-images-6e09bdff7361

2024 年 4 月 10 日

使用 FiftyOne、Scikit-learn和特征嵌入

在 2024 年深度学习的计算密集型环境中,集群一词最常出现在讨论 GPU 集群时--高度优化的矩阵乘法机器的大规模集合,用于训练同样大规模的生成模型。每个人都专注于训练更大、更好的模型,挑战人工智能模型性能的极限,并将最新的架构进展应用于他们的数据。

8

在本文中,我们将介绍聚类的基础知识,并向你展示如何使用开源机器学习库 Scikit-learn 和 FiftyOne 来构建可视化数据!

什么是聚类?

9

集群的构建模块

想象一下,你有一大堆各种形状和大小的乐高积木散落在地板上。到了该把乐高积木收起来的时候,你却发现自己没有一个足够大的垃圾桶来存放所有的乐高积木。幸运的是,你找到了四个较小的垃圾桶,每个都能容纳大致相同数量的乐高积木。你可以把各种乐高积木随意扔进每个垃圾桶,然后就可以收工了。但这样一来,下次你再去找某个特定的乐高积木时,就得花很多时间四处寻找了。

相反,你有一个更好的主意:把相似的乐高积木放在同一个垃圾桶里,会为你节省很多时间和麻烦。但是,你打算用什么标准来把乐高积木放进垃圾桶呢?是给不同颜色的乐高积木分配不同的盒子?还是把所有的方形乐高积木放在一个盒子里,圆形乐高积木放在另一个盒子里?这真的取决于你有哪些乐高积木!简而言之,这就是聚类。

更正式地说,聚类或聚类分析是一套对数据点进行分组的技术。聚类算法接收一堆对象,然后为每个对象分配任务。不过,与分类法不同的是,聚类算法并不是从一个类别列表开始对对象进行分类,迫使对象落入预设的桶中。相反,聚类试图根据数据发现不同的类别。换句话说,聚类的目的是发现数据中的结构,而不是预测预先存在的结构中的标签。

最后一点值得重复:聚类不是预测标签。与分类、检测和分割任务不同,聚类任务没有基本真实标签。我们将这种算法称为无监督算法,与有监督和自监督学习任务形成鲜明对比。

更重要的是,聚类是无需训练的。聚类算法会吸收数据点(对象)的特征,并利用这些特征将对象分成若干组。一旦成功,这些组就会突出独特的特征,让你了解数据的结构。

聚类是如何工作的?

聚类是一个包含技术的总称!

聚类算法有多种类型,根据其用于分配聚类成员资格的标准而有所区别。最常见的几种聚类算法是:

基于中心点的聚类:例如 K-means 聚类和均值移动聚类等技术。这些方法试图找到中心点来定义每个聚类,这些中心点被称为 "中心点",其目的是最大限度地提高聚类内各点之间的一致性。这种聚类方法适用于大型数据集,但对异常值和随机初始化比较敏感。通常情况下,我们会进行多次运行,然后选出最好的一次。你可能会发现,像 K-means 这样的技术在处理高维数据(即 "维度诅咒")时很吃力,如果与均匀流形逼近与投影(UMAP)等降维技术搭配使用,就能更好地发现结构。

基于密度的聚类:DBSCAN、HDBSCAN 和 OPTICS 等技术根据特征空间的疏密程度来选择聚类。从概念上讲,这些算法将高密度区域视为聚类,当点在特征空间中足够分散时,就会将聚类分解。像 DBSCAN 这样基于密度的简单技术在处理高维数据时可能会遇到困难,因为在高维数据中,数据可能并不是密集分布的。不过,HDBSCAN 等更复杂的技术可以克服其中的一些限制,并从高维特征中发现显著的结构。

分层聚类: 这些技术旨在:

  1. 从单个点入手构建聚类,然后迭代地将聚类组合成更大的复合体,或
  2. 解构聚类,从一个聚类中的所有对象开始,反复将聚类分解成更小的组成部分。

随着数据集的增长,聚合聚类(Agglomerative Clustering)等构建技术的计算成本会变得越来越高,但对于中小型数据集和低维特征来说,其性能还是相当可观的。

我应该对哪些特征进行聚类?

对于我们开始讨论的乐高积木,特征(长度、宽度、高度、曲率等)是独立的实体,我们可以将其视为数据表中的列。在对这些数据进行归一化处理后,我们就可以将一行数值作为特征向量传入每个乐高积木块的聚类算法中。从历史上看,聚类技术有很多类似的应用,可以对数据表或时间序列中的数值进行简单的预处理。

由于一些简单的原因,图像等非结构化数据并不能很好地融入这一框架:

  1. 图像的大小(长宽比和分辨率)可能不同
  2. 原始像素值可能非常嘈杂
  3. 像素之间的相关性可能是高度非线性的

如果我们大费周章地调整和标准化所有图像的尺寸、归一化像素值、去噪并将多维数组扁平化为 "特征向量",那么将这些经过处理的像素数组视为特征将给无监督聚类算法带来巨大的压力,使其难以发现结构。这对于像 MNIST 这样的简单数据集来说是可行的,但在实际应用中却往往行不通。

幸运的是,我们拥有强大的非线性函数逼近工具--深度神经网络!将我们的注意力限制在图像领域,我们有 CLIP 和 DINOv2 这样的模型,它们的输出是输入数据的有意义表示,我们还有为图像分类等特定任务训练的模型,我们通常从中提取网络第二层到最后一层的输出。还有变异自动编码器(VAE)网络,通常从中提取中间层的表示!

不同的模型有不同的架构,并在不同的数据集上针对不同的任务进行训练。

使用 FiftyOne 和 Scikit-learn 对图像进行聚类

设置和安装

我们将利用两个开源机器学习库:Scikit-learn 和 fiftyone,前者预装了大多数常见聚类算法的实现,后者简化了非结构化数据的管理和可视化:

pip install -U scikit-learn fiftyone

FiftyOne 聚类插件让我们的生活更加轻松。它在 scikit-learn 的聚类算法和我们的图像之间提供了连接组织,并将所有这些都封装在 FiftyOne 应用程序的一个简单用户界面中。我们可以通过 CLI 安装该插件:

fiftyone plugins download https://github.com/jacobmarks/clustering-plugin

我们还需要另外两个库: OpenAI 的 CLIP GitHub repo 可以让我们使用 CLIP 模型生成图像特征,而 umap-learn 库则可以让我们对这些特征应用一种名为 "统一曲面逼近和投影(UMAP)"的降维技术,从而将其可视化为二维图像:

pip install umap-learn git+https://github.com/openai/CLIP.git

请注意,这两个库中的任何一个都不是严格意义上的必需库--你可以使用 FiftyOne Model Zoo 中暴露嵌入的任何模型生成特征,也可以使用 PCA 或 tSNE 等其他技术进行降维。

安装好所有必要的库后,在 Python 进程中导入相关的 FiftyOne 模块,然后从 FiftyOne Dataset Zoo 中加载一个数据集(如果你愿意,也可以加载你的数据!)。在本文中,我们将使用 MS COCO 数据集的验证分割(5000 个样本):

import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz
from fiftyone import ViewField as F
# load dataset from the zoo
dataset = foz.load_zoo_dataset("coco-2017", split="validation")
# delete labels to simulate starting with unlabeled data
dataset.select_fields().keep_fields()
# rename and persist to database
dataset.name = "clustering-demo"
dataset.persistent = True
# launch the app to visualize the dataset
session = fo.launch_app(dataset)

如果你在 Jupyter Notebook 中工作,可以通过 auto=False,然后在浏览器中打开一个标签页,指向 session.url 指向的位置(通常是 http://localhost:5151/),以查看应用程序的全貌。

10

创建特征

现在我们有了数据,必须生成用于聚类的特征。在本演示中,我们将查看两种不同的特征:由 CLIP 视觉转换器生成的 512 维向量,以及通过 UMAP 降维例程运行这些高维向量生成的二维向量。

要在 FiftyOne 样本集上运行降维,我们将使用 FiftyOne Brain 的 compute_visualization() 函数,该函数通过方法关键字参数支持 UMAP、PCA 和 tSNE。我们可以使用数据集的 compute_embeddings() 方法生成 CLIP 嵌入,然后明确地将其传递到我们的降维例程中。不过,我们可以一石二鸟,隐式告诉 compute_visualization()使用 CLIP 计算内嵌,并将这些内嵌存储在字段 "clip_embeddings "中,然后使用这些内嵌获得二维表示:

res = fob.compute_visualization(
    dataset, 
    model="clip-vit-base32-torch", "clip-vit-base32-torch", 
    embeddings="clip_embeddings", 
    method="umap", 
    brain_key="clip_vis", 
    batch_size=10
)
dataset.set_values("clip_umap", res.current_points)

有了 brain_key 参数,我们就可以通过程序或 FiftyOne 应用程序中的名称来访问这些结果。最后一行将我们生成的二维向量数组存储到数据集的新字段 "clip_umap "中。

刷新应用程序并打开嵌入式面板,我们就能看到数据集的二维表示,图中的每个点都对应一幅图像:

11

计算和可视化聚类

有了特征向量,我们就可以使用 FiftyOne 聚类插件为数据添加结构。在 FiftyOne 应用程序中,按下键盘上的回车键并输入 compute_clusters。点击下拉菜单中的条目,打开聚类模式。

12

输入 run_key(类似于上面的 brain_key),以访问聚类运行的结果。在此过程中,请注意输入表单的动态更新。此时,你需要做出两个关键决定:根据哪些特征进行聚类以及采用哪种聚类算法!

选择 "kmeans "作为聚类方法,"clip_umap "作为特征向量。将聚类数目设为 20,其他参数均使用默认值。点击回车,让聚类算法运行。应该只需要几秒钟。

计算完成后,请注意样本上的新字段包含整数的字符串表示,表示给定样本被分配到哪个聚类。你可以直接过滤这些值,并在样本网格中一次查看一个聚类:

13

更有趣的是,我们在嵌入图中用这些集群标签着色:

14

通过可视化聚类,你可以检查聚类例程是否正确,还可以直观地了解数据结构。在这个例子中,我们可以看到一个泰迪熊聚类,它与数据的其他部分分离得相当好。这个聚类例程还发现了农场动物与大象和斑马等外来动物之间的界限。

现在,创建一个新的聚类运行,将聚类数量增加到 30 个(别忘了在这个新字段中给嵌入着色)。根据随机性(所有例程的初始化都是随机的),大象和斑马现在很有可能占据它们自己的聚类。

回到初始聚类集,让我们来研究嵌入图中的最后一个区域。请注意,有几张踢足球的图片被归入了一个主要由网球图片组成的聚类中。这是因为我们在聚类过程中传递的是二维降维向量,而不是嵌入向量本身。虽然二维投影有助于可视化,UMAP 等技术也能很好地保留结构,但相对距离并没有完全保留,因此会丢失一些信息。

假设我们将 CLIP 内嵌直接输入聚类计算,并使用相同的超参数。在这种情况下,这些足球图像就会与其他足球图像以及飞盘和棒球等其他野外运动图像被分配到同一个聚类中。

15

关键的启示是,高维特征并不比低维特征好,反之亦然。每一种选择都需要权衡利弊。这就是为什么你应该尝试不同的技术、超参数和特征。

为了更清楚地说明这一点,我们使用 HDBSCAN 作为聚类算法,它不允许我们指定聚类的数量,取而代之的是 min_cluster_size 和 max_cluster_size 等参数,以及合并聚类的标准。我们将使用 CLIP 嵌入作为特征,作为一个粗略的起点,我们只希望聚类的元素数在 10 到 300 之间。如果聚类太大,可能没有帮助;如果聚类太小,可能会捕捉到噪音而不是信号。当然,具体数值取决于数据集!

当我们根据聚类标签着色时,结果看起来有点乱。不过,当我们单独查看每个聚类的图像时,就会发现我们在数据集中识别出了一些非常有趣的样本集合。

16

对于 HDBSCAN,所有背景图像的标签均为"-1"。这些图像不会合并到任何最终聚类中。

跟踪聚类运行

在测试特征、聚类技术和超参数的各种组合时,你可能会想记录下生成特定聚类所使用的 "配置"。幸运的是,FiftyOne 聚类插件可以使用自定义运行为你处理所有这些问题。该插件提供了一个操作符 get_clustering_run_info,让你可以通过 run_key 选择一个运行,并在应用程序中查看该运行的所有参数的格式化打印输出:

17

你也可以通过将 run_key 传递给数据集的 get_run_info()方法,以编程方式访问该信息!

用 GPT-4V 标记集群

到目前为止,我们的聚类只有数字,这只是一种美化的内务管理工具。但是,如果我们针对数据集中的某些特定特征进行聚类,我们应该能够识别出这些特征,并用它们来松散地标记我们的样本。天真地说,我们可以逐个查看我们的聚类,只选择特定聚类中的图像并将其可视化,然后尝试自己标记聚类。

或者......我们可以使用多模态大型语言模型来完成这项工作!FiftyOne 聚类插件提供了这一功能,它利用 GPT-4V 的多模态理解能力为每个聚类贴上概念标签。

要使用此功能,你必须拥有 OpenAI API 密钥环境变量(必要时创建账户),设置方法如下:

export OPENAI_API_KEY=sk-...

该功能通过标签簇(label_clusters_with_gpt4v)操作符提供,操作符会从每个簇中随机选取五幅图像,将它们输入 GPT-4V 并给出特定任务提示,然后处理结果。

根据集群的数量(GPT-4V 的速度可能较慢,这与集群数量成线性关系),你可能需要委托执行操作,方法是选中操作员模式对话框中的复选框,然后从命令行启动任务:

fiftyone delegated launch

17

结论

在本文中,我们介绍了如何使用 scikit-learn 和 FiftyOne 将深度神经网络与流行的聚类算法相结合,为非结构化数据提供结构。在这一过程中,我们看到了特征向量、算法和超参数的选择会对聚类计算的最终结果产生很大影响,无论是聚类选择的内容还是聚类识别数据结构的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541690.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

谈谈我的软考高级考证之路(系统架构设计师篇)

系统架构设计师备考资料请移步 2023年软考高级系统架构设计师视频教程,推荐下载!获取。 备考总体策略 • 总体策略:刷视频记笔记刷真题 • 备考时间:建议报完名之后,开始备考,大致2-3个月(基础…

最优算法100例之45-不用循环乘法求1-n的和

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句。不能用循…

JS - BOM(浏览器对象模型)

BOM 浏览器对象模型 BOM可以使我们通过JS来操作浏览器 在BOM中为我们提供了一组对象,用来完成对浏览器的操作 BOM对象 BOM(Browser Object Model)是指浏览器对象模型,它提供了与浏览器窗口进行交互的对象和方法。BOM包括一些核…

数据库系统概论(超详解!!!)第四节 数据库安全性

问题的提出: 数据库的一大特点是数据可以共享 数据共享必然带来数据库的安全性问题 数据库系统中的数据共享不能是无条件的共享。 1.数据库的安全概述 数据库的安全性是指保护数据库以防止不合法使用所造成的数据泄露、更改或破坏 。 系统安全保护措施是否有效…

Xcode 15.0 新 #Preview 预览让 SwiftUI 界面调试更加悠然自得

概览 从 Xcode 15 开始,苹果推出了新的 #Preview 宏预览机制,它无论从语法还是灵活性上都远远超过之前的预览方式。#Preview 不但可以实时预览 SwiftUI 视图,而且对 UIKit 的界面预览也是信手拈来。 想学习新 #Preview 预览的一些超实用调试…

2024年MathorCup数学建模C题物流网络分拣中心货量预测及人员排班解题文档与程序

2024年第十四届MathorCup高校数学建模挑战赛 C题 物流网络分拣中心货量预测及人员排班 原题再现: 电商物流网络在订单履约中由多个环节组成,图1是一个简化的物流网络示意图。其中,分拣中心作为网络的中间环节,需要将包按照不同流…

无人机巡检技术革命性变革光伏电站运维管理

在中国广袤的大地上,光伏电站如雨后春笋般崛起,晶体硅组件板在阳光下熠熠生辉,为人们带来了源源不断的绿色能源。然而,随着光伏产业的迅猛发展,电站运维管理面临着前所未有的挑战。而无人机巡检技术的引入,…

webpack or vite? vuex or pinia?

2022.2.18, 新建一个vue3的项目,过程如下: 目录结构如下: 当还在犹豫选择webpack还是vite,vuex或者pinia的时候,尤大大已经给出了默认选择,vite && pinia。

算法100例(持续更新)

算法100道经典例子,按算法与数据结构分类 1、祖玛游戏2、找下一个更大的值3、换根树状dp4、一笔画完所有边5、树状数组,数字1e9映射到下标1e56、最长回文子序列7、超级洗衣机,正负值传递次数8、Dijkstra9、背包问题,01背包和完全背…

Django模型入门

Django模型入门 为了能够学会使用Django模型,本节通过构建一个实际的Django模型来帮助读者尽快入门。 3.2.1 定义模型 既然Django模型实现了ORM功能,那么它就是对数据库实例的描述和实现。下面,我们通过一个简单的实例进行讲解。 如果需…

SF506DS-ASEMI开关电源二极管SF506DS

编辑:ll SF506DS-ASEMI开关电源二极管SF506DS 型号:SF506DS 品牌:ASEMI 封装:TO-252 最大平均正向电流(IF):5A 最大循环峰值反向电压(VRRM):600V 最大…

【opencv】示例-pca.cpp PCA图像重建演示

// 加载必要的头文件 #include <iostream> // 用于标准输入输出流 #include <fstream> // 用于文件的输入输出 #include <sstream> // 用于字符串的输入输出流操作#include <opencv2/core.hpp> // OpenCV核心功能的头文件 #include "o…

数据结构之单链表相关刷题

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构 数据结构之单链表的相关知识点及应用-CSDN博客 下面题目基于上面这篇文章&#xff1a; 下面有任何不懂的地方欢迎在评论区留言或…

OpenAI CEO山姆·奥特曼推广新AI企业服务,直面微软竞争|TodayAI

近期&#xff0c;OpenAI的首席执行官山姆奥特曼在全球多地接待了来自《财富》500强公司的数百名高管&#xff0c;展示了公司最新的人工智能服务。在旧金山、纽约和伦敦的会议上&#xff0c;奥特曼及其团队向企业界领袖展示了OpenAI的企业级产品&#xff0c;并进行了与微软产品的…

ansible的常见用法

目录 ##编辑hosts文件 ##copy模块##复制过去 ##fetch模块##拉取 ##shell模块 ##好用 ##command模块## ##file模块### ##cron模块### ##crontab 计划任务 ##下载好时间插件 ##script模块 ##yum模块## ##yum下载源配置文件 /etc/yum.repos.d/CentOS-Base.repo ##ser…

【opencv】示例-minarea.cpp 如何寻找一组随机生成的点的最小外接矩形、三角形和圆...

// 包含OpenCV库的高GUI模块和图像处理模块的头文件 #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp"// 包含标准输入输出流的头文件 #include <iostream>// 使用命名空间cv和std&#xff0c;这样我们就可以直接使用OpenCV和标准库的…

Vitis HLS 学习笔记--ap_int.h / ap_fixed.h(1)

目录 目录 1. 概述 2. 简要规则 3. 浮点运算的复杂性 2.1 对阶 3.2 尾数运算 3.3 规格化和舍入 3.4 特殊值的处理 4. 示例&#xff08;ap_fixed.h&#xff09; 5. 量化模式&#xff08;ap_fixed.h&#xff09; 5.1 AP_SAT* 模式会增加资源用量 1. 概述 ap_int.h 和…

【网站项目】摄影竞赛小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【opencv】示例-opencv_version.cpp 输出OpenCV的版本和构建配置的示例

#include <opencv2/core/utility.hpp> // 引入OpenCV核心工具库 #include <iostream> // 引入标准输入输出流库// 定义一个包含命令行参数的字符串 static const std::string keys "{ b build | | print complete build info }" // 定义参数b&#xff…

2024年大唐杯官网模拟题

单选(出题角度很奇怪&#xff0c;不用太纠结&#xff09; 5G NR系统中&#xff0c;基于SSB的NR同频测量在measconfig里最多可以配置&#xff08; &#xff09;个SMTC窗口。 A、3 B、4 C、1 D、2 答案&#xff1a;D 2个 5G 中从BBU到AAU需要保证&#xff08; &#xff09;Gbps…