【CLIP系列】3:语义分割(LSeg、GroupViT)

1 LSeg

LANGUAGE-DRIVEN SEMANTIC SEGMENTATION

LSeg是第一篇将CLIP应用于语义分割的论文。它的分割的效果拔群,容错能力也很高:

效果

模型总览图跟CLIP很像:

模型结构

对于图像链路:输入一张图片,进入分割的模型,得到一个特征图,通过上采样放大,因为我们现在做的是密集任务,输出和原来图像的大小是一致的,所以需要做一些升维的操作,最后模型的输出和ground truth supervision去计算cross entropy loss即可。

图像的编码器是DPT的结构(前面有一个ViT,后面加了个Decoder),即拿ViT去做有监督的语义分割。Decoder的作用是把一个bottleneck feature慢慢地upscale上去。

对于文本链路:总共有N个label,这些标签通过文本编码器就能得到N个文本特征。这里对N是没有限制的,可以只检测狗,也可以检测狗和数,还能检测其他东西,N是随时可以改变的。文本通过编码器之后就会得到一个N×C的矩阵,C是特征的维度。

将图片特征和文本特征在C维度上相乘,就会得到一个H×W×N的tensor,到这一步,就和传统的分割没有区别了,因为传统的分割也是会得到一个H×W×N的特征。

该论文虽然说是用到了CLIP,并且是Zero-Shot,但是它的训练过程是有监督的训练,模型是在7个分割数据集上一起训练出来的,即最后是有ground truth mask的,目标函数就是跟ground truth mask去做的cross entropy loss,而不是像CLIP那样是对比学习的Loss,不是一个无监督训练的工作。

在训练的过程中,文本编码器直接用CLIP的,训练过程中完全冻住,不参与训练。

最后的spatial regularization blocks去掉也不影响我们对模型结构的理解。

2 Group ViT

GroupViT: Semantic Segmentation Emerges from Text Supervision

Group ViT的监督信号来自于文本,不依赖于segmentation mask的手工标注,可以像CLIP那样直接利用图像文本对进行的无监督训练。

Problem Overview

为什么叫Group ViT呢?因为在视觉领域,很早之前做无监督分类的,有一种常用的方法叫grouping,简单来说就是从一个聚类的中心点往外发散,把附近周围相似的点逐渐扩充成一个group,这个group相当于一个segmentation mask,是一种自下而上的方式。此处,作者相当于重新审视了这个grouping的方法,把它完美地用到当前这个框架中,他们提出了一个计算单元,如下图右侧框图,叫做grouping block,还有一些可以学习的group tokens,主要的目的是想让模型在初始学习的时候,能慢慢地把邻近的像素点都一点一点地group起来,变成一个又一个segmentation mask。下图中间画出了这些segmentation mask,在模型的浅层,学到的group token分割的效果还不是很好,能看到一些五颜六色的颜色块。经过模型的学习,深层的group token分割效果相当不错。

模型总览图

Group ViT的贡献是:在一个已有的ViT框架中,加入了grouping block,同时加入了这些可学习的group tokens。

Zero Shot推理过程如下图所示:

  • 给定一张图片,经过GroupViT的图像编码器,就会得到最后的8个Group Embedding;
  • 再把有可能的标签通过文本编码器,得到一系列的文本特征;
  • 接下来计算图像的Group Embedding和文本特征之间的相似度,就可以知道每个group Embedding对应那个Class。

这里有个明显的局限性:因为模型最后只有8个Group Embedding,也就意味着,一张图片的分割最多只能检测到8类。

推理过程

### 使用 CLIP 模型实现双阶段语义分割 #### 阶段一:生成初始分割图 在第一阶段,CLIP 模型用于生成初步的类激活图 (CAM),这些地图反映了不同类别在图像中的位置。具体来说,通过输入文本提示和目标图像至 CLIP 的图像编码器和文本编码器中,获得两者之间的相似度分数矩阵。此过程利用了 CLIP 对图像与文本之间关系的理解。 ```python import torch from PIL import Image import clip device = "cuda" if torch.cuda.is_available() else "cpu" model, preprocess = clip.load("ViT-B/32", device=device) def get_cam(image_path, text_prompts): image = preprocess(Image.open(image_path)).unsqueeze(0).to(device) texts = clip.tokenize(text_prompts).to(device) with torch.no_grad(): logits_per_image, _ = model(image, texts) probs = logits_per_image.softmax(dim=-1).cpu().numpy() return probs # 返回每个文本提示对应的概率分布 ``` 这段代码展示了如何加载预训练的 CLIP 模型,并计算给定图片对于一系列文字描述的概率得分[^4]。 #### 阶段二:优化与细化分割结果 第二阶段涉及对前一步骤产生的粗略 CAM 进行改进。这通常借助额外的技术如条件随机场(CRF)或其他后处理手段完成。目的是提高边界精度和平滑区域内的预测值,使得最终输出更加贴近真实情况。此外,在某些情况下还可以引入其他视觉特征或上下文信息辅助决策。 ```python import numpy as np from skimage.segmentation import felzenszwalb, slic, mark_boundaries from sklearn.cluster import KMeans def refine_segmentation(cam, n_clusters=5): cam_flat = cam.reshape(-1, cam.shape[-1]) kmeans = KMeans(n_clusters=n_clusters, random_state=0).fit(cam_flat) labels = kmeans.labels_.reshape((cam.shape[0], cam.shape[1])) segments_slic = slic(labels.astype(np.float32), n_segments=n_clusters, compactness=10, sigma=1) refined_img = mark_boundaries(labels / float(n_clusters), segments_slic) return refined_img ``` 上述函数接受由 `get_cam` 函数返回的结果作为输入参数之一,并应用聚类算法以及超像素分割方法对其进行精炼处理[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值