You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Siamese网络构建支持集、正负样本对适配多视角数据集

带视角层级目录的孪生网络样本生成适配方案

核心改造逻辑是在原有单级目录处理的基础上,额外记录每张图像的视角属性,建立「类别-视角」的分组索引,采样时严格匹配定义好的正负样本规则,同时按视角分层构建支持集即可。

改造后的数据加载函数

原有load_data_set只记录图像和类别标签,现在需要新增视角标签记录,同时建立分组索引,避免采样时每次全量遍历数据集:

import os
import numpy as np
from tensorflow.keras.preprocessing.image import load_img, img_to_array
from random import choice

def load_data_set(data_root, img_size=(224, 224)):
    images = []
    class_labels = []
    view_labels = []
    # 分组索引:键为(类别名, 视角名),值为对应分组下所有样本在图像数组中的索引列表
    group_index = {}
    # 读取所有一级类别目录
    class_list = [d for d in os.listdir(data_root) if os.path.isdir(os.path.join(data_root, d))]

    for class_name in class_list:
        class_path = os.path.join(data_root, class_name)
        # 读取类别下的视角子目录
        view_list = [d for d in os.listdir(class_path) if d.startswith("view") and os.path.isdir(os.path.join(class_path, d))]
        for view_name in view_list:
            view_path = os.path.join(class_path, view_name)
            img_list = [f for f in os.listdir(view_path) if f.endswith(".png")]
            group_key = (class_name, view_name)
            group_index[group_key] = []

            for img_name in img_list:
                img_path = os.path.join(view_path, img_name)
                # 按要求转换为RGB格式、缩放到指定尺寸
                img = load_img(img_path, target_size=img_size, color_mode="rgb")
                img_arr = img_to_array(img) / 255.0  # 像素值归一化到0-1区间,和原有预处理逻辑对齐
                images.append(img_arr)
                class_labels.append(class_name)
                view_labels.append(view_name)
                group_index[group_key].append(len(images) - 1)

    # 转换为numpy数组方便后续索引操作
    images = np.array(images)
    class_labels = np.array(class_labels)
    view_labels = np.array(view_labels)
    return images, class_labels, view_labels, group_index, class_list

改造后的正样本对生成函数

按照规则,正样本对只要求同类别,视角相同/不同都符合要求,采样时从锚点所属类别的所有视角样本池中抽取配对图即可,保留原有的图像增强开关:

def positive_pair(images, class_labels, group_index, augment=False, aug_pipeline=None):
    # 随机采样锚点
    anchor_idx = np.random.randint(0, len(images))
    anchor_class = class_labels[anchor_idx]
    # 收集同类别下所有视角的样本,排除锚点自身
    pos_candidates = []
    for view in ["view1", "view2", "view3"]:
        key = (anchor_class, view)
        if key in group_index:
            pos_candidates.extend([idx for idx in group_index[key] if idx != anchor_idx])
    pair_idx = choice(pos_candidates)

    anchor_img = images[anchor_idx]
    pair_img = images[pair_idx]
    # 执行图像增强
    if augment and aug_pipeline is not None:
        anchor_img = aug_pipeline(anchor_img)
        pair_img = aug_pipeline(pair_img)

    return [anchor_img, pair_img], 1.0

改造后的负样本对生成函数

负样本对要求同时满足「不同类别」+「不同视角」两个条件,采样时先过滤掉和锚点同类别、同视角的样本,再从剩余候选池中抽取配对图:

def negative_pair(images, class_labels, view_labels, group_index, augment=False, aug_pipeline=None):
    # 随机采样锚点
    anchor_idx = np.random.randint(0, len(images))
    anchor_class = class_labels[anchor_idx]
    anchor_view = view_labels[anchor_idx]
    # 收集满足条件的负样本候选:类别不同、视角也不同
    neg_candidates = []
    for (cls_name, view_name), idx_list in group_index.items():
        if cls_name != anchor_class and view_name != anchor_view:
            neg_candidates.extend(idx_list)
    pair_idx = choice(neg_candidates)

    anchor_img = images[anchor_idx]
    pair_img = images[pair_idx]
    # 执行图像增强
    if augment and aug_pipeline is not None:
        anchor_img = aug_pipeline(anchor_img)
        pair_img = aug_pipeline(pair_img)

    return [anchor_img, pair_img], 0.0

支持集构建方法

支持集按「类别-视角」两层结构存储,每个类别每个视角抽取固定数量的参考样本,推理时将查询样本和支持集样本逐对输入孪生网络计算相似度,取最高相似度对应的类别作为预测结果:

def build_support_set(images, class_labels, group_index, shot_num=1):
    """
    构建少样本训练/评估用支持集
    shot_num: 每个类别每个视角抽取的参考样本数量
    """
    support_set = {}
    for class_name in set(class_labels):
        support_set[class_name] = {}
        for view_name in ["view1", "view2", "view3"]:
            key = (class_name, view_name)
            if key not in group_index:
                continue
            # 从对应分组随机抽取指定数量的样本,不重复采样
            selected_idx = np.random.choice(group_index[key], size=shot_num, replace=False)
            support_set[class_name][view_name] = images[selected_idx]
    return support_set

训练批次生成示例

可以直接用下面的函数批量生成正负样本比例1:1的训练批次,适配孪生网络的双输入结构:

def generate_train_batch(images, class_labels, view_labels, group_index, batch_size=32, augment=False, aug_pipeline=None):
    pairs = []
    labels = []
    # 正负样本按1:1比例采样
    for _ in range(batch_size // 2):
        pos_pair, pos_label = positive_pair(images, class_labels, group_index, augment, aug_pipeline)
        neg_pair, neg_label = negative_pair(images, class_labels, view_labels, group_index, augment, aug_pipeline)
        pairs.extend([pos_pair, neg_pair])
        labels.extend([pos_label, neg_label])
    # 拆分出孪生网络需要的两路输入
    input_1 = np.array([p[0] for p in pairs])
    input_2 = np.array([p[1] for p in pairs])
    return [input_1, input_2], np.array(labels)

实现注意事项:

  • 若数据集存在某个视角样本缺失的情况,需要补充候选池为空的边界判断,避免采样报错
  • 图像增强建议对配对的两张图独立执行随机变换,不要使用完全相同的增强参数,防止模型学到增强操作的关联特征
  • 评估阶段构建支持集时建议固定随机种子,保证评估结果可复现
  • 可以根据训练需求调整正负样本的采样比例,不需要严格固定为1:1

内容的提问来源于stack exchange,提问作者Borhan Uddin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 00:51:16