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

FaceNet模型三元组生成报错问题及优化方案咨询

FaceNet三元组生成报错解决方案

问题描述

我正在构建FaceNet人脸识别模型,需要生成三元组用于训练,但三元组生成代码出现报错,错误信息如下:

InvalidArgumentError: Shapes of all inputs must match: values[0].shape = [7,96,96,3] != values[2].shape = [6,96,96,3] [Op:Pack] name: stack

尝试使用ragged tensor但不知如何操作,希望得到代码修改建议或更优实现方案。

原三元组生成及测试代码

# 因为数据量很少,所以不使用原论文中的约束条件
def select_all_triplets(images, labels):
    batch_size = len(labels)
    pos_images = [] # 存储正样本图片
    neg_images = [] # 存储负样本图片
    
    for i in range(batch_size):
        anchor_label = labels[i]
        
        pos_list = [] # 存储正样本索引
        neg_list = [] # 存储负样本索引
        
        for j in range(batch_size):
            if j != i: # 因此 len(pos_list) + len(neg_list) = len(images) - 1
                if labels[j] == anchor_label:
                    pos_list.append(j)
                else:
                    neg_list.append(j)
                    
        pos_images.append(tf.gather(images, pos_list))
        neg_images.append(tf.gather(images, neg_list))
        print(pos_list, neg_list)
        
    positive_images = tf.random.shuffle(tf.stack(pos_images))
    negative_images = tf.random.shuffle(tf.stack(neg_images))
    
    return positive_images, negative_images

# 测试代码
img, lbl = next(iter(train_ds))
select_all_triplets(img, lbl)

报错原因

tf.stack要求所有输入张量的形状完全一致,但每个锚点对应的正/负样本数量不相同(比如部分锚点有7个正样本,部分只有6个),导致pos_images和neg_images中的张量形状不一致,无法完成堆叠操作。


解决方案

方案一:使用Ragged Tensor处理可变长度

Ragged Tensor支持存储形状不一致的张量,可直接替代普通张量完成堆叠操作:

import tensorflow as tf

def select_all_triplets_ragged(images, labels):
    batch_size = len(labels)
    pos_images = []
    neg_images = []
    
    for i in range(batch_size):
        anchor_label = labels[i]
        # 向量化筛选正/负样本索引,替代嵌套循环提升效率
        mask_pos = (labels == anchor_label) & (tf.range(batch_size) != i)
        mask_neg = (labels != anchor_label)
        
        pos_indices = tf.where(mask_pos)[:, 0]
        neg_indices = tf.where(mask_neg)[:, 0]
        
        pos_images.append(tf.gather(images, pos_indices))
        neg_images.append(tf.gather(images, neg_indices))
    
    # 转换为Ragged Tensor,支持可变长度张量堆叠
    positive_ragged = tf.ragged.stack(pos_images)
    negative_ragged = tf.ragged.stack(neg_images)
    
    # 对每个锚点对应的正/负样本单独打乱顺序
    positive_ragged = positive_ragged.map(tf.random.shuffle)
    negative_ragged = negative_ragged.map(tf.random.shuffle)
    
    return positive_ragged, negative_ragged

方案二:生成固定数量的三元组(更适合训练)

实际训练中不需要每个锚点对应所有正/负样本,通常每个锚点随机选1个正样本和1个负样本,生成形状固定的三元组,避免形状不一致问题:

def generate_fixed_triplets(images, labels):
    batch_size = tf.shape(labels)[0]
    triplets = []
    
    for i in range(batch_size):
        anchor_label = labels[i]
        # 获取当前锚点的所有正样本索引(排除自身)
        pos_indices = tf.where((labels == anchor_label) & (tf.range(batch_size) != i))[:, 0]
        # 获取所有负样本索引
        neg_indices = tf.where(labels != anchor_label)[:, 0]
        
        if tf.size(pos_indices) == 0 or tf.size(neg_indices) == 0:
            continue  # 跳过没有正/负样本的锚点
        
        # 随机选取一个正样本和一个负样本
        pos_idx = tf.random.shuffle(pos_indices)[0]
        neg_idx = tf.random.shuffle(neg_indices)[0]
        
        triplets.append([images[i], images[pos_idx], images[neg_idx]])
    
    # 返回形状固定的张量,可直接输入Triplet Loss计算
    return tf.stack(triplets)

方案优势说明

  • 方案一适合需要保留所有正/负样本关联场景,但后续训练时需要额外处理Ragged Tensor的维度适配。
  • 方案二生成的三元组形状固定([num_triplets, 3, 96, 96, 3]),可直接对接FaceNet的Triplet Loss损失函数,更符合实际训练流程,是更推荐的实现方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 04:08:18