为何部分损失类实例需定义看似未被使用的属性?以BinaryCrossentropy为例
先看你给出的BinaryCrossentropy实现代码:
@keras_export("keras.losses.BinaryCrossentropy") class BinaryCrossentropy(LossFunctionWrapper): def __init__( self, from_logits=False, label_smoothing=0.0, axis=-1, reduction=losses_utils.ReductionV2.AUTO, name="binary_crossentropy", ): super().__init__( binary_crossentropy, name=name, reduction=reduction, from_logits=from_logits, label_smoothing=label_smoothing, axis=axis, ) self.from_logits = from_logits
你观察得很对,LossFunctionWrapper确实会把from_logits这类参数存入self._fn_kwargs,供调用时传递给底层的损失计算函数,但单独把这个参数绑定为实例属性,主要有这几个实际意义:
方便外部直接读取配置:很多场景下,不管是用户自己的代码还是Keras框架内部的组件,都需要知道这个损失实例是否基于logits计算。比如模型输出层要不要加Sigmoid激活,完全取决于损失的
from_logits配置——如果损失设了True,输出层就不用加激活;反之则需要。把from_logits作为公开属性暴露出来,外部代码可以直接通过loss_instance.from_logits获取这个配置,不用去碰_fn_kwargs这种下划线开头的内部属性(这类属性属于实现细节,官方不推荐直接访问)。保持API风格统一:Keras里类似的损失类(比如
CategoricalCrossentropy)都把from_logits作为公开实例属性,这样所有同类型损失类的API风格一致,用户不用去记不同类的参数存储方式,用起来更直观。兼容序列化与旧逻辑:在模型保存、序列化的时候,需要准确记录损失实例的配置参数。把
from_logits单独作为属性,序列化逻辑可以直接读取这个值,不用从_fn_kwargs里解析;另外,Keras迭代过程中有些旧代码可能直接依赖这个属性,保留它能避免兼容性问题。
BinaryFocalCrossentropy的情况和这个完全一致,都是为了让关键配置可直接访问、保持API统一,同时兼容内部和外部的依赖逻辑。
内容的提问来源于stack exchange,提问作者learner

