Zack Xia

    使用深度学习搜索相似的产品

    在电商铺货过程中,每天都会新增几十甚至几百个新品。由于产品数量众多,难免会遇到相同的SKU。为了避免重复上架,我们需要用到深度学习算法进行图片相似度比较,实现类似Google Lens的效果。

    图为Google Lens搜索结果
    图为Google Lens搜索结果

    今天要用到的模型和算法:

    • Faster R-CNN
    • OpenAI CLIP
    • Cosine Similarity

    在之前的文章中提到,余弦相似度(Cosine Similarity)在数据科学中可以被用来比较两个向量之间的相关性,从而达到相似度对比。详情可以看Phil Miesle的Exploring the Real-world Applications of Cosine Similarity

    什么是Faster R-CNN?

    Faster R-CNN(Region-based Convolutional Neural Network)是一种应用于对象检测(Object Detection)任务的深度学习模型。Faster R-CNN 通过引入区域建议网络(RPN),提高了对象检测的速度和准确性。RPN 生成一系列候选区域,这些区域随后由 Fast R-CNN 检测器进行分类和边界框回归,从而确定每个对象的类别和精确位置。

    Faster R-CNN 的工作流程如下:

    1. 特征提取:使用卷积神经网络(如 ResNet)从输入图像中提取特征。
    2. 区域建议:RPN 生成可能包含对象的候选区域(Anchor)。
    3. 区域分类和回归:Fast R-CNN 检测器对这些候选区域进行分类,并精确调整边界框的位置。
    model = models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
    def detect_objects(image):
        with torch.no_grad():
            prediction = model([transform(image)])[0]
        return prediction

    用fasterrcnn_resnet50_fpn进行预测,会输出由以下元素组成的Python dictionary:

    boxes: 输出包含[y_min, x_min, y_max, x_max]的张量(Tensor). 可以理解为图片中的框框

    labels: 输出由整数组成的张量,如tensor([28, 63, 64, 62, 28]). 这些整数代表了训练数据集的类目,由于fasterrcnn_resnet50_fpn是从COCO数据集训练的,数字对应的类别可以参考:https://github.com/amikelive/coco-labels/blob/master/coco-labels-paper.txt

    scores: 每个框框的置信度(confidence score), 代表了框框中的object和预测类目的相似度

    以Aosom.com的场景图片作为例子,以下是模型输出后的boxes:

    通过fasterrcnn_resnet50_fpn进行预测后的boxes
    通过fasterrcnn_resnet50_fpn进行预测后的boxes

    在不加任何限制条件时,模型会输出检测到的所有框框。假设我们现在的任务是匹配沙发的相似度,在coco-labels-paper.txt中找到63 = couch (沙发),那我们就可以在boxes中匹配labels = 63的box:

    提取label=63之后的输出图像
    提取label=63之后的输出图像

    什么是OpenAI CLIP?

    CLIP 通过多模态对比学习(Contrastive Learning)来训练(text image pairs),在训练时同时学习了大量图像和文本,CLIP 能够捕捉更丰富的语义信息,从而在图像向量表示中包含更多的上下文和语义信息 。CLIP拥有不错的零样本学习能力(Zero Shot Learning),也就是说我们可以直接通过预训练模型进行预测:

    clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
    clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
    
    # 使用上文预测的main_object
    inputs = clip_processor(images=main_object, return_tensors="pt")
    with torch.no_grad():
        image_features = clip_model.get_image_features(**inputs)

    模型会输出这个图像的嵌入(embeddings):

    tensor([[-2.9532e-01, 2.1558e-01, 4.4454e-02, -3.7444e-01, 3.6188e-01, -1.9132e-01, -2.2710e-01, 4.9299e-01, -4.9231e-02, -1.9174e-01, 5.0825e-01, 1.1113e-01, -4.0802e-02, -5.4021e-01, 3.3626e-01, -7.0196e-02, -5.7222e-01, -2.7112e-02, 1.4611e-01, -1.1657e-02, 4.0651e-01, 1.7071e-01, 1.5620e-01, … -8.3940e-02]])

    余弦相似度 Cosine Similarity:

    回归最经典的余弦相似度进行两张图对比:

    from sklearn.metrics.pairwise import cosine_similarity
    similarities = cosine_similarity(image_features, target_image_features)

    轻松找到重合产品:

    图片1:Credenza con Motivo a Spina di Pesce

    image

    图片2:HOMCOM Credenza Moderna in Truciolato e Metallo con 2 Armadietti a 2 Ante con Ripiani e 3 Cassetti

    image

    相似度:94.8%

    Faster R-CNN裁剪出方框,有没有更精准的裁剪算法?

    有,Mask R-CNN 在 Faster R-CNN 的基础上增加了一个用于实例分割的分支,能够为每个对象生成像素级的分割掩码。Mask R-CNN 优势在于实例分割能力,能够提供对象的精确边界,而不仅仅是边界框。这对于需要精确对象形状信息的任务(如医学图像分析、自动驾驶中的障碍物检测)尤为重要。

    原图:

    image

    通过maskrcnn_resnet50_fpn检测主体并裁切后的图片:

    image

    Mask R-CNN能更加精确的识别主体。但需要注意的是,Mask的算法需要更长时间。在电商铺品这个环境下,需要找到两者之间的平衡。

    Made w/ ❤️ by Zack
    Xiaohongshu
    def extract_main_object(image, prediction, target_label=63):
        boxes = prediction['boxes']
        scores = prediction['scores']
        labels = prediction['labels']
    
        # 筛选出标签为沙发的框框
        valid_boxes = boxes[labels == target_label]
        valid_scores = scores[labels == target_label]
    
        if len(valid_boxes) > 0:
            # 获取置信度最高的框框
            max_score_idx = valid_scores.argmax()
            x1, y1, x2, y2 = valid_boxes[max_score_idx].int().numpy()
            return image.crop((x1, y1, x2, y2))
        return image