You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Keras中实现单样本加权的自定义二元交叉熵损失函数

Custom Weighted Binary Crossentropy in Keras

I get it, you want to apply different weights to each sample (or each class within a sample) when calculating binary crossentropy loss. Let's break down how to implement this properly, depending on your specific needs.

Case 1: Per-Class Weights (Static)

If you have fixed weights for each class (like your example: <0.81,0.9,1.0> for three classes), you can hardcode these weights into your custom loss function using Keras backend operations:

import numpy as np
from tensorflow.keras import backend as K

def weighted_binary_crossentropy(y_true, y_pred):
    # Define your per-class weights here
    class_weights = K.constant([0.81, 0.9, 1.0], dtype=K.floatx())
    
    # Calculate standard binary crossentropy per element
    bce = K.binary_crossentropy(y_true, y_pred)
    
    # Multiply each element's loss by its corresponding class weight
    weighted_bce = bce * class_weights
    
    # Return the mean of the weighted loss (use K.sum if you want total loss instead)
    return K.mean(weighted_bce)

Case 2: Per-Sample Weights (Dynamic)

If you want each sample in the batch to have its own weight (and want to compute these weights dynamically within the loss function, like using your base_factor), here's how to complete your partial code:

def my_binary_crossentropy(y_true, y_pred):
    base_factor = 0.9
    
    # Get the batch size at runtime (handles dynamic batch sizes, which K.int_shape can't)
    batch_size = K.shape(y_true)[0]
    
    # Generate weights for each sample (example: base_factor raised to the sample index)
    sample_indices = K.arange(0, batch_size, dtype=K.floatx())
    sample_weights = K.pow(base_factor, sample_indices)
    
    # Reshape weights to (batch_size, 1) so they broadcast across all classes in the sample
    sample_weights = K.reshape(sample_weights, (batch_size, 1))
    
    # Calculate binary crossentropy per element
    bce = K.binary_crossentropy(y_true, y_pred)
    
    # Multiply each element's loss by its sample's weight
    weighted_bce = bce * sample_weights
    
    # Return the mean of the weighted loss
    return K.mean(weighted_bce)

Case 3: Passing External Weights (Flexible)

If your weights are dynamic and depend on external data (not computed inside the loss function), use a closure to create a reusable loss function that accepts weights as a parameter:

def create_weighted_bce(weights):
    # Convert weights to a Keras constant to integrate with the graph
    weights_tensor = K.constant(weights, dtype=K.floatx())
    
    def weighted_bce(y_true, y_pred):
        bce = K.binary_crossentropy(y_true, y_pred)
        weighted_bce = bce * weights_tensor
        return K.mean(weighted_bce)
    
    return weighted_bce

# Usage example:
my_weights = [0.81, 0.9, 1.0]
model.compile(loss=create_weighted_bce(my_weights), optimizer='adam')

Key Tips

  • Always use Keras backend functions (K.pow, K.arange, etc.) instead of NumPy operations—this ensures the computation is part of the TensorFlow graph and can be differentiated during training.
  • Match the shape of your weights to the binary crossentropy output: for per-sample weights, reshape to (batch_size, 1) to broadcast across all classes in each sample.
  • If you just need simple per-sample weights during training, Keras has a built-in sample_weight parameter in model.fit() that you can use without writing a custom loss. But for dynamic weight calculation or per-class weights, the custom loss approach is better.

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

火山引擎 最新活动