代码之家  ›  专栏  ›  技术社区  ›  Jonathan

keras中使用类权重的U-net自定义损失函数:三维目标不支持“类权重”

  •  3
  • Jonathan  · 技术社区  · 6 年前

    inputs = Input((IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS))
    ...
    outputs = Conv2D(4, (1, 1), activation='sigmoid') (c9)
    
    model = Model(inputs=[inputs], outputs=[outputs])
    model.compile(optimizer='adam', loss='dice', metrics=[mean_iou])
    
    results = model.fit(X_train, Y_train, validation_split=0.1, batch_size=8, epochs=30, class_weight=class_weights)
    

    我有四节课很不平衡。A类为70%,B类为15%,C类为10%,D类为5%。但是,我最关心的是D类,所以我做了以下计算: D_weight = A/D = 70/5 = 14 对于B类和A类的重量,以此类推。(如果有更好的方法来选择这些重量,请放心)

    class_weights = {0: 1.0, 1: 6, 2: 7, 3: 14} .

    但是,当我这样做时,我会得到以下错误。

    class_weight

    我有没有可能在最后一层之后添加一个密集层,并将其用作一个虚拟层,这样我就可以通过类权重,然后只使用最后一个conv2d层的输出来进行预测?

    如果这不可能,我将如何修改loss函数(我知道 post

    def dice_coef(y_true, y_pred):
        smooth = 1.
        y_true_f = K.flatten(y_true)
        y_pred_f = K.flatten(y_pred)
        intersection = K.sum(y_true_f * y_pred_f)
        return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)
    
    def bce_dice_loss(y_true, y_pred):
        return 0.5 * binary_crossentropy(y_true, y_pred) - dice_coef(y_true, y_pred)
    

    但我看不出我能用什么方法输入类权重。如果有人想要完整的工作代码,请看这个 post . 但请记住将最后一个conv2d层的num类更改为4,而不是1。

    1 回复  |  直到 5 年前
        1
  •  6
  •   Daniel Möller    6 年前

    你可以自己施加重量:

    def weightedLoss(originalLossFunc, weightsList):
    
        def lossFunc(true, pred):
    
            axis = -1 #if channels last 
            #axis=  1 #if channels first
    
    
            #argmax returns the index of the element with the greatest value
            #done in the class axis, it returns the class index    
            classSelectors = K.argmax(true, axis=axis) 
    
            #considering weights are ordered by class, for each class
            #true(1) if the class index is equal to the weight index   
            classSelectors = [K.equal(i, classSelectors) for i in range(len(weightsList))]
    
            #casting boolean to float for calculations  
            #each tensor in the list contains 1 where ground true class is equal to its index 
            #if you sum all these, you will get a tensor full of ones. 
            classSelectors = [K.cast(x, K.floatx()) for x in classSelectors]
    
            #for each of the selections above, multiply their respective weight
            weights = [sel * w for sel,w in zip(classSelectors, weightsList)] 
    
            #sums all the selections
            #result is a tensor with the respective weight for each element in predictions
            weightMultiplier = weights[0]
            for i in range(1, len(weights)):
                weightMultiplier = weightMultiplier + weights[i]
    
    
            #make sure your originalLossFunc only collapses the class axis
            #you need the other axes intact to multiply the weights tensor
            loss = originalLossFunc(true,pred) 
            loss = loss * weightMultiplier
    
            return loss
        return lossFunc
    

    直接在输入数据上更改类平衡

    您也可以更改输入样本的平衡。

    .

    使用 sample_weight

    你也可以“按样本”工作,而不是“按类”工作。

    为输入数组中的每个样本创建一个权重数组: len(x_train) == len(weights)

    以及 fit 将此数组传递给 争论。
    fit_generator ,发电机必须返回重量和列车/真对: return/yield inputs, targets, weights