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

自定义含可训练参数的损失函数遇报错,求排查方案

问题排查与解决方案

一、报错根源分析

你遇到的ValueError: expected no data, but got: [array...]是因为模型定义和训练数据传入的逻辑冲突:

  • 你使用了model.add_loss()注入自定义损失,此时Keras会认为模型损失已在内部计算完成,不需要外部传入目标标签(y参数);
  • 但你训练时还是传入了y_true作为目标数据,导致Keras报错——它预期y为None,却收到了真实标签数组。

二、自定义损失层的问题修正

你的损失层存在几个小问题,我帮你调整后实现了正确的逻辑:

  1. 初始化代码冗余:__init__里的gamma_init重复定义,且旧版Keras的initializations.get()已不再推荐使用;
  2. compute_output_shape返回值错误:输入是两个张量,输出应为每个样本的损失维度;
  3. 参数命名混淆:把可训练参数命名为gamma而非gamma_init,避免歧义。

修正后的损失层代码:

from keras.layers import Layer
import keras.backend as K

class BCLoss(Layer):
    def __init__(self, lamada=0.00005, **kwargs):
        self.lamada = lamada
        super(BCLoss, self).__init__(**kwargs)
    
    def build(self, input_shape):
        # 定义可训练参数gamma,初始化方式为uniform
        self.gamma = self.add_weight(
            name='gamma', 
            shape=(1,), 
            initializer='uniform', 
            trainable=True
        )
        super(BCLoss, self).build(input_shape)  # 必须调用父类build方法完成层构建
    
    def call(self, inputs, **kwargs):
        y_true, y_pred = inputs
        # 计算每个样本的二元交叉熵,按最后一维取平均
        bce_loss = K.mean(K.binary_crossentropy(y_true, y_pred), axis=-1)
        # 添加L1正则项:λ乘以gamma的绝对值
        reg_loss = self.lamada * K.abs(self.gamma)
        # 总损失 = 交叉熵损失 + 正则项(正则项会自动广播到batch中每个样本)
        total_loss = bce_loss + reg_loss
        return total_loss
    
    def compute_output_shape(self, input_shape):
        # 返回每个样本的损失维度:(batch_size,)
        return (input_shape[0][0],)

三、模型构建与训练代码调整

1. 模型构建修正

需要明确:当使用add_loss时,y_true需要作为模型的输入层传入,同时要手动添加准确率指标(因为默认的metrics=['accuracy']在这种模式下无法直接生效):

def build_model(self):
    img_input = layers.Input(shape=self.input_shape, name='img_input')
    nb_channels = self.growth_rate
    
    # 保留你原有的卷积、DenseBlock等网络结构代码
    layer_1 = layers.Convolution2D(2 * self.growth_rate, (1, 1), strides=(2, 2), kernel_regularizer=keras.regularizers.l2(self.weight_decay))(img_input)
    average_1 = layers.AveragePooling2D((2, 2), strides=(4, 4))(layer_1)
    x = layers.BatchNormalization()(layer_1)
    x = layers.Activation('relu')(x)
    x = layers.MaxPooling2D()(x)
    
    skip_layer = [average_1]
    for block in range(self.dense_blocks - 1):
        x, nb_channels = self.dense_block(x, self.dense_layers[block], nb_channels, self.growth_rate, self.dropout_rate, self.bottleneck, self.weight_decay)
        x_left,x_right = self.transition_layer(x, nb_channels, self.dropout_rate, self.compression, self.weight_decay)
        x = x_left
        nb_channels = int(nb_channels * self.compression)
        skip_layer.append(x_right)
    
    x, nb_channels = self.dense_block(x, self.dense_layers[-1], nb_channels, self.growth_rate, self.dropout_rate, self.weight_decay, skip_layer=skip_layer)
    x = layers.BatchNormalization()(x)
    x = layers.Activation('relu')(x)
    x = layers.GlobalAveragePooling2D()(x)
    x = layers.Dropout(0.2)(x)
    y_pred = layers.Dense(self.nb_classes, activation='sigmoid')(x)
    
    # 添加y_true输入层,对应二分类的(1,)维度
    y_true = layers.Input(shape=(self.nb_classes,), name='y_true')
    # 实例化自定义损失层
    loss_layer = BCLoss()([y_true, y_pred])
    
    # 定义模型:输入为图像和真实标签,输出为预测结果
    model = keras.Model(inputs=[img_input, y_true], outputs=y_pred)
    # 注入自定义损失
    model.add_loss(loss_layer)
    # 手动添加准确率指标,用于训练监控
    model.add_metric(K.mean(K.equal(y_true, K.round(y_pred))), name='accuracy')
    
    return model

2. 模型编译与训练修正

编译时loss设为None,训练时传入x为图像和标签的列表,y设为None:

from keras.optimizers import Adam

# 编译模型:无需指定loss,因为已通过add_loss注入
model.compile(optimizer=Adam(lr=0.001))

# 训练模型:x是[训练图像, 训练标签],y为None
model.fit(
    x=[train_imgs, train_labels],
    y=None,
    validation_data=([val_imgs, val_labels], None),
    epochs=50,
    batch_size=32,
    # 其他参数如早停等保留你的原有设置
)

四、验证损失函数逻辑正确性

修正后的代码完全符合你定义的损失公式:
Loss function = binary_crossentropy(y_true, y_pred) + λ|w|

  • binary_crossentropy部分:通过K.binary_crossentropy计算,按样本取平均;
  • λ|w|部分:λ对应lamada参数,w对应可训练参数gamma,通过K.abs(self.gamma)实现L1正则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:54:38