大模型应用实践——图片整理:还在为你那乱糟糟的相册烦恼吗?实现一键整理功能。

620 阅读4分钟

前言

前面我们介绍了很多大模型的理论知识,今天来实践一下。

我们要做的功能是图片整理,在生活中我们会不断的拍照,直到几百上千张后,我们已经很难找到前面的某张图片,这时候就需要对图片进行分类整理,才能方便使用。

数据准备

避免泄露隐私,我直接文生图搞了一些照片:

image.png

分组情况:

  • 大山里旅行:0,1,4,6,7,8,18
  • 生活中的美食:3,5,9,13,19
  • 会议和工作:10,12,17,20
  • 各种动漫:2,11,14,15,16

DBScan自动聚类

首先我们能想到的最简单的整理方式就是,直接用无监督学习中的聚类。

先将提取图片的特征

  • VIT:Vision Transformer (ViT) 是一种基于 Transformer 架构的图像特征提取模型。它不同于传统的卷积神经网络(CNN),使用了自注意力机制来处理图像数据。
import PIL.Image
import torch
from transformers import ViTModel, ViTImageProcessor

extractor = ViTImageProcessor.from_pretrained("google/vit-base-patch16-224-in21k")
vit_model = ViTModel.from_pretrained("google/vit-base-patch16-224-in21k")


def load_imgs_vit_embedding(dir: str):
    x, y = [], []
    for file in os.listdir(dir):
        if not file.endswith(".jpg"):
            continue
        img = PIL.Image.open(f"{dir}/{file}")
        img_input = extractor(images=img, return_tensors="pt")
        with torch.no_grad():
            output = vit_model(**img_input).last_hidden_state.mean(dim=1).reshape(-1, )
        x.append(output.numpy())
        y.append(file)
    return x, y

再用DBScan分类

from sklearn.cluster import DBSCAN

x, y = vit.load_imgs_vit_embedding("./imgs")
dbsy = DBSCAN(eps=5, min_samples=2).fit_predict(x)

方便查看聚类的效果,我们画一下特征在三维空间的PCA降维后的坐标图像:

fig = plt.figure()
pcax = PCA(n_components=3).fit_transform(x)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(pcax[:, 0], pcax[:, 1], pcax[:, 2], c=dbsy)
plt.show()
  • 可以看到同样分类的基本都聚在一起了。 image.png

打印一下具体的分组结果,除了噪点外,其他分类还可以。

噪点【-1】:['14.jpg', '13.jpg']
分组【0】:['8.jpg', '18.jpg', '4.jpg', '7.jpg', '6.jpg', '1.jpg', '0.jpg']
分组【1】:['9.jpg', '19.jpg', '5.jpg', '3.jpg']
分组【2】:['15.jpg', '16.jpg', '11.jpg', '2.jpg']
分组【3】:['17.jpg', '12.jpg', '10.jpg', '20.jpg']

CLIP召回

如果我们只对一类照片感兴趣,比如我想在所有的拍摄的照片中,找到在山上旅游的照片。

这时候我们就需要根据一段文字描述找到特征最相似的图片。

这里我们用clip算法

CLIP(Contrastive Language-Image Pretraining)是由OpenAI提出的一种联合图像和文本的预训练模型。CLIP通过对比学习的方法,将图像和文本嵌入到同一个向量空间中,使得相关的图像和文本具有相似的向量表示。这使得CLIP在图像和文本的跨模态任务中表现出色,如图像分类、图像检索、文本生成图像等。

代码实现:

import numpy as np
import torch
from transformers import CLIPModel, CLIPProcessor

clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")

x, y = data_process.load_images("./imgs")
text_input = clip_processor(text=["一个人在大山旅行"], images=x, return_tensors="pt", padding=True)

# logits_per_text 是文本特征和图片特征的相似度。
with torch.no_grad():
    output = clip_model(**text_input).logits_per_text.softmax(dim=1).numpy().reshape(-1)

y_index = np.argsort(-output)
ny = np.array(y)
print(ny[y_index])

打印结果:

['8.jpg' '1.jpg' '4.jpg' '18.jpg' '6.jpg' '16.jpg' '13.jpg' '7.jpg'
 '0.jpg' '17.jpg' '9.jpg' '14.jpg' '3.jpg' '5.jpg' '19.jpg' '2.jpg'
 '11.jpg' '20.jpg' '12.jpg' '15.jpg' '10.jpg']

对比上面我们的正确结果,召回准确率还是很高的。

基于大模型的方法

思考:我们在给图片分类时,还是需要考虑一些非图片的特征,比如照片的拍摄时间,拍摄地点,人文,节日等等关键信息。

比如,召回的输入是:国庆时在上海的旅游照片。这时只从图片特征处理是无法处理的。这时候就需要我们使用大模型的能力来处理:

  1. 图片信息扩展,我们将图片的内容转换为文字描述,然后和它附带的标签(时间,地点,人物,时间)一起放到查询引擎中。并提取记录它们的特征。
  2. 使用llm将用户查询的query,转换为查询条件和召回特征。
  3. 先检索,再在检索集中进行相似度匹配。

图片转文本

这一步可以使用大模型来完成,如下,用千问的vl模型来处理:

from dashscope import MultiModalConversation


def get_image_desc(img_path: str):
    messages = [{
        'role': 'system',
        'content': [{
            'text': 'You are a helpful assistant.'
        }]
    }, {
        'role':
            'user',
        'content': [
            {
                'image': img_path
            },
            {
                'text': '描述图片中的内容'
            },
        ]
    }]
    response = MultiModalConversation.call(model='qwen-vl-plus', messages=messages)
    return response.output.choices[0].message.content

文本向量化

上面用的clip的模型,能处理的文本长度是非常有限的,还是推荐用文本embedding大模型来处理。

如下还是用千问模型来处理。

def embed_with_str(query: str):
    resp = dashscope.TextEmbedding.call(
        model=dashscope.TextEmbedding.Models.text_embedding_v1,
        input=query)
    if resp.status_code == HTTPStatus.OK:
        return resp.output["embeddings"][0]["embedding"]
    else:
        return []

输入扩展

其他

具体的链路还比较复杂,这里就不写了

尾语

大模型应用才刚刚起步,前途还大有可为。只要肯思考,万物皆AI。