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

TensorFlow PGD攻击报错:标签与输入张量形状不兼容求助

问题根源与修复方案

错误核心原因

  1. PGD函数逻辑错误:当前代码直接用输入图像adv_image和标签计算交叉熵,但adv_image是(1,32,32,3)的图像张量,不是模型的输出结果(模型输出应对应8类的概率/ logits,形状为(1,8)),这才是形状不匹配的根本原因,不需要把标签转成图像形状。
  2. 标签格式不匹配:使用categorical_crossentropy需要标签是one-hot编码格式,但你的标签是单个整数,必须先做格式转换。

具体修复步骤

步骤1:修正PGD攻击函数的loss计算逻辑

计算loss前,必须先让模型对adv_image做预测,用模型的输出结果和标签计算损失,而非直接用图像张量。

步骤2:将整数标签转换为one-hot编码

标签取值0-7(共8类),需把单个整数转成形状为(1,8)的one-hot向量。

修复后的完整代码

修复后的PGD攻击函数

def pgd_attack(model, input_image, input_label= None, 
              epsilon=0.0313, 
              num_steps=20, 
              step_size=0.002, 
              clip_value_min=0., 
              clip_value_max=1.0, 
              soft_label=False,
              from_logits= False): 
    
    loss_fn = tf.keras.losses.categorical_crossentropy
    
    if type(input_image) is np.ndarray: 
        input_image = tf.convert_to_tensor(input_image)
    
    # 处理标签:整数转one-hot编码
    if input_label is not None:
        if type(input_label) is np.ndarray: 
            input_label = tf.convert_to_tensor(input_label)
        # 调整形状后转one-hot,类别数固定为8(0-7)
        input_label = tf.reshape(input_label, (1,))
        input_label = tf.one_hot(input_label, depth=8)
        
    # 随机初始化对抗样本
    random_noise = tf.random.uniform(shape=input_image.shape, minval=-epsilon, maxval=epsilon)
    adv_image = input_image + random_noise

    for _ in range(num_steps): 
        with tf.GradientTape(watch_accessed_variables=False) as tape: 
            tape.watch(adv_image)
            # 关键修复:先获取模型对对抗样本的输出
            model_output = model(adv_image, training=False)
            
            if not soft_label:
                loss = loss_fn(input_label, model_output, from_logits=from_logits)
            else: 
                # 软标签模式下,用模型预测的类别作为攻击目标
                pred_label = tf.math.argmax(model_output, axis=1)
                pred_label = tf.one_hot(pred_label, depth=8)
                loss = loss_fn(pred_label, model_output, from_logits=from_logits)

        gradient = tape.gradient(loss, adv_image)
        adv_image = adv_image + step_size * tf.sign(gradient)
        adv_image = tf.clip_by_value(adv_image, input_image-epsilon, input_image+epsilon)
        adv_image = tf.clip_by_value(adv_image, clip_value_min, clip_value_max)
        adv_image = tf.stop_gradient(adv_image)
    return adv_image

调用代码优化(避免索引越界)

for i in range(20):
    # 修正randint范围,避免索引越界
    n = random.randint(0, len(data_manager.X_test)-1)  
    label = data_manager.y_test[n]
    img = data_manager.X_test[n]
    img = tf.expand_dims(img, axis=0)
    img = img.astype('float32')

    true_pred = our_network_skip.predict(img)
    # 直接传入整数标签即可
    pa = pgd_attack(our_network_skip, img, label,
                  epsilon=0.0313, 
                  num_steps=20, 
                  step_size=0.002, 
                  clip_value_min=0., 
                  clip_value_max=1.0, 
                  soft_label=False,
                  from_logits= False)

    pgd_pred = our_network_skip.predict(pa)
    # 优化打印格式,显示真实类别和对抗样本预测类别
    print("True label: {}, adversarial label: {}".format(
        tf.argmax(true_pred, axis=1).numpy()[0], 
        tf.argmax(pgd_pred, axis=1).numpy()[0]
    ))

额外说明

  • 如果模型最后一层是无激活的Dense层(输出logits),需将from_logits=True传入PGD函数,损失函数会自动适配logits计算。
  • 原代码中random.randint(0, len(data_manager.X_test))会导致索引越界,因为randint是闭区间,所以调整为len(data_manager.X_test)-1。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:01:11