Keras多标签回归任务中如何查看每个标签的损失值?
你现在的场景是用Keras做多变量回归,输出层的n个神经元对应不同的回归目标,但默认的MAE损失是所有标签的平均值,没法单独查看每个标签的损失,训练进度条也只显示合并后的数值。你希望history里能记录每个标签的单独损失(比如{'loss': {'speed': 0.5, 'height': 0.3}}这种形式),同时训练时的进度条也能实时展示各标签的损失情况。
之前你考虑过为每个标签写单独的自定义指标,但觉得这是权宜之计,下面给你两种更系统的解决方案:
方法一:拆分输出层为独立输出分支(推荐方案)
Keras原生支持多输出模型,与其用一个Dense(n)输出所有标签,不如把每个回归目标做成单独的输出节点。这样Keras会自动为每个输出计算损失,训练时会分别展示各标签的损失值,history里也会单独记录每个输出的损失和指标。
示例代码如下:
from keras.layers import Input, Dense, Conv2D, Flatten from keras.models import Model # 假设输入是单通道图片 input_layer = Input(shape=(28, 28, 1)) x = Conv2D(32, (3,3), activation='relu')(input_layer) x = Flatten()(x) x = Dense(64, activation='relu')(x) # 每个回归目标单独创建输出层,并指定名称 output_speed = Dense(1, activation='linear', name='speed')(x) output_height = Dense(1, activation='linear', name='height')(x) # 若有更多标签,继续添加类似的output_xxx = Dense(1, ...) # 定义多输出模型 model = Model(inputs=input_layer, outputs=[output_speed, output_height]) # 编译时为每个输出指定损失和指标,支持字典或列表形式 model.compile( loss={'speed': 'mean_absolute_error', 'height': 'mean_absolute_error'}, optimizer='sgd', metrics={'speed': ['mean_squared_error'], 'height': ['mean_squared_error']} ) # 训练时,标签数据要对应输出的结构(字典或列表) # 假设y_train是形状为(样本数, 2)的数组,第一列是speed,第二列是height history = model.fit( X_train, {'speed': y_train[:, 0], 'height': y_train[:, 1]}, epochs=10, batch_size=32 )
这样训练时,进度条会显示loss(总损失,默认是各输出损失的平均值)、speed_loss、height_loss等字段;history.history里也会有speed_loss、height_loss、speed_mean_squared_error这些单独的键,完全满足你跟踪每个标签损失的需求,这也是最符合Keras设计逻辑的方案。
方法二:通用自定义指标(适合不改动模型结构的场景)
如果你不想重构现有的单输出层模型,可以写一个通用的指标生成函数,避免为每个标签重复写代码:
import keras.backend as K def mae_for_label(label_index, label_name): def mae(y_true, y_pred): # 提取对应索引的标签真实值和预测值 true = y_true[:, label_index] pred = y_pred[:, label_index] return K.mean(K.abs(pred - true)) # 给指标命名,方便在history和进度条中识别 mae.__name__ = f'mae_{label_name}' return mae # 假设你的标签列表是['speed', 'height'],对应索引0和1 custom_metrics = [ mae_for_label(0, 'speed'), mae_for_label(1, 'height'), # 更多标签可继续添加 ] # 保持原有的单输出模型结构不变 input_layer = Input(shape=shape) # ... 中间层定义 ... x = Dense(n, activation='linear')(x) model = Model(inputs=input_layer, outputs=x) # 编译时加入自定义指标 model.compile( loss='mean_absolute_error', optimizer='sgd', metrics=['mean_squared_error'] + custom_metrics ) history = model.fit_generator(...)
这种方式下,history.history里会出现mae_speed、mae_height等键,训练进度条也会显示这些指标。不过要注意:这里的总损失还是所有标签的平均MAE,自定义指标只是用来单独跟踪每个标签的损失情况,如果需要把总损失也拆分为各标签的单独值,还是方法一更合适。
内容的提问来源于stack exchange,提问作者0vbb

